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
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.
2022-03-14 01:20:51 +11:00
bool TestValidLedge ( ITEM_INFO * item , CollisionInfo * 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
2022-03-04 15:14:38 +11:00
int xl = phd_sin ( coll - > NearestLedgeAngle - ANGLE ( 90.0f ) ) * coll - > Setup . Radius ;
int zl = phd_cos ( coll - > NearestLedgeAngle - ANGLE ( 90.0f ) ) * coll - > Setup . Radius ;
int xr = phd_sin ( coll - > NearestLedgeAngle + ANGLE ( 90.0f ) ) * coll - > Setup . Radius ;
int zr = phd_cos ( coll - > NearestLedgeAngle + ANGLE ( 90.0f ) ) * coll - > Setup . Radius ;
2020-09-26 05:06:08 +10:00
2021-10-08 00:54:00 +03:00
// Determine probe top point
2022-02-09 16:55:46 +11:00
int y = item - > Position . yPos - coll - > Setup . Height ;
2020-09-26 05:06:08 +10:00
2021-12-13 13:32:45 +03:00
// Get frontal collision data
2022-03-14 01:20:51 +11:00
auto frontLeft = GetCollision ( item - > Position . xPos + xl , y , item - > Position . zPos + zl , GetRoom ( item - > Location , item - > Position . xPos , y , item - > Position . zPos ) . roomNumber ) ;
auto frontRight = GetCollision ( item - > Position . xPos + xr , y , item - > Position . zPos + zr , GetRoom ( item - > Location , item - > Position . xPos , y , item - > Position . zPos ) . roomNumber ) ;
2021-12-13 13:32:45 +03:00
// 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.
2022-02-09 16:55:46 +11:00
if ( frontLeft . Position . Floor < ( item - > Position . yPos - CLICK ( 0.5f ) ) | | frontRight . Position . Floor < ( item - > Position . yPos - CLICK ( 0.5f ) ) )
2021-12-13 13:32:45 +03:00
return false ;
2022-02-09 16:55:46 +11:00
if ( frontLeft . Position . Ceiling > ( item - > Position . yPos - coll - > Setup . Height ) | | frontRight . Position . Ceiling > ( item - > Position . yPos - coll - > Setup . Height ) )
2021-12-13 13:32:45 +03:00
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
2022-03-14 01:20:51 +11:00
auto left = GetCollision ( item - > Position . xPos + xf + xl , y , item - > Position . zPos + zf + zl , GetRoom ( item - > Location , item - > Position . xPos , y , item - > Position . zPos ) . roomNumber ) . Position . Floor ;
auto right = GetCollision ( item - > Position . xPos + xf + xr , y , item - > Position . zPos + zf + zr , GetRoom ( item - > Location , item - > Position . xPos , y , item - > Position . 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
2022-03-04 15:14:38 +11:00
auto slopeDelta = ( ( float ) STEPUP_HEIGHT / ( float ) SECTOR ( 1 ) ) * ( coll - > Setup . Radius * 2 ) ;
2021-12-13 13:32:45 +03:00
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-27 13:24:49 +11:00
if ( abs ( coll - > NearestLedgeDistance ) > OFFSET_RADIUS ( coll - > Setup . Radius ) )
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
2022-03-14 01:20:51 +11:00
bool TestValidLedgeAngle ( ITEM_INFO * item , CollisionInfo * coll )
2021-10-27 01:23:59 +03:00
{
2022-02-09 16:55:46 +11:00
return ( abs ( ( short ) ( coll - > NearestLedgeAngle - item - > Position . yRot ) ) < = LARA_GRAB_THRESHOLD ) ;
2020-09-26 05:06:08 +10:00
}
2022-03-14 01:20:51 +11:00
bool TestLaraHang ( ITEM_INFO * item , CollisionInfo * coll )
2020-09-26 05:06:08 +10:00
{
2022-02-28 21:02:19 +11:00
auto * lara = GetLaraInfo ( item ) ;
2021-11-29 15:26:55 +11:00
2022-02-28 21:02:19 +11:00
auto angle = lara - > Control . MoveAngle ;
2021-09-14 00:03:24 +03:00
2021-11-30 02:39:41 +03:00
auto climbShift = 0 ;
2022-02-28 21:02:19 +11:00
if ( lara - > Control . MoveAngle = = ( short ) ( item - > Position . yRot - ANGLE ( 90.0f ) ) )
2021-11-30 02:39:41 +03:00
climbShift = - coll - > Setup . Radius ;
2022-02-28 21:02:19 +11:00
else if ( lara - > Control . MoveAngle = = ( short ) ( item - > Position . 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
2022-02-09 16:55:46 +11:00
auto oldPos = item - > Position ;
item - > Position . xPos + = phd_sin ( item - > Position . yRot ) * coll - > Setup . Radius * 0.5f ;
item - > Position . zPos + = phd_cos ( item - > Position . yRot ) * coll - > Setup . Radius * 0.5f ;
2021-11-29 20:45:22 +03:00
2021-11-30 02:39:41 +03:00
// Get height difference with side spaces (left or right, depending on movement direction)
2022-02-28 21:02:19 +11:00
auto hdif = LaraFloorFront ( item , lara - > Control . 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
2022-02-28 21:02:19 +11:00
if ( LaraCeilingFront ( item , lara - > Control . 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
2022-02-09 16:55:46 +11:00
item - > Position = oldPos ;
2021-09-14 00:03:24 +03:00
2022-02-28 21:02:19 +11:00
// Setup coll lara
lara - > Control . MoveAngle = item - > Position . yRot ;
2022-01-30 14:43:33 +11:00
coll - > Setup . LowerFloorBound = NO_LOWER_BOUND ;
coll - > Setup . UpperFloorBound = - STEPUP_HEIGHT ;
coll - > Setup . LowerCeilingBound = 0 ;
2022-02-28 21:02:19 +11:00
coll - > Setup . ForwardAngle = lara - > Control . 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 ;
2022-02-09 16:55:46 +11:00
item - > Position . xPos + = phd_sin ( item - > Position . yRot ) * embedOffset ;
item - > Position . zPos + = phd_cos ( item - > Position . 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 ;
2022-02-28 21:02:19 +11:00
if ( lara - > Control . CanClimbLadder ) // Ladder case
2020-09-26 05:06:08 +10:00
{
2022-02-09 16:55:46 +11:00
if ( TrInput & IN_ACTION & & item - > HitPoints > 0 )
2020-09-26 05:06:08 +10:00
{
2022-02-28 21:02:19 +11:00
lara - > Control . MoveAngle = angle ;
2021-09-14 00:03:24 +03:00
2022-03-16 21:56:25 +11:00
if ( ! TestLaraHangOnClimbableWall ( item , coll ) )
2020-09-26 05:06:08 +10:00
{
2022-03-13 02:04:24 +11:00
if ( item - > Animation . AnimNumber ! = LA_LADDER_TO_HANG_RIGHT & &
item - > Animation . AnimNumber ! = LA_LADDER_TO_HANG_LEFT )
2020-09-26 05:06:08 +10:00
{
2022-02-09 16:55:46 +11:00
LaraSnapToEdgeOfBlock ( item , coll , GetQuadrant ( item - > Position . yRot ) ) ;
item - > Position . 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
{
2022-03-13 02:04:24 +11:00
if ( item - > Animation . AnimNumber = = LA_REACH_TO_HANG & & item - > Animation . FrameNumber = = GetFrameNumber ( item , 21 ) & &
2022-03-16 21:56:25 +11:00
TestLaraClimbIdle ( item , coll ) )
2021-11-10 02:01:43 +11:00
{
2022-03-13 02:04:24 +11:00
item - > Animation . TargetState = 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 ) ;
2022-03-17 18:57:46 +11:00
item - > Position . yPos + = CLICK ( 1 ) ;
2022-03-13 02:04:24 +11:00
item - > Animation . Airborne = true ;
item - > Animation . Velocity = 2 ;
item - > Animation . VerticalVelocity = 1 ;
2022-02-28 21:02:19 +11:00
lara - > Control . HandStatus = HandStatus : : 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
{
2022-02-09 16:55:46 +11: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 ;
2022-02-09 16:55:46 +11:00
auto x = item - > Position . xPos ;
auto z = item - > Position . zPos ;
2021-09-14 00:03:24 +03:00
2022-02-28 21:02:19 +11:00
lara - > Control . MoveAngle = angle ;
2021-11-30 02:39:41 +03:00
if ( climbShift ! = 0 )
2020-09-26 05:06:08 +10:00
{
2022-02-28 21:02:19 +11:00
auto s = phd_sin ( lara - > Control . MoveAngle ) ;
auto c = phd_cos ( lara - > Control . 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
2022-02-09 16:55:46 +11:00
if ( ( 256 < < GetQuadrant ( item - > Position . yRot ) ) & GetClimbFlags ( x , item - > Position . yPos , z , item - > RoomNumber ) )
2020-09-26 05:06:08 +10:00
{
2022-03-16 21:56:25 +11:00
if ( ! TestLaraHangOnClimbableWall ( item , coll ) )
2021-11-30 02:51:19 +03:00
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
{
2022-03-16 21:56:25 +11:00
if ( ( climbShift < 0 & & coll - > FrontLeft . Floor ! = coll - > Front . Floor ) | |
2021-11-30 02:39:41 +03:00
( climbShift > 0 & & coll - > FrontRight . Floor ! = coll - > Front . Floor ) )
2022-01-29 07:54:04 +11:00
{
2021-11-30 02:39:41 +03:00
stopped = true ;
2022-01-29 07:54:04 +11:00
}
2020-09-26 05:06:08 +10:00
}
2021-09-14 00:03:24 +03:00
2022-03-16 21:56:25 +11:00
if ( ! stopped & &
coll - > Middle . Ceiling < 0 & & coll - > CollisionType = = CT_FRONT & & ! coll - > HitStatic & &
2021-11-30 02:39:41 +03:00
abs ( verticalShift ) < SLOPE_DIFFERENCE & & TestValidLedgeAngle ( item , coll ) )
2020-09-26 05:06:08 +10:00
{
2022-03-13 02:04:24 +11:00
if ( item - > Animation . Velocity ! = 0 )
2021-10-23 15:35:59 +03:00
SnapItemToLedge ( item , coll ) ;
2021-09-14 00:03:24 +03:00
2022-02-09 16:55:46 +11:00
item - > Position . yPos + = verticalShift ;
2020-09-26 05:06:08 +10:00
}
else
{
2022-02-09 16:55:46 +11:00
item - > Position . xPos = coll - > Setup . OldPosition . x ;
item - > Position . yPos = coll - > Setup . OldPosition . y ;
item - > Position . zPos = coll - > Setup . OldPosition . z ;
2021-09-14 00:03:24 +03:00
2022-03-16 21:56:25 +11:00
if ( item - > Animation . ActiveState = = LS_SHIMMY_LEFT | |
2022-03-13 02:04:24 +11:00
item - > Animation . ActiveState = = 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
}
}
2022-01-29 07:54:04 +11: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 ) ;
2022-02-09 16:55:46 +11:00
item - > Position . xPos + = coll - > Shift . x ;
item - > Position . yPos + = GetBoundsAccurate ( item ) - > Y2 * 1.8f ;
item - > Position . zPos + = coll - > Shift . z ;
2022-03-13 02:04:24 +11:00
item - > Animation . Airborne = true ;
item - > Animation . Velocity = 2 ;
item - > Animation . VerticalVelocity = 1 ;
2022-02-28 21:02:19 +11:00
lara - > Control . HandStatus = HandStatus : : 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-03-16 21:56:25 +11:00
bool TestLaraHangJump ( ITEM_INFO * item , CollisionInfo * coll )
2022-01-14 19:25:56 +03:00
{
2022-02-28 21:02:19 +11:00
auto * lara = GetLaraInfo ( item ) ;
2022-02-10 01:38:32 +11:00
2022-03-16 21:56:25 +11:00
if ( ! ( TrInput & IN_ACTION ) | | lara - > Control . HandStatus ! = HandStatus : : Free | | coll - > HitStatic )
return false ;
2022-01-14 19:25:56 +03:00
2022-03-16 21:56:25 +11:00
if ( TestLaraMonkeyGrab ( item , coll ) )
{
SetAnimation ( item , LA_REACH_TO_MONKEY ) ;
ResetLaraFlex ( item ) ;
item - > Animation . Velocity = 0 ;
item - > Animation . VerticalVelocity = 0 ;
item - > Animation . Airborne = false ;
item - > Position . yPos + = coll - > Middle . Ceiling + ( LARA_HEIGHT_MONKEY - coll - > Setup . Height ) ;
lara - > Control . HandStatus = HandStatus : : Busy ;
return true ;
}
2022-01-14 19:25:56 +03:00
2022-03-16 21:56:25 +11:00
if ( coll - > Middle . Ceiling > - STEPUP_HEIGHT | |
coll - > Middle . Floor < 200 | |
coll - > CollisionType ! = CT_FRONT )
{
return false ;
}
2022-01-14 19:25:56 +03:00
2022-03-16 21:56:25 +11:00
int edge ;
auto edgeCatch = TestLaraEdgeCatch ( item , coll , & edge ) ;
if ( ! edgeCatch )
return false ;
2022-01-14 19:25:56 +03:00
2022-03-16 21:56:25 +11:00
bool ladder = TestLaraHangOnClimbableWall ( item , coll ) ;
if ( ! ( ladder & & edgeCatch ) & &
! ( TestValidLedge ( item , coll , true , true ) & & edgeCatch > 0 ) )
2022-01-14 19:25:56 +03:00
{
2022-03-16 21:56:25 +11:00
return false ;
}
2022-01-14 19:25:56 +03:00
2022-03-16 21:56:25 +11:00
if ( TestHangSwingIn ( item , coll ) )
{
SetAnimation ( item , LA_REACH_TO_HANG_OSCILLATE ) ;
ResetLaraFlex ( item ) ;
}
else
SetAnimation ( item , LA_REACH_TO_HANG ) ;
2022-01-14 19:25:56 +03:00
2022-03-16 21:56:25 +11:00
auto bounds = GetBoundsAccurate ( item ) ;
if ( edgeCatch < = 0 )
{
item - > Position . yPos = edge - bounds - > Y1 - 20 ;
item - > Position . yRot = coll - > NearestLedgeAngle ;
}
else
item - > Position . yPos + = coll - > Front . Floor - bounds - > Y1 - 20 ;
2022-01-14 19:25:56 +03:00
2022-03-16 21:56:25 +11: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-14 19:25:56 +03:00
2022-03-16 21:56:25 +11:00
item - > Animation . Velocity = 2 ;
item - > Animation . VerticalVelocity = 1 ;
item - > Animation . Airborne = true ;
lara - > Control . HandStatus = HandStatus : : Busy ;
return true ;
}
2022-01-14 19:25:56 +03:00
2022-03-16 21:56:25 +11:00
bool TestLaraHangJumpUp ( ITEM_INFO * item , CollisionInfo * coll )
{
auto * lara = GetLaraInfo ( item ) ;
2022-01-14 19:25:56 +03:00
2022-03-16 21:56:25 +11:00
if ( ! ( TrInput & IN_ACTION ) | | lara - > Control . HandStatus ! = HandStatus : : Free | | coll - > HitStatic )
return false ;
2022-01-14 19:25:56 +03:00
2022-03-16 21:56:25 +11:00
if ( TestLaraMonkeyGrab ( item , coll ) )
{
SetAnimation ( item , LA_JUMP_UP_TO_MONKEY ) ;
item - > Animation . Velocity = 0 ;
item - > Animation . VerticalVelocity = 0 ;
item - > Animation . Airborne = false ;
item - > Position . yPos + = coll - > Middle . Ceiling + ( LARA_HEIGHT_MONKEY - coll - > Setup . Height ) ;
lara - > Control . HandStatus = HandStatus : : Busy ;
return true ;
}
2022-01-14 19:25:56 +03:00
2022-03-16 21:56:25 +11:00
if ( coll - > Middle . Ceiling > - STEPUP_HEIGHT | | coll - > CollisionType ! = CT_FRONT )
return false ;
int edge ;
auto edgeCatch = TestLaraEdgeCatch ( item , coll , & edge ) ;
if ( ! edgeCatch )
return false ;
bool ladder = TestLaraHangOnClimbableWall ( item , coll ) ;
if ( ! ( ladder & & edgeCatch ) & &
! ( TestValidLedge ( item , coll , true , true ) & & edgeCatch > 0 ) )
{
return false ;
}
SetAnimation ( item , LA_REACH_TO_HANG , 12 ) ;
auto bounds = GetBoundsAccurate ( item ) ;
if ( edgeCatch < = 0 )
item - > Position . yPos = edge - bounds - > Y1 + 4 ;
else
item - > Position . yPos + = coll - > Front . Floor - bounds - > Y1 ;
if ( ladder )
SnapItemToGrid ( item , coll ) ; // HACK: until fragile ladder code is refactored, we must exactly snap to grid.
else
SnapItemToLedge ( item , coll ) ;
item - > Animation . Velocity = 0 ;
item - > Animation . VerticalVelocity = 0 ;
item - > Animation . Airborne = false ;
lara - > Control . HandStatus = HandStatus : : Busy ;
lara - > ExtraTorsoRot = PHD_3DPOS ( ) ;
return true ;
}
int TestLaraEdgeCatch ( ITEM_INFO * item , CollisionInfo * coll , int * edge )
{
BOUNDING_BOX * bounds = GetBoundsAccurate ( item ) ;
int hdif = coll - > Front . Floor - bounds - > Y1 ;
if ( hdif < 0 = = hdif + item - > Animation . VerticalVelocity < 0 )
{
hdif = item - > Position . yPos + bounds - > Y1 ;
if ( ( hdif + item - > Animation . VerticalVelocity & 0xFFFFFF00 ) ! = ( hdif & 0xFFFFFF00 ) )
2022-01-14 19:25:56 +03:00
{
2022-03-16 21:56:25 +11:00
if ( item - > Animation . VerticalVelocity > 0 )
* edge = ( hdif + item - > Animation . VerticalVelocity ) & 0xFFFFFF00 ;
else
* edge = hdif & 0xFFFFFF00 ;
return - 1 ;
2022-01-14 19:25:56 +03:00
}
2022-03-16 21:56:25 +11:00
return 0 ;
2022-01-14 19:25:56 +03:00
}
2022-03-16 21:56:25 +11:00
if ( ! TestValidLedge ( item , coll , true ) )
return 0 ;
return 1 ;
2022-01-14 19:25:56 +03:00
}
2022-03-16 21:56:25 +11:00
bool TestLaraClimbIdle ( ITEM_INFO * item , CollisionInfo * coll )
{
int shiftRight , shiftLeft ;
if ( LaraTestClimbPos ( item , coll - > Setup . Radius , coll - > Setup . Radius + CLICK ( 0.5f ) , - 700 , CLICK ( 2 ) , & shiftRight ) ! = 1 )
return false ;
if ( LaraTestClimbPos ( item , coll - > Setup . Radius , - ( coll - > Setup . Radius + CLICK ( 0.5f ) ) , - 700 , CLICK ( 2 ) , & shiftLeft ) ! = 1 )
return false ;
if ( shiftRight )
{
if ( shiftLeft )
{
if ( shiftRight < 0 ! = shiftLeft < 0 )
return false ;
if ( ( shiftRight < 0 & & shiftLeft < shiftRight ) | |
( shiftRight > 0 & & shiftLeft > shiftRight ) )
{
item - > Position . yPos + = shiftLeft ;
return true ;
}
}
item - > Position . yPos + = shiftRight ;
}
else if ( shiftLeft )
item - > Position . yPos + = shiftLeft ;
return true ;
}
bool TestLaraHangOnClimbableWall ( ITEM_INFO * item , CollisionInfo * coll )
{
auto * lara = GetLaraInfo ( item ) ;
int shift , result ;
if ( ! lara - > Control . CanClimbLadder )
return false ;
if ( item - > Animation . VerticalVelocity < 0 )
return false ;
// 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.
auto coll2 = * coll ;
coll2 . Setup . Mode = CollisionProbeMode : : Quadrants ;
GetCollisionInfo ( & coll2 , item ) ;
switch ( GetQuadrant ( item - > Position . yRot ) )
{
case NORTH :
case SOUTH :
item - > Position . zPos + = coll2 . Shift . z ;
break ;
case EAST :
case WEST :
item - > Position . xPos + = coll2 . Shift . x ;
break ;
default :
break ;
}
auto bounds = GetBoundsAccurate ( item ) ;
if ( lara - > Control . MoveAngle ! = item - > Position . yRot )
{
short l = LaraCeilingFront ( item , item - > Position . yRot , 0 , 0 ) ;
short r = LaraCeilingFront ( item , lara - > Control . MoveAngle , CLICK ( 0.5f ) , 0 ) ;
if ( abs ( l - r ) > SLOPE_DIFFERENCE )
return false ;
}
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 ) )
{
result = LaraTestClimbPos ( item , LARA_RAD , 0 , bounds - > Y1 , bounds - > Y2 - bounds - > Y1 , & shift ) ;
if ( result )
{
if ( result ! = 1 )
item - > Position . yPos + = shift ;
return true ;
}
}
return false ;
}
bool TestLaraValidHangPosition ( ITEM_INFO * item , CollisionInfo * coll )
{
auto * lara = GetLaraInfo ( item ) ;
// 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.
2022-03-17 01:19:21 +11:00
auto frontFloor = GetCollision ( item , lara - > Control . MoveAngle , coll - > Setup . Radius + CLICK ( 0.5f ) , - LARA_HEIGHT ) . Position . Floor ;
2022-03-16 21:56:25 +11:00
auto laraUpperBound = item - > Position . yPos - coll - > Setup . Height ;
// If difference is above 1/2 click, return false (ledge is out of reach).
if ( abs ( frontFloor - laraUpperBound ) > CLICK ( 0.5f ) )
return false ;
// Embed Lara into wall to make collision test succeed
item - > Position . xPos + = phd_sin ( item - > Position . yRot ) * 8 ;
item - > Position . zPos + = phd_cos ( item - > Position . yRot ) * 8 ;
// Setup new GCI call
lara - > Control . MoveAngle = item - > Position . yRot ;
coll - > Setup . LowerFloorBound = NO_LOWER_BOUND ;
coll - > Setup . UpperFloorBound = - CLICK ( 2 ) ;
coll - > Setup . LowerCeilingBound = 0 ;
coll - > Setup . Mode = CollisionProbeMode : : FreeFlat ;
coll - > Setup . ForwardAngle = lara - > Control . MoveAngle ;
GetCollisionInfo ( coll , item ) ;
// Filter out narrow ceiling spaces, no collision cases and statics in front.
if ( coll - > Middle . Ceiling > = 0 | | coll - > CollisionType ! = CT_FRONT | | coll - > HitStatic )
return false ;
// Finally, do ordinary ledge checks (slope difference etc.)
return TestValidLedge ( item , coll ) ;
}
CornerType TestLaraHangCorner ( ITEM_INFO * item , CollisionInfo * coll , float testAngle )
2020-09-26 05:06:08 +10:00
{
2022-02-28 21:02:19 +11:00
auto * lara = GetLaraInfo ( item ) ;
2021-11-29 15:26:55 +11:00
2021-10-26 12:50:26 +03:00
// Lara isn't in stop state yet, bypass test
2022-03-17 18:57:46 +11:00
if ( item - > Animation . AnimNumber ! = LA_REACH_TO_HANG & & item - > Animation . AnimNumber ! = LA_HANG_IDLE )
2022-03-16 21:56:25 +11:00
return CornerType : : 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 )
2022-03-16 21:56:25 +11:00
return CornerType : : 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
2022-02-09 16:55:46 +11:00
auto oldPos = item - > Position ;
2022-02-28 21:02:19 +11:00
auto oldMoveAngle = lara - > Control . 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-02-09 16:55:46 +11:00
item - > Position = cornerResult . RealPositionResult ;
2022-02-28 21:02:19 +11:00
lara - > NextCornerPos . xPos = item - > Position . xPos ;
2022-03-17 01:19:21 +11:00
lara - > NextCornerPos . yPos = GetCollision ( item , item - > Position . yRot , coll - > Setup . Radius * 2 , - ( abs ( bounds - > Y1 ) + LARA_HEADROOM ) ) . Position . Floor + abs ( bounds - > Y1 ) ;
2022-02-28 21:02:19 +11:00
lara - > NextCornerPos . zPos = item - > Position . zPos ;
lara - > NextCornerPos . yRot = item - > Position . yRot ;
lara - > Control . MoveAngle = item - > Position . yRot ;
2022-03-16 21:56:25 +11:00
2022-02-09 16:55:46 +11:00
item - > Position = cornerResult . ProbeResult ;
2022-03-16 21:56:25 +11:00
auto result = TestLaraValidHangPosition ( item , coll ) ;
2021-10-26 12:50:26 +03:00
2021-11-29 18:21:50 +03:00
// Restore original item positions
2022-02-09 16:55:46 +11:00
item - > Position = oldPos ;
2022-02-28 21:02:19 +11:00
lara - > Control . MoveAngle = oldMoveAngle ;
2021-10-27 02:24:55 +03:00
2021-11-30 02:39:41 +03:00
if ( result )
2022-03-16 21:56:25 +11:00
return CornerType : : Inner ;
2021-10-27 02:24:55 +03:00
2022-02-28 21:02:19 +11:00
if ( lara - > Control . CanClimbLadder )
2020-09-26 05:06:08 +10:00
{
2021-12-12 11:10:08 +03:00
auto & angleSet = testAngle > 0 ? LeftExtRightIntTab : LeftIntRightExtTab ;
2022-02-28 21:02:19 +11:00
if ( GetClimbFlags ( lara - > NextCornerPos . xPos , item - > Position . yPos , lara - > NextCornerPos . zPos , item - > RoomNumber ) & ( short ) angleSet [ GetQuadrant ( item - > Position . yRot ) ] )
2021-12-12 11:39:35 +03:00
{
2022-02-28 21:02:19 +11:00
lara - > NextCornerPos . yPos = item - > Position . yPos ; // Restore original Y pos for ladder tests because we don't snap to ledge height in such case.
2022-03-16 21:56:25 +11:00
return CornerType : : 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
2022-02-09 16:55:46 +11:00
item - > Position = oldPos ;
2022-02-28 21:02:19 +11:00
lara - > Control . 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
2022-02-09 16:55:46 +11:00
if ( ( LaraFloorFront ( item , item - > Position . yRot + ANGLE ( testAngle ) , coll - > Setup . Radius + CLICK ( 1 ) ) < 0 ) | |
( LaraCeilingFront ( item , item - > Position . yRot + ANGLE ( testAngle ) , coll - > Setup . Radius + CLICK ( 1 ) , coll - > Setup . Height ) > 0 ) )
2022-03-16 21:56:25 +11:00
return CornerType : : 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
2022-03-04 21:30:09 +11:00
if ( ! LaraPositionOnLOS ( item , item - > Position . yRot + ANGLE ( testAngle ) , coll - > Setup . Radius + CLICK ( 1 ) ) )
2022-03-16 21:56:25 +11:00
return CornerType : : 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
2022-02-09 16:55:46 +11:00
if ( ( LaraFloorFront ( item , item - > Position . yRot , 0 ) < 0 ) | |
( LaraCeilingFront ( item , item - > Position . 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-02-09 16:55:46 +11:00
item - > Position = cornerResult . RealPositionResult ;
2022-02-28 21:02:19 +11:00
lara - > NextCornerPos . xPos = item - > Position . xPos ;
2022-03-17 01:19:21 +11:00
lara - > NextCornerPos . yPos = GetCollision ( item , item - > Position . yRot , coll - > Setup . Radius * 2 , - ( abs ( bounds - > Y1 ) + LARA_HEADROOM ) ) . Position . Floor + abs ( bounds - > Y1 ) ;
2022-02-28 21:02:19 +11:00
lara - > NextCornerPos . zPos = item - > Position . zPos ;
lara - > NextCornerPos . yRot = item - > Position . yRot ;
lara - > Control . MoveAngle = item - > Position . yRot ;
2022-02-09 16:55:46 +11:00
item - > Position = cornerResult . ProbeResult ;
2022-03-16 21:56:25 +11:00
auto result = TestLaraValidHangPosition ( item , coll ) ;
2020-09-26 05:06:08 +10:00
2021-11-29 18:21:50 +03:00
// Restore original item positions
2022-02-09 16:55:46 +11:00
item - > Position = oldPos ;
2022-02-28 21:02:19 +11:00
lara - > Control . MoveAngle = oldMoveAngle ;
2021-11-29 18:21:50 +03:00
2021-11-30 02:39:41 +03:00
if ( result )
2022-03-16 21:56:25 +11:00
return CornerType : : Outer ;
2020-09-26 05:06:08 +10:00
2022-02-28 21:02:19 +11:00
if ( lara - > Control . CanClimbLadder )
2020-09-26 05:06:08 +10:00
{
2021-12-12 11:10:08 +03:00
auto & angleSet = testAngle > 0 ? LeftIntRightExtTab : LeftExtRightIntTab ;
2022-02-28 21:02:19 +11:00
if ( GetClimbFlags ( lara - > NextCornerPos . xPos , item - > Position . yPos , lara - > NextCornerPos . zPos , item - > RoomNumber ) & ( short ) angleSet [ GetQuadrant ( item - > Position . yRot ) ] )
2021-12-12 11:39:35 +03:00
{
2022-02-28 21:02:19 +11:00
lara - > NextCornerPos . yPos = item - > Position . yPos ; // Restore original Y pos for ladder tests because we don't snap to ledge height in such case.
2022-03-16 21:56:25 +11:00
return CornerType : : 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
2022-02-09 16:55:46 +11:00
item - > Position = oldPos ;
2022-02-28 21:02:19 +11:00
lara - > Control . MoveAngle = oldMoveAngle ;
2020-09-26 05:06:08 +10:00
2022-03-16 21:56:25 +11:00
return CornerType : : None ;
2020-09-26 05:06:08 +10:00
}
2022-03-16 21:56:25 +11:00
CornerTestResult TestItemAtNextCornerPosition ( ITEM_INFO * item , CollisionInfo * coll , float angle , bool outer )
2020-09-26 05:06:08 +10:00
{
2022-02-28 21:02:19 +11:00
auto * lara = GetLaraInfo ( item ) ;
2021-11-29 15:26:55 +11:00
2022-03-16 21:56:25 +11:00
auto result = CornerTestResult ( ) ;
2020-09-26 05:06:08 +10:00
2022-03-16 21:56:25 +11:00
// Determine real turning angle
auto turnAngle = outer ? angle : - angle ;
2020-09-26 05:06:08 +10:00
2022-03-16 21:56:25 +11:00
// Backup previous position into array
PHD_3DPOS pos [ 3 ] = { item - > Position , item - > Position , item - > Position } ;
2021-10-27 12:57:36 +03:00
2022-03-16 21:56:25 +11:00
// 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.
2020-09-26 05:06:08 +10:00
2022-03-16 21:56:25 +11:00
for ( int i = 0 ; i < 2 ; i + + )
2020-09-26 05:06:08 +10:00
{
2022-03-16 21:56:25 +11:00
// 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.
2020-09-26 05:06:08 +10:00
2022-03-16 21:56:25 +11:00
// 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 ) ) ;
2020-09-26 05:06:08 +10:00
2022-03-16 21:56:25 +11:00
// 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 - > Control . MoveAngle ) ) ;
pos [ i ] . zPos + = round ( ( coll - > Setup . Radius * ( i = = 0 ? 2.0f : 2.5f ) ) * phd_cos ( lara - > Control . MoveAngle ) ) ;
2020-09-26 05:06:08 +10:00
2022-03-16 21:56:25 +11:00
// 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 ) ) ) ) ;
2020-09-26 05:06:08 +10:00
2022-03-16 21:56:25 +11:00
// 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 ) ) ;
2021-11-10 02:01:43 +11:00
2022-03-16 21:56:25 +11:00
// 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 ;
2020-09-26 05:06:08 +10:00
2022-03-16 21:56:25 +11:00
// Virtually rotate item to new angle
short newAngle = pos [ i ] . yRot - ANGLE ( turnAngle ) ;
pos [ i ] . yRot = newAngle ;
2020-09-26 05:06:08 +10:00
2022-03-16 21:56:25 +11:00
// Snap to nearest ledge, if any.
item - > Position = pos [ i ] ;
SnapItemToLedge ( item , coll , item - > Position . yRot ) ;
2020-09-26 05:06:08 +10:00
2022-03-16 21:56:25 +11:00
// Copy resulting position to an array and restore original item position.
pos [ i ] = item - > Position ;
item - > Position = pos [ 2 ] ;
2020-09-26 05:06:08 +10:00
2022-03-16 21:56:25 +11:00
if ( i = = 1 ) // Both passes finished, construct the result.
2020-09-26 05:06:08 +10:00
{
2022-03-16 21:56:25 +11:00
result . RealPositionResult = pos [ 0 ] ;
result . ProbeResult = pos [ 1 ] ;
result . Success = newAngle = = pos [ i ] . yRot ;
2020-09-26 05:06:08 +10:00
}
}
2022-03-16 21:56:25 +11:00
return result ;
2020-09-26 05:06:08 +10:00
}
2022-03-14 01:20:51 +11:00
bool TestHangSwingIn ( ITEM_INFO * item , CollisionInfo * coll )
2020-09-26 05:06:08 +10:00
{
2022-02-28 21:02:19 +11:00
auto * lara = GetLaraInfo ( item ) ;
2020-09-26 05:06:08 +10:00
2022-02-09 16:55:46 +11:00
int y = item - > Position . yPos ;
2022-03-14 01:20:51 +11:00
auto probe = GetCollision ( item , item - > Position . yRot , OFFSET_RADIUS ( coll - > Setup . Radius ) ) ;
2020-09-26 05:06:08 +10:00
2022-01-13 03:13:18 +11:00
if ( ( probe . Position . Floor - y ) > 0 & &
2022-02-13 20:23:09 +11:00
( probe . Position . Ceiling - y ) < - CLICK ( 1.6f ) & &
2022-01-13 03:13:18 +11:00
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
2022-03-14 01:20:51 +11:00
bool TestLaraHangSideways ( ITEM_INFO * item , CollisionInfo * coll , short angle )
2020-09-26 05:06:08 +10:00
{
2022-02-28 21:02:19 +11:00
auto * lara = GetLaraInfo ( item ) ;
2021-12-30 22:17:36 +11:00
2022-02-09 16:55:46 +11:00
auto oldPos = item - > Position ;
2020-09-26 05:06:08 +10:00
2022-02-28 21:02:19 +11:00
lara - > Control . MoveAngle = item - > Position . yRot + angle ;
2021-12-15 15:21:39 +03:00
2021-12-01 11:59:24 +03:00
static constexpr auto sidewayTestDistance = 16 ;
2022-02-28 21:02:19 +11:00
item - > Position . xPos + = phd_sin ( lara - > Control . MoveAngle ) * sidewayTestDistance ;
item - > Position . zPos + = phd_cos ( lara - > Control . MoveAngle ) * sidewayTestDistance ;
2020-09-26 05:06:08 +10:00
2022-02-09 16:55:46 +11:00
coll - > Setup . OldPosition . y = item - > Position . 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
2022-02-09 16:55:46 +11:00
item - > Position = oldPos ;
2020-09-26 05:06:08 +10:00
return ! res ;
}
2022-03-16 21:56:25 +11:00
bool TestLaraWall ( ITEM_INFO * item , int distance , int height , int side )
{
float s = phd_sin ( item - > Position . yRot ) ;
float c = phd_cos ( item - > Position . yRot ) ;
auto start = GAME_VECTOR (
item - > Position . xPos + ( side * c ) ,
item - > Position . yPos + height ,
item - > Position . zPos + ( - side * s ) ,
item - > RoomNumber ) ;
auto end = GAME_VECTOR (
item - > Position . xPos + ( distance * s ) + ( side * c ) ,
item - > Position . yPos + height ,
item - > Position . zPos + ( distance * c ) + ( - side * s ) ,
item - > RoomNumber ) ;
return ! LOS ( & start , & end ) ;
}
2022-02-25 21:02:08 +11:00
bool TestLaraFacingCorner ( ITEM_INFO * item , short angle , int distance )
2021-08-29 23:53:58 +03:00
{
2022-02-25 21:02:08 +11:00
short angleLeft = angle - ANGLE ( 15.0f ) ;
short angleRight = angle + ANGLE ( 15.0f ) ;
2021-10-16 22:53:29 +11:00
2022-02-07 23:07:40 +11:00
auto start = GAME_VECTOR (
2022-02-09 16:55:46 +11:00
item - > Position . xPos ,
item - > Position . yPos - STEPUP_HEIGHT ,
item - > Position . zPos ,
item - > RoomNumber ) ;
2021-08-29 23:53:58 +03:00
2022-02-07 23:07:40 +11:00
auto end1 = GAME_VECTOR (
2022-02-25 21:02:08 +11:00
item - > Position . xPos + distance * phd_sin ( angleLeft ) ,
2022-02-09 16:55:46 +11:00
item - > Position . yPos - STEPUP_HEIGHT ,
2022-02-25 21:02:08 +11:00
item - > Position . zPos + distance * phd_cos ( angleLeft ) ,
2022-02-09 16:55:46 +11:00
item - > RoomNumber ) ;
2021-08-29 23:53:58 +03:00
2022-02-07 23:07:40 +11:00
auto end2 = GAME_VECTOR (
2022-02-25 21:02:08 +11:00
item - > Position . xPos + distance * phd_sin ( angleRight ) ,
2022-02-09 16:55:46 +11:00
item - > Position . yPos - STEPUP_HEIGHT ,
2022-02-25 21:02:08 +11:00
item - > Position . zPos + distance * phd_cos ( angleRight ) ,
2022-02-09 16:55:46 +11:00
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 ) ;
return ( ! result1 & & ! result2 ) ;
2021-08-29 23:53:58 +03:00
}
2022-02-25 21:02:08 +11:00
bool LaraPositionOnLOS ( ITEM_INFO * item , short angle , int distance )
2021-10-28 01:11:14 +03:00
{
2022-02-07 23:07:40 +11:00
auto start1 = GAME_VECTOR (
2022-02-09 16:55:46 +11:00
item - > Position . xPos ,
item - > Position . yPos - LARA_HEADROOM ,
item - > Position . zPos ,
item - > RoomNumber ) ;
2021-10-28 01:11:14 +03:00
2022-02-07 23:07:40 +11:00
auto start2 = GAME_VECTOR (
2022-02-09 16:55:46 +11:00
item - > Position . xPos ,
item - > Position . yPos - LARA_HEIGHT + LARA_HEADROOM ,
item - > Position . zPos ,
item - > RoomNumber ) ;
2021-10-28 01:11:14 +03:00
2022-02-07 23:07:40 +11:00
auto end1 = GAME_VECTOR (
2022-02-25 21:02:08 +11:00
item - > Position . xPos + distance * phd_sin ( angle ) ,
2022-02-09 16:55:46 +11:00
item - > Position . yPos - LARA_HEADROOM ,
2022-02-25 21:02:08 +11:00
item - > Position . zPos + distance * phd_cos ( angle ) ,
2022-02-09 16:55:46 +11:00
item - > RoomNumber ) ;
2021-10-28 01:11:14 +03:00
2022-02-07 23:07:40 +11:00
auto end2 = GAME_VECTOR (
2022-02-25 21:02:08 +11:00
item - > Position . xPos + distance * phd_sin ( angle ) ,
2022-02-09 16:55:46 +11:00
item - > Position . yPos - LARA_HEIGHT + LARA_HEADROOM ,
2022-02-25 21:02:08 +11:00
item - > Position . zPos + distance * phd_cos ( angle ) ,
2022-02-09 16:55:46 +11:00
item - > RoomNumber ) ;
2021-10-28 01:11:14 +03:00
2022-01-29 07:54:04 +11:00
auto result1 = LOS ( & start1 , & end1 ) ;
auto result2 = LOS ( & start2 , & end2 ) ;
2021-10-28 01:11:14 +03:00
2022-03-22 20:41:01 +11:00
return ( result1 & & result2 ) ;
2021-10-28 01:11:14 +03:00
}
2022-02-25 21:02:08 +11:00
int LaraFloorFront ( ITEM_INFO * item , short angle , int distance )
2021-08-24 16:54:26 +03:00
{
2022-02-25 21:02:08 +11:00
return LaraCollisionFront ( item , angle , distance ) . Position . Floor ;
2021-08-24 16:54:26 +03:00
}
2022-03-16 21:56:25 +11:00
int LaraCeilingFront ( ITEM_INFO * item , short angle , int distance , int height )
{
return LaraCeilingCollisionFront ( item , angle , distance , height ) . Position . Ceiling ;
}
2022-03-13 02:04:24 +11:00
CollisionResult LaraCollisionFront ( ITEM_INFO * item , short angle , int distance )
2020-09-26 05:06:08 +10:00
{
2022-03-14 01:20:51 +11:00
auto probe = GetCollision ( item , angle , distance , - LARA_HEIGHT ) ;
2020-09-26 05:06:08 +10:00
2021-11-20 12:25:51 +11:00
if ( probe . Position . Floor ! = NO_HEIGHT )
2022-02-09 16:55:46 +11:00
probe . Position . Floor - = item - > Position . 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
}
2022-03-13 02:04:24 +11:00
CollisionResult LaraCeilingCollisionFront ( ITEM_INFO * item , short angle , int distance , int height )
2020-09-26 05:06:08 +10:00
{
2022-03-14 01:20:51 +11:00
auto probe = GetCollision ( item , angle , distance , - height ) ;
2020-09-26 05:06:08 +10:00
2021-11-20 12:25:51 +11:00
if ( probe . Position . Ceiling ! = NO_HEIGHT )
2022-02-25 21:02:08 +11:00
probe . Position . Ceiling + = height - item - > Position . 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
}
2022-03-14 01:20:51 +11:00
bool TestLaraWaterStepOut ( ITEM_INFO * item , CollisionInfo * coll )
2021-11-09 23:26:31 +11:00
{
2022-02-28 21:02:19 +11:00
auto * lara = GetLaraInfo ( item ) ;
2021-11-29 15:26:55 +11:00
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-10 02:41:59 +03:00
SetAnimation ( item , LA_STAND_IDLE ) ;
2021-11-09 23:26:31 +11:00
else
{
2022-02-18 23:19:46 +11:00
SetAnimation ( item , LA_ONWATER_TO_WADE_1_STEP ) ;
2022-03-13 02:04:24 +11:00
item - > Animation . TargetState = LS_IDLE ;
2021-11-09 23:26:31 +11:00
}
2022-02-09 16:55:46 +11:00
item - > Position . yPos + = coll - > Middle . Floor + CLICK ( 2.75f ) - 9 ;
2021-11-09 23:26:31 +11:00
UpdateItemRoom ( item , - ( STEPUP_HEIGHT - 3 ) ) ;
2022-02-09 16:55:46 +11:00
item - > Position . xRot = 0 ;
2022-02-28 21:02:19 +11:00
item - > Position . zRot = 0 ;
2022-03-13 02:04:24 +11:00
item - > Animation . Velocity = 0 ;
item - > Animation . VerticalVelocity = 0 ;
item - > Animation . Airborne = false ;
2022-02-28 21:02:19 +11:00
lara - > Control . WaterStatus = WaterStatus : : Wade ;
2021-11-09 23:26:31 +11:00
return true ;
}
2022-03-14 01:20:51 +11:00
bool TestLaraWaterClimbOut ( ITEM_INFO * item , CollisionInfo * coll )
2021-11-09 23:26:31 +11:00
{
2022-02-28 21:02:19 +11:00
auto * lara = GetLaraInfo ( item ) ;
2021-11-21 13:47:55 +11:00
2021-11-09 23:26:31 +11:00
if ( coll - > CollisionType ! = CT_FRONT | | ! ( TrInput & IN_ACTION ) )
return false ;
2022-02-28 21:02:19 +11:00
if ( lara - > Control . HandStatus ! = HandStatus : : Free & &
2022-03-09 20:37:26 +11:00
( lara - > Control . HandStatus ! = HandStatus : : WeaponReady | | lara - > Control . Weapon . GunType ! = LaraWeaponType : : 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 ;
2022-03-17 01:19:21 +11:00
auto probe = GetCollision ( item , coll - > Setup . ForwardAngle , CLICK ( 2 ) , - CLICK ( 1 ) ) ;
int headroom = probe . Position . Floor - probe . Position . Ceiling ;
2021-11-09 23:26:31 +11:00
2021-12-12 21:11:27 +11:00
if ( frontFloor < = - CLICK ( 1 ) )
2021-11-09 23:26:31 +11:00
{
if ( headroom < LARA_HEIGHT )
{
2022-03-04 15:51:53 +11:00
if ( g_GameFlow - > Animations . HasCrawlExtended )
2022-02-18 23:19:46 +11:00
SetAnimation ( item , LA_ONWATER_TO_CROUCH_1_STEP ) ;
2021-11-09 23:26:31 +11:00
else
return false ;
}
else
2022-02-18 23:19:46 +11:00
SetAnimation ( item , LA_ONWATER_TO_STAND_1_STEP ) ;
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 )
{
2022-03-04 15:51:53 +11:00
if ( g_GameFlow - > Animations . HasCrawlExtended )
2022-02-18 23:19:46 +11:00
SetAnimation ( item , LA_ONWATER_TO_CROUCH_M1_STEP ) ;
2021-11-09 23:26:31 +11:00
else
return false ;
}
else
2022-02-18 23:19:46 +11:00
SetAnimation ( item , LA_ONWATER_TO_STAND_M1_STEP ) ;
2021-11-09 23:26:31 +11:00
}
else
{
if ( headroom < LARA_HEIGHT )
{
2022-03-04 15:51:53 +11:00
if ( g_GameFlow - > Animations . HasCrawlExtended )
2022-02-18 23:19:46 +11:00
SetAnimation ( item , LA_ONWATER_TO_CROUCH_0_STEP ) ;
2021-11-09 23:26:31 +11:00
else
return false ;
}
else
2022-02-18 23:19:46 +11:00
SetAnimation ( item , LA_ONWATER_TO_STAND_0_STEP ) ;
2021-11-09 23:26:31 +11:00
}
UpdateItemRoom ( item , - LARA_HEIGHT / 2 ) ;
SnapItemToLedge ( item , coll , 1.7f ) ;
2022-02-09 16:55:46 +11:00
item - > Position . yPos + = frontFloor - 5 ;
2022-03-13 02:04:24 +11:00
item - > Animation . ActiveState = LS_ONWATER_EXIT ;
item - > Animation . Airborne = false ;
item - > Animation . Velocity = 0 ;
item - > Animation . VerticalVelocity = 0 ;
2022-02-28 21:02:19 +11:00
lara - > Control . HandStatus = HandStatus : : Busy ;
lara - > Control . WaterStatus = WaterStatus : : Dry ;
2021-11-09 23:26:31 +11:00
return true ;
}
2022-03-14 01:20:51 +11:00
bool TestLaraLadderClimbOut ( ITEM_INFO * item , CollisionInfo * coll ) // NEW function for water to ladder move
2021-11-09 23:26:31 +11:00
{
2022-02-28 21:02:19 +11:00
auto * lara = GetLaraInfo ( item ) ;
2021-11-29 15:26:55 +11:00
2021-11-09 23:26:31 +11:00
if ( ! ( TrInput & IN_ACTION ) | |
2022-02-28 21:02:19 +11:00
! lara - > Control . CanClimbLadder | |
2021-11-09 23:26:31 +11:00
coll - > CollisionType ! = CT_FRONT )
{
return false ;
}
2022-02-28 21:02:19 +11:00
if ( lara - > Control . HandStatus ! = HandStatus : : Free & &
2022-03-09 20:37:26 +11:00
( lara - > Control . HandStatus ! = HandStatus : : WeaponReady | | lara - > Control . Weapon . GunType ! = LaraWeaponType : : Flare ) )
2021-11-09 23:26:31 +11:00
{
return false ;
}
2022-03-16 21:56:25 +11:00
if ( ! TestLaraClimbIdle ( item , coll ) )
2021-11-09 23:26:31 +11:00
return false ;
2022-02-09 16:55:46 +11:00
short rot = item - > Position . yRot ;
2021-11-09 23:26:31 +11:00
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 :
2022-02-25 14:28:28 +11:00
item - > Position . zPos = ( item - > Position . zPos | ( SECTOR ( 1 ) - 1 ) ) - LARA_RAD - 1 ;
2021-11-09 23:26:31 +11:00
break ;
case EAST :
2022-02-25 14:28:28 +11:00
item - > Position . xPos = ( item - > Position . xPos | ( SECTOR ( 1 ) - 1 ) ) - LARA_RAD - 1 ;
2021-11-09 23:26:31 +11:00
break ;
case SOUTH :
2022-02-25 14:28:28 +11:00
item - > Position . zPos = ( item - > Position . zPos & - SECTOR ( 1 ) ) + LARA_RAD + 1 ;
2021-11-09 23:26:31 +11:00
break ;
case WEST :
2022-02-25 14:28:28 +11:00
item - > Position . xPos = ( item - > Position . xPos & - SECTOR ( 1 ) ) + LARA_RAD + 1 ;
2021-11-09 23:26:31 +11:00
break ;
}
2021-11-10 02:41:59 +03:00
SetAnimation ( item , LA_ONWATER_IDLE ) ;
2022-03-13 02:04:24 +11:00
item - > Animation . TargetState = LS_LADDER_IDLE ;
2021-11-09 23:26:31 +11:00
AnimateLara ( item ) ;
2022-02-09 16:55:46 +11:00
item - > Position . yRot = rot ;
item - > Position . yPos - = 10 ; //otherwise she falls back into the water
item - > Position . xRot = 0 ;
2022-02-25 14:28:28 +11:00
item - > Position . zRot = 0 ;
2022-03-13 02:04:24 +11:00
item - > Animation . Velocity = 0 ;
item - > Animation . VerticalVelocity = 0 ;
item - > Animation . Airborne = false ;
2022-02-28 21:02:19 +11:00
lara - > Control . TurnRate = 0 ;
lara - > Control . HandStatus = HandStatus : : Busy ;
lara - > Control . WaterStatus = WaterStatus : : Dry ;
2021-11-09 23:26:31 +11:00
return true ;
}
2022-03-14 01:20:51 +11:00
void TestLaraWaterDepth ( ITEM_INFO * item , CollisionInfo * coll )
2021-11-10 01:32:54 +11:00
{
2022-02-28 21:02:19 +11:00
auto * lara = GetLaraInfo ( item ) ;
2021-11-29 15:26:55 +11:00
2022-02-09 16:55:46 +11:00
short roomNum = item - > RoomNumber ;
FLOOR_INFO * floor = GetFloor ( item - > Position . xPos , item - > Position . yPos , item - > Position . zPos , & roomNum ) ;
int waterDepth = GetWaterDepth ( item - > Position . xPos , item - > Position . yPos , item - > Position . zPos , roomNum ) ;
2021-11-10 01:32:54 +11:00
if ( waterDepth = = NO_HEIGHT )
{
2022-03-13 02:04:24 +11:00
item - > Animation . VerticalVelocity = 0 ;
2022-02-09 16:55:46 +11:00
item - > Position . xPos = coll - > Setup . OldPosition . x ;
item - > Position . yPos = coll - > Setup . OldPosition . y ;
item - > Position . zPos = coll - > Setup . OldPosition . z ;
2021-11-10 01:32:54 +11:00
}
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 ) ;
2022-03-13 02:04:24 +11:00
item - > Animation . TargetState = LS_IDLE ;
2022-02-09 16:55:46 +11:00
item - > Position . zRot = 0 ;
item - > Position . xRot = 0 ;
2022-03-13 02:04:24 +11:00
item - > Animation . Velocity = 0 ;
item - > Animation . VerticalVelocity = 0 ;
item - > Animation . Airborne = false ;
2022-02-09 16:55:46 +11:00
item - > Position . yPos = GetFloorHeight ( floor , item - > Position . xPos , item - > Position . yPos , item - > Position . zPos ) ;
2022-02-28 21:02:19 +11:00
lara - > Control . WaterStatus = WaterStatus : : Wade ;
2021-11-10 01:32:54 +11:00
}
}
2021-09-05 14:49:00 +02:00
# ifndef NEW_TIGHTROPE
2022-02-21 20:27:30 +11:00
void GetTightropeFallOff ( ITEM_INFO * item , int regularity )
2022-01-27 22:26:05 +11:00
{
2022-03-16 21:56:25 +11:00
auto * lara = GetLaraInfo ( item ) ;
2022-02-21 20:27:30 +11:00
if ( item - > HitPoints < = 0 | | item - > HitStatus )
SetAnimation ( item , LA_TIGHTROPE_FALL_LEFT ) ;
2020-09-26 05:06:08 +10:00
2022-03-16 21:56:25 +11:00
if ( ! lara - > Control . Tightrope . Fall & & ! ( GetRandomControl ( ) & regularity ) )
lara - > Control . Tightrope . Fall = 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
2022-03-16 21:56:25 +11:00
bool IsStandingWeapon ( LaraWeaponType weaponType )
{
if ( weaponType = = LaraWeaponType : : Shotgun | |
weaponType = = LaraWeaponType : : HK | |
weaponType = = LaraWeaponType : : Crossbow | |
weaponType = = LaraWeaponType : : Torch | |
weaponType = = LaraWeaponType : : GrenadeLauncher | |
weaponType = = LaraWeaponType : : HarpoonGun | |
weaponType = = LaraWeaponType : : RocketLauncher | |
weaponType = = LaraWeaponType : : Snowmobile )
{
return true ;
}
return false ;
}
bool IsVaultState ( LaraState state )
2021-10-16 20:50:16 +11:00
{
2022-03-16 21:56:25 +11:00
if ( state = = LS_VAULT | |
state = = LS_VAULT_2_STEPS | |
state = = LS_VAULT_3_STEPS | |
state = = LS_VAULT_1_STEP_CROUCH | |
state = = LS_VAULT_2_STEPS_CROUCH | |
state = = LS_VAULT_3_STEPS_CROUCH | |
state = = LS_AUTO_JUMP )
2021-10-16 20:50:16 +11:00
{
return true ;
}
return false ;
}
2022-02-12 16:25:59 +11:00
bool IsJumpState ( LaraState state )
2022-02-02 23:11:57 +11:00
{
if ( state = = LS_JUMP_FORWARD | |
state = = LS_JUMP_BACK | |
state = = LS_JUMP_LEFT | |
state = = LS_JUMP_RIGHT | |
state = = LS_JUMP_UP | |
state = = LS_FALL_BACK | |
2022-02-03 12:21:28 +11:00
state = = LS_REACH | |
state = = LS_SWAN_DIVE | |
state = = LS_FREEFALL_DIVE | |
state = = LS_FREEFALL )
2022-02-02 23:11:57 +11:00
{
return true ;
}
return false ;
}
2022-02-12 16:25:59 +11:00
bool IsRunJumpQueueableState ( LaraState state )
2022-02-06 13:31:10 +11:00
{
if ( state = = LS_RUN_FORWARD | |
state = = LS_STEP_UP | |
state = = LS_STEP_DOWN )
{
return true ;
}
return false ;
}
2022-02-12 16:25:59 +11:00
bool IsRunJumpCountableState ( LaraState state )
2022-02-04 22:18:55 +11:00
{
if ( state = = LS_RUN_FORWARD | |
state = = LS_WALK_FORWARD | |
state = = LS_JUMP_FORWARD | |
state = = LS_SPRINT | |
state = = LS_SPRINT_DIVE )
{
return true ;
}
return false ;
}
2022-03-16 21:56:25 +11:00
bool TestLaraPose ( ITEM_INFO * item , CollisionInfo * coll )
2022-02-05 23:13:31 +11:00
{
2022-03-16 21:56:25 +11:00
auto * lara = GetLaraInfo ( item ) ;
if ( TestEnvironment ( ENV_FLAG_SWAMP , item ) )
return false ;
if ( ! ( TrInput & ( IN_FLARE | IN_DRAW ) ) & & // Avoid unsightly concurrent actions.
lara - > Control . HandStatus = = HandStatus : : Free & & // Hands are free.
( lara - > Control . Weapon . GunType ! = LaraWeaponType : : Flare | | // Flare is not being handled. TODO: Will she pose with weapons drawn?
lara - > Flare . Life ) & &
lara - > Vehicle = = NO_ITEM ) // Not in a vehicle.
2022-02-05 23:13:31 +11:00
{
return true ;
}
return false ;
}
2022-03-16 21:56:25 +11:00
bool TestLaraKeepLow ( ITEM_INFO * item , CollisionInfo * coll )
2022-01-25 18:02:22 +11:00
{
2022-03-16 21:56:25 +11:00
// HACK: 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
int radius = ( item - > Animation . ActiveState = = LS_CROUCH_IDLE | |
item - > Animation . ActiveState = = LS_CROUCH_TURN_LEFT | |
item - > Animation . ActiveState = = LS_CROUCH_TURN_RIGHT )
? LARA_RAD : LARA_RAD_CRAWL ;
2022-02-25 21:02:08 +11:00
2022-03-16 21:56:25 +11:00
auto probeFront = GetCollision ( item , item - > Position . yRot , radius , - coll - > Setup . Height ) ;
auto probeBack = GetCollision ( item , item - > Position . yRot + ANGLE ( 180.0f ) , radius , - coll - > Setup . Height ) ;
auto probeMiddle = GetCollision ( item ) ;
2022-01-25 18:02:22 +11:00
2022-03-16 21:56:25 +11:00
if ( abs ( probeFront . Position . Ceiling - probeFront . Position . Floor ) < LARA_HEIGHT | | // Front is not a clamp.
abs ( probeBack . Position . Ceiling - probeBack . Position . Floor ) < LARA_HEIGHT | | // Back is not a clamp.
abs ( probeMiddle . Position . Ceiling - probeMiddle . Position . Floor ) < LARA_HEIGHT ) // Middle is not a clamp.
{
return true ;
}
2022-01-25 18:02:22 +11:00
2022-03-16 21:56:25 +11:00
return false ;
2022-01-25 18:02:22 +11:00
}
2022-03-16 21:56:25 +11:00
bool TestLaraSlide ( ITEM_INFO * item , CollisionInfo * coll )
{
int y = item - > Position . yPos ;
auto probe = GetCollision ( item ) ;
if ( abs ( probe . Position . Floor - y ) < = STEPUP_HEIGHT & &
probe . Position . FloorSlope & &
! TestEnvironment ( ENV_FLAG_SWAMP , item ) )
{
return true ;
}
return false ;
}
bool TestLaraLand ( ITEM_INFO * item , CollisionInfo * coll )
{
int heightFromFloor = GetCollision ( item ) . Position . Floor - item - > Position . yPos ;
if ( item - > Animation . Airborne & & item - > Animation . VerticalVelocity > = 0 & &
( heightFromFloor < = item - > Animation . VerticalVelocity | | TestEnvironment ( ENV_FLAG_SWAMP , item ) ) )
{
return true ;
}
return false ;
}
bool TestLaraFall ( ITEM_INFO * item , CollisionInfo * coll )
2021-10-31 18:33:39 +11:00
{
2022-02-28 21:02:19 +11:00
auto * lara = GetLaraInfo ( item ) ;
2021-11-20 12:25:51 +11:00
2022-03-16 21:56:25 +11:00
if ( coll - > Middle . Floor < = STEPUP_HEIGHT | |
lara - > Control . WaterStatus = = WaterStatus : : Wade ) // TODO: This causes a legacy floor snap bug when Lara wades off a ledge into a dry room. @Sezz 2021.09.26
{
2022-02-12 16:25:59 +11:00
return false ;
2022-03-16 21:56:25 +11:00
}
2022-02-12 16:25:59 +11:00
2022-03-16 21:56:25 +11:00
return true ;
}
bool TestLaraMonkeyGrab ( ITEM_INFO * item , CollisionInfo * coll )
{
auto * lara = GetLaraInfo ( item ) ;
if ( lara - > Control . CanMonkeySwing & & coll - > Middle . Ceiling < = CLICK ( 0.5f ) & &
( coll - > Middle . Ceiling > = 0 | | coll - > CollisionType = = CT_TOP | | coll - > CollisionType = = CT_TOP_FRONT ) & &
abs ( coll - > Middle . Ceiling + coll - > Middle . Floor + coll - > Setup . Height ) > LARA_HEIGHT_MONKEY )
{
return true ;
}
return false ;
}
bool TestLaraMonkeyFall ( ITEM_INFO * item , CollisionInfo * coll )
{
auto * lara = GetLaraInfo ( item ) ;
int y = item - > Position . yPos - LARA_HEIGHT_MONKEY ;
auto probe = GetCollision ( item ) ;
if ( ! lara - > Control . CanMonkeySwing | | // No monkey sector.
( probe . Position . Ceiling - y ) > CLICK ( 1.25f ) | | // Outside lower bound.
( probe . Position . Ceiling - y ) < - CLICK ( 1.25f ) | | // Outside upper bound.
probe . Position . CeilingSlope | | // Is ceiling slope.
probe . Position . Ceiling = = NO_HEIGHT )
2021-10-31 18:33:39 +11:00
{
return true ;
}
return false ;
}
2022-03-14 01:20:51 +11:00
bool TestLaraStep ( ITEM_INFO * item , CollisionInfo * coll )
2021-10-16 20:50:16 +11:00
{
2022-02-28 21:02:19 +11:00
auto * lara = GetLaraInfo ( item ) ;
2022-01-27 20:56:05 +11:00
2021-11-28 22:45:08 +11:00
if ( abs ( coll - > Middle . Floor ) > 0 & &
2022-02-12 16:25:59 +11:00
( coll - > Middle . Floor < = STEPUP_HEIGHT | | // Within lower floor bound...
2022-02-28 21:02:19 +11:00
lara - > Control . WaterStatus = = WaterStatus : : Wade ) & & // OR Lara is wading.
2022-02-12 16:25:59 +11:00
coll - > Middle . Floor > = - STEPUP_HEIGHT & & // Within upper floor bound.
2021-11-28 22:45:08 +11:00
coll - > Middle . Floor ! = NO_HEIGHT )
2021-10-16 20:50:16 +11:00
{
return true ;
}
return false ;
}
2022-03-14 01:20:51 +11:00
bool TestLaraStepUp ( ITEM_INFO * item , CollisionInfo * coll )
2022-01-16 13:56:39 +11:00
{
2022-01-30 15:17:57 +11:00
if ( coll - > Middle . Floor < - CLICK ( 0.5f ) & & // Within lower floor bound.
coll - > Middle . Floor > = - STEPUP_HEIGHT ) // Within upper floor bound.
2022-01-16 13:56:39 +11:00
{
return true ;
}
return false ;
}
2022-03-14 01:20:51 +11:00
bool TestLaraStepDown ( ITEM_INFO * item , CollisionInfo * coll )
2021-10-16 20:50:16 +11:00
{
2022-01-30 15:17:57 +11:00
if ( coll - > Middle . Floor < = STEPUP_HEIGHT & & // Within lower floor bound.
coll - > Middle . Floor > CLICK ( 0.5f ) ) // Within upper floor bound.
2021-10-16 20:50:16 +11:00
{
return true ;
}
return false ;
}
2022-03-14 01:20:51 +11:00
bool TestLaraMonkeyStep ( ITEM_INFO * item , CollisionInfo * coll )
2021-10-16 20:50:16 +11:00
{
2022-02-09 16:55:46 +11:00
int y = item - > Position . yPos - LARA_HEIGHT_MONKEY ;
2022-03-14 01:20:51 +11:00
auto probe = GetCollision ( item ) ;
2022-01-27 20:56:05 +11:00
2022-01-30 15:17:57 +11:00
if ( ( probe . Position . Ceiling - y ) < = CLICK ( 1.25f ) & & // Within lower ceiling bound.
( probe . Position . Ceiling - y ) > = - CLICK ( 1.25f ) & & // Within upper ceiling bound.
2022-01-27 20:56:05 +11:00
probe . Position . Ceiling ! = NO_HEIGHT )
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.
2022-02-21 20:27:30 +11:00
// For now, it supersedes old probes and is used alongside COLL_INFO. @Sezz 2021.10.24
2022-03-16 20:50:36 +11:00
bool TestLaraMoveTolerance ( ITEM_INFO * item , CollisionInfo * coll , MoveTestSetup testSetup , bool useCrawlSetup )
2021-10-22 00:07:24 +11:00
{
2022-03-16 20:50:36 +11:00
// HACK: coll->Setup.Radius and coll->Setup.Height are set in
// lara_col functions, then reset by LaraAboveWater() to defaults.
// This means they store the wrong values for move tests called in crawl lara_as functions.
// When states become objects, collision setup should occur at the beginning of each state, eliminating the need
// for the useCrawlSetup argument. @Sezz 2022.03.16
int laraRadius = useCrawlSetup ? LARA_RAD_CRAWL : coll - > Setup . Radius ;
int laraHeight = useCrawlSetup ? LARA_HEIGHT_CRAWL : coll - > Setup . Height ;
2022-02-09 16:55:46 +11:00
int y = item - > Position . yPos ;
2022-03-16 20:50:36 +11:00
int distance = OFFSET_RADIUS ( laraRadius ) ;
auto probe = GetCollision ( item , testSetup . Angle , distance , - laraHeight ) ;
2022-01-28 00:02:48 +11:00
2022-01-27 14:16:38 +11:00
bool isSlopeDown = testSetup . CheckSlopeDown ? ( probe . Position . FloorSlope & & probe . Position . Floor > y ) : false ;
bool isSlopeUp = testSetup . CheckSlopeUp ? ( probe . Position . FloorSlope & & probe . Position . Floor < y ) : false ;
2022-01-26 20:27:52 +11:00
bool isDeath = testSetup . CheckDeath ? probe . Block - > Flags . Death : false ;
2022-01-08 15:43:17 +11:00
2022-02-07 23:07:40 +11:00
auto start1 = GAME_VECTOR (
2022-02-09 16:55:46 +11:00
item - > Position . xPos ,
2022-02-07 23:07:40 +11:00
y + testSetup . UpperFloorBound - 1 ,
2022-02-09 16:55:46 +11:00
item - > Position . zPos ,
item - > RoomNumber ) ;
2022-02-07 23:07:40 +11:00
auto end1 = GAME_VECTOR (
probe . Coordinates . x ,
y + testSetup . UpperFloorBound - 1 ,
probe . Coordinates . z ,
2022-02-09 16:55:46 +11:00
item - > RoomNumber ) ;
2022-01-28 00:02:48 +11:00
2022-02-07 23:07:40 +11:00
auto start2 = GAME_VECTOR (
2022-02-09 16:55:46 +11:00
item - > Position . xPos ,
2022-03-16 20:50:36 +11:00
y - laraHeight + 1 ,
2022-02-09 16:55:46 +11:00
item - > Position . zPos ,
2022-03-16 20:50:36 +11:00
item - > RoomNumber ) ;
2022-02-06 13:31:10 +11:00
2022-02-07 23:07:40 +11:00
auto end2 = GAME_VECTOR (
probe . Coordinates . x ,
probe . Coordinates . y + 1 ,
probe . Coordinates . z ,
2022-02-09 16:55:46 +11:00
item - > RoomNumber ) ;
2022-01-28 00:02:48 +11:00
2022-02-07 23:07:40 +11:00
// Discard walls.
if ( probe . Position . Floor = = NO_HEIGHT )
return false ;
2022-02-06 13:31:10 +11:00
2022-02-08 01:26:59 +11:00
// Check for slope or death sector (if applicable).
2022-02-07 23:07:40 +11:00
if ( isSlopeDown | | isSlopeUp | | isDeath )
2022-02-06 13:31:10 +11:00
return false ;
2022-02-21 20:27:30 +11:00
// Conduct ray test at upper floor bound and lowest ceiling bound.
2022-02-07 23:07:40 +11:00
if ( ! LOS ( & start1 , & end1 ) | | ! LOS ( & start2 , & end2 ) )
2022-01-28 00:02:48 +11:00
return false ;
// Assess move feasibility to location ahead.
2022-03-16 20:50:36 +11:00
if ( ( probe . Position . Floor - y ) < = testSetup . LowerFloorBound & & // Within lower floor bound.
( probe . Position . Floor - y ) > = testSetup . UpperFloorBound & & // Within upper floor bound.
( probe . Position . Ceiling - y ) < - laraHeight & & // Within lowest ceiling bound.
abs ( probe . Position . Ceiling - probe . Position . Floor ) > laraHeight ) // Space is not a clamp.
2021-10-22 00:07:24 +11:00
{
return true ;
}
return false ;
}
2022-03-14 01:20:51 +11:00
bool TestLaraRunForward ( ITEM_INFO * item , CollisionInfo * coll )
2021-10-28 23:22:28 +11:00
{
2022-01-30 14:43:33 +11:00
// Using Lower/UpperFloorBound defined in run state collision function.
2021-10-28 23:22:28 +11:00
2022-01-26 20:27:52 +11:00
MoveTestSetup testSetup
2022-01-08 15:43:17 +11:00
{
2022-02-09 16:55:46 +11:00
item - > Position . yRot ,
2022-01-30 14:43:33 +11:00
NO_LOWER_BOUND , - STEPUP_HEIGHT ,
2022-01-08 15:43:17 +11:00
false , true , false
} ;
2021-10-28 23:22:28 +11:00
2022-01-26 20:27:52 +11:00
return TestLaraMoveTolerance ( item , coll , testSetup ) ;
2021-10-28 23:22:28 +11:00
}
2022-03-14 01:20:51 +11:00
bool TestLaraWalkForward ( ITEM_INFO * item , CollisionInfo * coll )
2021-10-22 00:07:24 +11:00
{
2022-01-30 14:43:33 +11:00
// Using Lower/UpperFloorBound defined in walk state collision function.
2021-10-28 23:22:28 +11:00
2022-01-26 20:27:52 +11:00
MoveTestSetup testSetup
2022-01-08 15:43:17 +11:00
{
2022-02-09 16:55:46 +11:00
item - > Position . yRot ,
2022-01-30 14:43:33 +11:00
STEPUP_HEIGHT , - STEPUP_HEIGHT
2022-01-08 15:43:17 +11:00
} ;
2021-10-29 21:41:00 +11:00
2022-01-26 20:27:52 +11:00
return TestLaraMoveTolerance ( item , coll , testSetup ) ;
2021-10-22 00:07:24 +11:00
}
2022-03-14 01:20:51 +11:00
bool TestLaraWalkBack ( ITEM_INFO * item , CollisionInfo * coll )
2021-10-04 22:02:02 +11:00
{
2022-01-30 14:43:33 +11:00
// Using Lower/UpperFloorBound defined in walk back state collision function.
2022-01-08 15:43:17 +11:00
2022-01-26 20:27:52 +11:00
MoveTestSetup testSetup
2022-01-08 15:43:17 +11:00
{
2022-02-09 16:55:46 +11:00
item - > Position . yRot + ANGLE ( 180.0f ) ,
2022-01-30 14:43:33 +11:00
STEPUP_HEIGHT , - STEPUP_HEIGHT
2022-01-08 15:43:17 +11:00
} ;
2022-01-26 20:27:52 +11:00
return TestLaraMoveTolerance ( item , coll , testSetup ) ;
2021-10-19 21:28:36 +11:00
}
2022-03-14 01:20:51 +11:00
bool TestLaraRunBack ( ITEM_INFO * item , CollisionInfo * coll )
2021-10-19 21:28:36 +11:00
{
2022-01-30 14:43:33 +11:00
// Using Lower/UpperFloorBound defined in hop back state collision function.
2022-01-08 15:43:17 +11:00
2022-01-26 20:27:52 +11:00
MoveTestSetup testSetup
2022-01-08 15:43:17 +11:00
{
2022-02-09 16:55:46 +11:00
item - > Position . yRot + ANGLE ( 180.0f ) ,
2022-01-30 14:43:33 +11:00
NO_LOWER_BOUND , - STEPUP_HEIGHT ,
2022-01-08 15:43:17 +11:00
false , false , false
} ;
2022-01-26 20:27:52 +11:00
return TestLaraMoveTolerance ( item , coll , testSetup ) ;
2021-10-04 22:02:02 +11:00
}
2022-03-14 01:20:51 +11:00
bool TestLaraStepLeft ( ITEM_INFO * item , CollisionInfo * coll )
2021-10-04 22:02:02 +11:00
{
2022-01-30 14:43:33 +11:00
// Using Lower/UpperFloorBound defined in step left state collision function.
2022-01-08 15:43:17 +11:00
2022-01-26 20:27:52 +11:00
MoveTestSetup testSetup
2022-01-08 15:43:17 +11:00
{
2022-02-09 16:55:46 +11:00
item - > Position . yRot - ANGLE ( 90.0f ) ,
2022-01-30 14:43:33 +11:00
CLICK ( 0.8f ) , - CLICK ( 0.8f )
2022-01-08 15:43:17 +11:00
} ;
2022-01-26 20:27:52 +11:00
return TestLaraMoveTolerance ( item , coll , testSetup ) ;
2021-10-19 21:28:36 +11:00
}
2022-03-14 01:20:51 +11:00
bool TestLaraStepRight ( ITEM_INFO * item , CollisionInfo * coll )
2021-10-19 21:28:36 +11:00
{
2022-01-30 14:43:33 +11:00
// Using Lower/UpperFloorBound defined in step right state collision function.
2022-01-08 15:43:17 +11:00
2022-01-26 20:27:52 +11:00
MoveTestSetup testSetup
2022-01-08 15:43:17 +11:00
{
2022-02-09 16:55:46 +11:00
item - > Position . yRot + ANGLE ( 90.0f ) ,
2022-01-30 14:43:33 +11:00
CLICK ( 0.8f ) , - CLICK ( 0.8f )
2022-01-08 15:43:17 +11:00
} ;
2022-01-26 20:27:52 +11:00
return TestLaraMoveTolerance ( item , coll , testSetup ) ;
2021-12-26 00:18:38 +11:00
}
2022-03-14 01:20:51 +11:00
bool TestLaraWadeForwardSwamp ( ITEM_INFO * item , CollisionInfo * coll )
2022-01-02 21:31:18 +11:00
{
2022-01-30 14:43:33 +11:00
// Using Lower/UpperFloorBound defined in wade forward state collision function.
2022-01-02 21:31:18 +11:00
2022-01-26 20:27:52 +11:00
MoveTestSetup testSetup
2022-01-08 15:43:17 +11:00
{
2022-02-09 16:55:46 +11:00
item - > Position . yRot ,
2022-01-30 14:43:33 +11:00
NO_LOWER_BOUND , - STEPUP_HEIGHT ,
2022-01-08 15:43:17 +11:00
false , false , false
} ;
2022-01-02 21:31:18 +11:00
2022-01-26 20:27:52 +11:00
return TestLaraMoveTolerance ( item , coll , testSetup ) ;
2021-10-24 20:43:02 +11:00
}
2021-10-04 22:02:02 +11:00
2022-03-14 01:20:51 +11:00
bool TestLaraWalkBackSwamp ( ITEM_INFO * item , CollisionInfo * coll )
2021-11-07 21:55:38 +11:00
{
2022-01-30 14:43:33 +11:00
// Using UpperFloorBound defined in walk back state collision function.
2022-01-08 15:43:17 +11:00
2022-01-26 20:27:52 +11:00
MoveTestSetup testSetup
2022-01-02 21:31:18 +11:00
{
2022-02-09 16:55:46 +11:00
item - > Position . yRot + ANGLE ( 180.0f ) ,
2022-01-30 14:43:33 +11:00
NO_LOWER_BOUND , - STEPUP_HEIGHT ,
2022-01-08 15:43:17 +11:00
false , false , false
} ;
2022-01-02 21:31:18 +11:00
2022-01-26 20:27:52 +11:00
return TestLaraMoveTolerance ( item , coll , testSetup ) ;
2021-11-07 21:55:38 +11:00
}
2022-03-14 01:20:51 +11:00
bool TestLaraStepLeftSwamp ( ITEM_INFO * item , CollisionInfo * coll )
2021-11-07 21:55:38 +11:00
{
2022-01-30 14:43:33 +11:00
// Using UpperFloorBound defined in step left state collision function.
2022-01-03 01:29:32 +11:00
2022-01-26 20:27:52 +11:00
MoveTestSetup testSetup
2022-01-08 15:43:17 +11:00
{
2022-02-09 16:55:46 +11:00
item - > Position . yRot - ANGLE ( 90.0f ) ,
2022-01-30 14:43:33 +11:00
NO_LOWER_BOUND , - CLICK ( 0.8f ) ,
2022-01-08 15:43:17 +11:00
false , false , false
} ;
2022-01-03 13:52:07 +11:00
2022-01-26 20:27:52 +11:00
return TestLaraMoveTolerance ( item , coll , testSetup ) ;
2021-11-07 21:55:38 +11:00
}
2022-03-14 01:20:51 +11:00
bool TestLaraStepRightSwamp ( ITEM_INFO * item , CollisionInfo * coll )
2021-11-07 21:55:38 +11:00
{
2022-01-30 14:43:33 +11:00
// Using UpperFloorBound defined in step right state collision function.
2022-01-08 15:43:17 +11:00
2022-01-26 20:27:52 +11:00
MoveTestSetup testSetup
2022-01-03 01:29:32 +11:00
{
2022-02-09 16:55:46 +11:00
item - > Position . yRot + ANGLE ( 90.0f ) ,
2022-01-30 14:43:33 +11:00
NO_LOWER_BOUND , - CLICK ( 0.8f ) ,
2022-01-08 15:43:17 +11:00
false , false , false
} ;
2022-01-03 01:29:32 +11:00
2022-01-26 20:27:52 +11:00
return TestLaraMoveTolerance ( item , coll , testSetup ) ;
2021-11-07 21:55:38 +11:00
}
2022-03-14 01:20:51 +11:00
bool TestLaraCrawlForward ( ITEM_INFO * item , CollisionInfo * coll )
2021-10-24 20:43:02 +11:00
{
2022-01-30 14:43:33 +11:00
// Using Lower/UpperFloorBound defined in crawl state collision functions.
2022-01-03 01:29:32 +11:00
2022-01-26 20:27:52 +11:00
MoveTestSetup testSetup
2022-01-08 15:43:17 +11:00
{
2022-02-09 16:55:46 +11:00
item - > Position . yRot ,
2022-01-30 14:43:33 +11:00
CLICK ( 1 ) - 1 , - ( CLICK ( 1 ) - 1 )
2022-01-08 15:43:17 +11:00
} ;
2022-01-03 01:29:32 +11:00
2022-03-16 20:50:36 +11:00
return TestLaraMoveTolerance ( item , coll , testSetup , true ) ;
2021-10-24 20:43:02 +11:00
}
2021-10-04 22:02:02 +11:00
2022-03-14 01:20:51 +11:00
bool TestLaraCrawlBack ( ITEM_INFO * item , CollisionInfo * coll )
2021-10-24 20:43:02 +11:00
{
2022-01-30 14:43:33 +11:00
// Using Lower/UpperFloorBound defined in crawl state collision functions.
2022-01-08 15:43:17 +11:00
2022-01-26 20:27:52 +11:00
MoveTestSetup testSetup
2022-01-08 15:43:17 +11:00
{
2022-02-09 16:55:46 +11:00
item - > Position . yRot + ANGLE ( 180.0f ) ,
2022-01-30 14:43:33 +11:00
CLICK ( 1 ) - 1 , - ( CLICK ( 1 ) - 1 )
2022-01-08 15:43:17 +11:00
} ;
2022-03-16 20:50:36 +11:00
return TestLaraMoveTolerance ( item , coll , testSetup , true ) ;
2021-10-04 22:02:02 +11:00
}
2022-03-14 01:20:51 +11:00
bool TestLaraCrouchRoll ( ITEM_INFO * item , CollisionInfo * coll )
2021-09-26 20:59:16 +10:00
{
2022-02-28 21:02:19 +11:00
auto * lara = GetLaraInfo ( item ) ;
2021-11-20 12:25:51 +11:00
2022-02-25 21:02:08 +11:00
int y = item - > Position . yPos ;
int distance = CLICK ( 3 ) ;
2022-03-14 01:20:51 +11:00
auto probe = GetCollision ( item , item - > Position . yRot , distance , - LARA_HEIGHT_CRAWL ) ;
2022-02-25 21:02:08 +11:00
2022-03-18 22:51:53 +11:00
if ( ! ( TrInput & ( IN_FLARE | IN_DRAW ) ) & & // Avoid unsightly concurrent actions.
( probe . Position . Floor - y ) < = ( CLICK ( 1 ) - 1 ) & & // Within lower floor bound.
( probe . Position . Floor - y ) > = - ( CLICK ( 1 ) - 1 ) & & // Within upper floor bound.
( probe . Position . Ceiling - y ) < - LARA_HEIGHT_CRAWL & & // Within lowest ceiling bound.
! probe . Position . FloorSlope & & // Not a slope.
lara - > WaterSurfaceDist > = - CLICK ( 1 ) ) // Water depth is optically permissive.
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
}
2022-02-25 21:02:08 +11:00
bool TestLaraCrouchToCrawl ( ITEM_INFO * item )
2021-09-27 18:18:03 +10:00
{
2022-02-28 21:02:19 +11:00
auto * lara = GetLaraInfo ( item ) ;
2021-11-20 12:25:51 +11:00
2022-03-09 20:37:26 +11:00
if ( ! ( TrInput & ( IN_FLARE | IN_DRAW ) ) & & // Avoid unsightly concurrent actions.
lara - > Control . HandStatus = = HandStatus : : Free & & // Hands are free.
2022-03-18 22:51:53 +11:00
( lara - > Control . Weapon . GunType ! = LaraWeaponType : : Flare | | // Not handling flare. TODO: Should be allowed, but the flare animation bugs out right now. @Sezz 2022.03.18
2022-02-28 21:02:19 +11:00
lara - > Flare . Life ) )
2021-10-16 20:50:16 +11:00
{
return true ;
}
return false ;
}
2022-03-14 01:20:51 +11:00
bool TestLaraMonkeyMoveTolerance ( ITEM_INFO * item , CollisionInfo * coll , MonkeyMoveTestSetup testSetup )
2021-10-16 20:50:16 +11:00
{
2022-02-09 16:55:46 +11:00
int y = item - > Position . yPos - LARA_HEIGHT_MONKEY ;
2022-02-25 21:02:08 +11:00
int distance = OFFSET_RADIUS ( coll - > Setup . Radius ) ;
2022-03-14 01:20:51 +11:00
auto probe = GetCollision ( item , testSetup . Angle , distance ) ;
2022-01-28 00:02:48 +11:00
2022-02-07 23:07:40 +11:00
auto start1 = GAME_VECTOR (
2022-02-09 16:55:46 +11:00
item - > Position . xPos ,
2022-02-07 23:07:40 +11:00
y + testSetup . LowerCeilingBound + 1 ,
2022-02-09 16:55:46 +11:00
item - > Position . zPos ,
item - > RoomNumber ) ;
2022-01-28 00:02:48 +11:00
2022-02-07 23:07:40 +11:00
auto end1 = GAME_VECTOR (
probe . Coordinates . x ,
probe . Coordinates . y - LARA_HEIGHT_MONKEY + testSetup . LowerCeilingBound + 1 ,
probe . Coordinates . z ,
2022-02-09 16:55:46 +11:00
item - > RoomNumber ) ;
2022-01-28 00:02:48 +11:00
2022-02-07 23:07:40 +11:00
auto start2 = GAME_VECTOR (
2022-02-09 16:55:46 +11:00
item - > Position . xPos ,
2022-02-07 23:07:40 +11:00
y + LARA_HEIGHT_MONKEY - 1 ,
2022-02-09 16:55:46 +11:00
item - > Position . zPos ,
item - > RoomNumber ) ;
2022-02-06 00:27:25 +11:00
2022-02-07 23:07:40 +11:00
auto end2 = GAME_VECTOR (
probe . Coordinates . x ,
probe . Coordinates . y - 1 ,
probe . Coordinates . z ,
2022-02-09 16:55:46 +11:00
item - > RoomNumber ) ;
2022-02-06 00:27:25 +11:00
2022-02-07 23:07:40 +11:00
// Discard walls.
if ( probe . Position . Ceiling = = NO_HEIGHT )
2022-02-06 00:27:25 +11:00
return false ;
2022-02-08 01:26:59 +11:00
// Check for ceiling slope.
2022-02-07 23:07:40 +11:00
if ( probe . Position . CeilingSlope )
return false ;
2022-02-21 20:27:30 +11:00
// Conduct ray test at lower ceiling bound and highest floor bound.
2022-02-07 23:07:40 +11:00
if ( ! LOS ( & start1 , & end1 ) | | ! LOS ( & start2 , & end2 ) )
2022-01-28 00:02:48 +11:00
return false ;
2022-01-15 22:48:35 +11:00
2022-01-28 00:02:48 +11:00
// Assess move feasibility to location ahead.
2022-01-22 22:36:29 +11:00
if ( probe . BottomBlock - > Flags . Monkeyswing & & // Is monkey sector.
2022-01-30 14:43:33 +11:00
( probe . Position . Floor - y ) > LARA_HEIGHT_MONKEY & & // Within highest floor bound.
2022-02-06 00:27:25 +11:00
( probe . Position . Ceiling - y ) < = testSetup . LowerCeilingBound & & // Within lower ceiling bound.
( probe . Position . Ceiling - y ) > = testSetup . UpperCeilingBound & & // Within upper ceiling bound.
2022-02-07 23:07:40 +11:00
abs ( probe . Position . Ceiling - probe . Position . Floor ) > LARA_HEIGHT_MONKEY ) // Space is not a clamp.
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-03-14 01:20:51 +11:00
bool TestLaraMonkeyForward ( ITEM_INFO * item , CollisionInfo * coll )
2022-01-08 16:08:31 +11:00
{
2022-01-30 14:43:33 +11:00
// Using Lower/UpperCeilingBound defined in monkey forward collision function.
2022-01-27 14:16:38 +11:00
MonkeyMoveTestSetup testSetup
2022-01-08 16:50:23 +11:00
{
2022-02-09 16:55:46 +11:00
item - > Position . yRot ,
2022-01-30 14:43:33 +11:00
CLICK ( 1.25f ) , - CLICK ( 1.25f )
2022-01-08 16:50:23 +11:00
} ;
2022-01-27 14:16:38 +11:00
return TestLaraMonkeyMoveTolerance ( item , coll , testSetup ) ;
2022-01-08 16:08:31 +11:00
}
2022-03-14 01:20:51 +11:00
bool TestLaraMonkeyBack ( ITEM_INFO * item , CollisionInfo * coll )
2021-10-16 20:50:16 +11:00
{
2022-01-30 14:43:33 +11:00
// Using Lower/UpperCeilingBound defined in monkey back collision function.
2022-01-27 14:16:38 +11:00
MonkeyMoveTestSetup testSetup
2022-01-08 16:50:23 +11:00
{
2022-02-09 16:55:46 +11:00
item - > Position . yRot + ANGLE ( 180.0f ) ,
2022-01-30 14:43:33 +11:00
CLICK ( 1.25f ) , - CLICK ( 1.25f )
2022-01-08 16:50:23 +11:00
} ;
2022-01-27 14:16:38 +11:00
return TestLaraMonkeyMoveTolerance ( item , coll , testSetup ) ;
2022-01-08 16:08:31 +11:00
}
2022-03-14 01:20:51 +11:00
bool TestLaraMonkeyShimmyLeft ( ITEM_INFO * item , CollisionInfo * coll )
2022-01-08 16:08:31 +11:00
{
2022-01-30 14:43:33 +11:00
// Using Lower/UpperCeilingBound defined in monkey shimmy left collision function.
2022-01-27 14:16:38 +11:00
MonkeyMoveTestSetup testSetup
2022-01-08 16:50:23 +11:00
{
2022-02-09 16:55:46 +11:00
item - > Position . yRot - ANGLE ( 90.0f ) ,
2022-01-30 14:43:33 +11:00
CLICK ( 0.5f ) , - CLICK ( 0.5f )
2022-01-08 16:50:23 +11:00
} ;
2022-01-27 14:16:38 +11:00
return TestLaraMonkeyMoveTolerance ( item , coll , testSetup ) ;
2022-01-08 16:08:31 +11:00
}
2022-03-14 01:20:51 +11:00
bool TestLaraMonkeyShimmyRight ( ITEM_INFO * item , CollisionInfo * coll )
2022-01-08 16:08:31 +11:00
{
2022-01-30 14:43:33 +11:00
// Using Lower/UpperCeilingBound defined in monkey shimmy right collision function.
2022-01-27 14:16:38 +11:00
MonkeyMoveTestSetup testSetup
2022-01-08 16:50:23 +11:00
{
2022-02-09 16:55:46 +11:00
item - > Position . yRot + ANGLE ( 90.0f ) ,
2022-01-30 14:43:33 +11:00
CLICK ( 0.5f ) , - CLICK ( 0.5f )
2022-01-08 16:50:23 +11:00
} ;
2022-01-27 14:16:38 +11:00
return TestLaraMonkeyMoveTolerance ( item , coll , testSetup ) ;
2022-01-08 16:08:31 +11:00
}
2022-03-14 01:20:51 +11:00
VaultTestResult TestLaraVaultTolerance ( ITEM_INFO * item , CollisionInfo * coll , VaultTestSetup testSetup )
2021-12-10 12:30:23 +11:00
{
2022-02-28 21:02:19 +11:00
auto * lara = GetLaraInfo ( item ) ;
2022-01-08 15:43:17 +11:00
2022-02-09 16:55:46 +11:00
int y = item - > Position . yPos ;
2022-02-25 21:02:08 +11:00
int distance = OFFSET_RADIUS ( coll - > Setup . Radius ) ;
2022-03-14 01:20:51 +11:00
auto probeFront = GetCollision ( item , coll - > NearestLedgeAngle , distance , - coll - > Setup . Height ) ;
auto probeMiddle = GetCollision ( item ) ;
2022-01-30 15:17:57 +11:00
2022-02-28 21:02:19 +11:00
bool swampTooDeep = testSetup . CheckSwampDepth ? ( TestEnvironment ( ENV_FLAG_SWAMP , item ) & & lara - > WaterSurfaceDist < - CLICK ( 3 ) ) : TestEnvironment ( ENV_FLAG_SWAMP , item ) ;
2022-02-07 23:07:40 +11:00
2022-02-08 01:26:59 +11:00
// Check swamp depth (if applicable).
2022-02-07 23:07:40 +11:00
if ( swampTooDeep )
return VaultTestResult { false } ;
2021-12-10 12:30:23 +11:00
2022-02-07 17:06:45 +11:00
// HACK: Where the probe finds that the wall in front is formed by a ceiling or the space between the floor and ceiling is a clamp,
2022-02-25 21:02:08 +11:00
// any climbable floor in a room above will be missed.
2022-02-07 17:06:45 +11:00
// Raise y position of probe point by increments of CLICK(0.5f) to find this potential vault candidate location.
2022-01-30 14:43:33 +11:00
int yOffset = testSetup . LowerCeilingBound ;
while ( ( ( probeFront . Position . Ceiling - y ) > - coll - > Setup . Height | | // Ceiling is below Lara's height...
abs ( probeFront . Position . Ceiling - probeFront . Position . Floor ) < = testSetup . ClampMin | | // OR clamp is too small
abs ( probeFront . Position . Ceiling - probeFront . Position . Floor ) > testSetup . ClampMax ) & & // OR clamp is too large (future-proofing; not possible right now).
yOffset > ( testSetup . UpperCeilingBound - coll - > Setup . Height ) ) // Offset is not too high.
2021-12-10 12:30:23 +11:00
{
2022-03-14 01:20:51 +11:00
probeFront = GetCollision ( item , coll - > NearestLedgeAngle , distance , yOffset ) ;
2022-01-27 22:26:05 +11:00
yOffset - = std : : max < int > ( CLICK ( 0.5f ) , testSetup . ClampMin ) ;
2022-01-08 15:43:17 +11:00
}
2022-02-07 23:07:40 +11:00
// Discard walls.
if ( probeFront . Position . Floor = = NO_HEIGHT )
return VaultTestResult { false } ;
2022-01-08 15:43:17 +11:00
// Assess vault candidate location.
2022-01-30 14:43:33 +11:00
if ( ( probeFront . Position . Floor - y ) < testSetup . LowerCeilingBound & & // Within lower floor bound.
( probeFront . Position . Floor - y ) > = testSetup . UpperCeilingBound & & // Within upper floor bound.
abs ( probeFront . Position . Ceiling - probeFront . Position . Floor ) > testSetup . ClampMin & & // Within clamp min.
abs ( probeFront . Position . Ceiling - probeFront . Position . Floor ) < = testSetup . ClampMax & & // Within clamp max.
2022-02-07 23:07:40 +11:00
abs ( probeMiddle . Position . Ceiling - probeFront . Position . Floor ) > = testSetup . GapMin ) // Gap is optically permissive.
2021-10-16 20:50:16 +11:00
{
2022-02-06 14:15:10 +11:00
return VaultTestResult { true , probeFront . Position . Floor } ;
2021-10-16 20:50:16 +11:00
}
2022-02-06 14:15:10 +11:00
return VaultTestResult { false } ;
2021-10-16 20:50:16 +11:00
}
2022-03-14 01:20:51 +11:00
VaultTestResult TestLaraVault2Steps ( ITEM_INFO * item , CollisionInfo * coll )
2021-10-28 23:22:28 +11:00
{
2022-01-08 15:43:17 +11:00
// Floor range: (-STEPUP_HEIGHT, -CLICK(2.5f)]
2022-01-30 14:43:33 +11:00
// Clamp range: (-LARA_HEIGHT, -MAX_HEIGHT]
2021-10-28 23:22:28 +11:00
2022-01-26 20:27:52 +11:00
VaultTestSetup testSetup
2022-01-08 15:43:17 +11:00
{
2022-01-30 14:43:33 +11:00
- 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-02-06 14:53:55 +11:00
auto testResult = TestLaraVaultTolerance ( item , coll , testSetup ) ;
testResult . Height + = CLICK ( 2 ) ;
testResult . SetBusyHands = true ;
testResult . SnapToLedge = true ;
2022-02-27 23:51:00 +11:00
testResult . SetJumpVelocity = false ;
2022-02-06 14:53:55 +11:00
return testResult ;
2021-10-19 21:28:36 +11:00
}
2022-03-14 01:20:51 +11:00
VaultTestResult TestLaraVault3Steps ( ITEM_INFO * item , CollisionInfo * 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)]
2022-01-30 14:43:33 +11:00
// Clamp range: (-LARA_HEIGHT, -MAX_HEIGHT]
2021-10-04 22:02:02 +11:00
2022-01-26 20:27:52 +11:00
VaultTestSetup testSetup
2022-01-08 15:43:17 +11:00
{
2022-01-30 14:43:33 +11:00
- CLICK ( 2.5f ) , - CLICK ( 3.5f ) ,
LARA_HEIGHT , - MAX_HEIGHT ,
2022-01-08 15:43:17 +11:00
CLICK ( 1 ) ,
} ;
2021-10-19 21:28:36 +11:00
2022-02-06 14:53:55 +11:00
auto testResult = TestLaraVaultTolerance ( item , coll , testSetup ) ;
testResult . Height + = CLICK ( 3 ) ;
testResult . SetBusyHands = true ;
testResult . SnapToLedge = true ;
2022-02-27 23:51:00 +11:00
testResult . SetJumpVelocity = false ;
2022-02-06 14:53:55 +11:00
return testResult ;
2021-10-24 20:43:02 +11:00
}
2021-10-04 22:02:02 +11:00
2022-03-14 01:20:51 +11:00
VaultTestResult TestLaraVault1StepToCrouch ( ITEM_INFO * item , CollisionInfo * 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]
2022-01-26 20:27:52 +11:00
VaultTestSetup testSetup
2022-01-08 15:43:17 +11:00
{
2022-01-30 14:43:33 +11:00
0 , - STEPUP_HEIGHT ,
LARA_HEIGHT_CRAWL , LARA_HEIGHT ,
2022-01-08 15:43:17 +11:00
CLICK ( 1 ) ,
} ;
2022-02-06 14:53:55 +11:00
auto testResult = TestLaraVaultTolerance ( item , coll , testSetup ) ;
testResult . Height + = CLICK ( 1 ) ;
testResult . SetBusyHands = true ;
testResult . SnapToLedge = true ;
2022-02-27 23:51:00 +11:00
testResult . SetJumpVelocity = false ;
2022-02-06 14:53:55 +11:00
return testResult ;
2021-11-07 21:55:38 +11:00
}
2022-03-14 01:20:51 +11:00
VaultTestResult TestLaraVault2StepsToCrouch ( ITEM_INFO * item , CollisionInfo * 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]
2022-01-26 20:27:52 +11:00
VaultTestSetup testSetup
2022-01-08 15:43:17 +11:00
{
2022-01-30 14:43:33 +11:00
- STEPUP_HEIGHT , - CLICK ( 2.5f ) ,
LARA_HEIGHT_CRAWL , LARA_HEIGHT ,
2022-01-08 15:43:17 +11:00
CLICK ( 1 ) ,
} ;
2022-02-06 14:53:55 +11:00
auto testResult = TestLaraVaultTolerance ( item , coll , testSetup ) ;
testResult . Height + = CLICK ( 2 ) ;
testResult . SetBusyHands = true ;
testResult . SnapToLedge = true ;
2022-02-27 23:51:00 +11:00
testResult . SetJumpVelocity = false ;
2022-02-06 14:53:55 +11:00
return testResult ;
2021-11-07 21:55:38 +11:00
}
2022-03-14 01:20:51 +11:00
VaultTestResult TestLaraVault3StepsToCrouch ( ITEM_INFO * item , CollisionInfo * 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]
2022-01-26 20:27:52 +11:00
VaultTestSetup testSetup
2022-01-08 15:43:17 +11:00
{
2022-01-30 14:43:33 +11:00
- CLICK ( 2.5f ) , - CLICK ( 3.5f ) ,
LARA_HEIGHT_CRAWL , LARA_HEIGHT ,
2022-01-08 15:43:17 +11:00
CLICK ( 1 ) ,
} ;
2022-02-06 14:53:55 +11:00
auto testResult = TestLaraVaultTolerance ( item , coll , testSetup ) ;
testResult . Height + = CLICK ( 3 ) ;
testResult . SetBusyHands = true ;
testResult . SnapToLedge = true ;
2022-02-27 23:51:00 +11:00
testResult . SetJumpVelocity = false ;
2022-02-06 14:53:55 +11:00
return testResult ;
2021-10-24 20:43:02 +11:00
}
2021-10-04 22:02:02 +11:00
2022-03-14 01:20:51 +11:00
VaultTestResult TestLaraLedgeAutoJump ( ITEM_INFO * item , CollisionInfo * coll )
2022-02-05 23:13:31 +11:00
{
// Floor range: (-CLICK(3.5f), -CLICK(7.5f)]
// Clamp range: (-CLICK(0.1f), -MAX_HEIGHT]
VaultTestSetup testSetup
{
- CLICK ( 3.5f ) , - CLICK ( 7.5f ) ,
CLICK ( 0.1f ) /* TODO: Is this enough hand room?*/ , - MAX_HEIGHT ,
CLICK ( 0.1f ) ,
false
} ;
2022-02-06 14:53:55 +11:00
auto testResult = TestLaraVaultTolerance ( item , coll , testSetup ) ;
testResult . SetBusyHands = false ;
testResult . SnapToLedge = true ;
2022-02-27 23:51:00 +11:00
testResult . SetJumpVelocity = true ;
2022-02-06 14:53:55 +11:00
return testResult ;
2022-02-05 23:13:31 +11:00
}
2022-03-14 01:20:51 +11:00
VaultTestResult TestLaraLadderAutoJump ( ITEM_INFO * item , CollisionInfo * coll )
2021-10-16 20:50:16 +11:00
{
2022-02-28 21:02:19 +11:00
auto * lara = GetLaraInfo ( item ) ;
2022-01-08 15:43:17 +11:00
2022-02-09 16:55:46 +11:00
int y = item - > Position . yPos ;
2022-02-25 21:02:08 +11:00
int distance = OFFSET_RADIUS ( coll - > Setup . Radius ) ;
2022-03-14 01:20:51 +11:00
auto probeFront = GetCollision ( item , coll - > NearestLedgeAngle , distance , - coll - > Setup . Height ) ;
auto probeMiddle = GetCollision ( item ) ;
2022-01-08 15:43:17 +11:00
2022-01-30 14:43:33 +11:00
if ( TestValidLedgeAngle ( item , coll ) & & // Appropriate angle difference from ladder.
2022-01-25 18:02:22 +11:00
! TestEnvironment ( ENV_FLAG_SWAMP , item ) & & // No swamp.
2022-02-28 21:02:19 +11:00
lara - > Control . CanClimbLadder & & // Ladder sector flag set.
2022-01-30 14:43:33 +11:00
( probeMiddle . Position . Ceiling - y ) < = - CLICK ( 6.5f ) & & // Within lowest middle ceiling bound. (Synced with TestLaraLadderMount())
coll - > NearestLedgeDistance < = coll - > Setup . Radius ) // Appropriate distance from wall (tentative).
2021-10-16 20:50:16 +11:00
{
2022-02-28 00:40:18 +11:00
return VaultTestResult { true , probeMiddle . Position . Ceiling , false , true , true } ;
2021-10-16 20:50:16 +11:00
}
2022-02-06 14:15:10 +11:00
return VaultTestResult { false } ;
2021-10-16 20:50:16 +11:00
}
2022-03-14 01:20:51 +11:00
VaultTestResult TestLaraLadderMount ( ITEM_INFO * item , CollisionInfo * coll )
2021-10-16 20:50:16 +11:00
{
2022-02-28 21:02:19 +11:00
auto * lara = GetLaraInfo ( item ) ;
2021-11-20 12:25:51 +11:00
2022-02-09 16:55:46 +11:00
int y = item - > Position . yPos ;
2022-02-25 21:02:08 +11:00
int distance = OFFSET_RADIUS ( coll - > Setup . Radius ) ;
2022-03-14 01:20:51 +11:00
auto probeFront = GetCollision ( item , coll - > NearestLedgeAngle , distance , - coll - > Setup . Height ) ;
auto probeMiddle = GetCollision ( item ) ;
2022-01-08 15:43:17 +11:00
if ( TestValidLedgeAngle ( item , coll ) & &
2022-02-28 21:02:19 +11:00
lara - > Control . CanClimbLadder & & // Ladder sector flag set.
2022-01-30 14:43:33 +11:00
( probeMiddle . Position . Ceiling - y ) < = - CLICK ( 4.5f ) & & // Within lower middle ceiling bound.
( probeMiddle . Position . Floor - y ) > - CLICK ( 6.5f ) & & // Within upper middle floor bound. (Synced with TestLaraAutoJump())
( probeFront . Position . Ceiling - y ) < = - CLICK ( 4.5f ) & & // Within lowest front ceiling bound.
2022-01-26 14:51:50 +11:00
coll - > NearestLedgeDistance < = coll - > Setup . Radius ) // Appropriate distance from wall.
2021-09-27 18:18:03 +10:00
{
2022-02-28 00:40:18 +11:00
return VaultTestResult { true , NO_HEIGHT , true , true , false } ;
2021-09-27 18:18:03 +10:00
}
2021-09-26 20:59:16 +10:00
2022-02-06 14:15:10 +11:00
return VaultTestResult { false } ;
2021-09-26 20:59:16 +10:00
}
2021-11-29 00:06:18 +11:00
2022-03-14 01:20:51 +11:00
VaultTestResult TestLaraMonkeyAutoJump ( ITEM_INFO * item , CollisionInfo * coll )
2021-09-27 18:18:03 +10:00
{
2022-02-28 21:02:19 +11:00
auto * lara = GetLaraInfo ( item ) ;
2021-11-20 12:25:51 +11:00
2022-02-09 16:55:46 +11:00
int y = item - > Position . yPos ;
2022-03-14 01:20:51 +11:00
auto probe = GetCollision ( item ) ;
2021-11-11 23:31:04 +11:00
2022-01-25 18:02:22 +11:00
if ( ! TestEnvironment ( ENV_FLAG_SWAMP , item ) & & // No swamp.
2022-02-28 21:02:19 +11:00
lara - > Control . CanMonkeySwing & & // Monkey swing sector flag set.
2022-01-30 14:43:33 +11:00
( probe . Position . Ceiling - y ) < - LARA_HEIGHT_MONKEY & & // Within lower ceiling bound.
( probe . Position . Ceiling - y ) > = - CLICK ( 7 ) ) // Within upper ceiling bound.
2021-10-16 20:50:16 +11:00
{
2022-02-28 00:40:18 +11:00
return VaultTestResult { true , probe . Position . Ceiling , false , false , true } ;
2022-02-05 23:13:31 +11:00
}
2022-02-06 14:15:10 +11:00
return VaultTestResult { false } ;
2022-02-05 23:13:31 +11:00
}
2022-03-14 01:20:51 +11:00
VaultTestResult TestLaraVault ( ITEM_INFO * item , CollisionInfo * coll )
2022-02-05 23:13:31 +11:00
{
2022-02-28 21:02:19 +11:00
auto * lara = GetLaraInfo ( item ) ;
2022-02-05 23:13:31 +11:00
2022-02-28 21:02:19 +11:00
if ( ! ( TrInput & IN_ACTION ) | | lara - > Control . HandStatus ! = HandStatus : : Free )
2022-02-06 14:15:10 +11:00
return VaultTestResult { false } ;
2022-02-05 23:13:31 +11:00
2022-02-28 21:02:19 +11:00
if ( TestEnvironment ( ENV_FLAG_SWAMP , item ) & & lara - > WaterSurfaceDist < - CLICK ( 3 ) )
2022-02-06 14:15:10 +11:00
return VaultTestResult { false } ;
2022-02-05 23:13:31 +11:00
VaultTestResult vaultResult ;
// Attempt ledge vault.
if ( TestValidLedge ( item , coll ) )
{
// Vault to crouch up one step.
vaultResult = TestLaraVault1StepToCrouch ( item , coll ) ;
if ( vaultResult . Success )
{
vaultResult . TargetState = LS_VAULT_1_STEP_CROUCH ;
2022-03-15 19:53:16 +11:00
vaultResult . Success = HasChange ( item , vaultResult . TargetState ) ;
2022-02-05 23:13:31 +11:00
return vaultResult ;
}
// Vault to stand up two steps.
vaultResult = TestLaraVault2Steps ( item , coll ) ;
if ( vaultResult . Success )
{
vaultResult . TargetState = LS_VAULT_2_STEPS ;
2022-03-15 19:53:16 +11:00
vaultResult . Success = HasChange ( item , vaultResult . TargetState ) ;
2022-02-05 23:13:31 +11:00
return vaultResult ;
}
// Vault to crouch up two steps.
vaultResult = TestLaraVault2StepsToCrouch ( item , coll ) ;
if ( vaultResult . Success & &
2022-03-04 15:51:53 +11:00
g_GameFlow - > Animations . HasCrawlExtended )
2022-02-05 23:13:31 +11:00
{
vaultResult . TargetState = LS_VAULT_2_STEPS_CROUCH ;
2022-03-15 19:53:16 +11:00
vaultResult . Success = HasChange ( item , vaultResult . TargetState ) ;
2022-02-05 23:13:31 +11:00
return vaultResult ;
}
// Vault to stand up three steps.
vaultResult = TestLaraVault3Steps ( item , coll ) ;
if ( vaultResult . Success )
{
vaultResult . TargetState = LS_VAULT_3_STEPS ;
2022-03-15 19:53:16 +11:00
vaultResult . Success = HasChange ( item , vaultResult . TargetState ) ;
2022-02-05 23:13:31 +11:00
return vaultResult ;
}
// Vault to crouch up three steps.
vaultResult = TestLaraVault3StepsToCrouch ( item , coll ) ;
if ( vaultResult . Success & &
2022-03-04 15:51:53 +11:00
g_GameFlow - > Animations . HasCrawlExtended )
2022-02-05 23:13:31 +11:00
{
vaultResult . TargetState = LS_VAULT_3_STEPS_CROUCH ;
2022-03-15 19:53:16 +11:00
vaultResult . Success = HasChange ( item , vaultResult . TargetState ) ;
2022-02-05 23:13:31 +11:00
return vaultResult ;
}
// Auto jump to ledge.
2022-02-12 20:23:45 +11:00
vaultResult = TestLaraLedgeAutoJump ( item , coll ) ;
2022-02-05 23:13:31 +11:00
if ( vaultResult . Success )
{
vaultResult . TargetState = LS_AUTO_JUMP ;
2022-03-15 19:53:16 +11:00
vaultResult . Success = HasChange ( item , vaultResult . TargetState ) ;
2022-02-05 23:13:31 +11:00
return vaultResult ;
}
}
// TODO: Move ladder checks here when ladders are less prone to breaking.
// In this case, they fail due to a reliance on ShiftItem(). @Sezz 2021.02.05
// Auto jump to monkey swing.
vaultResult = TestLaraMonkeyAutoJump ( item , coll ) ;
2022-02-06 14:53:55 +11:00
if ( vaultResult . Success & &
2022-03-04 15:51:53 +11:00
g_GameFlow - > Animations . HasMonkeyAutoJump )
2022-02-05 23:13:31 +11:00
{
vaultResult . TargetState = LS_AUTO_JUMP ;
2022-03-15 19:53:16 +11:00
vaultResult . Success = HasChange ( item , vaultResult . TargetState ) ;
2022-02-05 23:13:31 +11:00
return vaultResult ;
}
2022-02-06 14:15:10 +11:00
return VaultTestResult { false } ;
2022-02-05 23:13:31 +11:00
}
2022-03-17 01:19:21 +11:00
// Temporary solution to ladder mounts until ladders stop breaking whenever anyone tries to do anything with them. @Sezz 2022.02.05
2022-03-14 01:20:51 +11:00
bool TestAndDoLaraLadderClimb ( ITEM_INFO * item , CollisionInfo * coll )
2022-02-05 23:13:31 +11:00
{
2022-02-28 21:02:19 +11:00
auto * lara = GetLaraInfo ( item ) ;
2022-02-05 23:13:31 +11:00
2022-02-28 21:02:19 +11:00
if ( ! ( TrInput & IN_ACTION ) | | ! ( TrInput & IN_FORWARD ) | | lara - > Control . HandStatus ! = HandStatus : : Free )
2022-02-05 23:13:31 +11:00
return false ;
2022-02-28 21:02:19 +11:00
if ( TestEnvironment ( ENV_FLAG_SWAMP , item ) & & lara - > WaterSurfaceDist < - CLICK ( 3 ) )
2022-02-05 23:13:31 +11:00
return false ;
// Auto jump to ladder.
auto vaultResult = TestLaraLadderAutoJump ( item , coll ) ;
if ( vaultResult . Success )
{
2022-02-26 23:08:48 +11:00
// TODO: Somehow harmonise CalculatedJumpVelocity to work for both ledge and ladder auto jumps, because otherwise there will be a need for an odd workaround in the future.
2022-02-28 21:02:19 +11:00
lara - > Control . CalculatedJumpVelocity = - 3 - sqrt ( - 9600 - 12 * std : : max ( ( vaultResult . Height - item - > Position . yPos + CLICK ( 0.2f ) ) , - CLICK ( 7.1f ) ) ) ;
2022-03-13 02:04:24 +11:00
item - > Animation . AnimNumber = LA_STAND_SOLID ;
item - > Animation . FrameNumber = GetFrameNumber ( item , 0 ) ;
item - > Animation . TargetState = LS_JUMP_UP ;
item - > Animation . ActiveState = LS_IDLE ;
2022-02-28 21:02:19 +11:00
lara - > Control . HandStatus = HandStatus : : Busy ;
lara - > Control . TurnRate = 0 ;
2022-02-05 23:13:31 +11:00
ShiftItem ( item , coll ) ;
SnapItemToGrid ( item , coll ) ; // HACK: until fragile ladder code is refactored, we must exactly snap to grid.
2022-03-10 00:29:28 +11:00
lara - > TargetFacingAngle = item - > Position . yRot ;
2022-02-05 23:13:31 +11:00
AnimateLara ( item ) ;
2021-10-16 20:50:16 +11:00
return true ;
}
2022-02-05 23:13:31 +11:00
// Mount ladder.
vaultResult = TestLaraLadderMount ( item , coll ) ;
if ( vaultResult . Success & &
2022-03-16 21:56:25 +11:00
TestLaraClimbIdle ( item , coll ) )
2022-02-05 23:13:31 +11:00
{
2022-03-13 02:04:24 +11:00
item - > Animation . AnimNumber = LA_STAND_SOLID ;
item - > Animation . FrameNumber = GetFrameNumber ( item , 0 ) ;
item - > Animation . TargetState = LS_LADDER_IDLE ;
item - > Animation . ActiveState = LS_IDLE ;
2022-02-28 21:02:19 +11:00
lara - > Control . HandStatus = HandStatus : : Busy ;
lara - > Control . TurnRate = 0 ;
2022-02-05 23:13:31 +11:00
ShiftItem ( item , coll ) ;
SnapItemToGrid ( item , coll ) ; // HACK: until fragile ladder code is refactored, we must exactly snap to grid.
AnimateLara ( item ) ;
return true ;
}
2022-02-10 16:18:15 +11:00
return false ;
2021-10-16 20:50:16 +11:00
}
2022-03-15 20:42:35 +11:00
CrawlVaultTestResult TestLaraCrawlVaultTolerance ( ITEM_INFO * item , CollisionInfo * coll , CrawlVaultTestSetup testSetup )
2021-10-16 20:50:16 +11:00
{
2022-02-09 16:55:46 +11:00
int y = item - > Position . yPos ;
2022-03-14 01:20:51 +11:00
auto probeA = GetCollision ( item , item - > Position . yRot , testSetup . CrossDist , - LARA_HEIGHT_CRAWL ) ; // Crossing.
auto probeB = GetCollision ( item , item - > Position . yRot , testSetup . DestDist , - LARA_HEIGHT_CRAWL ) ; // Approximate destination.
auto probeMiddle = GetCollision ( item ) ;
2022-01-30 15:17:57 +11:00
2022-01-27 14:16:38 +11:00
bool isSlope = testSetup . CheckSlope ? probeB . Position . FloorSlope : false ;
2022-01-26 20:27:52 +11:00
bool isDeath = testSetup . CheckDeath ? probeB . Block - > Flags . Death : false ;
2022-02-07 23:07:40 +11:00
// Discard walls.
if ( probeA . Position . Floor = = NO_HEIGHT | | probeB . Position . Floor = = NO_HEIGHT )
2022-03-15 20:42:35 +11:00
return CrawlVaultTestResult { false } ;
2022-02-07 23:07:40 +11:00
2022-02-08 01:26:59 +11:00
// Check for slope or death sector (if applicable).
2022-02-07 23:07:40 +11:00
if ( isSlope | | isDeath )
2022-03-15 20:42:35 +11:00
return CrawlVaultTestResult { false } ;
2022-02-07 23:07:40 +11:00
// Assess crawl vault feasibility to location ahead.
2022-01-30 14:43:33 +11:00
if ( ( probeA . Position . Floor - y ) < = testSetup . LowerFloorBound & & // Within lower floor bound.
( probeA . Position . Floor - y ) > = testSetup . UpperFloorBound & & // Within upper floor bound.
2022-01-26 20:27:52 +11:00
abs ( probeA . Position . Ceiling - probeA . Position . Floor ) > testSetup . ClampMin & & // Crossing clamp limit.
abs ( probeB . Position . Ceiling - probeB . Position . Floor ) > testSetup . ClampMin & & // Destination clamp limit.
abs ( probeMiddle . Position . Ceiling - probeA . Position . Floor ) > = testSetup . GapMin & & // Gap is optically permissive (going up).
abs ( probeA . Position . Ceiling - probeMiddle . Position . Floor ) > = testSetup . GapMin & & // Gap is optically permissive (going down).
2022-01-30 15:17:57 +11:00
abs ( probeA . Position . Floor - probeB . Position . Floor ) < = testSetup . MaxProbeHeightDif & & // Crossing/destination floor height difference suggests continuous crawl surface.
2022-02-07 23:07:40 +11:00
( probeA . Position . Ceiling - y ) < - testSetup . GapMin ) // Ceiling height is permissive.
2021-10-16 20:50:16 +11:00
{
2022-03-15 20:42:35 +11:00
return CrawlVaultTestResult { true } ;
2021-10-16 20:50:16 +11:00
}
2022-03-15 20:42:35 +11:00
return CrawlVaultTestResult { false } ;
2021-10-16 20:50:16 +11:00
}
2022-03-15 20:42:35 +11:00
CrawlVaultTestResult TestLaraCrawlUpStep ( ITEM_INFO * item , CollisionInfo * coll )
2021-10-16 20:50:16 +11:00
{
2022-01-08 15:43:17 +11:00
// Floor range: [-CLICK(1), -STEPUP_HEIGHT]
2022-01-26 20:27:52 +11:00
CrawlVaultTestSetup testSetup
2022-01-08 15:43:17 +11:00
{
2022-01-30 14:43:33 +11:00
- CLICK ( 1 ) , - STEPUP_HEIGHT ,
2022-01-08 15:43:17 +11:00
LARA_HEIGHT_CRAWL ,
CLICK ( 0.6f ) ,
CLICK ( 1.2f ) ,
CLICK ( 2 ) ,
CLICK ( 1 ) - 1
} ;
2022-01-26 20:27:52 +11:00
return TestLaraCrawlVaultTolerance ( item , coll , testSetup ) ;
2022-01-02 14:21:45 +11:00
}
2021-10-16 20:50:16 +11:00
2022-03-15 20:42:35 +11:00
CrawlVaultTestResult TestLaraCrawlDownStep ( ITEM_INFO * item , CollisionInfo * coll )
2022-01-02 14:21:45 +11:00
{
2022-01-08 15:43:17 +11:00
// Floor range: [STEPUP_HEIGHT, CLICK(1)]
2022-01-26 20:27:52 +11:00
CrawlVaultTestSetup testSetup
2022-01-08 15:43:17 +11:00
{
2022-01-30 14:43:33 +11:00
STEPUP_HEIGHT , CLICK ( 1 ) ,
2022-01-08 15:43:17 +11:00
LARA_HEIGHT_CRAWL ,
CLICK ( 0.6f ) ,
CLICK ( 1.2f ) ,
CLICK ( 2 ) ,
CLICK ( 1 ) - 1
} ;
2022-01-26 20:27:52 +11:00
return TestLaraCrawlVaultTolerance ( item , coll , testSetup ) ;
2021-10-16 20:50:16 +11:00
}
2022-03-15 20:42:35 +11:00
CrawlVaultTestResult TestLaraCrawlExitDownStep ( ITEM_INFO * item , CollisionInfo * coll )
2021-10-16 20:50:16 +11:00
{
2022-01-08 15:43:17 +11:00
// Floor range: [STEPUP_HEIGHT, CLICK(1)]
2022-01-26 20:27:52 +11:00
CrawlVaultTestSetup testSetup
2022-01-08 15:43:17 +11:00
{
2022-01-30 14:43:33 +11:00
STEPUP_HEIGHT , CLICK ( 1 ) ,
2022-01-08 15:43:17 +11:00
LARA_HEIGHT ,
CLICK ( 1.25f ) ,
CLICK ( 1.2f ) ,
CLICK ( 1.5f ) ,
- MAX_HEIGHT ,
2022-02-09 20:38:13 +11:00
false , false
2022-01-08 15:43:17 +11:00
} ;
2022-01-26 20:27:52 +11:00
return TestLaraCrawlVaultTolerance ( item , coll , testSetup ) ;
2021-10-16 20:50:16 +11:00
}
2022-03-15 20:42:35 +11:00
CrawlVaultTestResult TestLaraCrawlExitJump ( ITEM_INFO * item , CollisionInfo * coll )
2021-10-16 20:50:16 +11:00
{
2022-01-30 14:43:33 +11:00
// Floor range: [NO_LOWER_BOUND, STEPUP_HEIGHT)
2022-01-08 15:43:17 +11:00
2022-01-26 20:27:52 +11:00
CrawlVaultTestSetup testSetup
2022-01-08 15:43:17 +11:00
{
2022-01-30 14:43:33 +11:00
NO_LOWER_BOUND , STEPUP_HEIGHT + 1 ,
2022-01-08 15:43:17 +11:00
LARA_HEIGHT ,
CLICK ( 1.25f ) ,
CLICK ( 1.2f ) ,
CLICK ( 1.5f ) ,
2022-01-30 14:43:33 +11:00
NO_LOWER_BOUND ,
2022-02-09 20:38:13 +11:00
false , false
2022-01-08 15:43:17 +11:00
} ;
2022-01-26 20:27:52 +11:00
return TestLaraCrawlVaultTolerance ( item , coll , testSetup ) ;
2021-10-16 20:50:16 +11:00
}
2022-03-14 01:20:51 +11:00
CrawlVaultTestResult TestLaraCrawlVault ( ITEM_INFO * item , CollisionInfo * coll )
2022-02-04 20:23:39 +11:00
{
if ( ! ( TrInput & ( IN_ACTION | IN_JUMP ) ) )
2022-02-07 23:07:40 +11:00
return CrawlVaultTestResult { false } ;
2022-02-04 20:23:39 +11:00
2022-03-15 20:42:35 +11:00
// Crawl vault exit down 1 step.
auto crawlVaultResult = TestLaraCrawlExitDownStep ( item , coll ) ;
if ( crawlVaultResult . Success )
2022-02-04 20:23:39 +11:00
{
2022-03-15 20:42:35 +11:00
if ( TrInput & IN_CROUCH & & TestLaraCrawlDownStep ( item , coll ) . Success )
crawlVaultResult . TargetState = LS_CRAWL_STEP_DOWN ;
2022-02-04 20:23:39 +11:00
else [[likely]]
2022-03-15 20:42:35 +11:00
crawlVaultResult . TargetState = LS_CRAWL_EXIT_STEP_DOWN ;
2022-03-17 01:19:21 +11:00
crawlVaultResult . Success = HasChange ( item , crawlVaultResult . TargetState ) ;
2022-03-15 20:42:35 +11:00
return crawlVaultResult ;
2022-02-04 20:23:39 +11:00
}
2022-03-15 20:42:35 +11:00
// Crawl vault exit jump.
crawlVaultResult = TestLaraCrawlExitJump ( item , coll ) ;
if ( crawlVaultResult . Success )
2022-02-04 20:23:39 +11:00
{
if ( TrInput & IN_WALK )
2022-03-15 20:42:35 +11:00
crawlVaultResult . TargetState = LS_CRAWL_EXIT_FLIP ;
2022-02-04 20:23:39 +11:00
else [[likely]]
2022-03-15 20:42:35 +11:00
crawlVaultResult . TargetState = LS_CRAWL_EXIT_JUMP ;
2022-03-17 01:19:21 +11:00
crawlVaultResult . Success = HasChange ( item , crawlVaultResult . TargetState ) ;
2022-03-15 20:42:35 +11:00
return crawlVaultResult ;
2022-02-04 20:23:39 +11:00
}
2022-03-15 20:42:35 +11:00
// Crawl vault up 1 step.
crawlVaultResult = TestLaraCrawlUpStep ( item , coll ) ;
if ( crawlVaultResult . Success )
{
crawlVaultResult . TargetState = LS_CRAWL_STEP_UP ;
2022-03-17 01:19:21 +11:00
crawlVaultResult . Success = HasChange ( item , crawlVaultResult . TargetState ) ;
2022-03-15 20:42:35 +11:00
return crawlVaultResult ;
}
2022-02-04 20:23:39 +11:00
2022-03-15 20:42:35 +11:00
// Crawl vault down 1 step.
crawlVaultResult = TestLaraCrawlDownStep ( item , coll ) ;
if ( crawlVaultResult . Success )
{
crawlVaultResult . TargetState = LS_CRAWL_STEP_DOWN ;
2022-03-17 01:19:21 +11:00
crawlVaultResult . Success = HasChange ( item , crawlVaultResult . TargetState ) ;
2022-03-15 20:42:35 +11:00
return crawlVaultResult ;
}
2022-02-04 20:23:39 +11:00
2022-02-07 23:07:40 +11:00
return CrawlVaultTestResult { false } ;
2022-02-04 20:23:39 +11:00
}
2022-03-15 20:42:35 +11:00
bool TestLaraCrawlToHang ( ITEM_INFO * item , CollisionInfo * coll )
{
int y = item - > Position . yPos ;
2022-03-19 22:55:23 +11:00
int distance = CLICK ( 1.2f ) ;
auto probe = GetCollision ( item , item - > Position . yRot + ANGLE ( 180.0f ) , distance , - LARA_HEIGHT_CRAWL ) ;
2022-03-15 20:42:35 +11:00
bool objectCollided = TestLaraObjectCollision ( item , item - > Position . yRot + ANGLE ( 180.0f ) , CLICK ( 1.2f ) , - LARA_HEIGHT_CRAWL ) ;
if ( ! objectCollided & & // No obstruction.
( probe . Position . Floor - y ) > = LARA_HEIGHT_STRETCH & & // Highest floor bound.
( probe . Position . Ceiling - y ) < = - CLICK ( 0.75f ) & & // Gap is optically permissive.
probe . Position . Floor ! = NO_HEIGHT )
{
return true ;
}
return false ;
}
2022-03-14 01:20:51 +11:00
bool TestLaraJumpTolerance ( ITEM_INFO * item , CollisionInfo * coll , JumpTestSetup testSetup )
2022-01-12 18:21:52 +11:00
{
2022-02-28 21:02:19 +11:00
auto * lara = GetLaraInfo ( item ) ;
2022-01-12 18:21:52 +11:00
2022-02-09 16:55:46 +11:00
int y = item - > Position . yPos ;
2022-03-14 01:20:51 +11:00
auto probe = GetCollision ( item , testSetup . Angle , testSetup . Distance , - coll - > Setup . Height ) ;
2022-01-30 15:17:57 +11:00
2022-02-07 23:07:40 +11:00
bool isSwamp = TestEnvironment ( ENV_FLAG_SWAMP , item ) ;
2022-02-28 21:02:19 +11:00
bool isWading = testSetup . CheckWadeStatus ? ( lara - > Control . WaterStatus = = WaterStatus : : Wade ) : false ;
2022-01-19 22:45:38 +11:00
2022-02-07 23:07:40 +11:00
// Discard walls.
if ( probe . Position . Floor = = NO_HEIGHT )
return false ;
2022-02-08 01:26:59 +11:00
// Check for swamp or wade status (if applicable).
2022-02-07 23:07:40 +11:00
if ( isSwamp | | isWading )
return false ;
// Assess jump feasibility toward location ahead.
2022-02-25 14:28:28 +11:00
if ( ! TestLaraFacingCorner ( item , testSetup . Angle , testSetup . Distance ) & & // Avoid jumping through corners.
2022-02-02 21:59:34 +11:00
( probe . Position . Floor - y ) > = - STEPUP_HEIGHT & & // Within highest floor bound.
( ( probe . Position . Ceiling - y ) < - ( coll - > Setup . Height + ( LARA_HEADROOM * 0.8f ) ) | | // Within lowest ceiling bound...
2022-01-19 22:45:38 +11:00
( ( probe . Position . Ceiling - y ) < - coll - > Setup . Height & & // OR ceiling is level with Lara's head
2022-02-07 23:07:40 +11:00
( probe . Position . Floor - y ) > = CLICK ( 0.5f ) ) ) ) // AND there is a drop below.
2022-01-12 18:21:52 +11:00
{
return true ;
}
return false ;
}
2022-03-14 01:20:51 +11:00
bool TestLaraRunJumpForward ( ITEM_INFO * item , CollisionInfo * coll )
2022-01-12 18:21:52 +11:00
{
2022-01-27 14:16:38 +11:00
JumpTestSetup testSetup
2022-01-12 18:21:52 +11:00
{
2022-02-09 16:55:46 +11:00
item - > Position . yRot ,
2022-01-12 18:21:52 +11:00
CLICK ( 1.5f )
} ;
2022-01-27 14:16:38 +11:00
return TestLaraJumpTolerance ( item , coll , testSetup ) ;
2022-01-12 18:21:52 +11:00
}
2022-03-14 01:20:51 +11:00
bool TestLaraJumpForward ( ITEM_INFO * item , CollisionInfo * coll )
2022-01-12 18:21:52 +11:00
{
2022-01-27 14:16:38 +11:00
JumpTestSetup testSetup
2022-01-12 18:21:52 +11:00
{
2022-02-09 16:55:46 +11:00
item - > Position . yRot
2022-01-12 18:21:52 +11:00
} ;
2022-01-27 14:16:38 +11:00
return TestLaraJumpTolerance ( item , coll , testSetup ) ;
2022-01-12 18:21:52 +11:00
}
2022-03-14 01:20:51 +11:00
bool TestLaraJumpBack ( ITEM_INFO * item , CollisionInfo * coll )
2022-01-12 18:21:52 +11:00
{
2022-01-27 14:16:38 +11:00
JumpTestSetup testSetup
2022-01-12 18:21:52 +11:00
{
2022-02-09 16:55:46 +11:00
item - > Position . yRot + ANGLE ( 180.0f )
2022-01-12 18:21:52 +11:00
} ;
2022-01-27 14:16:38 +11:00
return TestLaraJumpTolerance ( item , coll , testSetup ) ;
2022-01-12 18:21:52 +11:00
}
2022-03-14 01:20:51 +11:00
bool TestLaraJumpLeft ( ITEM_INFO * item , CollisionInfo * coll )
2022-01-12 18:21:52 +11:00
{
2022-01-27 14:16:38 +11:00
JumpTestSetup testSetup
2022-01-12 18:21:52 +11:00
{
2022-02-09 16:55:46 +11:00
item - > Position . yRot - ANGLE ( 90.0f )
2022-01-12 18:21:52 +11:00
} ;
2022-01-27 14:16:38 +11:00
return TestLaraJumpTolerance ( item , coll , testSetup ) ;
2022-01-12 18:21:52 +11:00
}
2022-03-14 01:20:51 +11:00
bool TestLaraJumpRight ( ITEM_INFO * item , CollisionInfo * coll )
2022-01-12 18:21:52 +11:00
{
2022-01-27 14:16:38 +11:00
JumpTestSetup testSetup
2022-01-12 18:21:52 +11:00
{
2022-02-09 16:55:46 +11:00
item - > Position . yRot + ANGLE ( 90.0f )
2022-01-12 18:21:52 +11:00
} ;
2022-01-27 14:16:38 +11:00
return TestLaraJumpTolerance ( item , coll , testSetup ) ;
2022-01-12 18:21:52 +11:00
}
2022-03-14 01:20:51 +11:00
bool TestLaraJumpUp ( ITEM_INFO * item , CollisionInfo * coll )
2022-01-12 18:21:52 +11:00
{
2022-01-27 14:16:38 +11:00
JumpTestSetup testSetup
2022-01-12 18:21:52 +11:00
{
0 ,
0 ,
false
} ;
2022-01-27 14:16:38 +11:00
return TestLaraJumpTolerance ( item , coll , testSetup ) ;
2022-01-12 18:21:52 +11:00
}
2022-03-14 01:20:51 +11:00
bool TestLaraSlideJump ( ITEM_INFO * item , CollisionInfo * coll )
2022-03-09 13:03:21 +11:00
{
// TODO: Broken on diagonal slides?
if ( g_GameFlow - > Animations . HasSlideExtended )
{
2022-03-14 01:20:51 +11:00
auto probe = GetCollision ( item ) ;
2022-03-09 13:03:21 +11:00
short direction = GetLaraSlideDirection ( item , coll ) ;
short steepness = GetSurfaceSteepnessAngle ( probe . FloorTilt . x , probe . FloorTilt . y ) ;
return ( abs ( ( short ) ( coll - > Setup . ForwardAngle - direction ) ) < = abs ( steepness ) ) ;
}
return true ;
}
2022-03-14 01:20:51 +11:00
bool TestLaraCrawlspaceDive ( ITEM_INFO * item , CollisionInfo * coll )
2022-02-25 21:02:08 +11:00
{
2022-03-14 01:20:51 +11:00
auto probe = GetCollision ( item , coll - > Setup . ForwardAngle , coll - > Setup . Radius , - coll - > Setup . Height ) ;
2022-03-01 21:17:40 +11:00
if ( abs ( probe . Position . Ceiling - probe . Position . Floor ) < LARA_HEIGHT | |
TestLaraKeepLow ( item , coll ) )
{
return true ;
}
2022-02-25 21:02:08 +11:00
2022-03-01 21:17:40 +11:00
return false ;
2022-02-25 21:02:08 +11:00
}
2022-03-14 01:20:51 +11:00
bool TestLaraTightropeDismount ( ITEM_INFO * item , CollisionInfo * coll )
2022-03-02 20:50:29 +11:00
{
auto * lara = GetLaraInfo ( item ) ;
2022-03-14 01:20:51 +11:00
auto probe = GetCollision ( item ) ;
2022-03-02 20:50:29 +11:00
if ( probe . Position . Floor = = item - > Position . yPos & &
2022-03-09 17:04:19 +11:00
lara - > Control . Tightrope . CanDismount )
2022-03-02 20:50:29 +11:00
{
return true ;
}
return false ;
}
2022-03-14 01:20:51 +11:00
bool TestLaraPoleCollision ( ITEM_INFO * item , CollisionInfo * coll , bool up , float offset )
2021-12-02 13:07:00 +11:00
{
static constexpr auto poleProbeCollRadius = 16.0f ;
bool atLeastOnePoleCollided = false ;
2022-02-25 14:28:28 +11:00
if ( GetCollidedObjects ( item , SECTOR ( 1 ) , true , CollidedItems , nullptr , 0 ) & & CollidedItems [ 0 ] )
2021-12-02 13:07:00 +11:00
{
2022-02-09 16:55:46 +11:00
auto laraBox = TO_DX_BBOX ( item - > Position , GetBoundsAccurate ( item ) ) ;
2021-12-02 13:07:00 +11:00
// 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 + + ;
2022-02-09 16:55:46 +11:00
if ( obj - > ObjectNumber ! = ID_POLEROPE )
2021-12-02 13:07:00 +11:00
continue ;
2022-02-09 16:55:46 +11:00
auto poleBox = TO_DX_BBOX ( obj - > Position , GetBoundsAccurate ( obj ) ) ;
2021-12-02 13:07:00 +11:00
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 ;
}
2022-03-14 01:20:51 +11:00
bool TestLaraPoleUp ( ITEM_INFO * item , CollisionInfo * coll )
2021-11-26 13:58:35 +11:00
{
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-12-12 21:11:27 +11:00
return ( coll - > Middle . Ceiling < - CLICK ( 1 ) ) ;
2021-11-26 13:58:35 +11:00
}
2022-03-14 01:20:51 +11:00
bool TestLaraPoleDown ( ITEM_INFO * item , CollisionInfo * coll )
2021-11-26 13:58:35 +11:00
{
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 ) ;
}