2020-09-26 05:06:08 +10:00
# include "framework.h"
# include "lara.h"
# include "lara_tests.h"
# include "input.h"
2021-09-19 18:29:25 +03:00
# include "level.h"
2021-09-16 05:06:03 +03:00
# include "animation.h"
2020-09-26 05:06:08 +10:00
# include "lara_climb.h"
2021-12-10 12:30:23 +11:00
# include "lara_helpers.h"
2021-10-27 10:13:47 +03:00
# include "lara_monkey.h"
2020-09-26 05:06:08 +10:00
# include "lara_collide.h"
2021-09-27 18:18:03 +10:00
# include "lara_flare.h"
2021-09-19 23:41:26 +03:00
# include "control/control.h"
2021-09-27 18:18:03 +10:00
# include "control/los.h"
2021-09-25 16:00:30 +03:00
# include "items.h"
2021-10-08 00:54:00 +03:00
# include "Renderer11.h"
2021-12-01 15:18:47 +03:00
# include "Scripting/GameFlowScript.h"
2021-09-25 11:27:47 +02:00
2021-10-08 00:54:00 +03:00
using namespace TEN : : Renderer ;
2021-08-30 18:03:21 +03:00
using namespace TEN : : Floordata ;
2021-01-17 15:56:48 -03:00
2021-11-03 21:44:48 +11:00
// -----------------------------
// TEST FUNCTIONS
// For State Control & Collision
// -----------------------------
2020-09-26 05:06:08 +10:00
2021-10-07 16:45:26 +03:00
// Test if a ledge in front of item is valid to climb.
2021-10-29 05:01:07 +03:00
bool TestValidLedge ( ITEM_INFO * item , COLL_INFO * coll , bool ignoreHeadroom , bool heightLimit )
2020-09-26 05:06:08 +10:00
{
2021-12-13 13:32:45 +03:00
// Determine probe base left/right points
int xl = phd_sin ( coll - > NearestLedgeAngle - ANGLE ( 90 ) ) * coll - > Setup . Radius ;
int zl = phd_cos ( coll - > NearestLedgeAngle - ANGLE ( 90 ) ) * coll - > Setup . Radius ;
int xr = phd_sin ( coll - > NearestLedgeAngle + ANGLE ( 90 ) ) * coll - > Setup . Radius ;
int zr = phd_cos ( coll - > NearestLedgeAngle + ANGLE ( 90 ) ) * coll - > Setup . Radius ;
2020-09-26 05:06:08 +10:00
2021-10-08 00:54:00 +03:00
// Determine probe top point
int y = item - > pos . yPos - coll - > Setup . Height ;
2020-09-26 05:06:08 +10:00
2021-12-13 13:32:45 +03:00
// Get frontal collision data
auto frontLeft = GetCollisionResult ( item - > pos . xPos + xl , y , item - > pos . zPos + zl , GetRoom ( item - > location , item - > pos . xPos , y , item - > pos . zPos ) . roomNumber ) ;
auto frontRight = GetCollisionResult ( item - > pos . xPos + xr , y , item - > pos . zPos + zr , GetRoom ( item - > location , item - > pos . xPos , y , item - > pos . zPos ) . roomNumber ) ;
// If any of the frontal collision results intersects item bounds, return false, because there is material intersection.
// This check helps to filter out cases when Lara is formally facing corner but ledge check returns true because probe distance is fixed.
if ( frontLeft . Position . Floor < ( item - > pos . yPos - CLICK ( 0.5f ) ) | | frontRight . Position . Floor < ( item - > pos . yPos - CLICK ( 0.5f ) ) )
return false ;
if ( frontLeft . Position . Ceiling > ( item - > pos . yPos - coll - > Setup . Height ) | | frontRight . Position . Ceiling > ( item - > pos . yPos - coll - > Setup . Height ) )
return false ;
2021-10-07 14:36:41 +03:00
2021-10-08 00:54:00 +03:00
//g_Renderer.addDebugSphere(Vector3(item->pos.xPos + xl, left, item->pos.zPos + zl), 64, Vector4::One, RENDERER_DEBUG_PAGE::LOGIC_STATS);
//g_Renderer.addDebugSphere(Vector3(item->pos.xPos + xr, right, item->pos.zPos + zr), 64, Vector4::One, RENDERER_DEBUG_PAGE::LOGIC_STATS);
2021-12-13 13:32:45 +03:00
// Determine ledge probe embed offset.
// We use 0.2f radius extents here for two purposes. First - we can't guarantee that shifts weren't already applied
// and misfire may occur. Second - it guarantees that Lara won't land on a very thin edge of diagonal geometry.
int xf = phd_sin ( coll - > NearestLedgeAngle ) * ( coll - > Setup . Radius * 1.2f ) ;
int zf = phd_cos ( coll - > NearestLedgeAngle ) * ( coll - > Setup . Radius * 1.2f ) ;
2021-10-07 16:45:26 +03:00
2021-12-13 13:32:45 +03:00
// Get floor heights at both points
auto left = GetCollisionResult ( item - > pos . xPos + xf + xl , y , item - > pos . zPos + zf + zl , GetRoom ( item - > location , item - > pos . xPos , y , item - > pos . zPos ) . roomNumber ) . Position . Floor ;
auto right = GetCollisionResult ( item - > pos . xPos + xf + xr , y , item - > pos . zPos + zf + zr , GetRoom ( item - > location , item - > pos . xPos , y , item - > pos . zPos ) . roomNumber ) . Position . Floor ;
2021-10-07 16:45:26 +03:00
2021-10-29 05:13:32 +03:00
// If specified, limit vertical search zone only to nearest height
2021-12-12 21:11:27 +11:00
if ( heightLimit & & ( abs ( left - y ) > CLICK ( 0.5f ) | | abs ( right - y ) > CLICK ( 0.5f ) ) )
2021-10-29 05:13:32 +03:00
return false ;
2021-10-29 05:01:07 +03:00
2021-12-13 13:32:45 +03:00
// Determine allowed slope difference for a given collision radius
auto slopeDelta = ( ( float ) STEPUP_HEIGHT / ( float ) WALL_SIZE ) * ( coll - > Setup . Radius * 2 ) ;
2021-10-07 19:49:59 +03:00
// Discard if there is a slope beyond tolerance delta
if ( abs ( left - right ) > = slopeDelta )
2021-10-07 16:45:26 +03:00
return false ;
2021-11-01 05:26:15 +03:00
// Discard if ledge is not within distance threshold
if ( abs ( coll - > NearestLedgeDistance ) > coll - > Setup . Radius )
return false ;
// Discard if ledge is not within angle threshold
2021-10-28 04:13:24 +03:00
if ( ! TestValidLedgeAngle ( item , coll ) )
2021-10-07 23:58:29 +03:00
return false ;
2021-10-23 12:53:55 +03:00
if ( ! ignoreHeadroom )
{
auto headroom = ( coll - > Front . Floor + coll - > Setup . Height ) - coll - > Middle . Ceiling ;
2021-12-12 21:11:27 +11:00
if ( headroom < CLICK ( 1 ) )
2021-10-23 12:53:55 +03:00
return false ;
}
2021-10-07 19:49:59 +03:00
2021-10-07 16:45:26 +03:00
return ( coll - > CollisionType = = CT_FRONT ) ;
}
2020-09-26 05:06:08 +10:00
2021-10-28 04:13:24 +03:00
bool TestValidLedgeAngle ( ITEM_INFO * item , COLL_INFO * coll )
2021-10-27 01:23:59 +03:00
{
2021-11-20 12:25:51 +11:00
return abs ( ( short ) ( coll - > NearestLedgeAngle - item - > pos . yRot ) ) < = LARA_GRAB_THRESHOLD ;
2021-10-27 01:23:59 +03:00
}
2021-09-13 23:44:52 +03:00
bool TestLaraVault ( ITEM_INFO * item , COLL_INFO * coll )
2020-09-26 05:06:08 +10:00
{
2021-11-20 12:25:51 +11:00
LaraInfo * & info = item - > data ;
2021-12-10 12:30:23 +11:00
if ( ! ( TrInput & IN_ACTION ) | | info - > gunStatus ! = LG_HANDS_FREE )
return false ;
2021-12-12 21:11:27 +11:00
if ( TestLaraSwamp ( item ) & & info - > waterSurfaceDist < - CLICK ( 3 ) )
2021-11-07 04:54:48 +03:00
return false ;
2021-10-07 16:45:26 +03:00
if ( TestValidLedge ( item , coll ) )
2020-09-26 05:06:08 +10:00
{
2021-10-27 01:23:59 +03:00
bool success = false ;
2021-10-20 11:24:57 +11:00
// Vault to crouch up one step.
2021-11-06 17:58:14 +11:00
if ( coll - > Front . Floor < 0 & & // Lower floor bound.
coll - > Front . Floor > - STEPUP_HEIGHT & & // Upper floor bound.
2021-12-02 12:47:07 +11:00
g_GameFlow - > Animations . CrawlExtended )
2020-09-26 05:06:08 +10:00
{
2021-11-20 12:25:51 +11:00
if ( abs ( ( coll - > Front . Ceiling - coll - > Setup . Height ) - coll - > Front . Floor ) > LARA_HEIGHT_CRAWL ) // Front clamp buffer. Presumably, nothing more is necessary, but tend to this in the future. @Sezz 2021.11.06
2020-09-26 05:06:08 +10:00
{
item - > animNumber = LA_VAULT_TO_CROUCH_1CLICK ;
item - > currentAnimState = LS_GRABBING ;
2021-11-11 01:02:50 +11:00
item - > frameNumber = GetFrameNumber ( item , 0 ) ;
2020-09-26 05:06:08 +10:00
item - > goalAnimState = LS_CROUCH_IDLE ;
2021-12-12 21:11:27 +11:00
item - > pos . yPos + = coll - > Front . Floor + CLICK ( 1 ) ;
2021-11-20 12:25:51 +11:00
info - > gunStatus = LG_HANDS_BUSY ;
2021-10-27 01:23:59 +03:00
success = true ;
2020-09-26 05:06:08 +10:00
}
}
2021-10-20 11:24:57 +11:00
// Vault up two steps.
2021-12-12 21:11:27 +11:00
else if ( coll - > Front . Floor < = - STEPUP_HEIGHT & & // Lower floor bound.
coll - > Front . Floor > = - CLICK ( 2.5f ) ) // Upper floor bound.
2020-09-26 05:06:08 +10:00
{
2021-10-20 11:24:57 +11:00
// Vault to stand up two steps.
2021-12-10 22:31:34 +11:00
if ( abs ( ( coll - > Front . Ceiling - coll - > Setup . Height ) - coll - > Front . Floor ) > LARA_HEIGHT ) // Front clamp buffer. BUG: Turned away from the ledge and toward a section with a low ceiling, stand-to-crawl vault will be performed instead. @Sezz 2021.11.06
2020-09-26 05:06:08 +10:00
{
item - > animNumber = LA_VAULT_TO_STAND_2CLICK_START ;
item - > currentAnimState = LS_GRABBING ;
2021-11-11 01:02:50 +11:00
item - > frameNumber = GetFrameNumber ( item , 0 ) ;
2021-11-25 23:38:59 +11:00
item - > goalAnimState = LS_IDLE ;
2021-12-10 22:31:34 +11:00
item - > pos . yPos + = coll - > Front . Floor + CLICK ( 2 ) ;
2021-11-20 12:25:51 +11:00
info - > gunStatus = LG_HANDS_BUSY ;
2021-10-27 01:23:59 +03:00
success = true ;
2020-09-26 05:06:08 +10:00
}
2021-10-20 11:24:57 +11:00
// Vault to crouch up two steps.
2021-11-06 17:58:14 +11:00
else if ( abs ( ( coll - > Front . Ceiling - coll - > Setup . Height ) - coll - > Front . Floor ) > LARA_HEIGHT_CRAWL & & // Front clamp buffer.
abs ( ( coll - > FrontLeft . Ceiling - coll - > Setup . Height ) - coll - > FrontLeft . Floor ) > LARA_HEIGHT_CRAWL & & // Left clamp buffer.
abs ( ( coll - > FrontRight . Ceiling - coll - > Setup . Height ) - coll - > FrontRight . Floor ) > LARA_HEIGHT_CRAWL & & // Right clamp buffer.
2021-12-02 12:47:07 +11:00
g_GameFlow - > Animations . CrawlExtended )
2020-09-26 05:06:08 +10:00
{
item - > animNumber = LA_VAULT_TO_CROUCH_2CLICK ;
2021-11-11 01:02:50 +11:00
item - > frameNumber = GetFrameNumber ( item , 0 ) ;
2020-09-26 05:06:08 +10:00
item - > currentAnimState = LS_GRABBING ;
item - > goalAnimState = LS_CROUCH_IDLE ;
2021-12-10 22:31:34 +11:00
item - > pos . yPos + = coll - > Front . Floor + CLICK ( 2 ) ;
2021-11-20 12:25:51 +11:00
info - > gunStatus = LG_HANDS_BUSY ;
2021-10-27 01:23:59 +03:00
success = true ;
2020-09-26 05:06:08 +10:00
}
}
2021-10-20 11:24:57 +11:00
// Vault up three steps.
2021-12-12 21:11:27 +11:00
else if ( coll - > Front . Floor < = - CLICK ( 2.5f ) & & // Lower floor bound.
coll - > Front . Floor > = - CLICK ( 3.5f ) ) // Upper floor bound.
2020-09-26 05:06:08 +10:00
{
2021-10-20 11:24:57 +11:00
// Vault to stand up three steps.
2021-12-10 22:31:34 +11:00
if ( abs ( ( coll - > Front . Ceiling - coll - > Setup . Height ) - coll - > Front . Floor ) > LARA_HEIGHT ) // Front clamp buffer. BUG: Turned away from the ledge and toward a section with a low ceiling, stand-to-crawl vault will be performed instead. @Sezz 2021.11.06
2020-09-26 05:06:08 +10:00
{
item - > animNumber = LA_VAULT_TO_STAND_3CLICK ;
item - > currentAnimState = LS_GRABBING ;
2021-11-11 01:02:50 +11:00
item - > frameNumber = GetFrameNumber ( item , 0 ) ;
2021-11-25 23:38:59 +11:00
item - > goalAnimState = LS_IDLE ;
2021-12-12 21:11:27 +11:00
item - > pos . yPos + = coll - > Front . Floor + CLICK ( 3 ) ;
2021-11-20 12:25:51 +11:00
info - > gunStatus = LG_HANDS_BUSY ;
2021-10-27 01:23:59 +03:00
success = true ;
2020-09-26 05:06:08 +10:00
}
2021-10-20 11:24:57 +11:00
// Vault to crouch up three steps.
2021-11-06 17:58:14 +11:00
else if ( abs ( ( coll - > Front . Ceiling - coll - > Setup . Height ) - coll - > Front . Floor ) > LARA_HEIGHT_CRAWL & & // Front clamp buffer.
abs ( ( coll - > FrontLeft . Ceiling - coll - > Setup . Height ) - coll - > FrontLeft . Floor ) > LARA_HEIGHT_CRAWL & & // Left clamp buffer.
abs ( ( coll - > FrontRight . Ceiling - coll - > Setup . Height ) - coll - > FrontRight . Floor ) > LARA_HEIGHT_CRAWL & & // Right clamp buffer.
2021-12-02 12:47:07 +11:00
g_GameFlow - > Animations . CrawlExtended )
2020-09-26 05:06:08 +10:00
{
item - > animNumber = LA_VAULT_TO_CROUCH_3CLICK ;
2021-11-11 01:02:50 +11:00
item - > frameNumber = GetFrameNumber ( item , 0 ) ;
2020-09-26 05:06:08 +10:00
item - > currentAnimState = LS_GRABBING ;
item - > goalAnimState = LS_CROUCH_IDLE ;
2021-12-12 21:11:27 +11:00
item - > pos . yPos + = coll - > Front . Floor + CLICK ( 3 ) ;
2021-11-20 12:25:51 +11:00
info - > gunStatus = LG_HANDS_BUSY ;
2021-10-27 01:23:59 +03:00
success = true ;
2020-09-26 05:06:08 +10:00
}
}
2021-10-20 11:24:57 +11:00
// Auto jump.
2021-12-12 21:11:27 +11:00
else if ( coll - > Front . Floor > = - CLICK ( 7.5f ) & & // Upper floor bound.
coll - > Front . Floor < = - CLICK ( 3.5f ) & & // Lower floor bound.
2021-11-29 00:12:52 +11:00
! TestLaraSwamp ( item ) )
2020-09-26 05:06:08 +10:00
{
item - > animNumber = LA_STAND_SOLID ;
2021-11-11 01:02:50 +11:00
item - > frameNumber = GetFrameNumber ( item , 0 ) ;
2020-09-26 05:06:08 +10:00
item - > goalAnimState = LS_JUMP_UP ;
2021-11-25 23:38:59 +11:00
item - > currentAnimState = LS_IDLE ;
2021-11-20 12:25:51 +11:00
info - > calcFallSpeed = - 3 - sqrt ( - 9600 - 12 * coll - > Front . Floor ) ;
2020-09-26 05:06:08 +10:00
AnimateLara ( item ) ;
2021-10-27 01:23:59 +03:00
success = true ;
2020-09-26 05:06:08 +10:00
}
2021-10-27 01:23:59 +03:00
if ( success )
2021-10-28 17:36:12 +03:00
{
2021-10-29 05:35:27 +03:00
SnapItemToLedge ( item , coll , 0.2f ) ;
2021-10-28 17:36:12 +03:00
return true ;
}
2021-10-09 01:55:22 +03:00
}
2021-10-27 01:23:59 +03:00
2021-10-20 11:24:57 +11:00
// Begin ladder climb.
2021-12-17 18:44:31 +11:00
if ( info - > climbStatus & & TestValidLedgeAngle ( item , coll ) )
2021-10-09 01:55:22 +03:00
{
2021-12-12 21:11:27 +11:00
if ( coll - > Front . Floor > - CLICK ( 7.5f ) | | // Upper front floor bound.
coll - > FrontLeft . Floor > - CLICK ( 7.5f ) | | // Upper left floor bound.
coll - > FrontRight . Floor > - CLICK ( 2 ) | | // Upper right floor bound.
coll - > Middle . Ceiling > - CLICK ( 4.5f ) + 6 | | // Upper ceiling bound.
2021-11-20 12:25:51 +11:00
info - > waterStatus = = LW_WADE )
2021-10-09 01:55:22 +03:00
{
2021-12-10 22:31:34 +11:00
if ( ( coll - > Front . Floor < - WALL_SIZE | | coll - > Front . Ceiling > = ( CLICK ( 2 ) - 6 ) ) & &
coll - > Middle . Ceiling < = - ( CLICK ( 2 ) + 6 ) )
2020-09-26 05:06:08 +10:00
{
2021-10-09 01:55:22 +03:00
if ( TestLaraClimbStance ( item , coll ) )
2020-09-26 05:06:08 +10:00
{
2021-10-09 01:55:22 +03:00
item - > animNumber = LA_STAND_SOLID ;
2021-11-11 01:02:50 +11:00
item - > frameNumber = GetFrameNumber ( item , 0 ) ;
2021-10-09 01:55:22 +03:00
item - > goalAnimState = LS_LADDER_IDLE ;
2021-11-25 23:38:59 +11:00
item - > currentAnimState = LS_IDLE ;
2021-11-20 12:25:51 +11:00
info - > gunStatus = LG_HANDS_BUSY ;
info - > turnRate = 0 ;
2021-10-27 01:23:59 +03:00
2021-10-27 12:46:36 +03:00
ShiftItem ( item , coll ) ;
2021-10-27 13:05:41 +03:00
SnapItemToGrid ( item , coll ) ; // HACK: until fragile ladder code is refactored, we must exactly snap to grid.
2021-10-27 10:31:46 +03:00
AnimateLara ( item ) ;
2021-11-01 19:00:03 +11:00
2021-10-09 01:55:22 +03:00
return true ;
2020-09-26 05:06:08 +10:00
}
}
2021-11-01 19:00:03 +11:00
2021-10-09 01:55:22 +03:00
return false ;
2020-09-26 05:06:08 +10:00
}
2021-11-29 00:12:52 +11:00
// Auto jump to ladder. TODO: Check swamps.
2021-10-09 01:55:22 +03:00
item - > animNumber = LA_STAND_SOLID ;
2021-11-11 01:02:50 +11:00
item - > frameNumber = GetFrameNumber ( item , 0 ) ;
2021-10-09 01:55:22 +03:00
item - > goalAnimState = LS_JUMP_UP ;
2021-11-25 23:38:59 +11:00
item - > currentAnimState = LS_IDLE ;
2021-11-20 12:25:51 +11:00
info - > calcFallSpeed = - 116 ;
info - > turnRate = 0 ;
2021-10-27 11:31:31 +03:00
2020-09-26 05:06:08 +10:00
ShiftItem ( item , coll ) ;
2021-10-27 13:05:41 +03:00
SnapItemToGrid ( item , coll ) ; // HACK: until fragile ladder code is refactored, we must exactly snap to grid.
2021-10-27 11:31:31 +03:00
AnimateLara ( item ) ;
2021-09-13 20:19:33 +02:00
2021-09-13 23:44:52 +03:00
return true ;
2020-09-26 05:06:08 +10:00
}
2021-10-27 01:23:59 +03:00
2021-10-20 11:24:57 +11:00
// Auto jump to monkey swing.
2021-11-20 12:25:51 +11:00
if ( info - > canMonkeySwing & &
2021-11-29 00:12:52 +11:00
! TestLaraSwamp ( item ) & &
2021-12-17 18:44:31 +11:00
g_GameFlow - > Animations . MonkeyAutoJump )
2020-09-26 05:06:08 +10:00
{
2021-10-09 01:55:22 +03:00
short roomNum = item - > roomNumber ;
int ceiling = ( GetCeiling ( GetFloor ( item - > pos . xPos , item - > pos . yPos , item - > pos . zPos , & roomNum ) ,
item - > pos . xPos , item - > pos . yPos , item - > pos . zPos ) ) - ( item - > pos . yPos ) ;
2021-07-08 14:15:14 -05:00
2021-12-12 21:11:27 +11:00
if ( ceiling > CLICK ( 7 ) | |
ceiling < - CLICK ( 7 ) | |
abs ( ceiling ) = = CLICK ( 3 ) )
2021-10-20 11:24:57 +11:00
{
2021-10-09 01:55:22 +03:00
return false ;
2021-10-20 11:24:57 +11:00
}
2021-07-08 14:15:14 -05:00
2021-10-09 01:55:22 +03:00
item - > animNumber = LA_STAND_IDLE ;
2021-11-11 01:02:50 +11:00
item - > frameNumber = GetFrameNumber ( item , 0 ) ;
2021-10-09 01:55:22 +03:00
item - > goalAnimState = LS_JUMP_UP ;
2021-12-10 11:04:28 +03:00
item - > currentAnimState = LS_MONKEY_VAULT ;
2021-10-20 11:24:57 +11:00
2021-10-09 01:55:22 +03:00
return true ;
2020-09-26 05:06:08 +10:00
}
2021-09-13 23:44:52 +03:00
return false ;
2020-09-26 05:06:08 +10:00
}
2021-11-13 18:10:22 +11:00
bool TestLaraKeepCrouched ( ITEM_INFO * item , COLL_INFO * coll )
2021-09-09 20:21:05 +03:00
{
2021-11-05 21:29:00 +11:00
// TODO: Temporary. coll->Setup.Radius is currently only set to
// LARA_RAD_CRAWL in the collision function, then reset by LaraAboveWater().
// For tests called in control functions, then, it will store the wrong radius. @Sezz 2021.11.05
auto radius = ( item - > currentAnimState = = LS_CROUCH_IDLE | |
item - > currentAnimState = = LS_CROUCH_TURN_LEFT | |
item - > currentAnimState = = LS_CROUCH_TURN_RIGHT )
? LARA_RAD : LARA_RAD_CRAWL ;
auto y = item - > pos . yPos ;
2021-12-01 01:13:22 +11:00
auto probeBack = GetCollisionResult ( item , item - > pos . yRot + ANGLE ( 180.0f ) , radius , 0 ) ;
2021-11-05 21:29:00 +11:00
// TODO: Cannot use as a failsafe in standing states; bugged with slanted ceilings reaching the ground.
// In common setups, Lara may embed on such ceilings, resulting in inappropriate crouch state dispatches.
2021-11-19 22:48:47 +11:00
// A buffer might help, but improved collision handling would presumably eliminate this issue entirely. @Sezz 2021.10.15
if ( ( coll - > Middle . Ceiling - LARA_HEIGHT_CRAWL ) > = - LARA_HEIGHT | | // Middle is not a clamp.
2021-11-17 17:51:27 +11:00
( coll - > Front . Ceiling - LARA_HEIGHT_CRAWL ) > = - LARA_HEIGHT | | // Front is not a clamp.
( probeBack . Position . Ceiling - y ) > = - LARA_HEIGHT ) // Back is not a clamp.
2021-10-25 23:24:34 +11:00
{
2021-10-15 21:59:41 +11:00
return true ;
2021-10-25 23:24:34 +11:00
}
2021-10-15 21:59:41 +11:00
return false ;
2021-09-09 20:21:05 +03:00
}
2021-09-13 09:12:46 +03:00
bool TestLaraSlide ( ITEM_INFO * item , COLL_INFO * coll )
{
2021-11-29 15:26:55 +11:00
LaraInfo * & info = item - > data ;
2021-11-26 16:25:16 +11:00
if ( TestLaraSwamp ( item ) )
return false ;
2021-09-13 09:12:46 +03:00
static short oldAngle = 1 ;
if ( abs ( coll - > TiltX ) < = 2 & & abs ( coll - > TiltZ ) < = 2 )
return false ;
short angle = ANGLE ( 0.0f ) ;
if ( coll - > TiltX > 2 )
angle = - ANGLE ( 90.0f ) ;
else if ( coll - > TiltX < - 2 )
angle = ANGLE ( 90.0f ) ;
if ( coll - > TiltZ > 2 & & coll - > TiltZ > abs ( coll - > TiltX ) )
angle = ANGLE ( 180.0f ) ;
else if ( coll - > TiltZ < - 2 & & - coll - > TiltZ > abs ( coll - > TiltX ) )
angle = ANGLE ( 0.0f ) ;
short delta = angle - item - > pos . yRot ;
ShiftItem ( item , coll ) ;
if ( delta < - ANGLE ( 90.0f ) | | delta > ANGLE ( 90.0f ) )
{
if ( item - > currentAnimState = = LS_SLIDE_BACK & & oldAngle = = angle )
return true ;
2021-11-10 02:41:59 +03:00
SetAnimation ( item , LA_SLIDE_BACK_START ) ;
2021-09-13 09:12:46 +03:00
item - > pos . yRot = angle + ANGLE ( 180.0f ) ;
}
else
{
if ( item - > currentAnimState = = LS_SLIDE_FORWARD & & oldAngle = = angle )
return true ;
2021-11-10 02:41:59 +03:00
SetAnimation ( item , LA_SLIDE_FORWARD ) ;
2021-09-13 09:12:46 +03:00
item - > pos . yRot = angle ;
}
2021-11-29 15:26:55 +11:00
info - > moveAngle = angle ;
2021-09-13 09:12:46 +03:00
oldAngle = angle ;
return true ;
}
2021-11-23 13:53:35 +11:00
bool TestLaraSwamp ( ITEM_INFO * item )
{
return ( g_Level . Rooms [ item - > roomNumber ] . flags & ENV_FLAG_SWAMP ) ;
}
bool TestLaraWater ( ITEM_INFO * item )
{
return ( g_Level . Rooms [ item - > roomNumber ] . flags & ENV_FLAG_WATER ) ;
}
2021-09-14 00:41:11 +03:00
SPLAT_COLL TestLaraWall ( ITEM_INFO * item , int front , int right , int down )
2020-09-26 05:06:08 +10:00
{
int x = item - > pos . xPos ;
int y = item - > pos . yPos + down ;
int z = item - > pos . zPos ;
short angle = GetQuadrant ( item - > pos . yRot ) ;
short roomNum = item - > roomNumber ;
switch ( angle )
{
case NORTH :
x - = right ;
break ;
case EAST :
z - = right ;
break ;
case SOUTH :
x + = right ;
break ;
case WEST :
z + = right ;
break ;
default :
break ;
}
GetFloor ( x , y , z , & roomNum ) ;
switch ( angle )
{
case NORTH :
z + = front ;
break ;
case EAST :
x + = front ;
break ;
case SOUTH :
z - = front ;
break ;
case WEST :
x - = front ;
break ;
default :
break ;
}
2021-12-10 12:30:23 +11:00
auto floor = GetFloor ( x , y , z , & roomNum ) ;
auto floorHeight = GetFloorHeight ( floor , x , y , z ) ;
auto ceilHeight = GetCeiling ( floor , x , y , z ) ;
2020-09-26 05:06:08 +10:00
2021-12-02 18:52:00 +11:00
if ( floorHeight = = NO_HEIGHT )
2021-10-27 09:48:31 +03:00
return SPLAT_COLL : : WALL ;
2020-09-26 05:06:08 +10:00
2021-12-02 18:52:00 +11:00
if ( y > = floorHeight | | y < = ceilHeight )
2021-10-27 09:48:31 +03:00
return SPLAT_COLL : : STEP ;
2020-09-26 05:06:08 +10:00
2021-10-27 09:48:31 +03:00
return SPLAT_COLL : : NONE ;
2020-09-26 05:06:08 +10:00
}
2021-10-27 10:13:47 +03:00
bool TestLaraHangJumpUp ( ITEM_INFO * item , COLL_INFO * coll )
{
2021-11-29 15:26:55 +11:00
LaraInfo * & info = item - > data ;
if ( ! ( TrInput & IN_ACTION ) | | ( info - > gunStatus ! = LG_HANDS_FREE ) | | ( coll - > HitStatic ) )
2021-10-27 10:13:47 +03:00
return false ;
2021-11-29 15:26:55 +11:00
if ( info - > canMonkeySwing & & coll - > CollisionType = = CT_TOP )
2021-10-27 10:13:47 +03:00
{
2021-11-10 02:41:59 +03:00
SetAnimation ( item , LA_JUMP_UP_TO_MONKEYSWING ) ;
2021-10-27 10:13:47 +03:00
item - > gravityStatus = false ;
item - > speed = 0 ;
item - > fallspeed = 0 ;
2021-11-29 15:26:55 +11:00
info - > gunStatus = LG_HANDS_BUSY ;
2021-10-27 10:13:47 +03:00
MonkeySwingSnap ( item , coll ) ;
return true ;
}
2021-10-28 03:04:20 +03:00
if ( ( coll - > CollisionType ! = CT_FRONT ) | | ( coll - > Middle . Ceiling > - STEPUP_HEIGHT ) )
2021-10-27 10:13:47 +03:00
return false ;
int edge ;
auto edgeCatch = TestLaraEdgeCatch ( item , coll , & edge ) ;
if ( ! edgeCatch )
return false ;
2021-10-27 12:46:36 +03:00
bool ladder = TestLaraHangOnClimbWall ( item , coll ) ;
if ( ! ( ladder & & edgeCatch ) & &
2021-10-29 05:01:07 +03:00
! ( TestValidLedge ( item , coll , true , true ) & & edgeCatch > 0 ) )
2021-10-27 10:13:47 +03:00
return false ;
auto angle = item - > pos . yRot ;
if ( TestHangSwingIn ( item , angle ) )
{
2021-11-10 02:41:59 +03:00
SetAnimation ( item , LA_JUMP_UP_TO_MONKEYSWING ) ;
2021-10-27 10:13:47 +03:00
}
else
{
2021-11-10 02:41:59 +03:00
SetAnimation ( item , LA_REACH_TO_HANG , 12 ) ;
2021-10-27 10:13:47 +03:00
}
auto bounds = GetBoundsAccurate ( item ) ;
if ( edgeCatch < = 0 )
item - > pos . yPos = edge - bounds - > Y1 + 4 ;
else
item - > pos . yPos + = coll - > Front . Floor - bounds - > Y1 ;
2021-10-27 12:46:36 +03:00
if ( ladder )
SnapItemToGrid ( item , coll ) ; // HACK: until fragile ladder code is refactored, we must exactly snap to grid.
else
SnapItemToLedge ( item , coll ) ;
2021-10-27 10:13:47 +03:00
item - > gravityStatus = false ;
item - > speed = 0 ;
item - > fallspeed = 0 ;
2021-11-29 15:26:55 +11:00
info - > gunStatus = LG_HANDS_BUSY ;
info - > torsoYrot = 0 ;
info - > torsoXrot = 0 ;
2021-10-27 10:13:47 +03:00
return true ;
}
2021-10-27 09:48:48 +03:00
bool TestLaraHangJump ( ITEM_INFO * item , COLL_INFO * coll )
{
2021-11-29 15:26:55 +11:00
LaraInfo * & info = item - > data ;
if ( ! ( TrInput & IN_ACTION ) | | ( info - > gunStatus ! = LG_HANDS_FREE ) | | ( coll - > HitStatic ) )
2021-10-27 09:48:48 +03:00
return false ;
2021-11-29 15:26:55 +11:00
if ( info - > canMonkeySwing & & coll - > CollisionType = = CT_TOP )
2021-10-27 09:48:48 +03:00
{
2021-12-10 12:30:23 +11:00
ResetLaraFlex ( item ) ;
2021-11-29 15:26:55 +11:00
info - > gunStatus = LG_HANDS_BUSY ;
2021-10-27 09:48:48 +03:00
2021-11-10 02:41:59 +03:00
SetAnimation ( item , LA_REACH_TO_MONKEYSWING ) ;
2021-10-27 09:48:48 +03:00
item - > gravityStatus = false ;
item - > speed = 0 ;
item - > fallspeed = 0 ;
return true ;
}
if ( ( coll - > Middle . Ceiling > - STEPUP_HEIGHT ) | |
( coll - > Middle . Floor < 200 ) | |
( coll - > CollisionType ! = CT_FRONT ) )
return false ;
2021-10-27 10:13:47 +03:00
int edge ;
2021-10-27 09:48:48 +03:00
auto edgeCatch = TestLaraEdgeCatch ( item , coll , & edge ) ;
if ( ! edgeCatch )
return false ;
2021-10-27 12:46:36 +03:00
bool ladder = TestLaraHangOnClimbWall ( item , coll ) ;
if ( ! ( ladder & & edgeCatch ) & &
2021-10-29 05:01:07 +03:00
! ( TestValidLedge ( item , coll , true , true ) & & edgeCatch > 0 ) )
2021-10-27 09:48:48 +03:00
return false ;
auto angle = item - > pos . yRot ;
if ( TestHangSwingIn ( item , angle ) )
{
2021-12-02 12:47:07 +11:00
if ( g_GameFlow - > Animations . OscillateHang )
2021-10-27 09:48:48 +03:00
{
2021-12-10 12:30:23 +11:00
ResetLaraFlex ( item ) ;
2021-11-10 02:41:59 +03:00
SetAnimation ( item , LA_REACH_TO_HANG_OSCILLATE ) ;
2021-10-27 09:48:48 +03:00
}
else
{
2021-12-10 12:30:23 +11:00
ResetLaraFlex ( item ) ;
2021-11-10 02:41:59 +03:00
SetAnimation ( item , LA_REACH_TO_MONKEYSWING ) ;
2021-10-27 09:48:48 +03:00
}
}
else
2021-11-10 02:41:59 +03:00
SetAnimation ( item , LA_REACH_TO_HANG ) ;
2021-10-27 09:48:48 +03:00
auto bounds = GetBoundsAccurate ( item ) ;
if ( edgeCatch < = 0 )
{
item - > pos . yPos = edge - bounds - > Y1 - 20 ;
item - > pos . yRot = coll - > NearestLedgeAngle ;
}
else
item - > pos . yPos + = coll - > Front . Floor - bounds - > Y1 - 20 ;
2021-10-27 12:46:36 +03:00
if ( ladder )
SnapItemToGrid ( item , coll ) ; // HACK: until fragile ladder code is refactored, we must exactly snap to grid.
else
SnapItemToLedge ( item , coll , 0.2f ) ;
2021-10-27 09:48:48 +03:00
item - > gravityStatus = true ;
item - > speed = 2 ;
item - > fallspeed = 1 ;
2021-11-29 15:26:55 +11:00
info - > gunStatus = LG_HANDS_BUSY ;
2021-10-27 09:48:48 +03:00
return true ;
2020-09-26 05:06:08 +10:00
}
2021-09-14 00:30:44 +03:00
bool TestLaraHang ( ITEM_INFO * item , COLL_INFO * coll )
2020-09-26 05:06:08 +10:00
{
2021-11-29 15:26:55 +11:00
LaraInfo * & info = item - > data ;
auto angle = info - > moveAngle ;
2021-09-14 00:03:24 +03:00
2021-11-30 02:39:41 +03:00
auto climbShift = 0 ;
2021-12-02 12:47:07 +11:00
if ( info - > moveAngle = = ( short ) ( item - > pos . yRot - ANGLE ( 90.0f ) ) )
2021-11-30 02:39:41 +03:00
climbShift = - coll - > Setup . Radius ;
2021-12-02 12:47:07 +11:00
else if ( info - > moveAngle = = ( short ) ( item - > pos . yRot + ANGLE ( 90.0f ) ) )
2021-11-30 02:39:41 +03:00
climbShift = coll - > Setup . Radius ;
2021-09-14 00:03:24 +03:00
2021-11-30 02:39:41 +03:00
// Temporarily move item a bit closer to the wall to get more precise coll results
2021-11-29 20:45:22 +03:00
auto oldPos = item - > pos ;
item - > pos . xPos + = phd_sin ( item - > pos . yRot ) * coll - > Setup . Radius * 0.5f ;
item - > pos . zPos + = phd_cos ( item - > pos . yRot ) * coll - > Setup . Radius * 0.5f ;
2021-11-30 02:39:41 +03:00
// Get height difference with side spaces (left or right, depending on movement direction)
2021-12-14 15:10:45 +03:00
auto hdif = LaraFloorFront ( item , info - > moveAngle , coll - > Setup . Radius * 1.4f ) ;
2021-11-30 02:39:41 +03:00
// Set stopped flag, if floor height is above footspace which is step size
2021-12-12 21:11:27 +11:00
auto stopped = hdif < CLICK ( 0.5f ) ;
2021-11-30 02:39:41 +03:00
// Set stopped flag, if ceiling height is below headspace which is step size
2021-12-02 12:47:07 +11:00
if ( LaraCeilingFront ( item , info - > moveAngle , coll - > Setup . Radius * 1.5f , 0 ) > - 950 )
2021-11-30 02:39:41 +03:00
stopped = true ;
2021-11-30 02:51:19 +03:00
// Backup item pos to restore it after coll tests
2021-11-29 20:45:22 +03:00
item - > pos = oldPos ;
2021-09-14 00:03:24 +03:00
2021-11-30 02:51:19 +03:00
// Setup coll info
2021-12-02 12:47:07 +11:00
info - > moveAngle = item - > pos . yRot ;
2021-11-30 02:39:41 +03:00
coll - > Setup . BadHeightDown = NO_BAD_POS ;
coll - > Setup . BadHeightUp = - STEPUP_HEIGHT ;
coll - > Setup . BadCeilingHeight = 0 ;
2021-12-02 12:47:07 +11:00
coll - > Setup . ForwardAngle = info - > moveAngle ;
2021-09-14 00:03:24 +03:00
2021-10-24 05:33:32 +03:00
// When Lara is about to move, use larger embed offset for stabilizing diagonal shimmying)
auto embedOffset = 4 ;
2021-11-10 02:01:43 +11:00
if ( TrInput & ( IN_LEFT | IN_RIGHT ) )
2021-10-24 05:33:32 +03:00
embedOffset = 16 ;
item - > pos . xPos + = phd_sin ( item - > pos . yRot ) * embedOffset ;
item - > pos . zPos + = phd_cos ( item - > pos . yRot ) * embedOffset ;
2021-09-14 00:03:24 +03:00
2021-09-19 06:42:24 +03:00
GetCollisionInfo ( coll , item ) ;
2021-09-14 00:03:24 +03:00
2021-09-16 01:56:02 +03:00
bool result = false ;
2021-12-02 12:47:07 +11:00
if ( info - > climbStatus ) // Ladder case
2020-09-26 05:06:08 +10:00
{
2021-11-30 02:39:41 +03:00
if ( TrInput & IN_ACTION & & item - > hitPoints > 0 )
2020-09-26 05:06:08 +10:00
{
2021-11-29 15:26:55 +11:00
info - > moveAngle = angle ;
2021-09-14 00:03:24 +03:00
2021-09-14 00:30:44 +03:00
if ( ! TestLaraHangOnClimbWall ( item , coll ) )
2020-09-26 05:06:08 +10:00
{
2021-11-10 02:01:43 +11:00
if ( item - > animNumber ! = LA_LADDER_TO_HANG_RIGHT & &
item - > animNumber ! = LA_LADDER_TO_HANG_LEFT )
2020-09-26 05:06:08 +10:00
{
2021-11-30 02:39:41 +03:00
LaraSnapToEdgeOfBlock ( item , coll , GetQuadrant ( item - > pos . yRot ) ) ;
2021-09-10 00:20:59 +03:00
item - > pos . yPos = coll - > Setup . OldPosition . y ;
2021-11-10 02:41:59 +03:00
SetAnimation ( item , LA_REACH_TO_HANG , 21 ) ;
2020-09-26 05:06:08 +10:00
}
2021-11-10 02:01:43 +11:00
2021-09-14 00:03:24 +03:00
result = true ;
2020-09-26 05:06:08 +10:00
}
else
{
2021-11-30 02:51:19 +03:00
if ( item - > animNumber = = LA_REACH_TO_HANG & & item - > frameNumber = = GetFrameNumber ( item , 21 ) & &
2021-11-10 02:01:43 +11:00
TestLaraClimbStance ( item , coll ) )
{
2020-09-26 05:06:08 +10:00
item - > goalAnimState = LS_LADDER_IDLE ;
2021-11-10 02:01:43 +11:00
}
2020-09-26 05:06:08 +10:00
}
}
2021-11-30 02:51:19 +03:00
else // Death or action release
2020-09-26 05:06:08 +10:00
{
2021-11-10 02:41:59 +03:00
SetAnimation ( item , LA_FALL_START ) ;
2020-09-26 05:06:08 +10:00
item - > pos . yPos + = 256 ;
item - > gravityStatus = true ;
item - > speed = 2 ;
item - > fallspeed = 1 ;
2021-11-29 15:26:55 +11:00
info - > gunStatus = LG_HANDS_FREE ;
2020-09-26 05:06:08 +10:00
}
}
2021-11-30 02:51:19 +03:00
else // Normal case
2020-09-26 05:06:08 +10:00
{
2021-11-30 02:39:41 +03:00
if ( TrInput & IN_ACTION & & item - > hitPoints > 0 & & coll - > Front . Floor < = 0 )
2020-09-26 05:06:08 +10:00
{
2021-11-30 02:39:41 +03:00
if ( stopped & & hdif > 0 & & climbShift ! = 0 & & ( climbShift > 0 = = coll - > MiddleLeft . Floor > coll - > MiddleRight . Floor ) )
stopped = false ;
2021-09-14 00:03:24 +03:00
2021-11-30 02:39:41 +03:00
auto verticalShift = coll - > Front . Floor - GetBoundsAccurate ( item ) - > Y1 ;
2021-09-14 00:03:24 +03:00
auto x = item - > pos . xPos ;
auto z = item - > pos . zPos ;
2021-12-02 12:47:07 +11:00
info - > moveAngle = angle ;
2021-11-30 02:39:41 +03:00
if ( climbShift ! = 0 )
2020-09-26 05:06:08 +10:00
{
2021-12-02 12:47:07 +11:00
auto s = phd_sin ( info - > moveAngle ) ;
auto c = phd_cos ( info - > moveAngle ) ;
2021-11-30 02:39:41 +03:00
auto testShift = Vector2 ( s * climbShift , c * climbShift ) ;
2021-10-23 15:35:59 +03:00
x + = testShift . x ;
z + = testShift . y ;
2020-09-26 05:06:08 +10:00
}
2021-09-14 00:03:24 +03:00
2021-11-30 02:39:41 +03:00
if ( ( 256 < < GetQuadrant ( item - > pos . yRot ) ) & GetClimbFlags ( x , item - > pos . yPos , z , item - > roomNumber ) )
2020-09-26 05:06:08 +10:00
{
2021-11-30 02:51:19 +03:00
if ( ! TestLaraHangOnClimbWall ( item , coll ) )
verticalShift = 0 ; // Ignore vertical shift if ladder is encountered next block
2020-09-26 05:06:08 +10:00
}
2021-10-23 15:35:59 +03:00
else if ( ! TestValidLedge ( item , coll , true ) )
2020-09-26 05:06:08 +10:00
{
2021-11-30 02:39:41 +03:00
if ( ( climbShift < 0 & & coll - > FrontLeft . Floor ! = coll - > Front . Floor ) | |
( climbShift > 0 & & coll - > FrontRight . Floor ! = coll - > Front . Floor ) )
stopped = true ;
2020-09-26 05:06:08 +10:00
}
2021-09-14 00:03:24 +03:00
2021-11-30 02:39:41 +03:00
if ( ! stopped & &
coll - > Middle . Ceiling < 0 & & coll - > CollisionType = = CT_FRONT & & ! coll - > HitStatic & &
abs ( verticalShift ) < SLOPE_DIFFERENCE & & TestValidLedgeAngle ( item , coll ) )
2020-09-26 05:06:08 +10:00
{
2021-10-23 15:35:59 +03:00
if ( item - > speed ! = 0 )
SnapItemToLedge ( item , coll ) ;
2021-09-14 00:03:24 +03:00
2021-11-30 02:39:41 +03:00
item - > pos . yPos + = verticalShift ;
2020-09-26 05:06:08 +10:00
}
else
{
2021-09-10 00:20:59 +03:00
item - > pos . xPos = coll - > Setup . OldPosition . x ;
item - > pos . yPos = coll - > Setup . OldPosition . y ;
item - > pos . zPos = coll - > Setup . OldPosition . z ;
2021-09-14 00:03:24 +03:00
2021-11-30 02:39:41 +03:00
if ( item - > currentAnimState = = LS_SHIMMY_LEFT | |
2021-11-10 02:01:43 +11:00
item - > currentAnimState = = LS_SHIMMY_RIGHT )
2020-09-26 05:06:08 +10:00
{
2021-11-10 02:41:59 +03:00
SetAnimation ( item , LA_REACH_TO_HANG , 21 ) ;
2020-09-26 05:06:08 +10:00
}
2021-09-14 00:03:24 +03:00
result = true ;
2020-09-26 05:06:08 +10:00
}
}
2021-11-30 02:51:19 +03:00
else // Death, incorrect ledge or action release
2020-09-26 05:06:08 +10:00
{
2021-11-10 02:41:59 +03:00
SetAnimation ( item , LA_JUMP_UP , 9 ) ;
2021-09-10 00:18:47 +03:00
item - > pos . xPos + = coll - > Shift . x ;
2021-11-23 01:03:58 +11:00
item - > pos . yPos + = GetBoundsAccurate ( item ) - > Y2 * 2.4f ;
2021-09-10 00:18:47 +03:00
item - > pos . zPos + = coll - > Shift . z ;
2020-09-26 05:06:08 +10:00
item - > gravityStatus = true ;
item - > speed = 2 ;
item - > fallspeed = 1 ;
2021-11-29 15:26:55 +11:00
info - > gunStatus = LG_HANDS_FREE ;
2020-09-26 05:06:08 +10:00
}
}
2021-09-14 00:03:24 +03:00
2020-09-26 05:06:08 +10:00
return result ;
}
2021-10-26 15:44:36 +03:00
CORNER_RESULT TestLaraHangCorner ( ITEM_INFO * item , COLL_INFO * coll , float testAngle )
2020-09-26 05:06:08 +10:00
{
2021-11-29 15:26:55 +11:00
LaraInfo * & info = item - > data ;
2021-10-26 12:50:26 +03:00
// Lara isn't in stop state yet, bypass test
2021-12-01 11:59:24 +03:00
if ( item - > animNumber ! = LA_REACH_TO_HANG )
2021-10-26 15:44:36 +03:00
return CORNER_RESULT : : NONE ;
2020-09-26 05:06:08 +10:00
2021-10-26 12:50:26 +03:00
// Static is in the way, bypass test
2021-09-10 00:18:47 +03:00
if ( coll - > HitStatic )
2021-10-26 15:44:36 +03:00
return CORNER_RESULT : : NONE ;
2020-09-26 05:06:08 +10:00
2021-10-26 12:50:26 +03:00
// INNER CORNER TESTS
2020-09-26 05:06:08 +10:00
2021-10-26 12:50:26 +03:00
// Backup old Lara position and frontal collision
auto oldPos = item - > pos ;
2021-11-30 22:37:46 +11:00
auto oldMoveAngle = Lara . moveAngle ;
2020-09-26 05:06:08 +10:00
2021-10-28 01:59:20 +03:00
// Do further testing only if test angle is equal to resulting edge angle
2021-11-29 18:09:34 +03:00
if ( SnapAndTestItemAtNextCornerPosition ( item , coll , testAngle , false ) )
2020-09-26 05:06:08 +10:00
{
2021-11-29 18:09:34 +03:00
// Get bounding box height for further ledge height calculations
auto bounds = GetBoundsAccurate ( item ) ;
2020-09-26 05:06:08 +10:00
2021-11-15 10:38:31 +03:00
// Store next position
2021-12-02 12:47:07 +11:00
info - > nextCornerPos . xPos = item - > pos . xPos ;
2021-12-13 18:25:34 +11:00
info - > nextCornerPos . yPos = LaraCollisionAboveFront ( item , item - > pos . yRot , coll - > Setup . Radius * 2 , abs ( bounds - > Y1 ) + LARA_HEADROOM ) . Position . Floor + abs ( bounds - > Y1 ) ;
2021-12-02 12:47:07 +11:00
info - > nextCornerPos . zPos = item - > pos . zPos ;
info - > nextCornerPos . yRot = item - > pos . yRot ;
2021-11-30 22:37:46 +11:00
info - > moveAngle = item - > pos . yRot ;
2021-11-30 02:39:41 +03:00
2021-10-28 01:59:20 +03:00
auto result = TestLaraValidHangPos ( item , coll ) ;
2021-10-26 12:50:26 +03:00
2021-11-29 18:21:50 +03:00
// Restore original item positions
item - > pos = oldPos ;
2021-11-30 22:37:46 +11:00
info - > moveAngle = oldMoveAngle ;
2021-10-27 02:24:55 +03:00
2021-11-30 02:39:41 +03:00
if ( result )
2021-11-29 18:21:50 +03:00
return CORNER_RESULT : : INNER ;
2021-10-27 02:24:55 +03:00
2021-11-29 15:26:55 +11:00
if ( info - > climbStatus )
2020-09-26 05:06:08 +10:00
{
2021-12-12 11:10:08 +03:00
auto & angleSet = testAngle > 0 ? LeftExtRightIntTab : LeftIntRightExtTab ;
if ( GetClimbFlags ( Lara . nextCornerPos . xPos , item - > pos . yPos , Lara . nextCornerPos . zPos , item - > roomNumber ) & ( short ) angleSet [ GetQuadrant ( item - > pos . yRot ) ] )
2021-12-12 11:39:35 +03:00
{
Lara . nextCornerPos . yPos = item - > pos . yPos ; // Restore original Y pos for ladder tests because we don't snap to ledge height in such case.
2021-10-28 01:59:20 +03:00
return CORNER_RESULT : : INNER ;
2021-12-12 11:39:35 +03:00
}
2020-09-26 05:06:08 +10:00
}
}
2021-10-27 02:24:55 +03:00
// Restore original item positions
item - > pos = oldPos ;
2021-12-02 12:47:07 +11:00
info - > moveAngle = oldMoveAngle ;
2020-09-26 05:06:08 +10:00
2021-10-26 12:50:26 +03:00
// OUTER CORNER TESTS
2020-09-26 05:06:08 +10:00
2021-10-26 13:39:42 +03:00
// Test if there's a material obstacles blocking outer corner pathway
2021-12-12 21:11:27 +11:00
if ( ( LaraFloorFront ( item , item - > pos . yRot + ANGLE ( testAngle ) , coll - > Setup . Radius + CLICK ( 1 ) ) < 0 ) | |
( LaraCeilingFront ( item , item - > pos . yRot + ANGLE ( testAngle ) , coll - > Setup . Radius + CLICK ( 1 ) , coll - > Setup . Height ) > 0 ) )
2021-10-26 15:44:36 +03:00
return CORNER_RESULT : : NONE ;
2020-09-26 05:06:08 +10:00
2021-10-28 01:13:28 +03:00
// Last chance for possible diagonal vs. non-diagonal cases: ray test
2021-12-12 21:11:27 +11:00
if ( ! LaraPositionOnLOS ( item , item - > pos . yRot + ANGLE ( testAngle ) , coll - > Setup . Radius + CLICK ( 1 ) ) )
2021-10-28 01:11:14 +03:00
return CORNER_RESULT : : NONE ;
2020-09-26 05:06:08 +10:00
2021-11-29 18:09:34 +03:00
bool snappable = SnapAndTestItemAtNextCornerPosition ( item , coll , testAngle , true ) ;
2020-09-26 05:06:08 +10:00
2021-11-29 18:21:50 +03:00
// Additional test if there's a material obstacles blocking outer corner pathway
if ( ( LaraFloorFront ( item , item - > pos . yRot , 0 ) < 0 ) | |
( LaraCeilingFront ( item , item - > pos . yRot , 0 , coll - > Setup . Height ) > 0 ) )
2021-11-30 02:39:41 +03:00
snappable = false ;
2021-11-29 18:21:50 +03:00
2021-10-28 01:59:20 +03:00
// Do further testing only if test angle is equal to resulting edge angle
2021-11-29 18:09:34 +03:00
if ( snappable )
2020-09-26 05:06:08 +10:00
{
2021-11-29 18:09:34 +03:00
// Get bounding box height for further ledge height calculations
auto bounds = GetBoundsAccurate ( item ) ;
2021-11-15 10:38:31 +03:00
// Store next position
2021-12-02 12:47:07 +11:00
info - > nextCornerPos . xPos = item - > pos . xPos ;
2021-12-13 18:25:34 +11:00
info - > nextCornerPos . yPos = LaraCollisionAboveFront ( item , item - > pos . yRot , coll - > Setup . Radius * 2 , abs ( bounds - > Y1 ) + LARA_HEADROOM ) . Position . Floor + abs ( bounds - > Y1 ) ;
2021-12-02 12:47:07 +11:00
info - > nextCornerPos . zPos = item - > pos . zPos ;
info - > nextCornerPos . yRot = item - > pos . yRot ;
2021-11-30 22:37:46 +11:00
info - > moveAngle = item - > pos . yRot ;
2020-09-26 05:06:08 +10:00
2021-11-29 18:21:50 +03:00
auto result = TestLaraValidHangPos ( item , coll ) ;
2020-09-26 05:06:08 +10:00
2021-11-29 18:21:50 +03:00
// Restore original item positions
item - > pos = oldPos ;
2021-11-30 22:37:46 +11:00
info - > moveAngle = oldMoveAngle ;
2021-11-29 18:21:50 +03:00
2021-11-30 02:39:41 +03:00
if ( result )
2021-11-29 18:21:50 +03:00
return CORNER_RESULT : : OUTER ;
2020-09-26 05:06:08 +10:00
2021-11-29 15:26:55 +11:00
if ( info - > climbStatus )
2020-09-26 05:06:08 +10:00
{
2021-12-12 11:10:08 +03:00
auto & angleSet = testAngle > 0 ? LeftIntRightExtTab : LeftExtRightIntTab ;
if ( GetClimbFlags ( Lara . nextCornerPos . xPos , item - > pos . yPos , Lara . nextCornerPos . zPos , item - > roomNumber ) & ( short ) angleSet [ GetQuadrant ( item - > pos . yRot ) ] )
2021-12-12 11:39:35 +03:00
{
Lara . nextCornerPos . yPos = item - > pos . yPos ; // Restore original Y pos for ladder tests because we don't snap to ledge height in such case.
2021-10-28 01:59:20 +03:00
return CORNER_RESULT : : OUTER ;
2021-12-12 11:39:35 +03:00
}
2020-09-26 05:06:08 +10:00
}
}
2021-10-27 02:24:55 +03:00
// Restore original item positions
item - > pos = oldPos ;
2021-12-02 12:47:07 +11:00
info - > moveAngle = oldMoveAngle ;
2020-09-26 05:06:08 +10:00
2021-10-27 02:24:55 +03:00
return CORNER_RESULT : : NONE ;
2020-09-26 05:06:08 +10:00
}
2021-10-26 15:44:36 +03:00
bool TestLaraValidHangPos ( ITEM_INFO * item , COLL_INFO * coll )
2020-09-26 05:06:08 +10:00
{
2021-11-29 15:26:55 +11:00
LaraInfo * & info = item - > data ;
2021-10-26 12:50:26 +03:00
// Get incoming ledge height and own Lara's upper bound.
// First one will be negative while first one is positive.
// Difference between two indicates difference in height between ledges.
2021-12-12 21:11:27 +11:00
auto frontFloor = LaraCollisionAboveFront ( item , info - > moveAngle , coll - > Setup . Radius + CLICK ( 0.5f ) , LARA_HEIGHT ) . Position . Floor ;
2021-10-26 12:50:26 +03:00
auto laraUpperBound = item - > pos . yPos - coll - > Setup . Height ;
2020-09-26 05:06:08 +10:00
2021-10-26 12:50:26 +03:00
// If difference is above 1/2 click, return false (ledge is out of reach).
2021-12-12 21:11:27 +11:00
if ( abs ( frontFloor - laraUpperBound ) > CLICK ( 0.5f ) )
2021-10-26 15:44:36 +03:00
return false ;
2020-09-26 05:06:08 +10:00
2021-10-26 12:50:26 +03:00
// Embed Lara into wall to make collision test succeed
item - > pos . xPos + = phd_sin ( item - > pos . yRot ) * 8 ;
item - > pos . zPos + = phd_cos ( item - > pos . yRot ) * 8 ;
2020-09-26 05:06:08 +10:00
2021-10-26 12:50:26 +03:00
// Setup new GCI call
2021-11-29 15:26:55 +11:00
info - > moveAngle = item - > pos . yRot ;
2021-09-19 17:48:32 +03:00
coll - > Setup . BadHeightDown = NO_BAD_POS ;
2021-12-12 11:55:11 +03:00
coll - > Setup . BadHeightUp = - CLICK ( 2 ) ;
2021-09-10 00:20:59 +03:00
coll - > Setup . BadCeilingHeight = 0 ;
2021-10-28 12:58:46 +03:00
coll - > Setup . Mode = COLL_PROBE_MODE : : FREE_FLAT ;
2021-11-29 15:26:55 +11:00
coll - > Setup . ForwardAngle = info - > moveAngle ;
2021-10-26 12:50:26 +03:00
2021-09-19 06:42:24 +03:00
GetCollisionInfo ( coll , item ) ;
2020-09-26 05:06:08 +10:00
2021-10-26 12:50:26 +03:00
// Filter out narrow ceiling spaces, no collision cases and statics in front.
2021-09-10 00:18:47 +03:00
if ( coll - > Middle . Ceiling > = 0 | | coll - > CollisionType ! = CT_FRONT | | coll - > HitStatic )
2021-10-26 15:44:36 +03:00
return false ;
2020-09-26 05:06:08 +10:00
2021-10-26 12:50:26 +03:00
// Finally, do ordinary ledge checks (slope difference etc.)
return TestValidLedge ( item , coll ) ;
2020-09-26 05:06:08 +10:00
}
2021-09-14 00:30:44 +03:00
bool TestLaraClimbStance ( ITEM_INFO * item , COLL_INFO * coll )
2020-09-26 05:06:08 +10:00
{
int shift_r , shift_l ;
2021-12-12 16:23:18 +03:00
if ( LaraTestClimbPos ( item , coll - > Setup . Radius , coll - > Setup . Radius + CLICK ( 0.5f ) , - 700 , CLICK ( 2 ) , & shift_r ) ! = 1 )
2020-09-26 05:06:08 +10:00
return false ;
2021-12-12 16:23:18 +03:00
if ( LaraTestClimbPos ( item , coll - > Setup . Radius , - ( coll - > Setup . Radius + CLICK ( 0.5f ) ) , - 700 , CLICK ( 2 ) , & shift_l ) ! = 1 )
2020-09-26 05:06:08 +10:00
return false ;
if ( shift_r )
{
if ( shift_l )
{
if ( shift_r < 0 ! = shift_l < 0 )
return false ;
if ( ( shift_r < 0 & & shift_l < shift_r ) | |
( shift_r > 0 & & shift_l > shift_r ) )
{
item - > pos . yPos + = shift_l ;
return true ;
}
}
item - > pos . yPos + = shift_r ;
}
else if ( shift_l )
{
item - > pos . yPos + = shift_l ;
}
return true ;
}
2021-09-14 00:30:44 +03:00
bool TestLaraHangOnClimbWall ( ITEM_INFO * item , COLL_INFO * coll )
2020-09-26 05:06:08 +10:00
{
2021-11-29 15:26:55 +11:00
LaraInfo * & info = item - > data ;
2020-09-26 05:06:08 +10:00
int shift , result ;
2021-11-29 15:26:55 +11:00
if ( info - > climbStatus = = 0 )
2021-09-13 09:12:46 +03:00
return false ;
2020-09-26 05:06:08 +10:00
if ( item - > fallspeed < 0 )
2021-09-13 09:12:46 +03:00
return false ;
2021-10-27 12:57:36 +03:00
// HACK: Climb wall tests are highly fragile and depend on quadrant shifts.
// Until climb wall tests are fully refactored, we need to recalculate COLL_INFO.
2021-10-27 13:05:41 +03:00
auto coll2 = * coll ;
coll2 . Setup . Mode = COLL_PROBE_MODE : : QUADRANTS ;
GetCollisionInfo ( & coll2 , item ) ;
2020-09-26 05:06:08 +10:00
switch ( GetQuadrant ( item - > pos . yRot ) )
{
case NORTH :
case SOUTH :
2021-10-27 13:05:41 +03:00
item - > pos . zPos + = coll2 . Shift . z ;
2020-09-26 05:06:08 +10:00
break ;
case EAST :
case WEST :
2021-10-27 13:05:41 +03:00
item - > pos . xPos + = coll2 . Shift . x ;
2020-09-26 05:06:08 +10:00
break ;
default :
break ;
}
2021-10-27 12:46:36 +03:00
auto bounds = GetBoundsAccurate ( item ) ;
2020-09-26 05:06:08 +10:00
2021-11-29 15:26:55 +11:00
if ( info - > moveAngle ! = item - > pos . yRot )
2020-09-26 05:06:08 +10:00
{
short l = LaraCeilingFront ( item , item - > pos . yRot , 0 , 0 ) ;
2021-12-12 21:11:27 +11:00
short r = LaraCeilingFront ( item , info - > moveAngle , CLICK ( 0.5f ) , 0 ) ;
2020-09-26 05:06:08 +10:00
2021-10-27 12:46:36 +03:00
if ( abs ( l - r ) > SLOPE_DIFFERENCE )
2021-09-13 09:12:46 +03:00
return false ;
2020-09-26 05:06:08 +10:00
}
2021-10-26 18:36:10 +03:00
if ( LaraTestClimbPos ( item , LARA_RAD , LARA_RAD , bounds - > Y1 , bounds - > Y2 - bounds - > Y1 , & shift ) & &
LaraTestClimbPos ( item , LARA_RAD , - LARA_RAD , bounds - > Y1 , bounds - > Y2 - bounds - > Y1 , & shift ) )
2020-09-26 05:06:08 +10:00
{
2021-10-26 18:36:10 +03:00
result = LaraTestClimbPos ( item , LARA_RAD , 0 , bounds - > Y1 , bounds - > Y2 - bounds - > Y1 , & shift ) ;
2020-09-26 05:06:08 +10:00
if ( result )
{
if ( result ! = 1 )
item - > pos . yPos + = shift ;
2021-11-10 02:01:43 +11:00
2021-09-13 09:12:46 +03:00
return true ;
2020-09-26 05:06:08 +10:00
}
}
2021-09-13 09:12:46 +03:00
return false ;
2020-09-26 05:06:08 +10:00
}
2021-09-14 00:30:44 +03:00
int TestLaraEdgeCatch ( ITEM_INFO * item , COLL_INFO * coll , int * edge )
2020-09-26 05:06:08 +10:00
{
BOUNDING_BOX * bounds = GetBoundsAccurate ( item ) ;
2021-09-10 00:18:47 +03:00
int hdif = coll - > Front . Floor - bounds - > Y1 ;
2020-09-26 05:06:08 +10:00
if ( hdif < 0 = = hdif + item - > fallspeed < 0 )
{
hdif = item - > pos . yPos + bounds - > Y1 ;
if ( ( hdif + item - > fallspeed & 0xFFFFFF00 ) ! = ( hdif & 0xFFFFFF00 ) )
{
if ( item - > fallspeed > 0 )
* edge = ( hdif + item - > fallspeed ) & 0xFFFFFF00 ;
else
* edge = hdif & 0xFFFFFF00 ;
return - 1 ;
}
return 0 ;
}
2021-10-23 12:53:55 +03:00
if ( ! TestValidLedge ( item , coll , true ) )
2020-09-26 05:06:08 +10:00
return 0 ;
return 1 ;
}
2021-09-13 09:12:46 +03:00
bool TestHangSwingIn ( ITEM_INFO * item , short angle )
2020-09-26 05:06:08 +10:00
{
2021-11-29 15:26:55 +11:00
LaraInfo * & info = item - > data ;
2020-09-26 05:06:08 +10:00
int x = item - > pos . xPos ;
int y = item - > pos . yPos ;
int z = item - > pos . zPos ;
short roomNum = item - > roomNumber ;
FLOOR_INFO * floor ;
2021-11-10 02:01:43 +11:00
int floorHeight , ceilingHeight ;
2020-09-26 05:06:08 +10:00
2021-12-12 21:11:27 +11:00
z + = phd_cos ( angle ) * CLICK ( 0.5f ) ;
x + = phd_sin ( angle ) * CLICK ( 0.5f ) ;
2020-09-26 05:06:08 +10:00
floor = GetFloor ( x , y , z , & roomNum ) ;
2021-11-10 02:01:43 +11:00
floorHeight = GetFloorHeight ( floor , x , y , z ) ;
ceilingHeight = GetCeiling ( floor , x , y , z ) ;
2020-09-26 05:06:08 +10:00
2021-11-10 02:01:43 +11:00
if ( floorHeight ! = NO_HEIGHT )
2020-09-26 05:06:08 +10:00
{
2021-12-02 12:47:07 +11:00
if ( g_GameFlow - > Animations . OscillateHang )
2020-09-26 05:06:08 +10:00
{
2021-11-10 02:01:43 +11:00
if ( floorHeight - y > 0 & & ceilingHeight - y < - 400 )
2021-09-13 09:12:46 +03:00
return true ;
2020-09-26 05:06:08 +10:00
}
else
2021-07-09 19:41:56 -05:00
{
2021-11-10 02:01:43 +11:00
if ( floorHeight - y > 0 & & ceilingHeight - y < - 400 & & ( y - 819 - ceilingHeight > - 72 ) )
2021-09-13 09:12:46 +03:00
return true ;
2021-07-09 19:41:56 -05:00
}
2020-09-26 05:06:08 +10:00
}
2021-09-13 09:12:46 +03:00
return false ;
2021-07-09 19:41:56 -05:00
}
2020-09-26 05:06:08 +10:00
2021-09-14 00:30:44 +03:00
bool TestLaraHangSideways ( ITEM_INFO * item , COLL_INFO * coll , short angle )
2020-09-26 05:06:08 +10:00
{
2021-11-29 15:26:55 +11:00
LaraInfo * & info = item - > data ;
2021-12-01 11:59:24 +03:00
auto oldPos = item - > pos ;
2020-09-26 05:06:08 +10:00
2021-12-15 15:21:39 +03:00
Lara . moveAngle = item - > pos . yRot + angle ;
2021-12-01 11:59:24 +03:00
static constexpr auto sidewayTestDistance = 16 ;
2021-12-02 12:47:07 +11:00
item - > pos . xPos + = phd_sin ( info - > moveAngle ) * sidewayTestDistance ;
item - > pos . zPos + = phd_cos ( info - > moveAngle ) * sidewayTestDistance ;
2020-09-26 05:06:08 +10:00
2021-09-10 00:20:59 +03:00
coll - > Setup . OldPosition . y = item - > pos . yPos ;
2020-09-26 05:06:08 +10:00
2021-09-14 00:30:44 +03:00
auto res = TestLaraHang ( item , coll ) ;
2020-09-26 05:06:08 +10:00
2021-12-01 11:59:24 +03:00
item - > pos = oldPos ;
2020-09-26 05:06:08 +10:00
return ! res ;
}
2021-11-03 21:44:48 +11:00
bool TestLaraStandingJump ( ITEM_INFO * item , COLL_INFO * coll , short angle )
{
auto y = item - > pos . yPos ;
2021-12-12 21:11:27 +11:00
auto probe = GetCollisionResult ( item , angle , CLICK ( 1 ) , coll - > Setup . Height ) ;
2021-12-12 02:36:46 +11:00
// TODO: Ceiling test interfered with bridges. For now, behaves as original.
2021-12-12 21:11:27 +11:00
if ( ! TestLaraFacingCorner ( item , angle , CLICK ( 1 ) ) & &
2021-12-12 02:36:46 +11:00
probe . Position . Floor + probe . Position . Bridge - y > = - STEPUP_HEIGHT & & // Highest floor bound.
probe . Position . Floor ! = NO_HEIGHT )
2021-11-03 21:44:48 +11:00
{
return true ;
}
return false ;
}
2021-10-16 23:51:42 +11:00
bool TestLaraFacingCorner ( ITEM_INFO * item , short angle , int dist )
2021-08-29 23:53:58 +03:00
{
2021-11-23 13:53:35 +11:00
auto angle1 = angle + ANGLE ( 15.0f ) ;
auto angle2 = angle - ANGLE ( 15.0f ) ;
2021-10-16 22:53:29 +11:00
2021-11-23 13:53:35 +11:00
auto vec1 = GAME_VECTOR ( item - > pos . xPos + dist * phd_sin ( angle1 ) ,
2021-11-30 22:37:46 +11:00
item - > pos . yPos - STEPUP_HEIGHT ,
item - > pos . zPos + dist * phd_cos ( angle1 ) ,
2021-08-29 23:53:58 +03:00
item - > roomNumber ) ;
2021-11-23 13:53:35 +11:00
auto vec2 = GAME_VECTOR ( item - > pos . xPos + dist * phd_sin ( angle2 ) ,
2021-11-30 22:37:46 +11:00
item - > pos . yPos - STEPUP_HEIGHT ,
2021-08-29 23:53:58 +03:00
item - > pos . zPos + dist * phd_cos ( angle2 ) ,
item - > roomNumber ) ;
2021-11-20 17:52:18 +11:00
auto pos = GAME_VECTOR ( item - > pos . xPos ,
2021-11-30 22:37:46 +11:00
item - > pos . yPos - STEPUP_HEIGHT ,
2021-08-29 23:53:58 +03:00
item - > pos . zPos ,
item - > roomNumber ) ;
2021-11-23 13:53:35 +11:00
auto result1 = LOS ( & pos , & vec1 ) ;
auto result2 = LOS ( & pos , & vec2 ) ;
2021-08-29 23:53:58 +03:00
2021-11-29 18:34:37 +03:00
return ( ( result1 = = 0 ) & & ( result2 = = 0 ) ) ;
2021-08-29 23:53:58 +03:00
}
2021-10-28 01:11:14 +03:00
bool LaraPositionOnLOS ( ITEM_INFO * item , short ang , int dist )
{
auto pos1 = GAME_VECTOR ( item - > pos . xPos ,
item - > pos . yPos - LARA_HEADROOM ,
item - > pos . zPos ,
item - > roomNumber ) ;
auto pos2 = GAME_VECTOR ( item - > pos . xPos ,
item - > pos . yPos - LARA_HEIGHT + LARA_HEADROOM ,
item - > pos . zPos ,
item - > roomNumber ) ;
auto vec1 = GAME_VECTOR ( item - > pos . xPos + dist * phd_sin ( ang ) ,
item - > pos . yPos - LARA_HEADROOM ,
item - > pos . zPos + dist * phd_cos ( ang ) ,
item - > roomNumber ) ;
auto vec2 = GAME_VECTOR ( item - > pos . xPos + dist * phd_sin ( ang ) ,
item - > pos . yPos - LARA_HEIGHT + LARA_HEADROOM ,
item - > pos . zPos + dist * phd_cos ( ang ) ,
item - > roomNumber ) ;
auto result1 = LOS ( & pos1 , & vec1 ) ;
auto result2 = LOS ( & pos2 , & vec2 ) ;
return ( result1 ! = 0 & & result2 ! = 0 ) ;
}
2021-02-06 11:50:08 -03:00
int LaraFloorFront ( ITEM_INFO * item , short ang , int dist )
2021-08-24 16:54:26 +03:00
{
2021-09-10 00:43:26 +03:00
return LaraCollisionFront ( item , ang , dist ) . Position . Floor ;
2021-08-24 16:54:26 +03:00
}
COLL_RESULT LaraCollisionFront ( ITEM_INFO * item , short ang , int dist )
2020-09-26 05:06:08 +10:00
{
2021-11-20 12:25:51 +11:00
auto probe = GetCollisionResult ( item , ang , dist , - LARA_HEIGHT ) ;
2020-09-26 05:06:08 +10:00
2021-11-20 12:25:51 +11:00
if ( probe . Position . Floor ! = NO_HEIGHT )
probe . Position . Floor - = item - > pos . yPos ;
2020-09-26 05:06:08 +10:00
2021-11-20 12:25:51 +11:00
return probe ;
2020-09-26 05:06:08 +10:00
}
2021-10-03 22:09:19 +03:00
COLL_RESULT LaraCollisionAboveFront ( ITEM_INFO * item , short ang , int dist , int h )
{
int x = item - > pos . xPos + dist * phd_sin ( ang ) ;
int y = item - > pos . yPos - h ;
int z = item - > pos . zPos + dist * phd_cos ( ang ) ;
return GetCollisionResult ( x , y , z , GetCollisionResult ( item - > pos . xPos , y , item - > pos . zPos , item - > roomNumber ) . RoomNumber ) ;
}
2021-02-06 11:50:08 -03:00
int LaraCeilingFront ( ITEM_INFO * item , short ang , int dist , int h )
2021-08-24 16:54:26 +03:00
{
2021-09-10 00:43:26 +03:00
return LaraCeilingCollisionFront ( item , ang , dist , h ) . Position . Ceiling ;
2021-08-24 16:54:26 +03:00
}
COLL_RESULT LaraCeilingCollisionFront ( ITEM_INFO * item , short ang , int dist , int h )
2020-09-26 05:06:08 +10:00
{
2021-11-20 12:25:51 +11:00
auto probe = GetCollisionResult ( item , ang , dist , - h ) ;
2020-09-26 05:06:08 +10:00
2021-11-20 12:25:51 +11:00
if ( probe . Position . Ceiling ! = NO_HEIGHT )
probe . Position . Ceiling + = h - item - > pos . yPos ;
2020-09-26 05:06:08 +10:00
2021-11-20 12:25:51 +11:00
return probe ;
2020-09-26 05:06:08 +10:00
}
2021-11-23 13:53:35 +11:00
bool TestLaraFall ( ITEM_INFO * item , COLL_INFO * coll )
2020-09-26 05:06:08 +10:00
{
2021-11-20 12:25:51 +11:00
LaraInfo * & info = item - > data ;
2021-11-23 13:53:35 +11:00
if ( coll - > Middle . Floor < = STEPUP_HEIGHT | |
info - > waterStatus = = LW_WADE ) // TODO: This causes a legacy floor snap bug when lara wades off a ledge into a dry room. @Sezz 2021.09.26
2020-09-26 05:06:08 +10:00
{
2021-09-13 09:12:46 +03:00
return false ;
2020-09-26 05:06:08 +10:00
}
2021-11-23 13:53:35 +11:00
return true ;
}
// TODO: Gradually replace calls.
bool LaraFallen ( ITEM_INFO * item , COLL_INFO * coll )
{
LaraInfo * & info = item - > data ;
if ( info - > waterStatus = = LW_WADE | | coll - > Middle . Floor < = STEPUP_HEIGHT )
return false ;
2021-11-20 12:25:51 +11:00
SetAnimation ( item , LA_FALL_START ) ;
2020-09-26 05:06:08 +10:00
item - > fallspeed = 0 ;
item - > gravityStatus = true ;
2021-11-20 12:25:51 +11:00
2021-09-13 09:12:46 +03:00
return true ;
2020-09-26 05:06:08 +10:00
}
2021-09-13 09:12:46 +03:00
bool LaraLandedBad ( ITEM_INFO * item , COLL_INFO * coll )
2020-09-26 05:06:08 +10:00
{
int landspeed = item - > fallspeed - 140 ;
if ( landspeed > 0 )
{
if ( landspeed < = 14 )
{
item - > hitPoints - = 1000 * SQUARE ( landspeed ) / 196 ;
2021-11-20 12:25:51 +11:00
2020-09-26 05:06:08 +10:00
return item - > hitPoints < = 0 ;
}
else
{
item - > hitPoints = - 1 ;
2021-11-20 12:25:51 +11:00
2021-09-13 09:12:46 +03:00
return true ;
2020-09-26 05:06:08 +10:00
}
}
2021-09-13 09:12:46 +03:00
return false ;
2020-09-26 05:06:08 +10:00
}
2021-09-13 09:12:46 +03:00
2021-11-09 23:26:31 +11:00
bool TestLaraWaterStepOut ( ITEM_INFO * item , COLL_INFO * coll )
{
2021-11-29 15:26:55 +11:00
LaraInfo * & info = item - > data ;
2021-11-09 23:26:31 +11:00
if ( coll - > CollisionType = = CT_FRONT | |
coll - > Middle . Slope | |
coll - > Middle . Floor > = 0 )
{
return false ;
}
2021-12-12 21:11:27 +11:00
if ( coll - > Middle . Floor > = - CLICK ( 0.5f ) )
2021-11-09 23:26:31 +11:00
{
2021-11-10 02:41:59 +03:00
SetAnimation ( item , LA_STAND_IDLE ) ;
2021-11-09 23:26:31 +11:00
}
else
{
2021-11-10 02:41:59 +03:00
SetAnimation ( item , LA_ONWATER_TO_WADE_1CLICK ) ;
2021-11-25 23:38:59 +11:00
item - > goalAnimState = LS_IDLE ;
2021-11-09 23:26:31 +11:00
}
2021-12-12 21:11:27 +11:00
item - > pos . yPos + = coll - > Middle . Floor + CLICK ( 2.75f ) - 9 ;
2021-11-09 23:26:31 +11:00
UpdateItemRoom ( item , - ( STEPUP_HEIGHT - 3 ) ) ;
item - > pos . zRot = 0 ;
item - > pos . xRot = 0 ;
item - > gravityStatus = false ;
item - > speed = 0 ;
item - > fallspeed = 0 ;
2021-11-29 15:26:55 +11:00
info - > waterStatus = LW_WADE ;
2021-11-09 23:26:31 +11:00
return true ;
}
bool TestLaraWaterClimbOut ( ITEM_INFO * item , COLL_INFO * coll )
{
2021-11-21 13:47:55 +11:00
LaraInfo * & info = item - > data ;
2021-11-09 23:26:31 +11:00
if ( coll - > CollisionType ! = CT_FRONT | | ! ( TrInput & IN_ACTION ) )
return false ;
2021-11-21 13:47:55 +11:00
if ( info - > gunStatus & &
( info - > gunStatus ! = LG_READY | | info - > gunType ! = WEAPON_FLARE ) )
2021-11-09 23:26:31 +11:00
{
return false ;
}
if ( coll - > Middle . Ceiling > - STEPUP_HEIGHT )
return false ;
int frontFloor = coll - > Front . Floor + LARA_HEIGHT_SURFSWIM ;
2021-12-12 21:11:27 +11:00
if ( frontFloor < = - CLICK ( 2 ) | |
frontFloor > CLICK ( 1.25f ) - 4 )
2021-11-09 23:26:31 +11:00
{
return false ;
}
if ( ! TestValidLedge ( item , coll ) )
return false ;
2021-12-12 21:11:27 +11:00
auto surface = LaraCollisionAboveFront ( item , coll - > Setup . ForwardAngle , CLICK ( 2 ) , CLICK ( 1 ) ) ;
2021-11-09 23:26:31 +11:00
auto headroom = surface . Position . Floor - surface . Position . Ceiling ;
2021-12-12 21:11:27 +11:00
if ( frontFloor < = - CLICK ( 1 ) )
2021-11-09 23:26:31 +11:00
{
if ( headroom < LARA_HEIGHT )
{
2021-12-02 12:47:07 +11:00
if ( g_GameFlow - > Animations . CrawlExtended )
2021-11-10 11:59:54 +03:00
SetAnimation ( item , LA_ONWATER_TO_CROUCH_1CLICK ) ;
2021-11-09 23:26:31 +11:00
else
return false ;
}
else
2021-11-10 11:59:54 +03:00
SetAnimation ( item , LA_ONWATER_TO_STAND_1CLICK ) ;
2021-11-09 23:26:31 +11:00
}
2021-12-12 21:11:27 +11:00
else if ( frontFloor > CLICK ( 0.5f ) )
2021-11-09 23:26:31 +11:00
{
if ( headroom < LARA_HEIGHT )
{
2021-12-02 12:47:07 +11:00
if ( g_GameFlow - > Animations . CrawlExtended )
2021-11-10 11:59:54 +03:00
SetAnimation ( item , LA_ONWATER_TO_CROUCH_M1CLICK ) ;
2021-11-09 23:26:31 +11:00
else
return false ;
}
else
2021-11-10 11:59:54 +03:00
SetAnimation ( item , LA_ONWATER_TO_STAND_M1CLICK ) ;
2021-11-09 23:26:31 +11:00
}
else
{
if ( headroom < LARA_HEIGHT )
{
2021-12-02 12:47:07 +11:00
if ( g_GameFlow - > Animations . CrawlExtended )
2021-11-10 11:59:54 +03:00
SetAnimation ( item , LA_ONWATER_TO_CROUCH_0CLICK ) ;
2021-11-09 23:26:31 +11:00
else
return false ;
}
else
2021-11-10 11:59:54 +03:00
SetAnimation ( item , LA_ONWATER_TO_STAND_0CLICK ) ;
2021-11-09 23:26:31 +11:00
}
UpdateItemRoom ( item , - LARA_HEIGHT / 2 ) ;
SnapItemToLedge ( item , coll , 1.7f ) ;
item - > pos . yPos + = frontFloor - 5 ;
item - > currentAnimState = LS_ONWATER_EXIT ;
item - > gravityStatus = false ;
item - > speed = 0 ;
item - > fallspeed = 0 ;
2021-11-21 13:47:55 +11:00
info - > gunStatus = LG_HANDS_BUSY ;
info - > waterStatus = LW_ABOVE_WATER ;
2021-11-09 23:26:31 +11:00
return true ;
}
bool TestLaraLadderClimbOut ( ITEM_INFO * item , COLL_INFO * coll ) // NEW function for water to ladder move
{
2021-11-29 15:26:55 +11:00
LaraInfo * & info = item - > data ;
2021-11-09 23:26:31 +11:00
if ( ! ( TrInput & IN_ACTION ) | |
2021-11-29 15:26:55 +11:00
! info - > climbStatus | |
2021-11-09 23:26:31 +11:00
coll - > CollisionType ! = CT_FRONT )
{
return false ;
}
2021-11-29 15:26:55 +11:00
if ( info - > gunStatus & &
( info - > gunStatus ! = LG_READY | | info - > gunType ! = WEAPON_FLARE ) )
2021-11-09 23:26:31 +11:00
{
return false ;
}
if ( ! TestLaraClimbStance ( item , coll ) )
return false ;
short rot = item - > pos . yRot ;
if ( rot > = - ANGLE ( 35.0f ) & & rot < = ANGLE ( 35.0f ) )
rot = 0 ;
else if ( rot > = ANGLE ( 55.0f ) & & rot < = ANGLE ( 125.0f ) )
rot = ANGLE ( 90.0f ) ;
else if ( rot > = ANGLE ( 145.0f ) | | rot < = - ANGLE ( 145.0f ) )
rot = ANGLE ( 180.0f ) ;
else if ( rot > = - ANGLE ( 125.0f ) & & rot < = - ANGLE ( 55.0f ) )
rot = - ANGLE ( 90.0f ) ;
if ( rot & 0x3FFF )
return false ;
switch ( ( unsigned short ) rot / ANGLE ( 90.0f ) )
{
case NORTH :
item - > pos . zPos = ( item - > pos . zPos | ( WALL_SIZE - 1 ) ) - LARA_RAD - 1 ;
break ;
case EAST :
item - > pos . xPos = ( item - > pos . xPos | ( WALL_SIZE - 1 ) ) - LARA_RAD - 1 ;
break ;
case SOUTH :
item - > pos . zPos = ( item - > pos . zPos & - WALL_SIZE ) + LARA_RAD + 1 ;
break ;
case WEST :
item - > pos . xPos = ( item - > pos . xPos & - WALL_SIZE ) + LARA_RAD + 1 ;
break ;
}
2021-11-10 02:41:59 +03:00
SetAnimation ( item , LA_ONWATER_IDLE ) ;
2021-11-09 23:26:31 +11:00
item - > goalAnimState = LS_LADDER_IDLE ;
AnimateLara ( item ) ;
item - > pos . yRot = rot ;
item - > pos . yPos - = 10 ; //otherwise she falls back into the water
item - > pos . zRot = 0 ;
item - > pos . xRot = 0 ;
item - > gravityStatus = false ;
item - > speed = 0 ;
item - > fallspeed = 0 ;
2021-11-29 15:26:55 +11:00
info - > gunStatus = LG_HANDS_BUSY ;
info - > waterStatus = LW_ABOVE_WATER ;
2021-11-09 23:26:31 +11:00
return true ;
}
2021-11-10 01:32:54 +11:00
void TestLaraWaterDepth ( ITEM_INFO * item , COLL_INFO * coll )
{
2021-11-29 15:26:55 +11:00
LaraInfo * & info = item - > data ;
2021-11-10 01:32:54 +11:00
short roomNumber = item - > roomNumber ;
FLOOR_INFO * floor = GetFloor ( item - > pos . xPos , item - > pos . yPos , item - > pos . zPos , & roomNumber ) ;
int waterDepth = GetWaterDepth ( item - > pos . xPos , item - > pos . yPos , item - > pos . zPos , roomNumber ) ;
if ( waterDepth = = NO_HEIGHT )
{
item - > fallspeed = 0 ;
item - > pos . xPos = coll - > Setup . OldPosition . x ;
item - > pos . yPos = coll - > Setup . OldPosition . y ;
item - > pos . zPos = coll - > Setup . OldPosition . z ;
}
2021-12-12 21:11:27 +11:00
// Height check was at CLICK(2) before but changed to this
2021-11-10 01:32:54 +11:00
// because now Lara surfaces on a head level, not mid-body level.
2021-12-10 09:09:09 +11:00
else if ( waterDepth < = LARA_HEIGHT - LARA_HEADROOM / 2 )
2021-11-10 01:32:54 +11:00
{
2021-11-10 02:41:59 +03:00
SetAnimation ( item , LA_UNDERWATER_TO_STAND ) ;
2021-11-25 23:38:59 +11:00
item - > goalAnimState = LS_IDLE ;
2021-11-10 01:32:54 +11:00
item - > pos . zRot = 0 ;
item - > pos . xRot = 0 ;
item - > speed = 0 ;
item - > fallspeed = 0 ;
item - > gravityStatus = false ;
2021-11-29 15:26:55 +11:00
info - > waterStatus = LW_WADE ;
2021-11-10 01:32:54 +11:00
item - > pos . yPos = GetFloorHeight ( floor , item - > pos . xPos , item - > pos . yPos , item - > pos . zPos ) ;
}
}
2021-09-05 14:49:00 +02:00
# ifndef NEW_TIGHTROPE
void GetTighRopeFallOff ( int regularity ) {
2021-11-23 13:53:35 +11:00
if ( LaraItem - > hitPoints < = 0 | | LaraItem - > hitStatus )
2021-11-10 02:41:59 +03:00
SetAnimation ( LaraItem , LA_TIGHTROPE_FALL_LEFT ) ;
2020-09-26 05:06:08 +10:00
2021-11-29 15:26:55 +11:00
if ( ! info - > tightRopeFall & & ! ( GetRandomControl ( ) & regularity ) )
info - > tightRopeFall = 2 - ( ( GetRandomControl ( ) & 0xF ) ! = 0 ) ;
2020-09-26 05:06:08 +10:00
}
2021-11-23 13:53:35 +11:00
# endif
2021-11-05 17:50:53 +11:00
2021-10-16 20:50:16 +11:00
bool IsStandingWeapon ( LARA_WEAPON_TYPE gunType )
{
2021-11-05 17:50:53 +11:00
if ( gunType = = LARA_WEAPON_TYPE : : WEAPON_SHOTGUN | |
gunType = = LARA_WEAPON_TYPE : : WEAPON_HK | |
gunType = = LARA_WEAPON_TYPE : : WEAPON_CROSSBOW | |
gunType = = LARA_WEAPON_TYPE : : WEAPON_TORCH | |
gunType = = LARA_WEAPON_TYPE : : WEAPON_GRENADE_LAUNCHER | |
gunType = = LARA_WEAPON_TYPE : : WEAPON_HARPOON_GUN | |
gunType = = LARA_WEAPON_TYPE : : WEAPON_ROCKET_LAUNCHER | |
gunType = = LARA_WEAPON_TYPE : : WEAPON_SNOWMOBILE )
2021-10-16 20:50:16 +11:00
{
return true ;
}
return false ;
}
2021-10-31 18:33:39 +11:00
bool TestLaraPose ( ITEM_INFO * item , COLL_INFO * coll )
{
2021-11-20 12:25:51 +11:00
LaraInfo * & info = item - > data ;
2021-11-13 22:36:46 +11:00
if ( ! TestLaraSwamp ( item ) & &
2021-11-25 23:38:59 +11:00
info - > gunStatus = = LG_HANDS_FREE & & // Hands are free.
2021-11-23 13:53:35 +11:00
! ( TrInput & ( IN_FLARE | IN_DRAW ) ) & & // Avoid unsightly concurrent actions.
2021-11-20 12:25:51 +11:00
( info - > gunType ! = WEAPON_FLARE | | info - > flareAge > 0 ) & & // Flare is not being handled. TODO: Will she pose with weapons drawn?
2021-11-23 13:53:35 +11:00
info - > Vehicle = = NO_ITEM ) // Not in a vehicle.
2021-10-31 18:33:39 +11:00
{
return true ;
}
return false ;
}
2021-10-16 20:50:16 +11:00
bool TestLaraStep ( COLL_INFO * coll )
{
2021-11-28 22:45:08 +11:00
if ( abs ( coll - > Middle . Floor ) > 0 & &
//coll->Middle.Floor <= STEPUP_HEIGHT && // Lower floor bound. BUG: Wading in water over a pit, Lara will not descend.
coll - > Middle . Floor > = - STEPUP_HEIGHT & & // Upper floor bound.
coll - > Middle . Floor ! = NO_HEIGHT )
2021-10-16 20:50:16 +11:00
{
return true ;
}
return false ;
}
bool TestLaraStepUp ( ITEM_INFO * item , COLL_INFO * coll )
{
2021-12-12 21:11:27 +11:00
if ( coll - > Middle . Floor < - CLICK ( 0.5f ) & & // Lower floor bound.
2021-11-07 23:58:51 +11:00
coll - > Middle . Floor > = - STEPUP_HEIGHT & & // Upper floor bound.
item - > currentAnimState ! = LS_CRAWL_IDLE & & // Crawl step up handled differently.
2021-10-18 20:15:53 +11:00
item - > currentAnimState ! = LS_CRAWL_FORWARD )
2021-10-16 20:50:16 +11:00
{
return true ;
}
return false ;
}
bool TestLaraStepDown ( ITEM_INFO * item , COLL_INFO * coll )
{
2021-12-12 21:11:27 +11:00
if ( coll - > Middle . Floor > CLICK ( 0.5f ) & & // Upper floor bound.
2021-11-05 17:50:53 +11:00
coll - > Middle . Floor < = STEPUP_HEIGHT & & // Lower floor bound.
2021-12-12 21:11:27 +11:00
item - > currentAnimState ! = LS_CRAWL_IDLE & & // Crawl step down handled differently.
2021-10-18 20:15:53 +11:00
item - > currentAnimState ! = LS_CRAWL_FORWARD )
2021-10-16 20:50:16 +11:00
{
return true ;
}
return false ;
2020-12-21 13:16:29 -03:00
}
2021-09-26 20:59:16 +10:00
2021-12-10 12:30:23 +11:00
// TODO: This function and its clone below should become obsolete with more accurate and accessible collision detection in the future.
2021-10-24 20:43:02 +11:00
// For now, it supercedes old probes and is used alongside COLL_INFO. @Sezz 2021.10.24
2021-11-30 22:29:15 +11:00
bool TestLaraMove ( ITEM_INFO * item , COLL_INFO * coll , short angle , int lowerBound , int upperBound , bool checkSlope , bool checkDeath )
2021-10-22 00:07:24 +11:00
{
auto y = item - > pos . yPos ;
2021-11-23 13:53:35 +11:00
auto probe = GetCollisionResult ( item , angle , coll - > Setup . Radius * sqrt ( 2 ) + 4 , 0 ) ; // Offset required to account for gap between Lara and the wall. Results in slight overshoot, but avoids oscillation.
2021-12-05 18:01:36 +11:00
auto isSlope = checkSlope ? probe . Position . Slope : false ;
auto isDeath = checkDeath ? probe . Block - > Flags . Death : false ;
2021-10-25 23:24:34 +11:00
2021-11-12 23:34:55 +11:00
if ( ( probe . Position . Floor - y ) < = lowerBound & & // Lower floor bound.
( probe . Position . Floor - y ) > = upperBound & & // Upper floor bound.
2021-12-05 18:01:36 +11:00
( probe . Position . Ceiling - y ) < - coll - > Setup . Height & & // Lowest ceiling bound.
abs ( probe . Position . Ceiling - probe . Position . Floor ) > coll - > Setup . Height & & // Space is not a clamp.
! isSlope & & ! isDeath & & // No slope or death sector (if applicable).
2021-10-24 20:43:02 +11:00
probe . Position . Floor ! = NO_HEIGHT )
2021-10-22 00:07:24 +11:00
{
return true ;
}
return false ;
}
2021-12-10 12:30:23 +11:00
// HACK: coll->Setup.Radius and coll->Setup.Height are only set
// in COLLISION functions, then reset by LaraAboveWater() to defaults.
// This means they will store the wrong values for tests called in crawl CONTROL functions.
// When states become objects, collision setup should occur at the beginning of each state, eliminating the need
// for this clone function. @Sezz 2021.12.05
bool TestLaraMoveCrawl ( ITEM_INFO * item , COLL_INFO * coll , short angle , int lowerBound , int upperBound , bool checkSlope , bool checkDeath )
{
auto y = item - > pos . yPos ;
auto probe = GetCollisionResult ( item , angle , LARA_RAD_CRAWL * sqrt ( 2 ) + 4 , 0 ) ; // Offset required to account for gap between Lara and the wall. Results in slight overshoot, but avoids oscillation.
auto isSlope = checkSlope ? probe . Position . Slope : false ;
auto isDeath = checkDeath ? probe . Block - > Flags . Death : false ;
if ( ( probe . Position . Floor - y ) < = lowerBound & & // Lower floor bound.
( probe . Position . Floor - y ) > = upperBound & & // Upper floor bound.
( probe . Position . Ceiling - y ) < - LARA_HEIGHT_CRAWL & & // Lowest ceiling bound.
abs ( probe . Position . Ceiling - probe . Position . Floor ) > LARA_HEIGHT_CRAWL & & // Space is not a clamp.
! isSlope & & ! isDeath & & // No slope or death sector (if applicable).
probe . Position . Floor ! = NO_HEIGHT )
{
return true ;
}
return false ;
}
2021-10-28 23:22:28 +11:00
bool TestLaraRunForward ( ITEM_INFO * item , COLL_INFO * coll )
{
auto y = item - > pos . yPos - coll - > Setup . Height ;
2021-12-01 01:13:22 +11:00
auto probe = GetCollisionResult ( item , item - > pos . yRot , coll - > Setup . Radius * sqrt ( 2 ) + 4 , 0 ) ;
2021-11-02 14:22:58 +11:00
2021-12-05 18:01:36 +11:00
// Hack to ensure Lara can run off diagonal ledges and stops on slanted ceilings. coll->Front.Floor often holds the wrong height because of quadrant-dependent wall pushing. @Sezz 2021.11.06
2021-11-12 23:34:55 +11:00
// BUG: This interferes with the one-step stand-to-crouch vault where the ceiling is lower than Lara's height.
2021-12-02 23:45:19 +11:00
if ( ( probe . Position . Ceiling - y ) < 0 )
2021-10-28 23:22:28 +11:00
return true ;
return false ;
2021-12-05 18:01:36 +11:00
// TODO: TestLaraMove() call not useful yet; it can block Lara from climbing. @Sezz 2021.10.28
2021-11-30 22:29:15 +11:00
//return TestLaraMove(item, coll, item->pos.yRot, STEPUP_HEIGHT, -STEPUP_HEIGHT, false); // Using BadHeightUp/Down defined in walk and run state collision functions.
2021-10-28 23:22:28 +11:00
}
bool TestLaraWalkForward ( ITEM_INFO * item , COLL_INFO * coll )
2021-10-22 00:07:24 +11:00
{
2021-10-28 23:22:28 +11:00
if ( coll - > CollisionType ! = CT_FRONT & &
coll - > CollisionType ! = CT_TOP_FRONT )
{
return true ;
}
2021-10-29 21:41:00 +11:00
return false ;
2021-11-05 17:50:53 +11:00
// TODO: Same issues as in TestLaraRunForward().
2021-11-30 22:29:15 +11:00
//return TestLaraMove(item, coll, item->pos.yRot, STEPUP_HEIGHT, -STEPUP_HEIGHT, true, true); // Using BadHeightUp/Down defined in walk and run state collision functions.
2021-10-22 00:07:24 +11:00
}
2021-10-24 20:43:02 +11:00
bool TestLaraWalkBack ( ITEM_INFO * item , COLL_INFO * coll )
2021-10-04 22:02:02 +11:00
{
2021-12-05 18:01:36 +11:00
return TestLaraMove ( item , coll , item - > pos . yRot + ANGLE ( 180.0f ) , STEPUP_HEIGHT , - STEPUP_HEIGHT ) ; // Using BadHeightUp/Down defined in walk back state collision function.
2021-10-19 21:28:36 +11:00
}
2021-10-24 20:43:02 +11:00
bool TestLaraHopBack ( ITEM_INFO * item , COLL_INFO * coll )
2021-10-19 21:28:36 +11:00
{
2021-12-05 18:01:36 +11:00
return TestLaraMove ( item , coll , item - > pos . yRot + ANGLE ( 180.0f ) , NO_BAD_POS , - STEPUP_HEIGHT , false , false ) ; // Using BadHeightUp/Down defined in hop back state collision function.
2021-10-04 22:02:02 +11:00
}
2021-10-19 21:28:36 +11:00
bool TestLaraStepLeft ( ITEM_INFO * item , COLL_INFO * coll )
2021-10-04 22:02:02 +11:00
{
2021-12-12 21:11:27 +11:00
return TestLaraMove ( item , coll , item - > pos . yRot - ANGLE ( 90.0f ) , CLICK ( 0.5f ) , - CLICK ( 0.5f ) ) ; // Using BadHeightUp/Down defined in step left state collision function.
2021-10-19 21:28:36 +11:00
}
bool TestLaraStepRight ( ITEM_INFO * item , COLL_INFO * coll )
{
2021-12-12 21:11:27 +11:00
return TestLaraMove ( item , coll , item - > pos . yRot + ANGLE ( 90.0f ) , CLICK ( 0.5f ) , - CLICK ( 0.5f ) ) ; // Using BadHeightUp/Down defined in step right state collision function.
2021-10-24 20:43:02 +11:00
}
2021-10-04 22:02:02 +11:00
2021-11-07 21:55:38 +11:00
bool TestLaraWalkBackSwamp ( ITEM_INFO * item , COLL_INFO * coll )
{
2021-11-30 22:29:15 +11:00
return TestLaraMove ( item , coll , item - > pos . yRot + ANGLE ( 180.0f ) , NO_BAD_POS , - STEPUP_HEIGHT , false ) ; // Using BadHeightUp defined in walk back state collision function.
2021-11-07 21:55:38 +11:00
}
bool TestLaraStepLeftSwamp ( ITEM_INFO * item , COLL_INFO * coll )
{
2021-12-12 21:11:27 +11:00
return TestLaraMove ( item , coll , item - > pos . yRot - ANGLE ( 90.0f ) , NO_BAD_POS , - CLICK ( 0.5f ) , false ) ; // Using BadHeightUp defined in step left state collision function.
2021-11-07 21:55:38 +11:00
}
bool TestLaraStepRightSwamp ( ITEM_INFO * item , COLL_INFO * coll )
{
2021-12-12 21:11:27 +11:00
return TestLaraMove ( item , coll , item - > pos . yRot + ANGLE ( 90.0f ) , NO_BAD_POS , - CLICK ( 0.5f ) , false ) ; // Using BadHeightUp defined in step right state collision function.
2021-11-07 21:55:38 +11:00
}
2021-10-24 20:43:02 +11:00
bool TestLaraCrawlForward ( ITEM_INFO * item , COLL_INFO * coll )
{
2021-12-12 21:11:27 +11:00
return TestLaraMoveCrawl ( item , coll , item - > pos . yRot , CLICK ( 1 ) - 1 , - ( CLICK ( 1 ) - 1 ) ) ; // Using BadHeightUp/Down defined in crawl state collision functions.
2021-10-24 20:43:02 +11:00
}
2021-10-04 22:02:02 +11:00
2021-10-24 20:43:02 +11:00
bool TestLaraCrawlBack ( ITEM_INFO * item , COLL_INFO * coll )
{
2021-12-12 21:11:27 +11:00
return TestLaraMoveCrawl ( item , coll , item - > pos . yRot + ANGLE ( 180.0f ) , CLICK ( 1 ) - 1 , - ( CLICK ( 1 ) - 1 ) ) ; // Using BadHeightUp/Down defined in crawl state collision functions.
2021-10-04 22:02:02 +11:00
}
2021-10-22 00:07:24 +11:00
bool TestLaraCrouchToCrawl ( ITEM_INFO * item )
2021-09-26 20:59:16 +10:00
{
2021-11-20 12:25:51 +11:00
LaraInfo * & info = item - > data ;
2021-11-25 23:38:59 +11:00
if ( info - > gunStatus = = LG_HANDS_FREE & & // Hands are free.
2021-10-24 20:43:02 +11:00
! ( TrInput & ( IN_FLARE | IN_DRAW ) ) & & // Avoid unsightly concurrent actions.
2021-11-20 12:25:51 +11:00
( info - > gunType ! = WEAPON_FLARE | | info - > flareAge > 0 ) ) // Not handling flare.
2021-09-27 18:18:03 +10:00
{
return true ;
}
2021-09-26 20:59:16 +10:00
2021-09-27 18:18:03 +10:00
return false ;
2021-09-26 20:59:16 +10:00
}
2021-10-14 01:17:21 +11:00
bool TestLaraCrouchRoll ( ITEM_INFO * item , COLL_INFO * coll )
2021-09-27 18:18:03 +10:00
{
2021-11-20 12:25:51 +11:00
LaraInfo * & info = item - > data ;
2021-11-11 23:31:04 +11:00
auto y = item - > pos . yPos ;
2021-11-30 22:29:15 +11:00
auto probe = GetCollisionResult ( item , item - > pos . yRot , WALL_SIZE / 2 , 0 ) ;
2021-11-11 23:31:04 +11:00
2021-12-12 21:11:27 +11:00
if ( ( probe . Position . Floor - y ) < = ( CLICK ( 1 ) - 1 ) & & // Lower floor bound.
( probe . Position . Floor - y ) > = - ( CLICK ( 1 ) - 1 ) & & // Upper floor bound.
2021-11-11 23:31:04 +11:00
( probe . Position . Ceiling - y ) < - LARA_HEIGHT_CRAWL & & // Lowest ceiling bound.
2021-11-29 00:06:18 +11:00
! probe . Position . Slope & & // Not a slope.
2021-12-12 21:11:27 +11:00
info - > waterSurfaceDist > = - CLICK ( 1 ) & & // Water depth is optically feasible for action.
2021-10-22 00:07:24 +11:00
! ( TrInput & ( IN_FLARE | IN_DRAW ) ) & & // Avoid unsightly concurrent actions.
2021-11-20 12:25:51 +11:00
( info - > gunType ! = WEAPON_FLARE | | info - > flareAge > 0 ) ) // Not handling flare.
2021-10-16 20:50:16 +11:00
{
return true ;
}
return false ;
}
bool TestLaraCrawlUpStep ( ITEM_INFO * item , COLL_INFO * coll )
{
auto y = item - > pos . yPos ;
2021-12-12 21:11:27 +11:00
auto probeA = GetCollisionResult ( item , item - > pos . yRot , CLICK ( 1 ) , 0 ) ; // Crossing.
auto probeB = GetCollisionResult ( item , item - > pos . yRot , CLICK ( 2 ) , 0 ) ; // Approximate destination.
2021-11-29 00:06:18 +11:00
2021-12-16 22:14:32 +11:00
if ( ( probeA . Position . Floor - y ) < = - CLICK ( 1 ) & & // Lower floor bound. Synced with crawl states' BadHeightUp.
( probeA . Position . Floor - y ) > = - STEPUP_HEIGHT & & // Upper floor bound.
abs ( probeA . Position . Floor - probeB . Position . Floor ) < = ( CLICK ( 1 ) - 1 ) & & // Destination height is within idle threshold.
2021-12-12 21:11:27 +11:00
( ( coll - > Front . Ceiling - LARA_HEIGHT_CRAWL ) - ( probeA . Position . Floor - y ) ) < = - ( CLICK ( 0.5f ) + CLICK ( 1 ) / 8 ) & & // Gap is optically feasible for action.
2021-12-16 22:14:32 +11:00
abs ( probeA . Position . Ceiling - probeA . Position . Floor ) > LARA_HEIGHT_CRAWL & & // Crossing is not a clamp.
abs ( probeB . Position . Ceiling - probeB . Position . Floor ) > LARA_HEIGHT_CRAWL & & // Destination is not a clamp.
! probeA . Position . Slope & & ! probeB . Position . Slope & & // No slopes.
2021-12-01 19:38:28 +11:00
probeA . Position . Floor ! = NO_HEIGHT & & probeB . Position . Floor ! = NO_HEIGHT )
2021-09-26 20:59:16 +10:00
{
2021-09-27 18:18:03 +10:00
return true ;
2021-09-26 20:59:16 +10:00
}
2021-09-27 18:18:03 +10:00
return false ;
2021-09-26 20:59:16 +10:00
}
2021-10-16 20:50:16 +11:00
bool TestLaraCrawlDownStep ( ITEM_INFO * item , COLL_INFO * coll )
{
auto y = item - > pos . yPos ;
2021-12-12 21:11:27 +11:00
auto probeA = GetCollisionResult ( item , item - > pos . yRot , CLICK ( 1 ) , 0 ) ; // Crossing.
auto probeB = GetCollisionResult ( item , item - > pos . yRot , CLICK ( 2 ) , 0 ) ; // Approximate destination.
2021-11-29 00:06:18 +11:00
if ( ( probeA . Position . Floor - y ) < = STEPUP_HEIGHT & & // Lower floor bound. Synced with crawl exit jump's highest floor bound.
2021-12-12 21:11:27 +11:00
( probeA . Position . Floor - y ) > = CLICK ( 1 ) & & // Upper floor bound. Synced with crawl states' BadHeightDown.
abs ( probeA . Position . Floor - probeB . Position . Floor ) < = ( CLICK ( 1 ) - 1 ) & & // Destination height is within idle threshold.
( probeA . Position . Ceiling - y ) < = - CLICK ( 0.75f ) & & // Gap is optically feasible for action.
2021-11-29 15:26:55 +11:00
abs ( probeA . Position . Ceiling - probeA . Position . Floor ) > LARA_HEIGHT_CRAWL & & // Crossing is not a clamp.
abs ( probeB . Position . Ceiling - probeB . Position . Floor ) > LARA_HEIGHT_CRAWL & & // Destination is not a clamp.
2021-12-01 19:38:28 +11:00
! probeA . Position . Slope & & ! probeB . Position . Slope & & // No slopes.
probeA . Position . Floor ! = NO_HEIGHT & & probeB . Position . Floor ! = NO_HEIGHT )
2021-10-16 20:50:16 +11:00
{
return true ;
}
return false ;
}
bool TestLaraCrawlExitDownStep ( ITEM_INFO * item , COLL_INFO * coll )
{
auto y = item - > pos . yPos ;
2021-12-12 21:11:27 +11:00
auto probeA = GetCollisionResult ( item , item - > pos . yRot , CLICK ( 1 ) , 0 ) ; // Crossing.
auto probeB = GetCollisionResult ( item , item - > pos . yRot , CLICK ( 1.5f ) , 0 ) ; // Approximate destination.
2021-11-29 00:06:18 +11:00
2021-12-03 13:59:29 +11:00
if ( ( ( ( probeA . Position . Floor - y ) < = STEPUP_HEIGHT & & // Lower floor bound. Synced with crawl exit jump's highest floor bound.
2021-12-12 21:11:27 +11:00
( probeA . Position . Floor - y ) > = CLICK ( 1 ) ) | | // Upper floor bound. Synced with crawl states' BadHeightDown. OR
2021-12-03 13:59:29 +11:00
( probeA . Position . Slope & & probeB . Position . Slope ) ) & & // Slopes ahead.
2021-12-12 21:11:27 +11:00
( probeA . Position . Ceiling - y ) < = - CLICK ( 1.25f ) & & // Gap is optically feasible for action.
2021-12-03 13:59:29 +11:00
abs ( probeA . Position . Ceiling - probeA . Position . Floor ) > LARA_HEIGHT & & // Crossing is not a clamp.
abs ( probeB . Position . Ceiling - probeB . Position . Floor ) > LARA_HEIGHT & & // Destination is not a clamp.
2021-12-01 19:38:28 +11:00
probeA . Position . Floor ! = NO_HEIGHT & & probeB . Position . Floor ! = NO_HEIGHT )
2021-10-16 20:50:16 +11:00
{
return true ;
}
return false ;
}
bool TestLaraCrawlExitJump ( ITEM_INFO * item , COLL_INFO * coll )
{
auto y = item - > pos . yPos ;
2021-12-12 21:11:27 +11:00
auto probeA = GetCollisionResult ( item , item - > pos . yRot , CLICK ( 1 ) , 0 ) ; // Crossing.
auto probeB = GetCollisionResult ( item , item - > pos . yRot , CLICK ( 1.5f ) , 0 ) ; // Approximate destination.
2021-11-29 00:06:18 +11:00
2021-12-12 21:11:27 +11:00
if ( ( probeA . Position . Floor - y ) > STEPUP_HEIGHT & & // Highest floor bound. Synced with crawl down step and crawl exit down step's lower floor bounds.
( probeA . Position . Ceiling - y ) < = - CLICK ( 1.25f ) & & // Gap is optically feasible for action.
abs ( probeA . Position . Ceiling - probeA . Position . Floor ) > LARA_HEIGHT & & // Crossing is not a clamp.
abs ( probeB . Position . Ceiling - probeB . Position . Floor ) > LARA_HEIGHT & & // Destination is not a clamp.
2021-12-01 19:38:28 +11:00
probeA . Position . Floor ! = NO_HEIGHT & & probeB . Position . Floor ! = NO_HEIGHT )
2021-10-16 20:50:16 +11:00
{
return true ;
}
return false ;
}
bool TestLaraCrawlVault ( ITEM_INFO * item , COLL_INFO * coll )
{
2021-10-25 17:56:49 +11:00
if ( TestLaraCrawlExitJump ( item , coll ) | |
TestLaraCrawlExitDownStep ( item , coll ) | |
TestLaraCrawlUpStep ( item , coll ) | |
TestLaraCrawlDownStep ( item , coll ) )
{
return true ;
}
return false ;
2021-10-16 20:50:16 +11:00
}
2021-10-17 22:10:01 +11:00
bool TestLaraCrawlToHang ( ITEM_INFO * item , COLL_INFO * coll )
{
auto y = item - > pos . yPos ;
2021-12-12 21:11:27 +11:00
auto probe = GetCollisionResult ( item , item - > pos . yRot + ANGLE ( 180.0f ) , CLICK ( 1 ) , 0 ) ;
auto objectCollided = TestLaraObjectCollision ( item , item - > pos . yRot + ANGLE ( 180.0f ) , CLICK ( 1 ) , 0 ) ;
2021-10-26 14:42:10 +11:00
2021-12-12 21:11:27 +11:00
if ( ! objectCollided & & // No obstruction.
( probe . Position . Floor - y ) > = LARA_HEIGHT_STRETCH & & // Highest floor bound.
( probe . Position . Ceiling - y ) < = - CLICK ( 0.75f ) & & // Gap is optically feasible for action.
2021-10-26 14:42:10 +11:00
probe . Position . Floor ! = NO_HEIGHT )
2021-10-17 22:10:01 +11:00
{
return true ;
}
return false ;
}
2021-11-26 13:58:35 +11:00
2021-12-09 12:48:54 +03:00
bool TestLaraPoleCollision ( ITEM_INFO * item , COLL_INFO * coll , bool up , float offset )
2021-12-02 13:07:00 +11:00
{
static constexpr auto poleProbeCollRadius = 16.0f ;
bool atLeastOnePoleCollided = false ;
if ( GetCollidedObjects ( item , WALL_SIZE , true , CollidedItems , nullptr , 0 ) & & CollidedItems [ 0 ] )
{
auto laraBox = TO_DX_BBOX ( item - > pos , GetBoundsAccurate ( item ) ) ;
// HACK: because Core implemented upward pole movement as SetPosition command, we can't precisely
// check her position. So we add a fixed height offset.
2021-12-09 21:41:28 +11:00
auto sphere = BoundingSphere ( laraBox . Center + Vector3 ( 0 , ( laraBox . Extents . y + poleProbeCollRadius + offset ) * ( up ? - 1 : 1 ) , 0 ) , poleProbeCollRadius ) ;
2021-12-09 12:48:54 +03:00
//g_Renderer.addDebugSphere(sphere.Center, 16.0f, Vector4(1, 0, 0, 1), RENDERER_DEBUG_PAGE::LOGIC_STATS);
2021-12-02 13:07:00 +11:00
int i = 0 ;
while ( CollidedItems [ i ] ! = NULL )
{
auto & obj = CollidedItems [ i ] ;
i + + ;
if ( obj - > objectNumber ! = ID_POLEROPE )
continue ;
auto poleBox = TO_DX_BBOX ( obj - > pos , GetBoundsAccurate ( obj ) ) ;
poleBox . Extents = poleBox . Extents + Vector3 ( coll - > Setup . Radius , 0 , coll - > Setup . Radius ) ;
2021-12-09 12:48:54 +03:00
//g_Renderer.addDebugBox(poleBox, Vector4(0, 0, 1, 1), RENDERER_DEBUG_PAGE::LOGIC_STATS);
2021-12-02 13:07:00 +11:00
if ( poleBox . Intersects ( sphere ) )
2021-12-09 12:48:54 +03:00
{
2021-12-02 13:07:00 +11:00
atLeastOnePoleCollided = true ;
2021-12-09 12:48:54 +03:00
break ;
}
2021-12-02 13:07:00 +11:00
}
}
return atLeastOnePoleCollided ;
}
2021-11-26 13:58:35 +11:00
bool TestLaraPoleUp ( ITEM_INFO * item , COLL_INFO * coll )
{
2021-12-12 21:11:27 +11:00
if ( ! TestLaraPoleCollision ( item , coll , true , CLICK ( 1 ) ) )
2021-12-02 13:07:00 +11:00
return false ;
2021-11-26 13:58:35 +11:00
// TODO: Accuracy.
2021-12-12 21:11:27 +11:00
return ( coll - > Middle . Ceiling < - CLICK ( 1 ) ) ;
2021-11-26 13:58:35 +11:00
}
bool TestLaraPoleDown ( ITEM_INFO * item , COLL_INFO * coll )
{
2021-12-02 13:07:00 +11:00
if ( ! TestLaraPoleCollision ( item , coll , false ) )
return false ;
2021-11-26 13:58:35 +11:00
return ( coll - > Middle . Floor > 0 ) ;
}