2021-09-27 18:18:03 +10:00
# include "framework.h"
2021-12-24 03:32:19 +03:00
# include "Game/Lara/lara_helpers.h"
2021-12-22 16:23:57 +03:00
# include "Game/collision/collide_room.h"
# include "Game/control/control.h"
# include "Game/items.h"
# include "Game/Lara/lara.h"
2022-02-14 17:05:52 +11:00
# include "Game/Lara/lara_collide.h"
2022-02-08 01:26:59 +11:00
# include "Game/Lara/lara_fire.h"
2021-12-22 16:23:57 +03:00
# include "Game/Lara/lara_tests.h"
# include "Scripting/GameFlowScript.h"
2021-12-24 03:32:19 +03:00
# include "Specific/input.h"
# include "Specific/level.h"
# include "Specific/setup.h"
2021-10-09 14:39:06 +11:00
2022-02-22 21:09:12 +11:00
# include "Objects/TR2/Vehicles/skidoo.h"
2022-02-08 01:26:59 +11:00
# include "Objects/TR3/Vehicles/biggun.h"
# include "Objects/TR3/Vehicles/kayak.h"
# include "Objects/TR3/Vehicles/minecart.h"
# include "Objects/TR3/Vehicles/quad.h"
# include "Objects/TR3/Vehicles/upv.h"
# include "Objects/TR4/Vehicles/jeep.h"
# include "Objects/TR4/Vehicles/motorbike.h"
2021-10-18 20:15:53 +11:00
// -----------------------------
// HELPER FUNCTIONS
// For State Control & Collision
// -----------------------------
2021-12-23 18:41:37 +11:00
// TODO: Make lean rate proportional to the turn rate, allowing for nicer aesthetics with future analog stick input.
2022-01-15 22:48:35 +11:00
void DoLaraLean ( ITEM_INFO * item , COLL_INFO * coll , short maxAngle , short rate )
2021-12-23 18:41:37 +11:00
{
2022-02-09 13:20:57 +11:00
if ( ! item - > Velocity )
2021-12-23 18:41:37 +11:00
return ;
int sign = copysign ( 1 , maxAngle ) ;
2022-02-19 13:01:19 +11:00
rate = abs ( rate ) ;
2021-12-23 18:41:37 +11:00
if ( coll - > CollisionType = = CT_LEFT | | coll - > CollisionType = = CT_RIGHT )
2022-02-12 14:56:28 +11:00
item - > Position . zRot + = std : : min < short > ( rate , abs ( ( maxAngle * 3 ) / 5 - item - > Position . zRot ) / 3 ) * sign ;
2021-12-23 18:41:37 +11:00
else
2022-02-12 14:56:28 +11:00
item - > Position . zRot + = std : : min < short > ( rate , abs ( maxAngle - item - > Position . zRot ) / 3 ) * sign ;
}
void ApproachLaraTargetAngle ( ITEM_INFO * item , short targetAngle , float rate )
{
2022-02-28 21:02:19 +11:00
auto * lara = GetLaraInfo ( item ) ;
2022-02-14 17:05:52 +11:00
if ( ! rate )
2022-02-24 14:22:30 +11:00
{
TENLog ( std : : string ( " ApproachLaraTargetAngle() attempted division by zero! " ) , LogLevel : : Warning ) ;
2022-02-14 17:05:52 +11:00
return ;
2022-02-24 14:22:30 +11:00
}
2022-02-12 14:56:28 +11:00
2022-02-14 17:05:52 +11:00
rate = abs ( rate ) ;
2022-02-12 14:56:28 +11:00
if ( abs ( ( short ) ( targetAngle - item - > Position . yRot ) ) > ANGLE ( 0.1f ) )
item - > Position . yRot + = ( short ) ( targetAngle - item - > Position . yRot ) / rate ;
else
item - > Position . yRot = targetAngle ;
2021-12-23 18:41:37 +11:00
}
2022-02-07 17:06:45 +11:00
void EaseOutLaraHeight ( ITEM_INFO * item , int height )
2021-10-09 14:39:06 +11:00
{
2022-02-07 17:06:45 +11:00
if ( height = = NO_HEIGHT )
2022-02-04 19:06:59 +11:00
return ;
2022-02-07 17:06:45 +11:00
// Translate Lara to new height.
// TODO: This approach may cause undesirable artefacts where an object pushes Lara rapidly up/down a slope or a platform rapidly ascends/descends.
2022-02-13 15:58:12 +11:00
static constexpr int rate = 50 ;
2022-02-21 20:27:30 +11:00
int threshold = std : : max ( abs ( item - > Velocity ) / 3 * 2 , CLICK ( 1 ) / 16 ) ;
2022-02-07 17:06:45 +11:00
int sign = std : : copysign ( 1 , height ) ;
if ( TestEnvironment ( ENV_FLAG_SWAMP , item ) & & height > 0 )
2022-02-09 16:55:46 +11:00
item - > Position . yPos + = SWAMP_GRAVITY ;
2022-02-07 17:06:45 +11:00
else if ( abs ( height ) > ( STEPUP_HEIGHT / 2 ) ) // Outer range.
2022-02-09 16:55:46 +11:00
item - > Position . yPos + = rate * sign ;
2022-02-07 17:06:45 +11:00
else if ( abs ( height ) < = ( STEPUP_HEIGHT / 2 ) & & // Inner range.
abs ( height ) > = threshold )
{
2022-02-09 16:55:46 +11:00
item - > Position . yPos + = std : : max < int > ( abs ( height / 2.75 ) , threshold ) * sign ;
2022-02-07 17:06:45 +11:00
}
else
2022-02-09 16:55:46 +11:00
item - > Position . yPos + = height ;
2022-02-07 17:06:45 +11:00
}
// TODO: Some states can't make the most of this function due to missing step up/down animations.
// Try implementing leg IK as a substitute to make step animations obsolete. @Sezz 2021.10.09
void DoLaraStep ( ITEM_INFO * item , COLL_INFO * coll )
{
2022-01-25 18:02:22 +11:00
if ( ! TestEnvironment ( ENV_FLAG_SWAMP , item ) )
2021-10-09 14:39:06 +11:00
{
2021-12-04 14:01:41 +11:00
if ( TestLaraStepUp ( item , coll ) )
2021-10-10 14:03:38 +11:00
{
2022-02-09 16:55:46 +11:00
item - > TargetState = LS_STEP_UP ;
if ( GetChange ( item , & g_Level . Anims [ item - > AnimNumber ] ) )
2021-12-04 14:01:41 +11:00
{
2022-02-09 16:55:46 +11:00
item - > Position . yPos + = coll - > Middle . Floor ;
2021-12-04 14:01:41 +11:00
return ;
}
2021-10-10 14:03:38 +11:00
}
2021-12-04 14:01:41 +11:00
else if ( TestLaraStepDown ( item , coll ) )
2021-10-10 14:03:38 +11:00
{
2022-02-09 16:55:46 +11:00
item - > TargetState = LS_STEP_DOWN ;
if ( GetChange ( item , & g_Level . Anims [ item - > AnimNumber ] ) )
2021-12-04 14:01:41 +11:00
{
2022-02-09 16:55:46 +11:00
item - > Position . yPos + = coll - > Middle . Floor ;
2021-12-04 14:01:41 +11:00
return ;
}
2021-10-10 14:03:38 +11:00
}
2021-10-09 14:39:06 +11:00
}
2022-02-07 17:06:45 +11:00
EaseOutLaraHeight ( item , coll - > Middle . Floor ) ;
2021-10-09 14:39:06 +11:00
}
2022-01-16 13:56:39 +11:00
void DoLaraMonkeyStep ( ITEM_INFO * item , COLL_INFO * coll )
{
2022-02-07 17:06:45 +11:00
EaseOutLaraHeight ( item , coll - > Middle . Ceiling ) ;
2022-01-16 13:56:39 +11:00
}
2022-01-03 17:57:57 +11:00
// TODO: Doesn't always work on bridges.
2021-10-18 15:22:38 +11:00
void DoLaraCrawlToHangSnap ( ITEM_INFO * item , COLL_INFO * coll )
{
2022-02-09 16:55:46 +11:00
coll - > Setup . ForwardAngle = item - > Position . yRot + ANGLE ( 180.0f ) ;
2021-11-03 21:44:48 +11:00
GetCollisionInfo ( coll , item ) ;
SnapItemToLedge ( item , coll ) ;
2022-02-09 16:55:46 +11:00
MoveItem ( item , item - > Position . yRot , - LARA_RAD_CRAWL ) ;
item - > Position . yRot + = ANGLE ( 180.0f ) ;
2021-11-03 21:44:48 +11:00
LaraResetGravityStatus ( item , coll ) ;
2021-10-18 15:22:38 +11:00
}
2021-11-27 20:35:16 +11:00
void DoLaraCrawlFlex ( ITEM_INFO * item , COLL_INFO * coll , short maxAngle , short rate )
{
2022-02-28 21:02:19 +11:00
auto * lara = GetLaraInfo ( item ) ;
2021-11-27 20:35:16 +11:00
2022-02-09 13:20:57 +11:00
if ( ! item - > Velocity )
2021-12-14 14:35:42 +11:00
return ;
2021-11-27 20:35:16 +11:00
int sign = copysign ( 1 , maxAngle ) ;
rate = copysign ( rate , maxAngle ) ;
2022-02-28 21:02:19 +11:00
lara - > ExtraTorsoRot . zRot + = std : : min ( abs ( rate ) , abs ( maxAngle - lara - > ExtraTorsoRot . zRot ) / 6 ) * sign ;
2021-11-27 20:35:16 +11:00
if ( ! ( TrInput & IN_LOOK ) & &
2022-02-09 16:55:46 +11:00
item - > ActiveState ! = LS_CRAWL_BACK )
2021-11-27 20:35:16 +11:00
{
2022-02-28 21:02:19 +11:00
lara - > ExtraHeadRot . zRot = lara - > ExtraTorsoRot . zRot / 2 ;
lara - > ExtraHeadRot . yRot = lara - > ExtraHeadRot . zRot ;
2021-11-27 20:35:16 +11:00
}
}
2022-01-22 22:36:29 +11:00
void DoLaraFallDamage ( ITEM_INFO * item )
{
2022-03-05 15:20:20 +11:00
if ( item - > VerticalVelocity > = LARA_DAMAGE_VELOCITY )
2022-01-22 22:36:29 +11:00
{
2022-03-05 15:20:20 +11:00
if ( item - > VerticalVelocity > = LARA_DEATH_VELOCITY )
2022-02-09 16:55:46 +11:00
item - > HitPoints = 0 ;
2022-03-05 01:51:13 +11:00
else [[likely]]
{
2022-03-05 15:20:20 +11:00
int base = item - > VerticalVelocity - ( LARA_DAMAGE_VELOCITY - 1 ) ;
2022-03-05 01:51:13 +11:00
item - > HitPoints - = LARA_HEALTH_MAX * ( pow ( base , 2 ) / 196 ) ;
}
2022-01-22 22:36:29 +11:00
}
}
2022-02-21 20:27:30 +11:00
void DoLaraTightropeBalance ( ITEM_INFO * item )
{
2022-02-28 21:02:19 +11:00
auto * lara = GetLaraInfo ( item ) ;
const int factor = ( ( lara - > Control . TightropeControl . TimeOnTightrope > > 7 ) & 0xFF ) * 128 ;
2022-02-21 20:27:30 +11:00
if ( TrInput & IN_LEFT )
2022-02-28 21:02:19 +11:00
lara - > Control . TightropeControl . Balance + = ANGLE ( 1.4f ) ;
2022-02-21 20:27:30 +11:00
if ( TrInput & IN_RIGHT )
2022-02-28 21:02:19 +11:00
lara - > Control . TightropeControl . Balance - = ANGLE ( 1.4f ) ;
2022-02-21 20:27:30 +11:00
2022-02-28 21:02:19 +11:00
if ( lara - > Control . TightropeControl . Balance < 0 )
2022-02-21 20:27:30 +11:00
{
2022-02-28 21:02:19 +11:00
lara - > Control . TightropeControl . Balance - = factor ;
if ( lara - > Control . TightropeControl . Balance < = - ANGLE ( 45.0f ) )
lara - > Control . TightropeControl . Balance = ANGLE ( 45.0f ) ;
2022-02-21 20:27:30 +11:00
}
2022-02-28 21:02:19 +11:00
else if ( lara - > Control . TightropeControl . Balance > 0 )
2022-02-21 20:27:30 +11:00
{
2022-02-28 21:02:19 +11:00
lara - > Control . TightropeControl . Balance + = factor ;
if ( lara - > Control . TightropeControl . Balance > = ANGLE ( 45.0f ) )
lara - > Control . TightropeControl . Balance = ANGLE ( 45.0f ) ;
2022-02-21 20:27:30 +11:00
}
else
2022-02-28 21:02:19 +11:00
lara - > Control . TightropeControl . Balance = GetRandomControl ( ) & 1 ? - 1 : 1 ;
2022-02-21 20:27:30 +11:00
}
void DoLaraTightropeLean ( ITEM_INFO * item )
{
2022-02-28 21:02:19 +11:00
auto * lara = GetLaraInfo ( item ) ;
2022-02-21 20:27:30 +11:00
2022-02-28 21:02:19 +11:00
item - > Position . zRot = lara - > Control . TightropeControl . Balance / 4 ;
lara - > ExtraTorsoRot . zRot = - lara - > Control . TightropeControl . Balance ;
2022-02-21 20:27:30 +11:00
}
void DoLaraTightropeBalanceRegen ( ITEM_INFO * item )
{
2022-02-28 21:02:19 +11:00
auto * lara = GetLaraInfo ( item ) ;
2022-02-21 20:27:30 +11:00
2022-02-28 21:02:19 +11:00
if ( lara - > Control . TightropeControl . TimeOnTightrope < = 32 )
lara - > Control . TightropeControl . TimeOnTightrope = 0 ;
2022-02-21 20:27:30 +11:00
else
2022-02-28 21:02:19 +11:00
lara - > Control . TightropeControl . TimeOnTightrope - = 32 ;
2022-02-21 20:27:30 +11:00
2022-02-28 21:02:19 +11:00
if ( lara - > Control . TightropeControl . Balance > 0 )
2022-02-21 20:27:30 +11:00
{
2022-02-28 21:02:19 +11:00
if ( lara - > Control . TightropeControl . Balance < = ANGLE ( 0.75f ) )
lara - > Control . TightropeControl . Balance = 0 ;
2022-02-21 20:27:30 +11:00
else
2022-02-28 21:02:19 +11:00
lara - > Control . TightropeControl . Balance - = ANGLE ( 0.75f ) ;
2022-02-21 20:27:30 +11:00
}
2022-02-28 21:02:19 +11:00
if ( lara - > Control . TightropeControl . Balance < 0 )
2022-02-21 20:27:30 +11:00
{
2022-02-28 21:02:19 +11:00
if ( lara - > Control . TightropeControl . Balance > = - ANGLE ( 0.75f ) )
lara - > Control . TightropeControl . Balance = 0 ;
2022-02-21 20:27:30 +11:00
else
2022-02-28 21:02:19 +11:00
lara - > Control . TightropeControl . Balance + = ANGLE ( 0.75f ) ;
2022-02-21 20:27:30 +11:00
}
}
2022-02-12 00:25:05 +11:00
LaraInfo * & GetLaraInfo ( ITEM_INFO * item )
{
2022-03-05 15:20:20 +11:00
if ( item - > ObjectNumber = = ID_LARA )
return ( LaraInfo * & ) item - > Data ;
TENLog ( std : : string ( " Attempted to fetch LaraInfo data from entity with object ID " ) + std : : to_string ( item - > ObjectNumber ) , LogLevel : : Warning ) ;
2022-02-12 00:25:05 +11:00
2022-03-05 15:20:20 +11:00
auto * firstLaraItem = FindItem ( ID_LARA ) ;
return ( LaraInfo * & ) firstLaraItem - > Data ;
2022-02-12 00:25:05 +11:00
}
2022-01-23 18:16:29 +11:00
short GetLaraSlideDirection ( ITEM_INFO * item , COLL_INFO * coll )
2021-12-27 21:29:21 +11:00
{
2022-02-09 16:55:46 +11:00
short direction = item - > Position . yRot ;
2022-01-04 01:39:02 +11:00
2022-03-04 18:03:04 +11:00
// Ground is flat.
if ( ! coll - > FloorTiltX & & ! coll - > FloorTiltZ )
return direction ;
2022-03-04 21:30:09 +11:00
float normalisedTiltX = coll - > FloorTiltX ? ( coll - > FloorTiltX / abs ( coll - > FloorTiltX ) ) : 0 ;
float normalisedTiltZ = coll - > FloorTiltZ ? ( coll - > FloorTiltZ / abs ( coll - > FloorTiltZ ) ) : 0 ;
2022-03-04 15:14:38 +11:00
2022-03-05 01:51:13 +11:00
short xAngle = FROM_RAD ( asin ( - normalisedTiltX ) ) ;
short zAngle = FROM_RAD ( acos ( - normalisedTiltZ ) ) ;
2022-03-04 15:14:38 +11:00
2022-03-05 01:51:13 +11:00
// Find true slope direction.
2022-03-04 21:30:09 +11:00
direction = ( ( xAngle * abs ( coll - > FloorTiltX ) ) + ( zAngle * abs ( coll - > FloorTiltZ ) ) ) / ( abs ( coll - > FloorTiltX ) + abs ( coll - > FloorTiltZ ) ) ;
2022-03-04 15:14:38 +11:00
2022-03-04 21:30:09 +11:00
// Find nearest cardinal slope direction.
if ( ! g_GameFlow - > Animations . HasSlideExtended )
direction = GetQuadrant ( direction ) * ANGLE ( 90.0f ) ;
2022-01-22 21:08:30 +11:00
2022-01-23 18:16:29 +11:00
return direction ;
2021-12-27 21:29:21 +11:00
}
2021-12-20 00:11:04 +11:00
void SetLaraJumpDirection ( ITEM_INFO * item , COLL_INFO * coll )
{
2022-02-28 21:02:19 +11:00
auto * lara = GetLaraInfo ( item ) ;
2021-12-20 00:11:04 +11:00
if ( TrInput & IN_FORWARD & &
2022-01-02 15:54:43 +11:00
TestLaraJumpForward ( item , coll ) )
2021-12-20 00:11:04 +11:00
{
2022-02-28 21:02:19 +11:00
lara - > Control . JumpDirection = JumpDirection : : Forward ;
2021-12-20 00:11:04 +11:00
}
else if ( TrInput & IN_BACK & &
2022-01-02 15:54:43 +11:00
TestLaraJumpBack ( item , coll ) )
2021-12-20 00:11:04 +11:00
{
2022-02-28 21:02:19 +11:00
lara - > Control . JumpDirection = JumpDirection : : Back ;
2021-12-20 00:11:04 +11:00
}
else if ( TrInput & IN_LEFT & &
2022-01-02 15:54:43 +11:00
TestLaraJumpLeft ( item , coll ) )
2021-12-20 00:11:04 +11:00
{
2022-02-28 21:02:19 +11:00
lara - > Control . JumpDirection = JumpDirection : : Left ;
2021-12-20 00:11:04 +11:00
}
else if ( TrInput & IN_RIGHT & &
2022-01-02 15:54:43 +11:00
TestLaraJumpRight ( item , coll ) )
2021-12-20 00:11:04 +11:00
{
2022-02-28 21:02:19 +11:00
lara - > Control . JumpDirection = JumpDirection : : Right ;
2021-12-20 00:11:04 +11:00
}
2022-01-02 15:54:43 +11:00
else if ( TestLaraJumpUp ( item , coll ) ) [[likely]]
2022-02-28 21:02:19 +11:00
lara - > Control . JumpDirection = JumpDirection : : Up ;
2021-12-20 00:11:04 +11:00
else
2022-02-28 21:02:19 +11:00
lara - > Control . JumpDirection = JumpDirection : : None ;
2021-12-20 00:11:04 +11:00
}
2022-01-22 00:22:24 +11:00
// TODO: Add a timeout? Imagine a small, sad rain cloud with the properties of a ceiling following Lara overhead.
2022-02-10 01:38:32 +11:00
// RunJumpQueued will never reset, and when the sad cloud flies away after an indefinite amount of time, Lara will jump. @Sezz 2022.01.22
2022-01-22 00:22:24 +11:00
void SetLaraRunJumpQueue ( ITEM_INFO * item , COLL_INFO * coll )
2021-12-19 19:12:35 +11:00
{
2022-02-28 21:02:19 +11:00
auto * lara = GetLaraInfo ( item ) ;
2021-12-19 19:12:35 +11:00
2022-02-09 16:55:46 +11:00
int y = item - > Position . yPos ;
2022-03-01 14:21:27 +11:00
int dist = SECTOR ( 1 ) ;
2022-02-09 16:55:46 +11:00
auto probe = GetCollisionResult ( item , item - > Position . yRot , dist , - coll - > Setup . Height ) ;
2021-12-19 19:12:35 +11:00
2022-01-22 00:22:24 +11:00
if ( ( TestLaraRunJumpForward ( item , coll ) | | // Area close ahead is permissive...
2022-02-02 21:59:34 +11:00
( probe . Position . Ceiling - y ) < - ( coll - > Setup . Height + ( LARA_HEADROOM * 0.8f ) ) | | // OR ceiling height is permissive far ahead
( probe . Position . Floor - y ) > = CLICK ( 0.5f ) ) & & // OR there is a drop below far ahead.
2022-01-04 16:25:12 +11:00
probe . Position . Floor ! = NO_HEIGHT )
2022-01-12 19:04:29 +11:00
{
2022-02-28 21:02:19 +11:00
lara - > Control . RunJumpQueued = IsRunJumpQueueableState ( ( LaraState ) item - > TargetState ) ;
2022-01-12 19:04:29 +11:00
}
2021-12-19 19:12:35 +11:00
else
2022-02-28 21:02:19 +11:00
lara - > Control . RunJumpQueued = false ;
2021-12-19 19:12:35 +11:00
}
2022-02-05 23:13:31 +11:00
void SetLaraVault ( ITEM_INFO * item , COLL_INFO * coll , VaultTestResult vaultResult )
{
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
lara - > ProjectedFloorHeight = vaultResult . Height ;
lara - > Control . HandStatus = vaultResult . SetBusyHands ? HandStatus : : Busy : lara - > Control . HandStatus ;
lara - > Control . TurnRate = 0 ;
2022-02-06 14:15:10 +11:00
if ( vaultResult . SnapToLedge )
2022-02-28 00:40:18 +11:00
{
2022-03-04 18:03:04 +11:00
SnapItemToLedge ( item , coll , 0.2f , false ) ;
lara - > TargetAngle = coll - > NearestLedgeAngle ;
2022-02-28 00:40:18 +11:00
}
2022-02-27 23:51:00 +11:00
if ( vaultResult . SetJumpVelocity )
2022-02-28 21:02:19 +11:00
lara - > Control . CalculatedJumpVelocity = - 3 - sqrt ( - 9600 - 12 * std : : max < int > ( lara - > ProjectedFloorHeight - item - > Position . yPos , - CLICK ( 7.5f ) ) ) ;
2022-02-05 23:13:31 +11:00
}
2022-01-22 21:08:30 +11:00
void SetLaraLand ( ITEM_INFO * item , COLL_INFO * coll )
{
2022-02-09 13:20:57 +11:00
item - > Velocity = 0 ;
item - > VerticalVelocity = 0 ;
2022-03-04 21:30:09 +11:00
//item->Airborne = false; // TODO: Removing this works around an unusual landing bug Core had worked around in an obscure way. I hope to find a proper solution. @Sezz 2022.02.18
2022-01-22 21:08:30 +11:00
LaraSnapToHeight ( item , coll ) ;
}
2021-12-10 12:30:23 +11:00
void SetLaraFallState ( ITEM_INFO * item )
{
SetAnimation ( item , LA_FALL_START ) ;
2022-02-09 13:20:57 +11:00
item - > VerticalVelocity = 0 ;
item - > Airborne = true ;
2021-12-10 12:30:23 +11:00
}
void SetLaraFallBackState ( ITEM_INFO * item )
{
SetAnimation ( item , LA_FALL_BACK ) ;
2022-02-09 13:20:57 +11:00
item - > VerticalVelocity = 0 ;
item - > Airborne = true ;
2021-12-10 12:30:23 +11:00
}
2022-01-12 17:31:03 +11:00
void SetLaraMonkeyFallState ( ITEM_INFO * item )
{
2022-02-14 17:05:52 +11:00
// HACK: Disallow release during 180 turn action.
2022-02-09 16:55:46 +11:00
if ( item - > ActiveState = = LS_MONKEY_TURN_180 )
2022-01-19 16:17:16 +11:00
return ;
2022-01-26 17:48:50 +11:00
SetAnimation ( item , LA_MONKEY_TO_FREEFALL ) ;
2022-01-19 16:17:16 +11:00
SetLaraMonkeyRelease ( item ) ;
}
void SetLaraMonkeyRelease ( ITEM_INFO * item )
{
2022-02-28 21:02:19 +11:00
auto * lara = GetLaraInfo ( item ) ;
2022-01-19 16:17:16 +11:00
2022-02-09 13:20:57 +11:00
item - > Velocity = 2 ;
item - > VerticalVelocity = 1 ;
item - > Airborne = true ;
2022-02-28 21:02:19 +11:00
lara - > Control . HandStatus = HandStatus : : Free ;
2022-01-12 17:31:03 +11:00
}
2021-12-18 20:42:15 +11:00
void SetLaraSlideState ( ITEM_INFO * item , COLL_INFO * coll )
{
2022-01-23 18:16:29 +11:00
short direction = GetLaraSlideDirection ( item , coll ) ;
2022-03-04 21:30:09 +11:00
short deltaAngle = direction - item - > Position . yRot ;
2021-12-18 20:42:15 +11:00
2022-03-05 01:51:13 +11:00
// TODO: Take inertia into consideration before switching animations if already sliding.
2022-03-04 19:58:40 +11:00
// Slide backward.
2022-03-04 21:30:09 +11:00
if ( abs ( deltaAngle ) > ANGLE ( 90.0f ) )
2021-12-18 20:42:15 +11:00
{
2022-03-04 21:30:09 +11:00
if ( item - > ActiveState = = LS_SLIDE_BACK & & abs ( short ( deltaAngle - ANGLE ( 180.0f ) ) ) < = - ANGLE ( 180.0f ) )
2021-12-18 20:42:15 +11:00
return ;
SetAnimation ( item , LA_SLIDE_BACK_START ) ;
}
2022-03-04 19:58:40 +11:00
// Slide forward.
2022-03-04 21:30:09 +11:00
else [[likely]]
2021-12-18 20:42:15 +11:00
{
2022-03-04 21:30:09 +11:00
if ( item - > ActiveState = = LS_SLIDE_FORWARD & & abs ( deltaAngle ) < = ANGLE ( 180.0f ) )
2021-12-18 20:42:15 +11:00
return ;
SetAnimation ( item , LA_SLIDE_FORWARD ) ;
}
}
2022-02-19 13:01:19 +11:00
void SetCornerAnimation ( ITEM_INFO * item , COLL_INFO * coll , bool flip )
{
2022-02-28 21:02:19 +11:00
auto * lara = GetLaraInfo ( item ) ;
2022-02-19 13:01:19 +11:00
if ( item - > HitPoints < = 0 )
{
SetAnimation ( item , LA_FALL_START ) ;
2022-03-01 14:21:27 +11:00
item - > Position . yPos + = CLICK ( 1 ) ;
item - > Position . yRot + = lara - > NextCornerPos . yRot / 2 ;
2022-02-19 13:01:19 +11:00
item - > Velocity = 2 ;
item - > VerticalVelocity = 1 ;
2022-03-01 14:21:27 +11:00
item - > Airborne = true ;
2022-02-28 21:02:19 +11:00
lara - > Control . HandStatus = HandStatus : : Free ;
2022-02-19 13:01:19 +11:00
return ;
}
if ( flip )
{
2022-02-28 21:02:19 +11:00
if ( lara - > Control . IsClimbingLadder )
2022-02-19 13:01:19 +11:00
SetAnimation ( item , LA_LADDER_IDLE ) ;
else
SetAnimation ( item , LA_HANG_IDLE ) ;
2022-02-28 21:02:19 +11:00
coll - > Setup . OldPosition . x = item - > Position . xPos = lara - > NextCornerPos . xPos ;
coll - > Setup . OldPosition . y = item - > Position . yPos = lara - > NextCornerPos . yPos ;
coll - > Setup . OldPosition . z = item - > Position . zPos = lara - > NextCornerPos . zPos ;
item - > Position . yRot = lara - > NextCornerPos . yRot ;
2022-02-19 13:01:19 +11:00
}
}
2022-02-12 00:25:05 +11:00
void ResetLaraLean ( ITEM_INFO * item , float rate , bool resetRoll , bool resetPitch )
{
2022-02-14 17:05:52 +11:00
if ( ! rate )
2022-02-24 14:22:30 +11:00
{
TENLog ( std : : string ( " ResetLaraLean() attempted division by zero! " ) , LogLevel : : Warning ) ;
2022-02-14 17:05:52 +11:00
return ;
2022-02-24 14:22:30 +11:00
}
2022-02-12 00:25:05 +11:00
2022-02-14 17:05:52 +11:00
rate = abs ( rate ) ;
2022-02-12 00:25:05 +11:00
if ( resetPitch )
{
if ( abs ( item - > Position . xRot ) > ANGLE ( 0.1f ) )
item - > Position . xRot + = item - > Position . xRot / - rate ;
else
item - > Position . xRot = 0 ;
}
2022-02-14 17:05:52 +11:00
if ( resetRoll )
{
if ( abs ( item - > Position . zRot ) > ANGLE ( 0.1f ) )
item - > Position . zRot + = item - > Position . zRot / - rate ;
else
item - > Position . zRot = 0 ;
}
2022-02-12 00:25:05 +11:00
}
2021-12-10 12:30:23 +11:00
void ResetLaraFlex ( ITEM_INFO * item , float rate )
2021-11-27 23:15:26 +11:00
{
2022-02-28 21:02:19 +11:00
auto * lara = GetLaraInfo ( item ) ;
2022-02-14 17:05:52 +11:00
if ( ! rate )
2022-02-24 14:22:30 +11:00
{
TENLog ( std : : string ( " ResetLaraFlex() attempted division by zero! " ) , LogLevel : : Warning ) ;
2022-02-14 17:05:52 +11:00
return ;
2022-02-24 14:22:30 +11:00
}
2022-02-12 00:25:05 +11:00
2022-02-14 17:05:52 +11:00
rate = abs ( rate ) ;
2021-11-27 23:15:26 +11:00
// Reset head.
2022-02-28 21:02:19 +11:00
if ( abs ( lara - > ExtraHeadRot . xRot ) > ANGLE ( 0.1f ) )
lara - > ExtraHeadRot . xRot + = lara - > ExtraHeadRot . xRot / - rate ;
2021-11-27 23:15:26 +11:00
else
2022-02-28 21:02:19 +11:00
lara - > ExtraHeadRot . xRot = 0 ;
2021-11-27 23:15:26 +11:00
2022-02-28 21:02:19 +11:00
if ( abs ( lara - > ExtraHeadRot . yRot ) > ANGLE ( 0.1f ) )
lara - > ExtraHeadRot . yRot + = lara - > ExtraHeadRot . yRot / - rate ;
2021-11-27 23:15:26 +11:00
else
2022-02-28 21:02:19 +11:00
lara - > ExtraHeadRot . yRot = 0 ;
2021-11-27 23:15:26 +11:00
2022-02-28 21:02:19 +11:00
if ( abs ( lara - > ExtraHeadRot . zRot ) > ANGLE ( 0.1f ) )
lara - > ExtraHeadRot . zRot + = lara - > ExtraHeadRot . zRot / - rate ;
2021-11-27 23:15:26 +11:00
else
2022-02-28 21:02:19 +11:00
lara - > ExtraHeadRot . zRot = 0 ;
2021-11-27 23:15:26 +11:00
// Reset torso.
2022-02-28 21:02:19 +11:00
if ( abs ( lara - > ExtraTorsoRot . xRot ) > ANGLE ( 0.1f ) )
lara - > ExtraTorsoRot . xRot + = lara - > ExtraTorsoRot . xRot / - rate ;
2021-11-27 23:15:26 +11:00
else
2022-02-28 21:02:19 +11:00
lara - > ExtraTorsoRot . xRot = 0 ;
2021-11-27 23:15:26 +11:00
2022-02-28 21:02:19 +11:00
if ( abs ( lara - > ExtraTorsoRot . yRot ) > ANGLE ( 0.1f ) )
lara - > ExtraTorsoRot . yRot + = lara - > ExtraTorsoRot . yRot / - rate ;
2021-11-27 23:15:26 +11:00
else
2022-02-28 21:02:19 +11:00
lara - > ExtraTorsoRot . yRot = 0 ;
2021-11-27 23:15:26 +11:00
2022-02-28 21:02:19 +11:00
if ( abs ( lara - > ExtraTorsoRot . zRot ) > ANGLE ( 0.1f ) )
lara - > ExtraTorsoRot . zRot + = lara - > ExtraTorsoRot . zRot / - rate ;
2021-11-27 23:15:26 +11:00
else
2022-02-28 21:02:19 +11:00
lara - > ExtraTorsoRot . zRot = 0 ;
2021-11-27 23:15:26 +11:00
}
2021-12-10 12:30:23 +11:00
void HandleLaraMovementParameters ( ITEM_INFO * item , COLL_INFO * coll )
2021-09-27 18:18:03 +10:00
{
2022-02-28 21:02:19 +11:00
auto * lara = GetLaraInfo ( item ) ;
2021-09-27 18:18:03 +10:00
2021-12-10 12:30:23 +11:00
// Reset running jump timer.
2022-02-12 16:25:59 +11:00
if ( ! IsRunJumpCountableState ( ( LaraState ) item - > ActiveState ) )
2022-02-28 21:02:19 +11:00
lara - > Control . Count . RunJump = 0 ;
2022-02-04 22:18:55 +11:00
2022-01-03 17:01:07 +11:00
// Reset running jump action queue.
2022-02-12 16:25:59 +11:00
if ( ! IsRunJumpQueueableState ( ( LaraState ) item - > ActiveState ) )
2022-02-28 21:02:19 +11:00
lara - > Control . RunJumpQueued = false ;
2021-12-12 13:27:26 +11:00
2021-12-10 12:30:23 +11:00
// Increment/reset AFK pose timer.
2022-02-28 21:02:19 +11:00
if ( lara - > Control . Count . Pose < LARA_POSE_TIME & &
2021-12-10 12:30:23 +11:00
TestLaraPose ( item , coll ) & &
! ( TrInput & ( IN_WAKE | IN_LOOK ) ) & &
2022-03-04 15:51:53 +11:00
g_GameFlow - > Animations . HasPose )
2021-12-10 12:30:23 +11:00
{
2022-02-28 21:02:19 +11:00
lara - > Control . Count . Pose + + ;
2021-12-10 12:30:23 +11:00
}
else
2022-02-28 21:02:19 +11:00
lara - > Control . Count . Pose = 0 ;
2021-12-10 12:30:23 +11:00
// Reset lean.
2022-02-28 21:02:19 +11:00
if ( ! lara - > Control . IsMoving | | ( lara - > Control . IsMoving & & ! ( TrInput & ( IN_LEFT | IN_RIGHT ) ) ) )
2022-02-12 00:25:05 +11:00
ResetLaraLean ( item , 6 ) ;
2021-12-22 16:00:13 +11:00
2021-12-10 12:30:23 +11:00
// Reset crawl flex.
if ( ! ( TrInput & IN_LOOK ) & &
2021-12-10 22:31:34 +11:00
coll - > Setup . Height > LARA_HEIGHT - LARA_HEADROOM & &
2022-02-09 13:20:57 +11:00
( ! item - > Velocity | | ( item - > Velocity & & ! ( TrInput & ( IN_LEFT | IN_RIGHT ) ) ) ) )
2021-12-10 12:30:23 +11:00
{
ResetLaraFlex ( item , 12 ) ;
}
// Reset turn rate.
2022-02-28 21:02:19 +11:00
int sign = copysign ( 1 , lara - > Control . TurnRate ) ;
if ( abs ( lara - > Control . TurnRate ) > ANGLE ( 2.0f ) )
lara - > Control . TurnRate - = ANGLE ( 2.0f ) * sign ;
else if ( abs ( lara - > Control . TurnRate ) > ANGLE ( 0.5f ) )
lara - > Control . TurnRate - = ANGLE ( 0.5f ) * sign ;
2021-12-10 12:30:23 +11:00
else
2022-02-28 21:02:19 +11:00
lara - > Control . TurnRate = 0 ;
item - > Position . yRot + = lara - > Control . TurnRate ;
2021-10-14 19:58:29 +11:00
}
2022-02-08 01:26:59 +11:00
2022-02-20 14:22:26 +11:00
bool HandleLaraVehicle ( ITEM_INFO * item , COLL_INFO * coll )
2022-02-08 01:26:59 +11:00
{
2022-02-28 21:02:19 +11:00
auto * lara = GetLaraInfo ( item ) ;
2022-02-08 01:26:59 +11:00
2022-02-28 21:02:19 +11:00
if ( lara - > Vehicle ! = NO_ITEM )
2022-02-08 01:26:59 +11:00
{
2022-02-28 21:02:19 +11:00
switch ( g_Level . Items [ lara - > Vehicle ] . ObjectNumber )
2022-02-08 01:26:59 +11:00
{
case ID_QUAD :
2022-02-20 14:22:26 +11:00
QuadBikeControl ( item , coll ) ;
2022-02-08 01:26:59 +11:00
break ;
case ID_JEEP :
2022-02-20 14:22:26 +11:00
JeepControl ( ) ;
2022-02-08 01:26:59 +11:00
break ;
case ID_MOTORBIKE :
2022-02-20 14:22:26 +11:00
MotorbikeControl ( ) ;
2022-02-08 01:26:59 +11:00
break ;
case ID_KAYAK :
2022-02-20 14:22:26 +11:00
KayakControl ( item ) ;
2022-02-08 01:26:59 +11:00
break ;
case ID_SNOWMOBILE :
2022-02-20 14:22:26 +11:00
SkidooControl ( item , coll ) ;
2022-02-08 01:26:59 +11:00
break ;
case ID_UPV :
2022-03-03 21:31:32 +11:00
UPVControl ( item , coll ) ;
2022-02-08 01:26:59 +11:00
break ;
case ID_MINECART :
2022-02-23 22:15:51 +11:00
MineCartControl ( item ) ;
2022-02-08 01:26:59 +11:00
break ;
case ID_BIGGUN :
2022-02-20 14:22:26 +11:00
BigGunControl ( item , coll ) ;
2022-02-08 01:26:59 +11:00
break ;
// Boats are processed like normal items in loop.
default :
LaraGun ( item ) ;
}
2022-02-20 14:22:26 +11:00
return true ;
2022-02-08 01:26:59 +11:00
}
2022-02-20 14:22:26 +11:00
return false ;
2022-02-08 01:26:59 +11:00
}