2020-09-26 05:06:08 +10:00
# include "framework.h"
2021-12-22 16:23:57 +03:00
# include "Game/Lara/lara_tests.h"
2021-12-24 03:32:19 +03:00
2021-12-22 16:23:57 +03:00
# include "Game/animation.h"
2021-12-24 03:32:19 +03:00
# include "Game/collision/collide_room.h"
# include "Game/collision/collide_item.h"
2021-12-22 16:23:57 +03:00
# include "Game/control/control.h"
# include "Game/control/los.h"
# include "Game/items.h"
2021-12-24 03:32:19 +03:00
# include "Game/Lara/lara.h"
# include "Game/Lara/lara_climb.h"
# include "Game/Lara/lara_collide.h"
# include "Game/Lara/lara_flare.h"
# include "Game/Lara/lara_helpers.h"
# include "Game/Lara/lara_monkey.h"
2021-12-22 16:23:57 +03:00
# include "Renderer/Renderer11.h"
2021-12-01 15:18:47 +03:00
# include "Scripting/GameFlowScript.h"
2021-12-24 03:32:19 +03:00
# include "Specific/input.h"
# include "Specific/level.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
2022-01-14 19:25:56 +03:00
// TODO: Move to lara_test_structs.h after merge of Sezz vaults branch
struct CornerTestResult
{
bool Success ;
PHD_3DPOS ProbeResult ;
PHD_3DPOS RealPositionResult ;
} ;
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
2022-01-08 16:08:31 +11:00
if ( abs ( coll - > NearestLedgeDistance ) > coll - > Setup . Radius * sqrt ( 2 ) + 4 )
2021-11-01 05:26:15 +03:00
return false ;
// Discard if ledge is not within angle threshold
2021-10-28 04:13:24 +03:00
if ( ! TestValidLedgeAngle ( item , coll ) )
2021-12-25 15:39:34 +11:00
return false ;
2021-10-07 23:58:29 +03:00
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-12-26 00:18:38 +11:00
return true ;
2021-10-07 16:45:26 +03:00
}
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 ;
2022-01-04 22:50:18 +11:00
if ( ! ( TrInput & IN_ACTION ) | | ! ( TrInput & IN_FORWARD ) | |
2021-12-25 15:39:34 +11:00
info - > gunStatus ! = LG_HANDS_FREE )
{
2021-12-10 12:30:23 +11:00
return false ;
2021-12-25 15:39:34 +11:00
}
2021-12-10 12:30:23 +11:00
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-12-26 00:18:38 +11:00
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.
2022-01-14 23:18:24 +11:00
auto vaultResult = TestLaraVault1StepToCrouch ( item , coll ) ;
if ( vaultResult . success & & ! success )
2020-09-26 05:06:08 +10:00
{
2022-01-14 23:18:24 +11:00
item - > pos . yPos = vaultResult . height + CLICK ( 1 ) ;
2021-12-26 00:18:38 +11:00
item - > animNumber = LA_VAULT_TO_CROUCH_1CLICK ;
item - > currentAnimState = LS_GRABBING ;
item - > frameNumber = GetFrameNumber ( item , 0 ) ;
item - > goalAnimState = LS_CROUCH_IDLE ;
info - > gunStatus = LG_HANDS_BUSY ;
success = true ;
2020-09-26 05:06:08 +10:00
}
2021-12-26 00:18:38 +11:00
// Vault to stand up two steps.
2022-01-14 23:18:24 +11:00
vaultResult = TestLaraVault2Steps ( item , coll ) ;
if ( vaultResult . success & & ! success )
2020-09-26 05:06:08 +10:00
{
2022-01-14 23:18:24 +11:00
item - > pos . yPos = vaultResult . height + CLICK ( 2 ) ;
2021-12-26 00:18:38 +11:00
item - > animNumber = LA_VAULT_TO_STAND_2CLICK_START ;
item - > currentAnimState = LS_GRABBING ;
item - > frameNumber = GetFrameNumber ( item , 0 ) ;
item - > goalAnimState = LS_IDLE ;
info - > gunStatus = LG_HANDS_BUSY ;
success = true ;
2020-09-26 05:06:08 +10:00
}
2021-12-26 00:18:38 +11:00
// Vault to crouch up two steps.
2022-01-14 23:18:24 +11:00
vaultResult = TestLaraVault2StepsToCrouch ( item , coll ) ;
if ( vaultResult . success & & ! success & &
2021-12-26 00:18:38 +11:00
g_GameFlow - > Animations . CrawlExtended )
2020-09-26 05:06:08 +10:00
{
2022-01-14 23:18:24 +11:00
item - > pos . yPos = vaultResult . height + CLICK ( 2 ) ;
2021-12-26 00:18:38 +11:00
item - > animNumber = LA_VAULT_TO_CROUCH_2CLICK ;
item - > frameNumber = GetFrameNumber ( item , 0 ) ;
item - > currentAnimState = LS_GRABBING ;
item - > goalAnimState = LS_CROUCH_IDLE ;
info - > gunStatus = LG_HANDS_BUSY ;
success = true ;
2020-09-26 05:06:08 +10:00
}
2021-12-26 00:18:38 +11:00
// Vault to stand up three steps.
2022-01-14 23:18:24 +11:00
vaultResult = TestLaraVault3Steps ( item , coll ) ;
if ( vaultResult . success & & ! success )
2020-09-26 05:06:08 +10:00
{
2022-01-14 23:18:24 +11:00
item - > pos . yPos = vaultResult . height + CLICK ( 3 ) ;
2021-12-26 00:18:38 +11:00
item - > animNumber = LA_VAULT_TO_STAND_3CLICK ;
item - > currentAnimState = LS_GRABBING ;
item - > frameNumber = GetFrameNumber ( item , 0 ) ;
item - > goalAnimState = LS_IDLE ;
info - > gunStatus = LG_HANDS_BUSY ;
success = true ;
}
// Vault to crouch up three steps.
2022-01-14 23:18:24 +11:00
vaultResult = TestLaraVault3StepsToCrouch ( item , coll ) ;
if ( vaultResult . success & & ! success & &
g_GameFlow - > Animations . CrawlExtended )
2021-12-26 00:18:38 +11:00
{
2022-01-14 23:18:24 +11:00
item - > pos . yPos = vaultResult . height + CLICK ( 3 ) ;
2021-12-26 00:18:38 +11:00
item - > animNumber = LA_VAULT_TO_CROUCH_3CLICK ;
item - > frameNumber = GetFrameNumber ( item , 0 ) ;
item - > currentAnimState = LS_GRABBING ;
item - > goalAnimState = LS_CROUCH_IDLE ;
info - > gunStatus = LG_HANDS_BUSY ;
success = true ;
2020-09-26 05:06:08 +10:00
}
2021-12-26 00:18:38 +11:00
2022-01-11 15:09:12 +11:00
// Auto jump to hang.
2022-01-14 23:18:24 +11:00
vaultResult = TestLaraVaultAutoJump ( item , coll ) ;
if ( vaultResult . success & & ! success )
2020-09-26 05:06:08 +10:00
{
2022-01-14 23:18:24 +11:00
info - > calcFallSpeed = - 3 - sqrt ( - 9600 - 12 * ( vaultResult . height - item - > pos . yPos ) ) ;
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 ;
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
{
2022-01-03 01:29:32 +11:00
info - > turnRate = 0 ;
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
}
2022-01-03 01:29:32 +11:00
// Auto jump to ladder.
2022-01-14 23:18:24 +11:00
auto ladderAutoJumpResult = TestLaraLadderAutoJump ( item , coll ) ;
if ( ladderAutoJumpResult . success )
2021-10-09 01:55:22 +03:00
{
2022-01-14 23:18:24 +11:00
info - > calcFallSpeed = - 3 - sqrt ( - 9600 - 12 * std : : max ( ( ladderAutoJumpResult . height - item - > pos . yPos + CLICK ( 0.2f ) ) , - CLICK ( 7.1f ) ) ) ;
2022-01-03 13:52:07 +11:00
item - > animNumber = LA_STAND_SOLID ;
item - > frameNumber = GetFrameNumber ( item , 0 ) ;
item - > goalAnimState = LS_JUMP_UP ;
item - > currentAnimState = LS_IDLE ;
2022-01-08 16:08:31 +11:00
info - > gunStatus = LG_HANDS_BUSY ;
2022-01-03 13:52:07 +11:00
info - > turnRate = 0 ;
2021-11-01 19:00:03 +11:00
2022-01-03 13:52:07 +11:00
ShiftItem ( item , coll ) ;
SnapItemToGrid ( item , coll ) ; // HACK: until fragile ladder code is refactored, we must exactly snap to grid.
AnimateLara ( item ) ;
2020-09-26 05:06:08 +10:00
2022-01-03 13:52:07 +11:00
return true ;
2022-01-03 01:29:32 +11:00
}
// Mount ladder.
2022-01-03 13:52:07 +11:00
else if ( TestLaraLadderMount ( item , coll ) & &
TestLaraClimbStance ( item , coll ) )
2022-01-03 01:29:32 +11: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 ) ;
2022-01-03 01:29:32 +11:00
item - > goalAnimState = LS_LADDER_IDLE ;
2021-11-25 23:38:59 +11:00
item - > currentAnimState = LS_IDLE ;
2022-01-03 01:29:32 +11:00
info - > gunStatus = LG_HANDS_BUSY ;
2021-11-20 12:25:51 +11:00
info - > turnRate = 0 ;
2022-01-03 01:29:32 +11: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.
2022-01-02 21:31:18 +11:00
if ( TestLaraMonkeyAutoJump ( item , coll ) & &
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
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-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
}
2022-01-03 17:01:07 +11:00
bool TestLaraKeepLow ( 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 ;
2022-01-03 17:57:57 +11:00
auto probeFront = GetCollisionResult ( item , item - > pos . yRot , radius , - coll - > Setup . Height ) ;
2021-12-23 14:38:26 +11:00
auto probeBack = GetCollisionResult ( item , item - > pos . yRot + ANGLE ( 180.0f ) , radius , - coll - > Setup . Height ) ;
2022-01-03 17:57:57 +11:00
auto probeMiddle = GetCollisionResult ( item ) ;
2021-11-05 21:29:00 +11:00
// TODO: Cannot use as a failsafe in standing states; bugged with slanted ceilings reaching the ground.
2022-01-03 17:57:57 +11:00
// In common setups, Lara may embed on such ceilings, resulting in inappropriate crouch state dispatches. @Sezz 2021.10.15
if ( ( probeFront . Position . Ceiling - y ) > = - LARA_HEIGHT | | // Front is not a clamp.
( probeBack . Position . Ceiling - y ) > = - LARA_HEIGHT | | // Back is not a clamp.
( probeMiddle . Position . Ceiling - y ) > = - LARA_HEIGHT ) // Middle 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 )
{
2022-01-18 16:52:52 +11:00
if ( GetCollisionResult ( item ) . Position . FloorSlope & &
2021-12-23 17:36:50 +11:00
! TestLaraSwamp ( item ) )
2021-09-13 09:12:46 +03:00
{
2021-12-18 20:42:15 +11:00
return true ;
2021-09-13 09:12:46 +03:00
}
2021-12-18 20:42:15 +11:00
return false ;
2021-09-13 09:12:46 +03:00
}
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-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 ) ;
2022-01-19 16:17:16 +11:00
info - > gunStatus = LG_HANDS_BUSY ;
2021-10-27 10:13:47 +03:00
item - > gravityStatus = false ;
item - > speed = 0 ;
item - > fallspeed = 0 ;
2022-01-12 18:21:52 +11:00
DoLaraMonkeySnap ( item , coll ) ;
2021-10-27 10:13:47 +03:00
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 ;
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 ;
2022-01-13 03:13:18 +11:00
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
{
2022-01-13 03:13:18 +11:00
SetAnimation ( item , LA_REACH_TO_MONKEYSWING ) ;
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
item - > gravityStatus = false ;
item - > speed = 0 ;
item - > fallspeed = 0 ;
2022-01-19 16:17:16 +11:00
DoLaraMonkeySnap ( item , coll ) ;
2021-10-27 09:48:48 +03:00
return true ;
}
2022-01-13 03:13:18 +11:00
if ( coll - > Middle . Ceiling > - STEPUP_HEIGHT | |
coll - > Middle . Floor < 200 | |
coll - > CollisionType ! = CT_FRONT )
{
2021-10-27 09:48:48 +03:00
return false ;
2022-01-13 03:13:18 +11:00
}
2021-10-27 09:48:48 +03:00
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 ) )
2022-01-13 03:13:18 +11:00
{
2021-10-27 09:48:48 +03:00
return false ;
2022-01-13 03:13:18 +11:00
}
2021-10-27 09:48:48 +03:00
2022-01-13 03:13:18 +11:00
if ( TestHangSwingIn ( item ) )
2021-10-27 09:48:48 +03:00
{
2022-01-13 03:13:18 +11:00
SetAnimation ( item , LA_REACH_TO_HANG_OSCILLATE ) ;
ResetLaraFlex ( item ) ;
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 ) ;
2022-01-13 03:13:18 +11:00
info - > gunStatus = LG_HANDS_BUSY ;
2021-10-27 09:48:48 +03:00
item - > gravityStatus = true ;
item - > speed = 2 ;
item - > fallspeed = 1 ;
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 ;
2022-01-16 02:34:09 +11:00
coll - > Setup . BadFloorHeightDown = NO_BAD_POS ;
coll - > Setup . BadFloorHeightUp = - STEPUP_HEIGHT ;
2022-01-15 23:21:45 +11:00
coll - > Setup . BadCeilingHeightDown = 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-12-18 01:22:23 +11:00
item - > pos . yPos + = GetBoundsAccurate ( item ) - > Y2 * 1.8f ;
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 ;
}
2022-01-14 19:25:56 +03:00
CornerTestResult TestItemAtNextCornerPosition ( ITEM_INFO * item , COLL_INFO * coll , float angle , bool outer )
{
auto result = CornerTestResult ( ) ;
// Determine real turning angle
auto turnAngle = outer ? angle : - angle ;
// Backup previous position into array
PHD_3DPOS pos [ 3 ] = { item - > pos , item - > pos , item - > pos } ;
// Do a two-step rotation check. First step is real resulting position, and second step is probing
// position. We need this because checking at exact ending position does not always return
// correct results with nearest ledge angle.
for ( int i = 0 ; i < 2 ; i + + )
{
// Determine collision box anchor point and rotate collision box around this anchor point.
// Then determine new test position from centerpoint of new collision box position.
// Push back item a bit to compensate for possible edge ledge cases
pos [ i ] . xPos - = round ( ( coll - > Setup . Radius * ( outer ? - 0.2f : 0.2f ) ) * phd_sin ( pos [ i ] . yRot ) ) ;
pos [ i ] . zPos - = round ( ( coll - > Setup . Radius * ( outer ? - 0.2f : 0.2f ) ) * phd_cos ( pos [ i ] . yRot ) ) ;
// Move item at the distance of full collision diameter plus half-radius margin to movement direction
pos [ i ] . xPos + = round ( ( coll - > Setup . Radius * ( i = = 0 ? 2.0f : 2.5f ) ) * phd_sin ( Lara . moveAngle ) ) ;
pos [ i ] . zPos + = round ( ( coll - > Setup . Radius * ( i = = 0 ? 2.0f : 2.5f ) ) * phd_cos ( Lara . moveAngle ) ) ;
// Determine anchor point
auto cX = pos [ i ] . xPos + round ( coll - > Setup . Radius * phd_sin ( pos [ i ] . yRot ) ) ;
auto cZ = pos [ i ] . zPos + round ( coll - > Setup . Radius * phd_cos ( pos [ i ] . yRot ) ) ;
cX + = ( coll - > Setup . Radius * phd_sin ( pos [ i ] . yRot + ANGLE ( 90.0f * - std : : copysign ( 1.0f , angle ) ) ) ) ;
cZ + = ( coll - > Setup . Radius * phd_cos ( pos [ i ] . yRot + ANGLE ( 90.0f * - std : : copysign ( 1.0f , angle ) ) ) ) ;
// Determine distance from anchor point to new item position
auto dist = Vector2 ( pos [ i ] . xPos , pos [ i ] . zPos ) - Vector2 ( cX , cZ ) ;
auto s = phd_sin ( ANGLE ( turnAngle ) ) ;
auto c = phd_cos ( ANGLE ( turnAngle ) ) ;
// Shift item to a new anchor point
pos [ i ] . xPos = dist . x * c - dist . y * s + cX ;
pos [ i ] . zPos = dist . x * s + dist . y * c + cZ ;
// Virtually rotate item to new angle
short newAngle = pos [ i ] . yRot - ANGLE ( turnAngle ) ;
pos [ i ] . yRot = newAngle ;
// Snap to nearest ledge, if any.
item - > pos = pos [ i ] ;
SnapItemToLedge ( item , coll , item - > pos . yRot ) ;
// Copy resulting position to an array and restore original item position.
pos [ i ] = item - > pos ;
item - > pos = pos [ 2 ] ;
if ( i = = 1 ) // Both passes finished, construct the result.
{
result . RealPositionResult = pos [ 0 ] ;
result . ProbeResult = pos [ 1 ] ;
result . Success = newAngle = = pos [ i ] . yRot ;
}
}
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
2022-01-14 19:25:56 +03:00
auto cornerResult = TestItemAtNextCornerPosition ( item , coll , testAngle , false ) ;
2021-10-28 01:59:20 +03:00
// Do further testing only if test angle is equal to resulting edge angle
2022-01-14 19:25:56 +03:00
if ( cornerResult . Success )
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
2022-01-14 19:25:56 +03:00
item - > pos = cornerResult . RealPositionResult ;
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
2022-01-14 19:25:56 +03:00
item - > pos = cornerResult . ProbeResult ;
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
2022-01-14 19:25:56 +03:00
cornerResult = TestItemAtNextCornerPosition ( 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 ) )
2022-01-14 19:25:56 +03:00
cornerResult . Success = 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
2022-01-14 19:25:56 +03:00
if ( cornerResult . Success )
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
2022-01-14 19:25:56 +03:00
item - > pos = cornerResult . RealPositionResult ;
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
2022-01-14 19:25:56 +03:00
item - > pos = cornerResult . ProbeResult ;
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 ;
2022-01-16 02:34:09 +11:00
coll - > Setup . BadFloorHeightDown = NO_BAD_POS ;
coll - > Setup . BadFloorHeightUp = - CLICK ( 2 ) ;
2022-01-15 23:21:45 +11:00
coll - > Setup . BadCeilingHeightDown = 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
{
2021-12-30 22:17:36 +11:00
int shiftRight , shiftLeft ;
2020-09-26 05:06:08 +10:00
2021-12-30 22:17:36 +11:00
if ( LaraTestClimbPos ( item , coll - > Setup . Radius , coll - > Setup . Radius + CLICK ( 0.5f ) , - 700 , CLICK ( 2 ) , & shiftRight ) ! = 1 )
2020-09-26 05:06:08 +10:00
return false ;
2021-12-30 22:17:36 +11:00
if ( LaraTestClimbPos ( item , coll - > Setup . Radius , - ( coll - > Setup . Radius + CLICK ( 0.5f ) ) , - 700 , CLICK ( 2 ) , & shiftLeft ) ! = 1 )
2020-09-26 05:06:08 +10:00
return false ;
2021-12-30 22:17:36 +11:00
if ( shiftRight )
2020-09-26 05:06:08 +10:00
{
2021-12-30 22:17:36 +11:00
if ( shiftLeft )
2020-09-26 05:06:08 +10:00
{
2021-12-30 22:17:36 +11:00
if ( shiftRight < 0 ! = shiftLeft < 0 )
2020-09-26 05:06:08 +10:00
return false ;
2021-12-30 22:17:36 +11:00
if ( ( shiftRight < 0 & & shiftLeft < shiftRight ) | |
( shiftRight > 0 & & shiftLeft > shiftRight ) )
2020-09-26 05:06:08 +10:00
{
2021-12-30 22:17:36 +11:00
item - > pos . yPos + = shiftLeft ;
2020-09-26 05:06:08 +10:00
return true ;
}
}
2021-12-30 22:17:36 +11:00
item - > pos . yPos + = shiftRight ;
2020-09-26 05:06:08 +10:00
}
2021-12-30 22:17:36 +11:00
else if ( shiftLeft )
item - > pos . yPos + = shiftLeft ;
2020-09-26 05:06:08 +10:00
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 ;
}
2022-01-13 03:13:18 +11:00
bool TestHangSwingIn ( ITEM_INFO * item )
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
2021-12-30 22:17:36 +11:00
int y = item - > pos . yPos ;
2022-01-13 03:13:18 +11:00
auto probe = GetCollisionResult ( item , item - > pos . yRot , CLICK ( 0.5f ) ) ;
2020-09-26 05:06:08 +10:00
2022-01-13 03:13:18 +11:00
if ( ( probe . Position . Floor - y ) > 0 & &
( probe . Position . Ceiling - y ) < - 400 & &
probe . Position . Floor ! = NO_HEIGHT )
2020-09-26 05:06:08 +10:00
{
2022-01-13 03:13:18 +11:00
return true ;
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-30 22:17:36 +11:00
2021-12-01 11:59:24 +03:00
auto oldPos = item - > pos ;
2020-09-26 05:06:08 +10:00
2021-12-30 22:17:36 +11:00
info - > moveAngle = item - > pos . yRot + angle ;
2021-12-15 15:21:39 +03:00
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-12-30 22:17:36 +11:00
bool 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-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-12-28 16:09:05 +11:00
short angle1 = angle + ANGLE ( 15.0f ) ;
short angle2 = angle - ANGLE ( 15.0f ) ;
2021-10-16 22:53:29 +11:00
2021-12-28 16:09:05 +11:00
auto start = GAME_VECTOR ( item - > pos . xPos ,
item - > pos . yPos - STEPUP_HEIGHT ,
item - > pos . zPos ,
item - > roomNumber ) ;
2021-08-29 23:53:58 +03:00
2021-12-28 16:09:05 +11:00
auto end1 = GAME_VECTOR ( item - > pos . xPos + dist * phd_sin ( angle1 ) ,
item - > pos . yPos - STEPUP_HEIGHT ,
item - > pos . zPos + dist * phd_cos ( angle1 ) ,
item - > roomNumber ) ;
2021-08-29 23:53:58 +03:00
2021-12-28 16:09:05 +11:00
auto end2 = GAME_VECTOR ( item - > pos . xPos + dist * phd_sin ( angle2 ) ,
item - > pos . yPos - STEPUP_HEIGHT ,
item - > pos . zPos + dist * phd_cos ( angle2 ) ,
item - > roomNumber ) ;
2021-08-29 23:53:58 +03:00
2021-12-28 16:09:05 +11:00
bool result1 = LOS ( & start , & end1 ) ;
bool result2 = LOS ( & start , & end2 ) ;
2021-08-29 23:53:58 +03:00
2021-12-28 16:09:05 +11:00
return ( ! result1 & & ! result2 ) ;
2021-08-29 23:53:58 +03:00
}
2021-12-27 17:52:29 +11:00
bool TestLaraSplat ( ITEM_INFO * item , int dist , int height , int side )
{
2022-01-04 00:35:53 +11:00
auto start = GAME_VECTOR (
item - > pos . xPos + ( phd_cos ( item - > pos . yRot ) * side ) ,
2021-12-27 17:52:29 +11:00
item - > pos . yPos + height ,
2022-01-04 00:35:53 +11:00
item - > pos . zPos + ( phd_sin ( item - > pos . yRot ) * - side ) ,
2021-12-27 17:52:29 +11:00
item - > roomNumber ) ;
2022-01-04 00:35:53 +11:00
auto end = GAME_VECTOR (
item - > pos . xPos + ( phd_sin ( item - > pos . yRot ) * dist ) + ( phd_cos ( item - > pos . yRot ) * side ) ,
2021-12-27 17:52:29 +11:00
item - > pos . yPos + height ,
2022-01-04 00:35:53 +11:00
item - > pos . zPos + ( phd_cos ( item - > pos . yRot ) * dist ) + ( phd_sin ( item - > pos . yRot ) * - side ) ,
2021-12-27 17:52:29 +11:00
item - > roomNumber ) ;
return ! LOS ( & start , & end ) ;
}
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 ;
}
2022-01-16 13:56:39 +11:00
bool TestLaraMonkeyFall ( ITEM_INFO * item , COLL_INFO * coll )
{
int y = item - > pos . yPos - LARA_HEIGHT_MONKEY ;
auto probe = GetCollisionResult ( item ) ;
2022-01-19 22:45:38 +11:00
if ( ! probe . BottomBlock - > Flags . Monkeyswing | | // No monkey sector.
( probe . Position . Ceiling - y ) > CLICK ( 1.25f ) | | // Lower bound.
( probe . Position . Ceiling - y ) < - CLICK ( 1.25f ) | | // Upper bound.
probe . Position . CeilingSlope | | // Ceiling slope.
2022-01-16 13:56:39 +11:00
probe . Position . Ceiling = = NO_HEIGHT )
{
return true ;
}
return false ;
}
2021-12-27 21:29:21 +11:00
bool TestLaraLand ( ITEM_INFO * item , COLL_INFO * coll )
2021-12-20 00:42:02 +11:00
{
2022-01-17 17:09:21 +11:00
g_Renderer . printDebugMessage ( " floor: %d " , coll - > Middle . Floor ) ;
g_Renderer . printDebugMessage ( " fall: %d " , item - > fallspeed ) ;
g_Renderer . printDebugMessage ( " grav: %d " , item - > gravityStatus ) ;
if ( //item->gravityStatus &&
2021-12-28 12:50:04 +11:00
item - > fallspeed > = 0 & &
2022-01-17 17:09:21 +11:00
( coll - > Middle . Floor < = item - > fallspeed | | TestLaraSwamp ( item ) ) )
2021-12-20 00:42:02 +11:00
{
return true ;
}
return false ;
}
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 | |
2022-01-18 16:52:52 +11:00
coll - > Middle . FloorSlope | |
2021-11-09 23:26:31 +11:00
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 ;
}
2022-01-16 13:56:39 +11:00
bool TestLaraMonkeyStep ( ITEM_INFO * item , COLL_INFO * coll )
{
int y = item - > pos . yPos - LARA_HEIGHT_MONKEY ;
auto probe = GetCollisionResult ( item ) ;
2022-01-19 22:45:38 +11:00
if ( ( probe . Position . Ceiling - y ) < = CLICK ( 1.25f ) & & // Lower bound.
( probe . Position . Ceiling - y ) > = - CLICK ( 1.25f ) & & // Upper bound.
probe . Position . Ceiling ! = NO_HEIGHT )
2022-01-16 13:56:39 +11:00
{
return true ;
}
return false ;
}
2021-10-16 20:50:16 +11:00
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
2022-01-12 18:21:52 +11:00
// TODO: This function and its clone TestLaraCrawlMoveTolerance() 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
2022-01-08 15:43:17 +11:00
bool TestLaraMoveTolerance ( ITEM_INFO * item , COLL_INFO * coll , MoveTestData testData )
2021-10-22 00:07:24 +11:00
{
2021-12-23 23:37:40 +11:00
int y = item - > pos . yPos ;
2022-01-08 16:08:31 +11:00
auto probe = GetCollisionResult ( item , testData . angle , coll - > Setup . Radius * sqrt ( 2 ) + 4 , - coll - > Setup . Height ) ; // Offset required to account for gap between Lara and the wall. Results in slight overshoot, but avoids oscillation.
2022-01-18 16:52:52 +11:00
bool isSlopeDown = testData . checkSlopeDown ? ( probe . Position . FloorSlope & & probe . Position . Floor > y ) : false ;
bool isSlopeUp = testData . checkSlopeUp ? ( probe . Position . FloorSlope & & probe . Position . Floor < y ) : false ;
2022-01-08 15:43:17 +11:00
bool isDeath = testData . checkDeath ? probe . Block - > Flags . Death : false ;
2021-10-25 23:24:34 +11:00
2022-01-08 15:43:17 +11:00
if ( ( probe . Position . Floor - y ) < = testData . lowerBound & & // Lower floor bound.
( probe . Position . Floor - y ) > = testData . 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.
2022-01-08 15:43:17 +11:00
! isSlopeDown & & ! isSlopeUp & & ! 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-10-28 23:22:28 +11:00
bool TestLaraRunForward ( ITEM_INFO * item , COLL_INFO * coll )
{
2022-01-16 02:34:09 +11:00
// Using BadFloorHeightUp/Down defined in run state collision function.
2021-10-28 23:22:28 +11:00
2022-01-08 15:43:17 +11:00
MoveTestData testData
{
item - > pos . yRot ,
NO_BAD_POS ,
- STEPUP_HEIGHT ,
false , true , false
} ;
2021-10-28 23:22:28 +11:00
2022-01-08 15:43:17 +11:00
return TestLaraMoveTolerance ( item , coll , testData ) ;
2021-10-28 23:22:28 +11:00
}
bool TestLaraWalkForward ( ITEM_INFO * item , COLL_INFO * coll )
2021-10-22 00:07:24 +11:00
{
2022-01-16 02:34:09 +11:00
// Using BadFloorHeightUp/Down defined in walk state collision function.
2021-10-28 23:22:28 +11:00
2022-01-08 15:43:17 +11:00
MoveTestData testData
{
item - > pos . yRot ,
STEPUP_HEIGHT ,
- STEPUP_HEIGHT
} ;
2021-10-29 21:41:00 +11:00
2022-01-08 15:43:17 +11:00
return TestLaraMoveTolerance ( item , coll , testData ) ;
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
{
2022-01-16 02:34:09 +11:00
// Using BadFloorHeightUp/Down defined in walk back state collision function.
2022-01-08 15:43:17 +11:00
MoveTestData testData
{
item - > pos . yRot + ANGLE ( 180.0f ) ,
STEPUP_HEIGHT ,
- STEPUP_HEIGHT
} ;
return TestLaraMoveTolerance ( item , coll , testData ) ;
2021-10-19 21:28:36 +11:00
}
2022-01-08 15:43:17 +11:00
bool TestLaraRunBack ( ITEM_INFO * item , COLL_INFO * coll )
2021-10-19 21:28:36 +11:00
{
2022-01-16 02:34:09 +11:00
// Using BadFloorHeightUp/Down defined in hop back state collision function.
2022-01-08 15:43:17 +11:00
MoveTestData testData
{
item - > pos . yRot + ANGLE ( 180.0f ) ,
NO_BAD_POS , - STEPUP_HEIGHT ,
false , false , false
} ;
return TestLaraMoveTolerance ( item , coll , testData ) ;
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
{
2022-01-16 02:34:09 +11:00
// Using BadFloorHeightUp/Down defined in step left state collision function.
2022-01-08 15:43:17 +11:00
MoveTestData testData
{
item - > pos . yRot - ANGLE ( 90.0f ) ,
CLICK ( 0.8f ) ,
- CLICK ( 0.8f )
} ;
return TestLaraMoveTolerance ( item , coll , testData ) ;
2021-10-19 21:28:36 +11:00
}
bool TestLaraStepRight ( ITEM_INFO * item , COLL_INFO * coll )
{
2022-01-16 02:34:09 +11:00
// Using BadFloorHeightUp/Down defined in step right state collision function.
2022-01-08 15:43:17 +11:00
MoveTestData testData
{
item - > pos . yRot + ANGLE ( 90.0f ) ,
CLICK ( 0.8f ) ,
- CLICK ( 0.8f )
} ;
return TestLaraMoveTolerance ( item , coll , testData ) ;
2021-12-26 00:18:38 +11:00
}
2022-01-08 15:43:17 +11:00
bool TestLaraWadeForwardSwamp ( ITEM_INFO * item , COLL_INFO * coll )
2022-01-02 21:31:18 +11:00
{
2022-01-16 02:34:09 +11:00
// Using BadFloorHeightUp/Down defined in wade forward state collision function.
2022-01-02 21:31:18 +11:00
2022-01-08 15:43:17 +11:00
MoveTestData testData
{
item - > pos . yRot ,
NO_BAD_POS ,
- STEPUP_HEIGHT ,
false , false , false
} ;
2022-01-02 21:31:18 +11:00
2022-01-08 15:43:17 +11:00
return TestLaraMoveTolerance ( item , coll , testData ) ;
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 )
{
2022-01-16 02:34:09 +11:00
// Using BadFloorHeightUp defined in walk back state collision function.
2022-01-08 15:43:17 +11:00
MoveTestData testData
2022-01-02 21:31:18 +11:00
{
2022-01-08 15:43:17 +11:00
item - > pos . yRot + ANGLE ( 180.0f ) ,
NO_BAD_POS ,
- STEPUP_HEIGHT ,
false , false , false
} ;
2022-01-02 21:31:18 +11:00
2022-01-08 15:43:17 +11:00
return TestLaraMoveTolerance ( item , coll , testData ) ;
2021-11-07 21:55:38 +11:00
}
bool TestLaraStepLeftSwamp ( ITEM_INFO * item , COLL_INFO * coll )
{
2022-01-16 02:34:09 +11:00
// Using BadFloorHeightUp defined in step left state collision function.
2022-01-03 01:29:32 +11:00
2022-01-08 15:43:17 +11:00
MoveTestData testData
{
item - > pos . yRot - ANGLE ( 90.0f ) ,
NO_BAD_POS ,
- CLICK ( 0.8f ) ,
false , false , false
} ;
2022-01-03 13:52:07 +11:00
2022-01-08 15:43:17 +11:00
return TestLaraMoveTolerance ( item , coll , testData ) ;
2021-11-07 21:55:38 +11:00
}
bool TestLaraStepRightSwamp ( ITEM_INFO * item , COLL_INFO * coll )
{
2022-01-16 02:34:09 +11:00
// Using BadFloorHeightUp defined in step right state collision function.
2022-01-08 15:43:17 +11:00
MoveTestData testData
2022-01-03 01:29:32 +11:00
{
2022-01-08 15:43:17 +11:00
item - > pos . yRot + ANGLE ( 90.0f ) ,
NO_BAD_POS ,
- CLICK ( 0.8f ) ,
false , false , false
} ;
2022-01-03 01:29:32 +11:00
2022-01-08 15:43:17 +11:00
return TestLaraMoveTolerance ( item , coll , testData ) ;
2021-11-07 21:55:38 +11:00
}
2022-01-12 18:21:52 +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 TestLaraCrawlMoveTolerance ( ITEM_INFO * item , COLL_INFO * coll , MoveTestData testData )
{
int y = item - > pos . yPos ;
auto probe = GetCollisionResult ( item , testData . angle , LARA_RAD_CRAWL * sqrt ( 2 ) + 4 , - LARA_HEIGHT_CRAWL ) ;
2022-01-18 16:52:52 +11:00
bool isSlopeDown = testData . checkSlopeDown ? ( probe . Position . FloorSlope & & probe . Position . Floor > y ) : false ;
bool isSlopeUp = testData . checkSlopeUp ? ( probe . Position . FloorSlope & & probe . Position . Floor < y ) : false ;
2022-01-12 18:21:52 +11:00
bool isDeath = testData . checkDeath ? probe . Block - > Flags . Death : false ;
if ( ( probe . Position . Floor - y ) < = testData . lowerBound & & // Lower floor bound.
( probe . Position . Floor - y ) > = testData . 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.
! isSlopeDown & & ! isSlopeUp & & ! isDeath & & // No slope or death sector (if applicable).
probe . Position . Floor ! = NO_HEIGHT )
{
return true ;
}
return false ;
}
2021-10-24 20:43:02 +11:00
bool TestLaraCrawlForward ( ITEM_INFO * item , COLL_INFO * coll )
{
2022-01-16 02:34:09 +11:00
// Using BadFloorHeightUp/Down defined in crawl state collision functions.
2022-01-03 01:29:32 +11:00
2022-01-08 15:43:17 +11:00
MoveTestData testData
{
item - > pos . yRot ,
CLICK ( 1 ) - 1 ,
- ( CLICK ( 1 ) - 1 )
} ;
2022-01-03 01:29:32 +11:00
2022-01-08 15:43:17 +11:00
return TestLaraCrawlMoveTolerance ( item , coll , testData ) ;
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 )
{
2022-01-16 02:34:09 +11:00
// Using BadFloorHeightUp/Down defined in crawl state collision functions.
2022-01-08 15:43:17 +11:00
MoveTestData testData
{
item - > pos . yRot + ANGLE ( 180.0f ) ,
CLICK ( 1 ) - 1 ,
- ( CLICK ( 1 ) - 1 )
} ;
return TestLaraCrawlMoveTolerance ( item , coll , testData ) ;
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-12-23 23:37:40 +11:00
int y = item - > pos . yPos ;
2022-01-03 18:55:05 +11:00
auto probe = GetCollisionResult ( item , item - > pos . yRot , CLICK ( 2 ) , - LARA_HEIGHT_CRAWL ) ;
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.
2022-01-18 16:52:52 +11:00
! probe . Position . FloorSlope & & // Not a slope.
2022-01-08 15:43:17 +11:00
info - > waterSurfaceDist > = - CLICK ( 1 ) & & // Water depth is optically permissive.
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 ;
}
2022-01-12 18:21:52 +11:00
bool TestLaraMonkeyMoveTolerance ( ITEM_INFO * item , COLL_INFO * coll , MonkeyMoveTestData testData )
2021-10-16 20:50:16 +11:00
{
2022-01-15 22:48:35 +11:00
int y = item - > pos . yPos - LARA_HEIGHT_MONKEY ;
2022-01-19 22:45:38 +11:00
auto probe = GetCollisionResult ( item , testData . Angle , coll - > Setup . Radius * sqrt ( 2 ) + 4 ) ;
2022-01-15 22:48:35 +11:00
2022-01-19 22:45:38 +11:00
if ( //probe.BottomBlock->Flags.Monkeyswing && // Is monkey sector.
2022-01-19 16:17:16 +11:00
( probe . Position . Floor - y ) > LARA_HEIGHT_MONKEY & & // Highest floor boundary.
2022-01-19 22:45:38 +11:00
( probe . Position . Ceiling - y ) < = testData . LowerBound & & // Lower ceiling boundary.
( probe . Position . Ceiling - y ) > = testData . UpperBound & & // Lower ceiling boundary. TODO: Not working??
2022-01-19 16:17:16 +11:00
abs ( probe . Position . Ceiling - probe . Position . Floor ) > LARA_HEIGHT_MONKEY & & // Space is not a clamp.
2022-01-18 16:52:52 +11:00
! probe . Position . CeilingSlope & & // No ceiling slope.
2022-01-15 22:48:35 +11:00
probe . Position . Ceiling ! = 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
2022-01-12 18:21:52 +11:00
bool TestLaraMonkeyForward ( ITEM_INFO * item , COLL_INFO * coll )
2022-01-08 16:08:31 +11:00
{
2022-01-12 18:21:52 +11:00
MonkeyMoveTestData testData
2022-01-08 16:50:23 +11:00
{
2022-01-19 16:17:16 +11:00
item - > pos . yRot ,
2022-01-16 13:56:39 +11:00
CLICK ( 1.25f ) ,
- CLICK ( 1.25f )
2022-01-08 16:50:23 +11:00
} ;
2022-01-12 18:21:52 +11:00
return TestLaraMonkeyMoveTolerance ( item , coll , testData ) ;
2022-01-08 16:08:31 +11:00
}
2022-01-12 18:21:52 +11:00
bool TestLaraMonkeyBack ( ITEM_INFO * item , COLL_INFO * coll )
2021-10-16 20:50:16 +11:00
{
2022-01-12 18:21:52 +11:00
MonkeyMoveTestData testData
2022-01-08 16:50:23 +11:00
{
2022-01-19 16:17:16 +11:00
item - > pos . yRot + ANGLE ( 180.0f ) ,
2022-01-16 13:56:39 +11:00
CLICK ( 1.25f ) ,
- CLICK ( 1.25f )
2022-01-08 16:50:23 +11:00
} ;
2022-01-12 18:21:52 +11:00
return TestLaraMonkeyMoveTolerance ( item , coll , testData ) ;
2022-01-08 16:08:31 +11:00
}
2022-01-12 18:21:52 +11:00
bool TestLaraMonkeyShimmyLeft ( ITEM_INFO * item , COLL_INFO * coll )
2022-01-08 16:08:31 +11:00
{
2022-01-12 18:21:52 +11:00
MonkeyMoveTestData testData
2022-01-08 16:50:23 +11:00
{
2022-01-19 16:17:16 +11:00
item - > pos . yRot - ANGLE ( 90.0f ) ,
CLICK ( 0.5f ) ,
- CLICK ( 0.5f )
2022-01-08 16:50:23 +11:00
} ;
2022-01-12 18:21:52 +11:00
return TestLaraMonkeyMoveTolerance ( item , coll , testData ) ;
2022-01-08 16:08:31 +11:00
}
2022-01-12 18:21:52 +11:00
bool TestLaraMonkeyShimmyRight ( ITEM_INFO * item , COLL_INFO * coll )
2022-01-08 16:08:31 +11:00
{
2022-01-12 18:21:52 +11:00
MonkeyMoveTestData testData
2022-01-08 16:50:23 +11:00
{
2022-01-19 16:17:16 +11:00
item - > pos . yRot + ANGLE ( 90.0f ) ,
CLICK ( 0.5f ) ,
- CLICK ( 0.5f )
2022-01-08 16:50:23 +11:00
} ;
2022-01-12 18:21:52 +11:00
return TestLaraMonkeyMoveTolerance ( item , coll , testData ) ;
2022-01-08 16:08:31 +11:00
}
2022-01-14 23:18:24 +11:00
VaultTestResultData TestLaraVaultTolerance ( ITEM_INFO * item , COLL_INFO * coll , VaultTestData testData )
2021-12-10 12:30:23 +11:00
{
2022-01-08 15:43:17 +11:00
LaraInfo * & info = item - > data ;
2021-12-23 23:37:40 +11:00
int y = item - > pos . yPos ;
2022-01-08 16:08:31 +11:00
auto probeFront = GetCollisionResult ( item , coll - > NearestLedgeAngle , coll - > Setup . Radius * sqrt ( 2 ) + 4 , - coll - > Setup . Height ) ;
2022-01-08 15:43:17 +11:00
auto probeMiddle = GetCollisionResult ( item ) ;
bool swampTooDeep = testData . checkSwampDepth ? ( TestLaraSwamp ( item ) & & info - > waterSurfaceDist < - CLICK ( 3 ) ) : TestLaraSwamp ( item ) ;
2021-12-10 12:30:23 +11:00
2022-01-08 15:43:17 +11:00
// "Floor" ahead may be formed by ceiling; raise y position of probe point to find potential vault candidate location.
int yOffset = testData . lowerBound ;
2022-01-11 14:49:42 +11:00
while ( ( ( probeFront . Position . Ceiling - y ) > - coll - > Setup . Height | | // Ceiling is below Lara's height.
2022-01-08 16:50:23 +11:00
abs ( probeFront . Position . Ceiling - probeFront . Position . Floor ) < = testData . clampMin | | // Clamp is too small.
abs ( probeFront . Position . Ceiling - probeFront . Position . Floor ) > testData . clampMax ) & & // Clamp is too large.
2022-01-11 15:09:12 +11:00
yOffset > ( testData . upperBound - coll - > Setup . Height ) ) // Offset is not too high.
2021-12-10 12:30:23 +11:00
{
2022-01-08 16:08:31 +11:00
probeFront = GetCollisionResult ( item , coll - > NearestLedgeAngle , coll - > Setup . Radius * sqrt ( 2 ) + 4 , yOffset ) ;
2022-01-11 14:49:42 +11:00
yOffset - = std : : max ( ( int ) CLICK ( 0.5f ) , testData . clampMin ) ;
2022-01-08 15:43:17 +11:00
}
// Assess vault candidate location.
if ( ( probeFront . Position . Floor - y ) < testData . lowerBound & & // Lower floor bound.
( probeFront . Position . Floor - y ) > = testData . upperBound & & // Upper floor bound.
abs ( probeFront . Position . Ceiling - probeFront . Position . Floor ) > testData . clampMin & & // Lower clamp limit.
abs ( probeFront . Position . Ceiling - probeFront . Position . Floor ) < = testData . clampMax & & // Upper clamp limit.
abs ( probeMiddle . Position . Ceiling - probeFront . Position . Floor ) > = testData . gapMin & & // Gap is optically permissive.
! swampTooDeep & & // Swamp depth is permissive.
probeFront . Position . Floor ! = NO_HEIGHT )
2021-10-16 20:50:16 +11:00
{
2022-01-08 15:43:17 +11:00
2022-01-14 23:18:24 +11:00
return VaultTestResultData { true , probeFront . Position . Floor } ;
2021-10-16 20:50:16 +11:00
}
2022-01-14 23:18:24 +11:00
return VaultTestResultData { false , NO_HEIGHT } ;
2021-10-16 20:50:16 +11:00
}
2022-01-14 23:18:24 +11:00
VaultTestResultData TestLaraVault2Steps ( ITEM_INFO * item , COLL_INFO * coll )
2021-10-28 23:22:28 +11:00
{
2022-01-08 15:43:17 +11:00
// Floor range: (-STEPUP_HEIGHT, -CLICK(2.5f)]
// Clamp range: (-LARA_HEIGHT, MAX_HEIGHT]
2021-10-28 23:22:28 +11:00
2022-01-08 15:43:17 +11:00
VaultTestData testData
{
- STEPUP_HEIGHT ,
- CLICK ( 2.5f ) ,
LARA_HEIGHT ,
- MAX_HEIGHT ,
2022-01-14 13:15:16 +11:00
CLICK ( 1 )
2022-01-08 15:43:17 +11:00
} ;
2021-10-22 00:07:24 +11:00
2022-01-08 15:43:17 +11:00
return TestLaraVaultTolerance ( item , coll , testData ) ;
2021-10-19 21:28:36 +11:00
}
2022-01-14 23:18:24 +11:00
VaultTestResultData TestLaraVault3Steps ( ITEM_INFO * item , COLL_INFO * coll )
2021-10-19 21:28:36 +11:00
{
2022-01-08 15:43:17 +11:00
// Floor range: (-CLICK(2.5f), -CLICK(3.5f)]
// Clamp range: (-LARA_HEIGHT, MAX_HEIGHT]
2021-10-04 22:02:02 +11:00
2022-01-08 15:43:17 +11:00
VaultTestData testData
{
- CLICK ( 2.5f ) ,
- CLICK ( 3.5f ) ,
LARA_HEIGHT ,
- MAX_HEIGHT ,
CLICK ( 1 ) ,
} ;
2021-10-19 21:28:36 +11:00
2022-01-08 15:43:17 +11:00
return TestLaraVaultTolerance ( item , coll , testData ) ;
2021-10-24 20:43:02 +11:00
}
2021-10-04 22:02:02 +11:00
2022-01-14 23:18:24 +11:00
VaultTestResultData TestLaraVaultAutoJump ( ITEM_INFO * item , COLL_INFO * coll )
2021-12-26 15:30:53 +11:00
{
2022-01-08 15:43:17 +11:00
// Floor range: (-CLICK(3.5f), -CLICK(7.5f)]
// Clamp range: (-CLICK(0.1f), MAX_HEIGHT]
2021-12-26 15:30:53 +11:00
2022-01-08 15:43:17 +11:00
VaultTestData testData
{
- CLICK ( 3.5f ) ,
- CLICK ( 7.5f ) ,
CLICK ( 0.1f ) , // TODO: Is this enough hand room?
- MAX_HEIGHT ,
CLICK ( 0.1f ) ,
false
} ;
return TestLaraVaultTolerance ( item , coll , testData ) ;
2021-11-07 21:55:38 +11:00
}
2022-01-14 23:18:24 +11:00
VaultTestResultData TestLaraVault1StepToCrouch ( ITEM_INFO * item , COLL_INFO * coll )
2021-11-07 21:55:38 +11:00
{
2022-01-08 15:43:17 +11:00
// Floor range: (0, -STEPUP_HEIGHT]
// Clamp range: (-LARA_HEIGHT_CRAWL, -LARA_HEIGHT]
VaultTestData testData
{
0 ,
- STEPUP_HEIGHT ,
LARA_HEIGHT_CRAWL ,
LARA_HEIGHT ,
CLICK ( 1 ) ,
} ;
return TestLaraVaultTolerance ( item , coll , testData ) ;
2021-11-07 21:55:38 +11:00
}
2022-01-14 23:18:24 +11:00
VaultTestResultData TestLaraVault2StepsToCrouch ( ITEM_INFO * item , COLL_INFO * coll )
2021-11-07 21:55:38 +11:00
{
2022-01-08 15:43:17 +11:00
// Floor range: (-STEPUP_HEIGHT, -CLICK(2.5f)]
// Clamp range: (-LARA_HEIGHT_CRAWL, -LARA_HEIGHT]
VaultTestData testData
{
- STEPUP_HEIGHT ,
- CLICK ( 2.5f ) ,
LARA_HEIGHT_CRAWL ,
LARA_HEIGHT ,
CLICK ( 1 ) ,
} ;
return TestLaraVaultTolerance ( item , coll , testData ) ;
2021-11-07 21:55:38 +11:00
}
2022-01-14 23:18:24 +11:00
VaultTestResultData TestLaraVault3StepsToCrouch ( ITEM_INFO * item , COLL_INFO * coll )
2021-10-24 20:43:02 +11:00
{
2022-01-08 15:43:17 +11:00
// Floor range: (-CLICK(2.5f), -CLICK(3.5f)]
// Clamp range: (-LARA_HEIGHT_CRAWL, -LARA_HEIGHT]
VaultTestData testData
{
- CLICK ( 2.5f ) ,
- CLICK ( 3.5f ) ,
LARA_HEIGHT_CRAWL ,
LARA_HEIGHT ,
CLICK ( 1 ) ,
} ;
return TestLaraVaultTolerance ( item , coll , testData ) ;
2021-10-24 20:43:02 +11:00
}
2021-10-04 22:02:02 +11:00
2022-01-14 23:18:24 +11:00
VaultTestResultData TestLaraLadderAutoJump ( ITEM_INFO * item , COLL_INFO * coll )
2021-10-16 20:50:16 +11:00
{
2022-01-08 15:43:17 +11:00
LaraInfo * & info = item - > data ;
2021-12-23 23:37:40 +11:00
int y = item - > pos . yPos ;
2022-01-08 16:30:27 +11:00
auto probeFront = GetCollisionResult ( item , coll - > NearestLedgeAngle , coll - > Setup . Radius * sqrt ( 2 ) + 4 , - coll - > Setup . Height ) ;
2022-01-08 15:43:17 +11:00
auto probeMiddle = GetCollisionResult ( item ) ;
if ( TestValidLedgeAngle ( item , coll ) & &
! TestLaraSwamp ( item ) & & // No swamp.
info - > climbStatus & & // Ladder sector flag set.
( probeMiddle . Position . Ceiling - y ) < = - CLICK ( 6.5f ) & & // Lower middle ceiling bound.
coll - > NearestLedgeDistance < = coll - > Setup . Radius ) // Appropriate distance from wall.
2021-10-16 20:50:16 +11:00
{
2022-01-14 23:18:24 +11:00
return VaultTestResultData { true , probeMiddle . Position . Ceiling } ;
2021-10-16 20:50:16 +11:00
}
2022-01-14 23:18:24 +11:00
return VaultTestResultData { false , NO_HEIGHT } ;
2021-10-16 20:50:16 +11:00
}
2022-01-08 15:43:17 +11:00
bool TestLaraLadderMount ( ITEM_INFO * item , COLL_INFO * coll )
2021-10-16 20:50:16 +11:00
{
2021-11-20 12:25:51 +11:00
LaraInfo * & info = item - > data ;
2021-12-23 23:37:40 +11:00
int y = item - > pos . yPos ;
2022-01-08 16:08:31 +11:00
auto probeFront = GetCollisionResult ( item , coll - > NearestLedgeAngle , coll - > Setup . Radius * sqrt ( 2 ) + 4 , - coll - > Setup . Height ) ;
2022-01-08 15:43:17 +11:00
auto probeMiddle = GetCollisionResult ( item ) ;
if ( TestValidLedgeAngle ( item , coll ) & &
info - > climbStatus & & // Ladder sector flag set.
( probeMiddle . Position . Ceiling - y ) < = - CLICK ( 4.5f ) & & // Lower middle ceiling bound.
( probeMiddle . Position . Floor - y ) > - CLICK ( 6.5f ) & & // Upper middle floor bound.
( probeFront . Position . Ceiling - y ) < = - CLICK ( 4.5f ) & & // Lower front ceiling bound.
coll - > NearestLedgeDistance < = coll - > Setup . Radius ) // Appropriate distance from wall.
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-11-29 00:06:18 +11:00
2022-01-14 23:18:24 +11:00
bool TestLaraMonkeyAutoJump ( 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-12-26 15:30:53 +11:00
int y = item - > pos . yPos ;
2022-01-14 23:18:24 +11:00
auto probe = GetCollisionResult ( item ) ;
2021-11-11 23:31:04 +11:00
2022-01-14 23:18:24 +11:00
if ( ! TestLaraSwamp ( item ) & & // No swamp.
info - > canMonkeySwing & & // Monkey swing sector flag set.
( probe . Position . Ceiling - y ) < - LARA_HEIGHT_MONKEY & & // Lower ceiling bound.
( probe . Position . Ceiling - y ) > = - CLICK ( 7 ) ) // Upper ceiling bound.
2021-10-16 20:50:16 +11:00
{
return true ;
}
return false ;
}
2022-01-08 15:43:17 +11:00
bool TestLaraCrawlVaultTolerance ( ITEM_INFO * item , COLL_INFO * coll , CrawlVaultTestData testData )
2021-10-16 20:50:16 +11:00
{
2021-12-26 15:30:53 +11:00
int y = item - > pos . yPos ;
2022-01-08 15:43:17 +11:00
auto probeA = GetCollisionResult ( item , item - > pos . yRot , testData . crossDist , - LARA_HEIGHT_CRAWL ) ; // Crossing.
auto probeB = GetCollisionResult ( item , item - > pos . yRot , testData . destDist , - LARA_HEIGHT_CRAWL ) ; // Approximate destination.
2022-01-02 14:21:45 +11:00
auto probeMiddle = GetCollisionResult ( item ) ;
2022-01-18 16:52:52 +11:00
bool isSlope = testData . checkSlope ? probeB . Position . FloorSlope : false ;
2022-01-08 15:43:17 +11:00
bool isDeath = testData . checkDeath ? probeB . Block - > Flags . Death : false ;
if ( ( probeA . Position . Floor - y ) < = testData . lowerBound & & // Lower floor bound.
( probeA . Position . Floor - y ) > = testData . upperBound & & // Upper floor bound.
abs ( probeA . Position . Ceiling - probeA . Position . Floor ) > testData . clampMin & & // Crossing clamp limit.
abs ( probeB . Position . Ceiling - probeB . Position . Floor ) > testData . clampMin & & // Destination clamp limit.
abs ( probeMiddle . Position . Ceiling - probeA . Position . Floor ) > = testData . gapMin & & // Gap is optically permissive (going up).
abs ( probeA . Position . Ceiling - probeMiddle . Position . Floor ) > = testData . gapMin & & // Gap is optically permissive (going down).
abs ( probeA . Position . Floor - probeB . Position . Floor ) < = testData . probeDeltaMax & & // Crossing and destination floor height difference suggests continuous crawl surface.
( probeA . Position . Ceiling - y ) < - testData . gapMin & & // Ceiling height is permissive.
! isSlope & & ! isDeath & & // No slope or death sector.
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 ;
}
2022-01-02 14:21:45 +11:00
bool TestLaraCrawlUpStep ( ITEM_INFO * item , COLL_INFO * coll )
2021-10-16 20:50:16 +11:00
{
2022-01-08 15:43:17 +11:00
// Floor range: [-CLICK(1), -STEPUP_HEIGHT]
CrawlVaultTestData testData
{
- CLICK ( 1 ) ,
- STEPUP_HEIGHT ,
LARA_HEIGHT_CRAWL ,
CLICK ( 0.6f ) ,
CLICK ( 1.2f ) ,
CLICK ( 2 ) ,
CLICK ( 1 ) - 1
} ;
return TestLaraCrawlVaultTolerance ( item , coll , testData ) ;
2022-01-02 14:21:45 +11:00
}
2021-10-16 20:50:16 +11:00
2022-01-02 14:21:45 +11:00
bool TestLaraCrawlDownStep ( ITEM_INFO * item , COLL_INFO * coll )
{
2022-01-08 15:43:17 +11:00
// Floor range: [STEPUP_HEIGHT, CLICK(1)]
CrawlVaultTestData testData
{
STEPUP_HEIGHT ,
CLICK ( 1 ) ,
LARA_HEIGHT_CRAWL ,
CLICK ( 0.6f ) ,
CLICK ( 1.2f ) ,
CLICK ( 2 ) ,
CLICK ( 1 ) - 1
} ;
return TestLaraCrawlVaultTolerance ( item , coll , testData ) ;
2021-10-16 20:50:16 +11:00
}
bool TestLaraCrawlExitDownStep ( ITEM_INFO * item , COLL_INFO * coll )
{
2022-01-08 15:43:17 +11:00
// Floor range: [STEPUP_HEIGHT, CLICK(1)]
CrawlVaultTestData testData
{
STEPUP_HEIGHT ,
CLICK ( 1 ) ,
LARA_HEIGHT ,
CLICK ( 1.25f ) ,
CLICK ( 1.2f ) ,
CLICK ( 1.5f ) ,
- MAX_HEIGHT ,
false
} ;
return TestLaraCrawlVaultTolerance ( item , coll , testData ) ;
2021-10-16 20:50:16 +11:00
}
bool TestLaraCrawlExitJump ( ITEM_INFO * item , COLL_INFO * coll )
{
2022-01-08 15:43:17 +11:00
// Floor range: [-MAX_HEIGHT, STEPUP_HEIGHT)
CrawlVaultTestData testData
{
- MAX_HEIGHT ,
STEPUP_HEIGHT + 1 ,
LARA_HEIGHT ,
CLICK ( 1.25f ) ,
CLICK ( 1.2f ) ,
CLICK ( 1.5f ) ,
- MAX_HEIGHT ,
false
} ;
return TestLaraCrawlVaultTolerance ( item , coll , testData ) ;
2021-10-16 20:50:16 +11:00
}
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 )
{
2021-12-23 23:37:40 +11:00
int y = item - > pos . yPos ;
2022-01-13 00:14:13 +11:00
auto probe = GetCollisionResult ( item , item - > pos . yRot + ANGLE ( 180.0f ) , CLICK ( 1.2f ) , - LARA_HEIGHT_CRAWL ) ;
bool objectCollided = TestLaraObjectCollision ( item , item - > pos . yRot + ANGLE ( 180.0f ) , CLICK ( 1.2f ) , - LARA_HEIGHT_CRAWL ) ;
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.
2022-01-02 14:21:45 +11:00
( probe . Position . Ceiling - y ) < = - CLICK ( 0.75f ) & & // Gap is optically permissive.
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
2022-01-12 18:21:52 +11:00
bool TestLaraJumpTolerance ( ITEM_INFO * item , COLL_INFO * coll , JumpTestData testData )
{
LaraInfo * & info = item - > data ;
int y = item - > pos . yPos ;
2022-01-19 22:45:38 +11:00
auto probe = GetCollisionResult ( item , testData . Angle , testData . Dist , - coll - > Setup . Height ) ;
bool isWading = testData . CheckWadeStatus ? ( info - > waterStatus = = LW_WADE ) : false ;
if ( ( ( probe . Position . Floor - y ) > = - STEPUP_HEIGHT | | // Highest floor bound...
probe . Position . FloorSlope ) & & // OR surface is a slope.
( ( probe . Position . Ceiling - y ) < - ( coll - > Setup . Height + ( LARA_HEADROOM * 0.7f ) ) | | // Ceiling height is permissive...
( ( probe . Position . Ceiling - y ) < - coll - > Setup . Height & & // OR ceiling is level with Lara's head
( probe . Position . Floor - y ) > = CLICK ( 0.5f ) ) ) & & // AND there is a drop below.
! isWading & & // Not wading in water (if applicable).
! TestLaraSwamp ( item ) & & // No swamp.
! TestLaraFacingCorner ( item , testData . Angle , testData . Dist ) & & // Avoid jumping through corners.
2022-01-12 18:21:52 +11:00
probe . Position . Floor ! = NO_HEIGHT )
{
return true ;
}
return false ;
}
bool TestLaraRunJumpForward ( ITEM_INFO * item , COLL_INFO * coll )
{
JumpTestData testData
{
item - > pos . yRot ,
CLICK ( 1.5f )
} ;
return TestLaraJumpTolerance ( item , coll , testData ) ;
}
bool TestLaraJumpForward ( ITEM_INFO * item , COLL_INFO * coll )
{
JumpTestData testData
{
item - > pos . yRot
} ;
return TestLaraJumpTolerance ( item , coll , testData ) ;
}
bool TestLaraJumpBack ( ITEM_INFO * item , COLL_INFO * coll )
{
JumpTestData testData
{
item - > pos . yRot + ANGLE ( 180.0f )
} ;
return TestLaraJumpTolerance ( item , coll , testData ) ;
}
bool TestLaraJumpLeft ( ITEM_INFO * item , COLL_INFO * coll )
{
JumpTestData testData
{
item - > pos . yRot - ANGLE ( 90.0f )
} ;
return TestLaraJumpTolerance ( item , coll , testData ) ;
}
bool TestLaraJumpRight ( ITEM_INFO * item , COLL_INFO * coll )
{
JumpTestData testData
{
item - > pos . yRot + ANGLE ( 90.0f )
} ;
return TestLaraJumpTolerance ( item , coll , testData ) ;
}
bool TestLaraJumpUp ( ITEM_INFO * item , COLL_INFO * coll )
{
JumpTestData testData
{
0 ,
0 ,
false
} ;
return TestLaraJumpTolerance ( item , coll , testData ) ;
}
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 ) ;
}