mirror of
https://github.com/TombEngine/TombEngine.git
synced 2025-05-13 14:07:04 +03:00
Vehicles cleanup before impacts were broken (#575)
* Enhance big gun rotation; vehicle cleanup * Determine defaults for vehicle info members; keep camera elevation aligned with line of sight on big gun * Organise constants * Fix jeep/bike floor tilts * Unify vehicle height calcs, fix bridges for vehicles * Fix water vehicles * Fix typo * Introduce unified vehicle mounting mechanism and use it for the skidoo * Ensure vehicle mounting occurs from correct side; modify skidoo and speedboat control inputs * Update VehicleHelpers.cpp * Fix kayak * Standardise vehicle inputs * Update vehicle acceleration input * Make vehicle inputs constants * Rename Airborne to IsAirborne * Move generic vehicle functions to VehicleHelpers.cpp * Also move constants * Remove inaccurate vehicle mount condition * Move vehicle constants to header; redo quad bike input replacement (further adjustment required) * Establish vehicle mount constants for later; convert vehicle macros to constants * Add condition to level start mount * Organise and demagic some vehicle constants * More cleanup and demagicking of vehicle constants * Demagic and simplify UPV garbage * Organise UPV angle macros and constants to make sense * Organise a little more * Final cleanup of UPV constants * Add temporary vehicle velocity scale constant for easier removal later; demagic rubber boat velocity and turn rate values * Cleanup, demagicking * Cleanup * Organisation * Prototype vehicle turn rate modulation with skidoo and UPV * Tentatively simplify UPV turn rate deceleration * Fix UPV turning * Tweak UPV turn rate macros * Tweak UPV turn rate macros * Complete vehicle mount function * Use new vehicle mount function with quad bike * Use new vehicle mount function with motorbike * Add oneshot check to GetVehicleMountType() * Prepare mechanism to allow starting a level already mounted on any vehicle * Fix typo * Cleanup and organisation * Remove use of Lara global * Use new vehicle mount function with minecart * Fix spike deaths on vehicles * Use new vehicle mount function with jeep * Assess 2D distance for vehicle mounts instead of 3D for better fidelity around steps * Cleanup * Use new vehicle mount function with speedboat * Fix mounts on boats * Use new vehicle mount function with rubber boat * Use new vehicle mount function with kayak * Cleanup * Use new mount function with UPV * Fix motorbike nitro and remove useless flag checks * Fix bike nitro, rotate wheels for vehicles * Fix ItemPushStatic not to corrupt non-Lara items room number * Remove unneeded clamps * Fix typo * Jeep: comply to tomb4 decompilation order * Uncomment drift code for jeep, rename unknown2 to Gear * Fix flag meanings * Further backport of jeep from tomb4 project * Use JeepBrakeLightJoints * Update jeep.cpp * Fix vehicle static collisions * Add disabled option to insert nitro into motorbike * Simplify UPV collision check * Update comment * Make vehicle function parameter ordering consistent * Rotate UPV rudders when turning the vehicle * Lean UPV when turning * Simplify condition * Simplify skidoo turn rate modulation * Fix UPV turbine rotation * Fix merge error * Tentatively invert turning when moving in reverse on skidoo * Add function to discard flares on vehicles to avoid copy-paste * Add big reminder comment for savegames * Fix another "epic" typo by me, convert enum hex values to shifts * lara_struct.h cleanup * UPV cleanup * #include cleanup in vehicle headers * Also brake quadbike with brake button Co-authored-by: Sezz <seb.zych@outlook.com>
This commit is contained in:
parent
deaae5093f
commit
aded24fa10
126 changed files with 5292 additions and 5558 deletions
|
@ -40,7 +40,6 @@
|
||||||
using namespace TEN::Effects::Lara;
|
using namespace TEN::Effects::Lara;
|
||||||
using namespace TEN::Control::Volumes;
|
using namespace TEN::Control::Volumes;
|
||||||
using namespace TEN::Input;
|
using namespace TEN::Input;
|
||||||
|
|
||||||
using std::function;
|
using std::function;
|
||||||
using TEN::Renderer::g_Renderer;
|
using TEN::Renderer::g_Renderer;
|
||||||
|
|
||||||
|
@ -448,7 +447,7 @@ void LaraControl(ItemInfo* item, CollisionInfo* coll)
|
||||||
item->Animation.AnimNumber == LA_STAND_IDLE &&
|
item->Animation.AnimNumber == LA_STAND_IDLE &&
|
||||||
item->Animation.ActiveState == LS_IDLE &&
|
item->Animation.ActiveState == LS_IDLE &&
|
||||||
item->Animation.TargetState == LS_IDLE &&
|
item->Animation.TargetState == LS_IDLE &&
|
||||||
!item->Animation.Airborne)
|
!item->Animation.IsAirborne)
|
||||||
{
|
{
|
||||||
lara->Control.HandStatus = HandStatus::Free;
|
lara->Control.HandStatus = HandStatus::Free;
|
||||||
}
|
}
|
||||||
|
@ -492,7 +491,7 @@ void LaraControl(ItemInfo* item, CollisionInfo* coll)
|
||||||
if (isWater)
|
if (isWater)
|
||||||
{
|
{
|
||||||
item->Pose.Position.y += CLICK(0.5f) - 28;
|
item->Pose.Position.y += CLICK(0.5f) - 28;
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
lara->Control.WaterStatus = WaterStatus::Underwater;
|
lara->Control.WaterStatus = WaterStatus::Underwater;
|
||||||
lara->Air = LARA_AIR_MAX;
|
lara->Air = LARA_AIR_MAX;
|
||||||
|
|
||||||
|
@ -529,15 +528,15 @@ void LaraControl(ItemInfo* item, CollisionInfo* coll)
|
||||||
{
|
{
|
||||||
lara->Control.WaterStatus = WaterStatus::Wade;
|
lara->Control.WaterStatus = WaterStatus::Wade;
|
||||||
|
|
||||||
// Make splash ONLY within this particular threshold before swim depth while airborne (WadeSplash() above interferes otherwise).
|
// Make splash ONLY within this particular threshold before swim depth while is_airborne (WadeSplash() above interferes otherwise).
|
||||||
if (waterDepth > (SWIM_DEPTH - CLICK(1)) &&
|
if (waterDepth > (SWIM_DEPTH - CLICK(1)) &&
|
||||||
item->Animation.Airborne && !isSwamp)
|
item->Animation.IsAirborne && !isSwamp)
|
||||||
{
|
{
|
||||||
item->Animation.TargetState = LS_IDLE;
|
item->Animation.TargetState = LS_IDLE;
|
||||||
Splash(item);
|
Splash(item);
|
||||||
}
|
}
|
||||||
// Lara is grounded; don't splash again.
|
// Lara is grounded; don't splash again.
|
||||||
else if (!item->Animation.Airborne)
|
else if (!item->Animation.IsAirborne)
|
||||||
item->Animation.TargetState = LS_IDLE;
|
item->Animation.TargetState = LS_IDLE;
|
||||||
else if (isSwamp)
|
else if (isSwamp)
|
||||||
{
|
{
|
||||||
|
@ -566,7 +565,7 @@ void LaraControl(ItemInfo* item, CollisionInfo* coll)
|
||||||
SetAnimation(item, LA_FALL_START);
|
SetAnimation(item, LA_FALL_START);
|
||||||
ResetLaraLean(item);
|
ResetLaraLean(item);
|
||||||
ResetLaraFlex(item);
|
ResetLaraFlex(item);
|
||||||
item->Animation.Airborne = true;
|
item->Animation.IsAirborne = true;
|
||||||
item->Animation.Velocity = item->Animation.VerticalVelocity / 4;
|
item->Animation.Velocity = item->Animation.VerticalVelocity / 4;
|
||||||
item->Animation.VerticalVelocity = 0;
|
item->Animation.VerticalVelocity = 0;
|
||||||
lara->Control.WaterStatus = WaterStatus::Dry;
|
lara->Control.WaterStatus = WaterStatus::Dry;
|
||||||
|
@ -606,7 +605,7 @@ void LaraControl(ItemInfo* item, CollisionInfo* coll)
|
||||||
if (heightFromWater <= WADE_DEPTH)
|
if (heightFromWater <= WADE_DEPTH)
|
||||||
{
|
{
|
||||||
SetAnimation(item, LA_FALL_START);
|
SetAnimation(item, LA_FALL_START);
|
||||||
item->Animation.Airborne = true;
|
item->Animation.IsAirborne = true;
|
||||||
item->Animation.Velocity = item->Animation.VerticalVelocity / 4;
|
item->Animation.Velocity = item->Animation.VerticalVelocity / 4;
|
||||||
lara->Control.WaterStatus = WaterStatus::Dry;
|
lara->Control.WaterStatus = WaterStatus::Dry;
|
||||||
}
|
}
|
||||||
|
@ -634,7 +633,7 @@ void LaraControl(ItemInfo* item, CollisionInfo* coll)
|
||||||
ResetLaraLean(item);
|
ResetLaraLean(item);
|
||||||
ResetLaraFlex(item);
|
ResetLaraFlex(item);
|
||||||
item->Pose.Position.y += 1 - heightFromWater;
|
item->Pose.Position.y += 1 - heightFromWater;
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
item->Animation.VerticalVelocity = 0;
|
item->Animation.VerticalVelocity = 0;
|
||||||
lara->Control.WaterStatus = WaterStatus::TreadWater;
|
lara->Control.WaterStatus = WaterStatus::TreadWater;
|
||||||
|
|
||||||
|
|
|
@ -179,7 +179,7 @@ void lara_col_walk_forward(ItemInfo* item, CollisionInfo* coll)
|
||||||
auto* lara = GetLaraInfo(item);
|
auto* lara = GetLaraInfo(item);
|
||||||
|
|
||||||
lara->Control.MoveAngle = item->Pose.Orientation.y;
|
lara->Control.MoveAngle = item->Pose.Orientation.y;
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
item->Animation.VerticalVelocity = 0;
|
item->Animation.VerticalVelocity = 0;
|
||||||
coll->Setup.LowerFloorBound = STEPUP_HEIGHT;
|
coll->Setup.LowerFloorBound = STEPUP_HEIGHT;
|
||||||
coll->Setup.UpperFloorBound = -STEPUP_HEIGHT;
|
coll->Setup.UpperFloorBound = -STEPUP_HEIGHT;
|
||||||
|
@ -310,7 +310,7 @@ void lara_col_run_forward(ItemInfo* item, CollisionInfo* coll)
|
||||||
auto* lara = GetLaraInfo(item);
|
auto* lara = GetLaraInfo(item);
|
||||||
|
|
||||||
lara->Control.MoveAngle = item->Pose.Orientation.y;
|
lara->Control.MoveAngle = item->Pose.Orientation.y;
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
item->Animation.VerticalVelocity = 0;
|
item->Animation.VerticalVelocity = 0;
|
||||||
coll->Setup.LowerFloorBound = NO_LOWER_BOUND;
|
coll->Setup.LowerFloorBound = NO_LOWER_BOUND;
|
||||||
coll->Setup.UpperFloorBound = -STEPUP_HEIGHT;
|
coll->Setup.UpperFloorBound = -STEPUP_HEIGHT;
|
||||||
|
@ -688,7 +688,7 @@ void lara_col_idle(ItemInfo* item, CollisionInfo* coll)
|
||||||
|
|
||||||
bool isSwamp = TestEnvironment(ENV_FLAG_SWAMP, item);
|
bool isSwamp = TestEnvironment(ENV_FLAG_SWAMP, item);
|
||||||
|
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
item->Animation.VerticalVelocity = 0;
|
item->Animation.VerticalVelocity = 0;
|
||||||
lara->Control.MoveAngle = (item->Animation.Velocity >= 0) ? item->Pose.Orientation.y : (item->Pose.Orientation.y + ANGLE(180.0f));
|
lara->Control.MoveAngle = (item->Animation.Velocity >= 0) ? item->Pose.Orientation.y : (item->Pose.Orientation.y + ANGLE(180.0f));
|
||||||
coll->Setup.LowerFloorBound = isSwamp ? NO_LOWER_BOUND : STEPUP_HEIGHT;
|
coll->Setup.LowerFloorBound = isSwamp ? NO_LOWER_BOUND : STEPUP_HEIGHT;
|
||||||
|
@ -793,7 +793,7 @@ void lara_col_run_back(ItemInfo* item, CollisionInfo* coll)
|
||||||
|
|
||||||
lara->Control.MoveAngle = item->Pose.Orientation.y + ANGLE(180.0f);
|
lara->Control.MoveAngle = item->Pose.Orientation.y + ANGLE(180.0f);
|
||||||
item->Animation.VerticalVelocity = 0;
|
item->Animation.VerticalVelocity = 0;
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
coll->Setup.BlockFloorSlopeDown = true;
|
coll->Setup.BlockFloorSlopeDown = true;
|
||||||
coll->Setup.LowerFloorBound = NO_LOWER_BOUND;
|
coll->Setup.LowerFloorBound = NO_LOWER_BOUND;
|
||||||
coll->Setup.UpperFloorBound = -STEPUP_HEIGHT;
|
coll->Setup.UpperFloorBound = -STEPUP_HEIGHT;
|
||||||
|
@ -1383,7 +1383,7 @@ void lara_col_death(ItemInfo* item, CollisionInfo* coll)
|
||||||
{
|
{
|
||||||
auto* lara = GetLaraInfo(item);
|
auto* lara = GetLaraInfo(item);
|
||||||
|
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
lara->Control.MoveAngle = item->Pose.Orientation.y;
|
lara->Control.MoveAngle = item->Pose.Orientation.y;
|
||||||
coll->Setup.LowerFloorBound = STEPUP_HEIGHT;
|
coll->Setup.LowerFloorBound = STEPUP_HEIGHT;
|
||||||
coll->Setup.UpperFloorBound = -STEPUP_HEIGHT;
|
coll->Setup.UpperFloorBound = -STEPUP_HEIGHT;
|
||||||
|
@ -1508,7 +1508,7 @@ void lara_col_walk_back(ItemInfo* item, CollisionInfo* coll)
|
||||||
bool isSwamp = TestEnvironment(ENV_FLAG_SWAMP, item);
|
bool isSwamp = TestEnvironment(ENV_FLAG_SWAMP, item);
|
||||||
|
|
||||||
lara->Control.MoveAngle = item->Pose.Orientation.y + ANGLE(180.0f);
|
lara->Control.MoveAngle = item->Pose.Orientation.y + ANGLE(180.0f);
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
item->Animation.VerticalVelocity = 0;
|
item->Animation.VerticalVelocity = 0;
|
||||||
coll->Setup.LowerFloorBound = (lara->Control.WaterStatus == WaterStatus::Wade) ? NO_LOWER_BOUND : STEPUP_HEIGHT;
|
coll->Setup.LowerFloorBound = (lara->Control.WaterStatus == WaterStatus::Wade) ? NO_LOWER_BOUND : STEPUP_HEIGHT;
|
||||||
coll->Setup.UpperFloorBound = -STEPUP_HEIGHT;
|
coll->Setup.UpperFloorBound = -STEPUP_HEIGHT;
|
||||||
|
@ -1842,7 +1842,7 @@ void lara_col_step_right(ItemInfo* item, CollisionInfo* coll)
|
||||||
bool isSwamp = TestEnvironment(ENV_FLAG_SWAMP, item);
|
bool isSwamp = TestEnvironment(ENV_FLAG_SWAMP, item);
|
||||||
|
|
||||||
lara->Control.MoveAngle = item->Pose.Orientation.y + ANGLE(90.0f);
|
lara->Control.MoveAngle = item->Pose.Orientation.y + ANGLE(90.0f);
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
item->Animation.VerticalVelocity = 0;
|
item->Animation.VerticalVelocity = 0;
|
||||||
coll->Setup.LowerFloorBound = (lara->Control.WaterStatus == WaterStatus::Wade) ? NO_LOWER_BOUND : CLICK(0.8f);
|
coll->Setup.LowerFloorBound = (lara->Control.WaterStatus == WaterStatus::Wade) ? NO_LOWER_BOUND : CLICK(0.8f);
|
||||||
coll->Setup.UpperFloorBound = -CLICK(0.8f);
|
coll->Setup.UpperFloorBound = -CLICK(0.8f);
|
||||||
|
@ -1931,7 +1931,7 @@ void lara_col_step_left(ItemInfo* item, CollisionInfo* coll)
|
||||||
bool isSwamp = TestEnvironment(ENV_FLAG_SWAMP, item);
|
bool isSwamp = TestEnvironment(ENV_FLAG_SWAMP, item);
|
||||||
|
|
||||||
lara->Control.MoveAngle = item->Pose.Orientation.y - ANGLE(90.0f);
|
lara->Control.MoveAngle = item->Pose.Orientation.y - ANGLE(90.0f);
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
item->Animation.VerticalVelocity = 0;
|
item->Animation.VerticalVelocity = 0;
|
||||||
coll->Setup.LowerFloorBound = (lara->Control.WaterStatus == WaterStatus::Wade) ? NO_LOWER_BOUND : CLICK(0.8f);
|
coll->Setup.LowerFloorBound = (lara->Control.WaterStatus == WaterStatus::Wade) ? NO_LOWER_BOUND : CLICK(0.8f);
|
||||||
coll->Setup.UpperFloorBound = -CLICK(0.8f);
|
coll->Setup.UpperFloorBound = -CLICK(0.8f);
|
||||||
|
@ -2003,7 +2003,7 @@ void lara_col_roll_back(ItemInfo* item, CollisionInfo* coll)
|
||||||
auto* lara = GetLaraInfo(item);
|
auto* lara = GetLaraInfo(item);
|
||||||
|
|
||||||
lara->Control.MoveAngle = item->Pose.Orientation.y + ANGLE(180.0f);
|
lara->Control.MoveAngle = item->Pose.Orientation.y + ANGLE(180.0f);
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
item->Animation.VerticalVelocity = 0;
|
item->Animation.VerticalVelocity = 0;
|
||||||
coll->Setup.LowerFloorBound = NO_LOWER_BOUND;
|
coll->Setup.LowerFloorBound = NO_LOWER_BOUND;
|
||||||
coll->Setup.UpperFloorBound = -STEPUP_HEIGHT;
|
coll->Setup.UpperFloorBound = -STEPUP_HEIGHT;
|
||||||
|
@ -2072,7 +2072,7 @@ void lara_col_roll_forward(ItemInfo* item, CollisionInfo* coll)
|
||||||
auto* lara = GetLaraInfo(item);
|
auto* lara = GetLaraInfo(item);
|
||||||
|
|
||||||
lara->Control.MoveAngle = item->Pose.Orientation.y;
|
lara->Control.MoveAngle = item->Pose.Orientation.y;
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
item->Animation.VerticalVelocity = 0;
|
item->Animation.VerticalVelocity = 0;
|
||||||
coll->Setup.LowerFloorBound = NO_LOWER_BOUND;
|
coll->Setup.LowerFloorBound = NO_LOWER_BOUND;
|
||||||
coll->Setup.UpperFloorBound = -STEPUP_HEIGHT;
|
coll->Setup.UpperFloorBound = -STEPUP_HEIGHT;
|
||||||
|
|
|
@ -69,7 +69,7 @@ void LaraCheatyBits(ItemInfo* item)
|
||||||
{
|
{
|
||||||
SetAnimation(item, LA_DOZY);
|
SetAnimation(item, LA_DOZY);
|
||||||
item->Animation.VerticalVelocity = 30;
|
item->Animation.VerticalVelocity = 30;
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
item->Pose.Orientation.x = ANGLE(30.0f);
|
item->Pose.Orientation.x = ANGLE(30.0f);
|
||||||
item->HitPoints = LARA_HEALTH_MAX;
|
item->HitPoints = LARA_HEALTH_MAX;
|
||||||
|
|
||||||
|
|
|
@ -982,7 +982,7 @@ bool LaraCheckForLetGo(ItemInfo* item, CollisionInfo* coll)
|
||||||
auto* lara = GetLaraInfo(item);
|
auto* lara = GetLaraInfo(item);
|
||||||
|
|
||||||
item->Animation.VerticalVelocity = 0;
|
item->Animation.VerticalVelocity = 0;
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
|
|
||||||
if (TrInput & IN_ACTION && item->HitPoints > 0 || item->Animation.AnimNumber == LA_ONWATER_TO_LADDER) // Can't let go on this anim
|
if (TrInput & IN_ACTION && item->HitPoints > 0 || item->Animation.AnimNumber == LA_ONWATER_TO_LADDER) // Can't let go on this anim
|
||||||
return false;
|
return false;
|
||||||
|
@ -993,7 +993,7 @@ bool LaraCheckForLetGo(ItemInfo* item, CollisionInfo* coll)
|
||||||
|
|
||||||
item->Animation.Velocity = 2;
|
item->Animation.Velocity = 2;
|
||||||
item->Animation.VerticalVelocity = 1;
|
item->Animation.VerticalVelocity = 1;
|
||||||
item->Animation.Airborne = true;
|
item->Animation.IsAirborne = true;
|
||||||
lara->Control.HandStatus = HandStatus::Free;
|
lara->Control.HandStatus = HandStatus::Free;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -158,7 +158,7 @@ bool LaraDeflectEdgeCrawl(ItemInfo* item, CollisionInfo* coll)
|
||||||
ShiftItem(item, coll);
|
ShiftItem(item, coll);
|
||||||
|
|
||||||
item->Animation.Velocity = 0;
|
item->Animation.Velocity = 0;
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,7 +189,7 @@ bool LaraDeflectEdgeMonkey(ItemInfo* item, CollisionInfo* coll)
|
||||||
|
|
||||||
item->Animation.TargetState = LS_MONKEY_IDLE;
|
item->Animation.TargetState = LS_MONKEY_IDLE;
|
||||||
item->Animation.Velocity = 0;
|
item->Animation.Velocity = 0;
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -385,7 +385,7 @@ void LaraResetGravityStatus(ItemInfo* item, CollisionInfo* coll)
|
||||||
if (coll->Middle.Floor <= STEPUP_HEIGHT)
|
if (coll->Middle.Floor <= STEPUP_HEIGHT)
|
||||||
{
|
{
|
||||||
item->Animation.VerticalVelocity = 0;
|
item->Animation.VerticalVelocity = 0;
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -686,7 +686,7 @@ bool TestLaraHitCeiling(CollisionInfo* coll)
|
||||||
|
|
||||||
void SetLaraHitCeiling(ItemInfo* item, CollisionInfo* coll)
|
void SetLaraHitCeiling(ItemInfo* item, CollisionInfo* coll)
|
||||||
{
|
{
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
item->Animation.Velocity = 0;
|
item->Animation.Velocity = 0;
|
||||||
item->Animation.VerticalVelocity = 0;
|
item->Animation.VerticalVelocity = 0;
|
||||||
item->Pose.Position = coll->Setup.OldPosition;
|
item->Pose.Position = coll->Setup.OldPosition;
|
||||||
|
|
|
@ -109,7 +109,7 @@ void lara_col_crouch_idle(ItemInfo* item, CollisionInfo* coll)
|
||||||
auto* lara = GetLaraInfo(item);
|
auto* lara = GetLaraInfo(item);
|
||||||
|
|
||||||
item->Animation.VerticalVelocity = 0;
|
item->Animation.VerticalVelocity = 0;
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
lara->Control.KeepLow = TestLaraKeepLow(item, coll);
|
lara->Control.KeepLow = TestLaraKeepLow(item, coll);
|
||||||
lara->Control.IsLow = true;
|
lara->Control.IsLow = true;
|
||||||
lara->Control.MoveAngle = item->Pose.Orientation.y;
|
lara->Control.MoveAngle = item->Pose.Orientation.y;
|
||||||
|
@ -172,7 +172,7 @@ void lara_col_crouch_roll(ItemInfo* item, CollisionInfo* coll)
|
||||||
auto* lara = GetLaraInfo(item);
|
auto* lara = GetLaraInfo(item);
|
||||||
|
|
||||||
item->Animation.VerticalVelocity = 0;
|
item->Animation.VerticalVelocity = 0;
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
lara->Control.KeepLow = TestLaraKeepLow(item, coll);
|
lara->Control.KeepLow = TestLaraKeepLow(item, coll);
|
||||||
lara->Control.IsLow = true;
|
lara->Control.IsLow = true;
|
||||||
lara->Control.MoveAngle = item->Pose.Orientation.y;
|
lara->Control.MoveAngle = item->Pose.Orientation.y;
|
||||||
|
@ -185,7 +185,7 @@ void lara_col_crouch_roll(ItemInfo* item, CollisionInfo* coll)
|
||||||
GetCollisionInfo(coll, item);
|
GetCollisionInfo(coll, item);
|
||||||
|
|
||||||
// TODO: With sufficient speed, Lara can still roll off ledges. This is particularly a problem in the uncommon scenario where
|
// TODO: With sufficient speed, Lara can still roll off ledges. This is particularly a problem in the uncommon scenario where
|
||||||
// she becomes Airborne within a crawlspace; collision handling will push her back very rapidly and potentially cause a softlock. @Sezz 2021.11.02
|
// she becomes IsAirborne within a crawlspace; collision handling will push her back very rapidly and potentially cause a softlock. @Sezz 2021.11.02
|
||||||
if (LaraDeflectEdgeCrawl(item, coll))
|
if (LaraDeflectEdgeCrawl(item, coll))
|
||||||
item->Pose.Position = coll->Setup.OldPosition;
|
item->Pose.Position = coll->Setup.OldPosition;
|
||||||
|
|
||||||
|
@ -472,7 +472,7 @@ void lara_col_crawl_idle(ItemInfo* item, CollisionInfo* coll)
|
||||||
auto* lara = GetLaraInfo(item);
|
auto* lara = GetLaraInfo(item);
|
||||||
|
|
||||||
item->Animation.VerticalVelocity = 0;
|
item->Animation.VerticalVelocity = 0;
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
lara->Control.KeepLow = TestLaraKeepLow(item, coll);
|
lara->Control.KeepLow = TestLaraKeepLow(item, coll);
|
||||||
lara->Control.IsLow = true;
|
lara->Control.IsLow = true;
|
||||||
lara->Control.MoveAngle = item->Pose.Orientation.y;
|
lara->Control.MoveAngle = item->Pose.Orientation.y;
|
||||||
|
@ -561,7 +561,7 @@ void lara_col_crawl_forward(ItemInfo* item, CollisionInfo* coll)
|
||||||
auto* lara = GetLaraInfo(item);
|
auto* lara = GetLaraInfo(item);
|
||||||
|
|
||||||
item->Animation.VerticalVelocity = 0;
|
item->Animation.VerticalVelocity = 0;
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
lara->Control.KeepLow = TestLaraKeepLow(item, coll);
|
lara->Control.KeepLow = TestLaraKeepLow(item, coll);
|
||||||
lara->Control.IsLow = true;
|
lara->Control.IsLow = true;
|
||||||
lara->Control.MoveAngle = item->Pose.Orientation.y;
|
lara->Control.MoveAngle = item->Pose.Orientation.y;
|
||||||
|
@ -649,7 +649,7 @@ void lara_col_crawl_back(ItemInfo* item, CollisionInfo* coll)
|
||||||
auto* lara = GetLaraInfo(item);
|
auto* lara = GetLaraInfo(item);
|
||||||
|
|
||||||
item->Animation.VerticalVelocity = 0;
|
item->Animation.VerticalVelocity = 0;
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
lara->Control.KeepLow = TestLaraKeepLow(item, coll);
|
lara->Control.KeepLow = TestLaraKeepLow(item, coll);
|
||||||
lara->Control.IsLow = true;
|
lara->Control.IsLow = true;
|
||||||
lara->Control.MoveAngle = item->Pose.Orientation.y + ANGLE(180.0f);
|
lara->Control.MoveAngle = item->Pose.Orientation.y + ANGLE(180.0f);
|
||||||
|
@ -859,7 +859,7 @@ void lara_col_crawl_to_hang(ItemInfo* item, CollisionInfo* coll)
|
||||||
GetCollisionInfo(coll, item);
|
GetCollisionInfo(coll, item);
|
||||||
lara->Control.HandStatus = HandStatus::Busy;
|
lara->Control.HandStatus = HandStatus::Busy;
|
||||||
item->Pose.Position.y += coll->Front.Floor - GetBoundsAccurate(item)->Y1 - 20;
|
item->Pose.Position.y += coll->Front.Floor - GetBoundsAccurate(item)->Y1 - 20;
|
||||||
item->Animation.Airborne = true;
|
item->Animation.IsAirborne = true;
|
||||||
item->Animation.Velocity = 2;
|
item->Animation.Velocity = 2;
|
||||||
item->Animation.VerticalVelocity = 1;
|
item->Animation.VerticalVelocity = 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -378,7 +378,7 @@ void DoFlareInHand(ItemInfo* laraItem, int flareLife)
|
||||||
if (lara->Flare.Life >= FLARE_LIFE_MAX)
|
if (lara->Flare.Life >= FLARE_LIFE_MAX)
|
||||||
{
|
{
|
||||||
// Prevent Lara from intercepting reach/jump states with flare throws.
|
// Prevent Lara from intercepting reach/jump states with flare throws.
|
||||||
if (laraItem->Animation.Airborne ||
|
if (laraItem->Animation.IsAirborne ||
|
||||||
laraItem->Animation.TargetState == LS_JUMP_PREPARE ||
|
laraItem->Animation.TargetState == LS_JUMP_PREPARE ||
|
||||||
laraItem->Animation.TargetState == LS_JUMP_FORWARD)
|
laraItem->Animation.TargetState == LS_JUMP_FORWARD)
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -49,7 +49,7 @@ void lara_col_hang(ItemInfo* item, CollisionInfo* coll)
|
||||||
{
|
{
|
||||||
auto* lara = GetLaraInfo(item);
|
auto* lara = GetLaraInfo(item);
|
||||||
|
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
item->Animation.VerticalVelocity = 0;
|
item->Animation.VerticalVelocity = 0;
|
||||||
|
|
||||||
if (item->Animation.AnimNumber == LA_REACH_TO_HANG ||
|
if (item->Animation.AnimNumber == LA_REACH_TO_HANG ||
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
#include "Objects/TR3/Vehicles/big_gun.h"
|
#include "Objects/TR3/Vehicles/big_gun.h"
|
||||||
#include "Objects/TR3/Vehicles/kayak.h"
|
#include "Objects/TR3/Vehicles/kayak.h"
|
||||||
#include "Objects/TR3/Vehicles/minecart.h"
|
#include "Objects/TR3/Vehicles/minecart.h"
|
||||||
#include "Objects/TR3/Vehicles/quad.h"
|
#include "Objects/TR3/Vehicles/quad_bike.h"
|
||||||
#include "Objects/TR3/Vehicles/upv.h"
|
#include "Objects/TR3/Vehicles/upv.h"
|
||||||
#include "Objects/TR4/Vehicles/jeep.h"
|
#include "Objects/TR4/Vehicles/jeep.h"
|
||||||
#include "Objects/TR4/Vehicles/motorbike.h"
|
#include "Objects/TR4/Vehicles/motorbike.h"
|
||||||
|
@ -346,6 +346,7 @@ short ModulateLaraTurnRate(short turnRate, short accelRate, short minTurnRate, s
|
||||||
return newTurnRate * sign;
|
return newTurnRate * sign;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Make these two functions methods of LaraInfo someday. @Sezz 2022.06.26
|
||||||
void ModulateLaraTurnRateX(ItemInfo* item, short accelRate, short minTurnRate, short maxTurnRate)
|
void ModulateLaraTurnRateX(ItemInfo* item, short accelRate, short minTurnRate, short maxTurnRate)
|
||||||
{
|
{
|
||||||
auto* lara = GetLaraInfo(item);
|
auto* lara = GetLaraInfo(item);
|
||||||
|
@ -358,7 +359,7 @@ void ModulateLaraTurnRateY(ItemInfo* item, short accelRate, short minTurnRate, s
|
||||||
auto* lara = GetLaraInfo(item);
|
auto* lara = GetLaraInfo(item);
|
||||||
|
|
||||||
float axisCoeff = AxisMap[InputAxis::MoveHorizontal];
|
float axisCoeff = AxisMap[InputAxis::MoveHorizontal];
|
||||||
if (item->Animation.Airborne)
|
if (item->Animation.IsAirborne)
|
||||||
{
|
{
|
||||||
int sign = std::copysign(1, axisCoeff);
|
int sign = std::copysign(1, axisCoeff);
|
||||||
axisCoeff = std::min(1.2f, abs(axisCoeff)) * sign;
|
axisCoeff = std::min(1.2f, abs(axisCoeff)) * sign;
|
||||||
|
@ -627,7 +628,7 @@ void SetLaraVault(ItemInfo* item, CollisionInfo* coll, VaultTestResult vaultResu
|
||||||
|
|
||||||
void SetLaraLand(ItemInfo* item, CollisionInfo* coll)
|
void SetLaraLand(ItemInfo* item, CollisionInfo* coll)
|
||||||
{
|
{
|
||||||
//item->Airborne = false; // TODO: Removing this avoids an unusual landing bug Core had worked around in an obscure way. I hope to find a proper solution. @Sezz 2022.02.18
|
//item->IsAirborne = false; // TODO: Removing this avoids an unusual landing bug Core had worked around in an obscure way. I hope to find a proper solution. @Sezz 2022.02.18
|
||||||
item->Animation.Velocity = 0;
|
item->Animation.Velocity = 0;
|
||||||
item->Animation.VerticalVelocity = 0;
|
item->Animation.VerticalVelocity = 0;
|
||||||
|
|
||||||
|
@ -637,14 +638,14 @@ void SetLaraLand(ItemInfo* item, CollisionInfo* coll)
|
||||||
void SetLaraFallAnimation(ItemInfo* item)
|
void SetLaraFallAnimation(ItemInfo* item)
|
||||||
{
|
{
|
||||||
SetAnimation(item, LA_FALL_START);
|
SetAnimation(item, LA_FALL_START);
|
||||||
item->Animation.Airborne = true;
|
item->Animation.IsAirborne = true;
|
||||||
item->Animation.VerticalVelocity = 0;
|
item->Animation.VerticalVelocity = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetLaraFallBackAnimation(ItemInfo* item)
|
void SetLaraFallBackAnimation(ItemInfo* item)
|
||||||
{
|
{
|
||||||
SetAnimation(item, LA_FALL_BACK);
|
SetAnimation(item, LA_FALL_BACK);
|
||||||
item->Animation.Airborne = true;
|
item->Animation.IsAirborne = true;
|
||||||
item->Animation.VerticalVelocity = 0;
|
item->Animation.VerticalVelocity = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -662,7 +663,7 @@ void SetLaraMonkeyRelease(ItemInfo* item)
|
||||||
{
|
{
|
||||||
auto* lara = GetLaraInfo(item);
|
auto* lara = GetLaraInfo(item);
|
||||||
|
|
||||||
item->Animation.Airborne = true;
|
item->Animation.IsAirborne = true;
|
||||||
item->Animation.Velocity = 2;
|
item->Animation.Velocity = 2;
|
||||||
item->Animation.VerticalVelocity = 1;
|
item->Animation.VerticalVelocity = 1;
|
||||||
lara->Control.HandStatus = HandStatus::Free;
|
lara->Control.HandStatus = HandStatus::Free;
|
||||||
|
@ -760,7 +761,7 @@ void SetLaraCornerAnimation(ItemInfo* item, CollisionInfo* coll, bool flip)
|
||||||
if (item->HitPoints <= 0)
|
if (item->HitPoints <= 0)
|
||||||
{
|
{
|
||||||
SetAnimation(item, LA_FALL_START);
|
SetAnimation(item, LA_FALL_START);
|
||||||
item->Animation.Airborne = true;
|
item->Animation.IsAirborne = true;
|
||||||
item->Animation.Velocity = 2;
|
item->Animation.Velocity = 2;
|
||||||
item->Animation.VerticalVelocity = 1;
|
item->Animation.VerticalVelocity = 1;
|
||||||
item->Pose.Position.y += CLICK(1);
|
item->Pose.Position.y += CLICK(1);
|
||||||
|
@ -865,14 +866,14 @@ void ResetLaraFlex(ItemInfo* item, float rate)
|
||||||
lara->ExtraTorsoRot.z = 0;
|
lara->ExtraTorsoRot.z = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RumbleLaraHealthCondition(ItemInfo* lara)
|
void RumbleLaraHealthCondition(ItemInfo* item)
|
||||||
{
|
{
|
||||||
auto* info = GetLaraInfo(lara);
|
auto* lara = GetLaraInfo(item);
|
||||||
|
|
||||||
if (lara->HitPoints > LARA_HEALTH_CRITICAL && !info->PoisonPotency)
|
if (item->HitPoints > LARA_HEALTH_CRITICAL && !lara->PoisonPotency)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool pulse = (GlobalCounter & 0x1F) % 0x1F == 0;
|
bool doPulse = (GlobalCounter & 0x0F) % 0x0F == 1;
|
||||||
if (pulse)
|
if (doPulse)
|
||||||
Rumble(0.2f, 0.1f);
|
Rumble(0.2f, 0.1f);
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,4 +51,4 @@ void SetLaraSwimDiveAnimation(ItemInfo* item);
|
||||||
void ResetLaraLean(ItemInfo* item, float rate = 1.0f, bool resetRoll = true, bool resetPitch = true);
|
void ResetLaraLean(ItemInfo* item, float rate = 1.0f, bool resetRoll = true, bool resetPitch = true);
|
||||||
void ResetLaraFlex(ItemInfo* item, float rate = 1.0f);
|
void ResetLaraFlex(ItemInfo* item, float rate = 1.0f);
|
||||||
|
|
||||||
void RumbleLaraHealthCondition(ItemInfo* lara);
|
void RumbleLaraHealthCondition(ItemInfo* item);
|
||||||
|
|
|
@ -161,7 +161,7 @@ void lara_col_freefall(ItemInfo* item, CollisionInfo* coll)
|
||||||
{
|
{
|
||||||
auto* lara = GetLaraInfo(item);
|
auto* lara = GetLaraInfo(item);
|
||||||
|
|
||||||
item->Animation.Airborne = true;
|
item->Animation.IsAirborne = true;
|
||||||
coll->Setup.LowerFloorBound = NO_LOWER_BOUND;
|
coll->Setup.LowerFloorBound = NO_LOWER_BOUND;
|
||||||
coll->Setup.UpperFloorBound = -STEPUP_HEIGHT;
|
coll->Setup.UpperFloorBound = -STEPUP_HEIGHT;
|
||||||
coll->Setup.LowerCeilingBound = BAD_JUMP_CEILING;
|
coll->Setup.LowerCeilingBound = BAD_JUMP_CEILING;
|
||||||
|
@ -224,7 +224,7 @@ void lara_col_reach(ItemInfo* item, CollisionInfo* coll)
|
||||||
auto* lara = GetLaraInfo(item);
|
auto* lara = GetLaraInfo(item);
|
||||||
|
|
||||||
if (lara->Control.Rope.Ptr == -1)
|
if (lara->Control.Rope.Ptr == -1)
|
||||||
item->Animation.Airborne = true;
|
item->Animation.IsAirborne = true;
|
||||||
|
|
||||||
lara->Control.MoveAngle = item->Pose.Orientation.y;
|
lara->Control.MoveAngle = item->Pose.Orientation.y;
|
||||||
|
|
||||||
|
|
|
@ -126,7 +126,7 @@ void lara_col_monkey_idle(ItemInfo* item, CollisionInfo* coll)
|
||||||
auto* lara = GetLaraInfo(item);
|
auto* lara = GetLaraInfo(item);
|
||||||
|
|
||||||
lara->Control.MoveAngle = item->Pose.Orientation.y;
|
lara->Control.MoveAngle = item->Pose.Orientation.y;
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
coll->Setup.LowerFloorBound = NO_LOWER_BOUND;
|
coll->Setup.LowerFloorBound = NO_LOWER_BOUND;
|
||||||
coll->Setup.UpperFloorBound = 0;
|
coll->Setup.UpperFloorBound = 0;
|
||||||
coll->Setup.LowerCeilingBound = CLICK(1.25f);
|
coll->Setup.LowerCeilingBound = CLICK(1.25f);
|
||||||
|
|
|
@ -277,7 +277,7 @@ void lara_as_horizontal_bar_leap(ItemInfo* item, CollisionInfo* coll)
|
||||||
auto* lara = GetLaraInfo(item);
|
auto* lara = GetLaraInfo(item);
|
||||||
auto* barItem = &g_Level.Items[lara->InteractedItem];
|
auto* barItem = &g_Level.Items[lara->InteractedItem];
|
||||||
|
|
||||||
item->Animation.Airborne = true;
|
item->Animation.IsAirborne = true;
|
||||||
|
|
||||||
if (item->Animation.FrameNumber == g_Level.Anims[item->Animation.AnimNumber].frameBase)
|
if (item->Animation.FrameNumber == g_Level.Anims[item->Animation.AnimNumber].frameBase)
|
||||||
{
|
{
|
||||||
|
@ -1062,7 +1062,7 @@ void lara_as_zip_line(ItemInfo* item, CollisionInfo* coll)
|
||||||
|
|
||||||
item->Animation.Velocity = 100;
|
item->Animation.Velocity = 100;
|
||||||
item->Animation.VerticalVelocity = 40;
|
item->Animation.VerticalVelocity = 40;
|
||||||
item->Animation.Airborne = true;
|
item->Animation.IsAirborne = true;
|
||||||
lara->Control.MoveAngle = item->Pose.Orientation.y;
|
lara->Control.MoveAngle = item->Pose.Orientation.y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -457,7 +457,7 @@ void lara_as_slopeclimb(ItemInfo* item, CollisionInfo* coll)
|
||||||
|
|
||||||
void lara_as_slopefall(ItemInfo* item, CollisionInfo* coll)
|
void lara_as_slopefall(ItemInfo* item, CollisionInfo* coll)
|
||||||
{
|
{
|
||||||
item->Animation.Airborne = true;
|
item->Animation.IsAirborne = true;
|
||||||
|
|
||||||
if (GlobalCounter % 2)
|
if (GlobalCounter % 2)
|
||||||
item->Pose.Orientation.x--;
|
item->Pose.Orientation.x--;
|
||||||
|
@ -492,7 +492,7 @@ void lara_col_slopehang(ItemInfo* item, CollisionInfo* coll)
|
||||||
if (!(TrInput & IN_ACTION))
|
if (!(TrInput & IN_ACTION))
|
||||||
{
|
{
|
||||||
SetAnimation(item, LA_OVERHANG_HANG_DROP);
|
SetAnimation(item, LA_OVERHANG_HANG_DROP);
|
||||||
item->Animation.Airborne = true;
|
item->Animation.IsAirborne = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -92,7 +92,7 @@ void lara_col_slide_forward(ItemInfo* item, CollisionInfo* coll)
|
||||||
{
|
{
|
||||||
auto* lara = GetLaraInfo(item);
|
auto* lara = GetLaraInfo(item);
|
||||||
|
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
lara->Control.MoveAngle = item->Pose.Orientation.y;
|
lara->Control.MoveAngle = item->Pose.Orientation.y;
|
||||||
coll->Setup.Height = LARA_HEIGHT_CRAWL; // HACK: Behaves better with clamps.
|
coll->Setup.Height = LARA_HEIGHT_CRAWL; // HACK: Behaves better with clamps.
|
||||||
coll->Setup.LowerFloorBound = NO_LOWER_BOUND;
|
coll->Setup.LowerFloorBound = NO_LOWER_BOUND;
|
||||||
|
@ -197,7 +197,7 @@ void lara_col_slide_back(ItemInfo* item, CollisionInfo* coll)
|
||||||
{
|
{
|
||||||
auto* lara = GetLaraInfo(item);
|
auto* lara = GetLaraInfo(item);
|
||||||
|
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
lara->Control.MoveAngle = item->Pose.Orientation.y + ANGLE(180.0f);
|
lara->Control.MoveAngle = item->Pose.Orientation.y + ANGLE(180.0f);
|
||||||
coll->Setup.Height = LARA_HEIGHT_CRAWL; // HACK: Behaves better with clamps.
|
coll->Setup.Height = LARA_HEIGHT_CRAWL; // HACK: Behaves better with clamps.
|
||||||
coll->Setup.LowerFloorBound = NO_LOWER_BOUND;
|
coll->Setup.LowerFloorBound = NO_LOWER_BOUND;
|
||||||
|
|
|
@ -844,7 +844,7 @@ enum class WeaponAmmoType
|
||||||
Ammo2,
|
Ammo2,
|
||||||
Ammo3,
|
Ammo3,
|
||||||
|
|
||||||
NumAmmos
|
NumAmmoTypes
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class LaraWeaponType
|
enum class LaraWeaponType
|
||||||
|
@ -868,17 +868,17 @@ enum class LaraWeaponType
|
||||||
|
|
||||||
enum LaraWeaponTypeCarried
|
enum LaraWeaponTypeCarried
|
||||||
{
|
{
|
||||||
WTYPE_MISSING = 0x0,
|
WTYPE_MISSING = 0,
|
||||||
WTYPE_PRESENT = 0x1,
|
WTYPE_PRESENT = (1 << 0),
|
||||||
WTYPE_SILENCER = 0x2,
|
WTYPE_SILENCER = (1 << 1),
|
||||||
WTYPE_LASERSIGHT = 0x4,
|
WTYPE_LASERSIGHT = (1 << 2),
|
||||||
WTYPE_AMMO_1 = 0x8,
|
WTYPE_AMMO_1 = (1 << 3),
|
||||||
WTYPE_AMMO_2 = 0x10,
|
WTYPE_AMMO_2 = (1 << 4),
|
||||||
WTYPE_AMMO_3 = 0x20,
|
WTYPE_AMMO_3 = (1 << 5),
|
||||||
WTYPE_MASK_AMMO = WTYPE_AMMO_1 | WTYPE_AMMO_2 | WTYPE_AMMO_3,
|
WTYPE_MASK_AMMO = WTYPE_AMMO_1 | WTYPE_AMMO_2 | WTYPE_AMMO_3,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class HolsterSlot : int
|
enum class HolsterSlot
|
||||||
{
|
{
|
||||||
Empty = ID_LARA_HOLSTERS,
|
Empty = ID_LARA_HOLSTERS,
|
||||||
Pistols = ID_LARA_HOLSTERS_PISTOLS,
|
Pistols = ID_LARA_HOLSTERS_PISTOLS,
|
||||||
|
@ -889,7 +889,7 @@ enum class HolsterSlot : int
|
||||||
Harpoon = ID_HARPOON_ANIM,
|
Harpoon = ID_HARPOON_ANIM,
|
||||||
Crowssbow = ID_CROSSBOW_ANIM,
|
Crowssbow = ID_CROSSBOW_ANIM,
|
||||||
GrenadeLauncher = ID_GRENADE_ANIM,
|
GrenadeLauncher = ID_GRENADE_ANIM,
|
||||||
RocketLauncher = ID_ROCKET_ANIM,
|
RocketLauncher = ID_ROCKET_ANIM
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Unused.
|
// TODO: Unused.
|
||||||
|
@ -1064,7 +1064,7 @@ struct HolsterInfo
|
||||||
struct CarriedWeaponInfo
|
struct CarriedWeaponInfo
|
||||||
{
|
{
|
||||||
bool Present;
|
bool Present;
|
||||||
Ammo Ammo[(int)WeaponAmmoType::NumAmmos];
|
Ammo Ammo[(int)WeaponAmmoType::NumAmmoTypes];
|
||||||
WeaponAmmoType SelectedAmmo; // WeaponAmmoType_enum
|
WeaponAmmoType SelectedAmmo; // WeaponAmmoType_enum
|
||||||
bool HasLasersight; // TODO: Duplicated in LaraInventoryData.
|
bool HasLasersight; // TODO: Duplicated in LaraInventoryData.
|
||||||
bool HasSilencer; // TODO: Duplicated in LaraInventoryData.
|
bool HasSilencer; // TODO: Duplicated in LaraInventoryData.
|
||||||
|
@ -1095,6 +1095,7 @@ struct TorchData
|
||||||
bool IsLit;
|
bool IsLit;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO: Someone's abandoned dairy feature.
|
||||||
#define MaxDiaryPages 64
|
#define MaxDiaryPages 64
|
||||||
#define MaxStringsPerPage 8
|
#define MaxStringsPerPage 8
|
||||||
|
|
||||||
|
|
|
@ -177,7 +177,7 @@ bool TestLaraHang(ItemInfo* item, CollisionInfo* coll)
|
||||||
{
|
{
|
||||||
SetAnimation(item, LA_FALL_START);
|
SetAnimation(item, LA_FALL_START);
|
||||||
item->Pose.Position.y += CLICK(1);
|
item->Pose.Position.y += CLICK(1);
|
||||||
item->Animation.Airborne = true;
|
item->Animation.IsAirborne = true;
|
||||||
item->Animation.Velocity = 2;
|
item->Animation.Velocity = 2;
|
||||||
item->Animation.VerticalVelocity = 1;
|
item->Animation.VerticalVelocity = 1;
|
||||||
lara->Control.HandStatus = HandStatus::Free;
|
lara->Control.HandStatus = HandStatus::Free;
|
||||||
|
@ -248,7 +248,7 @@ bool TestLaraHang(ItemInfo* item, CollisionInfo* coll)
|
||||||
item->Pose.Position.x += coll->Shift.x;
|
item->Pose.Position.x += coll->Shift.x;
|
||||||
item->Pose.Position.y += GetBoundsAccurate(item)->Y2 * 1.8f;
|
item->Pose.Position.y += GetBoundsAccurate(item)->Y2 * 1.8f;
|
||||||
item->Pose.Position.z += coll->Shift.z;
|
item->Pose.Position.z += coll->Shift.z;
|
||||||
item->Animation.Airborne = true;
|
item->Animation.IsAirborne = true;
|
||||||
item->Animation.Velocity = 2;
|
item->Animation.Velocity = 2;
|
||||||
item->Animation.VerticalVelocity = 1;
|
item->Animation.VerticalVelocity = 1;
|
||||||
lara->Control.HandStatus = HandStatus::Free;
|
lara->Control.HandStatus = HandStatus::Free;
|
||||||
|
@ -271,7 +271,7 @@ bool TestLaraHangJump(ItemInfo* item, CollisionInfo* coll)
|
||||||
ResetLaraFlex(item);
|
ResetLaraFlex(item);
|
||||||
item->Animation.Velocity = 0;
|
item->Animation.Velocity = 0;
|
||||||
item->Animation.VerticalVelocity = 0;
|
item->Animation.VerticalVelocity = 0;
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
item->Pose.Position.y += coll->Middle.Ceiling + (LARA_HEIGHT_MONKEY - coll->Setup.Height);
|
item->Pose.Position.y += coll->Middle.Ceiling + (LARA_HEIGHT_MONKEY - coll->Setup.Height);
|
||||||
lara->Control.HandStatus = HandStatus::Busy;
|
lara->Control.HandStatus = HandStatus::Busy;
|
||||||
return true;
|
return true;
|
||||||
|
@ -318,9 +318,9 @@ bool TestLaraHangJump(ItemInfo* item, CollisionInfo* coll)
|
||||||
else
|
else
|
||||||
SnapItemToLedge(item, coll, 0.2f);
|
SnapItemToLedge(item, coll, 0.2f);
|
||||||
|
|
||||||
|
item->Animation.IsAirborne = true;
|
||||||
item->Animation.Velocity = 2;
|
item->Animation.Velocity = 2;
|
||||||
item->Animation.VerticalVelocity = 1;
|
item->Animation.VerticalVelocity = 1;
|
||||||
item->Animation.Airborne = true;
|
|
||||||
lara->Control.TurnRate = 0;
|
lara->Control.TurnRate = 0;
|
||||||
lara->Control.HandStatus = HandStatus::Busy;
|
lara->Control.HandStatus = HandStatus::Busy;
|
||||||
return true;
|
return true;
|
||||||
|
@ -338,7 +338,7 @@ bool TestLaraHangJumpUp(ItemInfo* item, CollisionInfo* coll)
|
||||||
SetAnimation(item, LA_JUMP_UP_TO_MONKEY);
|
SetAnimation(item, LA_JUMP_UP_TO_MONKEY);
|
||||||
item->Animation.Velocity = 0;
|
item->Animation.Velocity = 0;
|
||||||
item->Animation.VerticalVelocity = 0;
|
item->Animation.VerticalVelocity = 0;
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
item->Pose.Position.y += coll->Middle.Ceiling + (LARA_HEIGHT_MONKEY - coll->Setup.Height);
|
item->Pose.Position.y += coll->Middle.Ceiling + (LARA_HEIGHT_MONKEY - coll->Setup.Height);
|
||||||
lara->Control.HandStatus = HandStatus::Busy;
|
lara->Control.HandStatus = HandStatus::Busy;
|
||||||
return true;
|
return true;
|
||||||
|
@ -374,7 +374,7 @@ bool TestLaraHangJumpUp(ItemInfo* item, CollisionInfo* coll)
|
||||||
|
|
||||||
item->Animation.Velocity = 0;
|
item->Animation.Velocity = 0;
|
||||||
item->Animation.VerticalVelocity = 0;
|
item->Animation.VerticalVelocity = 0;
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
lara->Control.HandStatus = HandStatus::Busy;
|
lara->Control.HandStatus = HandStatus::Busy;
|
||||||
lara->ExtraTorsoRot = Vector3Shrt();
|
lara->ExtraTorsoRot = Vector3Shrt();
|
||||||
return true;
|
return true;
|
||||||
|
@ -908,7 +908,7 @@ bool TestLaraWaterStepOut(ItemInfo* item, CollisionInfo* coll)
|
||||||
item->Pose.Orientation.z = 0;
|
item->Pose.Orientation.z = 0;
|
||||||
item->Animation.Velocity = 0;
|
item->Animation.Velocity = 0;
|
||||||
item->Animation.VerticalVelocity = 0;
|
item->Animation.VerticalVelocity = 0;
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
lara->Control.WaterStatus = WaterStatus::Wade;
|
lara->Control.WaterStatus = WaterStatus::Wade;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -990,7 +990,7 @@ bool TestLaraWaterClimbOut(ItemInfo* item, CollisionInfo* coll)
|
||||||
|
|
||||||
item->Pose.Position.y += frontFloor - 5;
|
item->Pose.Position.y += frontFloor - 5;
|
||||||
item->Animation.ActiveState = LS_ONWATER_EXIT;
|
item->Animation.ActiveState = LS_ONWATER_EXIT;
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
item->Animation.Velocity = 0;
|
item->Animation.Velocity = 0;
|
||||||
item->Animation.VerticalVelocity = 0;
|
item->Animation.VerticalVelocity = 0;
|
||||||
lara->Control.TurnRate = 0;
|
lara->Control.TurnRate = 0;
|
||||||
|
@ -1062,7 +1062,7 @@ bool TestLaraLadderClimbOut(ItemInfo* item, CollisionInfo* coll) // NEW function
|
||||||
item->Pose.Orientation.z = 0;
|
item->Pose.Orientation.z = 0;
|
||||||
item->Animation.Velocity = 0;
|
item->Animation.Velocity = 0;
|
||||||
item->Animation.VerticalVelocity = 0;
|
item->Animation.VerticalVelocity = 0;
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
lara->Control.TurnRate = 0;
|
lara->Control.TurnRate = 0;
|
||||||
lara->Control.HandStatus = HandStatus::Busy;
|
lara->Control.HandStatus = HandStatus::Busy;
|
||||||
lara->Control.WaterStatus = WaterStatus::Dry;
|
lara->Control.WaterStatus = WaterStatus::Dry;
|
||||||
|
@ -1090,7 +1090,7 @@ void TestLaraWaterDepth(ItemInfo* item, CollisionInfo* coll)
|
||||||
item->Pose.Position.y = probe.Position.Floor;
|
item->Pose.Position.y = probe.Position.Floor;
|
||||||
item->Pose.Orientation.x = 0;
|
item->Pose.Orientation.x = 0;
|
||||||
item->Pose.Orientation.z = 0;
|
item->Pose.Orientation.z = 0;
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
item->Animation.Velocity = 0;
|
item->Animation.Velocity = 0;
|
||||||
item->Animation.VerticalVelocity = 0;
|
item->Animation.VerticalVelocity = 0;
|
||||||
lara->Control.WaterStatus = WaterStatus::Wade;
|
lara->Control.WaterStatus = WaterStatus::Wade;
|
||||||
|
@ -1255,7 +1255,8 @@ bool TestLaraLand(ItemInfo* item, CollisionInfo* coll)
|
||||||
{
|
{
|
||||||
int heightFromFloor = GetCollision(item).Position.Floor - item->Pose.Position.y;
|
int heightFromFloor = GetCollision(item).Position.Floor - item->Pose.Position.y;
|
||||||
|
|
||||||
if (item->Animation.Airborne && item->Animation.VerticalVelocity >= 0 &&
|
if (item->Animation.IsAirborne &&
|
||||||
|
item->Animation.VerticalVelocity >= 0 &&
|
||||||
(heightFromFloor <= item->Animation.VerticalVelocity ||
|
(heightFromFloor <= item->Animation.VerticalVelocity ||
|
||||||
TestEnvironment(ENV_FLAG_SWAMP, item)))
|
TestEnvironment(ENV_FLAG_SWAMP, item)))
|
||||||
{
|
{
|
||||||
|
|
|
@ -51,7 +51,7 @@ void AnimateLara(ItemInfo* item)
|
||||||
case COMMAND_JUMP_VELOCITY:
|
case COMMAND_JUMP_VELOCITY:
|
||||||
item->Animation.VerticalVelocity = *(cmd++);
|
item->Animation.VerticalVelocity = *(cmd++);
|
||||||
item->Animation.Velocity = *(cmd++);
|
item->Animation.Velocity = *(cmd++);
|
||||||
item->Animation.Airborne = true;
|
item->Animation.IsAirborne = true;
|
||||||
if (lara->Control.CalculatedJumpVelocity)
|
if (lara->Control.CalculatedJumpVelocity)
|
||||||
{
|
{
|
||||||
item->Animation.VerticalVelocity = lara->Control.CalculatedJumpVelocity;
|
item->Animation.VerticalVelocity = lara->Control.CalculatedJumpVelocity;
|
||||||
|
@ -150,7 +150,7 @@ void AnimateLara(ItemInfo* item)
|
||||||
lateral += anim->Xacceleration * (item->Animation.FrameNumber - anim->frameBase);
|
lateral += anim->Xacceleration * (item->Animation.FrameNumber - anim->frameBase);
|
||||||
item->Animation.LateralVelocity = lateral >>= 16;
|
item->Animation.LateralVelocity = lateral >>= 16;
|
||||||
|
|
||||||
if (item->Animation.Airborne)
|
if (item->Animation.IsAirborne)
|
||||||
{
|
{
|
||||||
if (TestEnvironment(ENV_FLAG_SWAMP, item))
|
if (TestEnvironment(ENV_FLAG_SWAMP, item))
|
||||||
{
|
{
|
||||||
|
@ -158,7 +158,7 @@ void AnimateLara(ItemInfo* item)
|
||||||
if (abs(item->Animation.Velocity) < 8)
|
if (abs(item->Animation.Velocity) < 8)
|
||||||
{
|
{
|
||||||
item->Animation.Velocity = 0;
|
item->Animation.Velocity = 0;
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
}
|
}
|
||||||
if (item->Animation.VerticalVelocity > 128)
|
if (item->Animation.VerticalVelocity > 128)
|
||||||
item->Animation.VerticalVelocity /= 2;
|
item->Animation.VerticalVelocity /= 2;
|
||||||
|
@ -241,7 +241,7 @@ void AnimateItem(ItemInfo* item)
|
||||||
case COMMAND_JUMP_VELOCITY:
|
case COMMAND_JUMP_VELOCITY:
|
||||||
item->Animation.VerticalVelocity = *(cmd++);
|
item->Animation.VerticalVelocity = *(cmd++);
|
||||||
item->Animation.Velocity = *(cmd++);
|
item->Animation.Velocity = *(cmd++);
|
||||||
item->Animation.Airborne = true;
|
item->Animation.IsAirborne = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case COMMAND_DEACTIVATE:
|
case COMMAND_DEACTIVATE:
|
||||||
|
@ -348,7 +348,7 @@ void AnimateItem(ItemInfo* item)
|
||||||
|
|
||||||
int lateral = 0;
|
int lateral = 0;
|
||||||
|
|
||||||
if (item->Animation.Airborne)
|
if (item->Animation.IsAirborne)
|
||||||
{
|
{
|
||||||
item->Animation.VerticalVelocity += (item->Animation.VerticalVelocity >= 128 ? 1 : 6);
|
item->Animation.VerticalVelocity += (item->Animation.VerticalVelocity >= 128 ? 1 : 6);
|
||||||
item->Pose.Position.y += item->Animation.VerticalVelocity;
|
item->Pose.Position.y += item->Animation.VerticalVelocity;
|
||||||
|
|
|
@ -38,11 +38,11 @@ void GenericSphereBoxCollision(short itemNumber, ItemInfo* laraItem, CollisionIn
|
||||||
int collidedBits = TestCollision(item, laraItem);
|
int collidedBits = TestCollision(item, laraItem);
|
||||||
if (collidedBits)
|
if (collidedBits)
|
||||||
{
|
{
|
||||||
short oldRot = item->Pose.Orientation.y;
|
short oldYOrient = item->Pose.Orientation.y;
|
||||||
|
|
||||||
item->Pose.Orientation.y = 0;
|
item->Pose.Orientation.y = 0;
|
||||||
GetSpheres(item, CreatureSpheres, SPHERES_SPACE_WORLD, Matrix::Identity);
|
GetSpheres(item, CreatureSpheres, SPHERES_SPACE_WORLD, Matrix::Identity);
|
||||||
item->Pose.Orientation.y = oldRot;
|
item->Pose.Orientation.y = oldYOrient;
|
||||||
|
|
||||||
int deadlyBits = *((int*)&item->ItemFlags[0]);
|
int deadlyBits = *((int*)&item->ItemFlags[0]);
|
||||||
auto* sphere = &CreatureSpheres[0];
|
auto* sphere = &CreatureSpheres[0];
|
||||||
|
@ -821,6 +821,7 @@ bool ItemPushStatic(ItemInfo* item, MESH_INFO* mesh, CollisionInfo* coll) // pre
|
||||||
if (coll->CollisionType == CT_NONE)
|
if (coll->CollisionType == CT_NONE)
|
||||||
{
|
{
|
||||||
coll->Setup.OldPosition = item->Pose.Position;
|
coll->Setup.OldPosition = item->Pose.Position;
|
||||||
|
if (item->IsLara())
|
||||||
UpdateItemRoom(item, -10);
|
UpdateItemRoom(item, -10);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -830,10 +831,11 @@ bool ItemPushStatic(ItemInfo* item, MESH_INFO* mesh, CollisionInfo* coll) // pre
|
||||||
}
|
}
|
||||||
|
|
||||||
// If Lara is in the process of aligning to an object, cancel it.
|
// If Lara is in the process of aligning to an object, cancel it.
|
||||||
if (item == LaraItem && Lara.Control.IsMoving && Lara.Control.Count.PositionAdjust > (LARA_POSITION_ADJUST_MAX_TIME / 6))
|
if (item->IsLara() && Lara.Control.IsMoving && Lara.Control.Count.PositionAdjust > (LARA_POSITION_ADJUST_MAX_TIME / 6))
|
||||||
{
|
{
|
||||||
Lara.Control.IsMoving = false;
|
auto* lara = GetLaraInfo(item);
|
||||||
Lara.Control.HandStatus = HandStatus::Free;
|
lara->Control.IsMoving = false;
|
||||||
|
lara->Control.HandStatus = HandStatus::Free;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -1672,64 +1674,6 @@ void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv,
|
||||||
ItemNewRoom(itemNumber, collResult.RoomNumber);
|
ItemNewRoom(itemNumber, collResult.RoomNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DoVehicleCollision(ItemInfo* vehicle, int radius)
|
|
||||||
{
|
|
||||||
CollisionInfo coll = {};
|
|
||||||
coll.Setup.Radius = radius * 0.8f; // HACK: Most vehicles use radius larger than needed.
|
|
||||||
coll.Setup.UpperCeilingBound = MAX_HEIGHT; // HACK: this needs to be set to prevent GCI result interference.
|
|
||||||
coll.Setup.OldPosition = vehicle->Pose.Position;
|
|
||||||
coll.Setup.EnableObjectPush = true;
|
|
||||||
|
|
||||||
DoObjectCollision(vehicle, &coll);
|
|
||||||
}
|
|
||||||
|
|
||||||
int DoVehicleWaterMovement(ItemInfo* vehicle, ItemInfo* lara, int currentVelocity, int radius, short* angle)
|
|
||||||
{
|
|
||||||
if (TestEnvironment(ENV_FLAG_WATER, vehicle) ||
|
|
||||||
TestEnvironment(ENV_FLAG_SWAMP, vehicle))
|
|
||||||
{
|
|
||||||
auto waterDepth = (float)GetWaterDepth(vehicle);
|
|
||||||
auto waterHeight = vehicle->Pose.Position.y - GetWaterHeight(vehicle);
|
|
||||||
|
|
||||||
// HACK: Sometimes quadbike test position may end up under non-portal ceiling block.
|
|
||||||
// GetWaterDepth returns DEEP_WATER constant in that case, which is too large for our needs.
|
|
||||||
if (waterDepth == DEEP_WATER)
|
|
||||||
waterDepth = VEHICLE_MAX_WATER_HEIGHT;
|
|
||||||
|
|
||||||
if (waterDepth <= VEHICLE_MAX_WATER_HEIGHT)
|
|
||||||
{
|
|
||||||
bool isWater = TestEnvironment(ENV_FLAG_WATER, vehicle);
|
|
||||||
|
|
||||||
if (currentVelocity != 0)
|
|
||||||
{
|
|
||||||
auto coeff = isWater ? VEHICLE_WATER_VEL_COEFFICIENT : VEHICLE_SWAMP_VEL_COEFFICIENT;
|
|
||||||
currentVelocity -= std::copysign(currentVelocity * ((waterDepth / VEHICLE_MAX_WATER_HEIGHT) / coeff), currentVelocity);
|
|
||||||
|
|
||||||
if (TEN::Math::Random::GenerateInt(0, 32) > 28)
|
|
||||||
SoundEffect(SFX_TR4_LARA_WADE, &PHD_3DPOS(vehicle->Pose.Position), SoundEnvironment::Land, isWater ? 0.8f : 0.7f);
|
|
||||||
|
|
||||||
if (isWater)
|
|
||||||
TEN::Effects::TriggerSpeedboatFoam(vehicle, Vector3(0, -waterDepth / 2.0f, -radius));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (*angle != 0)
|
|
||||||
{
|
|
||||||
auto coeff = isWater ? VEHICLE_WATER_TURN_COEFFICIENT : VEHICLE_SWAMP_TURN_COEFFICIENT;
|
|
||||||
*angle -= *angle * ((waterDepth / VEHICLE_MAX_WATER_HEIGHT) / coeff);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (waterDepth > VEHICLE_MAX_WATER_HEIGHT && waterHeight > VEHICLE_MAX_WATER_HEIGHT)
|
|
||||||
ExplodeVehicle(lara, vehicle);
|
|
||||||
else if (TEN::Math::Random::GenerateInt(0, 32) > 25)
|
|
||||||
Splash(vehicle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return currentVelocity;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DoObjectCollision(ItemInfo* laraItem, CollisionInfo* coll)
|
void DoObjectCollision(ItemInfo* laraItem, CollisionInfo* coll)
|
||||||
{
|
{
|
||||||
laraItem->HitStatus = false;
|
laraItem->HitStatus = false;
|
||||||
|
|
|
@ -11,12 +11,6 @@ constexpr auto MAX_COLLIDED_OBJECTS = 1024;
|
||||||
constexpr auto ITEM_RADIUS_YMAX = SECTOR(3);
|
constexpr auto ITEM_RADIUS_YMAX = SECTOR(3);
|
||||||
|
|
||||||
constexpr auto VEHICLE_COLLISION_TERMINAL_VELOCITY = 30;
|
constexpr auto VEHICLE_COLLISION_TERMINAL_VELOCITY = 30;
|
||||||
constexpr auto VEHICLE_SINK_SPEED = 15;
|
|
||||||
constexpr auto VEHICLE_MAX_WATER_HEIGHT = CLICK(2.5f);
|
|
||||||
constexpr auto VEHICLE_WATER_VEL_COEFFICIENT = 16.0f;
|
|
||||||
constexpr auto VEHICLE_WATER_TURN_COEFFICIENT = 10.0f;
|
|
||||||
constexpr auto VEHICLE_SWAMP_VEL_COEFFICIENT = 8.0f;
|
|
||||||
constexpr auto VEHICLE_SWAMP_TURN_COEFFICIENT = 6.0f;
|
|
||||||
|
|
||||||
extern BOUNDING_BOX GlobalCollisionBounds;
|
extern BOUNDING_BOX GlobalCollisionBounds;
|
||||||
extern ItemInfo* CollidedItems[MAX_COLLIDED_OBJECTS];
|
extern ItemInfo* CollidedItems[MAX_COLLIDED_OBJECTS];
|
||||||
|
@ -62,5 +56,3 @@ void TrapCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll);
|
||||||
|
|
||||||
void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv, int zv);
|
void DoProjectileDynamics(short itemNumber, int x, int y, int z, int xv, int yv, int zv);
|
||||||
void DoObjectCollision(ItemInfo* item, CollisionInfo* coll);
|
void DoObjectCollision(ItemInfo* item, CollisionInfo* coll);
|
||||||
void DoVehicleCollision(ItemInfo* vehicle, int radius);
|
|
||||||
int DoVehicleWaterMovement(ItemInfo* vehicle, ItemInfo* lara, int currentVelocity, int radius, short* angle);
|
|
||||||
|
|
|
@ -123,7 +123,7 @@ CollisionResult GetCollision(ItemInfo* item)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Overload used to probe point/room collision parameters from a given item's position.
|
// Overload used to probe point/room collision parameters from a given item's position.
|
||||||
CollisionResult GetCollision(ItemInfo* item, short angle, float forward, float vertical, float lateral)
|
CollisionResult GetCollision(ItemInfo* item, short angle, float forward, float up, float right)
|
||||||
{
|
{
|
||||||
short tempRoomNumber = item->RoomNumber;
|
short tempRoomNumber = item->RoomNumber;
|
||||||
|
|
||||||
|
@ -133,18 +133,18 @@ CollisionResult GetCollision(ItemInfo* item, short angle, float forward, float v
|
||||||
item->Location :
|
item->Location :
|
||||||
ROOM_VECTOR{ GetFloor(item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z, &tempRoomNumber)->Room, item->Pose.Position.y };
|
ROOM_VECTOR{ GetFloor(item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z, &tempRoomNumber)->Room, item->Pose.Position.y };
|
||||||
|
|
||||||
auto point = TranslateVector(item->Pose.Position, angle, forward, vertical, lateral);
|
auto point = TranslateVector(item->Pose.Position, angle, forward, up, right);
|
||||||
int adjacentRoomNumber = GetRoom(location, item->Pose.Position.x, point.y, item->Pose.Position.z).roomNumber;
|
int adjacentRoomNumber = GetRoom(location, item->Pose.Position.x, point.y, item->Pose.Position.z).roomNumber;
|
||||||
return GetCollision(point.x, point.y, point.z, adjacentRoomNumber);
|
return GetCollision(point.x, point.y, point.z, adjacentRoomNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Overload used to probe point/room collision parameters from a given position.
|
// Overload used to probe point/room collision parameters from a given position.
|
||||||
CollisionResult GetCollision(Vector3Int pos, int roomNumber, short angle, float forward, float vertical, float lateral)
|
CollisionResult GetCollision(Vector3Int pos, int roomNumber, short angle, float forward, float up, float right)
|
||||||
{
|
{
|
||||||
short tempRoomNumber = roomNumber;
|
short tempRoomNumber = roomNumber;
|
||||||
auto location = ROOM_VECTOR{ GetFloor(pos.x, pos.y, pos.z, &tempRoomNumber)->Room, pos.y };
|
auto location = ROOM_VECTOR{ GetFloor(pos.x, pos.y, pos.z, &tempRoomNumber)->Room, pos.y };
|
||||||
|
|
||||||
auto point = TranslateVector(pos, angle, forward, vertical, lateral);
|
auto point = TranslateVector(pos, angle, forward, up, right);
|
||||||
int adjacentRoomNumber = GetRoom(location, pos.x, point.y, pos.z).roomNumber;
|
int adjacentRoomNumber = GetRoom(location, pos.x, point.y, pos.z).roomNumber;
|
||||||
return GetCollision(point.x, point.y, point.z, adjacentRoomNumber);
|
return GetCollision(point.x, point.y, point.z, adjacentRoomNumber);
|
||||||
}
|
}
|
||||||
|
@ -173,7 +173,7 @@ CollisionResult GetCollision(FloorInfo* floor, int x, int y, int z)
|
||||||
CollisionResult result = {};
|
CollisionResult result = {};
|
||||||
|
|
||||||
// Record coordinates.
|
// Record coordinates.
|
||||||
result.Coordinates = Vector3(x, y, z);
|
result.Coordinates = Vector3Int(x, y, z);
|
||||||
|
|
||||||
// Return provided block into result as itself.
|
// Return provided block into result as itself.
|
||||||
result.Block = floor;
|
result.Block = floor;
|
||||||
|
|
|
@ -54,7 +54,7 @@ struct CollisionPosition
|
||||||
|
|
||||||
struct CollisionResult
|
struct CollisionResult
|
||||||
{
|
{
|
||||||
Vector3 Coordinates;
|
Vector3Int Coordinates;
|
||||||
int RoomNumber;
|
int RoomNumber;
|
||||||
|
|
||||||
FloorInfo* Block;
|
FloorInfo* Block;
|
||||||
|
@ -123,8 +123,8 @@ struct CollisionInfo
|
||||||
[[nodiscard]] bool TestItemRoomCollisionAABB(ItemInfo* item);
|
[[nodiscard]] bool TestItemRoomCollisionAABB(ItemInfo* item);
|
||||||
|
|
||||||
CollisionResult GetCollision(ItemInfo* item);
|
CollisionResult GetCollision(ItemInfo* item);
|
||||||
CollisionResult GetCollision(ItemInfo* item, short angle, float forward, float vertical = 0.0f, float lateral = 0.0f);
|
CollisionResult GetCollision(ItemInfo* item, short angle, float forward, float up = 0.0f, float right = 0.0f);
|
||||||
CollisionResult GetCollision(Vector3Int pos, int roomNumber, short angle, float forward, float vertical = 0.0f, float lateral = 0.0f);
|
CollisionResult GetCollision(Vector3Int pos, int roomNumber, short angle, float forward, float up = 0.0f, float right = 0.0f);
|
||||||
CollisionResult GetCollision(int x, int y, int z, short roomNumber);
|
CollisionResult GetCollision(int x, int y, int z, short roomNumber);
|
||||||
CollisionResult GetCollision(FloorInfo* floor, int x, int y, int z);
|
CollisionResult GetCollision(FloorInfo* floor, int x, int y, int z);
|
||||||
|
|
||||||
|
@ -162,3 +162,4 @@ bool TestEnvironment(RoomEnvFlags environmentType, ItemInfo* item);
|
||||||
bool TestEnvironment(RoomEnvFlags environmentType, int roomNumber);
|
bool TestEnvironment(RoomEnvFlags environmentType, int roomNumber);
|
||||||
bool TestEnvironment(RoomEnvFlags environmentType, ROOM_INFO* room);
|
bool TestEnvironment(RoomEnvFlags environmentType, ROOM_INFO* room);
|
||||||
bool TestEnvironmentFlags(RoomEnvFlags environmentType, int flags);
|
bool TestEnvironmentFlags(RoomEnvFlags environmentType, int flags);
|
||||||
|
|
||||||
|
|
|
@ -17,5 +17,5 @@ struct SPHERE
|
||||||
extern SPHERE LaraSpheres[MAX_SPHERES];
|
extern SPHERE LaraSpheres[MAX_SPHERES];
|
||||||
extern SPHERE CreatureSpheres[MAX_SPHERES];
|
extern SPHERE CreatureSpheres[MAX_SPHERES];
|
||||||
|
|
||||||
int TestCollision(ItemInfo* item, ItemInfo* l);
|
int TestCollision(ItemInfo* item, ItemInfo* laraItem);
|
||||||
int GetSpheres(ItemInfo* item, SPHERE* ptr, int worldSpace, Matrix local);
|
int GetSpheres(ItemInfo* item, SPHERE* ptr, int worldSpace, Matrix local);
|
||||||
|
|
|
@ -262,7 +262,7 @@ void CreatureKill(ItemInfo* item, int killAnim, int killState, int laraKillState
|
||||||
LaraItem->Animation.TargetState = laraKillState;
|
LaraItem->Animation.TargetState = laraKillState;
|
||||||
|
|
||||||
LaraItem->Pose = item->Pose;
|
LaraItem->Pose = item->Pose;
|
||||||
LaraItem->Animation.Airborne = false;
|
LaraItem->Animation.IsAirborne = false;
|
||||||
LaraItem->Animation.Velocity = 0;
|
LaraItem->Animation.Velocity = 0;
|
||||||
LaraItem->Animation.VerticalVelocity = 0;
|
LaraItem->Animation.VerticalVelocity = 0;
|
||||||
|
|
||||||
|
|
|
@ -6,12 +6,12 @@
|
||||||
#include "Game/itemdata/creature_info.h"
|
#include "Game/itemdata/creature_info.h"
|
||||||
#include "Game/itemdata/door_data.h"
|
#include "Game/itemdata/door_data.h"
|
||||||
#include "Game/Lara/lara_struct.h"
|
#include "Game/Lara/lara_struct.h"
|
||||||
#include "Objects/TR2/Vehicles/boat_info.h"
|
#include "Objects/TR2/Vehicles/speedboat_info.h"
|
||||||
#include "Objects/TR2/Vehicles/skidoo_info.h"
|
#include "Objects/TR2/Vehicles/skidoo_info.h"
|
||||||
#include "Objects/TR3/Vehicles/minecart_info.h"
|
#include "Objects/TR3/Vehicles/minecart_info.h"
|
||||||
#include "Objects/TR3/Vehicles/big_gun_info.h"
|
#include "Objects/TR3/Vehicles/big_gun_info.h"
|
||||||
#include "Objects/TR3/Vehicles/kayak_info.h"
|
#include "Objects/TR3/Vehicles/kayak_info.h"
|
||||||
#include "Objects/TR3/Vehicles/quad_info.h"
|
#include "Objects/TR3/Vehicles/quad_bike_info.h"
|
||||||
#include "Objects/TR3/Vehicles/rubber_boat_info.h"
|
#include "Objects/TR3/Vehicles/rubber_boat_info.h"
|
||||||
#include "Objects/TR3/Vehicles/upv_info.h"
|
#include "Objects/TR3/Vehicles/upv_info.h"
|
||||||
#include "Objects/TR4/Vehicles/jeep_info.h"
|
#include "Objects/TR4/Vehicles/jeep_info.h"
|
||||||
|
@ -46,23 +46,23 @@ class ITEM_DATA
|
||||||
double,
|
double,
|
||||||
long double,
|
long double,
|
||||||
std::array<short, 4>,
|
std::array<short, 4>,
|
||||||
|
GameVector,
|
||||||
|
DOOR_DATA,
|
||||||
|
PushableInfo,
|
||||||
ItemInfo*,
|
ItemInfo*,
|
||||||
|
LaraInfo*,
|
||||||
CreatureInfo,
|
CreatureInfo,
|
||||||
|
WraithInfo,
|
||||||
LaserHeadInfo,
|
LaserHeadInfo,
|
||||||
QuadInfo,
|
QuadBikeInfo,
|
||||||
BigGunInfo,
|
BigGunInfo,
|
||||||
MotorbikeInfo,
|
MotorbikeInfo,
|
||||||
JeepInfo,
|
JeepInfo,
|
||||||
LaraInfo*,
|
|
||||||
KayakInfo,
|
KayakInfo,
|
||||||
DOOR_DATA,
|
|
||||||
SkidooInfo,
|
SkidooInfo,
|
||||||
UPVInfo,
|
UPVInfo,
|
||||||
SpeedBoatInfo,
|
SpeedboatInfo,
|
||||||
GameVector,
|
|
||||||
WraithInfo,
|
|
||||||
RubberBoatInfo,
|
RubberBoatInfo,
|
||||||
PushableInfo,
|
|
||||||
MinecartInfo
|
MinecartInfo
|
||||||
> data;
|
> data;
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -462,7 +462,7 @@ void InitialiseItem(short itemNumber)
|
||||||
|
|
||||||
item->Active = false;
|
item->Active = false;
|
||||||
item->Status = ITEM_NOT_ACTIVE;
|
item->Status = ITEM_NOT_ACTIVE;
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
item->HitStatus = false;
|
item->HitStatus = false;
|
||||||
item->Collidable = true;
|
item->Collidable = true;
|
||||||
item->LookedAt = false;
|
item->LookedAt = false;
|
||||||
|
|
|
@ -22,13 +22,13 @@ constexpr auto NUM_ITEMS = 1024;
|
||||||
|
|
||||||
enum AIObjectType
|
enum AIObjectType
|
||||||
{
|
{
|
||||||
NO_AI = 0x0000,
|
NO_AI = 0,
|
||||||
GUARD = 0x0001,
|
GUARD = (1 << 0),
|
||||||
AMBUSH = 0x0002,
|
AMBUSH = (1 << 1),
|
||||||
PATROL1 = 0x0004,
|
PATROL1 = (1 << 2),
|
||||||
MODIFY = 0x0008,
|
MODIFY = (1 << 3),
|
||||||
FOLLOW = 0x0010,
|
FOLLOW = (1 << 4),
|
||||||
PATROL2 = 0x0020,
|
PATROL2 = (1 << 5),
|
||||||
ALL_AIOBJ = (GUARD | AMBUSH | PATROL1 | MODIFY | FOLLOW | PATROL2)
|
ALL_AIOBJ = (GUARD | AMBUSH | PATROL1 | MODIFY | FOLLOW | PATROL2)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ struct EntityAnimationData
|
||||||
int TargetState;
|
int TargetState;
|
||||||
int RequiredState; // TODO: Phase out this weird feature.
|
int RequiredState; // TODO: Phase out this weird feature.
|
||||||
|
|
||||||
bool Airborne;
|
bool IsAirborne;
|
||||||
int Velocity;
|
int Velocity;
|
||||||
int VerticalVelocity;
|
int VerticalVelocity;
|
||||||
int LateralVelocity;
|
int LateralVelocity;
|
||||||
|
@ -85,8 +85,10 @@ struct ItemInfo
|
||||||
|
|
||||||
ITEM_DATA Data;
|
ITEM_DATA Data;
|
||||||
EntityAnimationData Animation;
|
EntityAnimationData Animation;
|
||||||
PHD_3DPOS Pose;
|
|
||||||
PHD_3DPOS StartPose;
|
PHD_3DPOS StartPose;
|
||||||
|
PHD_3DPOS Pose;
|
||||||
|
ROOM_VECTOR Location;
|
||||||
|
short RoomNumber;
|
||||||
int Floor;
|
int Floor;
|
||||||
|
|
||||||
int HitPoints;
|
int HitPoints;
|
||||||
|
@ -95,8 +97,6 @@ struct ItemInfo
|
||||||
bool Collidable;
|
bool Collidable;
|
||||||
bool InDrawRoom;
|
bool InDrawRoom;
|
||||||
|
|
||||||
ROOM_VECTOR Location;
|
|
||||||
short RoomNumber;
|
|
||||||
int BoxNumber;
|
int BoxNumber;
|
||||||
int Timer;
|
int Timer;
|
||||||
short Shade;
|
short Shade;
|
||||||
|
|
|
@ -339,7 +339,7 @@ bool SaveGame::Save(int slot)
|
||||||
CarriedWeaponInfo* info = &Lara.Weapons[i];
|
CarriedWeaponInfo* info = &Lara.Weapons[i];
|
||||||
|
|
||||||
std::vector<flatbuffers::Offset<Save::AmmoInfo>> ammos;
|
std::vector<flatbuffers::Offset<Save::AmmoInfo>> ammos;
|
||||||
for (int j = 0; j < (int)WeaponAmmoType::NumAmmos; j++)
|
for (int j = 0; j < (int)WeaponAmmoType::NumAmmoTypes; j++)
|
||||||
{
|
{
|
||||||
Save::AmmoInfoBuilder ammo{ fbb };
|
Save::AmmoInfoBuilder ammo{ fbb };
|
||||||
ammo.add_count(info->Ammo[j].getCount());
|
ammo.add_count(info->Ammo[j].getCount());
|
||||||
|
@ -466,9 +466,9 @@ bool SaveGame::Save(int slot)
|
||||||
creatureBuilder.add_ai_target_number(creature->AITargetNumber);
|
creatureBuilder.add_ai_target_number(creature->AITargetNumber);
|
||||||
creatureOffset = creatureBuilder.Finish();
|
creatureOffset = creatureBuilder.Finish();
|
||||||
}
|
}
|
||||||
else if (itemToSerialize.Data.is<QuadInfo>())
|
else if (itemToSerialize.Data.is<QuadBikeInfo>())
|
||||||
{
|
{
|
||||||
auto quad = (QuadInfo*)itemToSerialize.Data;
|
auto quad = (QuadBikeInfo*)itemToSerialize.Data;
|
||||||
|
|
||||||
Save::QuadBikeBuilder quadBuilder{ fbb };
|
Save::QuadBikeBuilder quadBuilder{ fbb };
|
||||||
|
|
||||||
|
@ -496,13 +496,13 @@ bool SaveGame::Save(int slot)
|
||||||
|
|
||||||
Save::UPVBuilder upvBuilder{ fbb };
|
Save::UPVBuilder upvBuilder{ fbb };
|
||||||
|
|
||||||
upvBuilder.add_fan_rot(upv->FanRot);
|
upvBuilder.add_fan_rot(upv->TurbineRotation);
|
||||||
upvBuilder.add_flags(upv->Flags);
|
upvBuilder.add_flags(upv->Flags);
|
||||||
upvBuilder.add_harpoon_left(upv->HarpoonLeft);
|
upvBuilder.add_harpoon_left(upv->HarpoonLeft);
|
||||||
upvBuilder.add_harpoon_timer(upv->HarpoonTimer);
|
upvBuilder.add_harpoon_timer(upv->HarpoonTimer);
|
||||||
upvBuilder.add_rot(upv->Rot);
|
upvBuilder.add_rot(upv->TurnRate.y);
|
||||||
upvBuilder.add_velocity(upv->Velocity);
|
upvBuilder.add_velocity(upv->Velocity);
|
||||||
upvBuilder.add_x_rot(upv->XRot);
|
upvBuilder.add_x_rot(upv->TurnRate.x);
|
||||||
upvOffset = upvBuilder.Finish();
|
upvOffset = upvBuilder.Finish();
|
||||||
}
|
}
|
||||||
else if (itemToSerialize.Data.is<MinecartInfo>())
|
else if (itemToSerialize.Data.is<MinecartInfo>())
|
||||||
|
@ -534,15 +534,15 @@ bool SaveGame::Save(int slot)
|
||||||
kayakBuilder.add_flags(kayak->Flags);
|
kayakBuilder.add_flags(kayak->Flags);
|
||||||
kayakBuilder.add_forward(kayak->Forward);
|
kayakBuilder.add_forward(kayak->Forward);
|
||||||
kayakBuilder.add_front_vertical_velocity(kayak->FrontVerticalVelocity);
|
kayakBuilder.add_front_vertical_velocity(kayak->FrontVerticalVelocity);
|
||||||
kayakBuilder.add_left_right_count(kayak->LeftRightCount);
|
kayakBuilder.add_left_right_count(kayak->LeftRightPaddleCount);
|
||||||
kayakBuilder.add_left_vertical_velocity(kayak->LeftVerticalVelocity);
|
kayakBuilder.add_left_vertical_velocity(kayak->LeftVerticalVelocity);
|
||||||
kayakBuilder.add_old_pos(&Save::Position(
|
kayakBuilder.add_old_pos(&Save::Position(
|
||||||
kayak->OldPos.Position.x,
|
kayak->OldPose.Position.x,
|
||||||
kayak->OldPos.Position.y,
|
kayak->OldPose.Position.y,
|
||||||
kayak->OldPos.Position.z,
|
kayak->OldPose.Position.z,
|
||||||
kayak->OldPos.Orientation.x,
|
kayak->OldPose.Orientation.x,
|
||||||
kayak->OldPos.Orientation.y,
|
kayak->OldPose.Orientation.y,
|
||||||
kayak->OldPos.Orientation.z));
|
kayak->OldPose.Orientation.z));
|
||||||
kayakBuilder.add_right_vertical_velocity(kayak->RightVerticalVelocity);
|
kayakBuilder.add_right_vertical_velocity(kayak->RightVerticalVelocity);
|
||||||
kayakBuilder.add_true_water(kayak->TrueWater);
|
kayakBuilder.add_true_water(kayak->TrueWater);
|
||||||
kayakBuilder.add_turn(kayak->Turn);
|
kayakBuilder.add_turn(kayak->Turn);
|
||||||
|
@ -601,7 +601,7 @@ bool SaveGame::Save(int slot)
|
||||||
serializedItem.add_triggered((itemToSerialize.Flags & (TRIGGERED | CODE_BITS | ONESHOT)) != 0);
|
serializedItem.add_triggered((itemToSerialize.Flags & (TRIGGERED | CODE_BITS | ONESHOT)) != 0);
|
||||||
serializedItem.add_active(itemToSerialize.Active);
|
serializedItem.add_active(itemToSerialize.Active);
|
||||||
serializedItem.add_status(itemToSerialize.Status);
|
serializedItem.add_status(itemToSerialize.Status);
|
||||||
serializedItem.add_airborne(itemToSerialize.Animation.Airborne);
|
serializedItem.add_is_airborne(itemToSerialize.Animation.IsAirborne);
|
||||||
serializedItem.add_hit_stauts(itemToSerialize.HitStatus);
|
serializedItem.add_hit_stauts(itemToSerialize.HitStatus);
|
||||||
serializedItem.add_ai_bits(itemToSerialize.AIBits);
|
serializedItem.add_ai_bits(itemToSerialize.AIBits);
|
||||||
serializedItem.add_collidable(itemToSerialize.Collidable);
|
serializedItem.add_collidable(itemToSerialize.Collidable);
|
||||||
|
@ -614,7 +614,7 @@ bool SaveGame::Save(int slot)
|
||||||
serializedItem.add_data_type(Save::ItemData::Creature);
|
serializedItem.add_data_type(Save::ItemData::Creature);
|
||||||
serializedItem.add_data(creatureOffset.Union());
|
serializedItem.add_data(creatureOffset.Union());
|
||||||
}
|
}
|
||||||
else if (itemToSerialize.Data.is<QuadInfo>())
|
else if (itemToSerialize.Data.is<QuadBikeInfo>())
|
||||||
{
|
{
|
||||||
serializedItem.add_data_type(Save::ItemData::QuadBike);
|
serializedItem.add_data_type(Save::ItemData::QuadBike);
|
||||||
serializedItem.add_data(quadOffset.Union());
|
serializedItem.add_data(quadOffset.Union());
|
||||||
|
@ -1284,7 +1284,7 @@ bool SaveGame::Load(int slot)
|
||||||
item->HitStatus = savedItem->hit_stauts();
|
item->HitStatus = savedItem->hit_stauts();
|
||||||
item->Status = savedItem->status();
|
item->Status = savedItem->status();
|
||||||
item->AIBits = savedItem->ai_bits();
|
item->AIBits = savedItem->ai_bits();
|
||||||
item->Animation.Airborne = savedItem->airborne();
|
item->Animation.IsAirborne = savedItem->is_airborne();
|
||||||
item->Collidable = savedItem->collidable();
|
item->Collidable = savedItem->collidable();
|
||||||
item->LookedAt = savedItem->looked_at();
|
item->LookedAt = savedItem->looked_at();
|
||||||
|
|
||||||
|
@ -1346,75 +1346,75 @@ bool SaveGame::Load(int slot)
|
||||||
creature->Tosspad = savedCreature->tosspad();
|
creature->Tosspad = savedCreature->tosspad();
|
||||||
SetBaddyTarget(i, savedCreature->ai_target_number());
|
SetBaddyTarget(i, savedCreature->ai_target_number());
|
||||||
}
|
}
|
||||||
else if (item->Data.is<QuadInfo>())
|
else if (item->Data.is<QuadBikeInfo>())
|
||||||
{
|
{
|
||||||
auto quad = (QuadInfo*)item->Data;
|
auto* quadBike = (QuadBikeInfo*)item->Data;
|
||||||
auto savedQuad = (Save::QuadBike*)savedItem->data();
|
auto* savedQuad = (Save::QuadBike*)savedItem->data();
|
||||||
|
|
||||||
quad->CanStartDrift = savedQuad->can_start_drift();
|
quadBike->CanStartDrift = savedQuad->can_start_drift();
|
||||||
quad->DriftStarting = savedQuad->drift_starting();
|
quadBike->DriftStarting = savedQuad->drift_starting();
|
||||||
quad->EngineRevs = savedQuad->engine_revs();
|
quadBike->EngineRevs = savedQuad->engine_revs();
|
||||||
quad->ExtraRotation = savedQuad->extra_rotation();
|
quadBike->ExtraRotation = savedQuad->extra_rotation();
|
||||||
quad->Flags = savedQuad->flags();
|
quadBike->Flags = savedQuad->flags();
|
||||||
quad->FrontRot = savedQuad->front_rot();
|
quadBike->FrontRot = savedQuad->front_rot();
|
||||||
quad->LeftVerticalVelocity = savedQuad->left_vertical_velocity();
|
quadBike->LeftVerticalVelocity = savedQuad->left_vertical_velocity();
|
||||||
quad->MomentumAngle = savedQuad->momentum_angle();
|
quadBike->MomentumAngle = savedQuad->momentum_angle();
|
||||||
quad->NoDismount = savedQuad->no_dismount();
|
quadBike->NoDismount = savedQuad->no_dismount();
|
||||||
quad->Pitch = savedQuad->pitch();
|
quadBike->Pitch = savedQuad->pitch();
|
||||||
quad->RearRot = savedQuad->rear_rot();
|
quadBike->RearRot = savedQuad->rear_rot();
|
||||||
quad->Revs = savedQuad->revs();
|
quadBike->Revs = savedQuad->revs();
|
||||||
quad->RightVerticalVelocity = savedQuad->right_vertical_velocity();
|
quadBike->RightVerticalVelocity = savedQuad->right_vertical_velocity();
|
||||||
quad->SmokeStart = savedQuad->smoke_start();
|
quadBike->SmokeStart = savedQuad->smoke_start();
|
||||||
quad->TurnRate = savedQuad->turn_rate();
|
quadBike->TurnRate = savedQuad->turn_rate();
|
||||||
quad->Velocity = savedQuad->velocity();
|
quadBike->Velocity = savedQuad->velocity();
|
||||||
}
|
}
|
||||||
else if (item->Data.is<UPVInfo>())
|
else if (item->Data.is<UPVInfo>())
|
||||||
{
|
{
|
||||||
auto upv = (UPVInfo*)item->Data;
|
auto* upv = (UPVInfo*)item->Data;
|
||||||
auto savedUpv = (Save::UPV*)savedItem->data();
|
auto* savedUpv = (Save::UPV*)savedItem->data();
|
||||||
|
|
||||||
upv->FanRot = savedUpv->fan_rot();
|
upv->TurbineRotation = savedUpv->fan_rot();
|
||||||
upv->Flags = savedUpv->flags();
|
upv->Flags = savedUpv->flags();
|
||||||
upv->HarpoonLeft = savedUpv->harpoon_left();
|
upv->HarpoonLeft = savedUpv->harpoon_left();
|
||||||
upv->HarpoonTimer = savedUpv->harpoon_timer();
|
upv->HarpoonTimer = savedUpv->harpoon_timer();
|
||||||
upv->Rot = savedUpv->rot();
|
upv->TurnRate.y = savedUpv->rot();
|
||||||
upv->Velocity = savedUpv->velocity();
|
upv->Velocity = savedUpv->velocity();
|
||||||
upv->XRot = savedUpv->x_rot();
|
upv->TurnRate.x = savedUpv->x_rot();
|
||||||
}
|
}
|
||||||
else if (item->Data.is<MinecartInfo>())
|
else if (item->Data.is<MinecartInfo>())
|
||||||
{
|
{
|
||||||
auto mine = (MinecartInfo*)item->Data;
|
auto* minecart = (MinecartInfo*)item->Data;
|
||||||
auto savedMine = (Save::Minecart*)savedItem->data();
|
auto* savedMine = (Save::Minecart*)savedItem->data();
|
||||||
|
|
||||||
mine->Flags = savedMine->flags();
|
minecart->Flags = savedMine->flags();
|
||||||
mine->FloorHeightFront = savedMine->floor_height_front();
|
minecart->FloorHeightFront = savedMine->floor_height_front();
|
||||||
mine->FloorHeightMiddle = savedMine->floor_height_middle();
|
minecart->FloorHeightMiddle = savedMine->floor_height_middle();
|
||||||
mine->Gradient = savedMine->gradient();
|
minecart->Gradient = savedMine->gradient();
|
||||||
mine->StopDelay = savedMine->stop_delay();
|
minecart->StopDelay = savedMine->stop_delay();
|
||||||
mine->TurnLen = savedMine->turn_len();
|
minecart->TurnLen = savedMine->turn_len();
|
||||||
mine->TurnRot = savedMine->turn_rot();
|
minecart->TurnRot = savedMine->turn_rot();
|
||||||
mine->TurnX = savedMine->turn_x();
|
minecart->TurnX = savedMine->turn_x();
|
||||||
mine->TurnZ = savedMine->turn_z();
|
minecart->TurnZ = savedMine->turn_z();
|
||||||
mine->Velocity = savedMine->velocity();
|
minecart->Velocity = savedMine->velocity();
|
||||||
mine->VerticalVelocity = savedMine->vertical_velocity();
|
minecart->VerticalVelocity = savedMine->vertical_velocity();
|
||||||
}
|
}
|
||||||
else if (item->Data.is<KayakInfo>())
|
else if (item->Data.is<KayakInfo>())
|
||||||
{
|
{
|
||||||
auto kayak = (KayakInfo*)item->Data;
|
auto* kayak = (KayakInfo*)item->Data;
|
||||||
auto savedKayak = (Save::Kayak*)savedItem->data();
|
auto* savedKayak = (Save::Kayak*)savedItem->data();
|
||||||
|
|
||||||
kayak->CurrentStartWake = savedKayak->flags();
|
kayak->CurrentStartWake = savedKayak->flags();
|
||||||
kayak->Flags = savedKayak->flags();
|
kayak->Flags = savedKayak->flags();
|
||||||
kayak->Forward = savedKayak->forward();
|
kayak->Forward = savedKayak->forward();
|
||||||
kayak->FrontVerticalVelocity = savedKayak->front_vertical_velocity();
|
kayak->FrontVerticalVelocity = savedKayak->front_vertical_velocity();
|
||||||
kayak->LeftRightCount = savedKayak->left_right_count();
|
kayak->LeftRightPaddleCount = savedKayak->left_right_count();
|
||||||
kayak->LeftVerticalVelocity = savedKayak->left_vertical_velocity();
|
kayak->LeftVerticalVelocity = savedKayak->left_vertical_velocity();
|
||||||
kayak->OldPos.Position.x = savedKayak->old_pos()->x_pos();
|
kayak->OldPose.Position.x = savedKayak->old_pos()->x_pos();
|
||||||
kayak->OldPos.Position.y = savedKayak->old_pos()->y_pos();
|
kayak->OldPose.Position.y = savedKayak->old_pos()->y_pos();
|
||||||
kayak->OldPos.Position.z = savedKayak->old_pos()->z_pos();
|
kayak->OldPose.Position.z = savedKayak->old_pos()->z_pos();
|
||||||
kayak->OldPos.Orientation.x = savedKayak->old_pos()->x_rot();
|
kayak->OldPose.Orientation.x = savedKayak->old_pos()->x_rot();
|
||||||
kayak->OldPos.Orientation.y = savedKayak->old_pos()->y_rot();
|
kayak->OldPose.Orientation.y = savedKayak->old_pos()->y_rot();
|
||||||
kayak->OldPos.Orientation.z = savedKayak->old_pos()->z_rot();
|
kayak->OldPose.Orientation.z = savedKayak->old_pos()->z_rot();
|
||||||
kayak->RightVerticalVelocity = savedKayak->right_vertical_velocity();
|
kayak->RightVerticalVelocity = savedKayak->right_vertical_velocity();
|
||||||
kayak->TrueWater = savedKayak->true_water();
|
kayak->TrueWater = savedKayak->true_water();
|
||||||
kayak->Turn = savedKayak->turn();
|
kayak->Turn = savedKayak->turn();
|
||||||
|
@ -1425,21 +1425,21 @@ bool SaveGame::Load(int slot)
|
||||||
}
|
}
|
||||||
else if (savedItem->data_type() == Save::ItemData::Short)
|
else if (savedItem->data_type() == Save::ItemData::Short)
|
||||||
{
|
{
|
||||||
auto data = savedItem->data();
|
auto* data = savedItem->data();
|
||||||
auto savedData = (Save::Short*)data;
|
auto* savedData = (Save::Short*)data;
|
||||||
item->Data = savedData->scalar();
|
item->Data = savedData->scalar();
|
||||||
}
|
}
|
||||||
else if (savedItem->data_type() == Save::ItemData::Int)
|
else if (savedItem->data_type() == Save::ItemData::Int)
|
||||||
{
|
{
|
||||||
auto data = savedItem->data();
|
auto* data = savedItem->data();
|
||||||
auto savedData = (Save::Int*)data;
|
auto* savedData = (Save::Int*)data;
|
||||||
item->Data = savedData->scalar();
|
item->Data = savedData->scalar();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < s->particles()->size(); i++)
|
for (int i = 0; i < s->particles()->size(); i++)
|
||||||
{
|
{
|
||||||
auto particleInfo = s->particles()->Get(i);
|
auto* particleInfo = s->particles()->Get(i);
|
||||||
auto* particle = &Particles[i];
|
auto* particle = &Particles[i];
|
||||||
|
|
||||||
particle->x = particleInfo->x();
|
particle->x = particleInfo->x();
|
||||||
|
@ -1483,7 +1483,7 @@ bool SaveGame::Load(int slot)
|
||||||
|
|
||||||
for (int i = 0; i < s->bats()->size(); i++)
|
for (int i = 0; i < s->bats()->size(); i++)
|
||||||
{
|
{
|
||||||
auto batInfo = s->bats()->Get(i);
|
auto* batInfo = s->bats()->Get(i);
|
||||||
auto* bat = &Bats[i];
|
auto* bat = &Bats[i];
|
||||||
|
|
||||||
bat->On = batInfo->on();
|
bat->On = batInfo->on();
|
||||||
|
@ -1515,7 +1515,7 @@ bool SaveGame::Load(int slot)
|
||||||
|
|
||||||
for (int i = 0; i < s->spiders()->size(); i++)
|
for (int i = 0; i < s->spiders()->size(); i++)
|
||||||
{
|
{
|
||||||
auto spiderInfo = s->spiders()->Get(i);
|
auto* spiderInfo = s->spiders()->Get(i);
|
||||||
auto* spider = &Spiders[i];
|
auto* spider = &Spiders[i];
|
||||||
|
|
||||||
spider->On = spiderInfo->on();
|
spider->On = spiderInfo->on();
|
||||||
|
|
|
@ -657,7 +657,7 @@ namespace TEN::Entities::Effects
|
||||||
!(TrInput & IN_ACTION) ||
|
!(TrInput & IN_ACTION) ||
|
||||||
laraItem->Animation.ActiveState != LS_IDLE ||
|
laraItem->Animation.ActiveState != LS_IDLE ||
|
||||||
laraItem->Animation.AnimNumber != LA_STAND_IDLE ||
|
laraItem->Animation.AnimNumber != LA_STAND_IDLE ||
|
||||||
laraItem->Animation.Airborne)
|
laraItem->Animation.IsAirborne)
|
||||||
{
|
{
|
||||||
if (item->ObjectNumber == ID_BURNING_ROOTS)
|
if (item->ObjectNumber == ID_BURNING_ROOTS)
|
||||||
ObjectCollision(itemNumber, laraItem, coll);
|
ObjectCollision(itemNumber, laraItem, coll);
|
||||||
|
|
|
@ -44,7 +44,7 @@ namespace TEN::Entities::Doors
|
||||||
laraItem->Animation.ActiveState == LS_IDLE &&
|
laraItem->Animation.ActiveState == LS_IDLE &&
|
||||||
laraItem->Animation.AnimNumber == LA_STAND_IDLE &&
|
laraItem->Animation.AnimNumber == LA_STAND_IDLE &&
|
||||||
!laraItem->HitStatus &&
|
!laraItem->HitStatus &&
|
||||||
!(doorItem->Status && doorItem->Animation.Airborne) &&
|
!(doorItem->Status && doorItem->Animation.IsAirborne) &&
|
||||||
laraInfo->Control.HandStatus == HandStatus::Free ||
|
laraInfo->Control.HandStatus == HandStatus::Free ||
|
||||||
laraInfo->Control.IsMoving && laraInfo->InteractedItem == itemNumber)
|
laraInfo->Control.IsMoving && laraInfo->InteractedItem == itemNumber)
|
||||||
{
|
{
|
||||||
|
|
|
@ -170,7 +170,7 @@ namespace TEN::Entities::Doors
|
||||||
auto* doorItem = &g_Level.Items[itemNumber];
|
auto* doorItem = &g_Level.Items[itemNumber];
|
||||||
|
|
||||||
if (doorItem->TriggerFlags == 2 &&
|
if (doorItem->TriggerFlags == 2 &&
|
||||||
doorItem->Status == ITEM_NOT_ACTIVE && !doorItem->Animation.Airborne && // CHECK
|
doorItem->Status == ITEM_NOT_ACTIVE && !doorItem->Animation.IsAirborne && // CHECK
|
||||||
((TrInput & IN_ACTION || g_Gui.GetInventoryItemChosen() == ID_CROWBAR_ITEM) &&
|
((TrInput & IN_ACTION || g_Gui.GetInventoryItemChosen() == ID_CROWBAR_ITEM) &&
|
||||||
laraItem->Animation.ActiveState == LS_IDLE &&
|
laraItem->Animation.ActiveState == LS_IDLE &&
|
||||||
laraItem->Animation.AnimNumber == LA_STAND_IDLE &&
|
laraItem->Animation.AnimNumber == LA_STAND_IDLE &&
|
||||||
|
|
|
@ -43,7 +43,7 @@ namespace TEN::Entities::Doors
|
||||||
if (TrInput & IN_ACTION &&
|
if (TrInput & IN_ACTION &&
|
||||||
laraItem->Animation.ActiveState == LS_UNDERWATER_IDLE &&
|
laraItem->Animation.ActiveState == LS_UNDERWATER_IDLE &&
|
||||||
laraInfo->Control.WaterStatus == WaterStatus::Underwater &&
|
laraInfo->Control.WaterStatus == WaterStatus::Underwater &&
|
||||||
!(doorItem->Status && doorItem->Animation.Airborne) &&
|
!(doorItem->Status && doorItem->Animation.IsAirborne) &&
|
||||||
laraInfo->Control.HandStatus == HandStatus::Free ||
|
laraInfo->Control.HandStatus == HandStatus::Free ||
|
||||||
laraInfo->Control.IsMoving && laraInfo->InteractedItem == itemNumber)
|
laraInfo->Control.IsMoving && laraInfo->InteractedItem == itemNumber)
|
||||||
{
|
{
|
||||||
|
|
|
@ -83,7 +83,7 @@ namespace TEN::Entities::Generic
|
||||||
Lara.Torch.State = TorchState::Dropping;
|
Lara.Torch.State = TorchState::Dropping;
|
||||||
}
|
}
|
||||||
else if (TrInput & IN_DRAW &&
|
else if (TrInput & IN_DRAW &&
|
||||||
!LaraItem->Animation.Airborne &&
|
!LaraItem->Animation.IsAirborne &&
|
||||||
!LaraItem->Animation.VerticalVelocity &&
|
!LaraItem->Animation.VerticalVelocity &&
|
||||||
LaraItem->Animation.ActiveState != LS_JUMP_PREPARE &&
|
LaraItem->Animation.ActiveState != LS_JUMP_PREPARE &&
|
||||||
LaraItem->Animation.ActiveState != LS_JUMP_UP &&
|
LaraItem->Animation.ActiveState != LS_JUMP_UP &&
|
||||||
|
@ -104,7 +104,7 @@ namespace TEN::Entities::Generic
|
||||||
}
|
}
|
||||||
else if (Lara.Torch.State == TorchState::Throwing)
|
else if (Lara.Torch.State == TorchState::Throwing)
|
||||||
{
|
{
|
||||||
if (Lara.LeftArm.FrameNumber < 12 && LaraItem->Animation.Airborne)
|
if (Lara.LeftArm.FrameNumber < 12 && LaraItem->Animation.IsAirborne)
|
||||||
{
|
{
|
||||||
Lara.LeftArm.Locked = false;
|
Lara.LeftArm.Locked = false;
|
||||||
Lara.LeftArm.FrameNumber = 0;
|
Lara.LeftArm.FrameNumber = 0;
|
||||||
|
@ -304,7 +304,7 @@ namespace TEN::Entities::Generic
|
||||||
if (!(TrInput & IN_ACTION) ||
|
if (!(TrInput & IN_ACTION) ||
|
||||||
laraItem->Animation.ActiveState != LS_IDLE ||
|
laraItem->Animation.ActiveState != LS_IDLE ||
|
||||||
laraItem->Animation.AnimNumber != LA_STAND_IDLE ||
|
laraItem->Animation.AnimNumber != LA_STAND_IDLE ||
|
||||||
laraItem->Animation.Airborne ||
|
laraItem->Animation.IsAirborne ||
|
||||||
laraInfo->Control.Weapon.GunType != LaraWeaponType::Torch ||
|
laraInfo->Control.Weapon.GunType != LaraWeaponType::Torch ||
|
||||||
laraInfo->Control.HandStatus != HandStatus::WeaponReady ||
|
laraInfo->Control.HandStatus != HandStatus::WeaponReady ||
|
||||||
laraInfo->LeftArm.Locked ||
|
laraInfo->LeftArm.Locked ||
|
||||||
|
|
|
@ -70,7 +70,7 @@ void CeilingTrapDoorCollision(short itemNumber, ItemInfo* laraItem, CollisionInf
|
||||||
|
|
||||||
if (TrInput & IN_ACTION &&
|
if (TrInput & IN_ACTION &&
|
||||||
laraItem->Animation.ActiveState == LS_JUMP_UP &&
|
laraItem->Animation.ActiveState == LS_JUMP_UP &&
|
||||||
laraItem->Animation.Airborne &&
|
laraItem->Animation.IsAirborne &&
|
||||||
laraInfo->Control.HandStatus == HandStatus::Free &&
|
laraInfo->Control.HandStatus == HandStatus::Free &&
|
||||||
trapDoorItem->Status != ITEM_ACTIVE &&
|
trapDoorItem->Status != ITEM_ACTIVE &&
|
||||||
itemIsAbove &&
|
itemIsAbove &&
|
||||||
|
@ -82,7 +82,7 @@ void CeilingTrapDoorCollision(short itemNumber, ItemInfo* laraItem, CollisionInf
|
||||||
|
|
||||||
ResetLaraFlex(laraItem);
|
ResetLaraFlex(laraItem);
|
||||||
laraItem->Animation.VerticalVelocity = 0;
|
laraItem->Animation.VerticalVelocity = 0;
|
||||||
laraItem->Animation.Airborne = false;
|
laraItem->Animation.IsAirborne = false;
|
||||||
laraItem->Animation.AnimNumber = LA_TRAPDOOR_CEILING_OPEN;
|
laraItem->Animation.AnimNumber = LA_TRAPDOOR_CEILING_OPEN;
|
||||||
laraItem->Animation.FrameNumber = g_Level.Anims[laraItem->Animation.AnimNumber].frameBase;
|
laraItem->Animation.FrameNumber = g_Level.Anims[laraItem->Animation.AnimNumber].frameBase;
|
||||||
laraItem->Animation.ActiveState = LS_FREEFALL_BIS;
|
laraItem->Animation.ActiveState = LS_FREEFALL_BIS;
|
||||||
|
|
|
@ -219,7 +219,7 @@ void HorizontalBarCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo*
|
||||||
laraItem->Animation.AnimNumber = LA_SWINGBAR_GRAB;
|
laraItem->Animation.AnimNumber = LA_SWINGBAR_GRAB;
|
||||||
laraItem->Animation.FrameNumber = g_Level.Anims[laraItem->Animation.AnimNumber].frameBase;
|
laraItem->Animation.FrameNumber = g_Level.Anims[laraItem->Animation.AnimNumber].frameBase;
|
||||||
laraItem->Animation.VerticalVelocity = false;
|
laraItem->Animation.VerticalVelocity = false;
|
||||||
laraItem->Animation.Airborne = false;
|
laraItem->Animation.IsAirborne = false;
|
||||||
|
|
||||||
ResetLaraFlex(barItem);
|
ResetLaraFlex(barItem);
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,7 @@ namespace TEN::Entities::Generic
|
||||||
}
|
}
|
||||||
else if (TrInput & IN_ACTION && isLara &&
|
else if (TrInput & IN_ACTION && isLara &&
|
||||||
laraInfo->Control.HandStatus == HandStatus::Free &&
|
laraInfo->Control.HandStatus == HandStatus::Free &&
|
||||||
laraItem->Animation.Airborne &&
|
laraItem->Animation.IsAirborne &&
|
||||||
laraItem->Animation.VerticalVelocity > (int)laraInfo->Control.HandStatus && // ?????
|
laraItem->Animation.VerticalVelocity > (int)laraInfo->Control.HandStatus && // ?????
|
||||||
laraItem->Animation.ActiveState == LS_REACH || laraItem->Animation.ActiveState == LS_JUMP_UP)
|
laraItem->Animation.ActiveState == LS_REACH || laraItem->Animation.ActiveState == LS_JUMP_UP)
|
||||||
{
|
{
|
||||||
|
@ -103,7 +103,7 @@ namespace TEN::Entities::Generic
|
||||||
|
|
||||||
laraItem->Animation.ActiveState = LS_POLE_IDLE;
|
laraItem->Animation.ActiveState = LS_POLE_IDLE;
|
||||||
laraItem->Animation.VerticalVelocity = 0;
|
laraItem->Animation.VerticalVelocity = 0;
|
||||||
laraItem->Animation.Airborne = false;
|
laraItem->Animation.IsAirborne = false;
|
||||||
laraInfo->Control.HandStatus = HandStatus::Busy;
|
laraInfo->Control.HandStatus = HandStatus::Busy;
|
||||||
poleItem->Pose.Orientation.y = rot;
|
poleItem->Pose.Orientation.y = rot;
|
||||||
}
|
}
|
||||||
|
|
|
@ -181,7 +181,7 @@ namespace TEN::Entities::Generic
|
||||||
if (TrInput & IN_ACTION &&
|
if (TrInput & IN_ACTION &&
|
||||||
laraInfo->Control.HandStatus == HandStatus::Free &&
|
laraInfo->Control.HandStatus == HandStatus::Free &&
|
||||||
(laraItem->Animation.ActiveState == LS_REACH || laraItem->Animation.ActiveState == LS_JUMP_UP) &&
|
(laraItem->Animation.ActiveState == LS_REACH || laraItem->Animation.ActiveState == LS_JUMP_UP) &&
|
||||||
laraItem->Animation.Airborne &&
|
laraItem->Animation.IsAirborne &&
|
||||||
laraItem->Animation.VerticalVelocity > 0&&
|
laraItem->Animation.VerticalVelocity > 0&&
|
||||||
rope->active)
|
rope->active)
|
||||||
{
|
{
|
||||||
|
@ -211,7 +211,7 @@ namespace TEN::Entities::Generic
|
||||||
|
|
||||||
laraItem->Animation.FrameNumber = g_Level.Anims[laraItem->Animation.AnimNumber].frameBase;
|
laraItem->Animation.FrameNumber = g_Level.Anims[laraItem->Animation.AnimNumber].frameBase;
|
||||||
laraItem->Animation.VerticalVelocity = 0;
|
laraItem->Animation.VerticalVelocity = 0;
|
||||||
laraItem->Animation.Airborne = false;
|
laraItem->Animation.IsAirborne = false;
|
||||||
|
|
||||||
laraInfo->Control.HandStatus = HandStatus::Busy;
|
laraInfo->Control.HandStatus = HandStatus::Busy;
|
||||||
laraInfo->Control.Rope.Ptr = ropeItem->TriggerFlags;
|
laraInfo->Control.Rope.Ptr = ropeItem->TriggerFlags;
|
||||||
|
@ -644,7 +644,7 @@ namespace TEN::Entities::Generic
|
||||||
}
|
}
|
||||||
|
|
||||||
item->Pose.Orientation.x = 0;
|
item->Pose.Orientation.x = 0;
|
||||||
item->Animation.Airborne = true;
|
item->Animation.IsAirborne = true;
|
||||||
|
|
||||||
Lara.Control.HandStatus = HandStatus::Free;
|
Lara.Control.HandStatus = HandStatus::Free;
|
||||||
|
|
||||||
|
@ -671,7 +671,7 @@ namespace TEN::Entities::Generic
|
||||||
SetAnimation(item, stumble ? LA_JUMP_WALL_SMASH_START : LA_FALL_START);
|
SetAnimation(item, stumble ? LA_JUMP_WALL_SMASH_START : LA_FALL_START);
|
||||||
|
|
||||||
item->Animation.VerticalVelocity = 0;
|
item->Animation.VerticalVelocity = 0;
|
||||||
item->Animation.Airborne = true;
|
item->Animation.IsAirborne = true;
|
||||||
|
|
||||||
auto* lara = GetLaraInfo(item);
|
auto* lara = GetLaraInfo(item);
|
||||||
lara->Control.HandStatus = HandStatus::Free;
|
lara->Control.HandStatus = HandStatus::Free;
|
||||||
|
|
|
@ -67,12 +67,12 @@ namespace TEN::Entities::Switches
|
||||||
|
|
||||||
if (switchItem->Status == ITEM_NOT_ACTIVE)
|
if (switchItem->Status == ITEM_NOT_ACTIVE)
|
||||||
{
|
{
|
||||||
if (!(switchItem->Flags & ONESHOT) &&
|
if (!(switchItem->Flags & IFLAG_INVISIBLE) &&
|
||||||
(TrInput & IN_ACTION &&
|
(TrInput & IN_ACTION &&
|
||||||
laraItem->Animation.ActiveState == LS_IDLE &&
|
laraItem->Animation.ActiveState == LS_IDLE &&
|
||||||
laraItem->Animation.AnimNumber == LA_STAND_IDLE &&
|
laraItem->Animation.AnimNumber == LA_STAND_IDLE &&
|
||||||
lara->Control.HandStatus == HandStatus::Free &&
|
lara->Control.HandStatus == HandStatus::Free &&
|
||||||
!switchItem->Animation.Airborne ||
|
!switchItem->Animation.IsAirborne ||
|
||||||
lara->Control.IsMoving &&
|
lara->Control.IsMoving &&
|
||||||
lara->InteractedItem == itemNum))
|
lara->InteractedItem == itemNum))
|
||||||
{
|
{
|
||||||
|
|
|
@ -31,7 +31,7 @@ namespace TEN::Entities::Switches
|
||||||
|
|
||||||
switchItem->Flags |= 0x3E00;
|
switchItem->Flags |= 0x3E00;
|
||||||
|
|
||||||
if (!TriggerActive(switchItem) && !(switchItem->Flags & ONESHOT))
|
if (!TriggerActive(switchItem) && !(switchItem->Flags & IFLAG_INVISIBLE))
|
||||||
{
|
{
|
||||||
if (switchItem->ObjectNumber == ID_JUMP_SWITCH)
|
if (switchItem->ObjectNumber == ID_JUMP_SWITCH)
|
||||||
{
|
{
|
||||||
|
|
|
@ -32,7 +32,7 @@ namespace TEN::Entities::Switches
|
||||||
|
|
||||||
if (TrInput & IN_ACTION &&
|
if (TrInput & IN_ACTION &&
|
||||||
(laraItem->Animation.ActiveState == LS_REACH || laraItem->Animation.ActiveState == LS_JUMP_UP) &&
|
(laraItem->Animation.ActiveState == LS_REACH || laraItem->Animation.ActiveState == LS_JUMP_UP) &&
|
||||||
(laraItem->Status || laraItem->Animation.Airborne) &&
|
(laraItem->Status || laraItem->Animation.IsAirborne) &&
|
||||||
laraItem->Animation.VerticalVelocity > 0 &&
|
laraItem->Animation.VerticalVelocity > 0 &&
|
||||||
laraInfo->Control.HandStatus == HandStatus::Free &&
|
laraInfo->Control.HandStatus == HandStatus::Free &&
|
||||||
!switchItem->Animation.ActiveState)
|
!switchItem->Animation.ActiveState)
|
||||||
|
@ -45,7 +45,7 @@ namespace TEN::Entities::Switches
|
||||||
laraItem->Animation.AnimNumber = LA_JUMPSWITCH_PULL;
|
laraItem->Animation.AnimNumber = LA_JUMPSWITCH_PULL;
|
||||||
laraItem->Animation.VerticalVelocity = 0;
|
laraItem->Animation.VerticalVelocity = 0;
|
||||||
laraItem->Animation.FrameNumber = g_Level.Anims[laraItem->Animation.AnimNumber].frameBase;
|
laraItem->Animation.FrameNumber = g_Level.Anims[laraItem->Animation.AnimNumber].frameBase;
|
||||||
laraItem->Animation.Airborne = false;
|
laraItem->Animation.IsAirborne = false;
|
||||||
laraInfo->Control.HandStatus = HandStatus::Busy;
|
laraInfo->Control.HandStatus = HandStatus::Busy;
|
||||||
switchItem->Animation.TargetState = SWITCH_ON;
|
switchItem->Animation.TargetState = SWITCH_ON;
|
||||||
switchItem->Status = ITEM_ACTIVE;
|
switchItem->Status = ITEM_ACTIVE;
|
||||||
|
|
|
@ -49,7 +49,7 @@ namespace TEN::Entities::Switches
|
||||||
if (TrInput & IN_ACTION &&
|
if (TrInput & IN_ACTION &&
|
||||||
laraItem->Animation.ActiveState == LS_IDLE &&
|
laraItem->Animation.ActiveState == LS_IDLE &&
|
||||||
laraItem->Animation.AnimNumber == LA_STAND_IDLE &&
|
laraItem->Animation.AnimNumber == LA_STAND_IDLE &&
|
||||||
laraItem->Animation.Airborne == false &&
|
laraItem->Animation.IsAirborne == false &&
|
||||||
laraInfo->Control.HandStatus == HandStatus::Free ||
|
laraInfo->Control.HandStatus == HandStatus::Free ||
|
||||||
laraInfo->Control.IsMoving && laraInfo->InteractedItem == itemNumber)
|
laraInfo->Control.IsMoving && laraInfo->InteractedItem == itemNumber)
|
||||||
{
|
{
|
||||||
|
|
|
@ -58,7 +58,7 @@ namespace TEN::Entities::Switches
|
||||||
if (TrInput & IN_ACTION &&
|
if (TrInput & IN_ACTION &&
|
||||||
laraItem->Animation.ActiveState == LS_IDLE &&
|
laraItem->Animation.ActiveState == LS_IDLE &&
|
||||||
laraItem->Animation.AnimNumber == LA_STAND_IDLE &&
|
laraItem->Animation.AnimNumber == LA_STAND_IDLE &&
|
||||||
laraItem->Animation.Airborne == false &&
|
laraItem->Animation.IsAirborne == false &&
|
||||||
laraInfo->Control.HandStatus == HandStatus::Free &&
|
laraInfo->Control.HandStatus == HandStatus::Free &&
|
||||||
switchItem->Animation.ActiveState == TURN_SWITCH_STOP ||
|
switchItem->Animation.ActiveState == TURN_SWITCH_STOP ||
|
||||||
laraInfo->Control.IsMoving && laraInfo->InteractedItem == itemNumber)
|
laraInfo->Control.IsMoving && laraInfo->InteractedItem == itemNumber)
|
||||||
|
|
|
@ -30,7 +30,7 @@ namespace TEN::Entities::TR1
|
||||||
|
|
||||||
constexpr auto SHIFT = 75;
|
constexpr auto SHIFT = 75;
|
||||||
|
|
||||||
#define APE_RUN_TURN_ANGLE ANGLE(5.0f)
|
#define APE_RUN_TURN_RATE_MAX ANGLE(5.0f)
|
||||||
#define APE_DISPLAY_ANGLE ANGLE(45.0f)
|
#define APE_DISPLAY_ANGLE ANGLE(45.0f)
|
||||||
|
|
||||||
enum ApeState
|
enum ApeState
|
||||||
|
@ -238,7 +238,7 @@ namespace TEN::Entities::TR1
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case APE_STATE_RUN_FORWARD:
|
case APE_STATE_RUN_FORWARD:
|
||||||
creatureInfo->MaxTurn = APE_RUN_TURN_ANGLE;
|
creatureInfo->MaxTurn = APE_RUN_TURN_RATE_MAX;
|
||||||
|
|
||||||
if (creatureInfo->Flags == 0 &&
|
if (creatureInfo->Flags == 0 &&
|
||||||
AI.angle > -APE_DISPLAY_ANGLE &&
|
AI.angle > -APE_DISPLAY_ANGLE &&
|
||||||
|
|
|
@ -32,8 +32,8 @@ namespace TEN::Entities::TR1
|
||||||
constexpr auto BEAR_REAR_CHANCE = 0x300;
|
constexpr auto BEAR_REAR_CHANCE = 0x300;
|
||||||
constexpr auto BEAR_DROP_CHANCE = 0x600;
|
constexpr auto BEAR_DROP_CHANCE = 0x600;
|
||||||
|
|
||||||
#define BEAR_WALK_TURN_ANGLE ANGLE(2.0f)
|
#define BEAR_WALK_TURN_RATE_MAX ANGLE(2.0f)
|
||||||
#define BEAR_RUN_TURN_ANGLE ANGLE(5.0f)
|
#define BEAR_RUN_TURN_RATE_MAX ANGLE(5.0f)
|
||||||
|
|
||||||
enum BearState
|
enum BearState
|
||||||
{
|
{
|
||||||
|
@ -163,7 +163,7 @@ namespace TEN::Entities::TR1
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BEAR_STATE_STROLL:
|
case BEAR_STATE_STROLL:
|
||||||
creature->MaxTurn = BEAR_WALK_TURN_ANGLE;
|
creature->MaxTurn = BEAR_WALK_TURN_RATE_MAX;
|
||||||
|
|
||||||
if (laraDead && item->TestBits(JointBitType::Touch, BearAttackJoints) && AI.ahead)
|
if (laraDead && item->TestBits(JointBitType::Touch, BearAttackJoints) && AI.ahead)
|
||||||
item->Animation.TargetState = BEAR_STATE_IDLE;
|
item->Animation.TargetState = BEAR_STATE_IDLE;
|
||||||
|
@ -183,7 +183,7 @@ namespace TEN::Entities::TR1
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BEAR_STATE_RUN_FORWARD:
|
case BEAR_STATE_RUN_FORWARD:
|
||||||
creature->MaxTurn = BEAR_RUN_TURN_ANGLE;
|
creature->MaxTurn = BEAR_RUN_TURN_RATE_MAX;
|
||||||
|
|
||||||
if (item->TestBits(JointBitType::Touch, BearAttackJoints))
|
if (item->TestBits(JointBitType::Touch, BearAttackJoints))
|
||||||
{
|
{
|
||||||
|
|
|
@ -92,12 +92,12 @@ namespace TEN::Entities::TR1
|
||||||
|
|
||||||
// Compare floor heights.
|
// Compare floor heights.
|
||||||
if (item->Floor >= laraFloorHeight + SECTOR(1) + 1 && // Add 1 to avoid bacon Lara dying when exiting water.
|
if (item->Floor >= laraFloorHeight + SECTOR(1) + 1 && // Add 1 to avoid bacon Lara dying when exiting water.
|
||||||
!LaraItem->Animation.Airborne)
|
!LaraItem->Animation.IsAirborne)
|
||||||
{
|
{
|
||||||
SetAnimation(item, LA_JUMP_WALL_SMASH_START);
|
SetAnimation(item, LA_JUMP_WALL_SMASH_START);
|
||||||
item->Animation.Velocity = 0;
|
item->Animation.Velocity = 0;
|
||||||
item->Animation.VerticalVelocity = 0;
|
item->Animation.VerticalVelocity = 0;
|
||||||
item->Animation.Airborne = true;
|
item->Animation.IsAirborne = true;
|
||||||
item->Data = -1;
|
item->Data = -1;
|
||||||
item->Pose.Position.y += 50;
|
item->Pose.Position.y += 50;
|
||||||
}
|
}
|
||||||
|
@ -115,7 +115,7 @@ namespace TEN::Entities::TR1
|
||||||
TestTriggers(item, true);
|
TestTriggers(item, true);
|
||||||
|
|
||||||
item->Animation.VerticalVelocity = 0;
|
item->Animation.VerticalVelocity = 0;
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
item->Animation.TargetState = LS_DEATH;
|
item->Animation.TargetState = LS_DEATH;
|
||||||
item->Animation.RequiredState = LS_DEATH;
|
item->Animation.RequiredState = LS_DEATH;
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,7 +95,7 @@ namespace TEN::Entities::TR1
|
||||||
{
|
{
|
||||||
case MUTANT_STATE_SET:
|
case MUTANT_STATE_SET:
|
||||||
item->Animation.TargetState = MUTANT_STATE_FALL;
|
item->Animation.TargetState = MUTANT_STATE_FALL;
|
||||||
item->Animation.Airborne = true;
|
item->Animation.IsAirborne = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MUTANT_STATE_IDLE:
|
case MUTANT_STATE_IDLE:
|
||||||
|
@ -204,7 +204,7 @@ namespace TEN::Entities::TR1
|
||||||
LaraItem->Pose.Position.z = item->Pose.Position.z;
|
LaraItem->Pose.Position.z = item->Pose.Position.z;
|
||||||
LaraItem->Pose.Orientation.y = item->Pose.Orientation.y;
|
LaraItem->Pose.Orientation.y = item->Pose.Orientation.y;
|
||||||
LaraItem->Pose.Orientation.x = LaraItem->Pose.Orientation.z = 0;
|
LaraItem->Pose.Orientation.x = LaraItem->Pose.Orientation.z = 0;
|
||||||
LaraItem->Animation.Airborne = false;
|
LaraItem->Animation.IsAirborne = false;
|
||||||
LaraItem->HitPoints = -1;
|
LaraItem->HitPoints = -1;
|
||||||
Lara.Air = -1;
|
Lara.Air = -1;
|
||||||
Lara.Control.HandStatus = HandStatus::Busy;
|
Lara.Control.HandStatus = HandStatus::Busy;
|
||||||
|
@ -229,7 +229,7 @@ namespace TEN::Entities::TR1
|
||||||
if (item->Pose.Position.y > item->Floor)
|
if (item->Pose.Position.y > item->Floor)
|
||||||
{
|
{
|
||||||
item->Animation.TargetState = MUTANT_STATE_IDLE;
|
item->Animation.TargetState = MUTANT_STATE_IDLE;
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
item->Pose.Position.y = item->Floor;
|
item->Pose.Position.y = item->Floor;
|
||||||
Camera.bounce = 500;
|
Camera.bounce = 500;
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,13 +88,13 @@ namespace TEN::Entities::TR1
|
||||||
case NATLA_STATE_FALL:
|
case NATLA_STATE_FALL:
|
||||||
if (item->Pose.Position.y < item->Floor)
|
if (item->Pose.Position.y < item->Floor)
|
||||||
{
|
{
|
||||||
item->Animation.Airborne = true;
|
item->Animation.IsAirborne = true;
|
||||||
item->Animation.Velocity = 0;
|
item->Animation.Velocity = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
item->Animation.TargetState = NATLA_STATE_SEMI_DEATH;
|
item->Animation.TargetState = NATLA_STATE_SEMI_DEATH;
|
||||||
item->Animation.Airborne = 0;
|
item->Animation.IsAirborne = 0;
|
||||||
item->Pose.Position.y = item->Floor;
|
item->Pose.Position.y = item->Floor;
|
||||||
timer = 0;
|
timer = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -180,7 +180,7 @@ void DragonCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll)
|
||||||
if ((anim == DRAGON_ANIM_DEAD || (anim == DRAGON_ANIM_DEAD + 1 && frame <= DRAGON_ALMOST_LIVE)) &&
|
if ((anim == DRAGON_ANIM_DEAD || (anim == DRAGON_ANIM_DEAD + 1 && frame <= DRAGON_ALMOST_LIVE)) &&
|
||||||
TrInput & IN_ACTION &&
|
TrInput & IN_ACTION &&
|
||||||
item->ObjectNumber == ID_DRAGON_BACK &&
|
item->ObjectNumber == ID_DRAGON_BACK &&
|
||||||
!laraItem->Animation.Airborne &&
|
!laraItem->Animation.IsAirborne &&
|
||||||
shift <= DRAGON_MID &&
|
shift <= DRAGON_MID &&
|
||||||
shift > (DRAGON_CLOSE - 350) &&
|
shift > (DRAGON_CLOSE - 350) &&
|
||||||
sideShift > -350 &&
|
sideShift > -350 &&
|
||||||
|
@ -194,7 +194,7 @@ void DragonCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll)
|
||||||
laraItem->Animation.TargetState = 7;
|
laraItem->Animation.TargetState = 7;
|
||||||
|
|
||||||
laraItem->Pose = item->Pose;
|
laraItem->Pose = item->Pose;
|
||||||
laraItem->Animation.Airborne = false;
|
laraItem->Animation.IsAirborne = false;
|
||||||
laraItem->Animation.Velocity = 0;
|
laraItem->Animation.Velocity = 0;
|
||||||
laraItem->Animation.VerticalVelocity = 0;
|
laraItem->Animation.VerticalVelocity = 0;
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ void EagleControl(short itemNumber)
|
||||||
{
|
{
|
||||||
item->Pose.Position.y = item->Floor;
|
item->Pose.Position.y = item->Floor;
|
||||||
item->Animation.VerticalVelocity = 0;
|
item->Animation.VerticalVelocity = 0;
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
item->Animation.TargetState = 5;
|
item->Animation.TargetState = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ void EagleControl(short itemNumber)
|
||||||
item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase;
|
item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase;
|
||||||
item->Animation.ActiveState = 4;
|
item->Animation.ActiveState = 4;
|
||||||
item->Animation.Velocity = 0;
|
item->Animation.Velocity = 0;
|
||||||
item->Animation.Airborne = true;
|
item->Animation.IsAirborne = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
item->Pose.Orientation.x = 0;
|
item->Pose.Orientation.x = 0;
|
||||||
|
|
|
@ -246,7 +246,7 @@ void SkidooManControl(short riderItemNumber)
|
||||||
RemoveActiveItem(riderItemNumber);
|
RemoveActiveItem(riderItemNumber);
|
||||||
riderItem->Collidable = false;
|
riderItem->Collidable = false;
|
||||||
riderItem->HitPoints = NOT_TARGETABLE;
|
riderItem->HitPoints = NOT_TARGETABLE;
|
||||||
riderItem->Flags |= ONESHOT;
|
riderItem->Flags |= IFLAG_INVISIBLE;
|
||||||
|
|
||||||
DisableEntityAI(itemNumber);
|
DisableEntityAI(itemNumber);
|
||||||
item->ObjectNumber = ID_SNOWMOBILE;
|
item->ObjectNumber = ID_SNOWMOBILE;
|
||||||
|
|
|
@ -61,7 +61,7 @@ void SwordGuardianControl(short itemNumber)
|
||||||
DisableEntityAI(itemNumber);
|
DisableEntityAI(itemNumber);
|
||||||
KillItem(itemNumber);
|
KillItem(itemNumber);
|
||||||
//item->status = ITEM_DESACTIVATED;
|
//item->status = ITEM_DESACTIVATED;
|
||||||
//item->flags |= ONESHOT;
|
//item->flags |= IFLAG_INVISIBLE;
|
||||||
item->Animation.ActiveState = 12;
|
item->Animation.ActiveState = 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ void SpringBoardControl(short itemNumber)
|
||||||
LaraItem->Animation.FrameNumber = g_Level.Anims[LaraItem->Animation.AnimNumber].frameBase;
|
LaraItem->Animation.FrameNumber = g_Level.Anims[LaraItem->Animation.AnimNumber].frameBase;
|
||||||
LaraItem->Animation.ActiveState = LS_JUMP_FORWARD;
|
LaraItem->Animation.ActiveState = LS_JUMP_FORWARD;
|
||||||
LaraItem->Animation.TargetState = LS_JUMP_FORWARD;
|
LaraItem->Animation.TargetState = LS_JUMP_FORWARD;
|
||||||
LaraItem->Animation.Airborne = true;
|
LaraItem->Animation.IsAirborne = true;
|
||||||
LaraItem->Animation.VerticalVelocity = -240;
|
LaraItem->Animation.VerticalVelocity = -240;
|
||||||
|
|
||||||
item->Animation.TargetState = 1;
|
item->Animation.TargetState = 1;
|
||||||
|
|
|
@ -1,995 +0,0 @@
|
||||||
#include "framework.h"
|
|
||||||
#include "Objects/TR2/Vehicles/boat.h"
|
|
||||||
|
|
||||||
#include "Game/animation.h"
|
|
||||||
#include "Game/camera.h"
|
|
||||||
#include "Game/collision/collide_item.h"
|
|
||||||
#include "Game/collision/sphere.h"
|
|
||||||
#include "Game/effects/effects.h"
|
|
||||||
#include "Game/items.h"
|
|
||||||
#include "Game/Lara/lara.h"
|
|
||||||
#include "Game/Lara/lara_helpers.h"
|
|
||||||
#include "Game/effects/simple_particle.h"
|
|
||||||
#include "Objects/TR2/Vehicles/boat_info.h"
|
|
||||||
#include "Sound/sound.h"
|
|
||||||
#include "Specific/input.h"
|
|
||||||
#include "Specific/level.h"
|
|
||||||
#include "Specific/setup.h"
|
|
||||||
|
|
||||||
using namespace TEN::Input;
|
|
||||||
|
|
||||||
namespace TEN::Entities::Vehicles
|
|
||||||
{
|
|
||||||
#define BOAT_UNDO_TURN ANGLE(0.25f)
|
|
||||||
#define BOAT_TURN (ANGLE(0.25f) / 2)
|
|
||||||
#define BOAT_MAX_TURN ANGLE(4.0f)
|
|
||||||
#define BOAT_MAX_VELOCITY 110
|
|
||||||
#define BOAT_SLOW_SPEED (BOAT_MAX_VELOCITY / 3)
|
|
||||||
#define BOAT_FAST_SPEED (BOAT_MAX_VELOCITY + 75)
|
|
||||||
#define BOAT_MIN_SPEED 20
|
|
||||||
#define BOAT_ACCELERATION 5
|
|
||||||
#define BOAT_BRAKE 5
|
|
||||||
#define BOAT_SLOWDOWN 1
|
|
||||||
#define BOAT_REVERSE -2 // -5
|
|
||||||
#define BOAT_MAX_BACK -20
|
|
||||||
#define BOAT_MAX_KICK -80
|
|
||||||
#define BOAT_SLIP 10
|
|
||||||
#define BOAT_SIDE_SLIP 30
|
|
||||||
#define BOAT_FRONT 750
|
|
||||||
#define BOAT_BACK -700
|
|
||||||
#define BOAT_SIDE 300
|
|
||||||
#define BOAT_RADIUS 500
|
|
||||||
#define BOAT_SNOW 500
|
|
||||||
#define BOAT_MAX_HEIGHT CLICK(1)
|
|
||||||
#define DISMOUNT_DISTANCE SECTOR(1)
|
|
||||||
#define BOAT_SOUND_CEILING SECTOR(5)
|
|
||||||
#define BOAT_TIP (BOAT_FRONT + 250)
|
|
||||||
|
|
||||||
#define SBOAT_IN_ACCELERATE IN_FORWARD
|
|
||||||
#define SBOAT_IN_REVERSE IN_BACK
|
|
||||||
#define SBOAT_IN_SPEED (IN_ACTION | IN_SPRINT)
|
|
||||||
#define SBOAT_IN_SLOW IN_WALK
|
|
||||||
#define SBOAT_IN_DISMOUNT (IN_JUMP | IN_ROLL)
|
|
||||||
#define SBOAT_IN_LEFT (IN_LEFT | IN_LSTEP)
|
|
||||||
#define SBOAT_IN_RIGHT (IN_RIGHT | IN_RSTEP)
|
|
||||||
|
|
||||||
enum SpeedBoatState
|
|
||||||
{
|
|
||||||
SBOAT_STATE_MOUNT = 0,
|
|
||||||
SBOAT_STATE_IDLE = 1,
|
|
||||||
SBOAT_STATE_MOVING = 2,
|
|
||||||
SBOAT_STATE_DISMOUNT_RIGHT = 3,
|
|
||||||
SBOAT_STATE_DISMOUNT_LEFT = 4,
|
|
||||||
SBOAT_STATE_HIT = 5,
|
|
||||||
SBOAT_STATE_FALL = 6,
|
|
||||||
SBOAT_STATE_TURN_RIGHT = 7,
|
|
||||||
SBOAT_STATE_DEATH = 8,
|
|
||||||
SBOAT_STATE_TURN_LEFT = 9
|
|
||||||
};
|
|
||||||
|
|
||||||
enum SpeedBoatAnim
|
|
||||||
{
|
|
||||||
SBOAT_ANIM_MOUNT_LEFT = 0,
|
|
||||||
SBOAT_ANIM_IDLE = 1, // ?
|
|
||||||
SBOAT_ANIM_FORWARD = 2, // ?
|
|
||||||
|
|
||||||
SBOAT_ANIM_DISMOUNT_LEFT = 5,
|
|
||||||
SBOAT_ANIM_MOUNT_JUMP = 6,
|
|
||||||
SBOAT_ANIM_DISMOUNT_RIGHT = 7,
|
|
||||||
SBOAT_ANIM_MOUNT_RIGHT = 8,
|
|
||||||
|
|
||||||
SBOAT_ANIM_HIT_LEFT = 11,
|
|
||||||
SBOAT_ANIM_HIT_RIGHT = 12,
|
|
||||||
SBOAT_ANIM_HIT_FRONT = 13,
|
|
||||||
SBOAT_ANIM_HIT_BACK = 14,
|
|
||||||
SBOAT_ANIM_LEAP_START = 15,
|
|
||||||
SBOAT_ANIM_LEAP = 16,
|
|
||||||
SBOAT_ANIM_LEAP_END = 17,
|
|
||||||
SBOAT_ANIM_DEATH = 18
|
|
||||||
};
|
|
||||||
|
|
||||||
void InitialiseSpeedBoat(short itemNumber)
|
|
||||||
{
|
|
||||||
auto* sBoatItem = &g_Level.Items[itemNumber];
|
|
||||||
sBoatItem->Data = SpeedBoatInfo();
|
|
||||||
auto* sBoat = (SpeedBoatInfo*)sBoatItem->Data;
|
|
||||||
|
|
||||||
sBoat->TurnRate = 0;
|
|
||||||
sBoat->LeanAngle = 0;
|
|
||||||
sBoat->ExtraRotation = 0;
|
|
||||||
sBoat->LeftVerticalVelocity = 0;
|
|
||||||
sBoat->RightVerticalVelocity = 0;
|
|
||||||
sBoat->Water = 0;
|
|
||||||
sBoat->Pitch = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
BoatMountType GetSpeedBoatMountType(ItemInfo* laraItem, ItemInfo* sBoatItem, CollisionInfo* coll)
|
|
||||||
{
|
|
||||||
auto* lara = GetLaraInfo(laraItem);
|
|
||||||
|
|
||||||
BoatMountType mountType = BoatMountType::None;
|
|
||||||
|
|
||||||
if (lara->Control.HandStatus != HandStatus::Free)
|
|
||||||
return mountType;
|
|
||||||
|
|
||||||
if (!TestBoundsCollide(sBoatItem, laraItem, coll->Setup.Radius))
|
|
||||||
return mountType;
|
|
||||||
|
|
||||||
if (!TestCollision(sBoatItem, laraItem))
|
|
||||||
return mountType;
|
|
||||||
|
|
||||||
int distance = (laraItem->Pose.Position.z - sBoatItem->Pose.Position.z) * phd_cos(-sBoatItem->Pose.Orientation.y) - (laraItem->Pose.Position.x - sBoatItem->Pose.Position.x) * phd_sin(-sBoatItem->Pose.Orientation.y);
|
|
||||||
if (distance > 200)
|
|
||||||
return mountType;
|
|
||||||
|
|
||||||
short deltaAngle = sBoatItem->Pose.Orientation.y - laraItem->Pose.Orientation.y;
|
|
||||||
if (lara->Control.WaterStatus == WaterStatus::TreadWater || lara->Control.WaterStatus == WaterStatus::Wade)
|
|
||||||
{
|
|
||||||
if (!(TrInput & IN_ACTION) || laraItem->Animation.Airborne || sBoatItem->Animation.Velocity)
|
|
||||||
return mountType;
|
|
||||||
|
|
||||||
if (deltaAngle > ANGLE(45.0f) && deltaAngle < ANGLE(135.0f))
|
|
||||||
mountType = BoatMountType::WaterRight;
|
|
||||||
else if (deltaAngle > -ANGLE(135.0f) && deltaAngle < -ANGLE(45.0f))
|
|
||||||
mountType = BoatMountType::WaterLeft;
|
|
||||||
}
|
|
||||||
else if (lara->Control.WaterStatus == WaterStatus::Dry)
|
|
||||||
{
|
|
||||||
if (laraItem->Animation.VerticalVelocity > 0)
|
|
||||||
{
|
|
||||||
if (deltaAngle > -ANGLE(135.0f) && deltaAngle < ANGLE(135.0f) &&
|
|
||||||
laraItem->Pose.Position.y > sBoatItem->Pose.Position.y)
|
|
||||||
{
|
|
||||||
mountType = BoatMountType::Jump;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (laraItem->Animation.VerticalVelocity == 0)
|
|
||||||
{
|
|
||||||
if (deltaAngle > -ANGLE(135.0f) && deltaAngle < ANGLE(135.0f))
|
|
||||||
{
|
|
||||||
if (laraItem->Pose.Position.x == sBoatItem->Pose.Position.x &&
|
|
||||||
laraItem->Pose.Position.y == sBoatItem->Pose.Position.y &&
|
|
||||||
laraItem->Pose.Position.z == sBoatItem->Pose.Position.z)
|
|
||||||
{
|
|
||||||
mountType = BoatMountType::StartPosition;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
mountType = BoatMountType::Jump;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return mountType;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TestSpeedBoatDismount(ItemInfo* sBoatItem, int direction)
|
|
||||||
{
|
|
||||||
short angle;
|
|
||||||
if (direction < 0)
|
|
||||||
angle = sBoatItem->Pose.Orientation.y - ANGLE(90.0f);
|
|
||||||
else
|
|
||||||
angle = sBoatItem->Pose.Orientation.y + ANGLE(90.0f);
|
|
||||||
|
|
||||||
int x = sBoatItem->Pose.Position.x + DISMOUNT_DISTANCE * phd_sin(angle);
|
|
||||||
int y = sBoatItem->Pose.Position.y;
|
|
||||||
int z = sBoatItem->Pose.Position.z + DISMOUNT_DISTANCE * phd_cos(angle);
|
|
||||||
auto probe = GetCollision(x, y, z, sBoatItem->RoomNumber);
|
|
||||||
|
|
||||||
if ((probe.Position.Floor - sBoatItem->Pose.Position.y) < -CLICK(2))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (probe.Position.FloorSlope ||
|
|
||||||
probe.Position.Floor == NO_HEIGHT)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((probe.Position.Floor - probe.Position.Ceiling) < LARA_HEIGHT ||
|
|
||||||
(probe.Position.Ceiling - sBoatItem->Pose.Position.y) > -LARA_HEIGHT)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DoSpeedBoatDismount(ItemInfo* laraItem, ItemInfo* sBoatItem)
|
|
||||||
{
|
|
||||||
auto* lara = GetLaraInfo(laraItem);
|
|
||||||
|
|
||||||
if ((laraItem->Animation.ActiveState == SBOAT_STATE_DISMOUNT_LEFT ||
|
|
||||||
laraItem->Animation.ActiveState == SBOAT_STATE_DISMOUNT_RIGHT) &&
|
|
||||||
TestLastFrame(laraItem, laraItem->Animation.AnimNumber))
|
|
||||||
{
|
|
||||||
if (laraItem->Animation.ActiveState == SBOAT_STATE_DISMOUNT_LEFT)
|
|
||||||
laraItem->Pose.Orientation.y -= ANGLE(90.0f);
|
|
||||||
else if (laraItem->Animation.ActiveState == SBOAT_STATE_DISMOUNT_RIGHT)
|
|
||||||
laraItem->Pose.Orientation.y += ANGLE(90.0f);
|
|
||||||
|
|
||||||
SetAnimation(laraItem, LA_JUMP_FORWARD);
|
|
||||||
laraItem->Animation.Velocity = 40;
|
|
||||||
laraItem->Animation.VerticalVelocity = -50;
|
|
||||||
laraItem->Animation.Airborne = true;
|
|
||||||
laraItem->Pose.Orientation.x = 0;
|
|
||||||
laraItem->Pose.Orientation.z = 0;
|
|
||||||
lara->Vehicle = NO_ITEM;
|
|
||||||
|
|
||||||
int x = laraItem->Pose.Position.x + 360 * phd_sin(laraItem->Pose.Orientation.y);
|
|
||||||
int y = laraItem->Pose.Position.y - 90;
|
|
||||||
int z = laraItem->Pose.Position.z + 360 * phd_cos(laraItem->Pose.Orientation.y);
|
|
||||||
auto probe = GetCollision(x, y, z, laraItem->RoomNumber);
|
|
||||||
|
|
||||||
if (probe.Position.Floor >= (y - CLICK(1)))
|
|
||||||
{
|
|
||||||
laraItem->Pose.Position.x = x;
|
|
||||||
laraItem->Pose.Position.z = z;
|
|
||||||
|
|
||||||
if (probe.RoomNumber != laraItem->RoomNumber)
|
|
||||||
ItemNewRoom(lara->ItemNumber, probe.RoomNumber);
|
|
||||||
}
|
|
||||||
laraItem->Pose.Position.y = y;
|
|
||||||
|
|
||||||
sBoatItem->Animation.AnimNumber = Objects[ID_SPEEDBOAT].animIndex;
|
|
||||||
sBoatItem->Animation.FrameNumber = g_Level.Anims[sBoatItem->Animation.AnimNumber].frameBase;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int SpeedBoatTestWaterHeight(ItemInfo* sBoatItem, int zOffset, int xOffset, Vector3Int* pos)
|
|
||||||
{
|
|
||||||
float s = phd_sin(sBoatItem->Pose.Orientation.y);
|
|
||||||
float c = phd_cos(sBoatItem->Pose.Orientation.y);
|
|
||||||
|
|
||||||
pos->x = sBoatItem->Pose.Position.x + zOffset * s + xOffset * c;
|
|
||||||
pos->y = sBoatItem->Pose.Position.y - zOffset * phd_sin(sBoatItem->Pose.Orientation.x) + xOffset * phd_sin(sBoatItem->Pose.Orientation.z);
|
|
||||||
pos->z = sBoatItem->Pose.Position.z + zOffset * c - xOffset * s;
|
|
||||||
|
|
||||||
auto probe = GetCollision(pos->x, pos->y, pos->z, sBoatItem->RoomNumber);
|
|
||||||
auto height = GetWaterHeight(pos->x, pos->y, pos->z, probe.RoomNumber);
|
|
||||||
|
|
||||||
if (height == NO_HEIGHT)
|
|
||||||
{
|
|
||||||
height = probe.Position.Floor;
|
|
||||||
if (height == NO_HEIGHT)
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (height - 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SpeedBoatDoBoatShift(ItemInfo* sBoatItem, int itemNumber)
|
|
||||||
{
|
|
||||||
short itemNumber2 = g_Level.Rooms[sBoatItem->RoomNumber].itemNumber;
|
|
||||||
while (itemNumber2 != NO_ITEM)
|
|
||||||
{
|
|
||||||
auto* item = &g_Level.Items[itemNumber2];
|
|
||||||
|
|
||||||
if (item->ObjectNumber == ID_SPEEDBOAT && itemNumber2 != itemNumber && Lara.Vehicle != itemNumber2)
|
|
||||||
{
|
|
||||||
int x = item->Pose.Position.x - sBoatItem->Pose.Position.x;
|
|
||||||
int z = item->Pose.Position.z - sBoatItem->Pose.Position.z;
|
|
||||||
|
|
||||||
int distance = pow(x, 2) + pow(z, 2);
|
|
||||||
int radius = pow(BOAT_RADIUS * 2, 2);
|
|
||||||
if (distance < radius)
|
|
||||||
{
|
|
||||||
sBoatItem->Pose.Position.x = item->Pose.Position.x - x * radius / distance;
|
|
||||||
sBoatItem->Pose.Position.z = item->Pose.Position.z - z * radius / distance;
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: mine and gondola
|
|
||||||
|
|
||||||
itemNumber2 = item->NextItem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
short SpeedBoatDoShift(ItemInfo* sBoatItem, Vector3Int* pos, Vector3Int* old)
|
|
||||||
{
|
|
||||||
int x = pos->x / SECTOR(1);
|
|
||||||
int z = pos->z / SECTOR(1);
|
|
||||||
|
|
||||||
int xOld = old->x / SECTOR(1);
|
|
||||||
int zOld = old->z / SECTOR(1);
|
|
||||||
|
|
||||||
int shiftX = pos->x & (SECTOR(1) - 1);
|
|
||||||
int shiftZ = pos->z & (SECTOR(1) - 1);
|
|
||||||
|
|
||||||
if (x == xOld)
|
|
||||||
{
|
|
||||||
if (z == zOld)
|
|
||||||
{
|
|
||||||
sBoatItem->Pose.Position.z += (old->z - pos->z);
|
|
||||||
sBoatItem->Pose.Position.x += (old->x - pos->x);
|
|
||||||
}
|
|
||||||
else if (z > zOld)
|
|
||||||
{
|
|
||||||
sBoatItem->Pose.Position.z -= shiftZ + 1;
|
|
||||||
return (pos->x - sBoatItem->Pose.Position.x);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sBoatItem->Pose.Position.z += SECTOR(1) - shiftZ;
|
|
||||||
return (sBoatItem->Pose.Position.x - pos->x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (z == zOld)
|
|
||||||
{
|
|
||||||
if (x > xOld)
|
|
||||||
{
|
|
||||||
sBoatItem->Pose.Position.x -= shiftX + 1;
|
|
||||||
return (sBoatItem->Pose.Position.z - pos->z);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sBoatItem->Pose.Position.x += SECTOR(1) - shiftX;
|
|
||||||
return (pos->z - sBoatItem->Pose.Position.z);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
x = 0;
|
|
||||||
z = 0;
|
|
||||||
|
|
||||||
auto probe = GetCollision(old->x, pos->y, pos->z, sBoatItem->RoomNumber);
|
|
||||||
if (probe.Position.Floor < (old->y - CLICK(1)))
|
|
||||||
{
|
|
||||||
if (pos->z > old->z)
|
|
||||||
z = -shiftZ - 1;
|
|
||||||
else
|
|
||||||
z = SECTOR(1) - shiftZ;
|
|
||||||
}
|
|
||||||
|
|
||||||
probe = GetCollision(pos->x, pos->y, old->z, sBoatItem->RoomNumber);
|
|
||||||
if (probe.Position.Floor < (old->y - CLICK(1)))
|
|
||||||
{
|
|
||||||
if (pos->x > old->x)
|
|
||||||
x = -shiftX - 1;
|
|
||||||
else
|
|
||||||
x = SECTOR(1) - shiftX;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (x && z)
|
|
||||||
{
|
|
||||||
sBoatItem->Pose.Position.z += z;
|
|
||||||
sBoatItem->Pose.Position.x += x;
|
|
||||||
}
|
|
||||||
else if (z)
|
|
||||||
{
|
|
||||||
sBoatItem->Pose.Position.z += z;
|
|
||||||
if (z > 0)
|
|
||||||
return (sBoatItem->Pose.Position.x - pos->x);
|
|
||||||
else
|
|
||||||
return (pos->x - sBoatItem->Pose.Position.x);
|
|
||||||
}
|
|
||||||
else if (x)
|
|
||||||
{
|
|
||||||
sBoatItem->Pose.Position.x += x;
|
|
||||||
if (x > 0)
|
|
||||||
return (pos->z - sBoatItem->Pose.Position.z);
|
|
||||||
else
|
|
||||||
return (sBoatItem->Pose.Position.z - pos->z);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sBoatItem->Pose.Position.z += (old->z - pos->z);
|
|
||||||
sBoatItem->Pose.Position.x += (old->x - pos->x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int GetSpeedBoatHitAnim(ItemInfo* sBoatItem, Vector3Int* moved)
|
|
||||||
{
|
|
||||||
moved->x = sBoatItem->Pose.Position.x - moved->x;
|
|
||||||
moved->z = sBoatItem->Pose.Position.z - moved->z;
|
|
||||||
|
|
||||||
if (moved->x || moved->z)
|
|
||||||
{
|
|
||||||
float s = phd_sin(sBoatItem->Pose.Orientation.y);
|
|
||||||
float c = phd_cos(sBoatItem->Pose.Orientation.y);
|
|
||||||
|
|
||||||
int front = moved->z * c + moved->x * s;
|
|
||||||
int side = -moved->z * s + moved->x * c;
|
|
||||||
|
|
||||||
if (abs(front) > abs(side))
|
|
||||||
{
|
|
||||||
if (front > 0)
|
|
||||||
return SBOAT_ANIM_HIT_BACK;
|
|
||||||
else
|
|
||||||
return SBOAT_ANIM_HIT_FRONT;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (side > 0)
|
|
||||||
return SBOAT_ANIM_HIT_LEFT;
|
|
||||||
else
|
|
||||||
return SBOAT_ANIM_HIT_RIGHT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int DoSpeedBoatDynamics(int height, int verticalVelocity, int* y)
|
|
||||||
{
|
|
||||||
if (height > *y)
|
|
||||||
{
|
|
||||||
*y += verticalVelocity;
|
|
||||||
if (*y > height)
|
|
||||||
{
|
|
||||||
*y = height;
|
|
||||||
verticalVelocity = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
verticalVelocity += GRAVITY;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
verticalVelocity += ((height - *y - verticalVelocity) / 8);
|
|
||||||
if (verticalVelocity < BOAT_MAX_BACK)
|
|
||||||
verticalVelocity = BOAT_MAX_BACK;
|
|
||||||
|
|
||||||
if (*y > height)
|
|
||||||
*y = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
return verticalVelocity;
|
|
||||||
}
|
|
||||||
|
|
||||||
int SpeedBoatDynamics(ItemInfo* laraItem, short itemNumber)
|
|
||||||
{
|
|
||||||
auto* lara = GetLaraInfo(laraItem);
|
|
||||||
auto* sBoatItem = &g_Level.Items[itemNumber];
|
|
||||||
auto* sBoat = (SpeedBoatInfo*)sBoatItem->Data;
|
|
||||||
|
|
||||||
sBoatItem->Pose.Orientation.z -= sBoat->LeanAngle;
|
|
||||||
|
|
||||||
Vector3Int old, frontLeftOld, frontRightOld, backLeftOld, backRightOld, frontOld;
|
|
||||||
int heightFrontLeftOld = SpeedBoatTestWaterHeight(sBoatItem, BOAT_FRONT, -BOAT_SIDE, &frontLeftOld);
|
|
||||||
int heightFrontRightOld = SpeedBoatTestWaterHeight(sBoatItem, BOAT_FRONT, BOAT_SIDE, &frontRightOld);
|
|
||||||
int heightBackLeftOld = SpeedBoatTestWaterHeight(sBoatItem, -BOAT_FRONT, -BOAT_SIDE, &backLeftOld);
|
|
||||||
int heightBackRightOld = SpeedBoatTestWaterHeight(sBoatItem, -BOAT_FRONT, BOAT_SIDE, &backRightOld);
|
|
||||||
int heightFrontOld = SpeedBoatTestWaterHeight(sBoatItem, BOAT_TIP, 0, &frontOld);
|
|
||||||
|
|
||||||
old.x = sBoatItem->Pose.Position.x;
|
|
||||||
old.y = sBoatItem->Pose.Position.y;
|
|
||||||
old.z = sBoatItem->Pose.Position.z;
|
|
||||||
|
|
||||||
if (backLeftOld.y > heightBackLeftOld)
|
|
||||||
backLeftOld.y = heightBackLeftOld;
|
|
||||||
if (backRightOld.y > heightBackRightOld)
|
|
||||||
backRightOld.y = heightBackRightOld;
|
|
||||||
if (frontLeftOld.y > heightFrontLeftOld)
|
|
||||||
frontLeftOld.y = heightFrontLeftOld;
|
|
||||||
if (frontRightOld.y > heightFrontRightOld)
|
|
||||||
frontRightOld.y = heightFrontRightOld;
|
|
||||||
if (frontOld.y > heightFrontOld)
|
|
||||||
frontOld.y = heightFrontOld;
|
|
||||||
|
|
||||||
sBoatItem->Pose.Orientation.y += sBoat->TurnRate + sBoat->ExtraRotation;
|
|
||||||
sBoat->LeanAngle = sBoat->TurnRate * 6;
|
|
||||||
|
|
||||||
sBoatItem->Pose.Position.x += sBoatItem->Animation.Velocity * phd_sin(sBoatItem->Pose.Orientation.y);
|
|
||||||
sBoatItem->Pose.Position.z += sBoatItem->Animation.Velocity * phd_cos(sBoatItem->Pose.Orientation.y);
|
|
||||||
|
|
||||||
int slip = BOAT_SIDE_SLIP * phd_sin(sBoatItem->Pose.Orientation.z);
|
|
||||||
if (!slip && sBoatItem->Pose.Orientation.z)
|
|
||||||
slip = (sBoatItem->Pose.Orientation.z > 0) ? 1 : -1;
|
|
||||||
sBoatItem->Pose.Position.x += slip * phd_sin(sBoatItem->Pose.Orientation.y);
|
|
||||||
sBoatItem->Pose.Position.z -= slip * phd_cos(sBoatItem->Pose.Orientation.y);
|
|
||||||
|
|
||||||
slip = BOAT_SLIP * phd_sin(sBoatItem->Pose.Orientation.x);
|
|
||||||
if (!slip && sBoatItem->Pose.Orientation.x)
|
|
||||||
slip = (sBoatItem->Pose.Orientation.x > 0) ? 1 : -1;
|
|
||||||
sBoatItem->Pose.Position.x -= slip * phd_sin(sBoatItem->Pose.Orientation.y);
|
|
||||||
sBoatItem->Pose.Position.z -= slip * phd_cos(sBoatItem->Pose.Orientation.y);
|
|
||||||
|
|
||||||
auto moved = Vector3Int(sBoatItem->Pose.Position.x, 0, sBoatItem->Pose.Position.z);
|
|
||||||
|
|
||||||
SpeedBoatDoBoatShift(sBoatItem, itemNumber);
|
|
||||||
|
|
||||||
Vector3Int fl, fr, br, bl, f;
|
|
||||||
short rotation = 0;
|
|
||||||
auto heightBackLeft = SpeedBoatTestWaterHeight(sBoatItem, -BOAT_FRONT, -BOAT_SIDE, &bl);
|
|
||||||
if (heightBackLeft < (backLeftOld.y - CLICK(0.5f)))
|
|
||||||
rotation = SpeedBoatDoShift(sBoatItem, &bl, &backLeftOld);
|
|
||||||
|
|
||||||
auto heightBackRight = SpeedBoatTestWaterHeight(sBoatItem, -BOAT_FRONT, BOAT_SIDE, &br);
|
|
||||||
if (heightBackRight < (backRightOld.y - CLICK(0.5f)))
|
|
||||||
rotation += SpeedBoatDoShift(sBoatItem, &br, &backRightOld);
|
|
||||||
|
|
||||||
auto heightFrontLeft = SpeedBoatTestWaterHeight(sBoatItem, BOAT_FRONT, -BOAT_SIDE, &fl);
|
|
||||||
if (heightFrontLeft < (frontLeftOld.y - CLICK(0.5f)))
|
|
||||||
rotation += SpeedBoatDoShift(sBoatItem, &fl, &frontLeftOld);
|
|
||||||
|
|
||||||
auto heightFrontRight = SpeedBoatTestWaterHeight(sBoatItem, BOAT_FRONT, BOAT_SIDE, &fr);
|
|
||||||
if (heightFrontRight < (frontRightOld.y - CLICK(0.5f)))
|
|
||||||
rotation += SpeedBoatDoShift(sBoatItem, &fr, &frontRightOld);
|
|
||||||
|
|
||||||
int heightFront = 0;
|
|
||||||
if (!slip)
|
|
||||||
{
|
|
||||||
heightFront = SpeedBoatTestWaterHeight(sBoatItem, BOAT_TIP, 0, &f);
|
|
||||||
if (heightFront < (frontOld.y - CLICK(0.5f)))
|
|
||||||
SpeedBoatDoShift(sBoatItem, &f, &frontOld);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto probe = GetCollision(sBoatItem);
|
|
||||||
auto height = GetWaterHeight(sBoatItem->Pose.Position.x, sBoatItem->Pose.Position.y - 5, sBoatItem->Pose.Position.z, probe.RoomNumber);
|
|
||||||
|
|
||||||
if (height == NO_HEIGHT)
|
|
||||||
height = GetFloorHeight(probe.Block, sBoatItem->Pose.Position.x, sBoatItem->Pose.Position.y - 5, sBoatItem->Pose.Position.z);
|
|
||||||
|
|
||||||
if (height < (sBoatItem->Pose.Position.y - CLICK(0.5f)))
|
|
||||||
SpeedBoatDoShift(sBoatItem, (Vector3Int*)&sBoatItem->Pose, &old);
|
|
||||||
|
|
||||||
sBoat->ExtraRotation = rotation;
|
|
||||||
|
|
||||||
DoVehicleCollision(sBoatItem, BOAT_RADIUS);
|
|
||||||
|
|
||||||
auto collide = GetSpeedBoatHitAnim(sBoatItem, &moved);
|
|
||||||
|
|
||||||
int newVelocity = 0;
|
|
||||||
if (slip || collide)
|
|
||||||
{
|
|
||||||
newVelocity = (sBoatItem->Pose.Position.z - old.z) * phd_cos(sBoatItem->Pose.Orientation.y) + (sBoatItem->Pose.Position.x - old.x) * phd_sin(sBoatItem->Pose.Orientation.y);
|
|
||||||
|
|
||||||
if (lara->Vehicle == itemNumber && sBoatItem->Animation.Velocity > BOAT_MAX_VELOCITY + BOAT_ACCELERATION && newVelocity < sBoatItem->Animation.Velocity - 10)
|
|
||||||
{
|
|
||||||
DoDamage(laraItem, sBoatItem->Animation.Velocity);
|
|
||||||
SoundEffect(SFX_TR4_LARA_INJURY, &laraItem->Pose);
|
|
||||||
newVelocity /= 2;
|
|
||||||
sBoatItem->Animation.Velocity /= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (slip)
|
|
||||||
{
|
|
||||||
if (sBoatItem->Animation.Velocity <= BOAT_MAX_VELOCITY + 10)
|
|
||||||
sBoatItem->Animation.Velocity = newVelocity;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (sBoatItem->Animation.Velocity > 0 && newVelocity < sBoatItem->Animation.Velocity)
|
|
||||||
sBoatItem->Animation.Velocity = newVelocity;
|
|
||||||
else if (sBoatItem->Animation.Velocity < 0 && newVelocity > sBoatItem->Animation.Velocity)
|
|
||||||
sBoatItem->Animation.Velocity = newVelocity;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sBoatItem->Animation.Velocity < BOAT_MAX_BACK)
|
|
||||||
sBoatItem->Animation.Velocity = BOAT_MAX_BACK;
|
|
||||||
}
|
|
||||||
|
|
||||||
return collide;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SpeedBoatUserControl(ItemInfo* laraItem, ItemInfo* sBoatItem)
|
|
||||||
{
|
|
||||||
auto* sBoat = (SpeedBoatInfo*)sBoatItem->Data;
|
|
||||||
|
|
||||||
bool noTurn = true;
|
|
||||||
int maxVelocity;
|
|
||||||
|
|
||||||
if (sBoatItem->Pose.Position.y >= sBoat->Water - CLICK(0.5f) && sBoat->Water != NO_HEIGHT)
|
|
||||||
{
|
|
||||||
if (!(TrInput & SBOAT_IN_DISMOUNT) && !(TrInput & IN_LOOK) ||
|
|
||||||
sBoatItem->Animation.Velocity)
|
|
||||||
{
|
|
||||||
if (TrInput & SBOAT_IN_LEFT && !(TrInput & SBOAT_IN_REVERSE) ||
|
|
||||||
TrInput & SBOAT_IN_RIGHT && TrInput & SBOAT_IN_REVERSE)
|
|
||||||
{
|
|
||||||
if (sBoat->TurnRate > 0)
|
|
||||||
sBoat->TurnRate -= BOAT_UNDO_TURN;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sBoat->TurnRate -= BOAT_TURN;
|
|
||||||
if (sBoat->TurnRate < -BOAT_MAX_TURN)
|
|
||||||
sBoat->TurnRate = -BOAT_MAX_TURN;
|
|
||||||
}
|
|
||||||
|
|
||||||
noTurn = false;
|
|
||||||
}
|
|
||||||
else if (TrInput & SBOAT_IN_RIGHT && !(TrInput & SBOAT_IN_REVERSE) ||
|
|
||||||
TrInput & SBOAT_IN_LEFT && TrInput & SBOAT_IN_REVERSE)
|
|
||||||
{
|
|
||||||
if (sBoat->TurnRate < 0)
|
|
||||||
sBoat->TurnRate += BOAT_UNDO_TURN;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sBoat->TurnRate += BOAT_TURN;
|
|
||||||
if (sBoat->TurnRate > BOAT_MAX_TURN)
|
|
||||||
sBoat->TurnRate = BOAT_MAX_TURN;
|
|
||||||
}
|
|
||||||
|
|
||||||
noTurn = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TrInput & SBOAT_IN_REVERSE)
|
|
||||||
{
|
|
||||||
if (sBoatItem->Animation.Velocity > 0)
|
|
||||||
sBoatItem->Animation.Velocity -= BOAT_BRAKE;
|
|
||||||
else if (sBoatItem->Animation.Velocity > BOAT_MAX_BACK)
|
|
||||||
sBoatItem->Animation.Velocity += BOAT_REVERSE;
|
|
||||||
}
|
|
||||||
else if (TrInput & SBOAT_IN_ACCELERATE)
|
|
||||||
{
|
|
||||||
if (TrInput & SBOAT_IN_SPEED)
|
|
||||||
maxVelocity = BOAT_FAST_SPEED;
|
|
||||||
else
|
|
||||||
maxVelocity = (TrInput & SBOAT_IN_SLOW) ? BOAT_SLOW_SPEED : BOAT_MAX_VELOCITY;
|
|
||||||
|
|
||||||
if (sBoatItem->Animation.Velocity < maxVelocity)
|
|
||||||
sBoatItem->Animation.Velocity += (BOAT_ACCELERATION / 2) + (BOAT_ACCELERATION * (sBoatItem->Animation.Velocity / (maxVelocity * 2)));
|
|
||||||
else if (sBoatItem->Animation.Velocity > maxVelocity + BOAT_SLOWDOWN)
|
|
||||||
sBoatItem->Animation.Velocity -= BOAT_SLOWDOWN;
|
|
||||||
}
|
|
||||||
else if (TrInput & (SBOAT_IN_LEFT | SBOAT_IN_RIGHT) &&
|
|
||||||
sBoatItem->Animation.Velocity >= 0 &&
|
|
||||||
sBoatItem->Animation.Velocity < BOAT_MIN_SPEED)
|
|
||||||
{
|
|
||||||
if (!(TrInput & SBOAT_IN_DISMOUNT) &&
|
|
||||||
sBoatItem->Animation.Velocity == 0)
|
|
||||||
sBoatItem->Animation.Velocity = BOAT_MIN_SPEED;
|
|
||||||
}
|
|
||||||
else if (sBoatItem->Animation.Velocity > BOAT_SLOWDOWN)
|
|
||||||
sBoatItem->Animation.Velocity -= BOAT_SLOWDOWN;
|
|
||||||
else
|
|
||||||
sBoatItem->Animation.Velocity = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (TrInput & (SBOAT_IN_LEFT | SBOAT_IN_RIGHT) &&
|
|
||||||
sBoatItem->Animation.Velocity >= 0 &&
|
|
||||||
sBoatItem->Animation.Velocity < BOAT_MIN_SPEED)
|
|
||||||
{
|
|
||||||
if (sBoatItem->Animation.Velocity == 0 && !(TrInput & SBOAT_IN_DISMOUNT))
|
|
||||||
sBoatItem->Animation.Velocity = BOAT_MIN_SPEED;
|
|
||||||
}
|
|
||||||
else if (sBoatItem->Animation.Velocity > BOAT_SLOWDOWN)
|
|
||||||
sBoatItem->Animation.Velocity -= BOAT_SLOWDOWN;
|
|
||||||
else
|
|
||||||
sBoatItem->Animation.Velocity = 0;
|
|
||||||
|
|
||||||
if (TrInput & IN_LOOK && sBoatItem->Animation.Velocity == 0)
|
|
||||||
LookUpDown(laraItem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return noTurn;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SpeedBoatAnimation(ItemInfo* laraItem, ItemInfo* sBoatItem, int collide)
|
|
||||||
{
|
|
||||||
auto* sBoat = (SpeedBoatInfo*)sBoatItem->Data;
|
|
||||||
|
|
||||||
if (laraItem->HitPoints <= 0)
|
|
||||||
{
|
|
||||||
if (laraItem->Animation.ActiveState != SBOAT_STATE_DEATH)
|
|
||||||
{
|
|
||||||
laraItem->Animation.AnimNumber = Objects[ID_SPEEDBOAT_LARA_ANIMS].animIndex + SBOAT_ANIM_DEATH;
|
|
||||||
laraItem->Animation.FrameNumber = g_Level.Anims[laraItem->Animation.AnimNumber].frameBase;
|
|
||||||
laraItem->Animation.ActiveState = laraItem->Animation.TargetState = SBOAT_STATE_DEATH;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (sBoatItem->Pose.Position.y < sBoat->Water - CLICK(0.5f) && sBoatItem->Animation.VerticalVelocity > 0)
|
|
||||||
{
|
|
||||||
if (laraItem->Animation.ActiveState != SBOAT_STATE_FALL)
|
|
||||||
{
|
|
||||||
laraItem->Animation.AnimNumber = Objects[ID_SPEEDBOAT_LARA_ANIMS].animIndex + SBOAT_ANIM_LEAP_START;
|
|
||||||
laraItem->Animation.FrameNumber = g_Level.Anims[laraItem->Animation.AnimNumber].frameBase;
|
|
||||||
laraItem->Animation.ActiveState = laraItem->Animation.TargetState = SBOAT_STATE_FALL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (collide)
|
|
||||||
{
|
|
||||||
if (laraItem->Animation.ActiveState != SBOAT_STATE_HIT)
|
|
||||||
{
|
|
||||||
laraItem->Animation.AnimNumber = Objects[ID_SPEEDBOAT_LARA_ANIMS].animIndex + collide;
|
|
||||||
laraItem->Animation.FrameNumber = g_Level.Anims[laraItem->Animation.AnimNumber].frameBase;
|
|
||||||
laraItem->Animation.ActiveState = laraItem->Animation.TargetState = SBOAT_STATE_HIT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
switch (laraItem->Animation.ActiveState)
|
|
||||||
{
|
|
||||||
case SBOAT_STATE_IDLE:
|
|
||||||
if (TrInput & SBOAT_IN_DISMOUNT)
|
|
||||||
{
|
|
||||||
if (sBoatItem->Animation.Velocity == 0)
|
|
||||||
{
|
|
||||||
if (TrInput & SBOAT_IN_RIGHT && TestSpeedBoatDismount(sBoatItem, sBoatItem->Pose.Orientation.y + ANGLE(90.0f)))
|
|
||||||
laraItem->Animation.TargetState = SBOAT_STATE_DISMOUNT_RIGHT;
|
|
||||||
else if (TrInput & SBOAT_IN_LEFT && TestSpeedBoatDismount(sBoatItem, sBoatItem->Pose.Orientation.y - ANGLE(90.0f)))
|
|
||||||
laraItem->Animation.TargetState = SBOAT_STATE_DISMOUNT_LEFT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sBoatItem->Animation.Velocity > 0)
|
|
||||||
laraItem->Animation.TargetState = SBOAT_STATE_MOVING;
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SBOAT_STATE_MOVING:
|
|
||||||
if (TrInput & SBOAT_IN_DISMOUNT)
|
|
||||||
{
|
|
||||||
if (TrInput & SBOAT_IN_RIGHT)
|
|
||||||
laraItem->Animation.TargetState = SBOAT_STATE_DISMOUNT_RIGHT;
|
|
||||||
else if (TrInput & SBOAT_IN_RIGHT)
|
|
||||||
laraItem->Animation.TargetState = SBOAT_STATE_DISMOUNT_LEFT;
|
|
||||||
}
|
|
||||||
else if (sBoatItem->Animation.Velocity <= 0)
|
|
||||||
laraItem->Animation.TargetState = SBOAT_STATE_IDLE;
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SBOAT_STATE_FALL:
|
|
||||||
laraItem->Animation.TargetState = SBOAT_STATE_MOVING;
|
|
||||||
break;
|
|
||||||
|
|
||||||
//case BOAT_TURNR:
|
|
||||||
if (sBoatItem->Animation.Velocity <= 0)
|
|
||||||
laraItem->Animation.TargetState = SBOAT_STATE_IDLE;
|
|
||||||
else if (!(TrInput & SBOAT_IN_RIGHT))
|
|
||||||
laraItem->Animation.TargetState = SBOAT_STATE_MOVING;
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SBOAT_STATE_TURN_LEFT:
|
|
||||||
if (sBoatItem->Animation.Velocity <= 0)
|
|
||||||
laraItem->Animation.TargetState = SBOAT_STATE_IDLE;
|
|
||||||
else if (!(TrInput & SBOAT_IN_LEFT))
|
|
||||||
laraItem->Animation.TargetState = SBOAT_STATE_MOVING;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SpeedBoatSplash(ItemInfo* item, long verticalVelocity, long water)
|
|
||||||
{
|
|
||||||
//OLD SPLASH
|
|
||||||
/*
|
|
||||||
splash_setup.x = item->pos.x_pos;
|
|
||||||
splash_setup.y = water;
|
|
||||||
splash_setup.z = item->pos.z_pos;
|
|
||||||
splash_setup.InnerXZoff = 16 << 2;
|
|
||||||
splash_setup.InnerXZsize = 12 << 2;
|
|
||||||
splash_setup.InnerYsize = -96 << 2;
|
|
||||||
splash_setup.InnerXZvel = 0xa0;
|
|
||||||
splash_setup.InnerYvel = -fallspeed << 7;
|
|
||||||
splash_setup.InnerGravity = 0x80;
|
|
||||||
splash_setup.InnerFriction = 7;
|
|
||||||
splash_setup.MiddleXZoff = 24 << 2;
|
|
||||||
splash_setup.MiddleXZsize = 24 << 2;
|
|
||||||
splash_setup.MiddleYsize = -64 << 2;
|
|
||||||
splash_setup.MiddleXZvel = 0xe0;
|
|
||||||
splash_setup.MiddleYvel = -fallspeed << 6;
|
|
||||||
splash_setup.MiddleGravity = 0x48;
|
|
||||||
splash_setup.MiddleFriction = 8;
|
|
||||||
splash_setup.OuterXZoff = 32 << 2;
|
|
||||||
splash_setup.OuterXZsize = 32 << 2;
|
|
||||||
splash_setup.OuterXZvel = 0x110;
|
|
||||||
splash_setup.OuterFriction = 9;
|
|
||||||
SetupSplash(&splash_setup);
|
|
||||||
SplashCount = 16;
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
void SpeedBoatCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll)
|
|
||||||
{
|
|
||||||
auto* lara = GetLaraInfo(laraItem);
|
|
||||||
|
|
||||||
if (laraItem->HitPoints < 0 || lara->Vehicle != NO_ITEM)
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto* sBoatItem = &g_Level.Items[itemNumber];
|
|
||||||
|
|
||||||
switch (GetSpeedBoatMountType(laraItem, sBoatItem, coll))
|
|
||||||
{
|
|
||||||
case BoatMountType::None:
|
|
||||||
coll->Setup.EnableObjectPush = true;
|
|
||||||
ObjectCollision(itemNumber, laraItem, coll);
|
|
||||||
return;
|
|
||||||
|
|
||||||
case BoatMountType::WaterLeft:
|
|
||||||
laraItem->Animation.AnimNumber = Objects[ID_SPEEDBOAT_LARA_ANIMS].animIndex + SBOAT_ANIM_MOUNT_LEFT;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BoatMountType::WaterRight:
|
|
||||||
laraItem->Animation.AnimNumber = Objects[ID_SPEEDBOAT_LARA_ANIMS].animIndex + SBOAT_ANIM_MOUNT_RIGHT;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BoatMountType::Jump:
|
|
||||||
laraItem->Animation.AnimNumber = Objects[ID_SPEEDBOAT_LARA_ANIMS].animIndex + SBOAT_ANIM_MOUNT_JUMP;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BoatMountType::StartPosition:
|
|
||||||
laraItem->Animation.AnimNumber = Objects[ID_SPEEDBOAT_LARA_ANIMS].animIndex + SBOAT_ANIM_IDLE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
laraItem->Pose.Position.x = sBoatItem->Pose.Position.x;
|
|
||||||
laraItem->Pose.Position.y = sBoatItem->Pose.Position.y - 5;
|
|
||||||
laraItem->Pose.Position.z = sBoatItem->Pose.Position.z;
|
|
||||||
laraItem->Pose.Orientation.x = 0;
|
|
||||||
laraItem->Pose.Orientation.y = sBoatItem->Pose.Orientation.y;
|
|
||||||
laraItem->Pose.Orientation.z = 0;
|
|
||||||
laraItem->Animation.Velocity = 0;
|
|
||||||
laraItem->Animation.VerticalVelocity = 0;
|
|
||||||
laraItem->Animation.Airborne = false;
|
|
||||||
laraItem->Animation.FrameNumber = g_Level.Anims[laraItem->Animation.AnimNumber].frameBase;
|
|
||||||
laraItem->Animation.ActiveState = SBOAT_STATE_MOUNT;
|
|
||||||
laraItem->Animation.TargetState = SBOAT_STATE_MOUNT;
|
|
||||||
lara->Control.WaterStatus = WaterStatus::Dry;
|
|
||||||
|
|
||||||
if (laraItem->RoomNumber != sBoatItem->RoomNumber)
|
|
||||||
ItemNewRoom(lara->ItemNumber, sBoatItem->RoomNumber);
|
|
||||||
|
|
||||||
AnimateItem(laraItem);
|
|
||||||
|
|
||||||
if (g_Level.Items[itemNumber].Status != ITEM_ACTIVE)
|
|
||||||
{
|
|
||||||
AddActiveItem(itemNumber);
|
|
||||||
g_Level.Items[itemNumber].Status = ITEM_ACTIVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
lara->Vehicle = itemNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SpeedBoatControl(short itemNumber)
|
|
||||||
{
|
|
||||||
auto* laraItem = LaraItem;
|
|
||||||
auto* lara = GetLaraInfo(laraItem);
|
|
||||||
auto* sBoatItem = &g_Level.Items[itemNumber];
|
|
||||||
auto* sBoat = (SpeedBoatInfo*)sBoatItem->Data;
|
|
||||||
|
|
||||||
int collide = SpeedBoatDynamics(laraItem, itemNumber);
|
|
||||||
|
|
||||||
Vector3Int frontLeft, frontRight;
|
|
||||||
int heightFrontLeft = SpeedBoatTestWaterHeight(sBoatItem, BOAT_FRONT, -BOAT_SIDE, &frontLeft);
|
|
||||||
int heightFrontRight = SpeedBoatTestWaterHeight(sBoatItem, BOAT_FRONT, BOAT_SIDE, &frontRight);
|
|
||||||
|
|
||||||
auto probe = GetCollision(sBoatItem);
|
|
||||||
|
|
||||||
if (lara->Vehicle == itemNumber)
|
|
||||||
{
|
|
||||||
TestTriggers(sBoatItem, true);
|
|
||||||
TestTriggers(sBoatItem, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto water = GetWaterHeight(sBoatItem->Pose.Position.x, sBoatItem->Pose.Position.y, sBoatItem->Pose.Position.z, probe.RoomNumber);
|
|
||||||
sBoat->Water = water;
|
|
||||||
|
|
||||||
bool noTurn = true;
|
|
||||||
bool drive = false;
|
|
||||||
bool idle = !sBoatItem->Animation.Velocity;
|
|
||||||
|
|
||||||
if (lara->Vehicle == itemNumber && laraItem->HitPoints > 0)
|
|
||||||
{
|
|
||||||
switch (laraItem->Animation.ActiveState)
|
|
||||||
{
|
|
||||||
case SBOAT_STATE_MOUNT:
|
|
||||||
case SBOAT_STATE_DISMOUNT_RIGHT:
|
|
||||||
case SBOAT_STATE_DISMOUNT_LEFT:
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
drive = true;
|
|
||||||
noTurn = SpeedBoatUserControl(laraItem, sBoatItem);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (sBoatItem->Animation.Velocity > BOAT_SLOWDOWN)
|
|
||||||
sBoatItem->Animation.Velocity -= BOAT_SLOWDOWN;
|
|
||||||
else
|
|
||||||
sBoatItem->Animation.Velocity = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (noTurn)
|
|
||||||
{
|
|
||||||
if (sBoat->TurnRate < -BOAT_UNDO_TURN)
|
|
||||||
sBoat->TurnRate += BOAT_UNDO_TURN;
|
|
||||||
else if (sBoat->TurnRate > BOAT_UNDO_TURN)
|
|
||||||
sBoat->TurnRate -= BOAT_UNDO_TURN;
|
|
||||||
else
|
|
||||||
sBoat->TurnRate = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
sBoatItem->Floor = probe.Position.Floor - 5;
|
|
||||||
if (sBoat->Water == NO_HEIGHT)
|
|
||||||
sBoat->Water = probe.Position.Floor;
|
|
||||||
else
|
|
||||||
sBoat->Water -= 5;
|
|
||||||
|
|
||||||
sBoat->LeftVerticalVelocity = DoSpeedBoatDynamics(heightFrontLeft, sBoat->LeftVerticalVelocity, (int*)&frontLeft.y);
|
|
||||||
sBoat->RightVerticalVelocity = DoSpeedBoatDynamics(heightFrontRight, sBoat->RightVerticalVelocity, (int*)&frontRight.y);
|
|
||||||
sBoatItem->Animation.VerticalVelocity = DoSpeedBoatDynamics(sBoat->Water, sBoatItem->Animation.VerticalVelocity, (int*)&sBoatItem->Pose.Position.y);
|
|
||||||
|
|
||||||
auto ofs = sBoatItem->Animation.VerticalVelocity;
|
|
||||||
if (ofs - sBoatItem->Animation.VerticalVelocity > 32 && sBoatItem->Animation.VerticalVelocity == 0 && water != NO_HEIGHT)
|
|
||||||
SpeedBoatSplash(sBoatItem, ofs - sBoatItem->Animation.VerticalVelocity, water);
|
|
||||||
|
|
||||||
probe.Position.Floor = (frontLeft.y + frontRight.y);
|
|
||||||
if (probe.Position.Floor < 0)
|
|
||||||
probe.Position.Floor = -(abs(probe.Position.Floor) / 2);
|
|
||||||
else
|
|
||||||
probe.Position.Floor /= 2;
|
|
||||||
|
|
||||||
short xRot = phd_atan(BOAT_FRONT, sBoatItem->Pose.Position.y - probe.Position.Floor);
|
|
||||||
short zRot = phd_atan(BOAT_SIDE, probe.Position.Floor - frontLeft.y);
|
|
||||||
|
|
||||||
sBoatItem->Pose.Orientation.x += ((xRot - sBoatItem->Pose.Orientation.x) / 2);
|
|
||||||
sBoatItem->Pose.Orientation.z += ((zRot - sBoatItem->Pose.Orientation.z) / 2);
|
|
||||||
|
|
||||||
if (!xRot && abs(sBoatItem->Pose.Orientation.x) < 4)
|
|
||||||
sBoatItem->Pose.Orientation.x = 0;
|
|
||||||
if (!zRot && abs(sBoatItem->Pose.Orientation.z) < 4)
|
|
||||||
sBoatItem->Pose.Orientation.z = 0;
|
|
||||||
|
|
||||||
if (lara->Vehicle == itemNumber)
|
|
||||||
{
|
|
||||||
SpeedBoatAnimation(laraItem, sBoatItem, collide);
|
|
||||||
|
|
||||||
if (probe.RoomNumber != sBoatItem->RoomNumber)
|
|
||||||
{
|
|
||||||
ItemNewRoom(lara->Vehicle, probe.RoomNumber);
|
|
||||||
ItemNewRoom(lara->ItemNumber, probe.RoomNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
laraItem->Pose.Position.x = sBoatItem->Pose.Position.x;
|
|
||||||
laraItem->Pose.Position.y = sBoatItem->Pose.Position.y;
|
|
||||||
laraItem->Pose.Position.z = sBoatItem->Pose.Position.z;
|
|
||||||
laraItem->Pose.Orientation.x = sBoatItem->Pose.Orientation.x;
|
|
||||||
laraItem->Pose.Orientation.y = sBoatItem->Pose.Orientation.y;
|
|
||||||
laraItem->Pose.Orientation.z = sBoatItem->Pose.Orientation.z;
|
|
||||||
sBoatItem->Pose.Orientation.z += sBoat->LeanAngle;
|
|
||||||
|
|
||||||
AnimateItem(laraItem);
|
|
||||||
|
|
||||||
if (laraItem->HitPoints > 0)
|
|
||||||
{
|
|
||||||
sBoatItem->Animation.AnimNumber = Objects[ID_SPEEDBOAT].animIndex + (laraItem->Animation.AnimNumber - Objects[ID_SPEEDBOAT_LARA_ANIMS].animIndex);
|
|
||||||
sBoatItem->Animation.FrameNumber = g_Level.Anims[sBoatItem->Animation.AnimNumber].frameBase + (laraItem->Animation.FrameNumber - g_Level.Anims[laraItem->Animation.AnimNumber].frameBase);
|
|
||||||
}
|
|
||||||
|
|
||||||
Camera.targetElevation = -ANGLE(20.0f);
|
|
||||||
Camera.targetDistance = SECTOR(2);
|
|
||||||
|
|
||||||
auto pitch = sBoatItem->Animation.Velocity;
|
|
||||||
sBoat->Pitch += (pitch - sBoat->Pitch) / 4;
|
|
||||||
|
|
||||||
if (drive)
|
|
||||||
{
|
|
||||||
bool accelerating = idle && abs(sBoatItem->Animation.Velocity) > 4;
|
|
||||||
bool moving = (abs(sBoatItem->Animation.Velocity) > 8 || sBoat->TurnRate);
|
|
||||||
int fx = accelerating ? SFX_TR2_VEHICLE_SPEEDBOAT_ACCELERATE : (moving ? SFX_TR2_VEHICLE_SPEEDBOAT_MOVING : SFX_TR2_VEHICLE_SPEEDBOAT_IDLE);
|
|
||||||
float pitch = idle ? 1.0f : 1.0f + sBoat->Pitch / (float)BOAT_MAX_VELOCITY / 4.0f;
|
|
||||||
SoundEffect(fx, &sBoatItem->Pose, SoundEnvironment::Land, pitch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (probe.RoomNumber != sBoatItem->RoomNumber)
|
|
||||||
ItemNewRoom(itemNumber, probe.RoomNumber);
|
|
||||||
|
|
||||||
sBoatItem->Pose.Orientation.z += sBoat->LeanAngle;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sBoatItem->Animation.Velocity && (water - 5) == sBoatItem->Pose.Position.y)
|
|
||||||
{
|
|
||||||
auto room = probe.Block->RoomBelow(sBoatItem->Pose.Position.x, sBoatItem->Pose.Position.z).value_or(NO_ROOM);
|
|
||||||
if (room != NO_ROOM && (TestEnvironment(RoomEnvFlags::ENV_FLAG_WATER, room) || TestEnvironment(RoomEnvFlags::ENV_FLAG_SWAMP, room)))
|
|
||||||
TEN::Effects::TriggerSpeedboatFoam(sBoatItem, Vector3(0, 0, BOAT_BACK));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lara->Vehicle != itemNumber)
|
|
||||||
return;
|
|
||||||
|
|
||||||
DoSpeedBoatDismount(laraItem, sBoatItem);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include "Game/collision/collide_room.h"
|
|
||||||
#include "Game/items.h"
|
|
||||||
|
|
||||||
namespace TEN::Entities::Vehicles
|
|
||||||
{
|
|
||||||
enum class BoatMountType
|
|
||||||
{
|
|
||||||
None = 0,
|
|
||||||
WaterRight = 1,
|
|
||||||
WaterLeft = 2,
|
|
||||||
Jump = 3,
|
|
||||||
StartPosition = 4
|
|
||||||
};
|
|
||||||
|
|
||||||
void InitialiseSpeedBoat(short itemNumber);
|
|
||||||
BoatMountType GetSpeedBoatMountType(ItemInfo* laraItem, ItemInfo* sBoatItem, CollisionInfo* coll);
|
|
||||||
bool TestSpeedBoatDismount(ItemInfo* sBoatItem, int direction);
|
|
||||||
void DoSpeedBoatDismount(ItemInfo* laraItem, ItemInfo* sBoatItem);
|
|
||||||
int SpeedBoatTestWaterHeight(ItemInfo* sBoatItem, int zOffset, int xOffset, Vector3Int* pos);
|
|
||||||
|
|
||||||
void SpeedBoatDoBoatShift(ItemInfo* sBoatItem, int itemNumber);
|
|
||||||
short SpeedBoatDoShift(ItemInfo* sBoatItem, Vector3Int* pos, Vector3Int* old);
|
|
||||||
|
|
||||||
int GetSpeedBoatHitAnim(ItemInfo* sBoatItem, Vector3Int* moved);
|
|
||||||
int DoSpeedBoatDynamics(int height, int verticalVelocity, int* y);
|
|
||||||
int SpeedBoatDynamics(ItemInfo* laraItem, short itemNumber);
|
|
||||||
bool SpeedBoatUserControl(ItemInfo* laraItem, ItemInfo* sBoatItem);
|
|
||||||
void SpeedBoatAnimation(ItemInfo* laraItem, ItemInfo* sBoatItem, int collide);
|
|
||||||
void SpeedBoatSplash(ItemInfo* item, long verticalVelocity, long water);
|
|
||||||
void SpeedBoatCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll);
|
|
||||||
void SpeedBoatControl(short itemNumber);
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace TEN::Entities::Vehicles
|
|
||||||
{
|
|
||||||
struct SpeedBoatInfo
|
|
||||||
{
|
|
||||||
int TurnRate;
|
|
||||||
short LeanAngle;
|
|
||||||
short ExtraRotation;
|
|
||||||
|
|
||||||
int LeftVerticalVelocity;
|
|
||||||
int RightVerticalVelocity;
|
|
||||||
|
|
||||||
int Water;
|
|
||||||
int Pitch;
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -23,53 +23,46 @@
|
||||||
|
|
||||||
using namespace TEN::Input;
|
using namespace TEN::Input;
|
||||||
using namespace TEN::Math::Random;
|
using namespace TEN::Math::Random;
|
||||||
|
using std::vector;
|
||||||
|
|
||||||
namespace TEN::Entities::Vehicles
|
namespace TEN::Entities::Vehicles
|
||||||
{
|
{
|
||||||
#define DAMAGE_START 140
|
constexpr auto SKIDOO_RADIUS = 500;
|
||||||
#define DAMAGE_LENGTH 14
|
constexpr auto SKIDOO_FRONT = 550;
|
||||||
|
constexpr auto SKIDOO_SIDE = 260;
|
||||||
|
constexpr auto SKIDOO_SLIP = 100;
|
||||||
|
constexpr auto SKIDOO_SLIP_SIDE = 50;
|
||||||
|
constexpr auto SKIDOO_SNOW = 500; // Unused.
|
||||||
|
constexpr auto SKIDOO_MOUNT_DISTANCE = CLICK(2);
|
||||||
|
constexpr auto SKIDOO_DISMOUNT_DISTANCE = 295;
|
||||||
|
|
||||||
#define SKIDOO_DISMOUNT_DISTANCE 295
|
constexpr auto SKIDOO_VELOCITY_ACCEL = 10;
|
||||||
|
constexpr auto SKIDOO_VELOCITY_DECEL = 2;
|
||||||
|
constexpr auto SKIDOO_VELOCITY_BRAKE_DECEL = 5;
|
||||||
|
constexpr auto SKIDOO_REVERSE_VELOCITY_ACCEL = 5;
|
||||||
|
constexpr auto SKIDOO_KICK_MAX = -80;
|
||||||
|
|
||||||
#define SKIDOO_UNDO_TURN ANGLE(2.0f)
|
constexpr auto SKIDOO_SLOW_VELOCITY_MAX = 50;
|
||||||
#define SKIDOO_TURN (ANGLE(0.5f) + SKIDOO_UNDO_TURN)
|
constexpr auto SKIDOO_NORMAL_VELOCITY_MAX = 100;
|
||||||
#define SKIDOO_MAX_TURN ANGLE(6.0f)
|
constexpr auto SKIDOO_FAST_VELOCITY_MAX = 150;
|
||||||
#define SKIDOO_MOMENTUM_TURN ANGLE(3.0f)
|
constexpr auto SKIDOO_TURN_VELOCITY_MAX = 15;
|
||||||
#define SKIDOO_MAX_MOMENTUM_TURN ANGLE(150.0f)
|
constexpr auto SKIDOO_REVERSE_VELOCITY_MAX = 30;
|
||||||
|
|
||||||
#define SKIDOO_FAST_VELOCITY 150
|
constexpr auto SKIDOO_STEP_HEIGHT_MAX = CLICK(1); // Unused.
|
||||||
#define SKIDOO_MAX_VELOCITY 100
|
constexpr auto SKIDOO_MIN_BOUNCE = (SKIDOO_NORMAL_VELOCITY_MAX / 2) / 256;
|
||||||
#define SKIDOO_SLOW_VELOCITY 50
|
|
||||||
#define SKIDOO_MIN_VELOCITY 15
|
|
||||||
|
|
||||||
#define SKIDOO_ACCELERATION 10
|
constexpr auto SKIDOO_DAMAGE_START = 140;
|
||||||
#define SKIDOO_BRAKE 5
|
constexpr auto SKIDOO_DAMAGE_LENGTH = 14;
|
||||||
#define SKIDOO_SLOWDOWN 2
|
|
||||||
#define SKIDOO_REVERSE -5
|
|
||||||
#define SKIDOO_MAX_BACK -30
|
|
||||||
#define SKIDOO_MAX_KICK -80
|
|
||||||
|
|
||||||
#define SKIDOO_SLIP 100
|
#define SKIDOO_TURN_RATE_ACCEL ANGLE(2.5f)
|
||||||
#define SKIDOO_SLIP_SIDE 50
|
#define SKIDOO_TURN_RATE_DECEL ANGLE(2.0f)
|
||||||
#define SKIDOO_FRONT 550
|
#define SKIDOO_TURN_RATE_MAX ANGLE(6.0f)
|
||||||
#define SKIDOO_SIDE 260
|
#define SKIDOO_MOMENTUM_TURN_RATE_ACCEL ANGLE(3.0f)
|
||||||
#define SKIDOO_RADIUS 500
|
#define SKIDOO_MOMENTUM_TURN_RATE_MAX ANGLE(150.0f)
|
||||||
#define SKIDOO_SNOW 500
|
|
||||||
|
|
||||||
#define SKIDOO_MAX_HEIGHT CLICK(1)
|
|
||||||
#define SKIDOO_MIN_BOUNCE ((SKIDOO_MAX_VELOCITY / 2) / 256)
|
|
||||||
|
|
||||||
#define SKIDOO_IN_ACCELERATE IN_FORWARD
|
|
||||||
#define SKIDOO_IN_BRAKE IN_BACK
|
|
||||||
#define SKIDOO_IN_SLOW IN_WALK
|
|
||||||
#define SKIDOO_IN_FIRE IN_ACTION
|
|
||||||
#define SKIDOO_IN_DISMOUNT (IN_JUMP | IN_ROLL)
|
|
||||||
#define SKIDOO_IN_LEFT IN_LEFT
|
|
||||||
#define SKIDOO_IN_RIGHT IN_RIGHT
|
|
||||||
|
|
||||||
enum SkidooState
|
enum SkidooState
|
||||||
{
|
{
|
||||||
SKIDOO_STATE_SIT = 0,
|
SKIDOO_STATE_DRIVE = 0,
|
||||||
SKIDOO_STATE_MOUNT = 1,
|
SKIDOO_STATE_MOUNT = 1,
|
||||||
SKIDOO_STATE_LEFT = 2,
|
SKIDOO_STATE_LEFT = 2,
|
||||||
SKIDOO_STATE_RIGHT = 3,
|
SKIDOO_STATE_RIGHT = 3,
|
||||||
|
@ -111,62 +104,86 @@ namespace TEN::Entities::Vehicles
|
||||||
SKIDOO_ANIM_FALL_DEATH = 22
|
SKIDOO_ANIM_FALL_DEATH = 22
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const vector<VehicleMountType> SkidooMountTypes =
|
||||||
|
{
|
||||||
|
VehicleMountType::LevelStart,
|
||||||
|
VehicleMountType::Left,
|
||||||
|
VehicleMountType::Right
|
||||||
|
};
|
||||||
|
|
||||||
|
SkidooInfo* GetSkidooInfo(ItemInfo* skidooItem)
|
||||||
|
{
|
||||||
|
return (SkidooInfo*)skidooItem->Data;
|
||||||
|
}
|
||||||
|
|
||||||
void InitialiseSkidoo(short itemNumber)
|
void InitialiseSkidoo(short itemNumber)
|
||||||
{
|
{
|
||||||
auto* skidooItem = &g_Level.Items[itemNumber];
|
auto* skidooItem = &g_Level.Items[itemNumber];
|
||||||
skidooItem->Data = SkidooInfo();
|
skidooItem->Data = SkidooInfo();
|
||||||
auto* skidoo = (SkidooInfo*)skidooItem->Data;
|
auto* skidoo = GetSkidooInfo(skidooItem);
|
||||||
|
|
||||||
skidoo->TurnRate = 0;
|
|
||||||
skidoo->MomentumAngle = skidooItem->Pose.Orientation.y;
|
|
||||||
skidoo->ExtraRotation = 0;
|
|
||||||
skidoo->LeftVerticalVelocity = 0;
|
|
||||||
skidoo->RightVerticalVelocity = 0;
|
|
||||||
skidoo->Pitch = 0;
|
|
||||||
skidoo->FlashTimer = 0;
|
|
||||||
|
|
||||||
if (skidooItem->ObjectNumber == ID_SNOWMOBILE_GUN)
|
|
||||||
skidoo->Armed = true;
|
|
||||||
else
|
|
||||||
skidoo->Armed = false;
|
|
||||||
|
|
||||||
if (skidooItem->Status != ITEM_ACTIVE)
|
if (skidooItem->Status != ITEM_ACTIVE)
|
||||||
{
|
{
|
||||||
AddActiveItem(itemNumber);
|
AddActiveItem(itemNumber);
|
||||||
skidooItem->Status = ITEM_ACTIVE;
|
skidooItem->Status = ITEM_ACTIVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (skidooItem->ObjectNumber == ID_SNOWMOBILE_GUN)
|
||||||
|
skidoo->Armed = true;
|
||||||
|
|
||||||
|
skidoo->MomentumAngle = skidooItem->Pose.Orientation.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GetSkidooMountType(ItemInfo* laraItem, ItemInfo* skidooItem, CollisionInfo* coll)
|
void SkidooPlayerCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll)
|
||||||
{
|
{
|
||||||
auto* lara = (LaraInfo*&)laraItem->Data;
|
auto* skidooItem = &g_Level.Items[itemNumber];
|
||||||
|
auto* lara = GetLaraInfo(laraItem);
|
||||||
|
|
||||||
int mountType = 0;
|
if (laraItem->HitPoints < 0 || lara->Vehicle != NO_ITEM)
|
||||||
|
return;
|
||||||
|
|
||||||
if (!(TrInput & IN_ACTION) ||
|
auto mountType = GetVehicleMountType(skidooItem, laraItem, coll, SkidooMountTypes, SKIDOO_MOUNT_DISTANCE);
|
||||||
lara->Control.HandStatus != HandStatus::Free ||
|
if (mountType == VehicleMountType::None)
|
||||||
laraItem->Animation.Airborne)
|
ObjectCollision(itemNumber, laraItem, coll);
|
||||||
{
|
|
||||||
return mountType = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
short deltaAngle = skidooItem->Pose.Orientation.y - laraItem->Pose.Orientation.y;
|
|
||||||
if (deltaAngle > ANGLE(45.0f) && deltaAngle < ANGLE(135.0f))
|
|
||||||
mountType = 1;
|
|
||||||
else if (deltaAngle > -ANGLE(135.0f) && deltaAngle < -ANGLE(45.0f))
|
|
||||||
mountType = 2;
|
|
||||||
else
|
else
|
||||||
mountType = 0;
|
|
||||||
|
|
||||||
auto probe = GetCollision(skidooItem);
|
|
||||||
if (probe.Position.Floor < -32000 ||
|
|
||||||
!TestBoundsCollide(skidooItem, laraItem, coll->Setup.Radius) ||
|
|
||||||
!TestCollision(skidooItem, laraItem))
|
|
||||||
{
|
{
|
||||||
mountType = 0;
|
lara->Vehicle = itemNumber;
|
||||||
|
DoSkidooMount(skidooItem, laraItem, mountType);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return mountType;
|
void DoSkidooMount(ItemInfo* skidooItem, ItemInfo* laraItem, VehicleMountType mountType)
|
||||||
|
{
|
||||||
|
auto* lara = GetLaraInfo(laraItem);
|
||||||
|
|
||||||
|
switch (mountType)
|
||||||
|
{
|
||||||
|
case VehicleMountType::LevelStart:
|
||||||
|
laraItem->Animation.AnimNumber = Objects[ID_SNOWMOBILE_LARA_ANIMS].animIndex + SKIDOO_ANIM_IDLE;
|
||||||
|
laraItem->Animation.ActiveState = SKIDOO_STATE_IDLE;
|
||||||
|
laraItem->Animation.TargetState = SKIDOO_STATE_IDLE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VehicleMountType::Left:
|
||||||
|
laraItem->Animation.AnimNumber = Objects[ID_SNOWMOBILE_LARA_ANIMS].animIndex + SKIDOO_ANIM_MOUNT_LEFT;
|
||||||
|
laraItem->Animation.ActiveState = SKIDOO_STATE_MOUNT;
|
||||||
|
laraItem->Animation.TargetState = SKIDOO_STATE_MOUNT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
case VehicleMountType::Right:
|
||||||
|
laraItem->Animation.AnimNumber = Objects[ID_SNOWMOBILE_LARA_ANIMS].animIndex + SKIDOO_ANIM_MOUNT_RIGHT;
|
||||||
|
laraItem->Animation.ActiveState = SKIDOO_STATE_MOUNT;
|
||||||
|
laraItem->Animation.TargetState = SKIDOO_STATE_MOUNT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
laraItem->Animation.FrameNumber = g_Level.Anims[laraItem->Animation.AnimNumber].frameBase;
|
||||||
|
|
||||||
|
DoVehicleFlareDiscard(laraItem);
|
||||||
|
laraItem->Pose.Position = skidooItem->Pose.Position;
|
||||||
|
laraItem->Pose.Orientation = Vector3Shrt(0, skidooItem->Pose.Orientation.y, 0);
|
||||||
|
lara->Control.HandStatus = HandStatus::Busy;
|
||||||
|
skidooItem->Collidable = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TestSkidooDismountOK(ItemInfo* skidooItem, int direction)
|
bool TestSkidooDismountOK(ItemInfo* skidooItem, int direction)
|
||||||
|
@ -177,10 +194,7 @@ namespace TEN::Entities::Vehicles
|
||||||
else
|
else
|
||||||
angle = skidooItem->Pose.Orientation.y - ANGLE(90.0f);
|
angle = skidooItem->Pose.Orientation.y - ANGLE(90.0f);
|
||||||
|
|
||||||
int x = skidooItem->Pose.Position.x - SKIDOO_DISMOUNT_DISTANCE * phd_sin(angle);
|
auto probe = GetCollision(skidooItem, angle, -SKIDOO_DISMOUNT_DISTANCE);
|
||||||
int y = skidooItem->Pose.Position.y;
|
|
||||||
int z = skidooItem->Pose.Position.z - SKIDOO_DISMOUNT_DISTANCE * phd_cos(angle);
|
|
||||||
auto probe = GetCollision(x, y, z, skidooItem->RoomNumber);
|
|
||||||
|
|
||||||
if ((probe.Position.FloorSlope || probe.Position.Floor == NO_HEIGHT) ||
|
if ((probe.Position.FloorSlope || probe.Position.Floor == NO_HEIGHT) ||
|
||||||
abs(probe.Position.Floor - skidooItem->Pose.Position.y) > CLICK(2) ||
|
abs(probe.Position.Floor - skidooItem->Pose.Position.y) > CLICK(2) ||
|
||||||
|
@ -193,9 +207,9 @@ namespace TEN::Entities::Vehicles
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TestSkidooDismount(ItemInfo* laraItem, ItemInfo* skidooItem)
|
bool TestSkidooDismount(ItemInfo* skidooItem, ItemInfo* laraItem)
|
||||||
{
|
{
|
||||||
auto* lara = (LaraInfo*&)laraItem->Data;
|
auto* lara = GetLaraInfo(laraItem);
|
||||||
|
|
||||||
if (lara->Vehicle != NO_ITEM)
|
if (lara->Vehicle != NO_ITEM)
|
||||||
{
|
{
|
||||||
|
@ -208,12 +222,11 @@ namespace TEN::Entities::Vehicles
|
||||||
laraItem->Pose.Orientation.y -= ANGLE(90.0f);
|
laraItem->Pose.Orientation.y -= ANGLE(90.0f);
|
||||||
|
|
||||||
SetAnimation(laraItem, LA_STAND_IDLE);
|
SetAnimation(laraItem, LA_STAND_IDLE);
|
||||||
laraItem->Pose.Position.x -= SKIDOO_DISMOUNT_DISTANCE * phd_sin(laraItem->Pose.Orientation.y);
|
TranslateItem(laraItem, laraItem->Pose.Orientation.y, -SKIDOO_DISMOUNT_DISTANCE);
|
||||||
laraItem->Pose.Position.z -= SKIDOO_DISMOUNT_DISTANCE * phd_cos(laraItem->Pose.Orientation.y);
|
|
||||||
laraItem->Pose.Orientation.x = 0;
|
laraItem->Pose.Orientation.x = 0;
|
||||||
laraItem->Pose.Orientation.z = 0;
|
laraItem->Pose.Orientation.z = 0;
|
||||||
lara->Vehicle = NO_ITEM;
|
|
||||||
lara->Control.HandStatus = HandStatus::Free;
|
lara->Control.HandStatus = HandStatus::Free;
|
||||||
|
lara->Vehicle = NO_ITEM;
|
||||||
}
|
}
|
||||||
else if (laraItem->Animation.ActiveState == SKIDOO_STATE_JUMP_OFF &&
|
else if (laraItem->Animation.ActiveState == SKIDOO_STATE_JUMP_OFF &&
|
||||||
(skidooItem->Pose.Position.y == skidooItem->Floor || TestLastFrame(laraItem)))
|
(skidooItem->Pose.Position.y == skidooItem->Floor || TestLastFrame(laraItem)))
|
||||||
|
@ -224,7 +237,7 @@ namespace TEN::Entities::Vehicles
|
||||||
{
|
{
|
||||||
laraItem->Animation.TargetState = LS_DEATH;
|
laraItem->Animation.TargetState = LS_DEATH;
|
||||||
laraItem->Animation.Velocity = 0;
|
laraItem->Animation.Velocity = 0;
|
||||||
laraItem->Animation.VerticalVelocity = DAMAGE_START + DAMAGE_LENGTH;
|
laraItem->Animation.VerticalVelocity = SKIDOO_DAMAGE_START + SKIDOO_DAMAGE_LENGTH;
|
||||||
ExplodeVehicle(laraItem, skidooItem);
|
ExplodeVehicle(laraItem, skidooItem);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -238,11 +251,11 @@ namespace TEN::Entities::Vehicles
|
||||||
|
|
||||||
laraItem->Pose.Orientation.x = 0;
|
laraItem->Pose.Orientation.x = 0;
|
||||||
laraItem->Pose.Orientation.z = 0;
|
laraItem->Pose.Orientation.z = 0;
|
||||||
laraItem->Animation.Airborne = true;
|
laraItem->Animation.IsAirborne = true;
|
||||||
lara->Control.HandStatus = HandStatus::Free;
|
|
||||||
lara->Control.MoveAngle = skidooItem->Pose.Orientation.y;
|
lara->Control.MoveAngle = skidooItem->Pose.Orientation.y;
|
||||||
skidooItem->Flags |= ONESHOT;
|
lara->Control.HandStatus = HandStatus::Free;
|
||||||
skidooItem->Collidable = false;
|
skidooItem->Collidable = false;
|
||||||
|
skidooItem->Flags |= IFLAG_INVISIBLE;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -253,128 +266,16 @@ namespace TEN::Entities::Vehicles
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int GetSkidooCollisionAnim(ItemInfo* skidooItem, Vector3Int* moved)
|
|
||||||
{
|
|
||||||
moved->x = skidooItem->Pose.Position.x - moved->x;
|
|
||||||
moved->z = skidooItem->Pose.Position.z - moved->z;
|
|
||||||
|
|
||||||
if (moved->x || moved->z)
|
|
||||||
{
|
|
||||||
float s = phd_sin(skidooItem->Pose.Orientation.y);
|
|
||||||
float c = phd_cos(skidooItem->Pose.Orientation.y);
|
|
||||||
|
|
||||||
int side = -moved->z * s + moved->x * c;
|
|
||||||
int front = moved->z * c + moved->x * s;
|
|
||||||
|
|
||||||
if (abs(front) > abs(side))
|
|
||||||
{
|
|
||||||
if (front > 0)
|
|
||||||
return SKIDOO_ANIM_HIT_BACK;
|
|
||||||
else
|
|
||||||
return SKIDOO_ANIM_HIT_FRONT;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (side > 0)
|
|
||||||
return SKIDOO_ANIM_HIT_LEFT;
|
|
||||||
else
|
|
||||||
return SKIDOO_ANIM_HIT_RIGHT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SkidooCollision(short itemNum, ItemInfo* laraItem, CollisionInfo* coll)
|
|
||||||
{
|
|
||||||
auto* lara = (LaraInfo*&)laraItem->Data;
|
|
||||||
auto* skidooItem = &g_Level.Items[itemNum];
|
|
||||||
|
|
||||||
if (laraItem->HitPoints < 0 || lara->Vehicle != NO_ITEM)
|
|
||||||
return;
|
|
||||||
|
|
||||||
int mountType = GetSkidooMountType(laraItem, skidooItem, coll);
|
|
||||||
if (mountType == 0)
|
|
||||||
{
|
|
||||||
ObjectCollision(itemNum, laraItem, coll);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
lara->Vehicle = itemNum;
|
|
||||||
|
|
||||||
if (lara->Control.Weapon.GunType == LaraWeaponType::Flare)
|
|
||||||
{
|
|
||||||
CreateFlare(laraItem, ID_FLARE_ITEM, false);
|
|
||||||
UndrawFlareMeshes(laraItem);
|
|
||||||
lara->Flare.ControlLeft = 0;
|
|
||||||
lara->Control.Weapon.RequestGunType = LaraWeaponType::None;
|
|
||||||
lara->Control.HandStatus = HandStatus::Free;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mountType == 1)
|
|
||||||
laraItem->Animation.AnimNumber = Objects[ID_SNOWMOBILE_LARA_ANIMS].animIndex + SKIDOO_ANIM_MOUNT_RIGHT;
|
|
||||||
else if (mountType == 2)
|
|
||||||
laraItem->Animation.AnimNumber = Objects[ID_SNOWMOBILE_LARA_ANIMS].animIndex + SKIDOO_ANIM_MOUNT_LEFT;
|
|
||||||
|
|
||||||
laraItem->Animation.FrameNumber = g_Level.Anims[laraItem->Animation.AnimNumber].frameBase;
|
|
||||||
laraItem->Animation.ActiveState = SKIDOO_STATE_MOUNT;
|
|
||||||
laraItem->Pose.Position.x = skidooItem->Pose.Position.x;
|
|
||||||
laraItem->Pose.Position.y = skidooItem->Pose.Position.y;
|
|
||||||
laraItem->Pose.Position.z = skidooItem->Pose.Position.z;
|
|
||||||
laraItem->Pose.Orientation.y = skidooItem->Pose.Orientation.y;
|
|
||||||
lara->Control.HandStatus = HandStatus::Busy;
|
|
||||||
skidooItem->Collidable = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SkidooGuns(ItemInfo* laraItem, ItemInfo* skidooItem)
|
|
||||||
{
|
|
||||||
auto* lara = (LaraInfo*&)laraItem->Data;
|
|
||||||
auto* skidoo = (SkidooInfo*)skidooItem->Data;
|
|
||||||
auto* weapon = &Weapons[(int)LaraWeaponType::Snowmobile];
|
|
||||||
|
|
||||||
LaraGetNewTarget(laraItem, weapon);
|
|
||||||
AimWeapon(laraItem, weapon, &lara->RightArm);
|
|
||||||
|
|
||||||
if (TrInput & SKIDOO_IN_FIRE && !skidooItem->ItemFlags[0])
|
|
||||||
{
|
|
||||||
auto angles = Vector3Shrt(
|
|
||||||
lara->RightArm.Orientation.x,
|
|
||||||
lara->RightArm.Orientation.y + laraItem->Pose.Orientation.y,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
|
|
||||||
if ((int)FireWeapon(LaraWeaponType::Pistol, lara->TargetEntity, laraItem, angles) +
|
|
||||||
(int)FireWeapon(LaraWeaponType::Pistol, lara->TargetEntity, laraItem, angles))
|
|
||||||
{
|
|
||||||
skidoo->FlashTimer = 2;
|
|
||||||
SoundEffect(weapon->SampleNum, &laraItem->Pose);
|
|
||||||
skidooItem->ItemFlags[0] = 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (skidooItem->ItemFlags[0])
|
|
||||||
skidooItem->ItemFlags[0]--;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DoSnowEffect(ItemInfo* skidooItem)
|
|
||||||
{
|
|
||||||
auto material = GetCollision(skidooItem).BottomBlock->Material;
|
|
||||||
if (material != FLOOR_MATERIAL::Ice && material != FLOOR_MATERIAL::Snow)
|
|
||||||
return;
|
|
||||||
|
|
||||||
TEN::Effects::TriggerSnowmobileSnow(skidooItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SkidooControl(ItemInfo* laraItem, CollisionInfo* coll)
|
bool SkidooControl(ItemInfo* laraItem, CollisionInfo* coll)
|
||||||
{
|
{
|
||||||
auto* lara = (LaraInfo*&)laraItem->Data;
|
auto* lara = GetLaraInfo(laraItem);
|
||||||
auto* skidooItem = &g_Level.Items[lara->Vehicle];
|
auto* skidooItem = &g_Level.Items[lara->Vehicle];
|
||||||
auto* skidoo = (SkidooInfo*)skidooItem->Data;
|
auto* skidoo = GetSkidooInfo(skidooItem);
|
||||||
|
|
||||||
Vector3Int frontLeft, frontRight;
|
Vector3Int frontLeft, frontRight;
|
||||||
auto collide = SkidooDynamics(laraItem, skidooItem);
|
auto collide = SkidooDynamics(skidooItem, laraItem);
|
||||||
auto heightFrontLeft = TestSkidooHeight(skidooItem, SKIDOO_FRONT, -SKIDOO_SIDE, &frontLeft);
|
auto heightFrontLeft = GetVehicleHeight(skidooItem, SKIDOO_FRONT, -SKIDOO_SIDE, true, &frontLeft);
|
||||||
auto heightFrontRight = TestSkidooHeight(skidooItem, SKIDOO_FRONT, SKIDOO_SIDE, &frontRight);
|
auto heightFrontRight = GetVehicleHeight(skidooItem, SKIDOO_FRONT, SKIDOO_SIDE, true, &frontRight);
|
||||||
|
|
||||||
auto probe = GetCollision(skidooItem);
|
auto probe = GetCollision(skidooItem);
|
||||||
|
|
||||||
|
@ -398,7 +299,7 @@ namespace TEN::Entities::Vehicles
|
||||||
int height = probe.Position.Floor;
|
int height = probe.Position.Floor;
|
||||||
int pitch = 0;
|
int pitch = 0;
|
||||||
|
|
||||||
if (skidooItem->Flags & ONESHOT)
|
if (skidooItem->Flags & IFLAG_INVISIBLE)
|
||||||
{
|
{
|
||||||
drive = 0;
|
drive = 0;
|
||||||
collide = 0;
|
collide = 0;
|
||||||
|
@ -417,8 +318,7 @@ namespace TEN::Entities::Vehicles
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
drive = SkidooUserControl(laraItem, skidooItem, height, &pitch);
|
drive = SkidooUserControl(skidooItem, laraItem, height, &pitch);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -429,7 +329,7 @@ namespace TEN::Entities::Vehicles
|
||||||
skidoo->TrackMesh = ((skidoo->TrackMesh & 3) == 1) ? 2 : 1;
|
skidoo->TrackMesh = ((skidoo->TrackMesh & 3) == 1) ? 2 : 1;
|
||||||
skidoo->Pitch += (pitch - skidoo->Pitch) / 4;
|
skidoo->Pitch += (pitch - skidoo->Pitch) / 4;
|
||||||
|
|
||||||
auto pitch = std::clamp(0.5f + (float)abs(skidoo->Pitch) / (float)SKIDOO_MAX_VELOCITY, 0.6f, 1.4f);
|
auto pitch = std::clamp(0.5f + (float)abs(skidoo->Pitch) / (float)SKIDOO_NORMAL_VELOCITY_MAX, 0.6f, 1.4f);
|
||||||
SoundEffect(skidoo->Pitch ? SFX_TR2_VEHICLE_SNOWMOBILE_MOVING : SFX_TR2_VEHICLE_SNOWMOBILE_ACCELERATE, &skidooItem->Pose, SoundEnvironment::Land, pitch);
|
SoundEffect(skidoo->Pitch ? SFX_TR2_VEHICLE_SNOWMOBILE_MOVING : SFX_TR2_VEHICLE_SNOWMOBILE_ACCELERATE, &skidooItem->Pose, SoundEnvironment::Land, pitch);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -450,10 +350,10 @@ namespace TEN::Entities::Vehicles
|
||||||
short xRot = phd_atan(SKIDOO_FRONT, skidooItem->Pose.Position.y - height);
|
short xRot = phd_atan(SKIDOO_FRONT, skidooItem->Pose.Position.y - height);
|
||||||
short zRot = phd_atan(SKIDOO_SIDE, height - frontLeft.y);
|
short zRot = phd_atan(SKIDOO_SIDE, height - frontLeft.y);
|
||||||
|
|
||||||
skidooItem->Pose.Orientation.x += ((xRot - skidooItem->Pose.Orientation.x) / 2);
|
skidooItem->Pose.Orientation.x += (xRot - skidooItem->Pose.Orientation.x) / 2;
|
||||||
skidooItem->Pose.Orientation.z += ((zRot - skidooItem->Pose.Orientation.z) / 2);
|
skidooItem->Pose.Orientation.z += (zRot - skidooItem->Pose.Orientation.z) / 2;
|
||||||
|
|
||||||
if (skidooItem->Flags & ONESHOT)
|
if (skidooItem->Flags & IFLAG_INVISIBLE)
|
||||||
{
|
{
|
||||||
if (probe.RoomNumber != skidooItem->RoomNumber)
|
if (probe.RoomNumber != skidooItem->RoomNumber)
|
||||||
{
|
{
|
||||||
|
@ -466,10 +366,10 @@ namespace TEN::Entities::Vehicles
|
||||||
if (skidooItem->Pose.Position.y == skidooItem->Floor)
|
if (skidooItem->Pose.Position.y == skidooItem->Floor)
|
||||||
ExplodeVehicle(laraItem, skidooItem);
|
ExplodeVehicle(laraItem, skidooItem);
|
||||||
|
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
SkidooAnimation(laraItem, skidooItem, collide, dead);
|
SkidooAnimation(skidooItem, laraItem, collide, dead);
|
||||||
|
|
||||||
if (probe.RoomNumber != skidooItem->RoomNumber)
|
if (probe.RoomNumber != skidooItem->RoomNumber)
|
||||||
{
|
{
|
||||||
|
@ -479,9 +379,7 @@ namespace TEN::Entities::Vehicles
|
||||||
|
|
||||||
if (laraItem->Animation.ActiveState != SKIDOO_STATE_FALLOFF)
|
if (laraItem->Animation.ActiveState != SKIDOO_STATE_FALLOFF)
|
||||||
{
|
{
|
||||||
laraItem->Pose.Position.x = skidooItem->Pose.Position.x;
|
laraItem->Pose.Position = skidooItem->Pose.Position;
|
||||||
laraItem->Pose.Position.y = skidooItem->Pose.Position.y;
|
|
||||||
laraItem->Pose.Position.z = skidooItem->Pose.Position.z;
|
|
||||||
laraItem->Pose.Orientation.y = skidooItem->Pose.Orientation.y;
|
laraItem->Pose.Orientation.y = skidooItem->Pose.Orientation.y;
|
||||||
|
|
||||||
if (drive >= 0)
|
if (drive >= 0)
|
||||||
|
@ -498,7 +396,7 @@ namespace TEN::Entities::Vehicles
|
||||||
AnimateItem(laraItem);
|
AnimateItem(laraItem);
|
||||||
|
|
||||||
if (!dead && drive >= 0 && banditSkidoo)
|
if (!dead && drive >= 0 && banditSkidoo)
|
||||||
SkidooGuns(laraItem, skidooItem);
|
SkidooGuns(skidooItem, laraItem);
|
||||||
|
|
||||||
if (!dead)
|
if (!dead)
|
||||||
{
|
{
|
||||||
|
@ -519,15 +417,15 @@ namespace TEN::Entities::Vehicles
|
||||||
DoSnowEffect(skidooItem);
|
DoSnowEffect(skidooItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TestSkidooDismount(laraItem, skidooItem);
|
return TestSkidooDismount(skidooItem, laraItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SkidooUserControl(ItemInfo* laraItem, ItemInfo* skidooItem, int height, int* pitch)
|
bool SkidooUserControl(ItemInfo* skidooItem, ItemInfo* laraItem, int height, int* pitch)
|
||||||
{
|
{
|
||||||
auto* skidoo = (SkidooInfo*)skidooItem->Data;
|
auto* skidoo = GetSkidooInfo(skidooItem);
|
||||||
|
|
||||||
bool drive = false;
|
|
||||||
int maxVelocity = 0;
|
int maxVelocity = 0;
|
||||||
|
bool drive = false;
|
||||||
|
|
||||||
if (skidooItem->Pose.Position.y >= (height - CLICK(1)))
|
if (skidooItem->Pose.Position.y >= (height - CLICK(1)))
|
||||||
{
|
{
|
||||||
|
@ -536,66 +434,55 @@ namespace TEN::Entities::Vehicles
|
||||||
if (TrInput & IN_LOOK && skidooItem->Animation.Velocity == 0)
|
if (TrInput & IN_LOOK && skidooItem->Animation.Velocity == 0)
|
||||||
LookUpDown(laraItem);
|
LookUpDown(laraItem);
|
||||||
|
|
||||||
if ((TrInput & SKIDOO_IN_LEFT && !(TrInput & SKIDOO_IN_BRAKE)) ||
|
if (TrInput & (VEHICLE_IN_LEFT | VEHICLE_IN_RIGHT))
|
||||||
(TrInput & SKIDOO_IN_RIGHT && TrInput & SKIDOO_IN_BRAKE))
|
ModulateVehicleTurnRateY(&skidoo->TurnRate, SKIDOO_TURN_RATE_ACCEL, -SKIDOO_TURN_RATE_MAX, SKIDOO_TURN_RATE_MAX);
|
||||||
{
|
|
||||||
skidoo->TurnRate -= SKIDOO_TURN;
|
|
||||||
if (skidoo->TurnRate < -SKIDOO_MAX_TURN)
|
|
||||||
skidoo->TurnRate = -SKIDOO_MAX_TURN;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((TrInput & SKIDOO_IN_RIGHT && !(TrInput & SKIDOO_IN_BRAKE)) ||
|
if (TrInput & VEHICLE_IN_REVERSE)
|
||||||
(TrInput & SKIDOO_IN_LEFT && TrInput & SKIDOO_IN_BRAKE))
|
|
||||||
{
|
|
||||||
skidoo->TurnRate += SKIDOO_TURN;
|
|
||||||
if (skidoo->TurnRate > SKIDOO_MAX_TURN)
|
|
||||||
skidoo->TurnRate = SKIDOO_MAX_TURN;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (TrInput & SKIDOO_IN_BRAKE)
|
|
||||||
{
|
{
|
||||||
if (skidooItem->Animation.Velocity > 0)
|
if (skidooItem->Animation.Velocity > 0)
|
||||||
skidooItem->Animation.Velocity -= SKIDOO_BRAKE;
|
skidooItem->Animation.Velocity -= SKIDOO_VELOCITY_BRAKE_DECEL;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (skidooItem->Animation.Velocity > SKIDOO_MAX_BACK)
|
if (skidooItem->Animation.Velocity > -SKIDOO_REVERSE_VELOCITY_MAX)
|
||||||
skidooItem->Animation.Velocity += SKIDOO_REVERSE;
|
skidooItem->Animation.Velocity -= SKIDOO_REVERSE_VELOCITY_ACCEL;
|
||||||
|
|
||||||
drive = true;
|
drive = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (TrInput & SKIDOO_IN_ACCELERATE)
|
else if (TrInput & VEHICLE_IN_ACCELERATE)
|
||||||
{
|
{
|
||||||
if (TrInput & SKIDOO_IN_FIRE && !skidoo->Armed)
|
if (TrInput & VEHICLE_IN_SPEED)
|
||||||
maxVelocity = SKIDOO_FAST_VELOCITY;
|
maxVelocity = SKIDOO_FAST_VELOCITY_MAX;
|
||||||
else if (TrInput & SKIDOO_IN_SLOW)
|
else if (TrInput & VEHICLE_IN_SLOW)
|
||||||
maxVelocity = SKIDOO_SLOW_VELOCITY;
|
maxVelocity = SKIDOO_SLOW_VELOCITY_MAX;
|
||||||
else
|
else
|
||||||
maxVelocity = SKIDOO_MAX_VELOCITY;
|
maxVelocity = SKIDOO_NORMAL_VELOCITY_MAX;
|
||||||
|
|
||||||
if (skidooItem->Animation.Velocity < maxVelocity)
|
if (skidooItem->Animation.Velocity < maxVelocity)
|
||||||
skidooItem->Animation.Velocity += (SKIDOO_ACCELERATION / 2) + (SKIDOO_ACCELERATION * (skidooItem->Animation.Velocity / (2 * maxVelocity)));
|
skidooItem->Animation.Velocity += (SKIDOO_VELOCITY_ACCEL / 2) + (SKIDOO_VELOCITY_ACCEL * (skidooItem->Animation.Velocity / (2 * maxVelocity)));
|
||||||
else if (skidooItem->Animation.Velocity > (maxVelocity + SKIDOO_SLOWDOWN))
|
else if (skidooItem->Animation.Velocity > (maxVelocity + SKIDOO_VELOCITY_DECEL))
|
||||||
skidooItem->Animation.Velocity -= SKIDOO_SLOWDOWN;
|
skidooItem->Animation.Velocity -= SKIDOO_VELOCITY_DECEL;
|
||||||
|
|
||||||
drive = true;
|
drive = true;
|
||||||
}
|
}
|
||||||
else if (TrInput & (SKIDOO_IN_LEFT | SKIDOO_IN_RIGHT) &&
|
else if (TrInput & (VEHICLE_IN_LEFT | VEHICLE_IN_RIGHT) &&
|
||||||
skidooItem->Animation.Velocity >= 0 &&
|
skidooItem->Animation.Velocity >= 0 &&
|
||||||
skidooItem->Animation.Velocity < SKIDOO_MIN_VELOCITY)
|
skidooItem->Animation.Velocity < SKIDOO_TURN_VELOCITY_MAX)
|
||||||
{
|
{
|
||||||
skidooItem->Animation.Velocity = SKIDOO_MIN_VELOCITY;
|
skidooItem->Animation.Velocity = SKIDOO_TURN_VELOCITY_MAX;
|
||||||
drive = true;
|
drive = true;
|
||||||
}
|
}
|
||||||
else if (skidooItem->Animation.Velocity > SKIDOO_SLOWDOWN)
|
else if (skidooItem->Animation.Velocity > SKIDOO_VELOCITY_DECEL)
|
||||||
{
|
{
|
||||||
skidooItem->Animation.Velocity -= SKIDOO_SLOWDOWN;
|
skidooItem->Animation.Velocity -= SKIDOO_VELOCITY_DECEL;
|
||||||
|
|
||||||
if ((GetRandomControl() & 0x7f) < skidooItem->Animation.Velocity)
|
if ((GetRandomControl() & 0x7f) < skidooItem->Animation.Velocity)
|
||||||
drive = true;
|
drive = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
skidooItem->Animation.Velocity = 0;
|
skidooItem->Animation.Velocity = 0;
|
||||||
}
|
}
|
||||||
else if (TrInput & (SKIDOO_IN_ACCELERATE | SKIDOO_IN_BRAKE))
|
else if (TrInput & (VEHICLE_IN_ACCELERATE | VEHICLE_IN_REVERSE))
|
||||||
{
|
{
|
||||||
*pitch = skidoo->Pitch + 50;
|
*pitch = skidoo->Pitch + 50;
|
||||||
drive = true;
|
drive = true;
|
||||||
|
@ -604,13 +491,13 @@ namespace TEN::Entities::Vehicles
|
||||||
return drive;
|
return drive;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkidooAnimation(ItemInfo* laraItem, ItemInfo* skidooItem, int collide, bool dead)
|
void SkidooAnimation(ItemInfo* skidooItem, ItemInfo* laraItem, int collide, bool dead)
|
||||||
{
|
{
|
||||||
auto* skidoo = (SkidooInfo*)skidooItem->Data;
|
auto* skidoo = GetSkidooInfo(skidooItem);
|
||||||
|
|
||||||
if (laraItem->Animation.ActiveState != SKIDOO_STATE_FALL &&
|
if (laraItem->Animation.ActiveState != SKIDOO_STATE_FALL &&
|
||||||
skidooItem->Pose.Position.y != skidooItem->Floor &&
|
|
||||||
skidooItem->Animation.VerticalVelocity > 0 &&
|
skidooItem->Animation.VerticalVelocity > 0 &&
|
||||||
|
skidooItem->Pose.Position.y != skidooItem->Floor &&
|
||||||
!dead)
|
!dead)
|
||||||
{
|
{
|
||||||
laraItem->Animation.AnimNumber = Objects[ID_SNOWMOBILE_LARA_ANIMS].animIndex + SKIDOO_ANIM_LEAP_START;
|
laraItem->Animation.AnimNumber = Objects[ID_SNOWMOBILE_LARA_ANIMS].animIndex + SKIDOO_ANIM_LEAP_START;
|
||||||
|
@ -647,52 +534,88 @@ namespace TEN::Entities::Vehicles
|
||||||
|
|
||||||
laraItem->Animation.TargetState = SKIDOO_STATE_IDLE;
|
laraItem->Animation.TargetState = SKIDOO_STATE_IDLE;
|
||||||
|
|
||||||
if (TrInput & SKIDOO_IN_DISMOUNT)
|
if (TrInput & VEHICLE_IN_DISMOUNT)
|
||||||
{
|
{
|
||||||
if (TrInput & SKIDOO_IN_RIGHT &&
|
if (TrInput & VEHICLE_IN_RIGHT &&
|
||||||
TestSkidooDismountOK(skidooItem, SKIDOO_STATE_DISMOUNT_RIGHT))
|
TestSkidooDismountOK(skidooItem, SKIDOO_STATE_DISMOUNT_RIGHT))
|
||||||
{
|
{
|
||||||
laraItem->Animation.TargetState = SKIDOO_STATE_DISMOUNT_RIGHT;
|
laraItem->Animation.TargetState = SKIDOO_STATE_DISMOUNT_RIGHT;
|
||||||
skidooItem->Animation.Velocity = 0;
|
skidooItem->Animation.Velocity = 0;
|
||||||
}
|
}
|
||||||
else if (TrInput & SKIDOO_IN_LEFT &&
|
else if (TrInput & VEHICLE_IN_LEFT &&
|
||||||
TestSkidooDismountOK(skidooItem, SKIDOO_STATE_DISMOUNT_LEFT))
|
TestSkidooDismountOK(skidooItem, SKIDOO_STATE_DISMOUNT_LEFT))
|
||||||
{
|
{
|
||||||
laraItem->Animation.TargetState = SKIDOO_STATE_DISMOUNT_LEFT;
|
laraItem->Animation.TargetState = SKIDOO_STATE_DISMOUNT_LEFT;
|
||||||
skidooItem->Animation.Velocity = 0;
|
skidooItem->Animation.Velocity = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (TrInput & SKIDOO_IN_LEFT)
|
else if (TrInput & VEHICLE_IN_LEFT)
|
||||||
|
{
|
||||||
|
if (skidooItem->Animation.Velocity >= 0)
|
||||||
laraItem->Animation.TargetState = SKIDOO_STATE_LEFT;
|
laraItem->Animation.TargetState = SKIDOO_STATE_LEFT;
|
||||||
else if (TrInput & SKIDOO_IN_RIGHT)
|
else
|
||||||
laraItem->Animation.TargetState = SKIDOO_STATE_RIGHT;
|
laraItem->Animation.TargetState = SKIDOO_STATE_RIGHT;
|
||||||
else if (TrInput & (SKIDOO_IN_ACCELERATE | SKIDOO_IN_BRAKE))
|
}
|
||||||
laraItem->Animation.TargetState = SKIDOO_STATE_SIT;
|
else if (TrInput & VEHICLE_IN_RIGHT)
|
||||||
|
{
|
||||||
|
if (skidooItem->Animation.Velocity >= 0)
|
||||||
|
laraItem->Animation.TargetState = SKIDOO_STATE_RIGHT;
|
||||||
|
else
|
||||||
|
laraItem->Animation.TargetState = SKIDOO_STATE_LEFT;
|
||||||
|
}
|
||||||
|
else if (TrInput & (VEHICLE_IN_ACCELERATE | VEHICLE_IN_REVERSE))
|
||||||
|
laraItem->Animation.TargetState = SKIDOO_STATE_DRIVE;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SKIDOO_STATE_SIT:
|
case SKIDOO_STATE_DRIVE:
|
||||||
if (skidooItem->Animation.Velocity == 0)
|
if (skidooItem->Animation.Velocity == 0)
|
||||||
laraItem->Animation.TargetState = SKIDOO_STATE_IDLE;
|
laraItem->Animation.TargetState = SKIDOO_STATE_IDLE;
|
||||||
|
|
||||||
if (dead)
|
if (dead)
|
||||||
laraItem->Animation.TargetState = SKIDOO_STATE_FALLOFF;
|
laraItem->Animation.TargetState = SKIDOO_STATE_FALLOFF;
|
||||||
else if (TrInput & SKIDOO_IN_LEFT)
|
else if (TrInput & VEHICLE_IN_LEFT)
|
||||||
|
{
|
||||||
|
if (skidooItem->Animation.Velocity >= 0)
|
||||||
laraItem->Animation.TargetState = SKIDOO_STATE_LEFT;
|
laraItem->Animation.TargetState = SKIDOO_STATE_LEFT;
|
||||||
else if (TrInput & SKIDOO_IN_RIGHT)
|
else
|
||||||
laraItem->Animation.TargetState = SKIDOO_STATE_RIGHT;
|
laraItem->Animation.TargetState = SKIDOO_STATE_RIGHT;
|
||||||
|
}
|
||||||
|
else if (TrInput & VEHICLE_IN_RIGHT)
|
||||||
|
{
|
||||||
|
if (skidooItem->Animation.Velocity >= 0)
|
||||||
|
laraItem->Animation.TargetState = SKIDOO_STATE_RIGHT;
|
||||||
|
else
|
||||||
|
laraItem->Animation.TargetState = SKIDOO_STATE_LEFT;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SKIDOO_STATE_LEFT:
|
case SKIDOO_STATE_LEFT:
|
||||||
if (!(TrInput & SKIDOO_IN_LEFT))
|
if (skidooItem->Animation.Velocity >= 0)
|
||||||
laraItem->Animation.TargetState = SKIDOO_STATE_SIT;
|
{
|
||||||
|
if (!(TrInput & VEHICLE_IN_LEFT))
|
||||||
|
laraItem->Animation.TargetState = SKIDOO_STATE_DRIVE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!(TrInput & VEHICLE_IN_RIGHT))
|
||||||
|
laraItem->Animation.TargetState = SKIDOO_STATE_DRIVE;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SKIDOO_STATE_RIGHT:
|
case SKIDOO_STATE_RIGHT:
|
||||||
if (!(TrInput & SKIDOO_IN_RIGHT))
|
if (skidooItem->Animation.Velocity >= 0)
|
||||||
laraItem->Animation.TargetState = SKIDOO_STATE_SIT;
|
{
|
||||||
|
if (!(TrInput & VEHICLE_IN_RIGHT))
|
||||||
|
laraItem->Animation.TargetState = SKIDOO_STATE_DRIVE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!(TrInput & VEHICLE_IN_LEFT))
|
||||||
|
laraItem->Animation.TargetState = SKIDOO_STATE_DRIVE;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -701,10 +624,10 @@ namespace TEN::Entities::Vehicles
|
||||||
skidoo->LeftVerticalVelocity <= 0 ||
|
skidoo->LeftVerticalVelocity <= 0 ||
|
||||||
skidoo->RightVerticalVelocity <= 0)
|
skidoo->RightVerticalVelocity <= 0)
|
||||||
{
|
{
|
||||||
laraItem->Animation.TargetState = SKIDOO_STATE_SIT;
|
laraItem->Animation.TargetState = SKIDOO_STATE_DRIVE;
|
||||||
SoundEffect(SFX_TR2_VEHICLE_IMPACT3, &skidooItem->Pose);
|
SoundEffect(SFX_TR2_VEHICLE_IMPACT3, &skidooItem->Pose);
|
||||||
}
|
}
|
||||||
else if (skidooItem->Animation.VerticalVelocity > (DAMAGE_START + DAMAGE_LENGTH))
|
else if (skidooItem->Animation.VerticalVelocity > (SKIDOO_DAMAGE_START + SKIDOO_DAMAGE_LENGTH))
|
||||||
laraItem->Animation.TargetState = SKIDOO_STATE_JUMP_OFF;
|
laraItem->Animation.TargetState = SKIDOO_STATE_JUMP_OFF;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -712,8 +635,80 @@ namespace TEN::Entities::Vehicles
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int GetSkidooCollisionAnim(ItemInfo* skidooItem, Vector3Int* moved)
|
||||||
|
{
|
||||||
|
moved->x = skidooItem->Pose.Position.x - moved->x;
|
||||||
|
moved->z = skidooItem->Pose.Position.z - moved->z;
|
||||||
|
|
||||||
|
if (moved->x || moved->z)
|
||||||
|
{
|
||||||
|
float sinY = phd_sin(skidooItem->Pose.Orientation.y);
|
||||||
|
float cosY = phd_cos(skidooItem->Pose.Orientation.y);
|
||||||
|
|
||||||
|
int front = (moved->z * cosY) + (moved->x * sinY);
|
||||||
|
int side = (moved->z * -sinY) + (moved->x * cosY);
|
||||||
|
|
||||||
|
if (abs(front) > abs(side))
|
||||||
|
{
|
||||||
|
if (front > 0)
|
||||||
|
return SKIDOO_ANIM_HIT_BACK;
|
||||||
|
else
|
||||||
|
return SKIDOO_ANIM_HIT_FRONT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (side > 0)
|
||||||
|
return SKIDOO_ANIM_HIT_LEFT;
|
||||||
|
else
|
||||||
|
return SKIDOO_ANIM_HIT_RIGHT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SkidooGuns(ItemInfo* skidooItem, ItemInfo* laraItem)
|
||||||
|
{
|
||||||
|
auto* skidoo = GetSkidooInfo(skidooItem);
|
||||||
|
auto* lara = GetLaraInfo(laraItem);
|
||||||
|
auto* weapon = &Weapons[(int)LaraWeaponType::Snowmobile];
|
||||||
|
|
||||||
|
LaraGetNewTarget(laraItem, weapon);
|
||||||
|
AimWeapon(laraItem, weapon, &lara->RightArm);
|
||||||
|
|
||||||
|
if (TrInput & VEHICLE_IN_FIRE && !skidooItem->ItemFlags[0])
|
||||||
|
{
|
||||||
|
auto angles = Vector3Shrt(
|
||||||
|
lara->RightArm.Orientation.x,
|
||||||
|
lara->RightArm.Orientation.y + laraItem->Pose.Orientation.y,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
if ((int)FireWeapon(LaraWeaponType::Pistol, lara->TargetEntity, laraItem, angles) +
|
||||||
|
(int)FireWeapon(LaraWeaponType::Pistol, lara->TargetEntity, laraItem, angles))
|
||||||
|
{
|
||||||
|
skidoo->FlashTimer = 2;
|
||||||
|
SoundEffect(weapon->SampleNum, &laraItem->Pose);
|
||||||
|
skidooItem->ItemFlags[0] = 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skidooItem->ItemFlags[0])
|
||||||
|
skidooItem->ItemFlags[0]--;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoSnowEffect(ItemInfo* skidooItem)
|
||||||
|
{
|
||||||
|
auto material = GetCollision(skidooItem).BottomBlock->Material;
|
||||||
|
if (material != FLOOR_MATERIAL::Ice && material != FLOOR_MATERIAL::Snow)
|
||||||
|
return;
|
||||||
|
|
||||||
|
TEN::Effects::TriggerSnowmobileSnow(skidooItem);
|
||||||
|
}
|
||||||
|
|
||||||
int DoSkidooDynamics(int height, int verticalVelocity, int* y)
|
int DoSkidooDynamics(int height, int verticalVelocity, int* y)
|
||||||
{
|
{
|
||||||
|
// Grounded.
|
||||||
if (height > *y)
|
if (height > *y)
|
||||||
{
|
{
|
||||||
*y += verticalVelocity;
|
*y += verticalVelocity;
|
||||||
|
@ -725,11 +720,12 @@ namespace TEN::Entities::Vehicles
|
||||||
else
|
else
|
||||||
verticalVelocity += GRAVITY;
|
verticalVelocity += GRAVITY;
|
||||||
}
|
}
|
||||||
|
// Airborne.
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int kick = (height - *y) * 4;
|
int kick = (height - *y) * 4;
|
||||||
if (kick < SKIDOO_MAX_KICK)
|
if (kick < SKIDOO_KICK_MAX)
|
||||||
kick = SKIDOO_MAX_KICK;
|
kick = SKIDOO_KICK_MAX;
|
||||||
|
|
||||||
verticalVelocity += (kick - verticalVelocity) / 8;
|
verticalVelocity += (kick - verticalVelocity) / 8;
|
||||||
|
|
||||||
|
@ -740,26 +736,6 @@ namespace TEN::Entities::Vehicles
|
||||||
return verticalVelocity;
|
return verticalVelocity;
|
||||||
}
|
}
|
||||||
|
|
||||||
int TestSkidooHeight(ItemInfo* skidooItem, int zOffset, int xOffset, Vector3Int* pos)
|
|
||||||
{
|
|
||||||
pos->y = skidooItem->Pose.Position.y - zOffset * phd_sin(skidooItem->Pose.Orientation.x) + xOffset * phd_sin(skidooItem->Pose.Orientation.z);
|
|
||||||
|
|
||||||
float s = phd_sin(skidooItem->Pose.Orientation.y);
|
|
||||||
float c = phd_cos(skidooItem->Pose.Orientation.y);
|
|
||||||
|
|
||||||
pos->x = skidooItem->Pose.Position.x + zOffset * s + xOffset * c;
|
|
||||||
pos->z = skidooItem->Pose.Position.z + zOffset * c - xOffset * s;
|
|
||||||
|
|
||||||
auto probe = GetCollision(pos->x, pos->y, pos->z, skidooItem->RoomNumber);
|
|
||||||
if (probe.Position.Ceiling > pos->y ||
|
|
||||||
probe.Position.Ceiling == NO_HEIGHT)
|
|
||||||
{
|
|
||||||
return NO_HEIGHT;
|
|
||||||
}
|
|
||||||
|
|
||||||
return probe.Position.Floor;
|
|
||||||
}
|
|
||||||
|
|
||||||
short DoSkidooShift(ItemInfo* skidooItem, Vector3Int* pos, Vector3Int* old)
|
short DoSkidooShift(ItemInfo* skidooItem, Vector3Int* pos, Vector3Int* old)
|
||||||
{
|
{
|
||||||
int x = pos->x / SECTOR(1);
|
int x = pos->x / SECTOR(1);
|
||||||
|
@ -860,62 +836,50 @@ namespace TEN::Entities::Vehicles
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SkidooDynamics(ItemInfo* laraItem, ItemInfo* skidooItem)
|
int SkidooDynamics(ItemInfo* skidooItem, ItemInfo* laraItem)
|
||||||
{
|
{
|
||||||
auto* skidoo = (SkidooInfo*)skidooItem->Data;
|
auto* skidoo = GetSkidooInfo(skidooItem);
|
||||||
|
|
||||||
Vector3Int frontLeftOld, frontRightOld, backLeftOld, backRightOld;
|
Vector3Int frontLeftOld, frontRightOld, backLeftOld, backRightOld;
|
||||||
auto heightFrontLeftOld = TestSkidooHeight(skidooItem, SKIDOO_FRONT, -SKIDOO_SIDE, &frontLeftOld);
|
auto heightFrontLeftOld = GetVehicleHeight(skidooItem, SKIDOO_FRONT, -SKIDOO_SIDE, true, &frontLeftOld);
|
||||||
auto heightFrontRightOld = TestSkidooHeight(skidooItem, SKIDOO_FRONT, SKIDOO_SIDE, &frontRightOld);
|
auto heightFrontRightOld = GetVehicleHeight(skidooItem, SKIDOO_FRONT, SKIDOO_SIDE, true, &frontRightOld);
|
||||||
auto heightBackLeftOld = TestSkidooHeight(skidooItem, -SKIDOO_FRONT, -SKIDOO_SIDE, &backLeftOld);
|
auto heightBackLeftOld = GetVehicleHeight(skidooItem, -SKIDOO_FRONT, -SKIDOO_SIDE, true, &backLeftOld);
|
||||||
auto heightBackRightOld = TestSkidooHeight(skidooItem, -SKIDOO_FRONT, SKIDOO_SIDE, &backRightOld);
|
auto heightBackRightOld = GetVehicleHeight(skidooItem, -SKIDOO_FRONT, SKIDOO_SIDE, true, &backRightOld);
|
||||||
|
|
||||||
Vector3Int old;
|
auto oldPos = skidooItem->Pose.Position;
|
||||||
old.x = skidooItem->Pose.Position.x;
|
|
||||||
old.y = skidooItem->Pose.Position.y;
|
|
||||||
old.z = skidooItem->Pose.Position.z;
|
|
||||||
|
|
||||||
if (backLeftOld.y > heightBackLeftOld)
|
|
||||||
backLeftOld.y = heightBackLeftOld;
|
|
||||||
if (backRightOld.y > heightBackRightOld)
|
|
||||||
backRightOld.y = heightBackRightOld;
|
|
||||||
if (frontLeftOld.y > heightFrontLeftOld)
|
|
||||||
frontLeftOld.y = heightFrontLeftOld;
|
|
||||||
if (frontRightOld.y > heightFrontRightOld)
|
|
||||||
frontRightOld.y = heightFrontRightOld;
|
|
||||||
|
|
||||||
short rotation;
|
short rotation;
|
||||||
|
|
||||||
if (skidooItem->Pose.Position.y > (skidooItem->Floor - CLICK(1)))
|
if (skidooItem->Pose.Position.y > (skidooItem->Floor - CLICK(1)))
|
||||||
{
|
{
|
||||||
if (skidoo->TurnRate < -SKIDOO_UNDO_TURN)
|
if (skidoo->TurnRate < -SKIDOO_TURN_RATE_DECEL)
|
||||||
skidoo->TurnRate += SKIDOO_UNDO_TURN;
|
skidoo->TurnRate += SKIDOO_TURN_RATE_DECEL;
|
||||||
else if (skidoo->TurnRate > SKIDOO_UNDO_TURN)
|
else if (skidoo->TurnRate > SKIDOO_TURN_RATE_DECEL)
|
||||||
skidoo->TurnRate -= SKIDOO_UNDO_TURN;
|
skidoo->TurnRate -= SKIDOO_TURN_RATE_DECEL;
|
||||||
else
|
else
|
||||||
skidoo->TurnRate = 0;
|
skidoo->TurnRate = 0;
|
||||||
skidooItem->Pose.Orientation.y += skidoo->TurnRate + skidoo->ExtraRotation;
|
skidooItem->Pose.Orientation.y += skidoo->TurnRate + skidoo->ExtraRotation;
|
||||||
|
|
||||||
rotation = skidooItem->Pose.Orientation.y - skidoo->MomentumAngle;
|
rotation = skidooItem->Pose.Orientation.y - skidoo->MomentumAngle;
|
||||||
if (rotation < -SKIDOO_MOMENTUM_TURN)
|
if (rotation < -SKIDOO_MOMENTUM_TURN_RATE_ACCEL)
|
||||||
{
|
{
|
||||||
if (rotation < -SKIDOO_MAX_MOMENTUM_TURN)
|
if (rotation < -SKIDOO_MOMENTUM_TURN_RATE_MAX)
|
||||||
{
|
{
|
||||||
rotation = -SKIDOO_MAX_MOMENTUM_TURN;
|
rotation = -SKIDOO_MOMENTUM_TURN_RATE_MAX;
|
||||||
skidoo->MomentumAngle = skidooItem->Pose.Orientation.y - rotation;
|
skidoo->MomentumAngle = skidooItem->Pose.Orientation.y - rotation;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
skidoo->MomentumAngle -= SKIDOO_MOMENTUM_TURN;
|
skidoo->MomentumAngle -= SKIDOO_MOMENTUM_TURN_RATE_ACCEL;
|
||||||
}
|
}
|
||||||
else if (rotation > SKIDOO_MOMENTUM_TURN)
|
else if (rotation > SKIDOO_MOMENTUM_TURN_RATE_ACCEL)
|
||||||
{
|
{
|
||||||
if (rotation > SKIDOO_MAX_MOMENTUM_TURN)
|
if (rotation > SKIDOO_MOMENTUM_TURN_RATE_MAX)
|
||||||
{
|
{
|
||||||
rotation = SKIDOO_MAX_MOMENTUM_TURN;
|
rotation = SKIDOO_MOMENTUM_TURN_RATE_MAX;
|
||||||
skidoo->MomentumAngle = skidooItem->Pose.Orientation.y - rotation;
|
skidoo->MomentumAngle = skidooItem->Pose.Orientation.y - rotation;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
skidoo->MomentumAngle += SKIDOO_MOMENTUM_TURN;
|
skidoo->MomentumAngle += SKIDOO_MOMENTUM_TURN_RATE_ACCEL;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
skidoo->MomentumAngle = skidooItem->Pose.Orientation.y;
|
skidoo->MomentumAngle = skidooItem->Pose.Orientation.y;
|
||||||
|
@ -923,59 +887,58 @@ namespace TEN::Entities::Vehicles
|
||||||
else
|
else
|
||||||
skidooItem->Pose.Orientation.y += skidoo->TurnRate + skidoo->ExtraRotation;
|
skidooItem->Pose.Orientation.y += skidoo->TurnRate + skidoo->ExtraRotation;
|
||||||
|
|
||||||
skidooItem->Pose.Position.z += skidooItem->Animation.Velocity * phd_cos(skidoo->MomentumAngle);
|
TranslateItem(skidooItem, skidoo->MomentumAngle, skidooItem->Animation.Velocity);
|
||||||
skidooItem->Pose.Position.x += skidooItem->Animation.Velocity * phd_sin(skidoo->MomentumAngle);
|
|
||||||
|
|
||||||
int slip = SKIDOO_SLIP * phd_sin(skidooItem->Pose.Orientation.x);
|
int slip = SKIDOO_SLIP * phd_sin(skidooItem->Pose.Orientation.x);
|
||||||
if (abs(slip) > (SKIDOO_SLIP / 2))
|
if (abs(slip) > (SKIDOO_SLIP / 2))
|
||||||
{
|
{
|
||||||
skidooItem->Pose.Position.z -= slip * phd_cos(skidooItem->Pose.Orientation.y);
|
|
||||||
skidooItem->Pose.Position.x -= slip * phd_sin(skidooItem->Pose.Orientation.y);
|
skidooItem->Pose.Position.x -= slip * phd_sin(skidooItem->Pose.Orientation.y);
|
||||||
|
skidooItem->Pose.Position.z -= slip * phd_cos(skidooItem->Pose.Orientation.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
slip = SKIDOO_SLIP_SIDE * phd_sin(skidooItem->Pose.Orientation.z);
|
slip = SKIDOO_SLIP_SIDE * phd_sin(skidooItem->Pose.Orientation.z);
|
||||||
if (abs(slip) > (SKIDOO_SLIP_SIDE / 2))
|
if (abs(slip) > (SKIDOO_SLIP_SIDE / 2))
|
||||||
{
|
{
|
||||||
skidooItem->Pose.Position.z -= slip * phd_sin(skidooItem->Pose.Orientation.y);
|
|
||||||
skidooItem->Pose.Position.x += slip * phd_cos(skidooItem->Pose.Orientation.y);
|
skidooItem->Pose.Position.x += slip * phd_cos(skidooItem->Pose.Orientation.y);
|
||||||
|
skidooItem->Pose.Position.z -= slip * phd_sin(skidooItem->Pose.Orientation.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3Int moved;
|
Vector3Int moved;
|
||||||
moved.x = skidooItem->Pose.Position.x;
|
moved.x = skidooItem->Pose.Position.x;
|
||||||
moved.z = skidooItem->Pose.Position.z;
|
moved.z = skidooItem->Pose.Position.z;
|
||||||
|
|
||||||
if (!(skidooItem->Flags & ONESHOT))
|
if (!(skidooItem->Flags & IFLAG_INVISIBLE))
|
||||||
DoVehicleCollision(skidooItem, SKIDOO_RADIUS);
|
DoVehicleCollision(skidooItem, SKIDOO_RADIUS);
|
||||||
|
|
||||||
Vector3Int frontLeft, frontRight, backRight, backLeft;
|
Vector3Int frontLeft, frontRight, backRight, backLeft;
|
||||||
rotation = 0;
|
rotation = 0;
|
||||||
auto heightBackLeft = TestSkidooHeight(skidooItem, -SKIDOO_FRONT, -SKIDOO_SIDE, &backLeft);
|
auto heightBackLeft = GetVehicleHeight(skidooItem, -SKIDOO_FRONT, -SKIDOO_SIDE, false, &backLeft);
|
||||||
if (heightBackLeft < (backLeftOld.y - CLICK(1)))
|
if (heightBackLeft < (backLeftOld.y - CLICK(1)))
|
||||||
rotation = DoSkidooShift(skidooItem, &backLeft, &backLeftOld);
|
rotation = DoSkidooShift(skidooItem, &backLeft, &backLeftOld);
|
||||||
|
|
||||||
auto heightBackRight = TestSkidooHeight(skidooItem, -SKIDOO_FRONT, SKIDOO_SIDE, &backRight);
|
auto heightBackRight = GetVehicleHeight(skidooItem, -SKIDOO_FRONT, SKIDOO_SIDE, false, &backRight);
|
||||||
if (heightBackRight < (backRightOld.y - CLICK(1)))
|
if (heightBackRight < (backRightOld.y - CLICK(1)))
|
||||||
rotation += DoSkidooShift(skidooItem, &backRight, &backRightOld);
|
rotation += DoSkidooShift(skidooItem, &backRight, &backRightOld);
|
||||||
|
|
||||||
auto heightFrontLeft = TestSkidooHeight(skidooItem, SKIDOO_FRONT, -SKIDOO_SIDE, &frontLeft);
|
auto heightFrontLeft = GetVehicleHeight(skidooItem, SKIDOO_FRONT, -SKIDOO_SIDE, false, &frontLeft);
|
||||||
if (heightFrontLeft < (frontLeftOld.y - CLICK(1)))
|
if (heightFrontLeft < (frontLeftOld.y - CLICK(1)))
|
||||||
rotation += DoSkidooShift(skidooItem, &frontLeft, &frontLeftOld);
|
rotation += DoSkidooShift(skidooItem, &frontLeft, &frontLeftOld);
|
||||||
|
|
||||||
auto heightFrontRight = TestSkidooHeight(skidooItem, SKIDOO_FRONT, SKIDOO_SIDE, &frontRight);
|
auto heightFrontRight = GetVehicleHeight(skidooItem, SKIDOO_FRONT, SKIDOO_SIDE, false, &frontRight);
|
||||||
if (heightFrontRight < (frontRightOld.y - CLICK(1)))
|
if (heightFrontRight < (frontRightOld.y - CLICK(1)))
|
||||||
rotation += DoSkidooShift(skidooItem, &frontRight, &frontRightOld);
|
rotation += DoSkidooShift(skidooItem, &frontRight, &frontRightOld);
|
||||||
|
|
||||||
auto probe = GetCollision(skidooItem);
|
auto probe = GetCollision(skidooItem);
|
||||||
if (probe.Position.Floor < (skidooItem->Pose.Position.y - CLICK(1)))
|
if (probe.Position.Floor < (skidooItem->Pose.Position.y - CLICK(1)))
|
||||||
DoSkidooShift(skidooItem, (Vector3Int*)&skidooItem->Pose, &old);
|
DoSkidooShift(skidooItem, (Vector3Int*)&skidooItem->Pose, &oldPos);
|
||||||
|
|
||||||
skidoo->ExtraRotation = rotation;
|
skidoo->ExtraRotation = rotation;
|
||||||
|
|
||||||
auto collide = GetSkidooCollisionAnim(skidooItem, &moved);
|
auto collide = GetSkidooCollisionAnim(skidooItem, &moved);
|
||||||
if (collide)
|
if (collide)
|
||||||
{
|
{
|
||||||
int newVelocity = (skidooItem->Pose.Position.z - old.z) * phd_cos(skidoo->MomentumAngle) + (skidooItem->Pose.Position.x - old.x) * phd_sin(skidoo->MomentumAngle);
|
int newVelocity = (skidooItem->Pose.Position.z - oldPos.z) * phd_cos(skidoo->MomentumAngle) + (skidooItem->Pose.Position.x - oldPos.x) * phd_sin(skidoo->MomentumAngle);
|
||||||
if (skidooItem->Animation.Velocity > (SKIDOO_MAX_VELOCITY + SKIDOO_ACCELERATION) &&
|
if (skidooItem->Animation.Velocity > (SKIDOO_NORMAL_VELOCITY_MAX + SKIDOO_VELOCITY_ACCEL) &&
|
||||||
newVelocity < (skidooItem->Animation.Velocity - 10))
|
newVelocity < (skidooItem->Animation.Velocity - 10))
|
||||||
{
|
{
|
||||||
DoDamage(laraItem, (skidooItem->Animation.Velocity - newVelocity) / 2);
|
DoDamage(laraItem, (skidooItem->Animation.Velocity - newVelocity) / 2);
|
||||||
|
@ -986,15 +949,10 @@ namespace TEN::Entities::Vehicles
|
||||||
else if (skidooItem->Animation.Velocity < 0 && newVelocity > skidooItem->Animation.Velocity)
|
else if (skidooItem->Animation.Velocity < 0 && newVelocity > skidooItem->Animation.Velocity)
|
||||||
skidooItem->Animation.Velocity = (newVelocity > 0) ? 0 : newVelocity;
|
skidooItem->Animation.Velocity = (newVelocity > 0) ? 0 : newVelocity;
|
||||||
|
|
||||||
if (skidooItem->Animation.Velocity < SKIDOO_MAX_BACK)
|
if (skidooItem->Animation.Velocity < SKIDOO_REVERSE_VELOCITY_MAX)
|
||||||
skidooItem->Animation.Velocity = SKIDOO_MAX_BACK;
|
skidooItem->Animation.Velocity = SKIDOO_REVERSE_VELOCITY_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
return collide;
|
return collide;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrawSkidoo(ItemInfo* skidooItem)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,29 +1,28 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "Game/collision/collide_room.h"
|
#include "Game/collision/collide_room.h"
|
||||||
#include "Game/items.h"
|
#include "Game/items.h"
|
||||||
|
#include "Objects/Utils/VehicleHelpers.h"
|
||||||
|
|
||||||
namespace TEN::Entities::Vehicles
|
namespace TEN::Entities::Vehicles
|
||||||
{
|
{
|
||||||
|
SkidooInfo* GetSkidooInfo(ItemInfo* skidooItem);
|
||||||
void InitialiseSkidoo(short itemNumber);
|
void InitialiseSkidoo(short itemNumber);
|
||||||
|
|
||||||
int GetSkidooMountType(ItemInfo* laraItem, ItemInfo* skidooItem, CollisionInfo* coll);
|
void SkidooPlayerCollision(short skidooItemNumber, ItemInfo* laraItem, CollisionInfo* coll);
|
||||||
|
void DoSkidooMount(ItemInfo* skidooItem, ItemInfo* laraItem, VehicleMountType mountType);
|
||||||
bool TestSkidooDismountOK(ItemInfo* skidooItem, int direction);
|
bool TestSkidooDismountOK(ItemInfo* skidooItem, int direction);
|
||||||
bool TestSkidooDismount(ItemInfo* laraItem, ItemInfo* skidooItem);
|
bool TestSkidooDismount(ItemInfo* skidooItem, ItemInfo* laraItem);
|
||||||
|
|
||||||
int GetSkidooCollisionAnim(ItemInfo* skidooItem, Vector3Int* moved);
|
|
||||||
void SkidooCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll);
|
|
||||||
|
|
||||||
void SkidooGuns(ItemInfo* laraItem, ItemInfo* skidooItem);
|
|
||||||
void DoSnowEffect(ItemInfo* skidooItem);
|
|
||||||
|
|
||||||
bool SkidooControl(ItemInfo* laraItem, CollisionInfo* coll);
|
bool SkidooControl(ItemInfo* laraItem, CollisionInfo* coll);
|
||||||
bool SkidooUserControl(ItemInfo* laraItem, ItemInfo* skidooItem, int height, int* pitch);
|
bool SkidooUserControl(ItemInfo* skidooItem, ItemInfo* laraItem, int height, int* pitch);
|
||||||
void SkidooAnimation(ItemInfo* laraItem, ItemInfo* skidooItem, int collide, bool dead);
|
void SkidooAnimation(ItemInfo* skidooItem, ItemInfo* laraItem, int collide, bool dead);
|
||||||
|
|
||||||
int SkidooDynamics(ItemInfo* laraItem, ItemInfo* skidooItem);
|
int GetSkidooCollisionAnim(ItemInfo* skidooItem, Vector3Int* moved);
|
||||||
int TestSkidooHeight(ItemInfo* skidooItem, int zOffset, int xOffset, Vector3Int* pos);
|
|
||||||
|
void SkidooGuns(ItemInfo* skidooItem, ItemInfo* laraItem);
|
||||||
|
void DoSnowEffect(ItemInfo* skidooItem);
|
||||||
|
|
||||||
|
int SkidooDynamics(ItemInfo* skidooItem, ItemInfo* laraItem);
|
||||||
short DoSkidooShift(ItemInfo* skidooItem, Vector3Int* pos, Vector3Int* old);
|
short DoSkidooShift(ItemInfo* skidooItem, Vector3Int* pos, Vector3Int* old);
|
||||||
int DoSkidooDynamics(int height, int verticalVelocity, int* y);
|
int DoSkidooDynamics(int height, int verticalVelocity, int* y);
|
||||||
|
|
||||||
void DrawSkidoo(ItemInfo* skidooItem);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,16 +4,16 @@ namespace TEN::Entities::Vehicles
|
||||||
{
|
{
|
||||||
struct SkidooInfo
|
struct SkidooInfo
|
||||||
{
|
{
|
||||||
short TurnRate;
|
int LeftVerticalVelocity = 0;
|
||||||
short MomentumAngle;
|
int RightVerticalVelocity = 0;
|
||||||
short ExtraRotation;
|
|
||||||
|
|
||||||
int LeftVerticalVelocity;
|
short TurnRate = 0;
|
||||||
int RightVerticalVelocity;
|
short MomentumAngle = 0;
|
||||||
|
short ExtraRotation = 0;
|
||||||
|
|
||||||
int Pitch;
|
int Pitch = 0;
|
||||||
int FlashTimer;
|
int FlashTimer = 0;
|
||||||
short TrackMesh;
|
short TrackMesh = 0;
|
||||||
bool Armed;
|
bool Armed = false;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
913
TombEngine/Objects/TR2/Vehicles/speedboat.cpp
Normal file
913
TombEngine/Objects/TR2/Vehicles/speedboat.cpp
Normal file
|
@ -0,0 +1,913 @@
|
||||||
|
#include "framework.h"
|
||||||
|
#include "Objects/TR2/Vehicles/speedboat.h"
|
||||||
|
|
||||||
|
#include "Game/animation.h"
|
||||||
|
#include "Game/camera.h"
|
||||||
|
#include "Game/collision/collide_item.h"
|
||||||
|
#include "Game/collision/sphere.h"
|
||||||
|
#include "Game/effects/effects.h"
|
||||||
|
#include "Game/items.h"
|
||||||
|
#include "Game/Lara/lara.h"
|
||||||
|
#include "Game/Lara/lara_helpers.h"
|
||||||
|
#include "Game/effects/simple_particle.h"
|
||||||
|
#include "Objects/TR2/Vehicles/speedboat_info.h"
|
||||||
|
#include "Objects/Utils/VehicleHelpers.h"
|
||||||
|
#include "Sound/sound.h"
|
||||||
|
#include "Specific/input.h"
|
||||||
|
#include "Specific/level.h"
|
||||||
|
#include "Specific/setup.h"
|
||||||
|
|
||||||
|
using std::vector;
|
||||||
|
using namespace TEN::Input;
|
||||||
|
|
||||||
|
namespace TEN::Entities::Vehicles
|
||||||
|
{
|
||||||
|
const vector<VehicleMountType> SpeedboatMountTypes =
|
||||||
|
{
|
||||||
|
VehicleMountType::LevelStart,
|
||||||
|
VehicleMountType::Left,
|
||||||
|
VehicleMountType::Right,
|
||||||
|
VehicleMountType::Jump
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr auto SPEEDBOAT_RADIUS = 500;
|
||||||
|
constexpr auto SPEEDBOAT_FRONT = 750;
|
||||||
|
constexpr auto SPEEDBOAT_BACK = -700;
|
||||||
|
constexpr auto SPEEDBOAT_SIDE = 300;
|
||||||
|
constexpr auto SPEEDBOAT_SLIP = 10;
|
||||||
|
constexpr auto SPEEDBOAT_SLIP_SIDE = 30;
|
||||||
|
constexpr auto SPEEDBOAT_MOUNT_DISTANCE = CLICK(2.25f);
|
||||||
|
constexpr auto SPEEDBOAT_DISMOUNT_DISTANCE = SECTOR(1);
|
||||||
|
|
||||||
|
constexpr auto SPEEDBOAT_VELOCITY_ACCEL = 5;
|
||||||
|
constexpr auto SPEEDBOAT_VELOCITY_DECEL = 1;
|
||||||
|
constexpr auto SPEEDBOAT_VELOCITY_BRAKE_DECEL = 5;
|
||||||
|
constexpr auto SPEEDBOAT_REVERSE_VELOCITY_DECEL = 5;
|
||||||
|
|
||||||
|
constexpr auto SPEEDBOAT_VELOCITY_MIN = 20;
|
||||||
|
constexpr auto SPEEDBOAT_SLOW_VELOCITY_MAX = 37;
|
||||||
|
constexpr auto SPEEDBOAT_NORMAL_VELOCITY_MAX = 110;
|
||||||
|
constexpr auto SPEEDBOAT_FAST_VELOCITY_MAX = 185;
|
||||||
|
constexpr auto SPEEDBOAT_REVERSE_VELOCITY_MAX = 20;
|
||||||
|
|
||||||
|
constexpr auto SPEEDBOAT_STEP_HEIGHT_MAX = CLICK(1); // Unused.
|
||||||
|
constexpr auto SPEEDBOAT_SOUND_CEILING = SECTOR(5); // Unused.
|
||||||
|
constexpr auto SPEEDBOAT_TIP = SPEEDBOAT_FRONT + 250;
|
||||||
|
|
||||||
|
#define SPEEDBOAT_TURN_RATE_ACCEL (ANGLE(0.25f) / 2)
|
||||||
|
#define SPEEDBOAT_TURN_RATE_DECEL ANGLE(0.25f)
|
||||||
|
#define SPEEDBOAT_TURN_RATE_MAX ANGLE(4.0f)
|
||||||
|
|
||||||
|
enum SpeedboatState
|
||||||
|
{
|
||||||
|
SPEEDBOAT_STATE_MOUNT = 0,
|
||||||
|
SPEEDBOAT_STATE_IDLE = 1,
|
||||||
|
SPEEDBOAT_STATE_MOVING = 2,
|
||||||
|
SPEEDBOAT_STATE_DISMOUNT_RIGHT = 3,
|
||||||
|
SPEEDBOAT_STATE_DISMOUNT_LEFT = 4,
|
||||||
|
SPEEDBOAT_STATE_HIT = 5,
|
||||||
|
SPEEDBOAT_STATE_FALL = 6,
|
||||||
|
SPEEDBOAT_STATE_TURN_RIGHT = 7,
|
||||||
|
SPEEDBOAT_STATE_DEATH = 8,
|
||||||
|
SPEEDBOAT_STATE_TURN_LEFT = 9
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SpeedboatAnim
|
||||||
|
{
|
||||||
|
SPEEDBOAT_ANIM_MOUNT_LEFT = 0,
|
||||||
|
SPEEDBOAT_ANIM_IDLE = 1, // ?
|
||||||
|
SPEEDBOAT_ANIM_FORWARD = 2, // ?
|
||||||
|
|
||||||
|
SPEEDBOAT_ANIM_DISMOUNT_LEFT = 5,
|
||||||
|
SPEEDBOAT_ANIM_MOUNT_JUMP = 6,
|
||||||
|
SPEEDBOAT_ANIM_DISMOUNT_RIGHT = 7,
|
||||||
|
SPEEDBOAT_ANIM_MOUNT_RIGHT = 8,
|
||||||
|
|
||||||
|
SPEEDBOAT_ANIM_HIT_LEFT = 11,
|
||||||
|
SPEEDBOAT_ANIM_HIT_RIGHT = 12,
|
||||||
|
SPEEDBOAT_ANIM_HIT_FRONT = 13,
|
||||||
|
SPEEDBOAT_ANIM_HIT_BACK = 14,
|
||||||
|
SPEEDBOAT_ANIM_LEAP_START = 15,
|
||||||
|
SPEEDBOAT_ANIM_LEAP = 16,
|
||||||
|
SPEEDBOAT_ANIM_LEAP_END = 17,
|
||||||
|
SPEEDBOAT_ANIM_DEATH = 18
|
||||||
|
};
|
||||||
|
|
||||||
|
SpeedboatInfo* GetSpeedboatInfo(ItemInfo* speedboatItem)
|
||||||
|
{
|
||||||
|
return (SpeedboatInfo*)speedboatItem->Data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitialiseSpeedboat(short itemNumber)
|
||||||
|
{
|
||||||
|
auto* speedboatItem = &g_Level.Items[itemNumber];
|
||||||
|
speedboatItem->Data = SpeedboatInfo();
|
||||||
|
auto* speedboat = GetSpeedboatInfo(speedboatItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpeedboatPlayerCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll)
|
||||||
|
{
|
||||||
|
auto* speedboatItem = &g_Level.Items[itemNumber];
|
||||||
|
auto* lara = GetLaraInfo(laraItem);
|
||||||
|
|
||||||
|
if (laraItem->HitPoints < 0 || lara->Vehicle != NO_ITEM)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto mountType = GetVehicleMountType(speedboatItem, laraItem, coll, SpeedboatMountTypes, SPEEDBOAT_MOUNT_DISTANCE, LARA_HEIGHT);
|
||||||
|
if (mountType == VehicleMountType::None)
|
||||||
|
{
|
||||||
|
coll->Setup.EnableObjectPush = true;
|
||||||
|
ObjectCollision(itemNumber, laraItem, coll);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lara->Vehicle = itemNumber;
|
||||||
|
DoSpeedboatMount(speedboatItem, laraItem,mountType);
|
||||||
|
|
||||||
|
if (g_Level.Items[itemNumber].Status != ITEM_ACTIVE)
|
||||||
|
{
|
||||||
|
AddActiveItem(itemNumber);
|
||||||
|
g_Level.Items[itemNumber].Status = ITEM_ACTIVE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoSpeedboatMount(ItemInfo* speedboatItem, ItemInfo* laraItem, VehicleMountType mountType)
|
||||||
|
{
|
||||||
|
auto* lara = GetLaraInfo(laraItem);
|
||||||
|
|
||||||
|
switch (mountType)
|
||||||
|
{
|
||||||
|
case VehicleMountType::LevelStart:
|
||||||
|
laraItem->Animation.AnimNumber = Objects[ID_SPEEDBOAT_LARA_ANIMS].animIndex + SPEEDBOAT_ANIM_IDLE;
|
||||||
|
laraItem->Animation.ActiveState = SPEEDBOAT_STATE_MOUNT;
|
||||||
|
laraItem->Animation.TargetState = SPEEDBOAT_STATE_MOUNT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VehicleMountType::Left:
|
||||||
|
laraItem->Animation.AnimNumber = Objects[ID_SPEEDBOAT_LARA_ANIMS].animIndex + SPEEDBOAT_ANIM_MOUNT_LEFT;
|
||||||
|
laraItem->Animation.ActiveState = SPEEDBOAT_STATE_MOUNT;
|
||||||
|
laraItem->Animation.TargetState = SPEEDBOAT_STATE_MOUNT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VehicleMountType::Right:
|
||||||
|
laraItem->Animation.AnimNumber = Objects[ID_SPEEDBOAT_LARA_ANIMS].animIndex + SPEEDBOAT_ANIM_MOUNT_RIGHT;
|
||||||
|
laraItem->Animation.ActiveState = SPEEDBOAT_STATE_MOUNT;
|
||||||
|
laraItem->Animation.TargetState = SPEEDBOAT_STATE_MOUNT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
case VehicleMountType::Jump:
|
||||||
|
laraItem->Animation.AnimNumber = Objects[ID_SPEEDBOAT_LARA_ANIMS].animIndex + SPEEDBOAT_ANIM_MOUNT_JUMP;
|
||||||
|
laraItem->Animation.ActiveState = SPEEDBOAT_STATE_MOUNT;
|
||||||
|
laraItem->Animation.TargetState = SPEEDBOAT_STATE_MOUNT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
laraItem->Animation.FrameNumber = g_Level.Anims[laraItem->Animation.AnimNumber].frameBase;
|
||||||
|
|
||||||
|
if (laraItem->RoomNumber != speedboatItem->RoomNumber)
|
||||||
|
ItemNewRoom(lara->ItemNumber, speedboatItem->RoomNumber);
|
||||||
|
|
||||||
|
laraItem->Pose.Position = speedboatItem->Pose.Position;
|
||||||
|
laraItem->Pose.Position.y -= 5;
|
||||||
|
laraItem->Pose.Orientation = Vector3Shrt(0, speedboatItem->Pose.Orientation.y, 0);
|
||||||
|
laraItem->Animation.IsAirborne = false;
|
||||||
|
laraItem->Animation.Velocity = 0;
|
||||||
|
laraItem->Animation.VerticalVelocity = 0;
|
||||||
|
lara->Control.WaterStatus = WaterStatus::Dry;
|
||||||
|
|
||||||
|
AnimateItem(laraItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TestSpeedboatDismount(ItemInfo* speedboatItem, int direction)
|
||||||
|
{
|
||||||
|
short angle;
|
||||||
|
if (direction < 0)
|
||||||
|
angle = speedboatItem->Pose.Orientation.y - ANGLE(90.0f);
|
||||||
|
else
|
||||||
|
angle = speedboatItem->Pose.Orientation.y + ANGLE(90.0f);
|
||||||
|
|
||||||
|
int x = speedboatItem->Pose.Position.x + SPEEDBOAT_DISMOUNT_DISTANCE * phd_sin(angle);
|
||||||
|
int y = speedboatItem->Pose.Position.y;
|
||||||
|
int z = speedboatItem->Pose.Position.z + SPEEDBOAT_DISMOUNT_DISTANCE * phd_cos(angle);
|
||||||
|
auto probe = GetCollision(x, y, z, speedboatItem->RoomNumber);
|
||||||
|
|
||||||
|
if ((probe.Position.Floor - speedboatItem->Pose.Position.y) < -CLICK(2))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (probe.Position.FloorSlope ||
|
||||||
|
probe.Position.Floor == NO_HEIGHT)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((probe.Position.Floor - probe.Position.Ceiling) < LARA_HEIGHT ||
|
||||||
|
(probe.Position.Ceiling - speedboatItem->Pose.Position.y) > -LARA_HEIGHT)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoSpeedboatDismount(ItemInfo* speedboatItem, ItemInfo* laraItem)
|
||||||
|
{
|
||||||
|
auto* lara = GetLaraInfo(laraItem);
|
||||||
|
|
||||||
|
if ((laraItem->Animation.ActiveState == SPEEDBOAT_STATE_DISMOUNT_LEFT ||
|
||||||
|
laraItem->Animation.ActiveState == SPEEDBOAT_STATE_DISMOUNT_RIGHT) &&
|
||||||
|
TestLastFrame(laraItem, laraItem->Animation.AnimNumber))
|
||||||
|
{
|
||||||
|
if (laraItem->Animation.ActiveState == SPEEDBOAT_STATE_DISMOUNT_LEFT)
|
||||||
|
laraItem->Pose.Orientation.y -= ANGLE(90.0f);
|
||||||
|
else if (laraItem->Animation.ActiveState == SPEEDBOAT_STATE_DISMOUNT_RIGHT)
|
||||||
|
laraItem->Pose.Orientation.y += ANGLE(90.0f);
|
||||||
|
|
||||||
|
SetAnimation(laraItem, LA_JUMP_FORWARD);
|
||||||
|
laraItem->Animation.IsAirborne = true;
|
||||||
|
laraItem->Animation.Velocity = 40;
|
||||||
|
laraItem->Animation.VerticalVelocity = -50;
|
||||||
|
laraItem->Pose.Orientation.x = 0;
|
||||||
|
laraItem->Pose.Orientation.z = 0;
|
||||||
|
lara->Vehicle = NO_ITEM;
|
||||||
|
|
||||||
|
int x = laraItem->Pose.Position.x + 360 * phd_sin(laraItem->Pose.Orientation.y);
|
||||||
|
int y = laraItem->Pose.Position.y - 90;
|
||||||
|
int z = laraItem->Pose.Position.z + 360 * phd_cos(laraItem->Pose.Orientation.y);
|
||||||
|
auto probe = GetCollision(x, y, z, laraItem->RoomNumber);
|
||||||
|
|
||||||
|
if (probe.Position.Floor >= (y - CLICK(1)))
|
||||||
|
{
|
||||||
|
laraItem->Pose.Position.x = x;
|
||||||
|
laraItem->Pose.Position.z = z;
|
||||||
|
|
||||||
|
if (probe.RoomNumber != laraItem->RoomNumber)
|
||||||
|
ItemNewRoom(lara->ItemNumber, probe.RoomNumber);
|
||||||
|
}
|
||||||
|
laraItem->Pose.Position.y = y;
|
||||||
|
|
||||||
|
speedboatItem->Animation.AnimNumber = Objects[ID_SPEEDBOAT].animIndex;
|
||||||
|
speedboatItem->Animation.FrameNumber = g_Level.Anims[speedboatItem->Animation.AnimNumber].frameBase;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpeedboatDoBoatShift(ItemInfo* speedboatItem, int itemNumber)
|
||||||
|
{
|
||||||
|
short itemNumber2 = g_Level.Rooms[speedboatItem->RoomNumber].itemNumber;
|
||||||
|
while (itemNumber2 != NO_ITEM)
|
||||||
|
{
|
||||||
|
auto* item = &g_Level.Items[itemNumber2];
|
||||||
|
|
||||||
|
if (item->ObjectNumber == ID_SPEEDBOAT && itemNumber2 != itemNumber && Lara.Vehicle != itemNumber2)
|
||||||
|
{
|
||||||
|
int x = item->Pose.Position.x - speedboatItem->Pose.Position.x;
|
||||||
|
int z = item->Pose.Position.z - speedboatItem->Pose.Position.z;
|
||||||
|
|
||||||
|
int distance = pow(x, 2) + pow(z, 2);
|
||||||
|
int radius = pow(SPEEDBOAT_RADIUS * 2, 2);
|
||||||
|
if (distance < radius)
|
||||||
|
{
|
||||||
|
speedboatItem->Pose.Position.x = item->Pose.Position.x - x * radius / distance;
|
||||||
|
speedboatItem->Pose.Position.z = item->Pose.Position.z - z * radius / distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: mine and gondola
|
||||||
|
|
||||||
|
itemNumber2 = item->NextItem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
short SpeedboatDoShift(ItemInfo* speedboatItem, Vector3Int* pos, Vector3Int* old)
|
||||||
|
{
|
||||||
|
int x = pos->x / SECTOR(1);
|
||||||
|
int z = pos->z / SECTOR(1);
|
||||||
|
|
||||||
|
int xOld = old->x / SECTOR(1);
|
||||||
|
int zOld = old->z / SECTOR(1);
|
||||||
|
|
||||||
|
int shiftX = pos->x & (SECTOR(1) - 1);
|
||||||
|
int shiftZ = pos->z & (SECTOR(1) - 1);
|
||||||
|
|
||||||
|
if (x == xOld)
|
||||||
|
{
|
||||||
|
if (z == zOld)
|
||||||
|
{
|
||||||
|
speedboatItem->Pose.Position.z += (old->z - pos->z);
|
||||||
|
speedboatItem->Pose.Position.x += (old->x - pos->x);
|
||||||
|
}
|
||||||
|
else if (z > zOld)
|
||||||
|
{
|
||||||
|
speedboatItem->Pose.Position.z -= shiftZ + 1;
|
||||||
|
return (pos->x - speedboatItem->Pose.Position.x);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
speedboatItem->Pose.Position.z += SECTOR(1) - shiftZ;
|
||||||
|
return (speedboatItem->Pose.Position.x - pos->x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (z == zOld)
|
||||||
|
{
|
||||||
|
if (x > xOld)
|
||||||
|
{
|
||||||
|
speedboatItem->Pose.Position.x -= shiftX + 1;
|
||||||
|
return (speedboatItem->Pose.Position.z - pos->z);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
speedboatItem->Pose.Position.x += SECTOR(1) - shiftX;
|
||||||
|
return (pos->z - speedboatItem->Pose.Position.z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
x = 0;
|
||||||
|
z = 0;
|
||||||
|
|
||||||
|
auto probe = GetCollision(old->x, pos->y, pos->z, speedboatItem->RoomNumber);
|
||||||
|
if (probe.Position.Floor < (old->y - CLICK(1)))
|
||||||
|
{
|
||||||
|
if (pos->z > old->z)
|
||||||
|
z = -shiftZ - 1;
|
||||||
|
else
|
||||||
|
z = SECTOR(1) - shiftZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
probe = GetCollision(pos->x, pos->y, old->z, speedboatItem->RoomNumber);
|
||||||
|
if (probe.Position.Floor < (old->y - CLICK(1)))
|
||||||
|
{
|
||||||
|
if (pos->x > old->x)
|
||||||
|
x = -shiftX - 1;
|
||||||
|
else
|
||||||
|
x = SECTOR(1) - shiftX;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x && z)
|
||||||
|
{
|
||||||
|
speedboatItem->Pose.Position.z += z;
|
||||||
|
speedboatItem->Pose.Position.x += x;
|
||||||
|
}
|
||||||
|
else if (z)
|
||||||
|
{
|
||||||
|
speedboatItem->Pose.Position.z += z;
|
||||||
|
if (z > 0)
|
||||||
|
return (speedboatItem->Pose.Position.x - pos->x);
|
||||||
|
else
|
||||||
|
return (pos->x - speedboatItem->Pose.Position.x);
|
||||||
|
}
|
||||||
|
else if (x)
|
||||||
|
{
|
||||||
|
speedboatItem->Pose.Position.x += x;
|
||||||
|
if (x > 0)
|
||||||
|
return (pos->z - speedboatItem->Pose.Position.z);
|
||||||
|
else
|
||||||
|
return (speedboatItem->Pose.Position.z - pos->z);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
speedboatItem->Pose.Position.z += (old->z - pos->z);
|
||||||
|
speedboatItem->Pose.Position.x += (old->x - pos->x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetSpeedboatHitAnim(ItemInfo* speedboatItem, Vector3Int* moved)
|
||||||
|
{
|
||||||
|
moved->x = speedboatItem->Pose.Position.x - moved->x;
|
||||||
|
moved->z = speedboatItem->Pose.Position.z - moved->z;
|
||||||
|
|
||||||
|
if (moved->x || moved->z)
|
||||||
|
{
|
||||||
|
float sinY = phd_sin(speedboatItem->Pose.Orientation.y);
|
||||||
|
float cosY = phd_cos(speedboatItem->Pose.Orientation.y);
|
||||||
|
|
||||||
|
int front = (moved->z * cosY) + (moved->x * sinY);
|
||||||
|
int side = (moved->z * -sinY) + (moved->x * cosY);
|
||||||
|
|
||||||
|
if (abs(front) > abs(side))
|
||||||
|
{
|
||||||
|
if (front > 0)
|
||||||
|
return SPEEDBOAT_ANIM_HIT_BACK;
|
||||||
|
else
|
||||||
|
return SPEEDBOAT_ANIM_HIT_FRONT;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (side > 0)
|
||||||
|
return SPEEDBOAT_ANIM_HIT_LEFT;
|
||||||
|
else
|
||||||
|
return SPEEDBOAT_ANIM_HIT_RIGHT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DoSpeedboatDynamics(int height, int verticalVelocity, int* y)
|
||||||
|
{
|
||||||
|
if (height > *y)
|
||||||
|
{
|
||||||
|
*y += verticalVelocity;
|
||||||
|
if (*y > height)
|
||||||
|
{
|
||||||
|
*y = height;
|
||||||
|
verticalVelocity = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
verticalVelocity += GRAVITY;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
verticalVelocity += ((height - *y - verticalVelocity) / 8);
|
||||||
|
if (verticalVelocity < -SPEEDBOAT_REVERSE_VELOCITY_MAX)
|
||||||
|
verticalVelocity = -SPEEDBOAT_REVERSE_VELOCITY_MAX;
|
||||||
|
|
||||||
|
if (*y > height)
|
||||||
|
*y = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
return verticalVelocity;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SpeedboatDynamics(short itemNumber, ItemInfo* laraItem)
|
||||||
|
{
|
||||||
|
auto* speedboatItem = &g_Level.Items[itemNumber];
|
||||||
|
auto* speedboat = GetSpeedboatInfo(speedboatItem);
|
||||||
|
auto* lara = GetLaraInfo(laraItem);
|
||||||
|
|
||||||
|
speedboatItem->Pose.Orientation.z -= speedboat->LeanAngle;
|
||||||
|
|
||||||
|
Vector3Int old, frontLeftOld, frontRightOld, backLeftOld, backRightOld, frontOld;
|
||||||
|
int heightFrontLeftOld = GetVehicleWaterHeight(speedboatItem, SPEEDBOAT_FRONT, -SPEEDBOAT_SIDE, true, &frontLeftOld);
|
||||||
|
int heightFrontRightOld = GetVehicleWaterHeight(speedboatItem, SPEEDBOAT_FRONT, SPEEDBOAT_SIDE, true, &frontRightOld);
|
||||||
|
int heightBackLeftOld = GetVehicleWaterHeight(speedboatItem, -SPEEDBOAT_FRONT, -SPEEDBOAT_SIDE, true, &backLeftOld);
|
||||||
|
int heightBackRightOld = GetVehicleWaterHeight(speedboatItem, -SPEEDBOAT_FRONT, SPEEDBOAT_SIDE, true, &backRightOld);
|
||||||
|
int heightFrontOld = GetVehicleWaterHeight(speedboatItem, SPEEDBOAT_TIP, 0, true, &frontOld);
|
||||||
|
|
||||||
|
old.x = speedboatItem->Pose.Position.x;
|
||||||
|
old.y = speedboatItem->Pose.Position.y;
|
||||||
|
old.z = speedboatItem->Pose.Position.z;
|
||||||
|
|
||||||
|
speedboatItem->Pose.Orientation.y += speedboat->TurnRate + speedboat->ExtraRotation;
|
||||||
|
speedboat->LeanAngle = speedboat->TurnRate * 6;
|
||||||
|
|
||||||
|
speedboatItem->Pose.Position.x += speedboatItem->Animation.Velocity * phd_sin(speedboatItem->Pose.Orientation.y);
|
||||||
|
speedboatItem->Pose.Position.z += speedboatItem->Animation.Velocity * phd_cos(speedboatItem->Pose.Orientation.y);
|
||||||
|
|
||||||
|
int slip = SPEEDBOAT_SLIP_SIDE * phd_sin(speedboatItem->Pose.Orientation.z);
|
||||||
|
if (!slip && speedboatItem->Pose.Orientation.z)
|
||||||
|
slip = (speedboatItem->Pose.Orientation.z > 0) ? 1 : -1;
|
||||||
|
speedboatItem->Pose.Position.x += slip * phd_sin(speedboatItem->Pose.Orientation.y);
|
||||||
|
speedboatItem->Pose.Position.z -= slip * phd_cos(speedboatItem->Pose.Orientation.y);
|
||||||
|
|
||||||
|
slip = SPEEDBOAT_SLIP * phd_sin(speedboatItem->Pose.Orientation.x);
|
||||||
|
if (!slip && speedboatItem->Pose.Orientation.x)
|
||||||
|
slip = (speedboatItem->Pose.Orientation.x > 0) ? 1 : -1;
|
||||||
|
speedboatItem->Pose.Position.x -= slip * phd_sin(speedboatItem->Pose.Orientation.y);
|
||||||
|
speedboatItem->Pose.Position.z -= slip * phd_cos(speedboatItem->Pose.Orientation.y);
|
||||||
|
|
||||||
|
auto moved = Vector3Int(speedboatItem->Pose.Position.x, 0, speedboatItem->Pose.Position.z);
|
||||||
|
|
||||||
|
SpeedboatDoBoatShift(speedboatItem, itemNumber);
|
||||||
|
|
||||||
|
Vector3Int fl, fr, br, bl, f;
|
||||||
|
short rotation = 0;
|
||||||
|
auto heightBackLeft = GetVehicleWaterHeight(speedboatItem, -SPEEDBOAT_FRONT, -SPEEDBOAT_SIDE, false, &bl);
|
||||||
|
if (heightBackLeft < (backLeftOld.y - CLICK(0.5f)))
|
||||||
|
rotation = SpeedboatDoShift(speedboatItem, &bl, &backLeftOld);
|
||||||
|
|
||||||
|
auto heightBackRight = GetVehicleWaterHeight(speedboatItem, -SPEEDBOAT_FRONT, SPEEDBOAT_SIDE, false, &br);
|
||||||
|
if (heightBackRight < (backRightOld.y - CLICK(0.5f)))
|
||||||
|
rotation += SpeedboatDoShift(speedboatItem, &br, &backRightOld);
|
||||||
|
|
||||||
|
auto heightFrontLeft = GetVehicleWaterHeight(speedboatItem, SPEEDBOAT_FRONT, -SPEEDBOAT_SIDE, false, &fl);
|
||||||
|
if (heightFrontLeft < (frontLeftOld.y - CLICK(0.5f)))
|
||||||
|
rotation += SpeedboatDoShift(speedboatItem, &fl, &frontLeftOld);
|
||||||
|
|
||||||
|
auto heightFrontRight = GetVehicleWaterHeight(speedboatItem, SPEEDBOAT_FRONT, SPEEDBOAT_SIDE, false, &fr);
|
||||||
|
if (heightFrontRight < (frontRightOld.y - CLICK(0.5f)))
|
||||||
|
rotation += SpeedboatDoShift(speedboatItem, &fr, &frontRightOld);
|
||||||
|
|
||||||
|
int heightFront = 0;
|
||||||
|
if (!slip)
|
||||||
|
{
|
||||||
|
heightFront = GetVehicleWaterHeight(speedboatItem, SPEEDBOAT_TIP, 0, false, &f);
|
||||||
|
if (heightFront < (frontOld.y - CLICK(0.5f)))
|
||||||
|
SpeedboatDoShift(speedboatItem, &f, &frontOld);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto probe = GetCollision(speedboatItem);
|
||||||
|
auto height = GetWaterHeight(speedboatItem->Pose.Position.x, speedboatItem->Pose.Position.y - 5, speedboatItem->Pose.Position.z, probe.RoomNumber);
|
||||||
|
|
||||||
|
if (height == NO_HEIGHT)
|
||||||
|
height = GetFloorHeight(probe.Block, speedboatItem->Pose.Position.x, speedboatItem->Pose.Position.y - 5, speedboatItem->Pose.Position.z);
|
||||||
|
|
||||||
|
if (height < (speedboatItem->Pose.Position.y - CLICK(0.5f)))
|
||||||
|
SpeedboatDoShift(speedboatItem, (Vector3Int*)&speedboatItem->Pose, &old);
|
||||||
|
|
||||||
|
speedboat->ExtraRotation = rotation;
|
||||||
|
|
||||||
|
DoVehicleCollision(speedboatItem, SPEEDBOAT_RADIUS);
|
||||||
|
|
||||||
|
auto collide = GetSpeedboatHitAnim(speedboatItem, &moved);
|
||||||
|
|
||||||
|
int newVelocity = 0;
|
||||||
|
if (slip || collide)
|
||||||
|
{
|
||||||
|
newVelocity = (speedboatItem->Pose.Position.z - old.z) * phd_cos(speedboatItem->Pose.Orientation.y) + (speedboatItem->Pose.Position.x - old.x) * phd_sin(speedboatItem->Pose.Orientation.y);
|
||||||
|
|
||||||
|
if (lara->Vehicle == itemNumber && speedboatItem->Animation.Velocity > SPEEDBOAT_NORMAL_VELOCITY_MAX + SPEEDBOAT_VELOCITY_ACCEL && newVelocity < speedboatItem->Animation.Velocity - 10)
|
||||||
|
{
|
||||||
|
DoDamage(laraItem, speedboatItem->Animation.Velocity);
|
||||||
|
SoundEffect(SFX_TR4_LARA_INJURY, &laraItem->Pose);
|
||||||
|
newVelocity /= 2;
|
||||||
|
speedboatItem->Animation.Velocity /= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slip)
|
||||||
|
{
|
||||||
|
if (speedboatItem->Animation.Velocity <= SPEEDBOAT_NORMAL_VELOCITY_MAX + 10)
|
||||||
|
speedboatItem->Animation.Velocity = newVelocity;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (speedboatItem->Animation.Velocity > 0 && newVelocity < speedboatItem->Animation.Velocity)
|
||||||
|
speedboatItem->Animation.Velocity = newVelocity;
|
||||||
|
else if (speedboatItem->Animation.Velocity < 0 && newVelocity > speedboatItem->Animation.Velocity)
|
||||||
|
speedboatItem->Animation.Velocity = newVelocity;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (speedboatItem->Animation.Velocity < -SPEEDBOAT_REVERSE_VELOCITY_MAX)
|
||||||
|
speedboatItem->Animation.Velocity = -SPEEDBOAT_REVERSE_VELOCITY_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
return collide;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SpeedboatUserControl(ItemInfo* speedboatItem, ItemInfo* laraItem)
|
||||||
|
{
|
||||||
|
auto* speedboat = GetSpeedboatInfo(speedboatItem);
|
||||||
|
|
||||||
|
bool noTurn = true;
|
||||||
|
int maxVelocity;
|
||||||
|
|
||||||
|
if (speedboatItem->Pose.Position.y >= speedboat->Water - CLICK(0.5f) && speedboat->Water != NO_HEIGHT)
|
||||||
|
{
|
||||||
|
if (!(TrInput & VEHICLE_IN_DISMOUNT) && !(TrInput & IN_LOOK) ||
|
||||||
|
speedboatItem->Animation.Velocity)
|
||||||
|
{
|
||||||
|
if (TrInput & VEHICLE_IN_LEFT && !(TrInput & VEHICLE_IN_REVERSE) ||
|
||||||
|
TrInput & VEHICLE_IN_RIGHT && TrInput & VEHICLE_IN_REVERSE)
|
||||||
|
{
|
||||||
|
if (speedboat->TurnRate > 0)
|
||||||
|
speedboat->TurnRate -= SPEEDBOAT_TURN_RATE_DECEL;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
speedboat->TurnRate -= SPEEDBOAT_TURN_RATE_ACCEL;
|
||||||
|
if (speedboat->TurnRate < -SPEEDBOAT_TURN_RATE_MAX)
|
||||||
|
speedboat->TurnRate = -SPEEDBOAT_TURN_RATE_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
noTurn = false;
|
||||||
|
}
|
||||||
|
else if (TrInput & VEHICLE_IN_RIGHT && !(TrInput & VEHICLE_IN_REVERSE) ||
|
||||||
|
TrInput & VEHICLE_IN_LEFT && TrInput & VEHICLE_IN_REVERSE)
|
||||||
|
{
|
||||||
|
if (speedboat->TurnRate < 0)
|
||||||
|
speedboat->TurnRate += SPEEDBOAT_TURN_RATE_DECEL;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
speedboat->TurnRate += SPEEDBOAT_TURN_RATE_ACCEL;
|
||||||
|
if (speedboat->TurnRate > SPEEDBOAT_TURN_RATE_MAX)
|
||||||
|
speedboat->TurnRate = SPEEDBOAT_TURN_RATE_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
noTurn = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TrInput & VEHICLE_IN_REVERSE)
|
||||||
|
{
|
||||||
|
if (speedboatItem->Animation.Velocity > 0)
|
||||||
|
speedboatItem->Animation.Velocity -= SPEEDBOAT_VELOCITY_BRAKE_DECEL;
|
||||||
|
else if (speedboatItem->Animation.Velocity > -SPEEDBOAT_REVERSE_VELOCITY_MAX)
|
||||||
|
speedboatItem->Animation.Velocity -= SPEEDBOAT_REVERSE_VELOCITY_DECEL;
|
||||||
|
}
|
||||||
|
else if (TrInput & VEHICLE_IN_ACCELERATE)
|
||||||
|
{
|
||||||
|
if (TrInput & VEHICLE_IN_SPEED)
|
||||||
|
maxVelocity = SPEEDBOAT_FAST_VELOCITY_MAX;
|
||||||
|
else
|
||||||
|
maxVelocity = (TrInput & VEHICLE_IN_SLOW) ? SPEEDBOAT_SLOW_VELOCITY_MAX : SPEEDBOAT_NORMAL_VELOCITY_MAX;
|
||||||
|
|
||||||
|
if (speedboatItem->Animation.Velocity < maxVelocity)
|
||||||
|
speedboatItem->Animation.Velocity += (SPEEDBOAT_VELOCITY_ACCEL / 2) + (SPEEDBOAT_VELOCITY_ACCEL * (speedboatItem->Animation.Velocity / (maxVelocity * 2)));
|
||||||
|
else if (speedboatItem->Animation.Velocity > (maxVelocity + SPEEDBOAT_VELOCITY_DECEL))
|
||||||
|
speedboatItem->Animation.Velocity -= SPEEDBOAT_VELOCITY_DECEL;
|
||||||
|
}
|
||||||
|
else if (TrInput & (VEHICLE_IN_LEFT | VEHICLE_IN_RIGHT) &&
|
||||||
|
speedboatItem->Animation.Velocity >= 0 &&
|
||||||
|
speedboatItem->Animation.Velocity < SPEEDBOAT_VELOCITY_MIN)
|
||||||
|
{
|
||||||
|
if (!(TrInput & VEHICLE_IN_DISMOUNT) &&
|
||||||
|
speedboatItem->Animation.Velocity == 0)
|
||||||
|
speedboatItem->Animation.Velocity = SPEEDBOAT_VELOCITY_MIN;
|
||||||
|
}
|
||||||
|
else if (speedboatItem->Animation.Velocity > SPEEDBOAT_VELOCITY_DECEL)
|
||||||
|
speedboatItem->Animation.Velocity -= SPEEDBOAT_VELOCITY_DECEL;
|
||||||
|
else
|
||||||
|
speedboatItem->Animation.Velocity = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (TrInput & (VEHICLE_IN_LEFT | VEHICLE_IN_RIGHT) &&
|
||||||
|
speedboatItem->Animation.Velocity >= 0 &&
|
||||||
|
speedboatItem->Animation.Velocity < SPEEDBOAT_VELOCITY_MIN)
|
||||||
|
{
|
||||||
|
if (speedboatItem->Animation.Velocity == 0 && !(TrInput & VEHICLE_IN_DISMOUNT))
|
||||||
|
speedboatItem->Animation.Velocity = SPEEDBOAT_VELOCITY_MIN;
|
||||||
|
}
|
||||||
|
else if (speedboatItem->Animation.Velocity > SPEEDBOAT_VELOCITY_DECEL)
|
||||||
|
speedboatItem->Animation.Velocity -= SPEEDBOAT_VELOCITY_DECEL;
|
||||||
|
else
|
||||||
|
speedboatItem->Animation.Velocity = 0;
|
||||||
|
|
||||||
|
if (TrInput & IN_LOOK && speedboatItem->Animation.Velocity == 0)
|
||||||
|
LookUpDown(laraItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return noTurn;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpeedboatAnimation(ItemInfo* speedboatItem, ItemInfo* laraItem, int collide)
|
||||||
|
{
|
||||||
|
auto* speedboat = GetSpeedboatInfo(speedboatItem);
|
||||||
|
|
||||||
|
if (laraItem->HitPoints <= 0)
|
||||||
|
{
|
||||||
|
if (laraItem->Animation.ActiveState != SPEEDBOAT_STATE_DEATH)
|
||||||
|
{
|
||||||
|
laraItem->Animation.AnimNumber = Objects[ID_SPEEDBOAT_LARA_ANIMS].animIndex + SPEEDBOAT_ANIM_DEATH;
|
||||||
|
laraItem->Animation.FrameNumber = g_Level.Anims[laraItem->Animation.AnimNumber].frameBase;
|
||||||
|
laraItem->Animation.ActiveState = laraItem->Animation.TargetState = SPEEDBOAT_STATE_DEATH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (speedboatItem->Pose.Position.y < speedboat->Water - CLICK(0.5f) && speedboatItem->Animation.VerticalVelocity > 0)
|
||||||
|
{
|
||||||
|
if (laraItem->Animation.ActiveState != SPEEDBOAT_STATE_FALL)
|
||||||
|
{
|
||||||
|
laraItem->Animation.AnimNumber = Objects[ID_SPEEDBOAT_LARA_ANIMS].animIndex + SPEEDBOAT_ANIM_LEAP_START;
|
||||||
|
laraItem->Animation.FrameNumber = g_Level.Anims[laraItem->Animation.AnimNumber].frameBase;
|
||||||
|
laraItem->Animation.ActiveState = laraItem->Animation.TargetState = SPEEDBOAT_STATE_FALL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (collide)
|
||||||
|
{
|
||||||
|
if (laraItem->Animation.ActiveState != SPEEDBOAT_STATE_HIT)
|
||||||
|
{
|
||||||
|
laraItem->Animation.AnimNumber = Objects[ID_SPEEDBOAT_LARA_ANIMS].animIndex + collide;
|
||||||
|
laraItem->Animation.FrameNumber = g_Level.Anims[laraItem->Animation.AnimNumber].frameBase;
|
||||||
|
laraItem->Animation.ActiveState = laraItem->Animation.TargetState = SPEEDBOAT_STATE_HIT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (laraItem->Animation.ActiveState)
|
||||||
|
{
|
||||||
|
case SPEEDBOAT_STATE_IDLE:
|
||||||
|
if (TrInput & VEHICLE_IN_DISMOUNT)
|
||||||
|
{
|
||||||
|
if (speedboatItem->Animation.Velocity == 0)
|
||||||
|
{
|
||||||
|
if (TrInput & VEHICLE_IN_RIGHT && TestSpeedboatDismount(speedboatItem, speedboatItem->Pose.Orientation.y + ANGLE(90.0f)))
|
||||||
|
laraItem->Animation.TargetState = SPEEDBOAT_STATE_DISMOUNT_RIGHT;
|
||||||
|
else if (TrInput & VEHICLE_IN_LEFT && TestSpeedboatDismount(speedboatItem, speedboatItem->Pose.Orientation.y - ANGLE(90.0f)))
|
||||||
|
laraItem->Animation.TargetState = SPEEDBOAT_STATE_DISMOUNT_LEFT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (speedboatItem->Animation.Velocity > 0)
|
||||||
|
laraItem->Animation.TargetState = SPEEDBOAT_STATE_MOVING;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SPEEDBOAT_STATE_MOVING:
|
||||||
|
if (TrInput & VEHICLE_IN_DISMOUNT)
|
||||||
|
{
|
||||||
|
if (TrInput & VEHICLE_IN_RIGHT)
|
||||||
|
laraItem->Animation.TargetState = SPEEDBOAT_STATE_DISMOUNT_RIGHT;
|
||||||
|
else if (TrInput & VEHICLE_IN_RIGHT)
|
||||||
|
laraItem->Animation.TargetState = SPEEDBOAT_STATE_DISMOUNT_LEFT;
|
||||||
|
}
|
||||||
|
else if (speedboatItem->Animation.Velocity <= 0)
|
||||||
|
laraItem->Animation.TargetState = SPEEDBOAT_STATE_IDLE;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SPEEDBOAT_STATE_FALL:
|
||||||
|
laraItem->Animation.TargetState = SPEEDBOAT_STATE_MOVING;
|
||||||
|
break;
|
||||||
|
|
||||||
|
//case SPEEDBOAT_TURN_RATE_ACCELR:
|
||||||
|
if (speedboatItem->Animation.Velocity <= 0)
|
||||||
|
laraItem->Animation.TargetState = SPEEDBOAT_STATE_IDLE;
|
||||||
|
else if (!(TrInput & VEHICLE_IN_RIGHT))
|
||||||
|
laraItem->Animation.TargetState = SPEEDBOAT_STATE_MOVING;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SPEEDBOAT_STATE_TURN_LEFT:
|
||||||
|
if (speedboatItem->Animation.Velocity <= 0)
|
||||||
|
laraItem->Animation.TargetState = SPEEDBOAT_STATE_IDLE;
|
||||||
|
else if (!(TrInput & VEHICLE_IN_LEFT))
|
||||||
|
laraItem->Animation.TargetState = SPEEDBOAT_STATE_MOVING;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpeedboatSplash(ItemInfo* speedboatItem, long verticalVelocity, long water)
|
||||||
|
{
|
||||||
|
//OLD SPLASH
|
||||||
|
/*
|
||||||
|
splash_setup.x = speedboatItem->pos.x_pos;
|
||||||
|
splash_setup.y = water;
|
||||||
|
splash_setup.z = item->pos.z_pos;
|
||||||
|
splash_setup.InnerXZoff = 16 << 2;
|
||||||
|
splash_setup.InnerXZsize = 12 << 2;
|
||||||
|
splash_setup.InnerYsize = -96 << 2;
|
||||||
|
splash_setup.InnerXZvel = 0xa0;
|
||||||
|
splash_setup.InnerYvel = -fallspeed << 7;
|
||||||
|
splash_setup.InnerGravity = 0x80;
|
||||||
|
splash_setup.InnerFriction = 7;
|
||||||
|
splash_setup.MiddleXZoff = 24 << 2;
|
||||||
|
splash_setup.MiddleXZsize = 24 << 2;
|
||||||
|
splash_setup.MiddleYsize = -64 << 2;
|
||||||
|
splash_setup.MiddleXZvel = 0xe0;
|
||||||
|
splash_setup.MiddleYvel = -fallspeed << 6;
|
||||||
|
splash_setup.MiddleGravity = 0x48;
|
||||||
|
splash_setup.MiddleFriction = 8;
|
||||||
|
splash_setup.OuterXZoff = 32 << 2;
|
||||||
|
splash_setup.OuterXZsize = 32 << 2;
|
||||||
|
splash_setup.OuterXZvel = 0x110;
|
||||||
|
splash_setup.OuterFriction = 9;
|
||||||
|
SetupSplash(&splash_setup);
|
||||||
|
SplashCount = 16;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpeedboatControl(short itemNumber)
|
||||||
|
{
|
||||||
|
auto* speedboatItem = &g_Level.Items[itemNumber];
|
||||||
|
auto* speedboat = GetSpeedboatInfo(speedboatItem);
|
||||||
|
auto* laraItem = LaraItem;
|
||||||
|
auto* lara = GetLaraInfo(laraItem);
|
||||||
|
|
||||||
|
int collide = SpeedboatDynamics(itemNumber, laraItem);
|
||||||
|
|
||||||
|
Vector3Int frontLeft, frontRight;
|
||||||
|
int heightFrontLeft = GetVehicleWaterHeight(speedboatItem, SPEEDBOAT_FRONT, -SPEEDBOAT_SIDE, true, &frontLeft);
|
||||||
|
int heightFrontRight = GetVehicleWaterHeight(speedboatItem, SPEEDBOAT_FRONT, SPEEDBOAT_SIDE, true, &frontRight);
|
||||||
|
|
||||||
|
auto probe = GetCollision(speedboatItem);
|
||||||
|
|
||||||
|
if (lara->Vehicle == itemNumber)
|
||||||
|
{
|
||||||
|
TestTriggers(speedboatItem, true);
|
||||||
|
TestTriggers(speedboatItem, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto water = GetWaterHeight(speedboatItem->Pose.Position.x, speedboatItem->Pose.Position.y, speedboatItem->Pose.Position.z, probe.RoomNumber);
|
||||||
|
speedboat->Water = water;
|
||||||
|
|
||||||
|
bool noTurn = true;
|
||||||
|
bool drive = false;
|
||||||
|
bool idle = !speedboatItem->Animation.Velocity;
|
||||||
|
|
||||||
|
if (lara->Vehicle == itemNumber && laraItem->HitPoints > 0)
|
||||||
|
{
|
||||||
|
switch (laraItem->Animation.ActiveState)
|
||||||
|
{
|
||||||
|
case SPEEDBOAT_STATE_MOUNT:
|
||||||
|
case SPEEDBOAT_STATE_DISMOUNT_RIGHT:
|
||||||
|
case SPEEDBOAT_STATE_DISMOUNT_LEFT:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
drive = true;
|
||||||
|
noTurn = SpeedboatUserControl(speedboatItem, laraItem);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (speedboatItem->Animation.Velocity > SPEEDBOAT_VELOCITY_DECEL)
|
||||||
|
speedboatItem->Animation.Velocity -= SPEEDBOAT_VELOCITY_DECEL;
|
||||||
|
else
|
||||||
|
speedboatItem->Animation.Velocity = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (noTurn)
|
||||||
|
{
|
||||||
|
if (speedboat->TurnRate < -SPEEDBOAT_TURN_RATE_DECEL)
|
||||||
|
speedboat->TurnRate += SPEEDBOAT_TURN_RATE_DECEL;
|
||||||
|
else if (speedboat->TurnRate > SPEEDBOAT_TURN_RATE_DECEL)
|
||||||
|
speedboat->TurnRate -= SPEEDBOAT_TURN_RATE_DECEL;
|
||||||
|
else
|
||||||
|
speedboat->TurnRate = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
speedboatItem->Floor = probe.Position.Floor - 5;
|
||||||
|
if (speedboat->Water == NO_HEIGHT)
|
||||||
|
speedboat->Water = probe.Position.Floor;
|
||||||
|
else
|
||||||
|
speedboat->Water -= 5;
|
||||||
|
|
||||||
|
speedboat->LeftVerticalVelocity = DoSpeedboatDynamics(heightFrontLeft, speedboat->LeftVerticalVelocity, (int*)&frontLeft.y);
|
||||||
|
speedboat->RightVerticalVelocity = DoSpeedboatDynamics(heightFrontRight, speedboat->RightVerticalVelocity, (int*)&frontRight.y);
|
||||||
|
speedboatItem->Animation.VerticalVelocity = DoSpeedboatDynamics(speedboat->Water, speedboatItem->Animation.VerticalVelocity, (int*)&speedboatItem->Pose.Position.y);
|
||||||
|
|
||||||
|
auto ofs = speedboatItem->Animation.VerticalVelocity;
|
||||||
|
if (ofs - speedboatItem->Animation.VerticalVelocity > 32 && speedboatItem->Animation.VerticalVelocity == 0 && water != NO_HEIGHT)
|
||||||
|
SpeedboatSplash(speedboatItem, ofs - speedboatItem->Animation.VerticalVelocity, water);
|
||||||
|
|
||||||
|
probe.Position.Floor = (frontLeft.y + frontRight.y);
|
||||||
|
if (probe.Position.Floor < 0)
|
||||||
|
probe.Position.Floor = -(abs(probe.Position.Floor) / 2);
|
||||||
|
else
|
||||||
|
probe.Position.Floor /= 2;
|
||||||
|
|
||||||
|
short xRot = phd_atan(SPEEDBOAT_FRONT, speedboatItem->Pose.Position.y - probe.Position.Floor);
|
||||||
|
short zRot = phd_atan(SPEEDBOAT_SIDE, probe.Position.Floor - frontLeft.y);
|
||||||
|
|
||||||
|
speedboatItem->Pose.Orientation.x += ((xRot - speedboatItem->Pose.Orientation.x) / 2);
|
||||||
|
speedboatItem->Pose.Orientation.z += ((zRot - speedboatItem->Pose.Orientation.z) / 2);
|
||||||
|
|
||||||
|
if (!xRot && abs(speedboatItem->Pose.Orientation.x) < 4)
|
||||||
|
speedboatItem->Pose.Orientation.x = 0;
|
||||||
|
if (!zRot && abs(speedboatItem->Pose.Orientation.z) < 4)
|
||||||
|
speedboatItem->Pose.Orientation.z = 0;
|
||||||
|
|
||||||
|
if (lara->Vehicle == itemNumber)
|
||||||
|
{
|
||||||
|
SpeedboatAnimation(speedboatItem, laraItem, collide);
|
||||||
|
|
||||||
|
if (probe.RoomNumber != speedboatItem->RoomNumber)
|
||||||
|
{
|
||||||
|
ItemNewRoom(lara->Vehicle, probe.RoomNumber);
|
||||||
|
ItemNewRoom(lara->ItemNumber, probe.RoomNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
laraItem->Pose = speedboatItem->Pose;
|
||||||
|
speedboatItem->Pose.Orientation.z += speedboat->LeanAngle;
|
||||||
|
|
||||||
|
AnimateItem(laraItem);
|
||||||
|
|
||||||
|
if (laraItem->HitPoints > 0)
|
||||||
|
{
|
||||||
|
speedboatItem->Animation.AnimNumber = Objects[ID_SPEEDBOAT].animIndex + (laraItem->Animation.AnimNumber - Objects[ID_SPEEDBOAT_LARA_ANIMS].animIndex);
|
||||||
|
speedboatItem->Animation.FrameNumber = g_Level.Anims[speedboatItem->Animation.AnimNumber].frameBase + (laraItem->Animation.FrameNumber - g_Level.Anims[laraItem->Animation.AnimNumber].frameBase);
|
||||||
|
}
|
||||||
|
|
||||||
|
Camera.targetElevation = -ANGLE(20.0f);
|
||||||
|
Camera.targetDistance = SECTOR(2);
|
||||||
|
|
||||||
|
auto pitch = speedboatItem->Animation.Velocity;
|
||||||
|
speedboat->Pitch += (pitch - speedboat->Pitch) / 4;
|
||||||
|
|
||||||
|
if (drive)
|
||||||
|
{
|
||||||
|
bool accelerating = idle && abs(speedboatItem->Animation.Velocity) > 4;
|
||||||
|
bool moving = (abs(speedboatItem->Animation.Velocity) > 8 || speedboat->TurnRate);
|
||||||
|
int fx = accelerating ? SFX_TR2_VEHICLE_SPEEDBOAT_ACCELERATE : (moving ? SFX_TR2_VEHICLE_SPEEDBOAT_MOVING : SFX_TR2_VEHICLE_SPEEDBOAT_IDLE);
|
||||||
|
float pitch = idle ? 1.0f : 1.0f + speedboat->Pitch / (float)SPEEDBOAT_NORMAL_VELOCITY_MAX / 4.0f;
|
||||||
|
SoundEffect(fx, &speedboatItem->Pose, SoundEnvironment::Land, pitch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (probe.RoomNumber != speedboatItem->RoomNumber)
|
||||||
|
ItemNewRoom(itemNumber, probe.RoomNumber);
|
||||||
|
|
||||||
|
speedboatItem->Pose.Orientation.z += speedboat->LeanAngle;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (speedboatItem->Animation.Velocity && (water - 5) == speedboatItem->Pose.Position.y)
|
||||||
|
{
|
||||||
|
auto room = probe.Block->RoomBelow(speedboatItem->Pose.Position.x, speedboatItem->Pose.Position.z).value_or(NO_ROOM);
|
||||||
|
if (room != NO_ROOM && (TestEnvironment(RoomEnvFlags::ENV_FLAG_WATER, room) || TestEnvironment(RoomEnvFlags::ENV_FLAG_SWAMP, room)))
|
||||||
|
TEN::Effects::TriggerSpeedboatFoam(speedboatItem, Vector3(0.0f, 0.0f, SPEEDBOAT_BACK));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lara->Vehicle != itemNumber)
|
||||||
|
return;
|
||||||
|
|
||||||
|
DoSpeedboatDismount(speedboatItem, laraItem);
|
||||||
|
}
|
||||||
|
}
|
26
TombEngine/Objects/TR2/Vehicles/speedboat.h
Normal file
26
TombEngine/Objects/TR2/Vehicles/speedboat.h
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
#pragma once
|
||||||
|
#include "Objects/Utils/VehicleHelpers.h"
|
||||||
|
|
||||||
|
struct CollisionInfo;
|
||||||
|
struct ItemInfo;
|
||||||
|
|
||||||
|
namespace TEN::Entities::Vehicles
|
||||||
|
{
|
||||||
|
void InitialiseSpeedboat(short itemNumber);
|
||||||
|
|
||||||
|
void SpeedboatPlayerCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll);
|
||||||
|
void DoSpeedboatMount(ItemInfo* speedboatItem, ItemInfo* laraItem, VehicleMountType mountType);
|
||||||
|
bool TestSpeedboatDismount(ItemInfo* speedboatItem, int direction);
|
||||||
|
void DoSpeedboatDismount(ItemInfo* speedboatItem, ItemInfo* laraItem);
|
||||||
|
|
||||||
|
void SpeedboatDoBoatShift(ItemInfo* speedboatItem, int itemNumber);
|
||||||
|
short SpeedboatDoShift(ItemInfo* speedboatItem, Vector3Int* pos, Vector3Int* old);
|
||||||
|
|
||||||
|
int GetSpeedboatHitAnim(ItemInfo* speedboatItem, Vector3Int* moved);
|
||||||
|
int DoSpeedboatDynamics(int height, int verticalVelocity, int* y);
|
||||||
|
int SpeedboatDynamics(short itemNumber, ItemInfo* laraItem);
|
||||||
|
bool SpeedboatUserControl(ItemInfo* speedboatItem, ItemInfo* laraItem);
|
||||||
|
void SpeedboatAnimation(ItemInfo* speedboatItem, ItemInfo* laraItem, int collide);
|
||||||
|
void SpeedboatSplash(ItemInfo* speedboatItem, long verticalVelocity, long water);
|
||||||
|
void SpeedboatControl(short itemNumber);
|
||||||
|
}
|
17
TombEngine/Objects/TR2/Vehicles/speedboat_info.h
Normal file
17
TombEngine/Objects/TR2/Vehicles/speedboat_info.h
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace TEN::Entities::Vehicles
|
||||||
|
{
|
||||||
|
struct SpeedboatInfo
|
||||||
|
{
|
||||||
|
int LeftVerticalVelocity = 0;
|
||||||
|
int RightVerticalVelocity = 0;
|
||||||
|
|
||||||
|
short TurnRate = 0;
|
||||||
|
short LeanAngle = 0;
|
||||||
|
short ExtraRotation = 0;
|
||||||
|
|
||||||
|
int Pitch = 0;
|
||||||
|
int Water = 0;
|
||||||
|
};
|
||||||
|
}
|
|
@ -26,7 +26,7 @@
|
||||||
#include "Objects/TR2/Trap/tr2_springboard.h"
|
#include "Objects/TR2/Trap/tr2_springboard.h"
|
||||||
#include "Objects/TR2/Trap/tr2_killerstatue.h"
|
#include "Objects/TR2/Trap/tr2_killerstatue.h"
|
||||||
/// vehicles
|
/// vehicles
|
||||||
#include "Objects/TR2/Vehicles/boat.h"
|
#include "Objects/TR2/Vehicles/speedboat.h"
|
||||||
#include "Objects/TR2/Vehicles/skidoo.h"
|
#include "Objects/TR2/Vehicles/skidoo.h"
|
||||||
/// necessary import
|
/// necessary import
|
||||||
#include "Game/control/box.h"
|
#include "Game/control/box.h"
|
||||||
|
@ -662,9 +662,9 @@ static void StartVehicles(ObjectInfo* obj)
|
||||||
obj = &Objects[ID_SPEEDBOAT];
|
obj = &Objects[ID_SPEEDBOAT];
|
||||||
if (obj->loaded)
|
if (obj->loaded)
|
||||||
{
|
{
|
||||||
obj->initialise = InitialiseSpeedBoat;
|
obj->initialise = InitialiseSpeedboat;
|
||||||
obj->collision = SpeedBoatCollision;
|
obj->collision = SpeedboatPlayerCollision;
|
||||||
obj->control = SpeedBoatControl;
|
obj->control = SpeedboatControl;
|
||||||
obj->saveAnim = true;
|
obj->saveAnim = true;
|
||||||
obj->saveFlags = true;
|
obj->saveFlags = true;
|
||||||
obj->savePosition = true;
|
obj->savePosition = true;
|
||||||
|
@ -676,7 +676,7 @@ static void StartVehicles(ObjectInfo* obj)
|
||||||
if (obj->loaded)
|
if (obj->loaded)
|
||||||
{
|
{
|
||||||
obj->initialise = InitialiseSkidoo;
|
obj->initialise = InitialiseSkidoo;
|
||||||
obj->collision = SkidooCollision;
|
obj->collision = SkidooPlayerCollision;
|
||||||
//obj->drawRoutine = DrawSkidoo; // TODO: create a new render for the skidoo. (with track animated)
|
//obj->drawRoutine = DrawSkidoo; // TODO: create a new render for the skidoo. (with track animated)
|
||||||
obj->saveAnim = true;
|
obj->saveAnim = true;
|
||||||
obj->saveFlags = true;
|
obj->saveFlags = true;
|
||||||
|
|
|
@ -467,7 +467,7 @@ namespace TEN::Entities::TR3
|
||||||
|
|
||||||
LaraItem->Pose.Position = item->Pose.Position;
|
LaraItem->Pose.Position = item->Pose.Position;
|
||||||
LaraItem->Pose.Orientation = Vector3Shrt(0, item->Pose.Orientation.y, 0);
|
LaraItem->Pose.Orientation = Vector3Shrt(0, item->Pose.Orientation.y, 0);
|
||||||
LaraItem->Animation.Airborne = false;
|
LaraItem->Animation.IsAirborne = false;
|
||||||
|
|
||||||
LaraItem->Animation.AnimNumber = Objects[ID_LARA_EXTRA_ANIMS].animIndex + LARA_ANIM_SHIVA_DEATH;
|
LaraItem->Animation.AnimNumber = Objects[ID_LARA_EXTRA_ANIMS].animIndex + LARA_ANIM_SHIVA_DEATH;
|
||||||
LaraItem->Animation.FrameNumber = g_Level.Anims[LaraItem->Animation.AnimNumber].frameBase;
|
LaraItem->Animation.FrameNumber = g_Level.Anims[LaraItem->Animation.AnimNumber].frameBase;
|
||||||
|
|
|
@ -101,7 +101,7 @@ namespace TEN::Entities::TR3
|
||||||
KillItem(itemNumber);
|
KillItem(itemNumber);
|
||||||
DisableEntityAI(itemNumber);
|
DisableEntityAI(itemNumber);
|
||||||
|
|
||||||
item->Flags |= ONESHOT;
|
item->Flags |= IFLAG_INVISIBLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ControlLaserBolts(short itemNumber)
|
void ControlLaserBolts(short itemNumber)
|
||||||
|
|
|
@ -500,7 +500,7 @@ namespace TEN::Entities::TR3
|
||||||
KillItem(itemNumber);
|
KillItem(itemNumber);
|
||||||
DisableEntityAI(itemNumber);
|
DisableEntityAI(itemNumber);
|
||||||
|
|
||||||
item->Flags |= ONESHOT;
|
item->Flags |= IFLAG_INVISIBLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool TonyIsDying()
|
static bool TonyIsDying()
|
||||||
|
|
|
@ -57,7 +57,7 @@ namespace TEN::Entities::TR3
|
||||||
|
|
||||||
laraItem->Pose.Position = tRexItem->Pose.Position;
|
laraItem->Pose.Position = tRexItem->Pose.Position;
|
||||||
laraItem->Pose.Orientation = Vector3Shrt(0, tRexItem->Pose.Orientation.y, 0);
|
laraItem->Pose.Orientation = Vector3Shrt(0, tRexItem->Pose.Orientation.y, 0);
|
||||||
laraItem->Animation.Airborne = false;
|
laraItem->Animation.IsAirborne = false;
|
||||||
|
|
||||||
laraItem->Animation.AnimNumber = Objects[ID_LARA_EXTRA_ANIMS].animIndex + LARA_ANIM_TREX_DEATH;
|
laraItem->Animation.AnimNumber = Objects[ID_LARA_EXTRA_ANIMS].animIndex + LARA_ANIM_TREX_DEATH;
|
||||||
laraItem->Animation.FrameNumber = g_Level.Anims[laraItem->Animation.AnimNumber].frameBase;
|
laraItem->Animation.FrameNumber = g_Level.Anims[laraItem->Animation.AnimNumber].frameBase;
|
||||||
|
|
|
@ -114,7 +114,7 @@ void TrainCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll)
|
||||||
laraItem->Pose.Orientation.y = trainItem->Pose.Orientation.y;
|
laraItem->Pose.Orientation.y = trainItem->Pose.Orientation.y;
|
||||||
laraItem->Animation.Velocity = 0;
|
laraItem->Animation.Velocity = 0;
|
||||||
laraItem->Animation.VerticalVelocity = 0;
|
laraItem->Animation.VerticalVelocity = 0;
|
||||||
laraItem->Animation.Airborne = false;
|
laraItem->Animation.IsAirborne = false;
|
||||||
|
|
||||||
DoDamage(laraItem, INT_MAX);
|
DoDamage(laraItem, INT_MAX);
|
||||||
|
|
||||||
|
|
|
@ -13,36 +13,41 @@
|
||||||
#include "Game/Lara/lara_helpers.h"
|
#include "Game/Lara/lara_helpers.h"
|
||||||
#include "Game/Lara/lara_struct.h"
|
#include "Game/Lara/lara_struct.h"
|
||||||
#include "Objects/TR3/Vehicles/big_gun_info.h"
|
#include "Objects/TR3/Vehicles/big_gun_info.h"
|
||||||
|
#include "Objects/Utils/VehicleHelpers.h"
|
||||||
#include "Sound/sound.h"
|
#include "Sound/sound.h"
|
||||||
#include "Specific/level.h"
|
#include "Specific/level.h"
|
||||||
#include "Specific/input.h"
|
#include "Specific/input.h"
|
||||||
#include "Specific/setup.h"
|
#include "Specific/setup.h"
|
||||||
|
|
||||||
|
using std::vector;
|
||||||
using namespace TEN::Input;
|
using namespace TEN::Input;
|
||||||
|
|
||||||
namespace TEN::Entities::Vehicles
|
namespace TEN::Entities::Vehicles
|
||||||
{
|
{
|
||||||
#define RECOIL_TIME 26
|
const vector<VehicleMountType> BigGunMountTypes =
|
||||||
#define RECOIL_Z 25
|
{
|
||||||
|
VehicleMountType::LevelStart,
|
||||||
|
VehicleMountType::Back
|
||||||
|
};
|
||||||
|
|
||||||
#define BGUN_NUM_UP_DOWN_FRAMES 59
|
constexpr auto BGUN_MOUNT_DISTANCE = CLICK(2);
|
||||||
#define BGUN_DISMOUNT_FRAME 30
|
|
||||||
|
|
||||||
#define BGUN_TURN_RATE ANGLE(2.0f)
|
constexpr auto BGUN_RECOIL_TIME = 26;
|
||||||
#define BGUN_TURN_MAX ANGLE(16.0f)
|
constexpr auto BGUN_RECOIL_Z = 25;
|
||||||
|
|
||||||
#define BGUN_IN_FIRE IN_ACTION
|
constexpr auto BGUN_X_ORIENT_NUM_FRAMES = 59;
|
||||||
#define BGUN_IN_DISMOUNT (IN_ROLL | IN_JUMP)
|
constexpr auto BGUN_X_ORIENT_MIDDLE_FRAME = 30;
|
||||||
#define BGUN_IN_UP IN_FORWARD
|
|
||||||
#define BGUN_IN_DOWN IN_BACK
|
#define BGUN_TURN_RATE_ACCEL ANGLE(0.5f)
|
||||||
#define BGUN_IN_LEFT IN_LEFT
|
#define BGUN_TURN_RATE_MAX ANGLE(4.0f)
|
||||||
#define BGUN_IN_RIGHT IN_RIGHT
|
#define BGUN_X_ORIENT_STEP (ANGLE(80.0f) / BGUN_X_ORIENT_NUM_FRAMES)
|
||||||
|
#define BGUN_X_ORIENT_MAX ANGLE(40.0f)
|
||||||
|
|
||||||
enum BigGunState
|
enum BigGunState
|
||||||
{
|
{
|
||||||
BGUN_STATE_MOUNT = 0,
|
BGUN_STATE_MOUNT = 0,
|
||||||
BGUN_STATE_DISMOUNT = 1,
|
BGUN_STATE_DISMOUNT = 1,
|
||||||
BGUN_STATE_UP_DOWN = 2,
|
BGUN_STATE_ROTATE_VERTICALLY = 2,
|
||||||
BGUN_STATE_RECOIL = 3
|
BGUN_STATE_RECOIL = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -50,41 +55,41 @@ namespace TEN::Entities::Vehicles
|
||||||
{
|
{
|
||||||
BGUN_ANIM_MOUNT = 0,
|
BGUN_ANIM_MOUNT = 0,
|
||||||
BGUN_ANIM_DISMOUNT = 1,
|
BGUN_ANIM_DISMOUNT = 1,
|
||||||
BGUN_ANIM_UP_DOWN = 2,
|
BGUN_ANIM_ROTATE_VERTICALLY = 2,
|
||||||
BGUN_ANIM_RECOIL = 3
|
BGUN_ANIM_RECOIL = 3
|
||||||
};
|
};
|
||||||
|
|
||||||
enum BigGunFlags
|
enum BigGunFlags
|
||||||
{
|
{
|
||||||
BGUN_FLAG_UP_DOWN = 1,
|
BGUN_FLAG_UP_DOWN = (1 << 0),
|
||||||
BGUN_FLAG_AUTO_ROT = 2,
|
BGUN_FLAG_AUTO_ROT = (1 << 2),
|
||||||
BGUN_FLAG_DISMOUNT = 4,
|
BGUN_FLAG_DISMOUNT = (1 << 3),
|
||||||
BGUN_FLAG_FIRE = 8
|
BGUN_FLAG_FIRE = (1 << 4)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
BigGunInfo* GetBigGunInfo(ItemInfo* bigGunItem)
|
||||||
|
{
|
||||||
|
return (BigGunInfo*)bigGunItem->Data;
|
||||||
|
}
|
||||||
|
|
||||||
void BigGunInitialise(short itemNumber)
|
void BigGunInitialise(short itemNumber)
|
||||||
{
|
{
|
||||||
auto* bigGunItem = &g_Level.Items[itemNumber];
|
auto* bigGunItem = &g_Level.Items[itemNumber];
|
||||||
bigGunItem->Data = BigGunInfo();
|
bigGunItem->Data = BigGunInfo();
|
||||||
auto* bigGun = (BigGunInfo*)bigGunItem->Data;
|
auto* bigGun = GetBigGunInfo(bigGunItem);
|
||||||
|
|
||||||
bigGun->Rotation.x = BGUN_DISMOUNT_FRAME;
|
bigGun->BaseOrientation = bigGunItem->Pose.Orientation;
|
||||||
bigGun->Rotation.z = 0;
|
bigGun->XOrientFrame = BGUN_X_ORIENT_MIDDLE_FRAME;
|
||||||
bigGun->StartYRot = bigGunItem->Pose.Orientation.y;
|
|
||||||
bigGun->GunRotYAdd = 0;
|
|
||||||
bigGun->FireCount = 0;
|
|
||||||
bigGun->Flags = 0;
|
|
||||||
bigGun->BarrelRotating = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool BigGunTestMount(ItemInfo* laraItem, ItemInfo* bigGunItem)
|
static bool BigGunTestMount(ItemInfo* bigGunItem, ItemInfo* laraItem)
|
||||||
{
|
{
|
||||||
// TODO: If Lara global is not used, the game crashes upon level load. Not sure why. @Sezz 2022.01.09
|
// TODO: If Lara global is not used, the game crashes upon level load. Not sure why. @Sezz 2022.01.09
|
||||||
auto* lara = &Lara/* GetLaraInfo(laraItem)*/;
|
auto* lara = &Lara/* GetLaraInfo(laraItem)*/;
|
||||||
|
|
||||||
if (!(TrInput & IN_ACTION) ||
|
if (!(TrInput & IN_ACTION) ||
|
||||||
lara->Control.HandStatus != HandStatus::Free ||
|
lara->Control.HandStatus != HandStatus::Free ||
|
||||||
laraItem->Animation.Airborne)
|
laraItem->Animation.IsAirborne)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -94,7 +99,7 @@ namespace TEN::Entities::Vehicles
|
||||||
int z = laraItem->Pose.Position.z - bigGunItem->Pose.Position.z;
|
int z = laraItem->Pose.Position.z - bigGunItem->Pose.Position.z;
|
||||||
|
|
||||||
int distance = pow(x, 2) + pow(y, 2) + pow(z, 2);
|
int distance = pow(x, 2) + pow(y, 2) + pow(z, 2);
|
||||||
if (distance > 30000)
|
if (distance > SECTOR(30))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
short deltaAngle = abs(laraItem->Pose.Orientation.y - bigGunItem->Pose.Orientation.y);
|
short deltaAngle = abs(laraItem->Pose.Orientation.y - bigGunItem->Pose.Orientation.y);
|
||||||
|
@ -104,9 +109,9 @@ namespace TEN::Entities::Vehicles
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BigGunFire(ItemInfo* laraItem, ItemInfo* bigGunItem)
|
void BigGunFire(ItemInfo* bigGunItem, ItemInfo* laraItem)
|
||||||
{
|
{
|
||||||
auto* bigGun = (BigGunInfo*)bigGunItem->Data;
|
auto* bigGun = GetBigGunInfo(bigGunItem);
|
||||||
|
|
||||||
short itemNumber = CreateItem();
|
short itemNumber = CreateItem();
|
||||||
auto* projectileItem = &g_Level.Items[itemNumber];
|
auto* projectileItem = &g_Level.Items[itemNumber];
|
||||||
|
@ -123,10 +128,12 @@ namespace TEN::Entities::Vehicles
|
||||||
|
|
||||||
InitialiseItem(itemNumber);
|
InitialiseItem(itemNumber);
|
||||||
|
|
||||||
projectileItem->Pose.Orientation.x = -((bigGun->Rotation.x - 32) * ANGLE(1.0f));
|
|
||||||
projectileItem->Pose.Orientation.y = bigGunItem->Pose.Orientation.y;
|
|
||||||
projectileItem->Pose.Orientation.z = 0;
|
|
||||||
projectileItem->Animation.Velocity = 16;
|
projectileItem->Animation.Velocity = 16;
|
||||||
|
projectileItem->Pose.Orientation = Vector3Shrt(
|
||||||
|
-((bigGun->XOrientFrame - 32) * ANGLE(1.0f)),
|
||||||
|
bigGunItem->Pose.Orientation.y,
|
||||||
|
0
|
||||||
|
);
|
||||||
projectileItem->ItemFlags[0] = BGUN_FLAG_UP_DOWN;
|
projectileItem->ItemFlags[0] = BGUN_FLAG_UP_DOWN;
|
||||||
|
|
||||||
AddActiveItem(itemNumber);
|
AddActiveItem(itemNumber);
|
||||||
|
@ -141,121 +148,141 @@ namespace TEN::Entities::Vehicles
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BigGunCollision(short itemNum, ItemInfo* laraItem, CollisionInfo* coll)
|
void BigGunCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll)
|
||||||
{
|
{
|
||||||
|
auto* bigGunItem = &g_Level.Items[itemNumber];
|
||||||
|
auto* bigGun = GetBigGunInfo(bigGunItem);
|
||||||
auto* lara = GetLaraInfo(laraItem);
|
auto* lara = GetLaraInfo(laraItem);
|
||||||
auto* bigGunItem = &g_Level.Items[itemNum];
|
|
||||||
auto* bigGun = (BigGunInfo*)bigGunItem->Data;
|
|
||||||
|
|
||||||
if (laraItem->HitPoints <= 0 || lara->Vehicle != NO_ITEM)
|
if (laraItem->HitPoints <= 0 || lara->Vehicle != NO_ITEM)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (BigGunTestMount(bigGunItem, laraItem))
|
if (BigGunTestMount(laraItem, bigGunItem))
|
||||||
{
|
{
|
||||||
lara->Vehicle = itemNum;
|
lara->Vehicle = itemNumber;
|
||||||
|
|
||||||
if (lara->Control.Weapon.GunType == LaraWeaponType::Flare)
|
|
||||||
{
|
|
||||||
CreateFlare(laraItem, ID_FLARE_ITEM, false);
|
|
||||||
UndrawFlareMeshes(laraItem);
|
|
||||||
|
|
||||||
lara->Flare.ControlLeft = false;
|
|
||||||
lara->Control.Weapon.RequestGunType = LaraWeaponType::None;
|
|
||||||
lara->Control.Weapon.GunType = LaraWeaponType::None;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
DoVehicleFlareDiscard(laraItem);
|
||||||
laraItem->Animation.AnimNumber = Objects[ID_BIGGUN_ANIMS].animIndex + BGUN_ANIM_MOUNT;
|
laraItem->Animation.AnimNumber = Objects[ID_BIGGUN_ANIMS].animIndex + BGUN_ANIM_MOUNT;
|
||||||
laraItem->Animation.FrameNumber = g_Level.Anims[Objects[ID_BIGGUN_ANIMS].animIndex + BGUN_ANIM_MOUNT].frameBase;
|
laraItem->Animation.FrameNumber = g_Level.Anims[Objects[ID_BIGGUN_ANIMS].animIndex + BGUN_ANIM_MOUNT].frameBase;
|
||||||
laraItem->Animation.TargetState = BGUN_STATE_MOUNT;
|
|
||||||
laraItem->Animation.ActiveState = BGUN_STATE_MOUNT;
|
laraItem->Animation.ActiveState = BGUN_STATE_MOUNT;
|
||||||
|
laraItem->Animation.TargetState = BGUN_STATE_MOUNT;
|
||||||
|
laraItem->Animation.IsAirborne = false;
|
||||||
laraItem->Pose = bigGunItem->Pose;
|
laraItem->Pose = bigGunItem->Pose;
|
||||||
laraItem->Animation.Airborne = false;
|
|
||||||
lara->Control.HandStatus = HandStatus::Busy;
|
lara->Control.HandStatus = HandStatus::Busy;
|
||||||
bigGunItem->HitPoints = 1;
|
bigGunItem->HitPoints = 1;
|
||||||
|
bigGun->XOrientFrame = BGUN_X_ORIENT_MIDDLE_FRAME;
|
||||||
bigGun->Flags = 0;
|
bigGun->Flags = 0;
|
||||||
bigGun->Rotation.x = BGUN_DISMOUNT_FRAME;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ObjectCollision(itemNum, laraItem, coll);
|
ObjectCollision(itemNumber, laraItem, coll);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BigGunControl(ItemInfo* laraItem, CollisionInfo* coll)
|
bool BigGunControl(ItemInfo* laraItem, CollisionInfo* coll)
|
||||||
{
|
{
|
||||||
auto* lara = GetLaraInfo(laraItem);
|
auto* lara = GetLaraInfo(laraItem);
|
||||||
auto* bigGunItem = &g_Level.Items[lara->Vehicle];
|
auto* bigGunItem = &g_Level.Items[lara->Vehicle];
|
||||||
auto* bigGun = (BigGunInfo*)bigGunItem->Data;
|
auto* bigGun = GetBigGunInfo(bigGunItem);
|
||||||
|
|
||||||
if (bigGun->Flags & BGUN_FLAG_UP_DOWN)
|
if (bigGun->Flags & BGUN_FLAG_UP_DOWN)
|
||||||
{
|
{
|
||||||
if (bigGun->BarrelRotating)
|
if (bigGun->IsBarrelRotating)
|
||||||
bigGun->BarrelZRotation--;
|
bigGun->BarrelRotation--;
|
||||||
|
|
||||||
if (!bigGun->BarrelZRotation)
|
if (!bigGun->BarrelRotation)
|
||||||
bigGun->BarrelRotating = false;
|
bigGun->IsBarrelRotating = false;
|
||||||
|
|
||||||
if (TrInput & BGUN_IN_DISMOUNT || laraItem->HitPoints <= 0)
|
if (TrInput & VEHICLE_IN_DISMOUNT || laraItem->HitPoints <= 0)
|
||||||
bigGun->Flags = BGUN_FLAG_AUTO_ROT;
|
bigGun->Flags = BGUN_FLAG_AUTO_ROT;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (TrInput & BGUN_IN_FIRE && bigGun->FireCount == 0)
|
if (TrInput & VEHICLE_IN_FIRE && !bigGun->FireCount)
|
||||||
{
|
{
|
||||||
BigGunFire(laraItem, bigGunItem);
|
BigGunFire(bigGunItem, laraItem);
|
||||||
bigGun->FireCount = RECOIL_TIME;
|
bigGun->FireCount = BGUN_RECOIL_TIME;
|
||||||
bigGun->BarrelZRotation = RECOIL_Z;
|
bigGun->BarrelRotation = BGUN_RECOIL_Z;
|
||||||
bigGun->BarrelRotating = true;
|
bigGun->IsBarrelRotating = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TrInput & BGUN_IN_LEFT)
|
if (TrInput & VEHICLE_IN_UP)
|
||||||
{
|
{
|
||||||
if (bigGun->GunRotYAdd > 0)
|
if (bigGun->TurnRate.x < 0)
|
||||||
bigGun->GunRotYAdd /= 2;
|
bigGun->TurnRate.x /= 2;
|
||||||
|
|
||||||
bigGun->GunRotYAdd -= BGUN_TURN_RATE;
|
bigGun->TurnRate.x += BGUN_TURN_RATE_ACCEL;
|
||||||
if (bigGun->GunRotYAdd < -BGUN_TURN_MAX)
|
if (bigGun->TurnRate.x > (BGUN_TURN_RATE_MAX / 2))
|
||||||
bigGun->GunRotYAdd = -BGUN_TURN_MAX;
|
bigGun->TurnRate.x = (BGUN_TURN_RATE_MAX / 2);
|
||||||
}
|
}
|
||||||
else if (TrInput & BGUN_IN_RIGHT)
|
else if (TrInput & VEHICLE_IN_DOWN)
|
||||||
{
|
{
|
||||||
if (bigGun->GunRotYAdd < 0)
|
if (bigGun->TurnRate.x > 0)
|
||||||
bigGun->GunRotYAdd /= 2;
|
bigGun->TurnRate.x /= 2;
|
||||||
|
|
||||||
bigGun->GunRotYAdd += BGUN_TURN_RATE;
|
bigGun->TurnRate.x -= BGUN_TURN_RATE_ACCEL;
|
||||||
if (bigGun->GunRotYAdd > BGUN_TURN_MAX)
|
if (bigGun->TurnRate.x < (-BGUN_TURN_RATE_MAX / 2))
|
||||||
bigGun->GunRotYAdd = BGUN_TURN_MAX;
|
bigGun->TurnRate.x = (-BGUN_TURN_RATE_MAX / 2);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bigGun->GunRotYAdd -= bigGun->GunRotYAdd / 4;
|
bigGun->TurnRate.x -= bigGun->TurnRate.x / 3;
|
||||||
if (abs(bigGun->GunRotYAdd) < BGUN_TURN_RATE)
|
if (abs(bigGun->TurnRate.x) < BGUN_TURN_RATE_ACCEL)
|
||||||
bigGun->GunRotYAdd = 0;
|
bigGun->TurnRate.x = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bigGun->Rotation.z += bigGun->GunRotYAdd / 4;
|
if (TrInput & VEHICLE_IN_LEFT)
|
||||||
|
{
|
||||||
|
if (bigGun->TurnRate.y > 0)
|
||||||
|
bigGun->TurnRate.y /= 2;
|
||||||
|
|
||||||
if (TrInput & BGUN_IN_UP && bigGun->Rotation.x < BGUN_NUM_UP_DOWN_FRAMES)
|
bigGun->TurnRate.y -= BGUN_TURN_RATE_ACCEL;
|
||||||
bigGun->Rotation.x++;
|
if (bigGun->TurnRate.y < -BGUN_TURN_RATE_MAX)
|
||||||
else if (TrInput & BGUN_IN_DOWN && bigGun->Rotation.x)
|
bigGun->TurnRate.y = -BGUN_TURN_RATE_MAX;
|
||||||
bigGun->Rotation.x--;
|
}
|
||||||
|
else if (TrInput & VEHICLE_IN_RIGHT)
|
||||||
|
{
|
||||||
|
if (bigGun->TurnRate.y < 0)
|
||||||
|
bigGun->TurnRate.y /= 2;
|
||||||
|
|
||||||
|
bigGun->TurnRate.y += BGUN_TURN_RATE_ACCEL;
|
||||||
|
if (bigGun->TurnRate.y > BGUN_TURN_RATE_MAX)
|
||||||
|
bigGun->TurnRate.y = BGUN_TURN_RATE_MAX;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bigGun->TurnRate.y -= bigGun->TurnRate.y / 3;
|
||||||
|
if (abs(bigGun->TurnRate.y) < BGUN_TURN_RATE_ACCEL)
|
||||||
|
bigGun->TurnRate.y = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bigGun->Rotation.x += bigGun->TurnRate.x;
|
||||||
|
bigGun->Rotation.y += bigGun->TurnRate.y;
|
||||||
|
|
||||||
|
if (bigGun->Rotation.x > BGUN_X_ORIENT_MAX)
|
||||||
|
bigGun->Rotation.x = BGUN_X_ORIENT_MAX;
|
||||||
|
else if (bigGun->Rotation.x < -BGUN_X_ORIENT_MAX)
|
||||||
|
bigGun->Rotation.x = -BGUN_X_ORIENT_MAX;
|
||||||
|
|
||||||
|
bigGun->XOrientFrame = (int)round((bigGun->Rotation.x + BGUN_X_ORIENT_MAX) / BGUN_X_ORIENT_STEP);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bigGun->Flags & BGUN_FLAG_AUTO_ROT)
|
if (bigGun->Flags & BGUN_FLAG_AUTO_ROT)
|
||||||
{
|
{
|
||||||
if (bigGun->Rotation.x == BGUN_DISMOUNT_FRAME)
|
if (bigGun->XOrientFrame == BGUN_X_ORIENT_MIDDLE_FRAME)
|
||||||
{
|
{
|
||||||
laraItem->Animation.AnimNumber = Objects[ID_BIGGUN_ANIMS].animIndex + BGUN_ANIM_DISMOUNT;
|
laraItem->Animation.AnimNumber = Objects[ID_BIGGUN_ANIMS].animIndex + BGUN_ANIM_DISMOUNT;
|
||||||
laraItem->Animation.FrameNumber = g_Level.Anims[Objects[ID_BIGGUN].animIndex + BGUN_ANIM_DISMOUNT].frameBase;
|
laraItem->Animation.FrameNumber = g_Level.Anims[Objects[ID_BIGGUN].animIndex + BGUN_ANIM_DISMOUNT].frameBase;
|
||||||
laraItem->Animation.ActiveState = BGUN_STATE_DISMOUNT;
|
laraItem->Animation.ActiveState = BGUN_STATE_DISMOUNT;
|
||||||
laraItem->Animation.TargetState = BGUN_STATE_DISMOUNT;
|
laraItem->Animation.TargetState = BGUN_STATE_DISMOUNT;
|
||||||
bigGun->GunRotYAdd = 0;
|
bigGun->TurnRate.y = 0;
|
||||||
bigGun->BarrelRotating = false;
|
bigGun->IsBarrelRotating = false;
|
||||||
bigGun->Flags = BGUN_FLAG_DISMOUNT;
|
bigGun->Flags = BGUN_FLAG_DISMOUNT;
|
||||||
}
|
}
|
||||||
else if (bigGun->Rotation.x > BGUN_DISMOUNT_FRAME)
|
else if (bigGun->Rotation.x > 0)
|
||||||
bigGun->Rotation.x--;
|
bigGun->Rotation.x -= BGUN_X_ORIENT_STEP;
|
||||||
else if (bigGun->Rotation.x < BGUN_DISMOUNT_FRAME)
|
else if (bigGun->Rotation.x < 0)
|
||||||
bigGun->Rotation.x++;
|
bigGun->Rotation.x += BGUN_X_ORIENT_STEP;
|
||||||
|
|
||||||
|
bigGun->XOrientFrame = (int)round((bigGun->Rotation.x + BGUN_X_ORIENT_MAX) / BGUN_X_ORIENT_STEP);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (laraItem->Animation.ActiveState)
|
switch (laraItem->Animation.ActiveState)
|
||||||
|
@ -276,9 +303,7 @@ namespace TEN::Entities::Vehicles
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BGUN_STATE_UP_DOWN:
|
case BGUN_STATE_ROTATE_VERTICALLY:
|
||||||
laraItem->Animation.AnimNumber = Objects[ID_BIGGUN_ANIMS].animIndex + BGUN_ANIM_UP_DOWN;
|
|
||||||
laraItem->Animation.FrameNumber = g_Level.Anims[Objects[ID_BIGGUN].animIndex + BGUN_ANIM_UP_DOWN].frameBase + bigGun->Rotation.x;
|
|
||||||
bigGunItem->Animation.AnimNumber = Objects[ID_BIGGUN].animIndex + (laraItem->Animation.AnimNumber - Objects[ID_BIGGUN_ANIMS].animIndex);
|
bigGunItem->Animation.AnimNumber = Objects[ID_BIGGUN].animIndex + (laraItem->Animation.AnimNumber - Objects[ID_BIGGUN_ANIMS].animIndex);
|
||||||
bigGunItem->Animation.FrameNumber = g_Level.Anims[bigGunItem->Animation.AnimNumber].frameBase + (laraItem->Animation.FrameNumber - g_Level.Anims[laraItem->Animation.AnimNumber].frameBase);
|
bigGunItem->Animation.FrameNumber = g_Level.Anims[bigGunItem->Animation.AnimNumber].frameBase + (laraItem->Animation.FrameNumber - g_Level.Anims[laraItem->Animation.AnimNumber].frameBase);
|
||||||
|
|
||||||
|
@ -288,15 +313,18 @@ namespace TEN::Entities::Vehicles
|
||||||
bigGun->FireCount = 0;
|
bigGun->FireCount = 0;
|
||||||
|
|
||||||
bigGun->Flags = BGUN_FLAG_UP_DOWN;
|
bigGun->Flags = BGUN_FLAG_UP_DOWN;
|
||||||
|
|
||||||
|
laraItem->Animation.AnimNumber = Objects[ID_BIGGUN_ANIMS].animIndex + BGUN_ANIM_ROTATE_VERTICALLY;
|
||||||
|
laraItem->Animation.FrameNumber = g_Level.Anims[Objects[ID_BIGGUN].animIndex + BGUN_ANIM_ROTATE_VERTICALLY].frameBase + bigGun->XOrientFrame;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Camera.targetElevation = -ANGLE(15.0f);
|
Camera.targetElevation = -(bigGun->Rotation.x + ANGLE(15.0f));
|
||||||
|
|
||||||
bigGunItem->Pose.Orientation.y = bigGun->StartYRot + bigGun->Rotation.z;
|
bigGunItem->Pose.Orientation.y = bigGun->BaseOrientation.y + bigGun->Rotation.y;
|
||||||
laraItem->Pose.Orientation.y = bigGunItem->Pose.Orientation.y;
|
laraItem->Pose.Orientation.y = bigGunItem->Pose.Orientation.y;
|
||||||
coll->Setup.EnableSpasm = false;
|
|
||||||
coll->Setup.EnableObjectPush = false;
|
coll->Setup.EnableObjectPush = false;
|
||||||
|
coll->Setup.EnableSpasm = false;
|
||||||
|
|
||||||
DoObjectCollision(laraItem, coll);
|
DoObjectCollision(laraItem, coll);
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include "Objects/Utils/VehicleHelpers.h"
|
||||||
|
|
||||||
struct CollisionInfo;
|
struct CollisionInfo;
|
||||||
struct ItemInfo;
|
struct ItemInfo;
|
||||||
|
@ -6,8 +7,8 @@ struct ItemInfo;
|
||||||
namespace TEN::Entities::Vehicles
|
namespace TEN::Entities::Vehicles
|
||||||
{
|
{
|
||||||
void BigGunInitialise(short itemNumber);
|
void BigGunInitialise(short itemNumber);
|
||||||
static bool BigGunTestMount(ItemInfo* laraItem, ItemInfo* bigGunItem);
|
static bool BigGunTestMount(ItemInfo* bigGunItem, ItemInfo* laraItem);
|
||||||
void BigGunFire(ItemInfo* laraItem, ItemInfo* bigGunItem);
|
void BigGunFire(ItemInfo* bigGunItem, ItemInfo* laraItem);
|
||||||
void BigGunCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll);
|
void BigGunCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll);
|
||||||
bool BigGunControl(ItemInfo* laraItem, CollisionInfo* coll);
|
bool BigGunControl(ItemInfo* laraItem, CollisionInfo* coll);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,14 +4,15 @@ namespace TEN::Entities::Vehicles
|
||||||
{
|
{
|
||||||
struct BigGunInfo
|
struct BigGunInfo
|
||||||
{
|
{
|
||||||
Vector3Shrt Rotation;
|
Vector3Shrt BaseOrientation = Vector3Shrt();
|
||||||
short BarrelZRotation;
|
Vector3Shrt TurnRate = Vector3Shrt();
|
||||||
short StartYRot;
|
Vector3Shrt Rotation = Vector3Shrt();
|
||||||
long GunRotYAdd;
|
short BarrelRotation = 0;
|
||||||
|
int XOrientFrame = 0;
|
||||||
|
|
||||||
unsigned int FireCount;
|
unsigned int FireCount = 0;
|
||||||
bool BarrelRotating;
|
bool IsBarrelRotating = false;
|
||||||
|
|
||||||
char Flags;
|
char Flags = NULL;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,60 +12,85 @@
|
||||||
#include "Game/Lara/lara_flare.h"
|
#include "Game/Lara/lara_flare.h"
|
||||||
#include "Game/Lara/lara_helpers.h"
|
#include "Game/Lara/lara_helpers.h"
|
||||||
#include "Objects/TR3/Vehicles/kayak_info.h"
|
#include "Objects/TR3/Vehicles/kayak_info.h"
|
||||||
|
#include "Objects/Utils/VehicleHelpers.h"
|
||||||
#include "Specific/level.h"
|
#include "Specific/level.h"
|
||||||
#include "Specific/input.h"
|
#include "Specific/input.h"
|
||||||
#include "Specific/setup.h"
|
#include "Specific/setup.h"
|
||||||
|
|
||||||
|
using std::vector;
|
||||||
using namespace TEN::Input;
|
using namespace TEN::Input;
|
||||||
|
|
||||||
namespace TEN::Entities::Vehicles
|
namespace TEN::Entities::Vehicles
|
||||||
{
|
{
|
||||||
#define KAYAK_COLLIDE CLICK(0.25f)
|
struct WAKE_PTS
|
||||||
#define DISMOUNT_DISTANCE CLICK(3) // TODO: Find accurate distance.
|
{
|
||||||
#define KAYAK_TO_ENTITY_RADIUS CLICK(1)
|
int x[2];
|
||||||
|
int y;
|
||||||
|
int z[2];
|
||||||
|
short xvel[2];
|
||||||
|
short zvel[2];
|
||||||
|
byte life;
|
||||||
|
byte pad[3];
|
||||||
|
};
|
||||||
|
static vector<int> KayakLaraLegJoints = { LM_HIPS, LM_LTHIGH, LM_LSHIN, LM_LFOOT, LM_RTHIGH, LM_RSHIN, LM_RFOOT };
|
||||||
|
static vector<VehicleMountType> KayakMountTypes =
|
||||||
|
{
|
||||||
|
VehicleMountType::LevelStart,
|
||||||
|
VehicleMountType::Left,
|
||||||
|
VehicleMountType::Right
|
||||||
|
};
|
||||||
|
|
||||||
#define MAX_VELOCITY 0x380000
|
constexpr auto KAYAK_TO_ENTITY_RADIUS = CLICK(1);
|
||||||
#define KAYAK_FRICTION 0x8000
|
constexpr auto KAYAK_COLLIDE = CLICK(0.25f);
|
||||||
#define KAYAK_ROTATE_FRICTION 0x50000
|
constexpr auto KAYAK_MOUNT_DISTANCE = CLICK(1.5f);
|
||||||
#define KAYAK_DEFLECT_ROTATION 0x80000
|
constexpr auto KAYAK_DISMOUNT_DISTANCE = CLICK(3); // TODO: Find accurate distance.
|
||||||
#define KAYAK_FORWARD_VELOCITY 0x180000
|
|
||||||
#define KAYAK_FORWARD_ROTATION 0x800000
|
|
||||||
#define KAYAK_LEFT_RIGHT_VELOCITY 0x100000
|
|
||||||
#define KAYAK_LEFT_RIGHT_ROTATION 0xc00000
|
|
||||||
#define KAYAK_MAX_LEFT_RIGHT 0xc00000
|
|
||||||
#define KAYAK_TURN_ROTATION 0x200000
|
|
||||||
#define KAYAK_MAX_TURN 0x1000000
|
|
||||||
#define KAYAK_TURN_BRAKE 0x8000
|
|
||||||
#define KAYAK_HARD_ROTATION 0x1000000
|
|
||||||
#define KAYAK_MAX_STAT 0x1000000
|
|
||||||
|
|
||||||
#define HIT_BACK 1
|
constexpr int KAYAK_VELOCITY_FORWARD_ACCEL = 24 * VEHICLE_VELOCITY_SCALE;
|
||||||
#define HIT_FRONT 2
|
constexpr int KAYAK_VELOCITY_LR_ACCEL = 16 * VEHICLE_VELOCITY_SCALE;
|
||||||
#define HIT_LEFT 3
|
constexpr int KAYAK_VELOCITY_HOLD_TURN_DECEL = 0.5f * VEHICLE_VELOCITY_SCALE;
|
||||||
#define HIT_RIGHT 4
|
constexpr int KAYAK_VELOCITY_FRICTION_DECEL = 0.5f * VEHICLE_VELOCITY_SCALE;
|
||||||
|
|
||||||
|
constexpr int KAYAK_VELOCITY_MAX = 56 * VEHICLE_VELOCITY_SCALE;
|
||||||
|
|
||||||
|
// TODO: Very confusing.
|
||||||
|
#define KAYAK_TURN_RATE_FRICTION_DECEL ANGLE(0.03f)
|
||||||
|
#define KAYAK_TURN_RATE_DEFLECT ANGLE(0.05f)
|
||||||
|
#define KAYAK_TURN_RATE_FORWARD_ACCEL ANGLE(0.7f)
|
||||||
|
#define KAYAK_TURN_RATE_LR_ACCEL ANGLE(1.0f)
|
||||||
|
#define KAYAK_TURN_RATE_LR_MAX ANGLE(1.0f)
|
||||||
|
#define KAYAK_TURN_ROTATION ANGLE(0.18f)
|
||||||
|
#define KAYAK_TURN_RATE_MAX ANGLE(1.4f)
|
||||||
|
#define KAYAK_TURN_RATE_HOLD_ACCEL ANGLE(1.4f)
|
||||||
|
#define KAYAK_TURN_RATE_HOLD_MAX ANGLE(1.4f)
|
||||||
|
|
||||||
|
constexpr auto HIT_BACK = 1;
|
||||||
|
constexpr auto HIT_FRONT = 2;
|
||||||
|
constexpr auto HIT_LEFT = 3;
|
||||||
|
constexpr auto HIT_RIGHT = 4;
|
||||||
|
|
||||||
#define KAYAK_MOUNT_LEFT_FRAME GetFrameNumber(KAYAK_ANIM_MOUNT_RIGHT, 0)
|
#define KAYAK_MOUNT_LEFT_FRAME GetFrameNumber(KAYAK_ANIM_MOUNT_RIGHT, 0)
|
||||||
#define KAYAK_IDLE_FRAME GetFrameNumber(KAYAK_ANIM_IDLE, 0)
|
#define KAYAK_IDLE_FRAME GetFrameNumber(KAYAK_ANIM_IDLE, 0)
|
||||||
#define KAYAK_MOUNT_RIGHT_FRAME GetFrameNumber(KAYAK_ANIM_MOUNT_LEFT, 0)
|
#define KAYAK_MOUNT_RIGHT_FRAME GetFrameNumber(KAYAK_ANIM_MOUNT_LEFT, 0)
|
||||||
|
|
||||||
#define KAYAK_DRAW_SHIFT 32
|
constexpr auto KAYAK_DRAW_SHIFT = 32;
|
||||||
#define LARA_LEG_BITS ((1 << LM_HIPS) | (1 << LM_LTHIGH) | (1 << LM_LSHIN) | (1 << LM_LFOOT) | (1 << LM_RTHIGH) | (1 << LM_RSHIN) | (1 << LM_RFOOT))
|
constexpr auto NUM_WAKE_SPRITES = 32;
|
||||||
#define NUM_WAKE_SPRITES 32
|
constexpr auto WAKE_SIZE = 32;
|
||||||
#define WAKE_SIZE 32
|
constexpr auto WAKE_VELOCITY = 4;
|
||||||
#define WAKE_VELOCITY 4
|
constexpr auto KAYAK_X = 128;
|
||||||
#define KAYAK_X 128
|
constexpr auto KAYAK_Z = 128;
|
||||||
#define KAYAK_Z 128
|
constexpr auto KAYAK_MAX_KICK = -80;
|
||||||
#define KAYAK_MAX_KICK -80
|
constexpr auto KAYAK_MIN_BOUNCE = (KAYAK_VELOCITY_MAX / 2) / VEHICLE_VELOCITY_SCALE;
|
||||||
#define KAYAK_MIN_BOUNCE ((MAX_VELOCITY / 2) / 256)
|
|
||||||
|
|
||||||
#define KAYAK_IN_FORWARD IN_FORWARD
|
// TODO: Kayak control is fairly unique. Keep this? @Sezz 2022.06.25
|
||||||
#define KAYAK_IN_BACK IN_BACK
|
constexpr auto KAYAK_IN_FORWARD = IN_FORWARD;
|
||||||
#define KAYAK_IN_LEFT IN_LEFT
|
constexpr auto KAYAK_IN_BACK = IN_BACK;
|
||||||
#define KAYAK_IN_RIGHT IN_RIGHT
|
constexpr auto KAYAK_IN_LEFT = IN_LEFT;
|
||||||
#define KAYAK_IN_HOLD IN_WALK
|
constexpr auto KAYAK_IN_RIGHT = IN_RIGHT;
|
||||||
#define KAYAK_IN_HOLD_LEFT IN_LSTEP
|
constexpr auto KAYAK_IN_HOLD = IN_WALK;
|
||||||
#define KAYAK_IN_HOLD_RIGHT IN_RSTEP
|
constexpr auto KAYAK_IN_HOLD_LEFT = IN_LSTEP;
|
||||||
#define KAYAK_IN_DISMOUNT (IN_JUMP | IN_ROLL)
|
constexpr auto KAYAK_IN_HOLD_RIGHT = IN_RSTEP;
|
||||||
|
|
||||||
|
WAKE_PTS WakePts[NUM_WAKE_SPRITES][2];
|
||||||
|
|
||||||
enum KayakState
|
enum KayakState
|
||||||
{
|
{
|
||||||
|
@ -123,42 +148,18 @@ namespace TEN::Entities::Vehicles
|
||||||
KAYAK_ANIM_DISMOUNT_RIGHT = 32
|
KAYAK_ANIM_DISMOUNT_RIGHT = 32
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class KayakMountType
|
KayakInfo* GetKayakInfo(ItemInfo* kayakItem)
|
||||||
{
|
{
|
||||||
None,
|
return (KayakInfo*)kayakItem->Data;
|
||||||
Left,
|
}
|
||||||
Right
|
|
||||||
};
|
|
||||||
|
|
||||||
struct WAKE_PTS
|
|
||||||
{
|
|
||||||
int x[2];
|
|
||||||
int y;
|
|
||||||
int z[2];
|
|
||||||
short xvel[2];
|
|
||||||
short zvel[2];
|
|
||||||
byte life;
|
|
||||||
byte pad[3];
|
|
||||||
};
|
|
||||||
|
|
||||||
WAKE_PTS WakePts[NUM_WAKE_SPRITES][2];
|
|
||||||
|
|
||||||
void InitialiseKayak(short itemNumber)
|
void InitialiseKayak(short itemNumber)
|
||||||
{
|
{
|
||||||
auto* kayakItem = &g_Level.Items[itemNumber];
|
auto* kayakItem = &g_Level.Items[itemNumber];
|
||||||
kayakItem->Data = KayakInfo();
|
kayakItem->Data = KayakInfo();
|
||||||
auto* kayak = (KayakInfo*)kayakItem->Data;
|
auto* kayak = GetKayakInfo(kayakItem);
|
||||||
|
|
||||||
kayak->TurnRate = 0;
|
kayak->OldPose = kayakItem->Pose;
|
||||||
kayak->Velocity = 0;
|
|
||||||
kayak->FrontVerticalVelocity = 0;
|
|
||||||
kayak->LeftVerticalVelocity = 0;
|
|
||||||
kayak->RightVerticalVelocity = 0;
|
|
||||||
kayak->LeftRightCount = 0;
|
|
||||||
kayak->OldPos = kayakItem->Pose;
|
|
||||||
kayak->CurrentStartWake = 0;
|
|
||||||
kayak->WakeShade = 0;
|
|
||||||
kayak->Flags = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < NUM_WAKE_SPRITES; i++)
|
for (int i = 0; i < NUM_WAKE_SPRITES; i++)
|
||||||
{
|
{
|
||||||
|
@ -167,6 +168,72 @@ namespace TEN::Entities::Vehicles
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void KayakPlayerCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll)
|
||||||
|
{
|
||||||
|
auto* kayakItem = &g_Level.Items[itemNumber];
|
||||||
|
auto* kayak = GetKayakInfo(kayakItem);
|
||||||
|
auto* lara = GetLaraInfo(laraItem);
|
||||||
|
|
||||||
|
if (laraItem->HitPoints < 0 || lara->Vehicle != NO_ITEM)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto mountType = GetVehicleMountType(kayakItem, laraItem, coll, KayakMountTypes, KAYAK_MOUNT_DISTANCE, LARA_HEIGHT);
|
||||||
|
if (mountType == VehicleMountType::None)
|
||||||
|
{
|
||||||
|
coll->Setup.EnableObjectPush = true;
|
||||||
|
ObjectCollision(itemNumber, laraItem, coll);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lara->Vehicle = itemNumber;
|
||||||
|
DoKayakMount(kayakItem, laraItem, mountType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoKayakMount(ItemInfo* kayakItem, ItemInfo* laraItem, VehicleMountType mountType)
|
||||||
|
{
|
||||||
|
auto* kayak = GetKayakInfo(kayakItem);
|
||||||
|
auto* lara = GetLaraInfo(laraItem);
|
||||||
|
|
||||||
|
switch (mountType)
|
||||||
|
{
|
||||||
|
case VehicleMountType::LevelStart:
|
||||||
|
laraItem->Animation.AnimNumber = Objects[ID_KAYAK_LARA_ANIMS].animIndex + KAYAK_ANIM_IDLE;
|
||||||
|
laraItem->Animation.ActiveState = KAYAK_STATE_IDLE;
|
||||||
|
laraItem->Animation.TargetState = KAYAK_STATE_IDLE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VehicleMountType::Left:
|
||||||
|
laraItem->Animation.AnimNumber = Objects[ID_KAYAK_LARA_ANIMS].animIndex + KAYAK_ANIM_MOUNT_LEFT;
|
||||||
|
laraItem->Animation.ActiveState = KAYAK_STATE_MOUNT_LEFT;
|
||||||
|
laraItem->Animation.TargetState = KAYAK_STATE_MOUNT_LEFT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
case VehicleMountType::Right:
|
||||||
|
laraItem->Animation.AnimNumber = Objects[ID_KAYAK_LARA_ANIMS].animIndex + KAYAK_ANIM_MOUNT_RIGHT;
|
||||||
|
laraItem->Animation.ActiveState = KAYAK_STATE_MOUNT_RIGHT;
|
||||||
|
laraItem->Animation.TargetState = KAYAK_STATE_MOUNT_RIGHT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
laraItem->Animation.FrameNumber = g_Level.Anims[laraItem->Animation.AnimNumber].frameBase;
|
||||||
|
|
||||||
|
if (laraItem->RoomNumber != kayakItem->RoomNumber)
|
||||||
|
ItemNewRoom(lara->ItemNumber, kayakItem->RoomNumber);
|
||||||
|
|
||||||
|
DoVehicleFlareDiscard(laraItem);
|
||||||
|
laraItem->Pose.Position = kayakItem->Pose.Position;
|
||||||
|
laraItem->Pose.Orientation = Vector3Shrt(0, kayakItem->Pose.Orientation.y, 0);
|
||||||
|
laraItem->Animation.IsAirborne = false;
|
||||||
|
laraItem->Animation.Velocity = 0;
|
||||||
|
laraItem->Animation.VerticalVelocity = 0;
|
||||||
|
lara->Control.WaterStatus = WaterStatus::Dry;
|
||||||
|
kayak->WaterHeight = kayakItem->Pose.Position.y;
|
||||||
|
kayak->Flags = 0;
|
||||||
|
|
||||||
|
AnimateItem(laraItem);
|
||||||
|
}
|
||||||
|
|
||||||
void KayakDraw(ItemInfo* kayakItem)
|
void KayakDraw(ItemInfo* kayakItem)
|
||||||
{
|
{
|
||||||
DrawAnimatingItem(kayakItem);
|
DrawAnimatingItem(kayakItem);
|
||||||
|
@ -174,19 +241,19 @@ namespace TEN::Entities::Vehicles
|
||||||
|
|
||||||
void KayakDoWake(ItemInfo* kayakItem, int xOffset, int zOffset, short rotate)
|
void KayakDoWake(ItemInfo* kayakItem, int xOffset, int zOffset, short rotate)
|
||||||
{
|
{
|
||||||
auto* kayak = (KayakInfo*)kayakItem->Data;
|
auto* kayak = GetKayakInfo(kayakItem);
|
||||||
|
|
||||||
if (WakePts[kayak->CurrentStartWake][rotate].life)
|
if (WakePts[kayak->CurrentStartWake][rotate].life)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
float s = phd_sin(kayakItem->Pose.Orientation.y);
|
float sinY = phd_sin(kayakItem->Pose.Orientation.y);
|
||||||
float c = phd_cos(kayakItem->Pose.Orientation.y);
|
float cosY = phd_cos(kayakItem->Pose.Orientation.y);
|
||||||
|
|
||||||
int x = kayakItem->Pose.Position.x + zOffset * s + xOffset * c;
|
int x = kayakItem->Pose.Position.x + (zOffset * sinY) + (xOffset * cosY);
|
||||||
int z = kayakItem->Pose.Position.z + zOffset * c - xOffset * s;
|
int z = kayakItem->Pose.Position.z + (zOffset * cosY) - (xOffset * sinY);
|
||||||
|
|
||||||
int probedRoomNum = GetCollision(x, kayakItem->Pose.Position.y, z, kayakItem->RoomNumber).RoomNumber;
|
int probedRoomNumber = GetCollision(x, kayakItem->Pose.Position.y, z, kayakItem->RoomNumber).RoomNumber;
|
||||||
int waterHeight = GetWaterHeight(x, kayakItem->Pose.Position.y, z, probedRoomNum);
|
int waterHeight = GetWaterHeight(x, kayakItem->Pose.Position.y, z, probedRoomNumber);
|
||||||
|
|
||||||
if (waterHeight != NO_HEIGHT)
|
if (waterHeight != NO_HEIGHT)
|
||||||
{
|
{
|
||||||
|
@ -245,14 +312,14 @@ namespace TEN::Entities::Vehicles
|
||||||
|
|
||||||
void KayakDoRipple(ItemInfo* kayakItem, int xOffset, int zOffset)
|
void KayakDoRipple(ItemInfo* kayakItem, int xOffset, int zOffset)
|
||||||
{
|
{
|
||||||
float s = phd_sin(kayakItem->Pose.Orientation.y);
|
float sinY = phd_sin(kayakItem->Pose.Orientation.y);
|
||||||
float c = phd_cos(kayakItem->Pose.Orientation.y);
|
float cosY = phd_cos(kayakItem->Pose.Orientation.y);
|
||||||
|
|
||||||
int x = kayakItem->Pose.Position.x + zOffset * s + xOffset * c;
|
int x = kayakItem->Pose.Position.x + (zOffset * sinY) + (xOffset * cosY);
|
||||||
int z = kayakItem->Pose.Position.z + zOffset * c - xOffset * s;
|
int z = kayakItem->Pose.Position.z + (zOffset * cosY) - (xOffset * sinY);
|
||||||
|
|
||||||
int probedRoomNum = GetCollision(x, kayakItem->Pose.Position.y, z, kayakItem->RoomNumber).RoomNumber;
|
int probedRoomNumber = GetCollision(x, kayakItem->Pose.Position.y, z, kayakItem->RoomNumber).RoomNumber;
|
||||||
int waterHeight = GetWaterHeight(x, kayakItem->Pose.Position.y, z, probedRoomNum);
|
int waterHeight = GetWaterHeight(x, kayakItem->Pose.Position.y, z, probedRoomNumber);
|
||||||
|
|
||||||
//if (waterHeight != NO_HEIGHT)
|
//if (waterHeight != NO_HEIGHT)
|
||||||
// SetupRipple(x, kayakItem->Pose.Position.y, z, -2 - (GetRandomControl() & 1), 0, Objects[ID_KAYAK_PADDLE_TRAIL_SPRITE].meshIndex,TO_RAD(kayakItem->Pose.Orientation.y));
|
// SetupRipple(x, kayakItem->Pose.Position.y, z, -2 - (GetRandomControl() & 1), 0, Objects[ID_KAYAK_PADDLE_TRAIL_SPRITE].meshIndex,TO_RAD(kayakItem->Pose.Orientation.y));
|
||||||
|
@ -276,46 +343,6 @@ namespace TEN::Entities::Vehicles
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
KayakMountType KayakGetMountType(ItemInfo* laraItem, short itemNumber)
|
|
||||||
{
|
|
||||||
auto* lara = GetLaraInfo(laraItem);
|
|
||||||
auto* kayakItem = &g_Level.Items[itemNumber];
|
|
||||||
|
|
||||||
if (!(TrInput & IN_ACTION) ||
|
|
||||||
lara->Control.HandStatus != HandStatus::Free ||
|
|
||||||
laraItem->Animation.Airborne)
|
|
||||||
{
|
|
||||||
return KayakMountType::None;
|
|
||||||
}
|
|
||||||
|
|
||||||
int distance = pow(laraItem->Pose.Position.x - kayakItem->Pose.Position.x, 2) + pow(laraItem->Pose.Position.z - kayakItem->Pose.Position.z, 2);
|
|
||||||
if (distance > pow(360, 2))
|
|
||||||
return KayakMountType::None;
|
|
||||||
|
|
||||||
auto probe = GetCollision(kayakItem);
|
|
||||||
if (probe.Position.Floor > -32000)
|
|
||||||
{
|
|
||||||
short angle = phd_atan(kayakItem->Pose.Position.z - laraItem->Pose.Position.z, kayakItem->Pose.Position.x - laraItem->Pose.Position.x);
|
|
||||||
angle -= kayakItem->Pose.Orientation.y;
|
|
||||||
|
|
||||||
int deltaAngle = laraItem->Pose.Orientation.y - kayakItem->Pose.Orientation.y;
|
|
||||||
if (angle > -ANGLE(45.0f) && angle < ANGLE(135.0f))
|
|
||||||
{
|
|
||||||
deltaAngle = laraItem->Pose.Orientation.y - kayakItem->Pose.Orientation.y;
|
|
||||||
if (deltaAngle > ANGLE(45.0f) && deltaAngle < ANGLE(135.0f))
|
|
||||||
return KayakMountType::Left;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
deltaAngle = laraItem->Pose.Orientation.y - kayakItem->Pose.Orientation.y;
|
|
||||||
if (deltaAngle > ANGLE(225.0f) && deltaAngle < ANGLE(315.0f))
|
|
||||||
return KayakMountType::Right;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return KayakMountType::None;
|
|
||||||
}
|
|
||||||
|
|
||||||
int KayakGetCollisionAnim(ItemInfo* kayakItem, int xDiff, int zDiff)
|
int KayakGetCollisionAnim(ItemInfo* kayakItem, int xDiff, int zDiff)
|
||||||
{
|
{
|
||||||
xDiff = kayakItem->Pose.Position.x - xDiff;
|
xDiff = kayakItem->Pose.Position.x - xDiff;
|
||||||
|
@ -378,10 +405,10 @@ namespace TEN::Entities::Vehicles
|
||||||
return verticalVelocity;
|
return verticalVelocity;
|
||||||
}
|
}
|
||||||
|
|
||||||
void KayakDoCurrent(ItemInfo* laraItem, ItemInfo* kayakItem)
|
void KayakDoCurrent(ItemInfo* kayakItem, ItemInfo* laraItem)
|
||||||
{
|
{
|
||||||
auto* lara = GetLaraInfo(laraItem);
|
auto* lara = GetLaraInfo(laraItem);
|
||||||
auto* room = &g_Level.Rooms[kayakItem->RoomNumber];
|
auto* room = &g_Level.Rooms[kayakItem->RoomNumber]; // Unused.
|
||||||
|
|
||||||
if (!lara->WaterCurrentActive)
|
if (!lara->WaterCurrentActive)
|
||||||
{
|
{
|
||||||
|
@ -439,37 +466,10 @@ namespace TEN::Entities::Vehicles
|
||||||
lara->WaterCurrentActive = 0;
|
lara->WaterCurrentActive = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int KayakTestHeight(ItemInfo* kayakItem, int x, int z, Vector3Int* pos)
|
bool KayakCanGetOut(ItemInfo* kayakItem, int direction)
|
||||||
{
|
|
||||||
Matrix world =
|
|
||||||
Matrix::CreateFromYawPitchRoll(TO_RAD(kayakItem->Pose.Orientation.y), TO_RAD(kayakItem->Pose.Orientation.x), TO_RAD(kayakItem->Pose.Orientation.z)) *
|
|
||||||
Matrix::CreateTranslation(kayakItem->Pose.Position.x, kayakItem->Pose.Position.y, kayakItem->Pose.Position.z);
|
|
||||||
|
|
||||||
Vector3 vec = Vector3(x, 0, z);
|
|
||||||
vec = Vector3::Transform(vec, world);
|
|
||||||
|
|
||||||
pos->x = vec.x;
|
|
||||||
pos->y = vec.y;
|
|
||||||
pos->z = vec.z;
|
|
||||||
|
|
||||||
auto probe = GetCollision(pos->x, pos->y, pos->z, kayakItem->RoomNumber);
|
|
||||||
int probedRoomNum = probe.RoomNumber;
|
|
||||||
|
|
||||||
int height = GetWaterHeight(pos->x, pos->y, pos->z, probedRoomNum);
|
|
||||||
if (height == NO_HEIGHT)
|
|
||||||
{
|
|
||||||
height = probe.Position.Floor;
|
|
||||||
if (height == NO_HEIGHT)
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (height - 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool KayakCanGetOut(ItemInfo* kayakItem, int dir)
|
|
||||||
{
|
{
|
||||||
Vector3Int pos;
|
Vector3Int pos;
|
||||||
int height = KayakTestHeight(kayakItem, (dir < 0) ? -DISMOUNT_DISTANCE : DISMOUNT_DISTANCE, 0, &pos);
|
int height = GetVehicleWaterHeight(kayakItem, 0, (direction < 0) ? -KAYAK_DISMOUNT_DISTANCE : KAYAK_DISMOUNT_DISTANCE, false, &pos);
|
||||||
|
|
||||||
if ((kayakItem->Pose.Position.y - height) > 0)
|
if ((kayakItem->Pose.Position.y - height) > 0)
|
||||||
return false;
|
return false;
|
||||||
|
@ -580,43 +580,37 @@ namespace TEN::Entities::Vehicles
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void KayakToBackground(ItemInfo* laraItem, ItemInfo* kayakItem)
|
void KayakToBackground(ItemInfo* kayakItem, ItemInfo* laraItem)
|
||||||
{
|
{
|
||||||
auto* kayak = (KayakInfo*)kayakItem->Data;
|
auto* kayak = GetKayakInfo(kayakItem);
|
||||||
|
|
||||||
kayak->OldPos = kayakItem->Pose;
|
kayak->OldPose = kayakItem->Pose;
|
||||||
|
|
||||||
Vector3Int oldPos[9];
|
Vector3Int oldPos[9];
|
||||||
int height[8];
|
int height[8];
|
||||||
height[0] = KayakTestHeight(kayakItem, 0, 1024, &oldPos[0]);
|
height[0] = GetVehicleWaterHeight(kayakItem, 1024, 0, true, &oldPos[0]);
|
||||||
height[1] = KayakTestHeight(kayakItem, -96, 512, &oldPos[1]);
|
height[1] = GetVehicleWaterHeight(kayakItem, 512, -96, true, &oldPos[1]);
|
||||||
height[2] = KayakTestHeight(kayakItem, 96, 512, &oldPos[2]);
|
height[2] = GetVehicleWaterHeight(kayakItem, 512, 96, true, &oldPos[2]);
|
||||||
height[3] = KayakTestHeight(kayakItem, -128, 128, &oldPos[3]);
|
height[3] = GetVehicleWaterHeight(kayakItem, 128, -128, true, &oldPos[3]);
|
||||||
height[4] = KayakTestHeight(kayakItem, 128, 128, &oldPos[4]);
|
height[4] = GetVehicleWaterHeight(kayakItem, 128, 128, true, &oldPos[4]);
|
||||||
height[5] = KayakTestHeight(kayakItem, -128, -320, &oldPos[5]);
|
height[5] = GetVehicleWaterHeight(kayakItem, -320, -128, true, &oldPos[5]);
|
||||||
height[6] = KayakTestHeight(kayakItem, 128, -320, &oldPos[6]);
|
height[6] = GetVehicleWaterHeight(kayakItem, -320, 128, true, &oldPos[6]);
|
||||||
height[7] = KayakTestHeight(kayakItem, 0, -640, &oldPos[7]);
|
height[7] = GetVehicleWaterHeight(kayakItem, -640, 0, true, &oldPos[7]);
|
||||||
|
|
||||||
for (int i = 0; i < 8; i++)
|
|
||||||
{
|
|
||||||
if (oldPos[i].y > height[i])
|
|
||||||
oldPos[i].y = height[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
oldPos[8].x = kayakItem->Pose.Position.x;
|
oldPos[8].x = kayakItem->Pose.Position.x;
|
||||||
oldPos[8].y = kayakItem->Pose.Position.y;
|
oldPos[8].y = kayakItem->Pose.Position.y;
|
||||||
oldPos[8].z = kayakItem->Pose.Position.z;
|
oldPos[8].z = kayakItem->Pose.Position.z;
|
||||||
|
|
||||||
Vector3Int frontPos, leftPos, rightPos;
|
Vector3Int frontPos, leftPos, rightPos;
|
||||||
int frontHeight = KayakTestHeight(kayakItem, 0, 1024, &frontPos);
|
int frontHeight = GetVehicleWaterHeight(kayakItem, 1024, 0, false, &frontPos);
|
||||||
int leftHeight = KayakTestHeight(kayakItem, -KAYAK_X, KAYAK_Z, &leftPos);
|
int leftHeight = GetVehicleWaterHeight(kayakItem, KAYAK_Z, -KAYAK_X, false, &leftPos);
|
||||||
int rightHeight = KayakTestHeight(kayakItem, KAYAK_X, KAYAK_Z, &rightPos);
|
int rightHeight = GetVehicleWaterHeight(kayakItem, KAYAK_Z, KAYAK_X, false, &rightPos);
|
||||||
|
|
||||||
kayakItem->Pose.Orientation.y += kayak->TurnRate / (USHRT_MAX + 1);
|
|
||||||
kayakItem->Pose.Position.x += kayakItem->Animation.Velocity * phd_sin(kayakItem->Pose.Orientation.y);
|
kayakItem->Pose.Position.x += kayakItem->Animation.Velocity * phd_sin(kayakItem->Pose.Orientation.y);
|
||||||
kayakItem->Pose.Position.z += kayakItem->Animation.Velocity * phd_cos(kayakItem->Pose.Orientation.y);
|
kayakItem->Pose.Position.z += kayakItem->Animation.Velocity * phd_cos(kayakItem->Pose.Orientation.y);
|
||||||
|
kayakItem->Pose.Orientation.y += kayak->TurnRate;
|
||||||
|
|
||||||
KayakDoCurrent(laraItem,kayakItem);
|
KayakDoCurrent(kayakItem, laraItem);
|
||||||
|
|
||||||
kayak->LeftVerticalVelocity = KayakDoDynamics(leftHeight, kayak->LeftVerticalVelocity, &leftPos.y);
|
kayak->LeftVerticalVelocity = KayakDoDynamics(leftHeight, kayak->LeftVerticalVelocity, &leftPos.y);
|
||||||
kayak->RightVerticalVelocity = KayakDoDynamics(rightHeight, kayak->RightVerticalVelocity, &rightPos.y);
|
kayak->RightVerticalVelocity = KayakDoDynamics(rightHeight, kayak->RightVerticalVelocity, &rightPos.y);
|
||||||
|
@ -637,28 +631,28 @@ namespace TEN::Entities::Vehicles
|
||||||
int rot = 0;
|
int rot = 0;
|
||||||
Vector3Int pos;
|
Vector3Int pos;
|
||||||
|
|
||||||
if ((height2 = KayakTestHeight(kayakItem, 0, -CLICK(2.5f), &pos)) < (oldPos[7].y - KAYAK_COLLIDE))
|
if ((height2 = GetVehicleWaterHeight(kayakItem, -CLICK(2.5f), 0, false, &pos)) < (oldPos[7].y - KAYAK_COLLIDE))
|
||||||
rot = KayakDoShift(kayakItem, &pos, &oldPos[7]);
|
rot = KayakDoShift(kayakItem, &pos, &oldPos[7]);
|
||||||
|
|
||||||
if ((height2 = KayakTestHeight(kayakItem, CLICK(0.5f), -CLICK(1.25f), &pos)) < (oldPos[6].y - KAYAK_COLLIDE))
|
if ((height2 = GetVehicleWaterHeight(kayakItem, -CLICK(1.25f), CLICK(0.5f), false, &pos)) < (oldPos[6].y - KAYAK_COLLIDE))
|
||||||
rot += KayakDoShift(kayakItem, &pos, &oldPos[6]);
|
rot += KayakDoShift(kayakItem, &pos, &oldPos[6]);
|
||||||
|
|
||||||
if ((height2 = KayakTestHeight(kayakItem, -CLICK(0.5f), -CLICK(1.25f), &pos)) < (oldPos[5].y - KAYAK_COLLIDE))
|
if ((height2 = GetVehicleWaterHeight(kayakItem, -CLICK(1.25f), -CLICK(0.5f), false, &pos)) < (oldPos[5].y - KAYAK_COLLIDE))
|
||||||
rot += KayakDoShift(kayakItem, &pos, &oldPos[5]);
|
rot += KayakDoShift(kayakItem, &pos, &oldPos[5]);
|
||||||
|
|
||||||
if ((height2 = KayakTestHeight(kayakItem, CLICK(0.5f), CLICK(0.5f), &pos)) < (oldPos[4].y - KAYAK_COLLIDE))
|
if ((height2 = GetVehicleWaterHeight(kayakItem, CLICK(0.5f), CLICK(0.5f), false, &pos)) < (oldPos[4].y - KAYAK_COLLIDE))
|
||||||
rot += KayakDoShift(kayakItem, &pos, &oldPos[4]);
|
rot += KayakDoShift(kayakItem, &pos, &oldPos[4]);
|
||||||
|
|
||||||
if ((height2 = KayakTestHeight(kayakItem, -CLICK(0.5f), CLICK(0.5f), &pos)) < (oldPos[3].y - KAYAK_COLLIDE))
|
if ((height2 = GetVehicleWaterHeight(kayakItem, CLICK(0.5f), -CLICK(0.5f), false, &pos)) < (oldPos[3].y - KAYAK_COLLIDE))
|
||||||
rot += KayakDoShift(kayakItem, &pos, &oldPos[3]);
|
rot += KayakDoShift(kayakItem, &pos, &oldPos[3]);
|
||||||
|
|
||||||
if ((height2 = KayakTestHeight(kayakItem, 96, CLICK(2), &pos)) < (oldPos[2].y - KAYAK_COLLIDE))
|
if ((height2 = GetVehicleWaterHeight(kayakItem, CLICK(2), 96, false, &pos)) < (oldPos[2].y - KAYAK_COLLIDE))
|
||||||
rot += KayakDoShift(kayakItem, &pos, &oldPos[2]);
|
rot += KayakDoShift(kayakItem, &pos, &oldPos[2]);
|
||||||
|
|
||||||
if ((height2 = KayakTestHeight(kayakItem, -96, CLICK(2), &pos)) < (oldPos[1].y - KAYAK_COLLIDE))
|
if ((height2 = GetVehicleWaterHeight(kayakItem, CLICK(2), -96, false, &pos)) < (oldPos[1].y - KAYAK_COLLIDE))
|
||||||
rot += KayakDoShift(kayakItem, &pos, &oldPos[1]);
|
rot += KayakDoShift(kayakItem, &pos, &oldPos[1]);
|
||||||
|
|
||||||
if ((height2 = KayakTestHeight(kayakItem, 0, CLICK(4), &pos)) < (oldPos[0].y - KAYAK_COLLIDE))
|
if ((height2 = GetVehicleWaterHeight(kayakItem, CLICK(4), 0, false, &pos)) < (oldPos[0].y - KAYAK_COLLIDE))
|
||||||
rot += KayakDoShift(kayakItem, &pos, &oldPos[0]);
|
rot += KayakDoShift(kayakItem, &pos, &oldPos[0]);
|
||||||
|
|
||||||
kayakItem->Pose.Orientation.y += rot;
|
kayakItem->Pose.Orientation.y += rot;
|
||||||
|
@ -683,9 +677,9 @@ namespace TEN::Entities::Vehicles
|
||||||
if (height2 == NO_HEIGHT)
|
if (height2 == NO_HEIGHT)
|
||||||
{
|
{
|
||||||
GameVector kayakPos;
|
GameVector kayakPos;
|
||||||
kayakPos.x = kayak->OldPos.Position.x;
|
kayakPos.x = kayak->OldPose.Position.x;
|
||||||
kayakPos.y = kayak->OldPos.Position.y;
|
kayakPos.y = kayak->OldPose.Position.y;
|
||||||
kayakPos.z = kayak->OldPos.Position.z;
|
kayakPos.z = kayak->OldPose.Position.z;
|
||||||
kayakPos.roomNumber = kayakItem->RoomNumber;
|
kayakPos.roomNumber = kayakItem->RoomNumber;
|
||||||
|
|
||||||
CameraCollisionBounds(&kayakPos, 256, 0);
|
CameraCollisionBounds(&kayakPos, 256, 0);
|
||||||
|
@ -707,11 +701,11 @@ namespace TEN::Entities::Vehicles
|
||||||
int newVelocity;
|
int newVelocity;
|
||||||
|
|
||||||
newVelocity = (kayakItem->Pose.Position.z - oldPos[8].z) * phd_cos(kayakItem->Pose.Orientation.y) + (kayakItem->Pose.Position.x - oldPos[8].x) * phd_sin(kayakItem->Pose.Orientation.y);
|
newVelocity = (kayakItem->Pose.Position.z - oldPos[8].z) * phd_cos(kayakItem->Pose.Orientation.y) + (kayakItem->Pose.Position.x - oldPos[8].x) * phd_sin(kayakItem->Pose.Orientation.y);
|
||||||
newVelocity *= 256;
|
newVelocity *= VEHICLE_VELOCITY_SCALE;
|
||||||
|
|
||||||
if (slip)
|
if (slip)
|
||||||
{
|
{
|
||||||
if (kayak->Velocity <= MAX_VELOCITY)
|
if (kayak->Velocity <= KAYAK_VELOCITY_MAX)
|
||||||
kayak->Velocity = newVelocity;
|
kayak->Velocity = newVelocity;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -723,15 +717,15 @@ namespace TEN::Entities::Vehicles
|
||||||
kayak->Velocity = newVelocity;
|
kayak->Velocity = newVelocity;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kayak->Velocity < -MAX_VELOCITY)
|
if (kayak->Velocity < -KAYAK_VELOCITY_MAX)
|
||||||
kayak->Velocity = -MAX_VELOCITY;
|
kayak->Velocity = -KAYAK_VELOCITY_MAX;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KayakUserInput(ItemInfo* laraItem, ItemInfo* kayakItem)
|
void KayakUserInput(ItemInfo* kayakItem, ItemInfo* laraItem)
|
||||||
{
|
{
|
||||||
|
auto* kayak = GetKayakInfo(kayakItem);
|
||||||
auto* lara = GetLaraInfo(laraItem);
|
auto* lara = GetLaraInfo(laraItem);
|
||||||
auto* kayak = (KayakInfo*)kayakItem->Data;
|
|
||||||
|
|
||||||
if (laraItem->HitPoints <= 0 &&
|
if (laraItem->HitPoints <= 0 &&
|
||||||
laraItem->Animation.ActiveState != KAYAK_STATE_IDLE_DEATH)
|
laraItem->Animation.ActiveState != KAYAK_STATE_IDLE_DEATH)
|
||||||
|
@ -746,7 +740,7 @@ namespace TEN::Entities::Vehicles
|
||||||
switch (laraItem->Animation.ActiveState)
|
switch (laraItem->Animation.ActiveState)
|
||||||
{
|
{
|
||||||
case KAYAK_STATE_IDLE:
|
case KAYAK_STATE_IDLE:
|
||||||
if (TrInput & KAYAK_IN_DISMOUNT &&
|
if (TrInput & VEHICLE_IN_DISMOUNT &&
|
||||||
!lara->WaterCurrentActive &&
|
!lara->WaterCurrentActive &&
|
||||||
!lara->WaterCurrentPull.x && !lara->WaterCurrentPull.z)
|
!lara->WaterCurrentPull.x && !lara->WaterCurrentPull.z)
|
||||||
{
|
{
|
||||||
|
@ -811,20 +805,20 @@ namespace TEN::Entities::Vehicles
|
||||||
if (kayak->Forward)
|
if (kayak->Forward)
|
||||||
{
|
{
|
||||||
if (!frame)
|
if (!frame)
|
||||||
kayak->LeftRightCount = 0;
|
kayak->LeftRightPaddleCount = 0;
|
||||||
|
|
||||||
// TODO: Sort out the bitwise operations.
|
// TODO: Sort out the bitwise operations.
|
||||||
if (frame == 2 && !(kayak->LeftRightCount & 0x80))
|
if (frame == 2 && !(kayak->LeftRightPaddleCount & 0x80))
|
||||||
kayak->LeftRightCount++;
|
kayak->LeftRightPaddleCount++;
|
||||||
|
|
||||||
else if (frame > 2)
|
else if (frame > 2)
|
||||||
kayak->LeftRightCount &= ~0x80;
|
kayak->LeftRightPaddleCount &= ~0x80;
|
||||||
|
|
||||||
if (TrInput & KAYAK_IN_FORWARD)
|
if (TrInput & KAYAK_IN_FORWARD)
|
||||||
{
|
{
|
||||||
if (TrInput & KAYAK_IN_LEFT && !(TrInput & KAYAK_IN_HOLD))
|
if (TrInput & KAYAK_IN_LEFT && !(TrInput & KAYAK_IN_HOLD))
|
||||||
{
|
{
|
||||||
if ((kayak->LeftRightCount & ~0x80) >= 2)
|
if ((kayak->LeftRightPaddleCount & ~0x80) >= 2)
|
||||||
laraItem->Animation.TargetState = KAYAK_STATE_TURN_RIGHT;
|
laraItem->Animation.TargetState = KAYAK_STATE_TURN_RIGHT;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -840,25 +834,25 @@ namespace TEN::Entities::Vehicles
|
||||||
{
|
{
|
||||||
if (kayak->Forward)
|
if (kayak->Forward)
|
||||||
{
|
{
|
||||||
kayak->TurnRate -= KAYAK_FORWARD_ROTATION;
|
kayak->TurnRate -= KAYAK_TURN_RATE_FORWARD_ACCEL;
|
||||||
if (kayak->TurnRate < -KAYAK_MAX_TURN)
|
if (kayak->TurnRate < -KAYAK_TURN_RATE_MAX)
|
||||||
kayak->TurnRate = -KAYAK_MAX_TURN;
|
kayak->TurnRate = -KAYAK_TURN_RATE_MAX;
|
||||||
|
|
||||||
kayak->Velocity += KAYAK_FORWARD_VELOCITY;
|
kayak->Velocity += KAYAK_VELOCITY_FORWARD_ACCEL;
|
||||||
}
|
}
|
||||||
else if (kayak->Turn)
|
else if (kayak->Turn)
|
||||||
{
|
{
|
||||||
kayak->TurnRate -= KAYAK_HARD_ROTATION;
|
kayak->TurnRate -= KAYAK_TURN_RATE_HOLD_ACCEL;
|
||||||
if (kayak->TurnRate < -KAYAK_MAX_STAT)
|
if (kayak->TurnRate < -KAYAK_TURN_RATE_HOLD_MAX)
|
||||||
kayak->TurnRate = -KAYAK_MAX_STAT;
|
kayak->TurnRate = -KAYAK_TURN_RATE_HOLD_MAX;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
kayak->TurnRate -= KAYAK_LEFT_RIGHT_ROTATION;
|
kayak->TurnRate -= KAYAK_TURN_RATE_LR_ACCEL;
|
||||||
if (kayak->TurnRate < -KAYAK_MAX_LEFT_RIGHT)
|
if (kayak->TurnRate < -KAYAK_TURN_RATE_LR_MAX)
|
||||||
kayak->TurnRate = -KAYAK_MAX_LEFT_RIGHT;
|
kayak->TurnRate = -KAYAK_TURN_RATE_LR_MAX;
|
||||||
|
|
||||||
kayak->Velocity += KAYAK_LEFT_RIGHT_VELOCITY;
|
kayak->Velocity += KAYAK_VELOCITY_LR_ACCEL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -871,19 +865,19 @@ namespace TEN::Entities::Vehicles
|
||||||
if (kayak->Forward)
|
if (kayak->Forward)
|
||||||
{
|
{
|
||||||
if (!frame)
|
if (!frame)
|
||||||
kayak->LeftRightCount = 0;
|
kayak->LeftRightPaddleCount = 0;
|
||||||
|
|
||||||
if (frame == 2 && !(kayak->LeftRightCount & 0x80))
|
if (frame == 2 && !(kayak->LeftRightPaddleCount & 0x80))
|
||||||
kayak->LeftRightCount++;
|
kayak->LeftRightPaddleCount++;
|
||||||
|
|
||||||
else if (frame > 2)
|
else if (frame > 2)
|
||||||
kayak->LeftRightCount &= ~0x80;
|
kayak->LeftRightPaddleCount &= ~0x80;
|
||||||
|
|
||||||
if (TrInput & KAYAK_IN_FORWARD)
|
if (TrInput & KAYAK_IN_FORWARD)
|
||||||
{
|
{
|
||||||
if (TrInput & KAYAK_IN_RIGHT && !(TrInput & KAYAK_IN_HOLD))
|
if (TrInput & KAYAK_IN_RIGHT && !(TrInput & KAYAK_IN_HOLD))
|
||||||
{
|
{
|
||||||
if ((kayak->LeftRightCount & ~0x80) >= 2)
|
if ((kayak->LeftRightPaddleCount & ~0x80) >= 2)
|
||||||
laraItem->Animation.TargetState = KAYAK_STATE_TURN_LEFT;
|
laraItem->Animation.TargetState = KAYAK_STATE_TURN_LEFT;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -900,25 +894,25 @@ namespace TEN::Entities::Vehicles
|
||||||
{
|
{
|
||||||
if (kayak->Forward)
|
if (kayak->Forward)
|
||||||
{
|
{
|
||||||
kayak->TurnRate += KAYAK_FORWARD_ROTATION;
|
kayak->TurnRate += KAYAK_TURN_RATE_FORWARD_ACCEL;
|
||||||
if (kayak->TurnRate > KAYAK_MAX_TURN)
|
if (kayak->TurnRate > KAYAK_TURN_RATE_MAX)
|
||||||
kayak->TurnRate = KAYAK_MAX_TURN;
|
kayak->TurnRate = KAYAK_TURN_RATE_MAX;
|
||||||
|
|
||||||
kayak->Velocity += KAYAK_FORWARD_VELOCITY;
|
kayak->Velocity += KAYAK_VELOCITY_FORWARD_ACCEL;
|
||||||
}
|
}
|
||||||
else if (kayak->Turn)
|
else if (kayak->Turn)
|
||||||
{
|
{
|
||||||
kayak->TurnRate += KAYAK_HARD_ROTATION;
|
kayak->TurnRate += KAYAK_TURN_RATE_HOLD_ACCEL;
|
||||||
if (kayak->TurnRate > KAYAK_MAX_STAT)
|
if (kayak->TurnRate > KAYAK_TURN_RATE_HOLD_MAX)
|
||||||
kayak->TurnRate = KAYAK_MAX_STAT;
|
kayak->TurnRate = KAYAK_TURN_RATE_HOLD_MAX;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
kayak->TurnRate += KAYAK_LEFT_RIGHT_ROTATION;
|
kayak->TurnRate += KAYAK_TURN_RATE_LR_ACCEL;
|
||||||
if (kayak->TurnRate > KAYAK_MAX_LEFT_RIGHT)
|
if (kayak->TurnRate > KAYAK_TURN_RATE_LR_MAX)
|
||||||
kayak->TurnRate = KAYAK_MAX_LEFT_RIGHT;
|
kayak->TurnRate = KAYAK_TURN_RATE_LR_MAX;
|
||||||
|
|
||||||
kayak->Velocity += KAYAK_LEFT_RIGHT_VELOCITY;
|
kayak->Velocity += KAYAK_VELOCITY_LR_ACCEL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -935,14 +929,14 @@ namespace TEN::Entities::Vehicles
|
||||||
{
|
{
|
||||||
if (frame == 8)
|
if (frame == 8)
|
||||||
{
|
{
|
||||||
kayak->TurnRate += KAYAK_FORWARD_ROTATION;
|
kayak->TurnRate += KAYAK_TURN_RATE_FORWARD_ACCEL;
|
||||||
kayak->Velocity -= KAYAK_FORWARD_VELOCITY;
|
kayak->Velocity -= KAYAK_VELOCITY_FORWARD_ACCEL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frame == 31)
|
if (frame == 31)
|
||||||
{
|
{
|
||||||
kayak->TurnRate -= KAYAK_FORWARD_ROTATION;
|
kayak->TurnRate -= KAYAK_TURN_RATE_FORWARD_ACCEL;
|
||||||
kayak->Velocity -= KAYAK_FORWARD_VELOCITY;
|
kayak->Velocity -= KAYAK_VELOCITY_FORWARD_ACCEL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frame < 15 && frame & 1)
|
if (frame < 15 && frame & 1)
|
||||||
|
@ -967,10 +961,10 @@ namespace TEN::Entities::Vehicles
|
||||||
if (kayak->Velocity >= 0)
|
if (kayak->Velocity >= 0)
|
||||||
{
|
{
|
||||||
kayak->TurnRate -= KAYAK_TURN_ROTATION;
|
kayak->TurnRate -= KAYAK_TURN_ROTATION;
|
||||||
if (kayak->TurnRate < -KAYAK_MAX_TURN)
|
if (kayak->TurnRate < -KAYAK_TURN_RATE_MAX)
|
||||||
kayak->TurnRate = -KAYAK_MAX_TURN;
|
kayak->TurnRate = -KAYAK_TURN_RATE_MAX;
|
||||||
|
|
||||||
kayak->Velocity += -KAYAK_TURN_BRAKE;
|
kayak->Velocity += -KAYAK_VELOCITY_HOLD_TURN_DECEL;
|
||||||
if (kayak->Velocity < 0)
|
if (kayak->Velocity < 0)
|
||||||
kayak->Velocity = 0;
|
kayak->Velocity = 0;
|
||||||
}
|
}
|
||||||
|
@ -979,7 +973,7 @@ namespace TEN::Entities::Vehicles
|
||||||
{
|
{
|
||||||
kayak->TurnRate += KAYAK_TURN_ROTATION;
|
kayak->TurnRate += KAYAK_TURN_ROTATION;
|
||||||
|
|
||||||
kayak->Velocity += KAYAK_TURN_BRAKE;
|
kayak->Velocity += KAYAK_VELOCITY_HOLD_TURN_DECEL;
|
||||||
if (kayak->Velocity > 0)
|
if (kayak->Velocity > 0)
|
||||||
kayak->Velocity = 0;
|
kayak->Velocity = 0;
|
||||||
}
|
}
|
||||||
|
@ -1003,10 +997,10 @@ namespace TEN::Entities::Vehicles
|
||||||
if (kayak->Velocity >= 0)
|
if (kayak->Velocity >= 0)
|
||||||
{
|
{
|
||||||
kayak->TurnRate += KAYAK_TURN_ROTATION;
|
kayak->TurnRate += KAYAK_TURN_ROTATION;
|
||||||
if (kayak->TurnRate > KAYAK_MAX_TURN)
|
if (kayak->TurnRate > KAYAK_TURN_RATE_MAX)
|
||||||
kayak->TurnRate = KAYAK_MAX_TURN;
|
kayak->TurnRate = KAYAK_TURN_RATE_MAX;
|
||||||
|
|
||||||
kayak->Velocity += -KAYAK_TURN_BRAKE;
|
kayak->Velocity += -KAYAK_VELOCITY_HOLD_TURN_DECEL;
|
||||||
if (kayak->Velocity < 0)
|
if (kayak->Velocity < 0)
|
||||||
kayak->Velocity = 0;
|
kayak->Velocity = 0;
|
||||||
}
|
}
|
||||||
|
@ -1015,7 +1009,7 @@ namespace TEN::Entities::Vehicles
|
||||||
{
|
{
|
||||||
kayak->TurnRate -= KAYAK_TURN_ROTATION;
|
kayak->TurnRate -= KAYAK_TURN_ROTATION;
|
||||||
|
|
||||||
kayak->Velocity += KAYAK_TURN_BRAKE;
|
kayak->Velocity += KAYAK_VELOCITY_HOLD_TURN_DECEL;
|
||||||
if (kayak->Velocity > 0)
|
if (kayak->Velocity > 0)
|
||||||
kayak->Velocity = 0;
|
kayak->Velocity = 0;
|
||||||
}
|
}
|
||||||
|
@ -1033,7 +1027,7 @@ namespace TEN::Entities::Vehicles
|
||||||
{
|
{
|
||||||
kayak->Flags |= 0x80;
|
kayak->Flags |= 0x80;
|
||||||
lara->MeshPtrs[LM_RHAND] = Objects[ID_KAYAK_LARA_ANIMS].meshIndex + LM_RHAND;
|
lara->MeshPtrs[LM_RHAND] = Objects[ID_KAYAK_LARA_ANIMS].meshIndex + LM_RHAND;
|
||||||
laraItem->MeshBits &= ~LARA_LEG_BITS;
|
laraItem->ClearBits(JointBitType::Mesh, KayakLaraLegJoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -1045,7 +1039,7 @@ namespace TEN::Entities::Vehicles
|
||||||
{
|
{
|
||||||
kayak->Flags &= ~0x80;
|
kayak->Flags &= ~0x80;
|
||||||
lara->MeshPtrs[LM_RHAND] = Objects[ID_LARA_SKIN].meshIndex + LM_RHAND;
|
lara->MeshPtrs[LM_RHAND] = Objects[ID_LARA_SKIN].meshIndex + LM_RHAND;
|
||||||
laraItem->MeshBits |= LARA_LEG_BITS;
|
laraItem->SetBits(JointBitType::Mesh, KayakLaraLegJoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
laraItem->Animation.TargetState = laraItem->Animation.RequiredState;
|
laraItem->Animation.TargetState = laraItem->Animation.RequiredState;
|
||||||
|
@ -1059,18 +1053,16 @@ namespace TEN::Entities::Vehicles
|
||||||
GetLaraJointPosition(&vec, LM_HIPS);
|
GetLaraJointPosition(&vec, LM_HIPS);
|
||||||
|
|
||||||
SetAnimation(laraItem, LA_JUMP_FORWARD);
|
SetAnimation(laraItem, LA_JUMP_FORWARD);
|
||||||
laraItem->Pose.Position.x = vec.x;
|
laraItem->Pose.Position = vec;
|
||||||
laraItem->Pose.Position.y = vec.y;
|
|
||||||
laraItem->Pose.Position.z = vec.z;
|
|
||||||
laraItem->Pose.Orientation.x = 0;
|
laraItem->Pose.Orientation.x = 0;
|
||||||
laraItem->Pose.Orientation.y = kayakItem->Pose.Orientation.y - ANGLE(90.0f);
|
laraItem->Pose.Orientation.y = kayakItem->Pose.Orientation.y - ANGLE(90.0f);
|
||||||
laraItem->Pose.Orientation.z = 0;
|
laraItem->Pose.Orientation.z = 0;
|
||||||
laraItem->Animation.Velocity = 40;
|
laraItem->Animation.Velocity = 40;
|
||||||
laraItem->Animation.VerticalVelocity = -50;
|
laraItem->Animation.VerticalVelocity = -50;
|
||||||
laraItem->Animation.Airborne = true;
|
laraItem->Animation.IsAirborne = true;
|
||||||
lara->Control.HandStatus = HandStatus::Free;
|
lara->Control.HandStatus = HandStatus::Free;
|
||||||
lara->Vehicle = NO_ITEM;
|
lara->Vehicle = NO_ITEM;
|
||||||
kayak->LeftRightCount = 0;
|
kayak->LeftRightPaddleCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -1083,56 +1075,54 @@ namespace TEN::Entities::Vehicles
|
||||||
GetLaraJointPosition(&vec, LM_HIPS);
|
GetLaraJointPosition(&vec, LM_HIPS);
|
||||||
|
|
||||||
SetAnimation(laraItem, LA_JUMP_FORWARD);
|
SetAnimation(laraItem, LA_JUMP_FORWARD);
|
||||||
laraItem->Pose.Position.x = vec.x;
|
laraItem->Pose.Position = vec;
|
||||||
laraItem->Pose.Position.y = vec.y;
|
|
||||||
laraItem->Pose.Position.z = vec.z;
|
|
||||||
laraItem->Pose.Orientation.x = 0;
|
laraItem->Pose.Orientation.x = 0;
|
||||||
laraItem->Pose.Orientation.y = kayakItem->Pose.Orientation.y + ANGLE(90.0f);
|
laraItem->Pose.Orientation.y = kayakItem->Pose.Orientation.y + ANGLE(90.0f);
|
||||||
laraItem->Pose.Orientation.z = 0;
|
laraItem->Pose.Orientation.z = 0;
|
||||||
|
laraItem->Animation.IsAirborne = true;
|
||||||
laraItem->Animation.Velocity = 40;
|
laraItem->Animation.Velocity = 40;
|
||||||
laraItem->Animation.VerticalVelocity = -50;
|
laraItem->Animation.VerticalVelocity = -50;
|
||||||
laraItem->Animation.Airborne = true;
|
|
||||||
lara->Control.HandStatus = HandStatus::Free;
|
lara->Control.HandStatus = HandStatus::Free;
|
||||||
lara->Vehicle = NO_ITEM;
|
lara->Vehicle = NO_ITEM;
|
||||||
kayak->LeftRightCount = 0;
|
kayak->LeftRightPaddleCount = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kayak->Velocity > 0)
|
if (kayak->Velocity > 0)
|
||||||
{
|
{
|
||||||
kayak->Velocity -= KAYAK_FRICTION;
|
kayak->Velocity -= KAYAK_VELOCITY_FRICTION_DECEL;
|
||||||
if (kayak->Velocity < 0)
|
if (kayak->Velocity < 0)
|
||||||
kayak->Velocity = 0;
|
kayak->Velocity = 0;
|
||||||
}
|
}
|
||||||
else if (kayak->Velocity < 0)
|
else if (kayak->Velocity < 0)
|
||||||
{
|
{
|
||||||
kayak->Velocity += KAYAK_FRICTION;
|
kayak->Velocity += KAYAK_VELOCITY_FRICTION_DECEL;
|
||||||
if (kayak->Velocity > 0)
|
if (kayak->Velocity > 0)
|
||||||
kayak->Velocity = 0;
|
kayak->Velocity = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kayak->Velocity > MAX_VELOCITY)
|
if (kayak->Velocity > KAYAK_VELOCITY_MAX)
|
||||||
kayak->Velocity = MAX_VELOCITY;
|
kayak->Velocity = KAYAK_VELOCITY_MAX;
|
||||||
else if (kayak->Velocity < -MAX_VELOCITY)
|
else if (kayak->Velocity < -KAYAK_VELOCITY_MAX)
|
||||||
kayak->Velocity = -MAX_VELOCITY;
|
kayak->Velocity = -KAYAK_VELOCITY_MAX;
|
||||||
|
|
||||||
|
kayakItem->Animation.Velocity = kayak->Velocity / VEHICLE_VELOCITY_SCALE;
|
||||||
|
|
||||||
kayakItem->Animation.Velocity = (kayak->Velocity / (USHRT_MAX + 1));
|
|
||||||
;
|
|
||||||
if (kayak->TurnRate >= 0)
|
if (kayak->TurnRate >= 0)
|
||||||
{
|
{
|
||||||
kayak->TurnRate -= KAYAK_ROTATE_FRICTION;
|
kayak->TurnRate -= KAYAK_TURN_RATE_FRICTION_DECEL;
|
||||||
if (kayak->TurnRate < 0)
|
if (kayak->TurnRate < 0)
|
||||||
kayak->TurnRate = 0;
|
kayak->TurnRate = 0;
|
||||||
}
|
}
|
||||||
else if (kayak->TurnRate < 0)
|
else if (kayak->TurnRate < 0)
|
||||||
{
|
{
|
||||||
kayak->TurnRate += KAYAK_ROTATE_FRICTION;
|
kayak->TurnRate += KAYAK_TURN_RATE_FRICTION_DECEL;
|
||||||
if (kayak->TurnRate > 0)
|
if (kayak->TurnRate > 0)
|
||||||
kayak->TurnRate = 0;
|
kayak->TurnRate = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KayakToItemCollision(ItemInfo* laraItem, ItemInfo* kayakItem)
|
void KayakToItemCollision(ItemInfo* kayakItem, ItemInfo* laraItem)
|
||||||
{
|
{
|
||||||
short roomsToCheck[128];
|
short roomsToCheck[128];
|
||||||
short numRoomsToCheck = 0;
|
short numRoomsToCheck = 0;
|
||||||
|
@ -1198,87 +1188,32 @@ namespace TEN::Entities::Vehicles
|
||||||
laraItem->Animation.FrameNumber = g_Level.Anims[LaraItem->Animation.AnimNumber].frameBase;
|
laraItem->Animation.FrameNumber = g_Level.Anims[LaraItem->Animation.AnimNumber].frameBase;
|
||||||
laraItem->Animation.ActiveState = 12; // TODO
|
laraItem->Animation.ActiveState = 12; // TODO
|
||||||
laraItem->Animation.TargetState = 12;
|
laraItem->Animation.TargetState = 12;
|
||||||
laraItem->HitPoints = -1;
|
laraItem->Animation.IsAirborne = false;
|
||||||
laraItem->Animation.Velocity = 0;
|
laraItem->Animation.Velocity = 0;
|
||||||
laraItem->Animation.VerticalVelocity = 0;
|
laraItem->Animation.VerticalVelocity = 0;
|
||||||
laraItem->Animation.Airborne = false;
|
laraItem->HitPoints = -1;
|
||||||
|
|
||||||
AnimateItem(laraItem);
|
AnimateItem(laraItem);
|
||||||
|
|
||||||
lara->ExtraAnim = 1;
|
|
||||||
lara->Control.HandStatus = HandStatus::Busy;
|
lara->Control.HandStatus = HandStatus::Busy;
|
||||||
lara->Control.Weapon.GunType = LaraWeaponType::None;
|
lara->Control.Weapon.GunType = LaraWeaponType::None;
|
||||||
|
lara->ExtraAnim = 1;
|
||||||
lara->HitDirection = -1;
|
lara->HitDirection = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void KayakCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll)
|
|
||||||
{
|
|
||||||
auto* lara = GetLaraInfo(laraItem);
|
|
||||||
auto* kayakItem = &g_Level.Items[itemNumber];
|
|
||||||
auto* kayak = (KayakInfo*)kayakItem->Data;
|
|
||||||
|
|
||||||
if (laraItem->HitPoints < 0 || lara->Vehicle != NO_ITEM)
|
|
||||||
return;
|
|
||||||
|
|
||||||
KayakMountType mountType = KayakGetMountType(laraItem, itemNumber);
|
|
||||||
if (mountType != KayakMountType::None)
|
|
||||||
{
|
|
||||||
lara->Vehicle = itemNumber;
|
|
||||||
|
|
||||||
if (lara->Control.Weapon.GunType == LaraWeaponType::Flare)
|
|
||||||
{
|
|
||||||
CreateFlare(laraItem, ID_FLARE_ITEM, 0);
|
|
||||||
UndrawFlareMeshes(laraItem);
|
|
||||||
lara->Flare.ControlLeft = 0;
|
|
||||||
lara->Control.Weapon.RequestGunType = lara->Control.Weapon.GunType = LaraWeaponType::None;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mountType == KayakMountType::Right)
|
|
||||||
laraItem->Animation.AnimNumber = Objects[ID_KAYAK_LARA_ANIMS].animIndex + KAYAK_ANIM_MOUNT_RIGHT;
|
|
||||||
else if (mountType == KayakMountType::Left)
|
|
||||||
laraItem->Animation.AnimNumber = Objects[ID_KAYAK_LARA_ANIMS].animIndex + KAYAK_ANIM_MOUNT_LEFT;
|
|
||||||
|
|
||||||
laraItem->Animation.FrameNumber = g_Level.Anims[laraItem->Animation.AnimNumber].frameBase;
|
|
||||||
laraItem->Animation.ActiveState = laraItem->Animation.TargetState = KAYAK_STATE_MOUNT_LEFT;
|
|
||||||
laraItem->Pose.Position.x = kayakItem->Pose.Position.x;
|
|
||||||
laraItem->Pose.Position.y = kayakItem->Pose.Position.y;
|
|
||||||
laraItem->Pose.Position.z = kayakItem->Pose.Position.z;
|
|
||||||
laraItem->Pose.Orientation.x = 0;
|
|
||||||
laraItem->Pose.Orientation.y = kayakItem->Pose.Orientation.y;
|
|
||||||
laraItem->Pose.Orientation.z = 0;
|
|
||||||
laraItem->Animation.Velocity = 0;
|
|
||||||
laraItem->Animation.VerticalVelocity = 0;
|
|
||||||
laraItem->Animation.Airborne = false;
|
|
||||||
lara->Control.WaterStatus = WaterStatus::Dry;
|
|
||||||
|
|
||||||
if (laraItem->RoomNumber != kayakItem->RoomNumber)
|
|
||||||
ItemNewRoom(lara->ItemNumber, kayakItem->RoomNumber);
|
|
||||||
|
|
||||||
AnimateItem(laraItem);
|
|
||||||
|
|
||||||
kayak->WaterHeight = kayakItem->Pose.Position.y;
|
|
||||||
kayak->Flags = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
coll->Setup.EnableObjectPush = true;
|
|
||||||
ObjectCollision(itemNumber, laraItem, coll);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool KayakControl(ItemInfo* laraItem)
|
bool KayakControl(ItemInfo* laraItem)
|
||||||
{
|
{
|
||||||
auto* lara = GetLaraInfo(laraItem);
|
auto* lara = GetLaraInfo(laraItem);
|
||||||
auto* kayakItem = &g_Level.Items[lara->Vehicle];
|
auto* kayakItem = &g_Level.Items[lara->Vehicle];
|
||||||
auto* kayak = (KayakInfo*)kayakItem->Data;
|
auto* kayak = GetKayakInfo(kayakItem);
|
||||||
|
|
||||||
if (TrInput & IN_LOOK)
|
if (TrInput & IN_LOOK)
|
||||||
LookUpDown(laraItem);
|
LookUpDown(laraItem);
|
||||||
|
|
||||||
int ofs = kayakItem->Animation.VerticalVelocity;
|
int ofs = kayakItem->Animation.VerticalVelocity;
|
||||||
|
|
||||||
KayakUserInput(laraItem, kayakItem);
|
KayakUserInput(kayakItem, laraItem);
|
||||||
KayakToBackground(laraItem, kayakItem);
|
KayakToBackground(kayakItem, laraItem);
|
||||||
TestTriggers(kayakItem, false);
|
TestTriggers(kayakItem, false);
|
||||||
|
|
||||||
auto probe = GetCollision(kayakItem);
|
auto probe = GetCollision(kayakItem);
|
||||||
|
@ -1314,9 +1249,7 @@ namespace TEN::Entities::Vehicles
|
||||||
ItemNewRoom(lara->ItemNumber, probe.RoomNumber);
|
ItemNewRoom(lara->ItemNumber, probe.RoomNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
laraItem->Pose.Position.x = kayakItem->Pose.Position.x;
|
laraItem->Pose.Position = kayakItem->Pose.Position;
|
||||||
laraItem->Pose.Position.y = kayakItem->Pose.Position.y;
|
|
||||||
laraItem->Pose.Position.z = kayakItem->Pose.Position.z;
|
|
||||||
laraItem->Pose.Orientation.x = kayakItem->Pose.Orientation.x;
|
laraItem->Pose.Orientation.x = kayakItem->Pose.Orientation.x;
|
||||||
laraItem->Pose.Orientation.y = kayakItem->Pose.Orientation.y;
|
laraItem->Pose.Orientation.y = kayakItem->Pose.Orientation.y;
|
||||||
laraItem->Pose.Orientation.z = kayakItem->Pose.Orientation.z / 2;
|
laraItem->Pose.Orientation.z = kayakItem->Pose.Orientation.z / 2;
|
||||||
|
@ -1373,7 +1306,7 @@ namespace TEN::Entities::Vehicles
|
||||||
}
|
}
|
||||||
|
|
||||||
KayakUpdateWakeFX();
|
KayakUpdateWakeFX();
|
||||||
KayakToItemCollision(laraItem, kayakItem);
|
KayakToItemCollision(kayakItem, laraItem);
|
||||||
|
|
||||||
return (lara->Vehicle != NO_ITEM) ? true : false;
|
return (lara->Vehicle != NO_ITEM) ? true : false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include "Objects/Utils/VehicleHelpers.h"
|
||||||
|
|
||||||
struct ItemInfo;
|
|
||||||
struct CollisionInfo;
|
struct CollisionInfo;
|
||||||
struct Vector3Int;
|
struct ItemInfo;
|
||||||
|
|
||||||
namespace TEN::Entities::Vehicles
|
namespace TEN::Entities::Vehicles
|
||||||
{
|
{
|
||||||
void InitialiseKayak(short itemNumber);
|
void InitialiseKayak(short itemNumber);
|
||||||
|
|
||||||
|
void KayakPlayerCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll);
|
||||||
|
void DoKayakMount(ItemInfo* kayakItem, ItemInfo* laraItem, VehicleMountType mountType);
|
||||||
|
|
||||||
void KayakDraw(ItemInfo* kayakItem);
|
void KayakDraw(ItemInfo* kayakItem);
|
||||||
|
|
||||||
void KayakDoWake(ItemInfo* kayakItem, int xOffset, int zOffset, short rotate);
|
void KayakDoWake(ItemInfo* kayakItem, int xOffset, int zOffset, short rotate);
|
||||||
|
@ -15,15 +19,13 @@ namespace TEN::Entities::Vehicles
|
||||||
|
|
||||||
int KayakGetCollisionAnim(ItemInfo* kayakItem, int xDiff, int zDiff);
|
int KayakGetCollisionAnim(ItemInfo* kayakItem, int xDiff, int zDiff);
|
||||||
int KayakDoDynamics(int height, int verticalVelocity, int* y);
|
int KayakDoDynamics(int height, int verticalVelocity, int* y);
|
||||||
void KayakDoCurrent(ItemInfo* laraItem, ItemInfo* kayakItem);
|
void KayakDoCurrent(ItemInfo* kayakItem, ItemInfo* laraItem);
|
||||||
int KayakTestHeight(ItemInfo* kayakItem, int x, int z, Vector3Int* pos);
|
|
||||||
bool KayakCanGetOut(ItemInfo* kayakItem, int dir);
|
bool KayakCanGetOut(ItemInfo* kayakItem, int dir);
|
||||||
int KayakDoShift(ItemInfo* kayakItem, Vector3Int* pos, Vector3Int* old);
|
int KayakDoShift(ItemInfo* kayakItem, Vector3Int* pos, Vector3Int* old);
|
||||||
void KayakToBackground(ItemInfo* laraItem, ItemInfo* kayakItem);
|
void KayakToBackground(ItemInfo* kayakItem, ItemInfo* laraItem);
|
||||||
void KayakUserInput(ItemInfo* laraItem, ItemInfo* kayakItem);
|
void KayakUserInput(ItemInfo* kayakItem, ItemInfo* laraItem);
|
||||||
void KayakToItemCollision(ItemInfo* laraItem, ItemInfo* kayakItem);
|
void KayakToItemCollision(ItemInfo* kayakItem, ItemInfo* laraItem);
|
||||||
void KayakLaraRapidsDrown(ItemInfo* laraItem);
|
void KayakLaraRapidsDrown(ItemInfo* laraItem);
|
||||||
|
|
||||||
void KayakCollision(short itemNum, ItemInfo* laraItem, CollisionInfo* coll);
|
|
||||||
bool KayakControl(ItemInfo* laraItem);
|
bool KayakControl(ItemInfo* laraItem);
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,23 +5,23 @@ namespace TEN::Entities::Vehicles
|
||||||
{
|
{
|
||||||
struct KayakInfo
|
struct KayakInfo
|
||||||
{
|
{
|
||||||
int TurnRate;
|
int TurnRate = 0;
|
||||||
|
|
||||||
int Velocity;
|
int Velocity = 0;
|
||||||
int FrontVerticalVelocity;
|
int FrontVerticalVelocity = 0;
|
||||||
int LeftVerticalVelocity;
|
int LeftVerticalVelocity = 0;
|
||||||
int RightVerticalVelocity;
|
int RightVerticalVelocity = 0;
|
||||||
|
|
||||||
unsigned int LeftRightCount;
|
PHD_3DPOS OldPose = PHD_3DPOS();
|
||||||
int WaterHeight;
|
unsigned int LeftRightPaddleCount = 0;
|
||||||
PHD_3DPOS OldPos;
|
int WaterHeight = 0;
|
||||||
bool Turn;
|
bool Turn = false;
|
||||||
bool Forward;
|
bool Forward = false;
|
||||||
bool TrueWater;
|
bool TrueWater = false;
|
||||||
|
|
||||||
int CurrentStartWake;
|
int CurrentStartWake = 0;
|
||||||
int WakeShade;
|
int WakeShade = 0;
|
||||||
|
|
||||||
char Flags;
|
char Flags = NULL;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,46 +12,56 @@
|
||||||
#include "Game/Lara/lara_flare.h"
|
#include "Game/Lara/lara_flare.h"
|
||||||
#include "Game/Lara/lara_helpers.h"
|
#include "Game/Lara/lara_helpers.h"
|
||||||
#include "Objects/TR3/Vehicles/minecart_info.h"
|
#include "Objects/TR3/Vehicles/minecart_info.h"
|
||||||
|
#include "Objects/Utils/VehicleHelpers.h"
|
||||||
#include "Sound/sound.h"
|
#include "Sound/sound.h"
|
||||||
#include "Specific/input.h"
|
#include "Specific/input.h"
|
||||||
#include "Specific/level.h"
|
#include "Specific/level.h"
|
||||||
#include "Specific/setup.h"
|
#include "Specific/setup.h"
|
||||||
#include "Specific/prng.h"
|
#include "Specific/prng.h"
|
||||||
|
|
||||||
using namespace TEN::Input;
|
|
||||||
using namespace TEN::Effects::Spark;
|
using namespace TEN::Effects::Spark;
|
||||||
|
using namespace TEN::Input;
|
||||||
using namespace TEN::Math::Random;
|
using namespace TEN::Math::Random;
|
||||||
|
using std::vector;
|
||||||
|
|
||||||
namespace TEN::Entities::Vehicles
|
namespace TEN::Entities::Vehicles
|
||||||
{
|
{
|
||||||
|
const vector<VehicleMountType> MinecartMountTypes =
|
||||||
|
{
|
||||||
|
VehicleMountType::LevelStart,
|
||||||
|
VehicleMountType::Left,
|
||||||
|
VehicleMountType::Right
|
||||||
|
};
|
||||||
|
|
||||||
constexpr auto MINECART_RADIUS = 100;
|
constexpr auto MINECART_RADIUS = 100;
|
||||||
constexpr auto MINECART_ENTITY_RADIUS = CLICK(1);
|
constexpr auto MINECART_ENTITY_RADIUS = CLICK(1);
|
||||||
constexpr auto MINECART_HEIGHT = CLICK(2);
|
constexpr auto MINECART_HEIGHT = CLICK(2);
|
||||||
constexpr auto MINECART_GRAVITY = SECTOR(1) + 1;
|
constexpr auto MINECART_GRAVITY = SECTOR(1) + 1;
|
||||||
|
constexpr auto MINECART_STEP_HEIGHT = CLICK(1);
|
||||||
|
constexpr auto MINECART_MOUNT_DISTANCE = CLICK(2);
|
||||||
constexpr auto MINECART_DISMOUNT_DISTANCE = 330;
|
constexpr auto MINECART_DISMOUNT_DISTANCE = 330;
|
||||||
constexpr auto MINECART_NUM_HITS = 25;
|
constexpr auto MINECART_NUM_HITS = 25;
|
||||||
|
|
||||||
constexpr auto MINECART_SPEED_MIN = 10 * 256; // TODO: These two have confusing names. @Sezz
|
constexpr auto MINECART_VELOCITY_DECEL = 6 * VEHICLE_VELOCITY_SCALE;
|
||||||
constexpr auto MINECART_VELOCITY_MIN = 32;
|
|
||||||
constexpr auto MINECART_VERTICAL_VELOCITY_MAX = 63 * 256;
|
|
||||||
constexpr auto MINECART_JUMP_VELOCITY = 63 * 1024;
|
|
||||||
constexpr auto MINECART_TURN_DEATH_VELOCITY = 128;
|
|
||||||
constexpr auto MINECART_TURN_FRICTION_VELOCITY = 70;
|
|
||||||
constexpr auto MINECART_DECELERATION = 6 * 256;
|
|
||||||
|
|
||||||
constexpr auto MINECART_FORWARD_GRADIENT = -128;
|
constexpr auto MINECART_SPEED_MIN = 10 * VEHICLE_VELOCITY_SCALE; // TODO: These two have confusing names. @Sezz
|
||||||
constexpr auto MINECART_BACK_GRADIENT = 128;
|
constexpr auto MINECART_VELOCITY_MIN = 32;
|
||||||
|
constexpr auto MINECART_FRICTION_VELOCITY_MIN = 70;
|
||||||
|
constexpr auto MINECART_STOP_VELOCITY_MAX = 240;
|
||||||
|
constexpr auto MINECART_VERTICAL_VELOCITY_MAX = 63 * VEHICLE_VELOCITY_SCALE;
|
||||||
|
|
||||||
|
constexpr auto MINECART_JUMP_VERTICAL_VELOCITY = 252 * VEHICLE_VELOCITY_SCALE;
|
||||||
|
constexpr auto MINECART_TURN_DEATH_VELOCITY = 128;
|
||||||
|
|
||||||
|
constexpr auto MINECART_FORWARD_GRADIENT = -CLICK(0.5f);
|
||||||
|
constexpr auto MINECART_BACK_GRADIENT = CLICK(0.5f);
|
||||||
|
|
||||||
constexpr auto MINECART_WRENCH_MESH_TOGGLE_FRAME = 20;
|
constexpr auto MINECART_WRENCH_MESH_TOGGLE_FRAME = 20;
|
||||||
|
|
||||||
#define MINECART_TERMINAL_ANGLE ANGLE(22.0f)
|
#define MINECART_TERMINAL_ANGLE ANGLE(22.0f)
|
||||||
|
|
||||||
#define MINECART_IN_BRAKE (IN_BACK | IN_WALK | IN_JUMP)
|
|
||||||
#define MINECART_IN_DUCK IN_CROUCH
|
#define MINECART_IN_DUCK IN_CROUCH
|
||||||
#define MINECART_IN_SWIPE IN_ACTION
|
#define MINECART_IN_SWIPE (IN_ACTION | IN_DRAW)
|
||||||
#define MINECART_IN_DISMOUNT (IN_JUMP | IN_ROLL)
|
|
||||||
#define MINECART_IN_LEFT IN_LEFT
|
|
||||||
#define MINECART_IN_RIGHT IN_RIGHT
|
|
||||||
|
|
||||||
int Wheels[4] = { 2, 3, 1, 4 };
|
int Wheels[4] = { 2, 3, 1, 4 };
|
||||||
|
|
||||||
|
@ -144,7 +154,7 @@ namespace TEN::Entities::Vehicles
|
||||||
MINECART_FLAG_DEAD = (1 << 7)
|
MINECART_FLAG_DEAD = (1 << 7)
|
||||||
};
|
};
|
||||||
|
|
||||||
static MinecartInfo* GetMinecartInfo(ItemInfo* minecartItem)
|
MinecartInfo* GetMinecartInfo(ItemInfo* minecartItem)
|
||||||
{
|
{
|
||||||
return (MinecartInfo*)minecartItem->Data;
|
return (MinecartInfo*)minecartItem->Data;
|
||||||
}
|
}
|
||||||
|
@ -154,20 +164,75 @@ namespace TEN::Entities::Vehicles
|
||||||
auto* minecartItem = &g_Level.Items[itemNumber];
|
auto* minecartItem = &g_Level.Items[itemNumber];
|
||||||
minecartItem->Data = MinecartInfo();
|
minecartItem->Data = MinecartInfo();
|
||||||
auto* minecart = GetMinecartInfo(minecartItem);
|
auto* minecart = GetMinecartInfo(minecartItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MinecartPlayerCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll)
|
||||||
|
{
|
||||||
|
auto* minecartItem = &g_Level.Items[itemNumber];
|
||||||
|
auto* lara = GetLaraInfo(laraItem);
|
||||||
|
|
||||||
|
if (laraItem->HitPoints < 0 || lara->Vehicle != NO_ITEM)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Don't get into minecart if there are two stop blocks in front.
|
||||||
|
// This allows creation of minecarts which will get to a point and stop forever.
|
||||||
|
auto mountType = GetVehicleMountType(minecartItem, laraItem, coll, MinecartMountTypes, MINECART_MOUNT_DISTANCE);
|
||||||
|
if (mountType == VehicleMountType::None ||
|
||||||
|
GetCollision(minecartItem, minecartItem->Pose.Orientation.y, SECTOR(1)).BottomBlock->Flags.MinecartStop())
|
||||||
|
{
|
||||||
|
ObjectCollision(itemNumber, laraItem, coll);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lara->Vehicle = itemNumber;
|
||||||
|
DoMinecartMount(minecartItem, laraItem, mountType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoMinecartMount(ItemInfo* minecartItem, ItemInfo* laraItem, VehicleMountType mountType)
|
||||||
|
{
|
||||||
|
auto* minecart = GetMinecartInfo(minecartItem);
|
||||||
|
auto* lara = GetLaraInfo(laraItem);
|
||||||
|
|
||||||
|
switch (mountType)
|
||||||
|
{
|
||||||
|
case VehicleMountType::LevelStart:
|
||||||
|
laraItem->Animation.AnimNumber = Objects[ID_MINECART_LARA_ANIMS].animIndex + MINECART_ANIM_IDLE;
|
||||||
|
laraItem->Animation.ActiveState = MINECART_STATE_IDLE;
|
||||||
|
laraItem->Animation.TargetState = MINECART_STATE_IDLE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VehicleMountType::Left:
|
||||||
|
laraItem->Animation.AnimNumber = Objects[ID_MINECART_LARA_ANIMS].animIndex + MINECART_ANIM_MOUNT_LEFT;
|
||||||
|
laraItem->Animation.ActiveState = MINECART_STATE_MOUNT;
|
||||||
|
laraItem->Animation.TargetState = MINECART_STATE_MOUNT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
case VehicleMountType::Right:
|
||||||
|
laraItem->Animation.AnimNumber = Objects[ID_MINECART_LARA_ANIMS].animIndex + MINECART_ANIM_MOUNT_RIGHT;
|
||||||
|
laraItem->Animation.ActiveState = MINECART_STATE_MOUNT;
|
||||||
|
laraItem->Animation.TargetState = MINECART_STATE_MOUNT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
laraItem->Animation.FrameNumber = g_Level.Anims[laraItem->Animation.AnimNumber].frameBase;
|
||||||
|
|
||||||
|
DoVehicleFlareDiscard(laraItem);
|
||||||
|
laraItem->Pose = minecartItem->Pose;
|
||||||
|
lara->Control.HandStatus = HandStatus::Busy;
|
||||||
minecart->Velocity = 0;
|
minecart->Velocity = 0;
|
||||||
minecart->VerticalVelocity = 0;
|
minecart->VerticalVelocity = 0;
|
||||||
minecart->Gradient = 0;
|
minecart->Gradient = 0;
|
||||||
minecart->Flags = NULL;
|
minecart->Flags = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void TriggerWheelSparkles(ItemInfo* item, bool left)
|
static void TriggerWheelSparkles(ItemInfo* minecartItem, bool left)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 2; i++)
|
for (int i = 0; i < 2; i++)
|
||||||
{
|
{
|
||||||
auto pos = Vector3Int{};
|
auto pos = Vector3Int();
|
||||||
GetJointAbsPosition(item, &pos, Wheels[(left ? 0 : 2) + i]);
|
GetJointAbsPosition(minecartItem, &pos, Wheels[(left ? 0 : 2) + i]);
|
||||||
TriggerFrictionSpark(&GameVector(pos.x, pos.y, pos.z, item->RoomNumber), item->Pose.Orientation, 512, 10);
|
TriggerFrictionSpark(&GameVector(pos.x, pos.y, pos.z, minecartItem->RoomNumber), minecartItem->Pose.Orientation, 512, 10);
|
||||||
|
|
||||||
if (i)
|
if (i)
|
||||||
{
|
{
|
||||||
|
@ -179,21 +244,6 @@ namespace TEN::Entities::Vehicles
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int TestMinecartHeight(ItemInfo* minecartItem, int xOffset, int zOffset)
|
|
||||||
{
|
|
||||||
float sinX = phd_sin(minecartItem->Pose.Orientation.x);
|
|
||||||
float sinY = phd_sin(minecartItem->Pose.Orientation.y);
|
|
||||||
float cosY = phd_cos(minecartItem->Pose.Orientation.y);
|
|
||||||
float sinZ = phd_sin(minecartItem->Pose.Orientation.z);
|
|
||||||
|
|
||||||
auto pos = Vector3Int(
|
|
||||||
minecartItem->Pose.Position.x + (zOffset * sinY) + (xOffset * cosY),
|
|
||||||
minecartItem->Pose.Position.y - (zOffset * sinX) + (xOffset * sinZ),
|
|
||||||
minecartItem->Pose.Position.z + (zOffset * cosY) - (xOffset * sinY)
|
|
||||||
);
|
|
||||||
return GetCollision(pos.x, pos.y, pos.z, minecartItem->RoomNumber).Position.Floor;
|
|
||||||
}
|
|
||||||
|
|
||||||
static short GetMinecartCollision(ItemInfo* minecartItem, short angle, int distance)
|
static short GetMinecartCollision(ItemInfo* minecartItem, short angle, int distance)
|
||||||
{
|
{
|
||||||
auto probe = GetCollision(minecartItem, angle, distance, -LARA_HEIGHT);
|
auto probe = GetCollision(minecartItem, angle, distance, -LARA_HEIGHT);
|
||||||
|
@ -204,41 +254,6 @@ namespace TEN::Entities::Vehicles
|
||||||
return (short)probe.Position.Floor;
|
return (short)probe.Position.Floor;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool GetInMinecart(ItemInfo* minecartItem, ItemInfo* laraItem, CollisionInfo* coll)
|
|
||||||
{
|
|
||||||
auto* lara = GetLaraInfo(laraItem);
|
|
||||||
|
|
||||||
if (!(TrInput & IN_ACTION) || lara->Control.HandStatus != HandStatus::Free ||
|
|
||||||
laraItem->Animation.Airborne)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!TestBoundsCollide(minecartItem, laraItem, coll->Setup.Radius))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!TestCollision(minecartItem, laraItem))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
int x = laraItem->Pose.Position.x - minecartItem->Pose.Position.x;
|
|
||||||
int z = laraItem->Pose.Position.z - minecartItem->Pose.Position.z;
|
|
||||||
|
|
||||||
int distance = pow(x, 2) + pow(z, 2);
|
|
||||||
if (distance > pow(CLICK(2), 2))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (GetCollision(minecartItem).Position.Floor < -SECTOR(31.25f))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Don't get into minecart if there's two stop blocks in front.
|
|
||||||
// Allows to create minecarts which will get to a point and stop forever.
|
|
||||||
|
|
||||||
if (GetCollision(minecartItem, minecartItem->Pose.Orientation.y, SECTOR(1)).BottomBlock->Flags.MinecartStop())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool TestMinecartDismount(ItemInfo* laraItem, int direction)
|
static bool TestMinecartDismount(ItemInfo* laraItem, int direction)
|
||||||
{
|
{
|
||||||
auto* lara = GetLaraInfo(laraItem);
|
auto* lara = GetLaraInfo(laraItem);
|
||||||
|
@ -267,7 +282,7 @@ namespace TEN::Entities::Vehicles
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void MinecartToEntityCollision(ItemInfo* laraItem, ItemInfo* minecartItem)
|
static void MinecartToEntityCollision(ItemInfo* minecartItem, ItemInfo* laraItem)
|
||||||
{
|
{
|
||||||
auto roomsList = GetRoomList(minecartItem->RoomNumber);
|
auto roomsList = GetRoomList(minecartItem->RoomNumber);
|
||||||
|
|
||||||
|
@ -336,10 +351,11 @@ namespace TEN::Entities::Vehicles
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void MoveCart(ItemInfo* laraItem, ItemInfo* minecartItem)
|
static void MoveCart(ItemInfo* minecartItem, ItemInfo* laraItem)
|
||||||
{
|
{
|
||||||
auto* lara = GetLaraInfo(laraItem);
|
|
||||||
auto* minecart = GetMinecartInfo(minecartItem);
|
auto* minecart = GetMinecartInfo(minecartItem);
|
||||||
|
auto* lara = GetLaraInfo(laraItem);
|
||||||
|
|
||||||
auto flags = GetCollision(minecartItem).BottomBlock->Flags;
|
auto flags = GetCollision(minecartItem).BottomBlock->Flags;
|
||||||
|
|
||||||
if (minecart->StopDelay)
|
if (minecart->StopDelay)
|
||||||
|
@ -348,7 +364,7 @@ namespace TEN::Entities::Vehicles
|
||||||
if ((flags.MinecartStop() && !minecart->StopDelay) &&
|
if ((flags.MinecartStop() && !minecart->StopDelay) &&
|
||||||
((minecartItem->Pose.Position.x & 0x380) == 512 || (minecartItem->Pose.Position.z & 0x380) == 512))
|
((minecartItem->Pose.Position.x & 0x380) == 512 || (minecartItem->Pose.Position.z & 0x380) == 512))
|
||||||
{
|
{
|
||||||
if (minecart->Velocity < 0xf000)
|
if (minecart->Velocity < MINECART_STOP_VELOCITY_MAX)
|
||||||
{
|
{
|
||||||
minecartItem->Animation.Velocity = 0;
|
minecartItem->Animation.Velocity = 0;
|
||||||
minecart->Velocity = 0;
|
minecart->Velocity = 0;
|
||||||
|
@ -434,7 +450,7 @@ namespace TEN::Entities::Vehicles
|
||||||
minecart->Velocity = MINECART_SPEED_MIN;
|
minecart->Velocity = MINECART_SPEED_MIN;
|
||||||
|
|
||||||
minecart->Velocity -= minecart->Gradient * 4;
|
minecart->Velocity -= minecart->Gradient * 4;
|
||||||
minecartItem->Animation.Velocity = minecart->Velocity / 256;
|
minecartItem->Animation.Velocity = minecart->Velocity / VEHICLE_VELOCITY_SCALE;
|
||||||
|
|
||||||
if (minecartItem->Animation.Velocity < MINECART_VELOCITY_MIN)
|
if (minecartItem->Animation.Velocity < MINECART_VELOCITY_MIN)
|
||||||
{
|
{
|
||||||
|
@ -515,7 +531,7 @@ namespace TEN::Entities::Vehicles
|
||||||
minecartItem->Pose.Position.x = minecart->TurnX + x * 3584;
|
minecartItem->Pose.Position.x = minecart->TurnX + x * 3584;
|
||||||
minecartItem->Pose.Position.z = minecart->TurnZ + z * 3584;
|
minecartItem->Pose.Position.z = minecart->TurnZ + z * 3584;
|
||||||
|
|
||||||
if (minecartItem->Animation.Velocity > MINECART_TURN_FRICTION_VELOCITY)
|
if (minecartItem->Animation.Velocity > MINECART_FRICTION_VELOCITY_MIN)
|
||||||
{
|
{
|
||||||
SoundEffect(SFX_TR3_VEHICLE_MINECART_BRAKE, &minecartItem->Pose, SoundEnvironment::Always);
|
SoundEffect(SFX_TR3_VEHICLE_MINECART_BRAKE, &minecartItem->Pose, SoundEnvironment::Always);
|
||||||
TriggerWheelSparkles(minecartItem, (minecart->Flags & MINECART_FLAG_TURNING_RIGHT) != 0);
|
TriggerWheelSparkles(minecartItem, (minecart->Flags & MINECART_FLAG_TURNING_RIGHT) != 0);
|
||||||
|
@ -525,12 +541,12 @@ namespace TEN::Entities::Vehicles
|
||||||
else
|
else
|
||||||
TranslateItem(minecartItem, minecartItem->Pose.Orientation.y, minecartItem->Animation.Velocity);
|
TranslateItem(minecartItem, minecartItem->Pose.Orientation.y, minecartItem->Animation.Velocity);
|
||||||
|
|
||||||
minecart->FloorHeightMiddle = TestMinecartHeight(minecartItem, 0, 0);
|
minecart->FloorHeightMiddle = GetVehicleHeight(minecartItem, 0, 0, true, &Vector3Int());
|
||||||
|
|
||||||
if (!minecart->VerticalVelocity)
|
if (!minecart->VerticalVelocity)
|
||||||
{
|
{
|
||||||
minecartItem->Pose.Position.y = minecart->FloorHeightMiddle;
|
minecartItem->Pose.Position.y = minecart->FloorHeightMiddle;
|
||||||
minecart->FloorHeightFront = TestMinecartHeight(minecartItem, 0, CLICK(1));
|
minecart->FloorHeightFront = GetVehicleHeight(minecartItem, CLICK(1), 0, false, &Vector3Int());
|
||||||
minecart->Gradient = minecart->FloorHeightMiddle - minecart->FloorHeightFront;
|
minecart->Gradient = minecart->FloorHeightMiddle - minecart->FloorHeightFront;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -549,7 +565,7 @@ namespace TEN::Entities::Vehicles
|
||||||
if (minecart->VerticalVelocity > MINECART_VERTICAL_VELOCITY_MAX)
|
if (minecart->VerticalVelocity > MINECART_VERTICAL_VELOCITY_MAX)
|
||||||
minecart->VerticalVelocity = MINECART_VERTICAL_VELOCITY_MAX;
|
minecart->VerticalVelocity = MINECART_VERTICAL_VELOCITY_MAX;
|
||||||
|
|
||||||
minecartItem->Pose.Position.y += minecart->VerticalVelocity / 256;
|
minecartItem->Pose.Position.y += minecart->VerticalVelocity / VEHICLE_VELOCITY_SCALE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -567,8 +583,9 @@ namespace TEN::Entities::Vehicles
|
||||||
minecartItem->Pose.Orientation.z -= minecartItem->Pose.Orientation.z / 8;
|
minecartItem->Pose.Orientation.z -= minecartItem->Pose.Orientation.z / 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DoUserInput(ItemInfo* minecartItem, ItemInfo* laraItem, MinecartInfo* minecart)
|
static void DoUserInput(ItemInfo* minecartItem, ItemInfo* laraItem)
|
||||||
{
|
{
|
||||||
|
auto* minecart = GetMinecartInfo(minecartItem);
|
||||||
auto* lara = GetLaraInfo(laraItem);
|
auto* lara = GetLaraInfo(laraItem);
|
||||||
|
|
||||||
short floorHeight;
|
short floorHeight;
|
||||||
|
@ -580,7 +597,7 @@ namespace TEN::Entities::Vehicles
|
||||||
laraItem->Animation.TargetState = MINECART_STATE_SWIPE;
|
laraItem->Animation.TargetState = MINECART_STATE_SWIPE;
|
||||||
else if (TrInput & MINECART_IN_DUCK)
|
else if (TrInput & MINECART_IN_DUCK)
|
||||||
laraItem->Animation.TargetState = MINECART_STATE_DUCK;
|
laraItem->Animation.TargetState = MINECART_STATE_DUCK;
|
||||||
else if (TrInput & MINECART_IN_BRAKE)
|
else if (TrInput & (VEHICLE_IN_BRAKE | VEHICLE_IN_SLOW))
|
||||||
laraItem->Animation.TargetState = MINECART_STATE_BRAKE;
|
laraItem->Animation.TargetState = MINECART_STATE_BRAKE;
|
||||||
else if (minecart->Velocity == MINECART_VELOCITY_MIN || minecart->Flags & MINECART_FLAG_STOPPED)
|
else if (minecart->Velocity == MINECART_VELOCITY_MIN || minecart->Flags & MINECART_FLAG_STOPPED)
|
||||||
laraItem->Animation.TargetState = MINECART_STATE_IDLE;
|
laraItem->Animation.TargetState = MINECART_STATE_IDLE;
|
||||||
|
@ -588,9 +605,9 @@ namespace TEN::Entities::Vehicles
|
||||||
laraItem->Animation.TargetState = MINECART_STATE_FORWARD;
|
laraItem->Animation.TargetState = MINECART_STATE_FORWARD;
|
||||||
else if (minecart->Gradient > MINECART_BACK_GRADIENT)
|
else if (minecart->Gradient > MINECART_BACK_GRADIENT)
|
||||||
laraItem->Animation.TargetState = MINECART_STATE_BACK;
|
laraItem->Animation.TargetState = MINECART_STATE_BACK;
|
||||||
else if (TrInput & MINECART_IN_LEFT)
|
else if (TrInput & VEHICLE_IN_LEFT)
|
||||||
laraItem->Animation.TargetState = MINECART_STATE_LEFT;
|
laraItem->Animation.TargetState = MINECART_STATE_LEFT;
|
||||||
else if (TrInput & MINECART_IN_RIGHT)
|
else if (TrInput & VEHICLE_IN_RIGHT)
|
||||||
laraItem->Animation.TargetState = MINECART_STATE_RIGHT;
|
laraItem->Animation.TargetState = MINECART_STATE_RIGHT;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -600,7 +617,7 @@ namespace TEN::Entities::Vehicles
|
||||||
laraItem->Animation.TargetState = MINECART_STATE_SWIPE;
|
laraItem->Animation.TargetState = MINECART_STATE_SWIPE;
|
||||||
else if (TrInput & MINECART_IN_DUCK)
|
else if (TrInput & MINECART_IN_DUCK)
|
||||||
laraItem->Animation.TargetState = MINECART_STATE_DUCK;
|
laraItem->Animation.TargetState = MINECART_STATE_DUCK;
|
||||||
else if (TrInput & MINECART_IN_BRAKE)
|
else if (TrInput & (VEHICLE_IN_BRAKE | VEHICLE_IN_SLOW))
|
||||||
laraItem->Animation.TargetState = MINECART_STATE_BRAKE;
|
laraItem->Animation.TargetState = MINECART_STATE_BRAKE;
|
||||||
else if (minecart->Gradient > MINECART_FORWARD_GRADIENT)
|
else if (minecart->Gradient > MINECART_FORWARD_GRADIENT)
|
||||||
laraItem->Animation.TargetState = MINECART_STATE_MOVE;
|
laraItem->Animation.TargetState = MINECART_STATE_MOVE;
|
||||||
|
@ -612,7 +629,7 @@ namespace TEN::Entities::Vehicles
|
||||||
laraItem->Animation.TargetState = MINECART_STATE_SWIPE;
|
laraItem->Animation.TargetState = MINECART_STATE_SWIPE;
|
||||||
else if (TrInput & MINECART_IN_DUCK)
|
else if (TrInput & MINECART_IN_DUCK)
|
||||||
laraItem->Animation.TargetState = MINECART_STATE_DUCK;
|
laraItem->Animation.TargetState = MINECART_STATE_DUCK;
|
||||||
else if (TrInput & MINECART_IN_BRAKE)
|
else if (TrInput & (VEHICLE_IN_BRAKE | VEHICLE_IN_SLOW))
|
||||||
laraItem->Animation.TargetState = MINECART_STATE_BRAKE;
|
laraItem->Animation.TargetState = MINECART_STATE_BRAKE;
|
||||||
else if (minecart->Gradient < MINECART_BACK_GRADIENT)
|
else if (minecart->Gradient < MINECART_BACK_GRADIENT)
|
||||||
laraItem->Animation.TargetState = MINECART_STATE_MOVE;
|
laraItem->Animation.TargetState = MINECART_STATE_MOVE;
|
||||||
|
@ -624,10 +641,10 @@ namespace TEN::Entities::Vehicles
|
||||||
laraItem->Animation.TargetState = MINECART_STATE_SWIPE;
|
laraItem->Animation.TargetState = MINECART_STATE_SWIPE;
|
||||||
else if (TrInput & MINECART_IN_DUCK)
|
else if (TrInput & MINECART_IN_DUCK)
|
||||||
laraItem->Animation.TargetState = MINECART_STATE_DUCK;
|
laraItem->Animation.TargetState = MINECART_STATE_DUCK;
|
||||||
else if (TrInput & MINECART_IN_BRAKE)
|
else if (TrInput & (VEHICLE_IN_BRAKE | VEHICLE_IN_SLOW))
|
||||||
laraItem->Animation.TargetState = MINECART_STATE_BRAKE;
|
laraItem->Animation.TargetState = MINECART_STATE_BRAKE;
|
||||||
|
|
||||||
if (!(TrInput & MINECART_IN_LEFT))
|
if (!(TrInput & VEHICLE_IN_LEFT))
|
||||||
laraItem->Animation.TargetState = MINECART_STATE_MOVE;
|
laraItem->Animation.TargetState = MINECART_STATE_MOVE;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -637,10 +654,10 @@ namespace TEN::Entities::Vehicles
|
||||||
laraItem->Animation.TargetState = MINECART_STATE_SWIPE;
|
laraItem->Animation.TargetState = MINECART_STATE_SWIPE;
|
||||||
else if (TrInput & MINECART_IN_DUCK)
|
else if (TrInput & MINECART_IN_DUCK)
|
||||||
laraItem->Animation.TargetState = MINECART_STATE_DUCK;
|
laraItem->Animation.TargetState = MINECART_STATE_DUCK;
|
||||||
else if (TrInput & MINECART_IN_BRAKE)
|
else if (TrInput & (VEHICLE_IN_BRAKE | VEHICLE_IN_SLOW))
|
||||||
laraItem->Animation.TargetState = MINECART_STATE_BRAKE;
|
laraItem->Animation.TargetState = MINECART_STATE_BRAKE;
|
||||||
|
|
||||||
if (!(TrInput & MINECART_IN_RIGHT))
|
if (!(TrInput & VEHICLE_IN_RIGHT))
|
||||||
laraItem->Animation.TargetState = MINECART_STATE_MOVE;
|
laraItem->Animation.TargetState = MINECART_STATE_MOVE;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -653,14 +670,14 @@ namespace TEN::Entities::Vehicles
|
||||||
minecart->StopDelay = 64;
|
minecart->StopDelay = 64;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TrInput & MINECART_IN_DISMOUNT && minecart->Flags & MINECART_FLAG_STOPPED)
|
if (TrInput & VEHICLE_IN_DISMOUNT && minecart->Flags & MINECART_FLAG_STOPPED)
|
||||||
{
|
{
|
||||||
if (TrInput & MINECART_IN_LEFT && TestMinecartDismount(laraItem, -1))
|
if (TrInput & VEHICLE_IN_LEFT && TestMinecartDismount(laraItem, -1))
|
||||||
{
|
{
|
||||||
laraItem->Animation.TargetState = MINECART_STATE_DISMOUNT;
|
laraItem->Animation.TargetState = MINECART_STATE_DISMOUNT;
|
||||||
minecart->Flags &= ~MINECART_FLAG_DISMOUNT_RIGHT;
|
minecart->Flags &= ~MINECART_FLAG_DISMOUNT_RIGHT;
|
||||||
}
|
}
|
||||||
else if (TrInput & MINECART_IN_RIGHT && TestMinecartDismount(laraItem, 1))
|
else if (TrInput & VEHICLE_IN_RIGHT && TestMinecartDismount(laraItem, 1))
|
||||||
{
|
{
|
||||||
laraItem->Animation.TargetState = MINECART_STATE_DISMOUNT;
|
laraItem->Animation.TargetState = MINECART_STATE_DISMOUNT;
|
||||||
minecart->Flags |= MINECART_FLAG_DISMOUNT_RIGHT;
|
minecart->Flags |= MINECART_FLAG_DISMOUNT_RIGHT;
|
||||||
|
@ -680,7 +697,7 @@ namespace TEN::Entities::Vehicles
|
||||||
case MINECART_STATE_DUCK:
|
case MINECART_STATE_DUCK:
|
||||||
if (TrInput & MINECART_IN_SWIPE)
|
if (TrInput & MINECART_IN_SWIPE)
|
||||||
laraItem->Animation.TargetState = MINECART_STATE_SWIPE;
|
laraItem->Animation.TargetState = MINECART_STATE_SWIPE;
|
||||||
else if (TrInput & MINECART_IN_BRAKE)
|
else if (TrInput & (VEHICLE_IN_BRAKE | VEHICLE_IN_SLOW))
|
||||||
laraItem->Animation.TargetState = MINECART_STATE_BRAKE;
|
laraItem->Animation.TargetState = MINECART_STATE_BRAKE;
|
||||||
else if (!(TrInput & MINECART_IN_DUCK))
|
else if (!(TrInput & MINECART_IN_DUCK))
|
||||||
laraItem->Animation.TargetState = MINECART_STATE_IDLE;
|
laraItem->Animation.TargetState = MINECART_STATE_IDLE;
|
||||||
|
@ -697,17 +714,17 @@ namespace TEN::Entities::Vehicles
|
||||||
laraItem->Animation.TargetState = MINECART_STATE_DUCK;
|
laraItem->Animation.TargetState = MINECART_STATE_DUCK;
|
||||||
StopSoundEffect(SFX_TR3_VEHICLE_MINECART_BRAKE);
|
StopSoundEffect(SFX_TR3_VEHICLE_MINECART_BRAKE);
|
||||||
}
|
}
|
||||||
else if (!(TrInput & MINECART_IN_BRAKE) || minecart->Flags & MINECART_FLAG_STOPPED)
|
else if (!(TrInput & (VEHICLE_IN_BRAKE | VEHICLE_IN_SLOW)) || minecart->Flags & MINECART_FLAG_STOPPED)
|
||||||
{
|
{
|
||||||
laraItem->Animation.TargetState = MINECART_STATE_MOVE;
|
laraItem->Animation.TargetState = MINECART_STATE_MOVE;
|
||||||
StopSoundEffect(SFX_TR3_VEHICLE_MINECART_BRAKE);
|
StopSoundEffect(SFX_TR3_VEHICLE_MINECART_BRAKE);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
minecart->Velocity -= MINECART_DECELERATION;
|
minecart->Velocity -= MINECART_VELOCITY_DECEL;
|
||||||
SoundEffect(SFX_TR3_VEHICLE_MINECART_BRAKE, &laraItem->Pose, SoundEnvironment::Always);
|
SoundEffect(SFX_TR3_VEHICLE_MINECART_BRAKE, &laraItem->Pose, SoundEnvironment::Always);
|
||||||
|
|
||||||
if (minecartItem->Animation.Velocity > MINECART_TURN_FRICTION_VELOCITY)
|
if (minecartItem->Animation.Velocity > MINECART_FRICTION_VELOCITY_MIN)
|
||||||
{
|
{
|
||||||
TriggerWheelSparkles(minecartItem, false);
|
TriggerWheelSparkles(minecartItem, false);
|
||||||
TriggerWheelSparkles(minecartItem, true);
|
TriggerWheelSparkles(minecartItem, true);
|
||||||
|
@ -797,8 +814,7 @@ namespace TEN::Entities::Vehicles
|
||||||
Camera.targetDistance = SECTOR(2);
|
Camera.targetDistance = SECTOR(2);
|
||||||
|
|
||||||
floorHeight = GetMinecartCollision(minecartItem, minecartItem->Pose.Orientation.y, CLICK(2));
|
floorHeight = GetMinecartCollision(minecartItem, minecartItem->Pose.Orientation.y, CLICK(2));
|
||||||
if (floorHeight > -CLICK(1) &&
|
if (abs(floorHeight) < MINECART_STEP_HEIGHT)
|
||||||
floorHeight < CLICK(1))
|
|
||||||
{
|
{
|
||||||
if (Wibble & 7 == 0)
|
if (Wibble & 7 == 0)
|
||||||
SoundEffect(SFX_TR3_VEHICLE_QUADBIKE_FRONT_IMPACT, &minecartItem->Pose, SoundEnvironment::Always);
|
SoundEffect(SFX_TR3_VEHICLE_QUADBIKE_FRONT_IMPACT, &minecartItem->Pose, SoundEnvironment::Always);
|
||||||
|
@ -906,59 +922,12 @@ namespace TEN::Entities::Vehicles
|
||||||
}
|
}
|
||||||
|
|
||||||
if (floorHeight > CLICK(2.25f) && !minecart->VerticalVelocity)
|
if (floorHeight > CLICK(2.25f) && !minecart->VerticalVelocity)
|
||||||
minecart->VerticalVelocity = MINECART_JUMP_VELOCITY;
|
minecart->VerticalVelocity = MINECART_JUMP_VERTICAL_VELOCITY;
|
||||||
|
|
||||||
MinecartToEntityCollision(laraItem, minecartItem);
|
MinecartToEntityCollision(minecartItem, laraItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MinecartCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll)
|
|
||||||
{
|
|
||||||
auto* lara = GetLaraInfo(laraItem);
|
|
||||||
|
|
||||||
if (laraItem->HitPoints < 0 || lara->Vehicle != NO_ITEM)
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto* minecartItem = &g_Level.Items[itemNumber];
|
|
||||||
|
|
||||||
bool doMount = GetInMinecart(minecartItem, laraItem, coll);
|
|
||||||
if (doMount)
|
|
||||||
{
|
|
||||||
lara->Vehicle = itemNumber;
|
|
||||||
|
|
||||||
if (lara->Control.Weapon.GunType == LaraWeaponType::Flare)
|
|
||||||
{
|
|
||||||
CreateFlare(laraItem, ID_FLARE_ITEM, false);
|
|
||||||
UndrawFlareMeshes(laraItem);
|
|
||||||
lara->Flare.ControlLeft = false;
|
|
||||||
lara->Control.Weapon.RequestGunType = LaraWeaponType::None;
|
|
||||||
lara->Control.Weapon.GunType = LaraWeaponType::None;
|
|
||||||
}
|
|
||||||
|
|
||||||
lara->Control.HandStatus = HandStatus::Busy;
|
|
||||||
|
|
||||||
short angle = short(mGetAngle(minecartItem->Pose.Position.x, minecartItem->Pose.Position.z, laraItem->Pose.Position.x, laraItem->Pose.Position.z) - minecartItem->Pose.Orientation.y);
|
|
||||||
if (angle > -ANGLE(45.0f) && angle < ANGLE(135.0f))
|
|
||||||
laraItem->Animation.AnimNumber = Objects[ID_MINECART_LARA_ANIMS].animIndex + MINECART_ANIM_MOUNT_RIGHT;
|
|
||||||
else
|
|
||||||
laraItem->Animation.AnimNumber = Objects[ID_MINECART_LARA_ANIMS].animIndex + MINECART_ANIM_MOUNT_LEFT;
|
|
||||||
|
|
||||||
laraItem->Animation.FrameNumber = g_Level.Anims[laraItem->Animation.AnimNumber].frameBase;
|
|
||||||
laraItem->Animation.ActiveState = MINECART_STATE_MOUNT;
|
|
||||||
laraItem->Animation.TargetState = MINECART_STATE_MOUNT;
|
|
||||||
laraItem->Pose = minecartItem->Pose;
|
|
||||||
|
|
||||||
auto* minecart = GetMinecartInfo(minecartItem);
|
|
||||||
|
|
||||||
minecart->Velocity = 0;
|
|
||||||
minecart->VerticalVelocity = 0;
|
|
||||||
minecart->Gradient = 0;
|
|
||||||
minecart->Flags = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ObjectCollision(itemNumber, laraItem, coll);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MinecartControl(ItemInfo* laraItem)
|
bool MinecartControl(ItemInfo* laraItem)
|
||||||
{
|
{
|
||||||
auto* lara = GetLaraInfo(laraItem);
|
auto* lara = GetLaraInfo(laraItem);
|
||||||
|
@ -971,10 +940,10 @@ namespace TEN::Entities::Vehicles
|
||||||
}
|
}
|
||||||
auto* minecart = GetMinecartInfo(minecartItem);
|
auto* minecart = GetMinecartInfo(minecartItem);
|
||||||
|
|
||||||
DoUserInput(minecartItem, laraItem, minecart);
|
DoUserInput(minecartItem, laraItem);
|
||||||
|
|
||||||
if (minecart->Flags & MINECART_FLAG_CONTROL)
|
if (minecart->Flags & MINECART_FLAG_CONTROL)
|
||||||
MoveCart(laraItem, minecartItem);
|
MoveCart(minecartItem, laraItem);
|
||||||
|
|
||||||
if (lara->Vehicle != NO_ITEM)
|
if (lara->Vehicle != NO_ITEM)
|
||||||
laraItem->Pose = minecartItem->Pose;
|
laraItem->Pose = minecartItem->Pose;
|
||||||
|
|
|
@ -1,11 +1,15 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include "Objects/Utils/VehicleHelpers.h"
|
||||||
|
|
||||||
struct ItemInfo;
|
|
||||||
struct CollisionInfo;
|
struct CollisionInfo;
|
||||||
|
struct ItemInfo;
|
||||||
|
|
||||||
namespace TEN::Entities::Vehicles
|
namespace TEN::Entities::Vehicles
|
||||||
{
|
{
|
||||||
void InitialiseMinecart(short itemNumber);
|
void InitialiseMinecart(short itemNumber);
|
||||||
void MinecartCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll);
|
|
||||||
|
void MinecartPlayerCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll);
|
||||||
|
void DoMinecartMount(ItemInfo* minecartItem, ItemInfo* laraItem, VehicleMountType mountType);
|
||||||
|
|
||||||
bool MinecartControl(ItemInfo* laraItem);
|
bool MinecartControl(ItemInfo* laraItem);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,19 +4,20 @@ namespace TEN::Entities::Vehicles
|
||||||
{
|
{
|
||||||
struct MinecartInfo
|
struct MinecartInfo
|
||||||
{
|
{
|
||||||
short TurnRot;
|
int Velocity = 0;
|
||||||
int TurnX;
|
int VerticalVelocity = 0;
|
||||||
int TurnZ;
|
|
||||||
short TurnLen;
|
|
||||||
|
|
||||||
int Velocity;
|
short TurnRot = 0;
|
||||||
int VerticalVelocity;
|
int TurnX = 0;
|
||||||
int Gradient;
|
int TurnZ = 0;
|
||||||
unsigned int StopDelay;
|
short TurnLen = 0;
|
||||||
|
|
||||||
int FloorHeightMiddle;
|
int Gradient = 0;
|
||||||
int FloorHeightFront;
|
unsigned int StopDelay = 0;
|
||||||
|
|
||||||
char Flags;
|
int FloorHeightMiddle = 0;
|
||||||
|
int FloorHeightFront = 0;
|
||||||
|
|
||||||
|
char Flags = NULL;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,11 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
struct ItemInfo;
|
|
||||||
struct CollisionInfo;
|
|
||||||
|
|
||||||
namespace TEN::Entities::Vehicles
|
|
||||||
{
|
|
||||||
void InitialiseQuadBike(short itemNumber);
|
|
||||||
void QuadBikeCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll);
|
|
||||||
bool QuadBikeControl(ItemInfo* laraItem, CollisionInfo* coll);
|
|
||||||
}
|
|
1272
TombEngine/Objects/TR3/Vehicles/quad_bike.cpp
Normal file
1272
TombEngine/Objects/TR3/Vehicles/quad_bike.cpp
Normal file
File diff suppressed because it is too large
Load diff
15
TombEngine/Objects/TR3/Vehicles/quad_bike.h
Normal file
15
TombEngine/Objects/TR3/Vehicles/quad_bike.h
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#pragma once
|
||||||
|
#include "Objects/Utils/VehicleHelpers.h"
|
||||||
|
|
||||||
|
struct CollisionInfo;
|
||||||
|
struct ItemInfo;
|
||||||
|
|
||||||
|
namespace TEN::Entities::Vehicles
|
||||||
|
{
|
||||||
|
void InitialiseQuadBike(short itemNumber);
|
||||||
|
|
||||||
|
void QuadBikePlayerCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll);
|
||||||
|
void DoQuadBikeMount(ItemInfo* quadBikeItem, ItemInfo* laraItem, VehicleMountType mountType);
|
||||||
|
|
||||||
|
bool QuadBikeControl(ItemInfo* laraItem, CollisionInfo* coll);
|
||||||
|
}
|
28
TombEngine/Objects/TR3/Vehicles/quad_bike_info.h
Normal file
28
TombEngine/Objects/TR3/Vehicles/quad_bike_info.h
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace TEN::Entities::Vehicles
|
||||||
|
{
|
||||||
|
struct QuadBikeInfo
|
||||||
|
{
|
||||||
|
short TurnRate = 0;
|
||||||
|
short FrontRot = 0;
|
||||||
|
short RearRot = 0;
|
||||||
|
short MomentumAngle = 0;
|
||||||
|
short ExtraRotation = 0;
|
||||||
|
|
||||||
|
int Velocity = 0;
|
||||||
|
int LeftVerticalVelocity = 0;
|
||||||
|
int RightVerticalVelocity = 0;
|
||||||
|
|
||||||
|
int Revs = 0;
|
||||||
|
int EngineRevs = 0;
|
||||||
|
int Pitch = 0;
|
||||||
|
|
||||||
|
int SmokeStart = 0;
|
||||||
|
bool CanStartDrift = 0;
|
||||||
|
bool DriftStarting = 0;
|
||||||
|
bool NoDismount = 0;
|
||||||
|
|
||||||
|
char Flags = NULL;
|
||||||
|
};
|
||||||
|
}
|
|
@ -1,28 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
namespace TEN::Entities::Vehicles
|
|
||||||
{
|
|
||||||
struct QuadInfo
|
|
||||||
{
|
|
||||||
short TurnRate;
|
|
||||||
short FrontRot;
|
|
||||||
short RearRot;
|
|
||||||
short MomentumAngle;
|
|
||||||
short ExtraRotation;
|
|
||||||
|
|
||||||
int Velocity;
|
|
||||||
int LeftVerticalVelocity;
|
|
||||||
int RightVerticalVelocity;
|
|
||||||
|
|
||||||
int Revs;
|
|
||||||
int EngineRevs;
|
|
||||||
int Pitch;
|
|
||||||
|
|
||||||
int SmokeStart;
|
|
||||||
bool CanStartDrift;
|
|
||||||
bool DriftStarting;
|
|
||||||
bool NoDismount;
|
|
||||||
|
|
||||||
char Flags;
|
|
||||||
};
|
|
||||||
}
|
|
|
@ -10,44 +10,47 @@
|
||||||
#include "Game/Lara/lara.h"
|
#include "Game/Lara/lara.h"
|
||||||
#include "Game/Lara/lara_helpers.h"
|
#include "Game/Lara/lara_helpers.h"
|
||||||
#include "Objects/TR3/Vehicles/rubber_boat_info.h"
|
#include "Objects/TR3/Vehicles/rubber_boat_info.h"
|
||||||
|
#include "Objects/Utils/VehicleHelpers.h"
|
||||||
#include "Sound/sound.h"
|
#include "Sound/sound.h"
|
||||||
#include "Specific/input.h"
|
#include "Specific/input.h"
|
||||||
#include "Specific/level.h"
|
#include "Specific/level.h"
|
||||||
#include "Specific/setup.h"
|
#include "Specific/setup.h"
|
||||||
#include "Renderer/Renderer11Enums.h"
|
#include "Renderer/Renderer11Enums.h"
|
||||||
|
|
||||||
|
using std::vector;
|
||||||
using namespace TEN::Input;
|
using namespace TEN::Input;
|
||||||
|
|
||||||
namespace TEN::Entities::Vehicles
|
namespace TEN::Entities::Vehicles
|
||||||
{
|
{
|
||||||
#define RBOAT_SLIP 10
|
const vector<VehicleMountType> RubberBoatMountTypes =
|
||||||
#define RBOAT_SIDE_SLIP 30
|
{
|
||||||
|
VehicleMountType::LevelStart,
|
||||||
|
VehicleMountType::Left,
|
||||||
|
VehicleMountType::Right,
|
||||||
|
VehicleMountType::Jump
|
||||||
|
};
|
||||||
|
|
||||||
#define RBOAT_FRONT 750
|
constexpr auto RBOAT_RADIUS = 500;
|
||||||
#define RBOAT_SIDE 300
|
constexpr auto RBOAT_FRONT = 750;
|
||||||
#define RBOAT_RADIUS 500
|
constexpr auto RBOAT_SIDE = 300;
|
||||||
#define RBOAT_SNOW 500
|
constexpr auto RBOAT_SLIP = 10;
|
||||||
|
constexpr auto RBOAT_SIDE_SLIP = 30;
|
||||||
|
constexpr auto RBOAT_MOUNT_DISTANCE = CLICK(2.25f);
|
||||||
|
|
||||||
#define RBOAT_MAX_VELOCITY 110
|
constexpr auto RBOAT_VELOCITY_ACCEL = 5;
|
||||||
#define RBOAT_SLOW_VELOCITY (RBOAT_MAX_VELOCITY / 3)
|
constexpr auto RBOAT_VELOCITY_DECEL = 1;
|
||||||
#define RBOAT_FAST_VELOCITY (RBOAT_MAX_VELOCITY + 75)
|
constexpr auto RBOAT_VELOCITY_BRAKE_DECEL = 5;
|
||||||
#define RBOAT_MIN_VELOCITY 20
|
constexpr auto RBOAT_REVERSE_VELOCITY_DECEL = 2;
|
||||||
#define RBOAT_MAX_BACK -20
|
|
||||||
#define RBOAT_MAX_KICK -80
|
|
||||||
|
|
||||||
#define RBOAT_ACCELERATION 5
|
constexpr auto RBOAT_VELOCITY_MIN = 20;
|
||||||
#define RBOAT_BRAKE 5
|
constexpr auto RBOAT_SLOW_VELOCITY_MAX = 37;
|
||||||
#define RBOAT_SLOW_DOWN 1
|
constexpr auto RBOAT_NORMAL_VELOCITY_MAX = 110;
|
||||||
#define RBOAT_UNDO_TURN ANGLE(0.25f)
|
constexpr auto RBOAT_FAST_VELOCITY_MAX = 185;
|
||||||
#define RBOAT_TURN (ANGLE(0.25f) / 2)
|
constexpr auto RBOAT_REVERSE_VELOCITY_MAX = 20;
|
||||||
|
|
||||||
#define RBOAT_IN_SPEED (IN_SPRINT | IN_CROUCH)
|
#define RBOAT_TURN_RATE_ACCEL (ANGLE(0.25f) / 2)
|
||||||
#define RBOAT_IN_SLOW IN_WALK
|
#define RBOAT_TURN_RATE_DECEL ANGLE(0.25f)
|
||||||
#define RBOAT_IN_DISMOUNT IN_ROLL
|
#define RBOAT_TURN_RATE_MAX ANGLE(4.0f)
|
||||||
#define RBOAT_IN_FORWARD IN_ACTION
|
|
||||||
#define RBOAT_IN_BACK IN_JUMP
|
|
||||||
#define RBOAT_IN_LEFT IN_LEFT
|
|
||||||
#define RBOAT_IN_RIGHT IN_RIGHT
|
|
||||||
|
|
||||||
enum RubberBoatState
|
enum RubberBoatState
|
||||||
{
|
{
|
||||||
|
@ -90,28 +93,90 @@ namespace TEN::Entities::Vehicles
|
||||||
RBOAT_ANIM_TURN_RIGHT_START = 22
|
RBOAT_ANIM_TURN_RIGHT_START = 22
|
||||||
};
|
};
|
||||||
|
|
||||||
enum RubberBoatMountType
|
RubberBoatInfo* GetRubberBoatInfo(ItemInfo* rBoatItem)
|
||||||
{
|
{
|
||||||
RBOAT_MOUNT_NONE = 0,
|
return (RubberBoatInfo*)rBoatItem->Data;
|
||||||
RBOAT_MOUNT_LEFT = 1,
|
}
|
||||||
RBOAT_MOUNT_RIGHT = 2,
|
|
||||||
RBOAT_MOUNT_JUMP = 3,
|
|
||||||
RBOAT_MOUNT_LEVEL_START = 4
|
|
||||||
};
|
|
||||||
|
|
||||||
void InitialiseRubberBoat(short itemNumber)
|
void InitialiseRubberBoat(short itemNumber)
|
||||||
{
|
{
|
||||||
auto* rBoatItem = &g_Level.Items[itemNumber];
|
auto* rBoatItem = &g_Level.Items[itemNumber];
|
||||||
rBoatItem->Data = RubberBoatInfo();
|
rBoatItem->Data = RubberBoatInfo();
|
||||||
auto* rBoat = (RubberBoatInfo*)rBoatItem->Data;
|
auto* rBoat = GetRubberBoatInfo(rBoatItem);
|
||||||
|
}
|
||||||
|
|
||||||
rBoat->TurnRate = 0;
|
void RubberBoatPlayerCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll)
|
||||||
rBoat->LeanAngle = 0;
|
{
|
||||||
rBoat->ExtraRotation = 0;
|
auto* rBoatItem = &g_Level.Items[itemNumber];
|
||||||
rBoat->LeftVerticalVelocity = 0;
|
auto* lara = GetLaraInfo(laraItem);
|
||||||
rBoat->RightVerticalVelocity = 0;
|
|
||||||
rBoat->Water = 0;
|
if (laraItem->HitPoints < 0 || lara->Vehicle != NO_ITEM)
|
||||||
rBoat->Pitch = 0;
|
return;
|
||||||
|
|
||||||
|
auto mountType = GetVehicleMountType(rBoatItem, laraItem, coll, RubberBoatMountTypes, RBOAT_MOUNT_DISTANCE, LARA_HEIGHT);
|
||||||
|
if (mountType == VehicleMountType::None)
|
||||||
|
{
|
||||||
|
coll->Setup.EnableObjectPush = true;
|
||||||
|
ObjectCollision(itemNumber, laraItem, coll);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lara->Vehicle = itemNumber;
|
||||||
|
DoRubberBoatMount(rBoatItem, laraItem, mountType);
|
||||||
|
|
||||||
|
if (g_Level.Items[itemNumber].Status != ITEM_ACTIVE)
|
||||||
|
{
|
||||||
|
AddActiveItem(itemNumber);
|
||||||
|
g_Level.Items[itemNumber].Status = ITEM_ACTIVE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DoRubberBoatMount(ItemInfo* rBoatItem, ItemInfo* laraItem, VehicleMountType mountType)
|
||||||
|
{
|
||||||
|
auto* lara = GetLaraInfo(laraItem);
|
||||||
|
|
||||||
|
switch (mountType)
|
||||||
|
{
|
||||||
|
case VehicleMountType::LevelStart:
|
||||||
|
laraItem->Animation.AnimNumber = Objects[ID_RUBBER_BOAT_LARA_ANIMS].animIndex + RBOAT_ANIM_IDLE;
|
||||||
|
laraItem->Animation.ActiveState = RBOAT_STATE_IDLE;
|
||||||
|
laraItem->Animation.TargetState = RBOAT_STATE_IDLE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VehicleMountType::Left:
|
||||||
|
laraItem->Animation.AnimNumber = Objects[ID_RUBBER_BOAT_LARA_ANIMS].animIndex + RBOAT_ANIM_MOUNT_LEFT;
|
||||||
|
laraItem->Animation.ActiveState = RBOAT_STATE_MOUNT;
|
||||||
|
laraItem->Animation.TargetState = RBOAT_STATE_MOUNT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VehicleMountType::Right:
|
||||||
|
laraItem->Animation.AnimNumber = Objects[ID_RUBBER_BOAT_LARA_ANIMS].animIndex + RBOAT_ANIM_MOUNT_RIGHT;
|
||||||
|
laraItem->Animation.ActiveState = RBOAT_STATE_MOUNT;
|
||||||
|
laraItem->Animation.TargetState = RBOAT_STATE_MOUNT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
case VehicleMountType::Jump:
|
||||||
|
laraItem->Animation.AnimNumber = Objects[ID_RUBBER_BOAT_LARA_ANIMS].animIndex + RBOAT_ANIM_MOUNT_JUMP;
|
||||||
|
laraItem->Animation.ActiveState = RBOAT_STATE_MOUNT;
|
||||||
|
laraItem->Animation.TargetState = RBOAT_STATE_MOUNT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
laraItem->Animation.FrameNumber = g_Level.Anims[laraItem->Animation.AnimNumber].frameBase;
|
||||||
|
|
||||||
|
if (laraItem->RoomNumber != rBoatItem->RoomNumber)
|
||||||
|
ItemNewRoom(lara->ItemNumber, rBoatItem->RoomNumber);
|
||||||
|
|
||||||
|
laraItem->Pose.Position = rBoatItem->Pose.Position;
|
||||||
|
laraItem->Pose.Position.y -= 5;
|
||||||
|
laraItem->Pose.Orientation = Vector3Shrt(0, rBoatItem->Pose.Orientation.y, 0);
|
||||||
|
laraItem->Animation.IsAirborne = false;
|
||||||
|
laraItem->Animation.Velocity = 0;
|
||||||
|
laraItem->Animation.VerticalVelocity = 0;
|
||||||
|
lara->Control.WaterStatus = WaterStatus::Dry;
|
||||||
|
|
||||||
|
AnimateItem(laraItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrawRubberBoat(ItemInfo* rBoatItem)
|
void DrawRubberBoat(ItemInfo* rBoatItem)
|
||||||
|
@ -126,95 +191,10 @@ namespace TEN::Entities::Vehicles
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
RubberBoatMountType GetRubberBoatMountType(ItemInfo* laraItem, short itemNumber, CollisionInfo* coll)
|
static void DoRubberBoatShift(int itemNumber, ItemInfo* laraItem)
|
||||||
{
|
{
|
||||||
auto* lara = GetLaraInfo(laraItem);
|
|
||||||
auto* rBoat = &g_Level.Items[itemNumber];
|
|
||||||
|
|
||||||
RubberBoatMountType mountType = RBOAT_MOUNT_NONE;
|
|
||||||
|
|
||||||
if (!(TrInput & IN_ACTION) ||
|
|
||||||
lara->Control.HandStatus != HandStatus::Free ||
|
|
||||||
laraItem->Animation.Airborne ||
|
|
||||||
rBoat->Animation.Velocity)
|
|
||||||
{
|
|
||||||
return mountType;
|
|
||||||
}
|
|
||||||
|
|
||||||
short x = laraItem->Pose.Position.x - rBoat->Pose.Position.x;
|
|
||||||
short z = laraItem->Pose.Position.z - rBoat->Pose.Position.z;
|
|
||||||
|
|
||||||
int distance = z * phd_cos(-rBoat->Pose.Orientation.y) - x * phd_sin(-rBoat->Pose.Orientation.y);
|
|
||||||
if (distance > CLICK(2))
|
|
||||||
return mountType;
|
|
||||||
|
|
||||||
short deltaAngle = rBoat->Pose.Orientation.y - laraItem->Pose.Orientation.y;
|
|
||||||
if (lara->Control.WaterStatus == WaterStatus::TreadWater || lara->Control.WaterStatus == WaterStatus::Wade)
|
|
||||||
{
|
|
||||||
if (deltaAngle > ANGLE(45.0f) && deltaAngle < ANGLE(135.0f))
|
|
||||||
mountType = RBOAT_MOUNT_LEFT;
|
|
||||||
if (deltaAngle < -ANGLE(135.0f) && deltaAngle > -ANGLE(45.0f))
|
|
||||||
mountType = RBOAT_MOUNT_RIGHT;
|
|
||||||
}
|
|
||||||
else if (lara->Control.WaterStatus == WaterStatus::Dry)
|
|
||||||
{
|
|
||||||
if (laraItem->Animation.VerticalVelocity > 0)
|
|
||||||
{
|
|
||||||
if ((laraItem->Pose.Position.y + CLICK(2)) > rBoat->Pose.Position.y)
|
|
||||||
mountType = RBOAT_MOUNT_JUMP;
|
|
||||||
}
|
|
||||||
else if (laraItem->Animation.VerticalVelocity == 0)
|
|
||||||
{
|
|
||||||
if (deltaAngle > -ANGLE(135.0f) && deltaAngle < ANGLE(135.0f))
|
|
||||||
{
|
|
||||||
if (laraItem->Pose.Position == rBoat->Pose.Position)
|
|
||||||
mountType = RBOAT_MOUNT_LEVEL_START;
|
|
||||||
else
|
|
||||||
mountType = RBOAT_MOUNT_JUMP;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mountType)
|
|
||||||
return RBOAT_MOUNT_NONE;
|
|
||||||
|
|
||||||
if (!TestBoundsCollide(rBoat, laraItem, coll->Setup.Radius))
|
|
||||||
return RBOAT_MOUNT_NONE;
|
|
||||||
|
|
||||||
if (!TestCollision(rBoat, laraItem))
|
|
||||||
return RBOAT_MOUNT_NONE;
|
|
||||||
|
|
||||||
return mountType;
|
|
||||||
}
|
|
||||||
|
|
||||||
int TestWaterHeight(ItemInfo* rBoatItem, int zOffset, int xOffset, Vector3Int* pos)
|
|
||||||
{
|
|
||||||
float sinX = phd_sin(rBoatItem->Pose.Orientation.x);
|
|
||||||
float sinY = phd_sin(rBoatItem->Pose.Orientation.y);
|
|
||||||
float cosY = phd_cos(rBoatItem->Pose.Orientation.y);
|
|
||||||
float sinZ = phd_sin(rBoatItem->Pose.Orientation.z);
|
|
||||||
|
|
||||||
pos->x = rBoatItem->Pose.Position.x + (zOffset * sinY) + (xOffset * cosY);
|
|
||||||
pos->y = rBoatItem->Pose.Position.y - (zOffset * sinX) + (xOffset * sinZ);
|
|
||||||
pos->z = rBoatItem->Pose.Position.z + (zOffset * cosY) - (xOffset * sinY);
|
|
||||||
|
|
||||||
auto probe = GetCollision(pos->x, pos->y, pos->z, rBoatItem->RoomNumber);
|
|
||||||
auto height = GetWaterHeight(pos->x, pos->y, pos->z, probe.RoomNumber);
|
|
||||||
|
|
||||||
if (height == NO_HEIGHT)
|
|
||||||
{
|
|
||||||
height = probe.Position.Floor;
|
|
||||||
if (height == NO_HEIGHT)
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (height - 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void DoRubberBoatShift(ItemInfo* laraItem, int itemNumber)
|
|
||||||
{
|
|
||||||
auto* lara = GetLaraInfo(laraItem);
|
|
||||||
auto* boatItem = &g_Level.Items[itemNumber];
|
auto* boatItem = &g_Level.Items[itemNumber];
|
||||||
|
auto* lara = GetLaraInfo(laraItem);
|
||||||
|
|
||||||
int itemNumber2 = g_Level.Rooms[boatItem->RoomNumber].itemNumber;
|
int itemNumber2 = g_Level.Rooms[boatItem->RoomNumber].itemNumber;
|
||||||
while (itemNumber2 != NO_ITEM)
|
while (itemNumber2 != NO_ITEM)
|
||||||
|
@ -368,37 +348,26 @@ namespace TEN::Entities::Vehicles
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int RubberBoatDynamics(ItemInfo* laraItem, short itemNumber)
|
static int RubberBoatDynamics(short itemNumber, ItemInfo* laraItem)
|
||||||
{
|
{
|
||||||
auto* lara = GetLaraInfo(laraItem);
|
|
||||||
auto* rBoatItem = &g_Level.Items[itemNumber];
|
auto* rBoatItem = &g_Level.Items[itemNumber];
|
||||||
auto* rBoat = (RubberBoatInfo*)rBoatItem->Data;
|
auto* rBoat = GetRubberBoatInfo(rBoatItem);
|
||||||
|
auto* lara = GetLaraInfo(laraItem);
|
||||||
|
|
||||||
rBoatItem->Pose.Orientation.z -= rBoat->LeanAngle;
|
rBoatItem->Pose.Orientation.z -= rBoat->LeanAngle;
|
||||||
|
|
||||||
Vector3Int frontLeftOld, frontRightOld, backLeftOld, backRightOld, frontOld;
|
Vector3Int frontLeftOld, frontRightOld, backLeftOld, backRightOld, frontOld;
|
||||||
int heightFrontLeftOld = TestWaterHeight(rBoatItem, RBOAT_FRONT, -RBOAT_SIDE, &frontLeftOld);
|
int heightFrontLeftOld = GetVehicleWaterHeight(rBoatItem, RBOAT_FRONT, -RBOAT_SIDE, true, &frontLeftOld);
|
||||||
int heightFrontRightOld = TestWaterHeight(rBoatItem, RBOAT_FRONT, RBOAT_SIDE, &frontRightOld);
|
int heightFrontRightOld = GetVehicleWaterHeight(rBoatItem, RBOAT_FRONT, RBOAT_SIDE, true, &frontRightOld);
|
||||||
int heightBackLeftOld = TestWaterHeight(rBoatItem, -RBOAT_FRONT, -RBOAT_SIDE, &backLeftOld);
|
int heightBackLeftOld = GetVehicleWaterHeight(rBoatItem, -RBOAT_FRONT, -RBOAT_SIDE, true, &backLeftOld);
|
||||||
int heightBackRightOld = TestWaterHeight(rBoatItem, -RBOAT_FRONT, RBOAT_SIDE, &backRightOld);
|
int heightBackRightOld = GetVehicleWaterHeight(rBoatItem, -RBOAT_FRONT, RBOAT_SIDE, true, &backRightOld);
|
||||||
int heightFrontOld = TestWaterHeight(rBoatItem, 1000, 0, &frontOld);
|
int heightFrontOld = GetVehicleWaterHeight(rBoatItem, 1000, 0, true, &frontOld);
|
||||||
|
|
||||||
Vector3Int old;
|
Vector3Int old;
|
||||||
old.x = rBoatItem->Pose.Position.x;
|
old.x = rBoatItem->Pose.Position.x;
|
||||||
old.y = rBoatItem->Pose.Position.y;
|
old.y = rBoatItem->Pose.Position.y;
|
||||||
old.z = rBoatItem->Pose.Position.z;
|
old.z = rBoatItem->Pose.Position.z;
|
||||||
|
|
||||||
if (backLeftOld.y > heightBackLeftOld)
|
|
||||||
backLeftOld.y = heightBackLeftOld;
|
|
||||||
if (backRightOld.y > heightBackRightOld)
|
|
||||||
backRightOld.y = heightBackRightOld;
|
|
||||||
if (frontLeftOld.y > heightFrontLeftOld)
|
|
||||||
frontLeftOld.y = heightFrontLeftOld;
|
|
||||||
if (frontRightOld.y > heightFrontRightOld)
|
|
||||||
frontRightOld.y = heightFrontRightOld;
|
|
||||||
if (frontOld.y > heightFrontOld)
|
|
||||||
frontOld.y = heightFrontOld;
|
|
||||||
|
|
||||||
rBoatItem->Pose.Orientation.y += rBoat->TurnRate + rBoat->ExtraRotation;
|
rBoatItem->Pose.Orientation.y += rBoat->TurnRate + rBoat->ExtraRotation;
|
||||||
rBoat->LeanAngle = rBoat->TurnRate * 6;
|
rBoat->LeanAngle = rBoat->TurnRate * 6;
|
||||||
|
|
||||||
|
@ -427,30 +396,30 @@ namespace TEN::Entities::Vehicles
|
||||||
moved.x = rBoatItem->Pose.Position.x;
|
moved.x = rBoatItem->Pose.Position.x;
|
||||||
moved.z = rBoatItem->Pose.Position.z;
|
moved.z = rBoatItem->Pose.Position.z;
|
||||||
|
|
||||||
DoRubberBoatShift(laraItem, itemNumber);
|
DoRubberBoatShift(itemNumber, laraItem);
|
||||||
|
|
||||||
Vector3Int frontLeft, frontRight, backRight, backLeft, front;
|
Vector3Int frontLeft, frontRight, backRight, backLeft, front;
|
||||||
short rotation = 0;
|
short rotation = 0;
|
||||||
|
|
||||||
int heightBackLeft = TestWaterHeight(rBoatItem, -RBOAT_FRONT, -RBOAT_SIDE, &backLeft);
|
int heightBackLeft = GetVehicleWaterHeight(rBoatItem, -RBOAT_FRONT, -RBOAT_SIDE, false, &backLeft);
|
||||||
if (heightBackLeft < (backLeftOld.y - CLICK(0.5f)))
|
if (heightBackLeft < (backLeftOld.y - CLICK(0.5f)))
|
||||||
rotation = DoRubberBoatShift2(rBoatItem, &backLeft, &backLeftOld);
|
rotation = DoRubberBoatShift2(rBoatItem, &backLeft, &backLeftOld);
|
||||||
|
|
||||||
int heightBackRight = TestWaterHeight(rBoatItem, -RBOAT_FRONT, RBOAT_SIDE, &backRight);
|
int heightBackRight = GetVehicleWaterHeight(rBoatItem, -RBOAT_FRONT, RBOAT_SIDE, false, &backRight);
|
||||||
if (heightBackRight < (backRightOld.y - CLICK(0.5f)))
|
if (heightBackRight < (backRightOld.y - CLICK(0.5f)))
|
||||||
rotation += DoRubberBoatShift2(rBoatItem, &backRight, &backRightOld);
|
rotation += DoRubberBoatShift2(rBoatItem, &backRight, &backRightOld);
|
||||||
|
|
||||||
int heightFrontLeft = TestWaterHeight(rBoatItem, RBOAT_FRONT, -RBOAT_SIDE, &frontLeft);
|
int heightFrontLeft = GetVehicleWaterHeight(rBoatItem, RBOAT_FRONT, -RBOAT_SIDE, false, &frontLeft);
|
||||||
if (heightFrontLeft < (frontLeftOld.y - CLICK(0.5f)))
|
if (heightFrontLeft < (frontLeftOld.y - CLICK(0.5f)))
|
||||||
rotation += DoRubberBoatShift2(rBoatItem, &frontLeft, &frontLeftOld);
|
rotation += DoRubberBoatShift2(rBoatItem, &frontLeft, &frontLeftOld);
|
||||||
|
|
||||||
int heightFrontRight = TestWaterHeight(rBoatItem, RBOAT_FRONT, RBOAT_SIDE, &frontRight);
|
int heightFrontRight = GetVehicleWaterHeight(rBoatItem, RBOAT_FRONT, RBOAT_SIDE, false, &frontRight);
|
||||||
if (heightFrontRight < (frontRightOld.y - CLICK(0.5f)))
|
if (heightFrontRight < (frontRightOld.y - CLICK(0.5f)))
|
||||||
rotation += DoRubberBoatShift2(rBoatItem, &frontRight, &frontRightOld);
|
rotation += DoRubberBoatShift2(rBoatItem, &frontRight, &frontRightOld);
|
||||||
|
|
||||||
if (!slip)
|
if (!slip)
|
||||||
{
|
{
|
||||||
int heightFront = TestWaterHeight(rBoatItem, 1000, 0, &front);
|
int heightFront = GetVehicleWaterHeight(rBoatItem, 1000, 0, false, &front);
|
||||||
if (heightFront < (frontOld.y - CLICK(0.5f)))
|
if (heightFront < (frontOld.y - CLICK(0.5f)))
|
||||||
DoRubberBoatShift2(rBoatItem, &front, &frontOld);
|
DoRubberBoatShift2(rBoatItem, &front, &frontOld);
|
||||||
}
|
}
|
||||||
|
@ -475,7 +444,7 @@ namespace TEN::Entities::Vehicles
|
||||||
int newVelocity = (rBoatItem->Pose.Position.z - old.z) * phd_cos(rBoatItem->Pose.Orientation.y) + (rBoatItem->Pose.Position.x - old.x) * phd_sin(rBoatItem->Pose.Orientation.y);
|
int newVelocity = (rBoatItem->Pose.Position.z - old.z) * phd_cos(rBoatItem->Pose.Orientation.y) + (rBoatItem->Pose.Position.x - old.x) * phd_sin(rBoatItem->Pose.Orientation.y);
|
||||||
|
|
||||||
if (lara->Vehicle == itemNumber &&
|
if (lara->Vehicle == itemNumber &&
|
||||||
rBoatItem->Animation.Velocity > (RBOAT_MAX_VELOCITY + RBOAT_ACCELERATION) &&
|
rBoatItem->Animation.Velocity > (RBOAT_NORMAL_VELOCITY_MAX + RBOAT_VELOCITY_ACCEL) &&
|
||||||
newVelocity < rBoatItem->Animation.Velocity - 10)
|
newVelocity < rBoatItem->Animation.Velocity - 10)
|
||||||
{
|
{
|
||||||
DoDamage(laraItem, rBoatItem->Animation.Velocity);
|
DoDamage(laraItem, rBoatItem->Animation.Velocity);
|
||||||
|
@ -486,7 +455,7 @@ namespace TEN::Entities::Vehicles
|
||||||
|
|
||||||
if (slip)
|
if (slip)
|
||||||
{
|
{
|
||||||
if (rBoatItem->Animation.Velocity <= RBOAT_MAX_VELOCITY + 10)
|
if (rBoatItem->Animation.Velocity <= RBOAT_NORMAL_VELOCITY_MAX + 10)
|
||||||
rBoatItem->Animation.Velocity = newVelocity;
|
rBoatItem->Animation.Velocity = newVelocity;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -497,8 +466,8 @@ namespace TEN::Entities::Vehicles
|
||||||
rBoatItem->Animation.Velocity = newVelocity;
|
rBoatItem->Animation.Velocity = newVelocity;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rBoatItem->Animation.Velocity < RBOAT_MAX_BACK)
|
if (rBoatItem->Animation.Velocity < -RBOAT_REVERSE_VELOCITY_MAX)
|
||||||
rBoatItem->Animation.Velocity = RBOAT_MAX_BACK;
|
rBoatItem->Animation.Velocity = -RBOAT_REVERSE_VELOCITY_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
return collide;
|
return collide;
|
||||||
|
@ -530,90 +499,90 @@ namespace TEN::Entities::Vehicles
|
||||||
return verticalVelocity;
|
return verticalVelocity;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RubberBoatUserControl(ItemInfo* laraItem, ItemInfo* rBoatItem)
|
bool RubberBoatUserControl(ItemInfo* rBoatItem, ItemInfo* laraItem)
|
||||||
{
|
{
|
||||||
auto* rBoat = (RubberBoatInfo*)rBoatItem->Data;
|
auto* rBoat = GetRubberBoatInfo(rBoatItem);
|
||||||
|
|
||||||
bool noTurn = true;
|
bool noTurn = true;
|
||||||
|
|
||||||
if (rBoatItem->Pose.Position.y >= (rBoat->Water - 128) &&
|
if (rBoatItem->Pose.Position.y >= (rBoat->Water - 128) &&
|
||||||
rBoat->Water != NO_HEIGHT)
|
rBoat->Water != NO_HEIGHT)
|
||||||
{
|
{
|
||||||
if (!(TrInput & RBOAT_IN_DISMOUNT) && !(TrInput & IN_LOOK) || rBoatItem->Animation.Velocity)
|
if (!(TrInput & VEHICLE_IN_DISMOUNT) && !(TrInput & IN_LOOK) || rBoatItem->Animation.Velocity)
|
||||||
{
|
{
|
||||||
if ((TrInput & RBOAT_IN_LEFT && !(TrInput & RBOAT_IN_BACK)) ||
|
if ((TrInput & VEHICLE_IN_LEFT && !(TrInput & VEHICLE_IN_REVERSE)) ||
|
||||||
(TrInput & RBOAT_IN_RIGHT && TrInput & RBOAT_IN_BACK))
|
(TrInput & VEHICLE_IN_RIGHT && TrInput & VEHICLE_IN_REVERSE))
|
||||||
{
|
{
|
||||||
if (rBoat->TurnRate > 0)
|
if (rBoat->TurnRate > 0)
|
||||||
rBoat->TurnRate -= ANGLE(0.25f);
|
rBoat->TurnRate -= RBOAT_TURN_RATE_DECEL;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rBoat->TurnRate -= ANGLE(0.25f) / 2;
|
rBoat->TurnRate -= RBOAT_TURN_RATE_ACCEL;
|
||||||
if (rBoat->TurnRate < -ANGLE(4.0f))
|
if (rBoat->TurnRate < -RBOAT_TURN_RATE_MAX)
|
||||||
rBoat->TurnRate = -ANGLE(4.0f);
|
rBoat->TurnRate = -RBOAT_TURN_RATE_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
noTurn = false;
|
noTurn = false;
|
||||||
}
|
}
|
||||||
else if ((TrInput & RBOAT_IN_RIGHT && !(TrInput & RBOAT_IN_BACK)) ||
|
else if ((TrInput & VEHICLE_IN_RIGHT && !(TrInput & VEHICLE_IN_REVERSE)) ||
|
||||||
(TrInput & RBOAT_IN_LEFT && TrInput & RBOAT_IN_BACK))
|
(TrInput & VEHICLE_IN_LEFT && TrInput & VEHICLE_IN_REVERSE))
|
||||||
{
|
{
|
||||||
if (rBoat->TurnRate < 0)
|
if (rBoat->TurnRate < 0)
|
||||||
rBoat->TurnRate += ANGLE(0.25f);
|
rBoat->TurnRate += RBOAT_TURN_RATE_DECEL;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rBoat->TurnRate += ANGLE(0.25f) / 2;
|
rBoat->TurnRate += RBOAT_TURN_RATE_ACCEL;
|
||||||
if (rBoat->TurnRate > ANGLE(4.0f))
|
if (rBoat->TurnRate > RBOAT_TURN_RATE_MAX)
|
||||||
rBoat->TurnRate = ANGLE(4.0f);
|
rBoat->TurnRate = RBOAT_TURN_RATE_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
noTurn = false;
|
noTurn = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TrInput & RBOAT_IN_BACK)
|
if (TrInput & VEHICLE_IN_REVERSE)
|
||||||
{
|
{
|
||||||
if (rBoatItem->Animation.Velocity > 0)
|
if (rBoatItem->Animation.Velocity > 0)
|
||||||
rBoatItem->Animation.Velocity -= 5;
|
rBoatItem->Animation.Velocity -= RBOAT_VELOCITY_BRAKE_DECEL;
|
||||||
else if (rBoatItem->Animation.Velocity > -20)
|
else if (rBoatItem->Animation.Velocity > -RBOAT_REVERSE_VELOCITY_MAX)
|
||||||
rBoatItem->Animation.Velocity += -2;
|
rBoatItem->Animation.Velocity -= RBOAT_REVERSE_VELOCITY_DECEL;
|
||||||
}
|
}
|
||||||
else if (TrInput & RBOAT_IN_FORWARD)
|
else if (TrInput & VEHICLE_IN_ACCELERATE)
|
||||||
{
|
{
|
||||||
int maxVelocity;
|
int maxVelocity;
|
||||||
if (TrInput & RBOAT_IN_SPEED)
|
if (TrInput & VEHICLE_IN_SPEED)
|
||||||
maxVelocity = 185;
|
maxVelocity = RBOAT_FAST_VELOCITY_MAX;
|
||||||
else
|
else
|
||||||
maxVelocity = (TrInput & RBOAT_IN_SLOW) ? 37 : 110;
|
maxVelocity = (TrInput & VEHICLE_IN_SLOW) ? RBOAT_SLOW_VELOCITY_MAX : RBOAT_NORMAL_VELOCITY_MAX;
|
||||||
|
|
||||||
if (rBoatItem->Animation.Velocity < maxVelocity)
|
if (rBoatItem->Animation.Velocity < maxVelocity)
|
||||||
rBoatItem->Animation.Velocity += 3 + (5 * rBoatItem->Animation.Velocity) / (maxVelocity * 2);
|
rBoatItem->Animation.Velocity += (RBOAT_VELOCITY_ACCEL / 2 + 1) + (RBOAT_VELOCITY_ACCEL * rBoatItem->Animation.Velocity) / (maxVelocity * 2);
|
||||||
else if (rBoatItem->Animation.Velocity > (maxVelocity + 1))
|
else if (rBoatItem->Animation.Velocity > (maxVelocity + RBOAT_VELOCITY_DECEL))
|
||||||
rBoatItem->Animation.Velocity -= 1;
|
rBoatItem->Animation.Velocity -= RBOAT_VELOCITY_DECEL;
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (TrInput & (RBOAT_IN_LEFT | RBOAT_IN_RIGHT) &&
|
else if (TrInput & (VEHICLE_IN_LEFT | VEHICLE_IN_RIGHT) &&
|
||||||
rBoatItem->Animation.Velocity >= 0 &&
|
rBoatItem->Animation.Velocity >= 0 &&
|
||||||
rBoatItem->Animation.Velocity < 20)
|
rBoatItem->Animation.Velocity < RBOAT_VELOCITY_MIN)
|
||||||
{
|
{
|
||||||
if (!(TrInput & RBOAT_IN_DISMOUNT) && rBoatItem->Animation.Velocity == 0)
|
if (!(TrInput & VEHICLE_IN_DISMOUNT) && rBoatItem->Animation.Velocity == 0)
|
||||||
rBoatItem->Animation.Velocity = 20;
|
rBoatItem->Animation.Velocity = RBOAT_VELOCITY_MIN;
|
||||||
}
|
}
|
||||||
else if (rBoatItem->Animation.Velocity > 1)
|
else if (rBoatItem->Animation.Velocity > RBOAT_VELOCITY_DECEL)
|
||||||
rBoatItem->Animation.Velocity -= 1;
|
rBoatItem->Animation.Velocity -= RBOAT_VELOCITY_DECEL;
|
||||||
else
|
else
|
||||||
rBoatItem->Animation.Velocity = 0;
|
rBoatItem->Animation.Velocity = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (TrInput & (RBOAT_IN_LEFT | RBOAT_IN_RIGHT) &&
|
if (TrInput & (VEHICLE_IN_LEFT | VEHICLE_IN_RIGHT) &&
|
||||||
rBoatItem->Animation.Velocity >= 0 &&
|
rBoatItem->Animation.Velocity >= 0 &&
|
||||||
rBoatItem->Animation.Velocity < 20)
|
rBoatItem->Animation.Velocity < RBOAT_VELOCITY_MIN)
|
||||||
{
|
{
|
||||||
if (!(TrInput & RBOAT_IN_DISMOUNT) && rBoatItem->Animation.Velocity == 0)
|
if (!(TrInput & VEHICLE_IN_DISMOUNT) && rBoatItem->Animation.Velocity == 0)
|
||||||
rBoatItem->Animation.Velocity = 20;
|
rBoatItem->Animation.Velocity = RBOAT_VELOCITY_MIN;
|
||||||
}
|
}
|
||||||
else if (rBoatItem->Animation.Velocity > 1)
|
else if (rBoatItem->Animation.Velocity > RBOAT_VELOCITY_DECEL)
|
||||||
rBoatItem->Animation.Velocity -= 1;
|
rBoatItem->Animation.Velocity -= RBOAT_VELOCITY_DECEL;
|
||||||
else
|
else
|
||||||
rBoatItem->Animation.Velocity = 0;
|
rBoatItem->Animation.Velocity = 0;
|
||||||
|
|
||||||
|
@ -625,59 +594,6 @@ namespace TEN::Entities::Vehicles
|
||||||
return noTurn;
|
return noTurn;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RubberBoatCollision(short itemNum, ItemInfo* laraItem, CollisionInfo* coll)
|
|
||||||
{
|
|
||||||
auto* lara = GetLaraInfo(laraItem);
|
|
||||||
|
|
||||||
if (laraItem->HitPoints <= 0 || lara->Vehicle != NO_ITEM)
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto* item = &g_Level.Items[itemNum];
|
|
||||||
int mountType = GetRubberBoatMountType(laraItem, itemNum, coll);
|
|
||||||
|
|
||||||
if (!mountType)
|
|
||||||
{
|
|
||||||
coll->Setup.EnableObjectPush = true;
|
|
||||||
ObjectCollision(itemNum, laraItem, coll);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
lara->Vehicle = itemNum;
|
|
||||||
|
|
||||||
if (mountType == 1)
|
|
||||||
laraItem->Animation.AnimNumber = Objects[ID_RUBBER_BOAT_LARA_ANIMS].animIndex + RBOAT_ANIM_MOUNT_RIGHT;
|
|
||||||
else if (mountType == 2)
|
|
||||||
laraItem->Animation.AnimNumber = Objects[ID_RUBBER_BOAT_LARA_ANIMS].animIndex + RBOAT_ANIM_MOUNT_LEFT;
|
|
||||||
else if (mountType == 3)
|
|
||||||
laraItem->Animation.AnimNumber = Objects[ID_RUBBER_BOAT_LARA_ANIMS].animIndex + RBOAT_ANIM_MOUNT_JUMP;
|
|
||||||
else
|
|
||||||
laraItem->Animation.AnimNumber = Objects[ID_RUBBER_BOAT_LARA_ANIMS].animIndex + RBOAT_ANIM_IDLE;
|
|
||||||
|
|
||||||
laraItem->Pose.Position.x = item->Pose.Position.x;
|
|
||||||
laraItem->Pose.Position.y = item->Pose.Position.y - 5;
|
|
||||||
laraItem->Pose.Position.z = item->Pose.Position.z;
|
|
||||||
laraItem->Pose.Orientation.x = 0;
|
|
||||||
laraItem->Pose.Orientation.y = item->Pose.Orientation.y;
|
|
||||||
laraItem->Pose.Orientation.z = 0;
|
|
||||||
laraItem->Animation.Airborne = false;
|
|
||||||
laraItem->Animation.Velocity = 0;
|
|
||||||
laraItem->Animation.VerticalVelocity = 0;
|
|
||||||
laraItem->Animation.ActiveState = 0;
|
|
||||||
laraItem->Animation.FrameNumber = g_Level.Anims[laraItem->Animation.AnimNumber].frameBase;
|
|
||||||
lara->Control.WaterStatus = WaterStatus::Dry;
|
|
||||||
|
|
||||||
if (laraItem->RoomNumber != item->RoomNumber)
|
|
||||||
ItemNewRoom(lara->ItemNumber, item->RoomNumber);
|
|
||||||
|
|
||||||
AnimateItem(laraItem);
|
|
||||||
|
|
||||||
if (g_Level.Items[itemNum].Status != ITEM_ACTIVE)
|
|
||||||
{
|
|
||||||
AddActiveItem(itemNum);
|
|
||||||
g_Level.Items[itemNum].Status = ITEM_ACTIVE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool TestRubberBoatDismount(ItemInfo* laraItem, int direction)
|
static bool TestRubberBoatDismount(ItemInfo* laraItem, int direction)
|
||||||
{
|
{
|
||||||
auto* lara = GetLaraInfo(laraItem);
|
auto* lara = GetLaraInfo(laraItem);
|
||||||
|
@ -710,9 +626,9 @@ namespace TEN::Entities::Vehicles
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RubberBoatAnimation(ItemInfo* laraItem, ItemInfo* rBoatItem, int collide)
|
void RubberBoatAnimation(ItemInfo* rBoatItem, ItemInfo* laraItem, int collide)
|
||||||
{
|
{
|
||||||
auto* rBoat = (RubberBoatInfo*)rBoatItem->Data;
|
auto* rBoat = GetRubberBoatInfo(rBoatItem);
|
||||||
|
|
||||||
if (laraItem->HitPoints <= 0)
|
if (laraItem->HitPoints <= 0)
|
||||||
{
|
{
|
||||||
|
@ -750,7 +666,7 @@ namespace TEN::Entities::Vehicles
|
||||||
switch (laraItem->Animation.ActiveState)
|
switch (laraItem->Animation.ActiveState)
|
||||||
{
|
{
|
||||||
case RBOAT_STATE_IDLE:
|
case RBOAT_STATE_IDLE:
|
||||||
if (TrInput & RBOAT_IN_DISMOUNT)
|
if (TrInput & VEHICLE_IN_DISMOUNT)
|
||||||
{
|
{
|
||||||
if (rBoatItem->Animation.Velocity == 0)
|
if (rBoatItem->Animation.Velocity == 0)
|
||||||
{
|
{
|
||||||
|
@ -770,9 +686,9 @@ namespace TEN::Entities::Vehicles
|
||||||
if (rBoatItem->Animation.Velocity <= 0)
|
if (rBoatItem->Animation.Velocity <= 0)
|
||||||
laraItem->Animation.TargetState = RBOAT_STATE_IDLE;
|
laraItem->Animation.TargetState = RBOAT_STATE_IDLE;
|
||||||
|
|
||||||
if (TrInput & RBOAT_IN_RIGHT)
|
if (TrInput & VEHICLE_IN_RIGHT)
|
||||||
laraItem->Animation.TargetState = RBOAT_STATE_TURN_RIGHT;
|
laraItem->Animation.TargetState = RBOAT_STATE_TURN_RIGHT;
|
||||||
else if (TrInput & RBOAT_IN_LEFT)
|
else if (TrInput & VEHICLE_IN_LEFT)
|
||||||
laraItem->Animation.TargetState = RBOAT_STATE_TURN_LEFT;
|
laraItem->Animation.TargetState = RBOAT_STATE_TURN_LEFT;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -784,7 +700,7 @@ namespace TEN::Entities::Vehicles
|
||||||
case RBOAT_STATE_TURN_RIGHT:
|
case RBOAT_STATE_TURN_RIGHT:
|
||||||
if (rBoatItem->Animation.Velocity <= 0)
|
if (rBoatItem->Animation.Velocity <= 0)
|
||||||
laraItem->Animation.TargetState = RBOAT_STATE_IDLE;
|
laraItem->Animation.TargetState = RBOAT_STATE_IDLE;
|
||||||
else if (!(TrInput & RBOAT_IN_RIGHT))
|
else if (!(TrInput & VEHICLE_IN_RIGHT))
|
||||||
laraItem->Animation.TargetState = RBOAT_STATE_MOVING;
|
laraItem->Animation.TargetState = RBOAT_STATE_MOVING;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -792,7 +708,7 @@ namespace TEN::Entities::Vehicles
|
||||||
case RBOAT_STATE_TURN_LEFT:
|
case RBOAT_STATE_TURN_LEFT:
|
||||||
if (rBoatItem->Animation.Velocity <= 0)
|
if (rBoatItem->Animation.Velocity <= 0)
|
||||||
laraItem->Animation.TargetState = RBOAT_STATE_IDLE;
|
laraItem->Animation.TargetState = RBOAT_STATE_IDLE;
|
||||||
else if (!(TrInput & RBOAT_IN_LEFT))
|
else if (!(TrInput & VEHICLE_IN_LEFT))
|
||||||
laraItem->Animation.TargetState = RBOAT_STATE_MOVING;
|
laraItem->Animation.TargetState = RBOAT_STATE_MOVING;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -863,7 +779,7 @@ namespace TEN::Entities::Vehicles
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DoRubberBoatDismount(ItemInfo* laraItem, ItemInfo* rBoatItem)
|
void DoRubberBoatDismount(ItemInfo* rBoatItem, ItemInfo* laraItem)
|
||||||
{
|
{
|
||||||
auto* lara = GetLaraInfo(laraItem);
|
auto* lara = GetLaraInfo(laraItem);
|
||||||
|
|
||||||
|
@ -881,7 +797,7 @@ namespace TEN::Entities::Vehicles
|
||||||
laraItem->Animation.TargetState = LS_JUMP_FORWARD;
|
laraItem->Animation.TargetState = LS_JUMP_FORWARD;
|
||||||
laraItem->Pose.Orientation.x = 0;
|
laraItem->Pose.Orientation.x = 0;
|
||||||
laraItem->Pose.Orientation.z = 0;
|
laraItem->Pose.Orientation.z = 0;
|
||||||
laraItem->Animation.Airborne = true;
|
laraItem->Animation.IsAirborne = true;
|
||||||
laraItem->Animation.Velocity = 20;
|
laraItem->Animation.Velocity = 20;
|
||||||
laraItem->Animation.VerticalVelocity = -40;
|
laraItem->Animation.VerticalVelocity = -40;
|
||||||
lara->Vehicle = NO_ITEM;
|
lara->Vehicle = NO_ITEM;
|
||||||
|
@ -908,10 +824,10 @@ namespace TEN::Entities::Vehicles
|
||||||
|
|
||||||
void RubberBoatControl(short itemNumber)
|
void RubberBoatControl(short itemNumber)
|
||||||
{
|
{
|
||||||
|
auto* rBoatItem = &g_Level.Items[itemNumber];
|
||||||
|
auto* rBoat = GetRubberBoatInfo(rBoatItem);
|
||||||
auto* laraItem = LaraItem;
|
auto* laraItem = LaraItem;
|
||||||
auto* lara = GetLaraInfo(laraItem);
|
auto* lara = GetLaraInfo(laraItem);
|
||||||
auto* rBoatItem = &g_Level.Items[itemNumber];
|
|
||||||
auto* rBoat = (RubberBoatInfo*)rBoatItem->Data;
|
|
||||||
|
|
||||||
bool noTurn = true;
|
bool noTurn = true;
|
||||||
bool drive = false;
|
bool drive = false;
|
||||||
|
@ -919,10 +835,9 @@ namespace TEN::Entities::Vehicles
|
||||||
int pitch, height, ofs, nowake;
|
int pitch, height, ofs, nowake;
|
||||||
|
|
||||||
Vector3Int frontLeft, frontRight;
|
Vector3Int frontLeft, frontRight;
|
||||||
int collide = RubberBoatDynamics(laraItem, itemNumber);
|
int collide = RubberBoatDynamics(itemNumber, laraItem);
|
||||||
int heightFrontLeft = TestWaterHeight(rBoatItem, RBOAT_FRONT, -RBOAT_SIDE, &frontLeft);
|
int heightFrontLeft = GetVehicleWaterHeight(rBoatItem, RBOAT_FRONT, -RBOAT_SIDE, true, &frontLeft);
|
||||||
int heightFrontRight = TestWaterHeight(rBoatItem, RBOAT_FRONT, RBOAT_SIDE, &frontRight);
|
int heightFrontRight = GetVehicleWaterHeight(rBoatItem, RBOAT_FRONT, RBOAT_SIDE, true, &frontRight);
|
||||||
|
|
||||||
|
|
||||||
if (lara->Vehicle == itemNumber)
|
if (lara->Vehicle == itemNumber)
|
||||||
{
|
{
|
||||||
|
@ -945,24 +860,24 @@ namespace TEN::Entities::Vehicles
|
||||||
|
|
||||||
default:
|
default:
|
||||||
drive = true;
|
drive = true;
|
||||||
noTurn = RubberBoatUserControl(laraItem, rBoatItem);
|
noTurn = RubberBoatUserControl(rBoatItem, laraItem);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (rBoatItem->Animation.Velocity > RBOAT_SLOW_DOWN)
|
if (rBoatItem->Animation.Velocity > RBOAT_VELOCITY_DECEL)
|
||||||
rBoatItem->Animation.Velocity -= RBOAT_SLOW_DOWN;
|
rBoatItem->Animation.Velocity -= RBOAT_VELOCITY_DECEL;
|
||||||
else
|
else
|
||||||
rBoatItem->Animation.Velocity = 0;
|
rBoatItem->Animation.Velocity = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (noTurn)
|
if (noTurn)
|
||||||
{
|
{
|
||||||
if (rBoat->TurnRate < -RBOAT_UNDO_TURN)
|
if (rBoat->TurnRate < -RBOAT_TURN_RATE_DECEL)
|
||||||
rBoat->TurnRate += RBOAT_UNDO_TURN;
|
rBoat->TurnRate += RBOAT_TURN_RATE_DECEL;
|
||||||
else if (rBoat->TurnRate > RBOAT_UNDO_TURN)
|
else if (rBoat->TurnRate > RBOAT_TURN_RATE_DECEL)
|
||||||
rBoat->TurnRate -= RBOAT_UNDO_TURN;
|
rBoat->TurnRate -= RBOAT_TURN_RATE_DECEL;
|
||||||
else
|
else
|
||||||
rBoat->TurnRate = 0;
|
rBoat->TurnRate = 0;
|
||||||
}
|
}
|
||||||
|
@ -999,7 +914,7 @@ namespace TEN::Entities::Vehicles
|
||||||
|
|
||||||
if (lara->Vehicle == itemNumber)
|
if (lara->Vehicle == itemNumber)
|
||||||
{
|
{
|
||||||
RubberBoatAnimation(laraItem, rBoatItem, collide);
|
RubberBoatAnimation(rBoatItem, laraItem, collide);
|
||||||
|
|
||||||
if (probe.RoomNumber != rBoatItem->RoomNumber)
|
if (probe.RoomNumber != rBoatItem->RoomNumber)
|
||||||
{
|
{
|
||||||
|
@ -1033,14 +948,14 @@ namespace TEN::Entities::Vehicles
|
||||||
rBoat->Pitch += ((pitch - rBoat->Pitch) / 4);
|
rBoat->Pitch += ((pitch - rBoat->Pitch) / 4);
|
||||||
|
|
||||||
if (rBoatItem->Animation.Velocity > 8)
|
if (rBoatItem->Animation.Velocity > 8)
|
||||||
SoundEffect(SFX_TR3_VEHICLE_RUBBERBOAT_MOVING, &rBoatItem->Pose, SoundEnvironment::Land, 0.5f + (float)abs(rBoat->Pitch) / (float)RBOAT_MAX_VELOCITY);
|
SoundEffect(SFX_TR3_VEHICLE_RUBBERBOAT_MOVING, &rBoatItem->Pose, SoundEnvironment::Land, 0.5f + (float)abs(rBoat->Pitch) / (float)RBOAT_NORMAL_VELOCITY_MAX);
|
||||||
else if (drive)
|
else if (drive)
|
||||||
SoundEffect(SFX_TR3_VEHICLE_RUBBERBOAT_IDLE, &rBoatItem->Pose, SoundEnvironment::Land, 0.5f + (float)abs(rBoat->Pitch) / (float)RBOAT_MAX_VELOCITY);
|
SoundEffect(SFX_TR3_VEHICLE_RUBBERBOAT_IDLE, &rBoatItem->Pose, SoundEnvironment::Land, 0.5f + (float)abs(rBoat->Pitch) / (float)RBOAT_NORMAL_VELOCITY_MAX);
|
||||||
|
|
||||||
if (lara->Vehicle != itemNumber)
|
if (lara->Vehicle != itemNumber)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
DoRubberBoatDismount(laraItem, rBoatItem);
|
DoRubberBoatDismount(rBoatItem, laraItem);
|
||||||
|
|
||||||
short probedRoomNumber = GetCollision(rBoatItem->Pose.Position.x, rBoatItem->Pose.Position.y + 128, rBoatItem->Pose.Position.z, rBoatItem->RoomNumber).RoomNumber;
|
short probedRoomNumber = GetCollision(rBoatItem->Pose.Position.x, rBoatItem->Pose.Position.y + 128, rBoatItem->Pose.Position.z, rBoatItem->RoomNumber).RoomNumber;
|
||||||
height = GetWaterHeight(rBoatItem->Pose.Position.x, rBoatItem->Pose.Position.y + 128, rBoatItem->Pose.Position.z, probedRoomNumber);
|
height = GetWaterHeight(rBoatItem->Pose.Position.x, rBoatItem->Pose.Position.y + 128, rBoatItem->Pose.Position.z, probedRoomNumber);
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
#include "Objects/Utils/VehicleHelpers.h"
|
||||||
|
|
||||||
#include "Game/items.h"
|
struct CollisionInfo;
|
||||||
#include "Game/collision/collide_room.h"
|
struct ItemInfo;
|
||||||
|
|
||||||
namespace TEN::Entities::Vehicles
|
namespace TEN::Entities::Vehicles
|
||||||
{
|
{
|
||||||
void InitialiseRubberBoat(short itemNumber);
|
void InitialiseRubberBoat(short itemNumber);
|
||||||
void RubberBoatCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll);
|
|
||||||
|
void RubberBoatPlayerCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll);
|
||||||
|
void DoRubberBoatMount(ItemInfo* rBoatItem, ItemInfo* laraItem, VehicleMountType mountType);
|
||||||
|
|
||||||
void RubberBoatControl(short itemNumber);
|
void RubberBoatControl(short itemNumber);
|
||||||
void DrawRubberBoat(ItemInfo* rBoatItem);
|
void DrawRubberBoat(ItemInfo* rBoatItem);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,15 +4,15 @@ namespace TEN::Entities::Vehicles
|
||||||
{
|
{
|
||||||
struct RubberBoatInfo
|
struct RubberBoatInfo
|
||||||
{
|
{
|
||||||
int TurnRate;
|
int TurnRate = 0;
|
||||||
short LeanAngle;
|
short LeanAngle = 0;
|
||||||
short PropellerRotation;
|
short PropellerRotation = 0;
|
||||||
short ExtraRotation;
|
short ExtraRotation = 0;
|
||||||
|
|
||||||
int LeftVerticalVelocity;
|
int LeftVerticalVelocity = 0;
|
||||||
int RightVerticalVelocity;
|
int RightVerticalVelocity = 0;
|
||||||
|
|
||||||
int Water;
|
int Water = 0;
|
||||||
int Pitch;
|
int Pitch = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,11 +1,16 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "Game/items.h"
|
#include "Objects/Utils/VehicleHelpers.h"
|
||||||
#include "Game/collision/collide_room.h"
|
|
||||||
|
struct CollisionInfo;
|
||||||
|
struct ItemInfo;
|
||||||
|
|
||||||
namespace TEN::Entities::Vehicles
|
namespace TEN::Entities::Vehicles
|
||||||
{
|
{
|
||||||
void UPVInitialise(short itemNumber);
|
void UPVInitialise(short itemNumber);
|
||||||
void UPVCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll);
|
|
||||||
|
void UPVPlayerCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll);
|
||||||
|
void DoUPVMount(ItemInfo* UPVItem, ItemInfo* laraItem, VehicleMountType mountType);
|
||||||
|
|
||||||
void UPVEffects(short itemNumber);
|
void UPVEffects(short itemNumber);
|
||||||
bool UPVControl(ItemInfo* laraItem, CollisionInfo* coll);
|
bool UPVControl(ItemInfo* laraItem, CollisionInfo* coll);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,13 +4,16 @@ namespace TEN::Entities::Vehicles
|
||||||
{
|
{
|
||||||
struct UPVInfo
|
struct UPVInfo
|
||||||
{
|
{
|
||||||
int Velocity;
|
Vector3Shrt TurnRate;
|
||||||
int Rot;
|
short TurbineRotation = 0;
|
||||||
int XRot;
|
short LeftRudderRotation = 0;
|
||||||
short FanRot;
|
short RightRudderRotation = 0;
|
||||||
unsigned int HarpoonTimer;
|
|
||||||
bool HarpoonLeft;
|
|
||||||
|
|
||||||
char Flags;
|
int Velocity = 0;
|
||||||
|
|
||||||
|
unsigned int HarpoonTimer = 0;
|
||||||
|
bool HarpoonLeft = false;
|
||||||
|
|
||||||
|
char Flags = NULL;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
#include "Objects/TR3/Vehicles/big_gun.h"
|
#include "Objects/TR3/Vehicles/big_gun.h"
|
||||||
#include "Objects/TR3/Vehicles/kayak.h"
|
#include "Objects/TR3/Vehicles/kayak.h"
|
||||||
#include "Objects/TR3/Vehicles/minecart.h"
|
#include "Objects/TR3/Vehicles/minecart.h"
|
||||||
#include "Objects/TR3/Vehicles/quad.h"
|
#include "Objects/TR3/Vehicles/quad_bike.h"
|
||||||
#include "Objects/TR3/Vehicles/upv.h"
|
#include "Objects/TR3/Vehicles/upv.h"
|
||||||
#include "Objects/TR3/Vehicles/rubber_boat.h"
|
#include "Objects/TR3/Vehicles/rubber_boat.h"
|
||||||
/// necessary import
|
/// necessary import
|
||||||
|
@ -388,7 +388,7 @@ static void StartVehicles(ObjectInfo* obj)
|
||||||
if (obj->loaded)
|
if (obj->loaded)
|
||||||
{
|
{
|
||||||
obj->initialise = InitialiseQuadBike;
|
obj->initialise = InitialiseQuadBike;
|
||||||
obj->collision = QuadBikeCollision;
|
obj->collision = QuadBikePlayerCollision;
|
||||||
obj->hitEffect = HIT_RICOCHET;
|
obj->hitEffect = HIT_RICOCHET;
|
||||||
obj->savePosition = true;
|
obj->savePosition = true;
|
||||||
obj->saveAnim = true;
|
obj->saveAnim = true;
|
||||||
|
@ -401,7 +401,7 @@ static void StartVehicles(ObjectInfo* obj)
|
||||||
{
|
{
|
||||||
obj->initialise = InitialiseRubberBoat;
|
obj->initialise = InitialiseRubberBoat;
|
||||||
obj->control = RubberBoatControl;
|
obj->control = RubberBoatControl;
|
||||||
obj->collision = RubberBoatCollision;
|
obj->collision = RubberBoatPlayerCollision;
|
||||||
obj->drawRoutine = DrawRubberBoat;
|
obj->drawRoutine = DrawRubberBoat;
|
||||||
obj->hitEffect = HIT_RICOCHET;
|
obj->hitEffect = HIT_RICOCHET;
|
||||||
obj->savePosition = true;
|
obj->savePosition = true;
|
||||||
|
@ -415,7 +415,7 @@ static void StartVehicles(ObjectInfo* obj)
|
||||||
if (obj->loaded)
|
if (obj->loaded)
|
||||||
{
|
{
|
||||||
obj->initialise = InitialiseKayak;
|
obj->initialise = InitialiseKayak;
|
||||||
obj->collision = KayakCollision;
|
obj->collision = KayakPlayerCollision;
|
||||||
//obj->drawRoutine = KayakDraw;
|
//obj->drawRoutine = KayakDraw;
|
||||||
obj->hitEffect = HIT_RICOCHET;
|
obj->hitEffect = HIT_RICOCHET;
|
||||||
obj->saveAnim = true;
|
obj->saveAnim = true;
|
||||||
|
@ -429,7 +429,7 @@ static void StartVehicles(ObjectInfo* obj)
|
||||||
if (obj->loaded)
|
if (obj->loaded)
|
||||||
{
|
{
|
||||||
obj->initialise = InitialiseMinecart;
|
obj->initialise = InitialiseMinecart;
|
||||||
obj->collision = MinecartCollision;
|
obj->collision = MinecartPlayerCollision;
|
||||||
obj->hitEffect = HIT_RICOCHET;
|
obj->hitEffect = HIT_RICOCHET;
|
||||||
obj->saveAnim = true;
|
obj->saveAnim = true;
|
||||||
obj->saveFlags = true;
|
obj->saveFlags = true;
|
||||||
|
@ -455,7 +455,7 @@ static void StartVehicles(ObjectInfo* obj)
|
||||||
{
|
{
|
||||||
obj->initialise = UPVInitialise;
|
obj->initialise = UPVInitialise;
|
||||||
obj->control = UPVEffects;
|
obj->control = UPVEffects;
|
||||||
obj->collision = UPVCollision;
|
obj->collision = UPVPlayerCollision;
|
||||||
// obj->drawRoutine = SubDraw;
|
// obj->drawRoutine = SubDraw;
|
||||||
obj->hitEffect = HIT_RICOCHET;
|
obj->hitEffect = HIT_RICOCHET;
|
||||||
obj->saveAnim = true;
|
obj->saveAnim = true;
|
||||||
|
|
|
@ -354,7 +354,7 @@ namespace TEN::Entities::TR4
|
||||||
}
|
}
|
||||||
else if (creature->Mood == MoodType::Attack)
|
else if (creature->Mood == MoodType::Attack)
|
||||||
{
|
{
|
||||||
if (!(item->AIBits & FOLLOW) || (!item->Animation.Airborne && AI.distance <= pow(BABOON_ROLL_FORWARD_RANGE, 2)))
|
if (!(item->AIBits & FOLLOW) || (!item->Animation.IsAirborne && AI.distance <= pow(BABOON_ROLL_FORWARD_RANGE, 2)))
|
||||||
{
|
{
|
||||||
if (AI.bite && AI.distance < pow(BABOON_ATTACK_RANGE, 2))
|
if (AI.bite && AI.distance < pow(BABOON_ATTACK_RANGE, 2))
|
||||||
{
|
{
|
||||||
|
@ -471,7 +471,7 @@ namespace TEN::Entities::TR4
|
||||||
if (AI.ahead && Lara.TargetEntity != item)
|
if (AI.ahead && Lara.TargetEntity != item)
|
||||||
item->Animation.TargetState = BABOON_STATE_IDLE;
|
item->Animation.TargetState = BABOON_STATE_IDLE;
|
||||||
}
|
}
|
||||||
else if (item->AIBits & FOLLOW && (item->Animation.Airborne || AI.distance > pow(BABOON_FOLLOW_RANGE, 2)))
|
else if (item->AIBits & FOLLOW && (item->Animation.IsAirborne || AI.distance > pow(BABOON_FOLLOW_RANGE, 2)))
|
||||||
item->Animation.TargetState = BABOON_STATE_IDLE;
|
item->Animation.TargetState = BABOON_STATE_IDLE;
|
||||||
else if (creature->Mood == MoodType::Attack)
|
else if (creature->Mood == MoodType::Attack)
|
||||||
{
|
{
|
||||||
|
|
|
@ -437,31 +437,31 @@ namespace TEN::Entities::TR4
|
||||||
switch (item->Animation.ActiveState)
|
switch (item->Animation.ActiveState)
|
||||||
{
|
{
|
||||||
case BADDY_STATE_DEATH:
|
case BADDY_STATE_DEATH:
|
||||||
item->Animation.Airborne = true;
|
item->Animation.IsAirborne = true;
|
||||||
currentCreature->LOT.IsMonkeying = false;
|
currentCreature->LOT.IsMonkeying = false;
|
||||||
|
|
||||||
if (item->Pose.Position.y >= item->Floor)
|
if (item->Pose.Position.y >= item->Floor)
|
||||||
{
|
{
|
||||||
item->Pose.Position.y = item->Floor;
|
item->Pose.Position.y = item->Floor;
|
||||||
item->Animation.VerticalVelocity = 0;
|
item->Animation.VerticalVelocity = 0;
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BADDY_STATE_MONKEY_TO_FREEFALL:
|
case BADDY_STATE_MONKEY_TO_FREEFALL:
|
||||||
item->Animation.TargetState = BADDY_STATE_FREEFALL;
|
item->Animation.TargetState = BADDY_STATE_FREEFALL;
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BADDY_STATE_FREEFALL:
|
case BADDY_STATE_FREEFALL:
|
||||||
item->Animation.Airborne = true;
|
item->Animation.IsAirborne = true;
|
||||||
|
|
||||||
if (item->Pose.Position.y >= item->Floor)
|
if (item->Pose.Position.y >= item->Floor)
|
||||||
{
|
{
|
||||||
item->Pose.Position.y = item->Floor;
|
item->Pose.Position.y = item->Floor;
|
||||||
item->Animation.VerticalVelocity = 0;
|
item->Animation.VerticalVelocity = 0;
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
item->Animation.TargetState = BADDY_STATE_FREEFALL_LAND_DEATH;
|
item->Animation.TargetState = BADDY_STATE_FREEFALL_LAND_DEATH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1034,7 +1034,7 @@ namespace TEN::Entities::TR4
|
||||||
if (item->TouchBits)
|
if (item->TouchBits)
|
||||||
{
|
{
|
||||||
SetAnimation(LaraItem, LA_JUMP_UP);
|
SetAnimation(LaraItem, LA_JUMP_UP);
|
||||||
LaraItem->Animation.Airborne = true;
|
LaraItem->Animation.IsAirborne = true;
|
||||||
LaraItem->Animation.VerticalVelocity = 2;
|
LaraItem->Animation.VerticalVelocity = 2;
|
||||||
LaraItem->Animation.VerticalVelocity = 1;
|
LaraItem->Animation.VerticalVelocity = 1;
|
||||||
LaraItem->Pose.Position.y += CLICK(0.75f);
|
LaraItem->Pose.Position.y += CLICK(0.75f);
|
||||||
|
|
|
@ -155,7 +155,7 @@ namespace TEN::Entities::TR4
|
||||||
if (item->Pose.Position.y >= item->Floor)
|
if (item->Pose.Position.y >= item->Floor)
|
||||||
{
|
{
|
||||||
item->Animation.TargetState = BAT_STATE_DEATH;
|
item->Animation.TargetState = BAT_STATE_DEATH;
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
item->Pose.Position.y = item->Floor;
|
item->Pose.Position.y = item->Floor;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -164,7 +164,7 @@ namespace TEN::Entities::TR4
|
||||||
item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase;
|
item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase;
|
||||||
item->Animation.ActiveState = BAT_STATE_DEATH_FALL;
|
item->Animation.ActiveState = BAT_STATE_DEATH_FALL;
|
||||||
item->Animation.TargetState = BAT_STATE_DEATH_FALL;
|
item->Animation.TargetState = BAT_STATE_DEATH_FALL;
|
||||||
item->Animation.Airborne = true;
|
item->Animation.IsAirborne = true;
|
||||||
item->Animation.Velocity = 0;
|
item->Animation.Velocity = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,14 +97,14 @@ namespace TEN::Entities::TR4
|
||||||
item->Animation.AnimNumber = Objects[item->ObjectNumber].animIndex + BBEETLE_ANIM_DEATH_START;
|
item->Animation.AnimNumber = Objects[item->ObjectNumber].animIndex + BBEETLE_ANIM_DEATH_START;
|
||||||
item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase;
|
item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase;
|
||||||
item->Animation.ActiveState = BBEETLE_STATE_DEATH_START;
|
item->Animation.ActiveState = BBEETLE_STATE_DEATH_START;
|
||||||
item->Animation.Airborne = true;
|
item->Animation.IsAirborne = true;
|
||||||
item->Animation.Velocity = 0;
|
item->Animation.Velocity = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (item->Pose.Position.y >= item->Floor)
|
else if (item->Pose.Position.y >= item->Floor)
|
||||||
{
|
{
|
||||||
item->Pose.Position.y = item->Floor;
|
item->Pose.Position.y = item->Floor;
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
item->Animation.VerticalVelocity = 0;
|
item->Animation.VerticalVelocity = 0;
|
||||||
item->Animation.TargetState = BBEETLE_STATE_DEATH_END;
|
item->Animation.TargetState = BBEETLE_STATE_DEATH_END;
|
||||||
}
|
}
|
||||||
|
|
|
@ -369,11 +369,11 @@ namespace TEN::Entities::TR4
|
||||||
ItemNewRoom(itemNumber, probe.RoomNumber);
|
ItemNewRoom(itemNumber, probe.RoomNumber);
|
||||||
|
|
||||||
if (item->Pose.Position.y < item->Floor)
|
if (item->Pose.Position.y < item->Floor)
|
||||||
item->Animation.Airborne = true;
|
item->Animation.IsAirborne = true;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
item->Pose.Position.y = item->Floor;
|
item->Pose.Position.y = item->Floor;
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
item->Animation.VerticalVelocity = 0;
|
item->Animation.VerticalVelocity = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -290,7 +290,7 @@ namespace TEN::Entities::TR4
|
||||||
item->Animation.AnimNumber = object->animIndex + 5;
|
item->Animation.AnimNumber = object->animIndex + 5;
|
||||||
item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase;
|
item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase;
|
||||||
item->Animation.ActiveState = HARPY_STATE_DEATH_START;
|
item->Animation.ActiveState = HARPY_STATE_DEATH_START;
|
||||||
item->Animation.Airborne = true;
|
item->Animation.IsAirborne = true;
|
||||||
item->Animation.Velocity = 0;
|
item->Animation.Velocity = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -311,7 +311,7 @@ namespace TEN::Entities::TR4
|
||||||
{
|
{
|
||||||
item->Pose.Position.y = item->Floor;
|
item->Pose.Position.y = item->Floor;
|
||||||
item->Animation.TargetState = HARPY_STATE_DEATH_END;
|
item->Animation.TargetState = HARPY_STATE_DEATH_END;
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
item->Animation.VerticalVelocity = 0;
|
item->Animation.VerticalVelocity = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -650,7 +650,7 @@ namespace TEN::Entities::TR4
|
||||||
auto* item = &g_Level.Items[itemNumber];
|
auto* item = &g_Level.Items[itemNumber];
|
||||||
|
|
||||||
if ((!(TrInput & IN_ACTION) ||
|
if ((!(TrInput & IN_ACTION) ||
|
||||||
laraItem->Animation.Airborne ||
|
laraItem->Animation.IsAirborne ||
|
||||||
laraItem->Animation.ActiveState != LS_IDLE ||
|
laraItem->Animation.ActiveState != LS_IDLE ||
|
||||||
laraItem->Animation.AnimNumber != LA_STAND_IDLE ||
|
laraItem->Animation.AnimNumber != LA_STAND_IDLE ||
|
||||||
Lara.Control.HandStatus != HandStatus::Free ||
|
Lara.Control.HandStatus != HandStatus::Free ||
|
||||||
|
|
|
@ -348,7 +348,7 @@ namespace TEN::Entities::TR4
|
||||||
case 14:
|
case 14:
|
||||||
if (item->Animation.AnimNumber != Objects[item->Animation.AnimNumber].animIndex + 26)
|
if (item->Animation.AnimNumber != Objects[item->Animation.AnimNumber].animIndex + 26)
|
||||||
{
|
{
|
||||||
item->Animation.Airborne = false;
|
item->Animation.IsAirborne = false;
|
||||||
creature->MaxTurn = 0;
|
creature->MaxTurn = 0;
|
||||||
creature->Target.y = LaraItem->Pose.Position.y;
|
creature->Target.y = LaraItem->Pose.Position.y;
|
||||||
creature->LOT.Fly = 16;
|
creature->LOT.Fly = 16;
|
||||||
|
@ -374,7 +374,7 @@ namespace TEN::Entities::TR4
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
item->Animation.Airborne = true;
|
item->Animation.IsAirborne = true;
|
||||||
creature->LOT.Fly = 0;
|
creature->LOT.Fly = 0;
|
||||||
|
|
||||||
if ((item->Pose.Position.y - item->Floor) > 0)
|
if ((item->Pose.Position.y - item->Floor) > 0)
|
||||||
|
|
|
@ -551,7 +551,7 @@ namespace TEN::Entities::TR4
|
||||||
item->Animation.AnimNumber = Objects[ID_SKELETON].animIndex + 44;
|
item->Animation.AnimNumber = Objects[ID_SKELETON].animIndex + 44;
|
||||||
item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase;
|
item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase;
|
||||||
item->Animation.ActiveState = 23;
|
item->Animation.ActiveState = 23;
|
||||||
item->Animation.Airborne = true;
|
item->Animation.IsAirborne = true;
|
||||||
creature->MaxTurn = 0;
|
creature->MaxTurn = 0;
|
||||||
creature->LOT.IsJumping = false;
|
creature->LOT.IsJumping = false;
|
||||||
}
|
}
|
||||||
|
@ -685,7 +685,7 @@ namespace TEN::Entities::TR4
|
||||||
item->Animation.AnimNumber = Objects[item->ObjectNumber].animIndex + 44;
|
item->Animation.AnimNumber = Objects[item->ObjectNumber].animIndex + 44;
|
||||||
item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase;
|
item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase;
|
||||||
item->Animation.ActiveState = 23;
|
item->Animation.ActiveState = 23;
|
||||||
item->Animation.Airborne = true;
|
item->Animation.IsAirborne = true;
|
||||||
creature->MaxTurn = 0;
|
creature->MaxTurn = 0;
|
||||||
creature->LOT.IsJumping = false;
|
creature->LOT.IsJumping = false;
|
||||||
}
|
}
|
||||||
|
@ -740,7 +740,7 @@ namespace TEN::Entities::TR4
|
||||||
item->Animation.AnimNumber = Objects[item->ObjectNumber].animIndex + 47;
|
item->Animation.AnimNumber = Objects[item->ObjectNumber].animIndex + 47;
|
||||||
item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase;
|
item->Animation.FrameNumber = g_Level.Anims[item->Animation.AnimNumber].frameBase;
|
||||||
item->Animation.ActiveState = 24;
|
item->Animation.ActiveState = 24;
|
||||||
item->Animation.Airborne = true;
|
item->Animation.IsAirborne = true;
|
||||||
creature->MaxTurn = 0;
|
creature->MaxTurn = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -239,7 +239,7 @@ namespace TEN::Entities::TR4
|
||||||
laraItem->Animation.ActiveState != LS_IDLE ||
|
laraItem->Animation.ActiveState != LS_IDLE ||
|
||||||
laraItem->Animation.AnimNumber != LA_STAND_IDLE ||
|
laraItem->Animation.AnimNumber != LA_STAND_IDLE ||
|
||||||
!laraInfo->Torch.IsLit ||
|
!laraInfo->Torch.IsLit ||
|
||||||
laraItem->Animation.Airborne)
|
laraItem->Animation.IsAirborne)
|
||||||
{
|
{
|
||||||
if (laraItem->Animation.AnimNumber != LA_TORCH_LIGHT_3 ||
|
if (laraItem->Animation.AnimNumber != LA_TORCH_LIGHT_3 ||
|
||||||
g_Level.Anims[LA_TORCH_LIGHT_3].frameBase + 16 ||
|
g_Level.Anims[LA_TORCH_LIGHT_3].frameBase + 16 ||
|
||||||
|
|
|
@ -129,7 +129,7 @@ namespace TEN::Entities::TR4
|
||||||
int bloodCount = 0;
|
int bloodCount = 0;
|
||||||
|
|
||||||
if ((item->ItemFlags[0] > 1024 ||
|
if ((item->ItemFlags[0] > 1024 ||
|
||||||
LaraItem->Animation.Airborne) &&
|
LaraItem->Animation.IsAirborne) &&
|
||||||
(item->TriggerFlags & 7) > 2 &&
|
(item->TriggerFlags & 7) > 2 &&
|
||||||
(item->TriggerFlags & 7) < 6)
|
(item->TriggerFlags & 7) < 6)
|
||||||
{
|
{
|
||||||
|
@ -183,14 +183,14 @@ namespace TEN::Entities::TR4
|
||||||
TriggerBlood(dx, yBottom - (GetRandomControl() % dy), dz, GetRandomControl() << 1, 1);
|
TriggerBlood(dx, yBottom - (GetRandomControl() % dy), dz, GetRandomControl() << 1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LaraItem->HitPoints <= 0)
|
if (LaraItem->HitPoints <= 0 && Lara.Vehicle == NO_ITEM)
|
||||||
{
|
{
|
||||||
int heightFromFloor = GetCollision(LaraItem).Position.Floor - LaraItem->Pose.Position.y;
|
int heightFromFloor = GetCollision(LaraItem).Position.Floor - LaraItem->Pose.Position.y;
|
||||||
if (item->Pose.Position.y >= LaraItem->Pose.Position.y &&
|
if (item->Pose.Position.y >= LaraItem->Pose.Position.y &&
|
||||||
heightFromFloor < CLICK(1))
|
heightFromFloor < CLICK(1))
|
||||||
{
|
{
|
||||||
SetAnimation(LaraItem, LA_SPIKE_DEATH);
|
SetAnimation(LaraItem, LA_SPIKE_DEATH);
|
||||||
LaraItem->Animation.Airborne = false;
|
LaraItem->Animation.IsAirborne = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue