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-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 "Game/Lara/lara_collide.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-08 01:26:59 +11:00
|
|
|
#include "Objects/TR2/Vehicles/snowmobile.h"
|
|
|
|
#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);
|
|
|
|
|
|
|
|
if (coll->CollisionType == CT_LEFT || coll->CollisionType == CT_RIGHT)
|
2022-02-09 16:55:46 +11:00
|
|
|
item->Position.zRot += std::min(rate, (short)(abs((maxAngle * 3) / 5 - item->Position.zRot) / 3)) * sign;
|
2021-12-23 18:41:37 +11:00
|
|
|
else
|
2022-02-09 16:55:46 +11:00
|
|
|
item->Position.zRot += std::min(rate, (short)(abs(maxAngle - item->Position.zRot) / 3)) * sign;
|
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.
|
|
|
|
constexpr int rate = 50;
|
2022-02-09 13:20:57 +11:00
|
|
|
int threshold = std::max(abs(item->Velocity) / 3 * 2, STEP_SIZE / 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-12 00:25:05 +11:00
|
|
|
auto info = 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-10 01:38:32 +11:00
|
|
|
info->Control.ExtraTorsoRot.zRot += std::min(abs(rate), abs(maxAngle - info->Control.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-10 01:38:32 +11:00
|
|
|
info->Control.ExtraHeadRot.zRot = info->Control.ExtraTorsoRot.zRot / 2;
|
|
|
|
info->Control.ExtraHeadRot.yRot = info->Control.ExtraHeadRot.zRot;
|
2021-11-27 20:35:16 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-22 22:36:29 +11:00
|
|
|
void DoLaraFallDamage(ITEM_INFO* item)
|
|
|
|
{
|
|
|
|
// TODO: Demagic more of these numbers.
|
2022-02-09 13:20:57 +11:00
|
|
|
int landSpeed = item->VerticalVelocity - 140;
|
2022-01-22 22:36:29 +11:00
|
|
|
|
|
|
|
if (landSpeed > 0)
|
|
|
|
{
|
|
|
|
if (landSpeed <= 14)
|
2022-02-09 16:55:46 +11:00
|
|
|
item->HitPoints -= LARA_HEALTH_MAX * pow(landSpeed, 2) / 196;
|
2022-01-22 22:36:29 +11:00
|
|
|
else
|
2022-02-09 16:55:46 +11:00
|
|
|
item->HitPoints = 0;
|
2022-01-22 22:36:29 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-12 00:25:05 +11:00
|
|
|
LaraInfo*& GetLaraInfo(ITEM_INFO* item)
|
|
|
|
{
|
|
|
|
if (item->ObjectNumber != ID_LARA)
|
|
|
|
{
|
|
|
|
TENLog(std::string("Attempted to fetch LaraInfo data from object with ID ") + std::to_string(item->ObjectNumber), LogLevel::Warning);
|
|
|
|
|
|
|
|
// TODO: I don't know what to do here. @Sezz 2022.02.12
|
|
|
|
return (LaraInfo*&)LaraItem->Data;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (LaraInfo*&)item->Data;
|
|
|
|
}
|
|
|
|
|
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-01-22 21:08:30 +11:00
|
|
|
//if (g_GameFlow->Animations.SlideExtended)
|
|
|
|
//{
|
|
|
|
// // TODO: Get true slope direction.
|
|
|
|
//}
|
|
|
|
//else
|
|
|
|
{
|
|
|
|
if (coll->FloorTiltX > 2)
|
2022-01-23 18:16:29 +11:00
|
|
|
direction = -ANGLE(90.0f);
|
2022-01-22 21:08:30 +11:00
|
|
|
else if (coll->FloorTiltX < -2)
|
2022-01-23 18:16:29 +11:00
|
|
|
direction = ANGLE(90.0f);
|
2022-01-22 21:08:30 +11:00
|
|
|
|
|
|
|
if (coll->FloorTiltZ > 2 && coll->FloorTiltZ > abs(coll->FloorTiltX))
|
2022-01-23 18:16:29 +11:00
|
|
|
direction = ANGLE(180.0f);
|
2022-01-22 21:08:30 +11:00
|
|
|
else if (coll->FloorTiltZ < -2 && -coll->FloorTiltZ > abs(coll->FloorTiltX))
|
2022-01-23 18:16:29 +11:00
|
|
|
direction = ANGLE(0.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-12 00:25:05 +11:00
|
|
|
auto info = 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-10 01:38:32 +11:00
|
|
|
info->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-10 01:38:32 +11:00
|
|
|
info->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-10 01:38:32 +11:00
|
|
|
info->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-10 01:38:32 +11:00
|
|
|
info->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-10 01:38:32 +11:00
|
|
|
info->Control.JumpDirection = JumpDirection::Up;
|
2021-12-20 00:11:04 +11:00
|
|
|
else
|
2022-02-10 16:18:15 +11:00
|
|
|
info->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-12 00:25:05 +11:00
|
|
|
auto info = GetLaraInfo(item);
|
2021-12-19 19:12:35 +11:00
|
|
|
|
2022-02-09 16:55:46 +11:00
|
|
|
int y = item->Position.yPos;
|
2022-01-22 00:22:24 +11:00
|
|
|
int dist = WALL_SIZE;
|
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-10 01:38:32 +11:00
|
|
|
info->Control.RunJumpQueued = IsRunJumpQueueableState((LARA_STATE)item->TargetState);
|
2022-01-12 19:04:29 +11:00
|
|
|
}
|
2021-12-19 19:12:35 +11:00
|
|
|
else
|
2022-02-10 01:38:32 +11:00
|
|
|
info->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-12 00:25:05 +11:00
|
|
|
auto info = GetLaraInfo(item);
|
2022-02-05 23:13:31 +11:00
|
|
|
|
2022-02-11 19:26:08 +11:00
|
|
|
info->ProjectedFloorHeight = vaultResult.Height;
|
2022-02-11 01:31:54 +11:00
|
|
|
info->Control.HandStatus = vaultResult.SetBusyHands ? HandStatus::Busy : info->Control.HandStatus;
|
2022-02-10 01:38:32 +11:00
|
|
|
info->Control.TurnRate = 0;
|
2022-02-06 14:15:10 +11:00
|
|
|
|
|
|
|
if (vaultResult.SnapToLedge)
|
2022-02-07 13:06:02 +11:00
|
|
|
SnapItemToLedge(item, coll);
|
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;
|
|
|
|
item->Airborne = false;
|
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-01-19 16:17:16 +11:00
|
|
|
// Hack.
|
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-12 00:25:05 +11:00
|
|
|
auto info = 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-11 01:31:54 +11:00
|
|
|
info->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-02-12 00:25:05 +11:00
|
|
|
auto info = GetLaraInfo(item);
|
2021-12-18 20:42:15 +11:00
|
|
|
|
2022-01-23 18:16:29 +11:00
|
|
|
short direction = GetLaraSlideDirection(item, coll);
|
2022-02-09 16:55:46 +11:00
|
|
|
short delta = direction - item->Position.yRot;
|
2021-12-18 20:42:15 +11:00
|
|
|
static short oldAngle = 1;
|
|
|
|
|
|
|
|
ShiftItem(item, coll);
|
|
|
|
|
|
|
|
if (delta < -ANGLE(90.0f) || delta > ANGLE(90.0f))
|
|
|
|
{
|
2022-02-09 16:55:46 +11:00
|
|
|
if (item->ActiveState == LS_SLIDE_BACK && oldAngle == direction)
|
2021-12-18 20:42:15 +11:00
|
|
|
return;
|
|
|
|
|
|
|
|
SetAnimation(item, LA_SLIDE_BACK_START);
|
2022-02-09 16:55:46 +11:00
|
|
|
item->Position.yRot = direction + ANGLE(180.0f);
|
2021-12-18 20:42:15 +11:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2022-02-09 16:55:46 +11:00
|
|
|
if (item->ActiveState == LS_SLIDE_FORWARD && oldAngle == direction)
|
2021-12-18 20:42:15 +11:00
|
|
|
return;
|
|
|
|
|
|
|
|
SetAnimation(item, LA_SLIDE_FORWARD);
|
2022-02-09 16:55:46 +11:00
|
|
|
item->Position.yRot = direction;
|
2021-12-18 20:42:15 +11:00
|
|
|
}
|
|
|
|
|
2022-01-23 15:06:05 +11:00
|
|
|
LaraSnapToHeight(item, coll);
|
2022-02-10 01:38:32 +11:00
|
|
|
info->Control.MoveAngle = direction;
|
2022-01-23 15:06:05 +11:00
|
|
|
oldAngle = direction;
|
2021-12-18 20:42:15 +11:00
|
|
|
}
|
|
|
|
|
2022-02-12 00:25:05 +11:00
|
|
|
void ResetLaraLean(ITEM_INFO* item, float rate, bool resetRoll, bool resetPitch)
|
|
|
|
{
|
|
|
|
if (rate < 0)
|
|
|
|
rate = -rate;
|
|
|
|
|
|
|
|
// Reset roll.
|
|
|
|
if (resetRoll)
|
|
|
|
{
|
|
|
|
if (abs(item->Position.zRot) > ANGLE(0.1f))
|
|
|
|
item->Position.zRot += item->Position.zRot / -rate;
|
|
|
|
else
|
|
|
|
item->Position.zRot = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reset pitch.
|
|
|
|
if (resetPitch)
|
|
|
|
{
|
|
|
|
if (abs(item->Position.xRot) > ANGLE(0.1f))
|
|
|
|
item->Position.xRot += item->Position.xRot / -rate;
|
|
|
|
else
|
|
|
|
item->Position.xRot = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-12 00:25:05 +11:00
|
|
|
auto info = GetLaraInfo(item);
|
|
|
|
|
|
|
|
if (rate < 0)
|
|
|
|
rate = -rate;
|
2021-11-27 23:15:26 +11:00
|
|
|
|
|
|
|
// Reset head.
|
2022-02-10 01:38:32 +11:00
|
|
|
if (abs(info->Control.ExtraHeadRot.xRot) > ANGLE(0.1f))
|
|
|
|
info->Control.ExtraHeadRot.xRot += info->Control.ExtraHeadRot.xRot / -rate;
|
2021-11-27 23:15:26 +11:00
|
|
|
else
|
2022-02-10 01:38:32 +11:00
|
|
|
info->Control.ExtraHeadRot.xRot = 0;
|
2021-11-27 23:15:26 +11:00
|
|
|
|
2022-02-10 01:38:32 +11:00
|
|
|
if (abs(info->Control.ExtraHeadRot.yRot) > ANGLE(0.1f))
|
|
|
|
info->Control.ExtraHeadRot.yRot += info->Control.ExtraHeadRot.yRot / -rate;
|
2021-11-27 23:15:26 +11:00
|
|
|
else
|
2022-02-10 01:38:32 +11:00
|
|
|
info->Control.ExtraHeadRot.yRot = 0;
|
2021-11-27 23:15:26 +11:00
|
|
|
|
2022-02-10 01:38:32 +11:00
|
|
|
if (abs(info->Control.ExtraHeadRot.zRot) > ANGLE(0.1f))
|
|
|
|
info->Control.ExtraHeadRot.zRot += info->Control.ExtraHeadRot.zRot / -rate;
|
2021-11-27 23:15:26 +11:00
|
|
|
else
|
2022-02-10 01:38:32 +11:00
|
|
|
info->Control.ExtraHeadRot.zRot = 0;
|
2021-11-27 23:15:26 +11:00
|
|
|
|
|
|
|
// Reset torso.
|
2022-02-10 17:17:41 +11:00
|
|
|
if (abs(info->Control.ExtraTorsoRot.xRot) > ANGLE(0.1f))
|
|
|
|
info->Control.ExtraTorsoRot.xRot += info->Control.ExtraTorsoRot.xRot / -rate;
|
2021-11-27 23:15:26 +11:00
|
|
|
else
|
2022-02-10 17:17:41 +11:00
|
|
|
info->Control.ExtraTorsoRot.xRot = 0;
|
2021-11-27 23:15:26 +11:00
|
|
|
|
2022-02-10 01:38:32 +11:00
|
|
|
if (abs(info->Control.ExtraTorsoRot.yRot) > ANGLE(0.1f))
|
|
|
|
info->Control.ExtraTorsoRot.yRot += info->Control.ExtraTorsoRot.yRot / -rate;
|
2021-11-27 23:15:26 +11:00
|
|
|
else
|
2022-02-10 01:38:32 +11:00
|
|
|
info->Control.ExtraTorsoRot.yRot = 0;
|
2021-11-27 23:15:26 +11:00
|
|
|
|
2022-02-10 01:38:32 +11:00
|
|
|
if (abs(info->Control.ExtraTorsoRot.zRot) > ANGLE(0.1f))
|
|
|
|
info->Control.ExtraTorsoRot.zRot += info->Control.ExtraTorsoRot.zRot / -rate;
|
2021-11-27 23:15:26 +11:00
|
|
|
else
|
2022-02-10 01:38:32 +11:00
|
|
|
info->Control.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-12 00:25:05 +11:00
|
|
|
auto info = GetLaraInfo(item);
|
2021-09-27 18:18:03 +10:00
|
|
|
|
2021-12-10 12:30:23 +11:00
|
|
|
// Reset running jump timer.
|
2022-02-09 16:55:46 +11:00
|
|
|
if (!IsRunJumpCountableState((LARA_STATE)item->ActiveState))
|
2022-02-11 19:26:08 +11:00
|
|
|
info->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-09 16:55:46 +11:00
|
|
|
if (!IsRunJumpQueueableState((LARA_STATE)item->ActiveState))
|
2022-02-10 01:38:32 +11:00
|
|
|
info->Control.RunJumpQueued = false;
|
2021-12-12 13:27:26 +11:00
|
|
|
|
2022-02-04 20:23:39 +11:00
|
|
|
// Reset projected height value used by step function.
|
2022-02-09 16:55:46 +11:00
|
|
|
//if (!IsVaultState((LARA_STATE)item->ActiveState))
|
2022-02-11 19:26:08 +11:00
|
|
|
// info->ProjectedFloorHeight = NO_HEIGHT;
|
2022-02-05 23:13:31 +11:00
|
|
|
|
|
|
|
// Reset calculated auto jump velocity.
|
2022-02-09 16:55:46 +11:00
|
|
|
//if (item->ActiveState != LS_AUTO_JUMP)
|
2022-02-10 01:38:32 +11:00
|
|
|
// info->Control.CalculatedJumpVelocity = 0;
|
2022-02-04 19:06:59 +11:00
|
|
|
|
2021-12-10 12:30:23 +11:00
|
|
|
// Increment/reset AFK pose timer.
|
2022-02-11 19:26:08 +11:00
|
|
|
if (info->Control.Count.Pose < LARA_POSE_TIME &&
|
2021-12-10 12:30:23 +11:00
|
|
|
TestLaraPose(item, coll) &&
|
|
|
|
!(TrInput & (IN_WAKE | IN_LOOK)) &&
|
|
|
|
g_GameFlow->Animations.Pose)
|
|
|
|
{
|
2022-02-11 19:26:08 +11:00
|
|
|
info->Control.Count.Pose++;
|
2021-12-10 12:30:23 +11:00
|
|
|
}
|
|
|
|
else
|
2022-02-11 19:26:08 +11:00
|
|
|
info->Control.Count.Pose = 0;
|
2021-12-10 12:30:23 +11:00
|
|
|
|
|
|
|
// Reset lean.
|
2022-02-10 01:38:32 +11:00
|
|
|
if (!info->Control.IsMoving || (info->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-10 01:38:32 +11:00
|
|
|
int sign = copysign(1, info->Control.TurnRate);
|
|
|
|
if (abs(info->Control.TurnRate) > ANGLE(2.0f))
|
|
|
|
info->Control.TurnRate -= ANGLE(2.0f) * sign;
|
|
|
|
else if (abs(info->Control.TurnRate) > ANGLE(0.5f))
|
|
|
|
info->Control.TurnRate -= ANGLE(0.5f) * sign;
|
2021-12-10 12:30:23 +11:00
|
|
|
else
|
2022-02-10 01:38:32 +11:00
|
|
|
info->Control.TurnRate = 0;
|
|
|
|
item->Position.yRot += info->Control.TurnRate;
|
2021-10-14 19:58:29 +11:00
|
|
|
}
|
2022-02-08 01:26:59 +11:00
|
|
|
|
2022-02-08 20:45:21 +11:00
|
|
|
void HandleLaraVehicle(ITEM_INFO* item, COLL_INFO* coll)
|
2022-02-08 01:26:59 +11:00
|
|
|
{
|
2022-02-12 00:25:05 +11:00
|
|
|
auto info = GetLaraInfo(item);
|
2022-02-08 01:26:59 +11:00
|
|
|
|
|
|
|
if (info->Vehicle != NO_ITEM)
|
|
|
|
{
|
2022-02-09 16:55:46 +11:00
|
|
|
switch (g_Level.Items[info->Vehicle].ObjectNumber)
|
2022-02-08 01:26:59 +11:00
|
|
|
{
|
|
|
|
case ID_QUAD:
|
|
|
|
if (QuadBikeControl(item, coll))
|
|
|
|
return;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ID_JEEP:
|
|
|
|
if (JeepControl())
|
|
|
|
return;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ID_MOTORBIKE:
|
|
|
|
if (MotorbikeControl())
|
|
|
|
return;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ID_KAYAK:
|
|
|
|
if (KayakControl(item))
|
|
|
|
return;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ID_SNOWMOBILE:
|
|
|
|
if (SkidooControl(item, coll))
|
|
|
|
return;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ID_UPV:
|
|
|
|
if (SubControl(item, coll))
|
|
|
|
return;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ID_MINECART:
|
|
|
|
if (MineCartControl())
|
|
|
|
return;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ID_BIGGUN:
|
|
|
|
if (BigGunControl(item, coll))
|
|
|
|
return;
|
|
|
|
break;
|
|
|
|
|
|
|
|
// Boats are processed like normal items in loop.
|
|
|
|
default:
|
|
|
|
LaraGun(item);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|