-
TombEngine 1.0.9 scripting interface
+
TombEngine 1.1.0 scripting interface
Welcome to the TombEngine scripting API. This is a work in progress and some information might be wrong or outdated. Please also note that this is primarily a reference document, not a tutorial, so expect descriptions to be fairly sparse.
At the time of writing, there is a tutorial describing the basics of Lua, as well as a number of example scripts, on the TombEngine website.
@@ -254,6 +255,10 @@ local door = GetMoveableByName("door_type4_14")
Misc.LogLevel |
Constants for LogLevel IDs. |
+
+ Misc.SoundTrackType |
+ Constants for the type of the audio tracks. |
+
Objects.ObjID |
Constants for object IDs. |
@@ -283,7 +288,7 @@ local door = GetMoveableByName("door_type4_14")
generated by TEN-LDoc (a fork of LDoc 1.4.6)
-
Last updated 2023-06-03 11:42:57
+
Last updated 2023-07-20 12:10:11
diff --git a/Documentation/output.xml b/Documentation/output.xml
index da1d3b73a..9bc265b8d 100644
--- a/Documentation/output.xml
+++ b/Documentation/output.xml
@@ -356,7 +356,7 @@
speed
float
- (default 1.0). Speed in "amount" per second. A value of 1 will make the flash take one second. Clamped to [0.005, 1.0]
+ (default 1.0). Speed in "amount" per second. Value of 1 will make flash take one second. Clamped to [0.005, 1.0].
@@ -1013,9 +1013,9 @@ eyes of the creatures would be.
of track (without file extension) to play
- loop
- bool
- if true, the track will loop; if false, it won't (default: false)
+ type
+ Misc.SoundTrackType
+ of the audio track to play
@@ -1045,13 +1045,46 @@ eyes of the creatures would be.
Stop audio track that is currently playing
- looped
- bool
- if set, stop looped audio track, if not, stop one-shot audio track
+ type
+ Misc.SoundTrackType
+ of the audio track
+
+ Misc
+ GetAudioTrackLoudness
+ Get current loudness level for specified track type
+
+
+ type
+ Misc.SoundTrackType
+ of the audio track
+
+
+
+
+ float
+ current loudness of a specified audio track
+
+
+
+
+
+ Misc
+ GetCurrentSubtitle
+ Get current subtitle string for a voice track currently playing.
+ Subtitle file must be in .srt format, have same filename as voice track, and be placed in same directory as voice track.
+Returns nil if no voice track is playing or no subtitle present.
+
+
+ string
+ current subtitle string
+
+
+
+
Misc
PlaySound
@@ -1083,6 +1116,19 @@ eyes of the creatures would be.
+
+ Misc
+ IsAudioTrackPlaying
+ Check if the audio track is playing
+
+
+ Track
+ string
+ filename to check. Should be without extension and without full directory path.
+
+
+
+
Misc
FlipMap
diff --git a/Scripts/Engine/Timer.lua b/Scripts/Engine/Timer.lua
index df05d13b0..1f0cb269b 100644
--- a/Scripts/Engine/Timer.lua
+++ b/Scripts/Engine/Timer.lua
@@ -125,7 +125,10 @@ Timer = {
else
t.remainingTime = t.remainingTime + t.totalTime
end
- t.func(table.unpack(t.funcArgs))
+
+ if (t.func ~= nil) then
+ t.func(table.unpack(t.funcArgs))
+ end
end
end
diff --git a/Scripts/Strings.lua b/Scripts/Strings.lua
index ce5d11c32..73db2c480 100644
--- a/Scripts/Strings.lua
+++ b/Scripts/Strings.lua
@@ -5,6 +5,48 @@ corresponding to languages in the table at the end of this file.
local strings =
{
+ actions_accelerate = { "Accelerate" },
+ actions_reverse = { "Reverse" },
+ actions_speed = { "Speed" },
+ actions_slow = { "Slow" },
+ actions_brake = { "Brake/Dismount" },
+ actions_fire = { "Fire" },
+ actions_action = { "Action" },
+ actions_sprint = { "Sprint" },
+ actions_draw = { "Draw" },
+ actions_crouch = { "Crouch" },
+ actions_inventory = { "Inventory" },
+ actions_jump = { "Jump" },
+ actions_look = { "Look" },
+ actions_backward = { "Backward" },
+ actions_forward = { "Forward" },
+ actions_left = { "Left" },
+ actions_right = { "Right" },
+ actions_roll = { "Roll" },
+ actions_step_left = { "Step Left" },
+ actions_step_right = { "Step Right" },
+ actions_pause = { "Pause" },
+ actions_walk = { "Walk" },
+ actions_save = { "Save" },
+ actions_load = { "Load" },
+ actions_select = { "Select" },
+ actions_deselect = { "Deselect" },
+ actions_large_medipack = { "Large Medipack" },
+ actions_flare = { "Flare" },
+ actions_next_weapon = { "Next Weapon" },
+ actions_previous_weapon = { "Previous Weapon" },
+ actions_small_medipack = { "Small Medipack" },
+ actions_weapon_1 = { "Weapon 1" },
+ actions_weapon_2 = { "Weapon 2" },
+ actions_weapon_3 = { "Weapon 3" },
+ actions_weapon_4 = { "Weapon 4" },
+ actions_weapon_5 = { "Weapon 5" },
+ actions_weapon_6 = { "Weapon 6" },
+ actions_weapon_7 = { "Weapon 7" },
+ actions_weapon_8 = { "Weapon 8" },
+ actions_weapon_9 = { "Weapon 9" },
+ actions_weapon_10 = { "Weapon 10" },
+ window_title = { "TombEngine" },
all = { "All" },
apply = { "Apply" },
automatic_targeting = { "Automatic Targeting" },
@@ -18,24 +60,7 @@ local strings =
combine = { "Combine" },
combine_with = { "Combine With" },
controls = { "Controls" },
- controls_action = { "Action" },
- controls_sprint = { "Sprint" },
- controls_draw_weapon = { "Draw Weapon" },
- controls_crouch = { "Crouch" },
- controls_inventory = { "Inventory" },
- controls_jump = { "Jump" },
- controls_look = { "Look" },
- controls_move_backward = { "Move Backward" },
- controls_move_forward = { "Move Forward" },
- controls_move_left = { "Move Left" },
- controls_move_right = { "Move Right" },
- controls_roll = { "Roll" },
- controls_step_left = { "Step Left" },
- controls_step_right = { "Step Right" },
- controls_pause = { "Pause" },
- controls_use_flare = { "Use Flare" },
- controls_walk = { "Walk" },
- controls_defaults = { "Reset to Defaults" },
+ reset_to_defaults = { "Reset to Defaults" },
crossbow = { "Crossbow" },
crossbow_normal_ammo = { "Crossbow Normal Ammo" },
crossbow_poison_ammo = { "Crossbow Poison Ammo" },
@@ -54,6 +79,7 @@ local strings =
exit_game = { "Exit Game" },
exit_to_title = { "Exit to Title" },
flares = { "Flares" },
+ general_actions = { "General Actions"},
grenade_launcher = { "Grenade Launcher" },
grenade_launcher_normal_ammo = { "Grenade Launcher Normal Ammo" },
grenade_launcher_super_ammo = { "Grenade Launcher Super Ammo" },
@@ -70,6 +96,7 @@ local strings =
lara_home = { "Lara's Home" },
large_medipack = { "Large Medipack" },
lasersight = { "Lasersight" },
+ menu_actions = { "Menu Actions" },
music_volume = { "Music Volume" },
new_game = { "New Game" },
none = { "None" },
@@ -125,6 +152,8 @@ local strings =
waiting_for_input = { "Waiting For Input" },
windowed = { "Windowed" },
load_game = { "Load Game" },
+ quick_actions = { "Quick Actions" },
+ vehicle_actions = { "Vehicle Actions" },
test_level = { "Test Level" },
torch2 = { "Torch 2" },
waterskin_small_empty = { "Small Waterskin (Empty)" },
@@ -141,13 +170,7 @@ local strings =
mechanical_scarab = { "Mechanical Scarab With Winding Key" },
mechanical_scarab_1 = { "Mechanical Scarab (No Winding Key)" },
mechanical_scarab_2 = { "Mechanical Scarab Winding Key" },
- title = { "Title" },
- accelerate = { "Accelerate" },
- reverse = { "Reverse" },
- speed = { "Speed" },
- slow = { "Slow" },
- brake = { "Brake" },
- fire = { "Fire" }
+ title = { "Title" }
}
TEN.Flow.SetStrings(strings)
diff --git a/TombEngine/Game/Hud/PickupSummary.h b/TombEngine/Game/Hud/PickupSummary.h
index c2dde5a5c..169adca76 100644
--- a/TombEngine/Game/Hud/PickupSummary.h
+++ b/TombEngine/Game/Hud/PickupSummary.h
@@ -10,7 +10,7 @@ namespace TEN::Hud
{
static constexpr auto LIFE_MAX = 3.0f;
- GAME_OBJECT_ID ObjectID = ID_NO_OBJECT;
+ GAME_OBJECT_ID ObjectID = GAME_OBJECT_ID::ID_NO_OBJECT;
unsigned int Count = 0;
Vector2 Position2D = Vector2::Zero;
diff --git a/TombEngine/Game/Lara/lara.cpp b/TombEngine/Game/Lara/lara.cpp
index f388b208b..edee58508 100644
--- a/TombEngine/Game/Lara/lara.cpp
+++ b/TombEngine/Game/Lara/lara.cpp
@@ -38,6 +38,7 @@
#include "Scripting/Include/Flow/ScriptInterfaceFlowHandler.h"
#include "Scripting/Include/ScriptInterfaceLevel.h"
#include "Sound/sound.h"
+#include "Specific/winmain.h"
using namespace TEN::Control::Volumes;
using namespace TEN::Effects::Hair;
@@ -491,6 +492,7 @@ void LaraControl(ItemInfo* item, CollisionInfo* coll)
if (lara->Status.Stamina < LARA_STAMINA_MAX && item->Animation.ActiveState != LS_SPRINT)
lara->Status.Stamina++;
+ HandlePlayerQuickActions(*item);
RumbleLaraHealthCondition(item);
bool isWater = TestEnvironment(ENV_FLAG_WATER, item);
@@ -588,7 +590,7 @@ void LaraControl(ItemInfo* item, CollisionInfo* coll)
if (item->Animation.ActiveState == LS_SWAN_DIVE ||
item->Animation.ActiveState == LS_FREEFALL_DIVE)
{
- item->Pose.Position.y = waterHeight + (SECTOR(1) - 24);
+ item->Pose.Position.y = waterHeight + (BLOCK(1) - 24);
}
SetAnimation(item, LA_WADE);
@@ -707,9 +709,7 @@ void LaraControl(ItemInfo* item, CollisionInfo* coll)
}
if (TestEnvironment(ENV_FLAG_DAMAGE, item) && item->HitPoints > 0)
- {
item->HitPoints--;
- }
if (item->HitPoints <= 0)
{
@@ -861,6 +861,12 @@ void LaraControl(ItemInfo* item, CollisionInfo* coll)
}
Statistics.Game.Distance += (int)round(Vector3::Distance(prevPos.ToVector3(), item->Pose.Position.ToVector3()));
+
+ if (DebugMode)
+ {
+ DrawNearbyPathfinding(GetCollision(item).BottomBlock->Box);
+ DrawNearbySectorFlags(*item);
+ }
}
void LaraAboveWater(ItemInfo* item, CollisionInfo* coll)
@@ -931,9 +937,7 @@ void LaraAboveWater(ItemInfo* item, CollisionInfo* coll)
// Test for flags and triggers.
ProcessSectorFlags(item);
TestTriggers(item, false);
- TestVolumes(Lara.ItemNumber, &coll->Setup);
-
- DrawNearbyPathfinding(GetCollision(item).BottomBlock->Box);
+ TestVolumes(item->Index, &coll->Setup);
}
void LaraWaterSurface(ItemInfo* item, CollisionInfo* coll)
@@ -1005,7 +1009,7 @@ void LaraWaterSurface(ItemInfo* item, CollisionInfo* coll)
ProcessSectorFlags(item);
TestTriggers(item, false);
- TestVolumes(Lara.ItemNumber);
+ TestVolumes(item->Index);
}
void LaraUnderwater(ItemInfo* item, CollisionInfo* coll)
@@ -1094,7 +1098,7 @@ void LaraUnderwater(ItemInfo* item, CollisionInfo* coll)
ProcessSectorFlags(item);
TestTriggers(item, false);
- TestVolumes(Lara.ItemNumber);
+ TestVolumes(item->Index);
}
void LaraCheat(ItemInfo* item, CollisionInfo* coll)
diff --git a/TombEngine/Game/Lara/lara_basic.cpp b/TombEngine/Game/Lara/lara_basic.cpp
index e5f0bcf7b..1b54e3268 100644
--- a/TombEngine/Game/Lara/lara_basic.cpp
+++ b/TombEngine/Game/Lara/lara_basic.cpp
@@ -103,7 +103,7 @@ void lara_as_vault(ItemInfo* item, CollisionInfo* coll)
coll->Setup.EnableObjectPush = false;
coll->Setup.EnableSpasm = false;
- EaseOutLaraHeight(item, lara->Context.ProjectedFloorHeight - item->Pose.Position.y);
+ EasePlayerVerticalPosition(item, lara->Context.ProjectedFloorHeight - item->Pose.Position.y);
item->Pose.Orientation.Lerp(lara->Context.TargetOrientation, 0.4f);
item->Animation.TargetState = LS_IDLE;
@@ -252,13 +252,13 @@ void lara_as_run_forward(ItemInfo* item, CollisionInfo* coll)
return;
}
- if (TrInput & (IN_LEFT | IN_RIGHT))
+ if (IsHeld(In::Left) || IsHeld(In::Right))
{
ModulateLaraTurnRateY(item, LARA_TURN_RATE_ACCEL, 0, LARA_FAST_TURN_RATE_MAX);
ModulateLaraLean(item, coll, LARA_LEAN_RATE, LARA_LEAN_MAX);
}
- if (TrInput & IN_JUMP || lara->Control.RunJumpQueued)
+ if (IsHeld(In::Jump) || lara->Control.RunJumpQueued)
{
if (!(TrInput & IN_SPRINT) && lara->Control.Count.Run >= LARA_RUN_JUMP_TIME &&
TestLaraRunJumpForward(item, coll))
@@ -418,8 +418,8 @@ void lara_as_idle(ItemInfo* item, CollisionInfo* coll)
if (!IsHeld(In::Jump) || isSwamp) // JUMP locks orientation outside swamps.
{
// Sidestep locks orientation.
- if ((IsHeld(In::LeftStep) || (IsHeld(In::Walk) && IsHeld(In::Left))) ||
- (IsHeld(In::RightStep) || (IsHeld(In::Walk) && IsHeld(In::Right))))
+ if ((IsHeld(In::StepLeft) || (IsHeld(In::Walk) && IsHeld(In::Left))) ||
+ (IsHeld(In::StepRight) || (IsHeld(In::Walk) && IsHeld(In::Right))))
{
ModulateLaraTurnRateY(item, 0, 0, 0);
}
@@ -508,7 +508,7 @@ void lara_as_idle(ItemInfo* item, CollisionInfo* coll)
}
}
- if (IsHeld(In::LeftStep) || (IsHeld(In::Walk) && IsHeld(In::Left)))
+ if (IsHeld(In::StepLeft) || (IsHeld(In::Walk) && IsHeld(In::Left)))
{
if (TestLaraStepLeft(item, coll))
item->Animation.TargetState = LS_STEP_LEFT;
@@ -517,7 +517,7 @@ void lara_as_idle(ItemInfo* item, CollisionInfo* coll)
return;
}
- else if (IsHeld(In::RightStep) || (IsHeld(In::Walk) && IsHeld(In::Right)))
+ else if (IsHeld(In::StepRight) || (IsHeld(In::Walk) && IsHeld(In::Right)))
{
if (TestLaraStepRight(item, coll))
item->Animation.TargetState = LS_STEP_RIGHT;
@@ -571,7 +571,7 @@ void PseudoLaraAsWadeIdle(ItemInfo* item, CollisionInfo* coll)
{
auto* lara = GetLaraInfo(item);
- if (TrInput & IN_JUMP && TestLaraJumpUp(item, coll))
+ if (IsHeld(In::Jump) && TestLaraJumpUp(item, coll))
{
item->Animation.TargetState = LS_JUMP_PREPARE;
lara->Control.JumpDirection = JumpDirection::Up;
@@ -798,7 +798,7 @@ void lara_as_run_back(ItemInfo* item, CollisionInfo* coll)
{
auto* lara = GetLaraInfo(item);
- if (TrInput & (IN_LEFT | IN_RIGHT))
+ if (IsHeld(In::Left) || IsHeld(In::Right))
{
ModulateLaraTurnRateY(item, LARA_TURN_RATE_ACCEL, 0, LARA_MED_TURN_RATE_MAX);
ModulateLaraLean(item, coll, LARA_LEAN_RATE / 4, LARA_LEAN_MAX / 3);
@@ -822,7 +822,6 @@ void lara_col_run_back(ItemInfo* item, CollisionInfo* coll)
lara->Control.MoveAngle = item->Pose.Orientation.y + ANGLE(180.0f);
item->Animation.Velocity.y = 0;
item->Animation.IsAirborne = false;
- coll->Setup.BlockFloorSlopeDown = true;
coll->Setup.LowerFloorBound = NO_LOWER_BOUND;
coll->Setup.UpperFloorBound = -STEPUP_HEIGHT;
coll->Setup.LowerCeilingBound = 0;
@@ -885,7 +884,7 @@ void lara_as_turn_right_slow(ItemInfo* item, CollisionInfo* coll)
ModulateLaraTurnRateY(item, LARA_TURN_RATE_ACCEL, 0, LARA_MED_FAST_TURN_RATE_MAX);
- if (TrInput & IN_JUMP)
+ if (IsHeld(In::Jump))
{
SetLaraJumpDirection(item, coll);
if (lara->Control.JumpDirection != JumpDirection::None)
@@ -994,7 +993,7 @@ void PsuedoLaraAsWadeTurnRightSlow(ItemInfo* item, CollisionInfo* coll)
ModulateLaraTurnRateY(item, LARA_TURN_RATE_ACCEL, 0, LARA_WADE_TURN_RATE_MAX);
- if (TrInput & IN_JUMP && TestLaraJumpUp(item, coll))
+ if (IsHeld(In::Jump) && TestLaraJumpUp(item, coll))
{
item->Animation.TargetState = LS_JUMP_PREPARE;
lara->Control.JumpDirection = JumpDirection::Up;
@@ -1131,7 +1130,7 @@ void lara_as_turn_left_slow(ItemInfo* item, CollisionInfo* coll)
ModulateLaraTurnRateY(item, LARA_TURN_RATE_ACCEL, 0, LARA_MED_FAST_TURN_RATE_MAX);
- if (TrInput & IN_JUMP)
+ if (IsHeld(In::Jump))
{
SetLaraJumpDirection(item, coll);
if (lara->Control.JumpDirection != JumpDirection::None)
@@ -1240,7 +1239,7 @@ void PsuedoLaraAsWadeTurnLeftSlow(ItemInfo* item, CollisionInfo* coll)
ModulateLaraTurnRateY(item, LARA_TURN_RATE_ACCEL, 0, LARA_WADE_TURN_RATE_MAX);
- if (TrInput & IN_JUMP && TestLaraJumpUp(item, coll))
+ if (IsHeld(In::Jump) && TestLaraJumpUp(item, coll))
{
item->Animation.TargetState = LS_JUMP_PREPARE;
lara->Control.JumpDirection = JumpDirection::Up;
@@ -1465,7 +1464,7 @@ void lara_as_walk_back(ItemInfo* item, CollisionInfo* coll)
return;
}
- if (TrInput & (IN_LEFT | IN_RIGHT))
+ if (IsHeld(In::Left) || IsHeld(In::Right))
{
ModulateLaraTurnRateY(item, LARA_TURN_RATE_ACCEL, 0, LARA_SLOW_TURN_RATE_MAX);
ModulateLaraLean(item, coll, LARA_LEAN_RATE / 4, LARA_LEAN_MAX / 3);
@@ -1486,7 +1485,7 @@ void PseudoLaraAsSwampWalkBack(ItemInfo* item, CollisionInfo* coll)
{
auto* lara = GetLaraInfo(item);
- if (TrInput & (IN_LEFT | IN_RIGHT))
+ if (IsHeld(In::Left) || IsHeld(In::Right))
{
ModulateLaraTurnRateY(item, LARA_TURN_RATE_ACCEL, 0, LARA_SLOW_TURN_RATE_MAX / 3);
ModulateLaraLean(item, coll, LARA_LEAN_RATE / 3, LARA_LEAN_MAX / 3);
@@ -1563,7 +1562,7 @@ void lara_as_turn_right_fast(ItemInfo* item, CollisionInfo* coll)
ModulateLaraTurnRateY(item, LARA_TURN_RATE_ACCEL, LARA_MED_TURN_RATE_MAX, LARA_FAST_TURN_RATE_MAX);
- if (TrInput & IN_JUMP)
+ if (IsHeld(In::Jump))
{
SetLaraJumpDirection(item, coll);
if (lara->Control.JumpDirection != JumpDirection::None)
@@ -1690,7 +1689,7 @@ void lara_as_turn_left_fast(ItemInfo* item, CollisionInfo* coll)
ModulateLaraTurnRateY(item, LARA_TURN_RATE_ACCEL, LARA_MED_TURN_RATE_MAX, LARA_FAST_TURN_RATE_MAX);
- if (TrInput & IN_JUMP)
+ if (IsHeld(In::Jump))
{
SetLaraJumpDirection(item, coll);
if (lara->Control.JumpDirection != JumpDirection::None)
@@ -1826,7 +1825,7 @@ void lara_as_step_right(ItemInfo* item, CollisionInfo* coll)
ModulateLaraTurnRateY(item, 0, 0, 0);
else
{
- if (TrInput & (IN_LEFT | IN_RIGHT))
+ if (IsHeld(In::Left) || IsHeld(In::Right))
ModulateLaraTurnRateY(item, LARA_TURN_RATE_ACCEL, 0, LARA_SLOW_TURN_RATE_MAX);
}
@@ -1920,7 +1919,7 @@ void lara_as_step_left(ItemInfo* item, CollisionInfo* coll)
ModulateLaraTurnRateY(item, 0, 0, 0);
else
{
- if (TrInput & (IN_LEFT | IN_RIGHT))
+ if (IsHeld(In::Left) || IsHeld(In::Right))
ModulateLaraTurnRateY(item, LARA_TURN_RATE_ACCEL, 0, LARA_SLOW_TURN_RATE_MAX);
}
@@ -2143,7 +2142,7 @@ void lara_as_wade_forward(ItemInfo* item, CollisionInfo* coll)
return;
}
- if (TrInput & (IN_LEFT | IN_RIGHT))
+ if (IsHeld(In::Left) || IsHeld(In::Right))
{
ModulateLaraTurnRateY(item, LARA_TURN_RATE_ACCEL, 0, LARA_MED_TURN_RATE_MAX);
ModulateLaraLean(item, coll, LARA_LEAN_RATE / 2, LARA_LEAN_MAX);
@@ -2175,7 +2174,7 @@ void PseudoLaraAsSwampWadeForward(ItemInfo* item, CollisionInfo* coll)
{
auto* lara = GetLaraInfo(item);
- if (TrInput & (IN_LEFT | IN_RIGHT))
+ if (IsHeld(In::Left) || IsHeld(In::Right))
{
ModulateLaraTurnRateY(item, LARA_TURN_RATE_ACCEL, 0, LARA_SWAMP_TURN_RATE_MAX);
ModulateLaraLean(item, coll, LARA_LEAN_RATE / 3, LARA_LEAN_MAX * 0.6f);
@@ -2264,13 +2263,13 @@ void lara_as_sprint(ItemInfo* item, CollisionInfo* coll)
return;
}
- if (TrInput & (IN_LEFT | IN_RIGHT))
+ if (IsHeld(In::Left) || IsHeld(In::Right))
{
ModulateLaraTurnRateY(item, LARA_TURN_RATE_ACCEL, 0, LARA_SLOW_TURN_RATE_MAX);
ModulateLaraLean(item, coll, LARA_LEAN_RATE, LARA_LEAN_MAX);
}
- if (TrInput & IN_JUMP || lara->Control.RunJumpQueued)
+ if (IsHeld(In::Jump) || lara->Control.RunJumpQueued)
{
if (TrInput & IN_WALK || !g_GameFlow->HasSprintJump())
{
@@ -2400,7 +2399,7 @@ void lara_as_sprint_dive(ItemInfo* item, CollisionInfo* coll)
if (lara->Control.Count.Run > LARA_RUN_JUMP_TIME)
lara->Control.Count.Run = LARA_RUN_JUMP_TIME;
- if (TrInput & (IN_LEFT | IN_RIGHT))
+ if (IsHeld(In::Left) || IsHeld(In::Right))
{
ModulateLaraTurnRateY(item, LARA_TURN_RATE_ACCEL, 0, LARA_SLOW_TURN_RATE_MAX);
ModulateLaraLean(item, coll, LARA_LEAN_RATE, LARA_LEAN_MAX * 0.6f);
diff --git a/TombEngine/Game/Lara/lara_cheat.cpp b/TombEngine/Game/Lara/lara_cheat.cpp
index f858e6c96..f014708ef 100644
--- a/TombEngine/Game/Lara/lara_cheat.cpp
+++ b/TombEngine/Game/Lara/lara_cheat.cpp
@@ -35,10 +35,7 @@ void lara_as_swimcheat(ItemInfo* item, CollisionInfo* coll)
if (TrInput & IN_ACTION)
TriggerDynamicLight(item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z, 31, 150, 150, 150);
- if (TrInput & IN_OPTION)
- lara->Control.TurnRate = -ANGLE(12.0f);
-
- if (TrInput & IN_JUMP)
+ if (IsHeld(In::Jump))
{
item->Animation.Velocity.y += LARA_SWIM_VELOCITY_ACCEL * 2;
if (item->Animation.Velocity.y > LARA_SWIM_VELOCITY_MAX * 2)
diff --git a/TombEngine/Game/Lara/lara_climb.cpp b/TombEngine/Game/Lara/lara_climb.cpp
index 4db8ce34b..c4f8d050b 100644
--- a/TombEngine/Game/Lara/lara_climb.cpp
+++ b/TombEngine/Game/Lara/lara_climb.cpp
@@ -378,7 +378,7 @@ void lara_as_climb_idle(ItemInfo* item, CollisionInfo* coll)
item->Animation.TargetState = LS_LADDER_RIGHT;
lara->Control.MoveAngle = item->Pose.Orientation.y + ANGLE(90.0f);
}
- else if (TrInput & IN_JUMP)
+ else if (IsHeld(In::Jump))
{
if (item->Animation.AnimNumber == LA_LADDER_IDLE)
{
@@ -619,8 +619,8 @@ int LaraClimbRightCornerTest(ItemInfo* item, CollisionInfo* coll)
if (angle && angle != SOUTH)
{
- x = (item->Pose.Position.x & -SECTOR(1)) - (item->Pose.Position.z % SECTOR(1)) + SECTOR(1);
- z = (item->Pose.Position.z & -SECTOR(1)) - (item->Pose.Position.x % SECTOR(1)) + SECTOR(1);
+ x = (item->Pose.Position.x & -BLOCK(1)) - (item->Pose.Position.z % BLOCK(1)) + BLOCK(1);
+ z = (item->Pose.Position.z & -BLOCK(1)) - (item->Pose.Position.x % BLOCK(1)) + BLOCK(1);
}
else
{
@@ -649,24 +649,24 @@ int LaraClimbRightCornerTest(ItemInfo* item, CollisionInfo* coll)
switch (angle)
{
case NORTH:
- x = ((item->Pose.Position.x + SECTOR(1)) & -SECTOR(1)) - (item->Pose.Position.z % SECTOR(1)) + SECTOR(1);
- z = ((item->Pose.Position.z + SECTOR(1)) & -SECTOR(1)) - (item->Pose.Position.x % SECTOR(1)) + SECTOR(1);
+ x = ((item->Pose.Position.x + BLOCK(1)) & -BLOCK(1)) - (item->Pose.Position.z % BLOCK(1)) + BLOCK(1);
+ z = ((item->Pose.Position.z + BLOCK(1)) & -BLOCK(1)) - (item->Pose.Position.x % BLOCK(1)) + BLOCK(1);
break;
case SOUTH:
- x = ((item->Pose.Position.x - SECTOR(1)) & -SECTOR(1)) - (item->Pose.Position.z % SECTOR(1)) + SECTOR(1);
- z = ((item->Pose.Position.z - SECTOR(1)) & -SECTOR(1)) - (item->Pose.Position.x % SECTOR(1)) + SECTOR(1);
+ x = ((item->Pose.Position.x - BLOCK(1)) & -BLOCK(1)) - (item->Pose.Position.z % BLOCK(1)) + BLOCK(1);
+ z = ((item->Pose.Position.z - BLOCK(1)) & -BLOCK(1)) - (item->Pose.Position.x % BLOCK(1)) + BLOCK(1);
break;
case EAST:
- x = ((item->Pose.Position.z ^ item->Pose.Position.x) % SECTOR(1)) ^ (item->Pose.Position.x + SECTOR(1));
- z = (item->Pose.Position.z ^ ((item->Pose.Position.z ^ item->Pose.Position.x) % SECTOR(1))) - SECTOR(1);
+ x = ((item->Pose.Position.z ^ item->Pose.Position.x) % BLOCK(1)) ^ (item->Pose.Position.x + BLOCK(1));
+ z = (item->Pose.Position.z ^ ((item->Pose.Position.z ^ item->Pose.Position.x) % BLOCK(1))) - BLOCK(1);
break;
case WEST:
default:
- x = (item->Pose.Position.x ^ (item->Pose.Position.z ^ item->Pose.Position.x) % SECTOR(1)) - SECTOR(1);
- z = ((item->Pose.Position.z ^ item->Pose.Position.x) % SECTOR(1)) ^ (item->Pose.Position.z + SECTOR(1));
+ x = (item->Pose.Position.x ^ (item->Pose.Position.z ^ item->Pose.Position.x) % BLOCK(1)) - BLOCK(1);
+ z = ((item->Pose.Position.z ^ item->Pose.Position.x) % BLOCK(1)) ^ (item->Pose.Position.z + BLOCK(1));
break;
}
@@ -713,8 +713,8 @@ int LaraClimbLeftCornerTest(ItemInfo* item, CollisionInfo* coll)
}
else
{
- x = (item->Pose.Position.x & -SECTOR(1)) - (item->Pose.Position.z & WALL_MASK) + SECTOR(1);
- z = (item->Pose.Position.z & -SECTOR(1)) - (item->Pose.Position.x & WALL_MASK) + SECTOR(1);
+ x = (item->Pose.Position.x & -BLOCK(1)) - (item->Pose.Position.z & WALL_MASK) + BLOCK(1);
+ z = (item->Pose.Position.z & -BLOCK(1)) - (item->Pose.Position.x & WALL_MASK) + BLOCK(1);
}
int shift = 0;
@@ -738,24 +738,24 @@ int LaraClimbLeftCornerTest(ItemInfo* item, CollisionInfo* coll)
switch (angle)
{
case NORTH:
- x = (item->Pose.Position.x ^ ((item->Pose.Position.z ^ item->Pose.Position.x) & WALL_MASK)) - SECTOR(1);
- z = ((item->Pose.Position.z ^ item->Pose.Position.x) & WALL_MASK) ^ (item->Pose.Position.z + SECTOR(1));
+ x = (item->Pose.Position.x ^ ((item->Pose.Position.z ^ item->Pose.Position.x) & WALL_MASK)) - BLOCK(1);
+ z = ((item->Pose.Position.z ^ item->Pose.Position.x) & WALL_MASK) ^ (item->Pose.Position.z + BLOCK(1));
break;
case SOUTH:
- x = ((item->Pose.Position.z ^ item->Pose.Position.x) & WALL_MASK) ^ (item->Pose.Position.x + SECTOR(1));
- z = ((item->Pose.Position.z ^ item->Pose.Position.x) & WALL_MASK) ^ (item->Pose.Position.z - SECTOR(1));
+ x = ((item->Pose.Position.z ^ item->Pose.Position.x) & WALL_MASK) ^ (item->Pose.Position.x + BLOCK(1));
+ z = ((item->Pose.Position.z ^ item->Pose.Position.x) & WALL_MASK) ^ (item->Pose.Position.z - BLOCK(1));
break;
case EAST:
- x = ((item->Pose.Position.x + SECTOR(1)) & -SECTOR(1)) - (item->Pose.Position.z & WALL_MASK) + SECTOR(1);
- z = ((item->Pose.Position.z + SECTOR(1)) & -SECTOR(1)) - (item->Pose.Position.x & WALL_MASK) + SECTOR(1);
+ x = ((item->Pose.Position.x + BLOCK(1)) & -BLOCK(1)) - (item->Pose.Position.z & WALL_MASK) + BLOCK(1);
+ z = ((item->Pose.Position.z + BLOCK(1)) & -BLOCK(1)) - (item->Pose.Position.x & WALL_MASK) + BLOCK(1);
break;
case WEST:
default:
- x = (item->Pose.Position.x & -SECTOR(1)) - (item->Pose.Position.z & WALL_MASK);
- z = (item->Pose.Position.z & -SECTOR(1)) - (item->Pose.Position.x & WALL_MASK);
+ x = (item->Pose.Position.x & -BLOCK(1)) - (item->Pose.Position.z & WALL_MASK);
+ z = (item->Pose.Position.z & -BLOCK(1)) - (item->Pose.Position.x & WALL_MASK);
break;
}
diff --git a/TombEngine/Game/Lara/lara_collide.cpp b/TombEngine/Game/Lara/lara_collide.cpp
index 378914128..4969d72c2 100644
--- a/TombEngine/Game/Lara/lara_collide.cpp
+++ b/TombEngine/Game/Lara/lara_collide.cpp
@@ -633,8 +633,8 @@ void LaraWaterCurrent(ItemInfo* item, CollisionInfo* coll)
const auto& sink = g_Level.Sinks[lara->Context.WaterCurrentActive - 1];
short headingAngle = Geometry::GetOrientToPoint(item->Pose.Position.ToVector3(), sink.Position).y;
- lara->Context.WaterCurrentPull.x += ((sink.Strength * SECTOR(1) * phd_sin(headingAngle)) - lara->Context.WaterCurrentPull.x) / 16;
- lara->Context.WaterCurrentPull.z += ((sink.Strength * SECTOR(1) * phd_cos(headingAngle)) - lara->Context.WaterCurrentPull.z) / 16;
+ lara->Context.WaterCurrentPull.x += ((sink.Strength * BLOCK(1) * phd_sin(headingAngle)) - lara->Context.WaterCurrentPull.x) / 16;
+ lara->Context.WaterCurrentPull.z += ((sink.Strength * BLOCK(1) * phd_cos(headingAngle)) - lara->Context.WaterCurrentPull.z) / 16;
item->Pose.Position.y += (sink.Position.y - item->Pose.Position.y) / 16;
}
diff --git a/TombEngine/Game/Lara/lara_crawl.cpp b/TombEngine/Game/Lara/lara_crawl.cpp
index dfbe187ff..c1796da68 100644
--- a/TombEngine/Game/Lara/lara_crawl.cpp
+++ b/TombEngine/Game/Lara/lara_crawl.cpp
@@ -40,7 +40,7 @@ void lara_as_crouch_idle(ItemInfo* item, CollisionInfo* coll)
coll->Setup.EnableObjectPush = true;
coll->Setup.EnableSpasm = false;
- Camera.targetDistance = SECTOR(1);
+ Camera.targetDistance = BLOCK(1);
AlignLaraToSurface(item);
@@ -65,7 +65,7 @@ void lara_as_crouch_idle(ItemInfo* item, CollisionInfo* coll)
if (TrInput & (IN_LEFT | IN_RIGHT))
ModulateLaraTurnRateY(item, LARA_TURN_RATE_ACCEL, 0, LARA_CRAWL_TURN_RATE_MAX);
- if ((TrInput & IN_CROUCH || lara->Control.KeepLow) &&
+ if ((IsHeld(In::Crouch) || lara->Control.KeepLow) &&
lara->Control.WaterStatus != WaterStatus::Wade)
{
if (TrInput & IN_ROLL || (TrInput & IN_FORWARD && TrInput & IN_BACK))
@@ -157,7 +157,7 @@ void lara_as_crouch_roll(ItemInfo* item, CollisionInfo* coll)
lara->Control.CanLook = false;
coll->Setup.EnableObjectPush = true;
coll->Setup.EnableSpasm = false;
- Camera.targetDistance = SECTOR(1);
+ Camera.targetDistance = BLOCK(1);
AlignLaraToSurface(item);
@@ -230,7 +230,7 @@ void lara_as_crouch_turn_left(ItemInfo* item, CollisionInfo* coll)
auto* lara = GetLaraInfo(item);
coll->Setup.EnableSpasm = false;
- Camera.targetDistance = SECTOR(1);
+ Camera.targetDistance = BLOCK(1);
AlignLaraToSurface(item);
@@ -243,7 +243,7 @@ void lara_as_crouch_turn_left(ItemInfo* item, CollisionInfo* coll)
if (TrInput & IN_LOOK)
LookUpDown(item);
- if ((TrInput & IN_CROUCH || lara->Control.KeepLow) &&
+ if ((IsHeld(In::Crouch) || lara->Control.KeepLow) &&
lara->Control.WaterStatus != WaterStatus::Wade)
{
if (TrInput & IN_SPRINT && TestLaraCrouchRoll(item, coll) &&
@@ -287,7 +287,7 @@ void lara_as_crouch_turn_right(ItemInfo* item, CollisionInfo* coll)
auto* lara = GetLaraInfo(item);
coll->Setup.EnableSpasm = false;
- Camera.targetDistance = SECTOR(1);
+ Camera.targetDistance = BLOCK(1);
AlignLaraToSurface(item);
@@ -300,7 +300,7 @@ void lara_as_crouch_turn_right(ItemInfo* item, CollisionInfo* coll)
if (TrInput & IN_LOOK)
LookUpDown(item);
- if ((TrInput & IN_CROUCH || lara->Control.KeepLow) &&
+ if ((IsHeld(In::Crouch) || lara->Control.KeepLow) &&
lara->Control.WaterStatus != WaterStatus::Wade)
{
if (TrInput & IN_SPRINT && TestLaraCrouchRoll(item, coll) &&
@@ -344,11 +344,11 @@ void lara_as_crouch_turn_180(ItemInfo* item, CollisionInfo* coll)
auto* lara = GetLaraInfo(item);
coll->Setup.EnableSpasm = false;
- Camera.targetDistance = SECTOR(1);
+ Camera.targetDistance = BLOCK(1);
AlignLaraToSurface(item);
- if ((TrInput & IN_CROUCH || lara->Control.KeepLow) &&
+ if ((IsHeld(In::Crouch) || lara->Control.KeepLow) &&
lara->Control.WaterStatus != WaterStatus::Wade)
{
if (TrInput & (IN_FORWARD | IN_BACK) && TestLaraCrouchToCrawl(item))
@@ -381,7 +381,7 @@ void lara_as_crawl_idle(ItemInfo* item, CollisionInfo* coll)
{
coll->Setup.EnableObjectPush = true;
coll->Setup.EnableSpasm = false;
- Camera.targetDistance = SECTOR(1);
+ Camera.targetDistance = BLOCK(1);
AlignLaraToSurface(item);
@@ -409,7 +409,7 @@ void lara_as_crawl_idle(ItemInfo* item, CollisionInfo* coll)
if (TrInput & (IN_LEFT | IN_RIGHT))
ModulateLaraTurnRateY(item, LARA_TURN_RATE_ACCEL, 0, LARA_CRAWL_TURN_RATE_MAX);
- if ((TrInput & IN_CROUCH || lara->Control.KeepLow) &&
+ if ((IsHeld(In::Crouch) || lara->Control.KeepLow) &&
lara->Control.WaterStatus != WaterStatus::Wade)
{
if (TrInput & IN_ROLL || (TrInput & IN_FORWARD && TrInput & IN_BACK))
@@ -419,7 +419,7 @@ void lara_as_crawl_idle(ItemInfo* item, CollisionInfo* coll)
}
if ((TrInput & IN_SPRINT && TestLaraCrouchRoll(item, coll)) ||
- (TrInput & (IN_DRAW | IN_FLARE) &&
+ ((IsHeld(In::Draw) || IsHeld(In::Flare)) &&
!IsStandingWeapon(item, lara->Control.Weapon.GunType) && HasStateDispatch(item, LS_CROUCH_IDLE)))
{
item->Animation.TargetState = LS_CROUCH_IDLE;
@@ -431,7 +431,7 @@ void lara_as_crawl_idle(ItemInfo* item, CollisionInfo* coll)
{
auto crawlVaultResult = TestLaraCrawlVault(item, coll);
- if (TrInput & (IN_ACTION | IN_JUMP) && crawlVaultResult.Success &&
+ if ((IsHeld(In::Action) || IsHeld(In::Jump)) && crawlVaultResult.Success &&
g_GameFlow->HasCrawlExtended())
{
item->Animation.TargetState = crawlVaultResult.TargetState;
@@ -447,7 +447,7 @@ void lara_as_crawl_idle(ItemInfo* item, CollisionInfo* coll)
}
else if (TrInput & IN_BACK)
{
- if (TrInput & (IN_ACTION | IN_JUMP) && TestLaraCrawlToHang(item, coll))
+ if ((IsHeld(In::Action) || IsHeld(In::Jump)) && TestLaraCrawlToHang(item, coll))
{
item->Animation.TargetState = LS_CRAWL_TO_HANG;
DoLaraCrawlToHangSnap(item, coll);
@@ -532,7 +532,7 @@ void lara_as_crawl_forward(ItemInfo* item, CollisionInfo* coll)
lara->Control.HandStatus = HandStatus::Busy;
coll->Setup.EnableObjectPush = true;
coll->Setup.EnableSpasm = false;
- Camera.targetDistance = SECTOR(1);
+ Camera.targetDistance = BLOCK(1);
AlignLaraToSurface(item);
@@ -548,7 +548,7 @@ void lara_as_crawl_forward(ItemInfo* item, CollisionInfo* coll)
ModulateLaraCrawlFlex(item, LARA_CRAWL_FLEX_RATE, LARA_CRAWL_FLEX_MAX);
}
- if ((TrInput & IN_CROUCH || lara->Control.KeepLow) &&
+ if ((IsHeld(In::Crouch) || lara->Control.KeepLow) &&
lara->Control.WaterStatus != WaterStatus::Wade)
{
if (TrInput & IN_SPRINT && TestLaraCrouchRoll(item, coll))
@@ -628,7 +628,7 @@ void lara_as_crawl_back(ItemInfo* item, CollisionInfo* coll)
lara->Control.HandStatus = HandStatus::Busy;
coll->Setup.EnableObjectPush = true;
coll->Setup.EnableSpasm = false;
- Camera.targetDistance = SECTOR(1);
+ Camera.targetDistance = BLOCK(1);
AlignLaraToSurface(item);
@@ -644,7 +644,7 @@ void lara_as_crawl_back(ItemInfo* item, CollisionInfo* coll)
ModulateLaraCrawlFlex(item, LARA_CRAWL_FLEX_RATE, LARA_CRAWL_FLEX_MAX);
}
- if ((TrInput & IN_CROUCH || lara->Control.KeepLow) &&
+ if ((IsHeld(In::Crouch) || lara->Control.KeepLow) &&
lara->Control.WaterStatus != WaterStatus::Wade)
{
if (TrInput & IN_BACK)
@@ -715,7 +715,7 @@ void lara_as_crawl_turn_left(ItemInfo* item, CollisionInfo* coll)
lara->Control.HandStatus = HandStatus::Busy;
coll->Setup.EnableObjectPush = true;
coll->Setup.EnableSpasm = false;
- Camera.targetDistance = SECTOR(1);
+ Camera.targetDistance = BLOCK(1);
AlignLaraToSurface(item);
@@ -725,7 +725,7 @@ void lara_as_crawl_turn_left(ItemInfo* item, CollisionInfo* coll)
return;
}
- if ((TrInput & IN_CROUCH || lara->Control.KeepLow) &&
+ if ((IsHeld(In::Crouch) || lara->Control.KeepLow) &&
lara->Control.WaterStatus != WaterStatus::Wade)
{
if (TrInput & IN_SPRINT && TestLaraCrouchRoll(item, coll))
@@ -776,7 +776,7 @@ void lara_as_crawl_turn_right(ItemInfo* item, CollisionInfo* coll)
lara->Control.HandStatus = HandStatus::Busy;
coll->Setup.EnableObjectPush = true;
coll->Setup.EnableSpasm = false;
- Camera.targetDistance = SECTOR(1);
+ Camera.targetDistance = BLOCK(1);
AlignLaraToSurface(item);
@@ -786,7 +786,7 @@ void lara_as_crawl_turn_right(ItemInfo* item, CollisionInfo* coll)
return;
}
- if ((TrInput & IN_CROUCH || lara->Control.KeepLow) &&
+ if ((IsHeld(In::Crouch) || lara->Control.KeepLow) &&
lara->Control.WaterStatus != WaterStatus::Wade)
{
if (TrInput & IN_SPRINT && TestLaraCrouchRoll(item, coll))
@@ -835,11 +835,11 @@ void lara_as_crawl_turn_180(ItemInfo* item, CollisionInfo* coll)
auto* lara = GetLaraInfo(item);
coll->Setup.EnableSpasm = false;
- Camera.targetDistance = SECTOR(1);
+ Camera.targetDistance = BLOCK(1);
AlignLaraToSurface(item);
- if ((TrInput & IN_CROUCH || lara->Control.KeepLow) &&
+ if ((IsHeld(In::Crouch) || lara->Control.KeepLow) &&
lara->Control.WaterStatus != WaterStatus::Wade)
{
item->Animation.TargetState = LS_CRAWL_IDLE;
@@ -864,7 +864,7 @@ void lara_col_crawl_to_hang(ItemInfo* item, CollisionInfo* coll)
coll->Setup.EnableObjectPush = true;
coll->Setup.EnableSpasm = false;
Camera.targetAngle = 0;
- Camera.targetDistance = SECTOR(1);
+ Camera.targetDistance = BLOCK(1);
ResetPlayerLean(item, 1 / 6.0f);
diff --git a/TombEngine/Game/Lara/lara_fire.cpp b/TombEngine/Game/Lara/lara_fire.cpp
index 650caca11..81bfb894f 100644
--- a/TombEngine/Game/Lara/lara_fire.cpp
+++ b/TombEngine/Game/Lara/lara_fire.cpp
@@ -519,7 +519,7 @@ void HandleWeapon(ItemInfo& laraItem)
else if (player.Control.HandStatus == HandStatus::Free)
{
// Draw weapon.
- if (IsHeld(In::DrawWeapon))
+ if (IsHeld(In::Draw))
{
// No weapon - no any actions.
if (player.Control.Weapon.LastGunType != LaraWeaponType::None)
@@ -547,7 +547,7 @@ void HandleWeapon(ItemInfo& laraItem)
}
}
- if ((IsHeld(In::DrawWeapon) && player.Control.Weapon.LastGunType != LaraWeaponType::None) ||
+ if ((IsHeld(In::Draw) && player.Control.Weapon.LastGunType != LaraWeaponType::None) ||
player.Control.Weapon.RequestGunType != player.Control.Weapon.GunType)
{
if (player.Control.IsLow &&
@@ -596,7 +596,7 @@ void HandleWeapon(ItemInfo& laraItem)
}
else if (player.Control.HandStatus == HandStatus::WeaponReady)
{
- if (IsHeld(In::DrawWeapon) ||
+ if (IsHeld(In::Draw) ||
player.Control.Weapon.RequestGunType != player.Control.Weapon.GunType)
{
player.Control.HandStatus = HandStatus::WeaponUndraw;
diff --git a/TombEngine/Game/Lara/lara_hang.cpp b/TombEngine/Game/Lara/lara_hang.cpp
index affb268c9..cb61bf2c3 100644
--- a/TombEngine/Game/Lara/lara_hang.cpp
+++ b/TombEngine/Game/Lara/lara_hang.cpp
@@ -130,7 +130,7 @@ void lara_col_hang(ItemInfo* item, CollisionInfo* coll)
}
// TODO: Allow direction locking just like with standing jumps. Needs new ledge jump prepare state? -- Sezz 24.10.2022
- if (TrInput & IN_JUMP && TestLaraLedgeJump(item, coll))
+ if (IsHeld(In::Jump) && TestLaraLedgeJump(item, coll))
{
if (TrInput & IN_BACK)
item->Animation.TargetState = LS_JUMP_FORWARD;
diff --git a/TombEngine/Game/Lara/lara_helpers.cpp b/TombEngine/Game/Lara/lara_helpers.cpp
index d6458d541..8d3b09d6c 100644
--- a/TombEngine/Game/Lara/lara_helpers.cpp
+++ b/TombEngine/Game/Lara/lara_helpers.cpp
@@ -13,6 +13,7 @@
#include "Game/Lara/lara_collide.h"
#include "Game/Lara/lara_fire.h"
#include "Game/Lara/lara_tests.h"
+#include "Game/savegame.h"
#include "Game/Setup.h"
#include "Math/Math.h"
#include "Renderer/Renderer11.h"
@@ -68,7 +69,7 @@ void HandleLaraMovementParameters(ItemInfo* item, CollisionInfo* coll)
lara->Control.RunJumpQueued = false;
// Reset lean.
- if ((!lara->Control.IsMoving || (lara->Control.IsMoving && !(TrInput & (IN_LEFT | IN_RIGHT)))) &&
+ if ((!lara->Control.IsMoving || (lara->Control.IsMoving && !(IsHeld(In::Left) || IsHeld(In::Right)))) &&
(!lara->Control.IsLow && item->Animation.ActiveState != LS_DEATH)) // HACK: Don't interfere with surface alignment in crouch, crawl, and death states.
{
ResetPlayerLean(item, 1 / 6.0f);
@@ -76,20 +77,186 @@ void HandleLaraMovementParameters(ItemInfo* item, CollisionInfo* coll)
// Reset crawl flex.
if (!(TrInput & IN_LOOK) && coll->Setup.Height > LARA_HEIGHT - LARA_HEADROOM && // HACK
- (!item->Animation.Velocity.z || (item->Animation.Velocity.z && !(TrInput & (IN_LEFT | IN_RIGHT)))))
+ (!item->Animation.Velocity.z || (item->Animation.Velocity.z && !(IsHeld(In::Left) || IsHeld(In::Right)))))
{
ResetPlayerFlex(item, 0.1f);
}
// Apply and reset turn rate.
item->Pose.Orientation.y += lara->Control.TurnRate;
- if (!(TrInput & (IN_LEFT | IN_RIGHT)))
+ if (!(IsHeld(In::Left) || IsHeld(In::Right)))
lara->Control.TurnRate = 0;
lara->Control.IsLow = false;
lara->Control.IsMonkeySwinging = false;
}
+static void UsePlayerMedipack(ItemInfo& item)
+{
+ auto& player = GetLaraInfo(item);
+
+ // Can't use medipack; return early.
+ if (item.HitPoints <= 0 ||
+ (item.HitPoints >= LARA_HEALTH_MAX && player.Status.Poison == 0))
+ {
+ return;
+ }
+
+ bool hasUsedMedipack = false;
+
+ if (IsClicked(In::SmallMedipack) &&
+ player.Inventory.TotalSmallMedipacks != 0)
+ {
+ hasUsedMedipack = true;
+
+ item.HitPoints += LARA_HEALTH_MAX / 2;
+ if (item.HitPoints > LARA_HEALTH_MAX)
+ item.HitPoints = LARA_HEALTH_MAX;
+
+ if (player.Inventory.TotalSmallMedipacks != -1)
+ player.Inventory.TotalSmallMedipacks--;
+ }
+ else if (IsClicked(In::LargeMedipack) &&
+ player.Inventory.TotalLargeMedipacks != 0)
+ {
+ hasUsedMedipack = true;
+ item.HitPoints = LARA_HEALTH_MAX;
+
+ if (player.Inventory.TotalLargeMedipacks != -1)
+ player.Inventory.TotalLargeMedipacks--;
+ }
+
+ if (hasUsedMedipack)
+ {
+ player.Status.Poison = 0;
+ Statistics.Game.HealthUsed++;
+ SoundEffect(SFX_TR4_MENU_MEDI, nullptr, SoundEnvironment::Always);
+ }
+}
+
+static std::optional GetPlayerScrolledWeaponType(const ItemInfo& item, LaraWeaponType currentWeaponType, bool getPrev)
+{
+ static const auto SCROLL_WEAPON_TYPES = std::vector
+ {
+ LaraWeaponType::Pistol,
+ LaraWeaponType::Shotgun,
+ LaraWeaponType::Uzi,
+ LaraWeaponType::Revolver,
+ LaraWeaponType::GrenadeLauncher,
+ LaraWeaponType::Crossbow,
+ LaraWeaponType::HarpoonGun,
+ LaraWeaponType::HK,
+ LaraWeaponType::RocketLauncher
+ };
+
+ auto& player = GetLaraInfo(item);
+
+ // Get vector index for current weapon type.
+ auto currentIndex = std::optional(std::nullopt);
+ for (int i = 0; i < SCROLL_WEAPON_TYPES.size(); i++)
+ {
+ if (SCROLL_WEAPON_TYPES[i] == currentWeaponType)
+ {
+ currentIndex = i;
+ break;
+ }
+ }
+
+ // Invalid current weapon type; return nullopt.
+ if (!currentIndex.has_value())
+ return std::nullopt;
+
+ // Getter for next index.
+ auto getNextIndex = [getPrev](unsigned int index)
+ {
+ return (index + (getPrev ? ((unsigned int)SCROLL_WEAPON_TYPES.size() - 1) : 1)) % (unsigned int)SCROLL_WEAPON_TYPES.size();
+ };
+
+ // Get next valid weapon type in sequence.
+ unsigned int nextIndex = getNextIndex(*currentIndex);
+ while (nextIndex != *currentIndex)
+ {
+ auto nextWeaponType = SCROLL_WEAPON_TYPES[nextIndex];
+ if (player.Weapons[(int)nextWeaponType].Present)
+ return nextWeaponType;
+
+ nextIndex = getNextIndex(nextIndex);
+ }
+
+ // No valid weapon type; return nullopt.
+ return std::nullopt;
+}
+
+void HandlePlayerQuickActions(ItemInfo& item)
+{
+ auto& player = GetLaraInfo(item);
+
+ // Handle medipacks.
+ if (IsClicked(In::SmallMedipack) || IsClicked(In::LargeMedipack))
+ UsePlayerMedipack(item);
+
+ // Handle weapon scroll requests.
+ if (IsClicked(In::PreviousWeapon) || IsClicked(In::NextWeapon))
+ {
+ bool getPrev = IsClicked(In::PreviousWeapon);
+ auto weaponType = GetPlayerScrolledWeaponType(item, player.Control.Weapon.GunType, getPrev);
+
+ if (weaponType.has_value())
+ player.Control.Weapon.RequestGunType = *weaponType;
+ }
+
+ // Handle weapon requests.
+ if (IsClicked(In::Weapon1) && player.Weapons[(int)LaraWeaponType::Pistol].Present)
+ player.Control.Weapon.RequestGunType = LaraWeaponType::Pistol;
+
+ if (IsClicked(In::Weapon2) && player.Weapons[(int)LaraWeaponType::Shotgun].Present)
+ player.Control.Weapon.RequestGunType = LaraWeaponType::Shotgun;
+
+ if (IsClicked(In::Weapon3) && player.Weapons[(int)LaraWeaponType::Uzi].Present)
+ player.Control.Weapon.RequestGunType = LaraWeaponType::Uzi;
+
+ if (IsClicked(In::Weapon4) && player.Weapons[(int)LaraWeaponType::Revolver].Present)
+ player.Control.Weapon.RequestGunType = LaraWeaponType::Revolver;
+
+ if (IsClicked(In::Weapon5) && player.Weapons[(int)LaraWeaponType::GrenadeLauncher].Present)
+ player.Control.Weapon.RequestGunType = LaraWeaponType::GrenadeLauncher;
+
+ if (IsClicked(In::Weapon6) && player.Weapons[(int)LaraWeaponType::Crossbow].Present)
+ player.Control.Weapon.RequestGunType = LaraWeaponType::Crossbow;
+
+ if (IsClicked(In::Weapon7) && player.Weapons[(int)LaraWeaponType::HarpoonGun].Present)
+ player.Control.Weapon.RequestGunType = LaraWeaponType::HarpoonGun;
+
+ if (IsClicked(In::Weapon8) && player.Weapons[(int)LaraWeaponType::HK].Present)
+ player.Control.Weapon.RequestGunType = LaraWeaponType::HK;
+
+ if (IsClicked(In::Weapon9) && player.Weapons[(int)LaraWeaponType::RocketLauncher].Present)
+ player.Control.Weapon.RequestGunType = LaraWeaponType::RocketLauncher;
+
+ // TODO: 10th possible weapon, probably grapple gun.
+ /*if (IsClicked(In::Weapon10) && player.Weapons[(int)LaraWeaponType::].Present)
+ player.Control.Weapon.RequestGunType = LaraWeaponType::;*/
+
+ // TODO: Could theoretically remove SwitchTarget and instead do unique behaviour handling using only Look. -- Sezz 2023.07.08
+ // HACK: Handle target switch when locked on to an entity.
+ if (player.Control.HandStatus == HandStatus::WeaponReady &&
+ player.TargetEntity != nullptr)
+ {
+ if (IsClicked(In::Look))
+ {
+ ActionMap[(int)In::SwitchTarget].Update(true);
+ }
+ else
+ {
+ ClearAction(In::SwitchTarget);
+ }
+ }
+ else
+ {
+ ClearAction(In::SwitchTarget);
+ }
+}
+
bool HandleLaraVehicle(ItemInfo* item, CollisionInfo* coll)
{
auto* lara = GetLaraInfo(item);
@@ -229,7 +396,7 @@ void HandlePlayerAirBubbles(ItemInfo* item)
SoundEffect(SFX_TR4_LARA_BUBBLES, &item->Pose, SoundEnvironment::Water);
const auto& level = *g_GameFlow->GetLevel(CurrentLevel);
-
+
auto pos = (level.GetLaraType() == LaraType::Divesuit) ?
GetJointPosition(item, LM_TORSO, Vector3i(0, -192, -160)).ToVector3() :
GetJointPosition(item, LM_HEAD, Vector3i(0, -4, -64)).ToVector3();
@@ -243,12 +410,9 @@ void HandlePlayerAirBubbles(ItemInfo* item)
// Potential solutions:
// 1. Consider floor tilt when translating objects.
// 2. Object parenting. -- Sezz 2022.10.28
-void EaseOutLaraHeight(ItemInfo* item, int height)
+void EasePlayerVerticalPosition(ItemInfo* item, int height)
{
- constexpr auto LINEAR_THRESHOLD = STEPUP_HEIGHT / 2;
- constexpr auto EASING_THRESHOLD_MIN = BLOCK(1.0f / 64);
- constexpr auto LINEAR_RATE = 50;
- constexpr auto EASING_ALPHA = 0.35f;
+ constexpr auto LINEAR_RATE_MIN = 50.0f;
// Check for wall.
if (height == NO_HEIGHT)
@@ -261,18 +425,12 @@ void EaseOutLaraHeight(ItemInfo* item, int height)
return;
}
- int easingThreshold = std::max(abs(item->Animation.Velocity.z), EASING_THRESHOLD_MIN);
-
// Handle regular case.
- if (abs(height) > LINEAR_THRESHOLD)
+ float linearRate = std::max(LINEAR_RATE_MIN, abs(item->Animation.Velocity.z));
+ if (abs(height) > linearRate)
{
int sign = std::copysign(1, height);
- item->Pose.Position.y += LINEAR_RATE * sign;
- }
- else if (abs(height) > easingThreshold)
- {
- int vPos = item->Pose.Position.y;
- item->Pose.Position.y = (int)round(Lerp(vPos, vPos + height, EASING_ALPHA));
+ item->Pose.Position.y += linearRate * sign;
}
else
{
@@ -306,12 +464,12 @@ void DoLaraStep(ItemInfo* item, CollisionInfo* coll)
}
}
- EaseOutLaraHeight(item, coll->Middle.Floor);
+ EasePlayerVerticalPosition(item, coll->Middle.Floor);
}
void DoLaraMonkeyStep(ItemInfo* item, CollisionInfo* coll)
{
- EaseOutLaraHeight(item, coll->Middle.Ceiling);
+ EasePlayerVerticalPosition(item, coll->Middle.Ceiling);
}
void DoLaraCrawlToHangSnap(ItemInfo* item, CollisionInfo* coll)
@@ -513,7 +671,7 @@ void ModulateLaraSwimTurnRates(ItemInfo* item, CollisionInfo* coll)
auto* lara = GetLaraInfo(item);
/*if (TrInput & (IN_FORWARD | IN_BACK))
- ModulateLaraTurnRateX(item, 0, 0, 0);*/
+ ModulateLaraTurnRateX(item, 0, 0, 0);*/
if (TrInput & IN_FORWARD)
item->Pose.Orientation.x -= ANGLE(3.0f);
@@ -609,16 +767,16 @@ void UpdateLaraSubsuitAngles(ItemInfo* item)
else if (lara->Control.TurnRate < 0)
lara->Control.Subsuit.Velocity[1] += 2 * abs(lara->Control.TurnRate);
- if (lara->Control.Subsuit.Velocity[0] > SECTOR(1.5f))
- lara->Control.Subsuit.Velocity[0] = SECTOR(1.5f);
+ if (lara->Control.Subsuit.Velocity[0] > BLOCK(1.5f))
+ lara->Control.Subsuit.Velocity[0] = BLOCK(1.5f);
- if (lara->Control.Subsuit.Velocity[1] > SECTOR(1.5f))
- lara->Control.Subsuit.Velocity[1] = SECTOR(1.5f);
+ if (lara->Control.Subsuit.Velocity[1] > BLOCK(1.5f))
+ lara->Control.Subsuit.Velocity[1] = BLOCK(1.5f);
if (lara->Control.Subsuit.Velocity[0] != 0 || lara->Control.Subsuit.Velocity[1] != 0)
{
- auto mul1 = (float)abs(lara->Control.Subsuit.Velocity[0]) / SECTOR(8);
- auto mul2 = (float)abs(lara->Control.Subsuit.Velocity[1]) / SECTOR(8);
+ auto mul1 = (float)abs(lara->Control.Subsuit.Velocity[0]) / BLOCK(8);
+ auto mul2 = (float)abs(lara->Control.Subsuit.Velocity[1]) / BLOCK(8);
auto vol = ((mul1 + mul2) * 5.0f) + 0.5f;
SoundEffect(SFX_TR5_VEHICLE_DIVESUIT_ENGINE, &item->Pose, SoundEnvironment::Water, 1.0f + (mul1 + mul2), vol);
}
@@ -686,7 +844,7 @@ void ModulateLaraSlideVelocity(ItemInfo* item, CollisionInfo* coll)
//lara->ExtraVelocity.y += slideVelocity * phd_sin(steepness);
}
//else
- //lara->ExtraVelocity.x += minVelocity;
+ //lara->ExtraVelocity.x += minVelocity;
}
void AlignLaraToSurface(ItemInfo* item, float alpha)
@@ -737,7 +895,7 @@ void SetLaraRunJumpQueue(ItemInfo* item, CollisionInfo* coll)
auto* lara = GetLaraInfo(item);
int y = item->Pose.Position.y;
- int distance = SECTOR(1);
+ int distance = BLOCK(1);
auto probe = GetCollision(item, item->Pose.Orientation.y, distance, -coll->Setup.Height);
if ((TestLaraRunJumpForward(item, coll) || // Area close ahead is permissive...
diff --git a/TombEngine/Game/Lara/lara_helpers.h b/TombEngine/Game/Lara/lara_helpers.h
index 35d3cdd6d..24e5d9384 100644
--- a/TombEngine/Game/Lara/lara_helpers.h
+++ b/TombEngine/Game/Lara/lara_helpers.h
@@ -12,12 +12,13 @@ struct VaultTestResult;
// -----------------------------
void HandleLaraMovementParameters(ItemInfo* item, CollisionInfo* coll);
+void HandlePlayerQuickActions(ItemInfo& item);
bool HandleLaraVehicle(ItemInfo* item, CollisionInfo* coll);
void HandlePlayerWetnessDrips(ItemInfo& item);
void HandlePlayerDiveBubbles(ItemInfo& item);
void HandlePlayerAirBubbles(ItemInfo* item);
-void EaseOutLaraHeight(ItemInfo* item, int height);
+void EasePlayerVerticalPosition(ItemInfo* item, int height);
void DoLaraStep(ItemInfo* item, CollisionInfo* coll);
void DoLaraMonkeyStep(ItemInfo* item, CollisionInfo* coll);
void DoLaraCrawlToHangSnap(ItemInfo* item, CollisionInfo* coll);
diff --git a/TombEngine/Game/Lara/lara_initialise.cpp b/TombEngine/Game/Lara/lara_initialise.cpp
index e89d81697..08cb427d9 100644
--- a/TombEngine/Game/Lara/lara_initialise.cpp
+++ b/TombEngine/Game/Lara/lara_initialise.cpp
@@ -12,31 +12,36 @@
using namespace TEN::Hud;
-void InitializeLara(bool restore)
+LaraInfo lBackup = {};
+int lHitPoints = 0;
+
+void BackupLara()
{
- if (Lara.ItemNumber == NO_ITEM)
+ if (LaraItem == nullptr || LaraItem->Index == NO_ITEM)
return;
- LaraInfo lBackup = {};
- if (restore)
- memcpy(&lBackup, &Lara, sizeof(LaraInfo));
+ memcpy(&lBackup, &Lara, sizeof(LaraInfo));
+ lHitPoints = LaraItem->HitPoints;
+}
- short itemNumber = Lara.ItemNumber;
+void InitializeLara(bool restore)
+{
+ if (LaraItem == nullptr || LaraItem->Index == NO_ITEM)
+ return;
+
+ ZeroMemory(&Lara, sizeof(LaraInfo));
LaraItem->Data = &Lara;
LaraItem->Collidable = false;
LaraItem->Location.roomNumber = LaraItem->RoomNumber;
LaraItem->Location.yNumber = LaraItem->Pose.Position.y;
- ZeroMemory(&Lara, sizeof(LaraInfo));
-
Lara.Status.Air = LARA_AIR_MAX;
Lara.Status.Exposure = LARA_EXPOSURE_MAX;
Lara.Status.Poison = 0;
Lara.Status.Stamina = LARA_STAMINA_MAX;
Lara.Control.CanLook = true;
- Lara.ItemNumber = itemNumber;
Lara.HitDirection = -1;
Lara.Control.Weapon.WeaponItem = NO_ITEM;
Lara.Context.WaterSurfaceDist = 100;
@@ -46,13 +51,18 @@ void InitializeLara(bool restore)
Lara.Location = -1;
Lara.HighestLocation = -1;
Lara.Control.Rope.Ptr = -1;
- LaraItem->HitPoints = LARA_HEALTH_MAX;
Lara.Control.HandStatus = HandStatus::Free;
if (restore)
- InitializeLaraLevelJump(itemNumber, &lBackup);
+ {
+ InitializeLaraLevelJump(LaraItem->Index, &lBackup);
+ LaraItem->HitPoints = lHitPoints;
+ }
else
+ {
InitializeLaraDefaultInventory();
+ LaraItem->HitPoints = LARA_HEALTH_MAX;
+ }
InitializeLaraMeshes(LaraItem);
InitializeLaraAnims(LaraItem);
@@ -143,10 +153,9 @@ void InitializeLaraAnims(ItemInfo* item)
}
}
-void InitializeLaraLoad(short itemNum)
+void InitializeLaraLoad(short itemNumber)
{
- Lara.ItemNumber = itemNum;
- LaraItem = &g_Level.Items[itemNum];
+ LaraItem = &g_Level.Items[itemNumber];
}
void InitializeLaraLevelJump(short itemNum, LaraInfo* lBackup)
@@ -157,6 +166,7 @@ void InitializeLaraLevelJump(short itemNum, LaraInfo* lBackup)
// Restore inventory.
// It restores even puzzle/key items, to reset them, a ResetHub analog must be made.
lara->Inventory = lBackup->Inventory;
+ lara->Control.Weapon.LastGunType = lBackup->Control.Weapon.LastGunType;
memcpy(&lara->Weapons, &lBackup->Weapons, sizeof(CarriedWeaponInfo) * int(LaraWeaponType::NumWeapons));
// If no flare present, quit
diff --git a/TombEngine/Game/Lara/lara_initialise.h b/TombEngine/Game/Lara/lara_initialise.h
index 2cb022644..3469f9d1e 100644
--- a/TombEngine/Game/Lara/lara_initialise.h
+++ b/TombEngine/Game/Lara/lara_initialise.h
@@ -1,6 +1,7 @@
#pragma once
#include "Game/Lara/lara_struct.h"
+void BackupLara();
void InitializeLara(bool restore);
void InitializeLaraMeshes(ItemInfo* item);
void InitializeLaraAnims(ItemInfo* item);
diff --git a/TombEngine/Game/Lara/lara_jump.cpp b/TombEngine/Game/Lara/lara_jump.cpp
index 4e0446150..87a280cc0 100644
--- a/TombEngine/Game/Lara/lara_jump.cpp
+++ b/TombEngine/Game/Lara/lara_jump.cpp
@@ -265,12 +265,12 @@ void lara_as_jump_prepare(ItemInfo* item, CollisionInfo* coll)
}
// JUMP key repressed without directional key; cancel directional jump lock.
- if (DbInput & IN_JUMP && !IsDirectionActionHeld())
+ if (IsClicked(In::Jump) && !IsDirectionalActionHeld())
lara->Control.JumpDirection = JumpDirection::None;
if (((TrInput & IN_FORWARD &&
!(TrInput & IN_BACK && lara->Control.JumpDirection == JumpDirection::Back)) || // Back jump takes priority in this exception.
- !IsDirectionActionHeld() && lara->Control.JumpDirection == JumpDirection::Forward) &&
+ !IsDirectionalActionHeld() && lara->Control.JumpDirection == JumpDirection::Forward) &&
TestLaraJumpForward(item, coll))
{
item->Animation.TargetState = LS_JUMP_FORWARD;
@@ -278,7 +278,7 @@ void lara_as_jump_prepare(ItemInfo* item, CollisionInfo* coll)
return;
}
else if ((TrInput & IN_BACK ||
- !IsDirectionActionHeld() && lara->Control.JumpDirection == JumpDirection::Back) &&
+ !IsDirectionalActionHeld() && lara->Control.JumpDirection == JumpDirection::Back) &&
TestLaraJumpBack(item, coll))
{
item->Animation.TargetState = LS_JUMP_BACK;
@@ -287,7 +287,7 @@ void lara_as_jump_prepare(ItemInfo* item, CollisionInfo* coll)
}
if ((TrInput & IN_LEFT ||
- !IsDirectionActionHeld() && lara->Control.JumpDirection == JumpDirection::Left) &&
+ !IsDirectionalActionHeld() && lara->Control.JumpDirection == JumpDirection::Left) &&
TestLaraJumpLeft(item, coll))
{
item->Animation.TargetState = LS_JUMP_LEFT;
@@ -295,7 +295,7 @@ void lara_as_jump_prepare(ItemInfo* item, CollisionInfo* coll)
return;
}
else if ((TrInput & IN_RIGHT ||
- !IsDirectionActionHeld() && lara->Control.JumpDirection == JumpDirection::Right) &&
+ !IsDirectionalActionHeld() && lara->Control.JumpDirection == JumpDirection::Right) &&
TestLaraJumpRight(item, coll))
{
item->Animation.TargetState = LS_JUMP_RIGHT;
diff --git a/TombEngine/Game/Lara/lara_monkey.cpp b/TombEngine/Game/Lara/lara_monkey.cpp
index f7f453f76..b1b359943 100644
--- a/TombEngine/Game/Lara/lara_monkey.cpp
+++ b/TombEngine/Game/Lara/lara_monkey.cpp
@@ -57,7 +57,7 @@ void lara_as_monkey_idle(ItemInfo* item, CollisionInfo* coll)
if (TrInput & IN_ACTION && lara->Control.CanMonkeySwing)
{
- if (TrInput & IN_JUMP)
+ if (IsHeld(In::Jump))
{
item->Animation.TargetState = LS_JUMP_FORWARD;
lara->Control.HandStatus = HandStatus::Free;
@@ -497,7 +497,7 @@ void lara_as_monkey_turn_left(ItemInfo* item, CollisionInfo* coll)
if (TrInput & IN_ACTION && lara->Control.CanMonkeySwing)
{
- if (TrInput & IN_JUMP)
+ if (IsHeld(In::Jump))
{
item->Animation.TargetState = LS_JUMP_FORWARD;
lara->Control.HandStatus = HandStatus::Free;
@@ -576,7 +576,7 @@ void lara_as_monkey_turn_right(ItemInfo* item, CollisionInfo* coll)
if (TrInput & IN_ACTION && lara->Control.CanMonkeySwing)
{
- if (TrInput & IN_JUMP)
+ if (IsHeld(In::Jump))
{
item->Animation.TargetState = LS_JUMP_FORWARD;
lara->Control.HandStatus = HandStatus::Free;
diff --git a/TombEngine/Game/Lara/lara_objects.cpp b/TombEngine/Game/Lara/lara_objects.cpp
index e1fc79b76..9d2550f6e 100644
--- a/TombEngine/Game/Lara/lara_objects.cpp
+++ b/TombEngine/Game/Lara/lara_objects.cpp
@@ -37,7 +37,7 @@ void lara_as_pickup(ItemInfo* item, CollisionInfo* coll)
coll->Setup.EnableSpasm = false;
Camera.targetAngle = -ANGLE(130.0f);
Camera.targetElevation = -ANGLE(15.0f);
- Camera.targetDistance = SECTOR(1);
+ Camera.targetDistance = BLOCK(1);
if (TestLastFrame(item))
item->Animation.TargetState = GetNextAnimState(item);
@@ -54,7 +54,7 @@ void lara_as_pickup_flare(ItemInfo* item, CollisionInfo* coll)
coll->Setup.EnableSpasm = false;
Camera.targetAngle = ANGLE(130.0f);
Camera.targetElevation = -ANGLE(15.0f);
- Camera.targetDistance = SECTOR(1);
+ Camera.targetDistance = BLOCK(1);
if (item->Animation.FrameNumber == (GetAnimData(*item).frameEnd - 1))
lara->Control.HandStatus = HandStatus::Free;
@@ -75,7 +75,7 @@ void lara_as_switch_on(ItemInfo* item, CollisionInfo* coll)
coll->Setup.EnableSpasm = false;
Camera.targetAngle = ANGLE(80.0f);
Camera.targetElevation = -ANGLE(25.0f);
- Camera.targetDistance = SECTOR(1);
+ Camera.targetDistance = BLOCK(1);
Camera.speed = 6;
}
@@ -90,7 +90,7 @@ void lara_as_switch_off(ItemInfo* item, CollisionInfo* coll)
coll->Setup.EnableSpasm = false;
Camera.targetAngle = ANGLE(80.0f);
Camera.targetElevation = -ANGLE(25.0f);
- Camera.targetDistance = SECTOR(1);
+ Camera.targetDistance = BLOCK(1);
Camera.speed = 6;
}
@@ -129,7 +129,7 @@ void lara_as_use_key(ItemInfo* item, CollisionInfo* coll)
coll->Setup.EnableSpasm = false;
Camera.targetAngle = -ANGLE(80.0f);
Camera.targetElevation = -ANGLE(25.0f);
- Camera.targetDistance = SECTOR(1);
+ Camera.targetDistance = BLOCK(1);
}
// State: LS_USE_PUZZLE (43)
@@ -143,7 +143,7 @@ void lara_as_use_puzzle(ItemInfo* item, CollisionInfo* coll)
coll->Setup.EnableSpasm = false;
Camera.targetAngle = -ANGLE(80.0f);
Camera.targetElevation = -ANGLE(25.0f);
- Camera.targetDistance = SECTOR(1);
+ Camera.targetDistance = BLOCK(1);
if (TestLastFrame(item) && item->ItemFlags[0])
{
@@ -266,7 +266,7 @@ void lara_as_horizontal_bar_swing(ItemInfo* item, CollisionInfo* coll)
if (TrInput & IN_ACTION)
{
- if (TrInput & IN_JUMP)
+ if (IsHeld(In::Jump))
item->Animation.TargetState = LS_HORIZONTAL_BAR_LEAP;
item->Animation.TargetState = LS_HORIZONTAL_BAR_SWING;
@@ -502,7 +502,7 @@ void lara_col_rope_swing(ItemInfo* item, CollisionInfo* coll)
{
auto* lara = GetLaraInfo(item);
- Camera.targetDistance = SECTOR(2);
+ Camera.targetDistance = BLOCK(2);
UpdateRopeSwing(item);
RopeSwingCollision(item, coll, true);
@@ -550,7 +550,7 @@ void lara_col_rope_swing(ItemInfo* item, CollisionInfo* coll)
item->Animation.FrameNumber = GetAnimData(item).frameBase;
}
- if (TrInput & IN_JUMP)
+ if (IsHeld(In::Jump))
JumpOffRope(item);
}
else if (item->Animation.FrameNumber == GetAnimData(LA_ROPE_IDLE_TO_SWING).frameBase + 15)
@@ -618,7 +618,7 @@ void lara_as_pole_idle(ItemInfo* item, CollisionInfo* coll)
}
// TODO: Add forward jump.
- if (TrInput & IN_JUMP)
+ if (IsHeld(In::Jump))
{
item->Animation.TargetState = LS_JUMP_BACK;
return;
@@ -707,7 +707,7 @@ void lara_as_pole_up(ItemInfo* item, CollisionInfo* coll)
if (TrInput & (IN_LEFT | IN_RIGHT))
ModulateLaraTurnRateY(item, LARA_POLE_TURN_RATE_ACCEL, 0, LARA_POLE_TURN_RATE_MAX, true);
- if (TrInput & IN_JUMP)
+ if (IsHeld(In::Jump))
{
item->Animation.TargetState = LS_POLE_IDLE;
return;
@@ -756,7 +756,7 @@ void lara_as_pole_down(ItemInfo* item, CollisionInfo* coll)
if (TrInput & (IN_LEFT | IN_RIGHT))
ModulateLaraTurnRateY(item, LARA_POLE_TURN_RATE_ACCEL, 0, LARA_POLE_TURN_RATE_MAX, true);
- if (TrInput & IN_JUMP)
+ if (IsHeld(In::Jump))
{
item->Animation.TargetState = LS_POLE_IDLE;
return;
diff --git a/TombEngine/Game/Lara/lara_one_gun.cpp b/TombEngine/Game/Lara/lara_one_gun.cpp
index 15a2e96f3..1e6eddf9c 100644
--- a/TombEngine/Game/Lara/lara_one_gun.cpp
+++ b/TombEngine/Game/Lara/lara_one_gun.cpp
@@ -9,6 +9,7 @@
#include "Game/control/los.h"
#include "Game/effects/Bubble.h"
#include "Game/effects/debris.h"
+#include "Game/effects/Drip.h"
#include "Game/effects/effects.h"
#include "Game/effects/item_fx.h"
#include "Game/effects/Ripple.h"
@@ -31,6 +32,7 @@
#include "Specific/level.h"
using namespace TEN::Effects::Bubble;
+using namespace TEN::Effects::Drip;
using namespace TEN::Effects::Environment;
using namespace TEN::Effects::Items;
using namespace TEN::Effects::Ripple;
@@ -44,6 +46,9 @@ constexpr auto GRENADE_FLASH_TIMEOUT = 4;
constexpr auto HARPOON_VELOCITY = BLOCK(0.25f);
constexpr auto HARPOON_TIME = 10 * FPS;
+constexpr auto BOLT_VELOCITY = BLOCK(0.25f);
+constexpr auto BOLT_TIME = 10 * FPS;
+constexpr auto BOLT_STUCK_LIFE = 5 * FPS;
constexpr auto ROCKET_VELOCITY = CLICK(2);
constexpr auto ROCKET_TIME = 4.5f * FPS;
constexpr auto GRENADE_VELOCITY = BLOCK(1 / 8.0f);
@@ -204,7 +209,7 @@ void AnimateShotgun(ItemInfo& laraItem, LaraWeaponType weaponType)
break;
case LaraWeaponType::Crossbow:
- FireCrossbow(laraItem, nullptr);
+ FireCrossbow(laraItem);
break;
case LaraWeaponType::HK:
@@ -556,109 +561,112 @@ void UndrawShotgunMeshes(ItemInfo& laraItem, LaraWeaponType weaponType)
}
}
-ItemInfo* FireHarpoon(ItemInfo& laraItem)
+bool FireHarpoon(ItemInfo& laraItem, const std::optional& pose)
{
auto& player = *GetLaraInfo(&laraItem);
auto& ammo = GetAmmo(player, LaraWeaponType::HarpoonGun);
if (!ammo)
- return nullptr;
+ return false;
player.Control.Weapon.HasFired = true;
- // Create a new item for harpoon.
- short itemNumber = CreateItem();
+ int itemNumber = CreateItem();
if (itemNumber == NO_ITEM)
- return nullptr;
+ return false;
+
+ auto& harpoonItem = g_Level.Items[itemNumber];
+
+ harpoonItem.ObjectNumber = ID_HARPOON;
+ harpoonItem.Model.Color = Vector4(0.5f, 0.5f, 0.5f, 1.0f);
if (!ammo.HasInfinite())
ammo--;
- auto& item = g_Level.Items[itemNumber];
-
- item.Model.Color = Vector4(0.5f, 0.5f, 0.5f, 1.0f);
- item.ObjectNumber = ID_HARPOON;
- item.RoomNumber = laraItem.RoomNumber;
-
- auto jointPos = GetJointPosition(&laraItem, LM_RHAND, Vector3i(-2, 373, 77));
- int floorHeight = GetCollision(jointPos.x, jointPos.y, jointPos.z, item.RoomNumber).Position.Floor;
-
- if (floorHeight >= jointPos.y)
+ if (pose.has_value())
{
- item.Pose.Position = jointPos;
+ harpoonItem.Pose.Position = pose->Position;
+ harpoonItem.RoomNumber = laraItem.RoomNumber;
+
+ InitializeItem(itemNumber);
+
+ harpoonItem.Pose.Orientation = EulerAngles(
+ player.LeftArm.Orientation.x + laraItem.Pose.Orientation.x,
+ player.LeftArm.Orientation.y + laraItem.Pose.Orientation.y,
+ 0);
}
else
{
- item.Pose.Position = Vector3i(laraItem.Pose.Position.x, jointPos.y, laraItem.Pose.Position.z);
- item.RoomNumber = laraItem.RoomNumber;
+ auto jointPos = GetJointPosition(&laraItem, LM_RHAND, Vector3i(-2, 373, 77));
+ harpoonItem.RoomNumber = laraItem.RoomNumber;
+
+ int floorHeight = GetCollision(jointPos.x, jointPos.y, jointPos.z, harpoonItem.RoomNumber).Position.Floor;
+ if (floorHeight >= jointPos.y)
+ {
+ harpoonItem.Pose.Position = jointPos;
+ }
+ else
+ {
+ harpoonItem.Pose.Position = Vector3i(laraItem.Pose.Position.x, jointPos.y, laraItem.Pose.Position.z);
+ harpoonItem.RoomNumber = laraItem.RoomNumber;
+ }
+
+ InitializeItem(itemNumber);
+
+ harpoonItem.Pose.Orientation.x = player.LeftArm.Orientation.x + laraItem.Pose.Orientation.x;
+ harpoonItem.Pose.Orientation.z = 0;
+ harpoonItem.Pose.Orientation.y = player.LeftArm.Orientation.y + laraItem.Pose.Orientation.y;
+
+ if (!player.LeftArm.Locked)
+ harpoonItem.Pose.Orientation += player.ExtraTorsoRot;
}
- InitializeItem(itemNumber);
+ harpoonItem.Animation.Velocity.z = HARPOON_VELOCITY;
+ harpoonItem.HitPoints = HARPOON_TIME;
- item.Pose.Orientation = EulerAngles(
- player.LeftArm.Orientation.x + laraItem.Pose.Orientation.x,
- player.LeftArm.Orientation.y + laraItem.Pose.Orientation.y,
- 0);
+ AddActiveItem(itemNumber);
- if (!player.LeftArm.Locked)
- item.Pose.Orientation += player.ExtraTorsoRot;
-
- item.Pose.Orientation.z = 0;
- item.Animation.Velocity.z = HARPOON_VELOCITY * phd_cos(item.Pose.Orientation.x);
- item.Animation.Velocity.y = -HARPOON_VELOCITY * phd_sin(item.Pose.Orientation.x);
- item.HitPoints = HARPOON_TIME;
+ harpoonItem.ItemFlags[0] = (int)ProjectileType::Harpoon;
Rumble(0.2f, 0.1f);
- AddActiveItem(itemNumber);
Statistics.Level.AmmoUsed++;
Statistics.Game.AmmoUsed++;
- return &item;
+ return true;
}
-
+
void HarpoonBoltControl(short itemNumber)
{
auto& harpoonItem = g_Level.Items[itemNumber];
if (harpoonItem.HitPoints < HARPOON_TIME)
{
- if (harpoonItem.HitPoints > 0)
+ harpoonItem.HitPoints--;
+
+ if (harpoonItem.HitPoints == 0)
{
- harpoonItem.HitPoints--;
- }
- else
- {
- ExplodeItemNode(&harpoonItem, 0, 0, BODY_EXPLODE);
+ ExplodeItemNode(&harpoonItem, 0, 0, BODY_DO_EXPLOSION);
KillItem(itemNumber);
}
return;
}
- harpoonItem.Pose.Orientation.z += ANGLE(35.0f);
-
- if (!TestEnvironment(ENV_FLAG_WATER, harpoonItem.RoomNumber))
+ if (TestEnvironment(ENV_FLAG_WATER, &harpoonItem))
{
- harpoonItem.Pose.Orientation.x -= ANGLE(1.0f);
+ if (harpoonItem.Animation.Velocity.z > 64.0f)
+ harpoonItem.Animation.Velocity.z -= harpoonItem.Animation.Velocity.z / 16;
- if (harpoonItem.Pose.Orientation.x < ANGLE(-90.0f))
- harpoonItem.Pose.Orientation.x = ANGLE(-90.0f);
-
- harpoonItem.Animation.Velocity.y = -HARPOON_VELOCITY * phd_sin(harpoonItem.Pose.Orientation.x);
- harpoonItem.Animation.Velocity.z = HARPOON_VELOCITY * phd_cos(harpoonItem.Pose.Orientation.x);
- }
- else
- {
- if (Wibble & 4)
- SpawnBubble(harpoonItem.Pose.Position.ToVector3(), harpoonItem.RoomNumber, (int)BubbleFlags::HighAmplitude);
-
- harpoonItem.Animation.Velocity.y = -HARPOON_VELOCITY * phd_sin(harpoonItem.Pose.Orientation.x) / 2;
- harpoonItem.Animation.Velocity.z = HARPOON_VELOCITY * phd_cos(harpoonItem.Pose.Orientation.x) / 2;
+ if (GlobalCounter & 1)
+ SpawnBubble(harpoonItem.Pose.Position.ToVector3(), harpoonItem.RoomNumber);
}
+ auto prevPos = harpoonItem.Pose.Position;
TranslateItem(&harpoonItem, harpoonItem.Pose.Orientation, harpoonItem.Animation.Velocity.z);
- HandleProjectile(harpoonItem, *LaraItem, harpoonItem.Pose.Position, ProjectileType::Harpoon, Weapons[(int)LaraWeaponType::HarpoonGun].Damage);
+
+ int damage = Weapons[(int)LaraWeaponType::HarpoonGun].Damage;
+ HandleProjectile(harpoonItem, *LaraItem, prevPos, (ProjectileType)harpoonItem.ItemFlags[0], damage);
}
void FireGrenade(ItemInfo& laraItem)
@@ -983,7 +991,7 @@ void RocketControl(short itemNumber)
HandleProjectile(rocketItem, *LaraItem, prevPos, ProjectileType::Explosive, Weapons[(int)LaraWeaponType::RocketLauncher].ExplosiveDamage);
}
-void FireCrossbow(ItemInfo& laraItem, Pose* pos)
+void FireCrossbow(ItemInfo& laraItem, const std::optional& pose)
{
auto& player = *GetLaraInfo(&laraItem);
auto& ammo = GetAmmo(player, LaraWeaponType::Crossbow);
@@ -1004,14 +1012,14 @@ void FireCrossbow(ItemInfo& laraItem, Pose* pos)
if (!ammo.HasInfinite())
ammo--;
- if (pos)
+ if (pose.has_value())
{
- boltItem.Pose.Position = pos->Position;
+ boltItem.Pose.Position = pose->Position;
boltItem.RoomNumber = laraItem.RoomNumber;
InitializeItem(itemNumber);
- boltItem.Pose.Orientation = pos->Orientation;
+ boltItem.Pose.Orientation = pose->Orientation;
}
else
{
@@ -1040,8 +1048,8 @@ void FireCrossbow(ItemInfo& laraItem, Pose* pos)
}
}
- boltItem.Animation.Velocity.z = 512.0f;
- boltItem.HitPoints = HARPOON_TIME;
+ boltItem.Animation.Velocity.z = BOLT_VELOCITY;
+ boltItem.HitPoints = BOLT_TIME;
AddActiveItem(itemNumber);
@@ -1074,7 +1082,7 @@ void FireCrossBowFromLaserSight(ItemInfo& laraItem, GameVector* origin, GameVect
{
auto orient = Geometry::GetOrientToPoint(origin->ToVector3(), target->ToVector3());
auto boltPose = Pose(origin->x, origin->y, origin->z, orient);
- FireCrossbow(laraItem, &boltPose);
+ FireCrossbow(laraItem, boltPose);
}
void CrossbowBoltControl(short itemNumber)
@@ -1412,18 +1420,31 @@ bool EmitFromProjectile(ItemInfo& projectile, ProjectileType type)
bool TestProjectileNewRoom(ItemInfo& item, const CollisionResult& coll)
{
- // Has projectile changed room?
+ // Check if projectile changed room.
if (item.RoomNumber == coll.RoomNumber)
return false;
- // If currently in water and previously on land, add a ripple.
+ // If currently in water and previously on land, spawn ripple.
if (TestEnvironment(ENV_FLAG_WATER, item.RoomNumber) != TestEnvironment(ENV_FLAG_WATER, coll.RoomNumber))
{
+ const auto& player = GetLaraInfo(item);
+
int floorDiff = abs(coll.Position.Floor - item.Pose.Position.y);
int ceilingDiff = abs(coll.Position.Ceiling - item.Pose.Position.y);
int yPoint = (floorDiff > ceilingDiff) ? coll.Position.Ceiling : coll.Position.Floor;
- SpawnRipple(Vector3(item.Pose.Position.x, yPoint, item.Pose.Position.z), item.RoomNumber, Random::GenerateInt(8, 16));
+ if (player.Control.Weapon.GunType != LaraWeaponType::GrenadeLauncher && player.Control.Weapon.GunType != LaraWeaponType::RocketLauncher)
+ {
+ SpawnSplashDrips(
+ Vector3(item.Pose.Position.x, yPoint, item.Pose.Position.z),
+ item.RoomNumber, 3, false);
+
+ SpawnRipple(Vector3(item.Pose.Position.x, yPoint, item.Pose.Position.z), item.RoomNumber, Random::GenerateInt(8, 16));
+ }
+ else
+ {
+ Splash(&item);
+ }
}
ItemNewRoom(item.Index, coll.RoomNumber);
@@ -1458,8 +1479,8 @@ void HandleProjectile(ItemInfo& projectile, ItemInfo& emitter, const Vector3i& p
bool hasHit = false;
bool hasHitNotByEmitter = false;
- bool isExplosive = type >= ProjectileType::Explosive;
- bool isShatterable = type != ProjectileType::Harpoon;
+ bool isExplosive = (type >= ProjectileType::Explosive);
+ bool isShatterable = (type != ProjectileType::Harpoon);
// For non-grenade projectiles, check for room collision.
if (type < ProjectileType::Grenade)
@@ -1467,7 +1488,6 @@ void HandleProjectile(ItemInfo& projectile, ItemInfo& emitter, const Vector3i& p
if (pointColl.Position.Floor < projectile.Pose.Position.y ||
pointColl.Position.Ceiling > projectile.Pose.Position.y)
{
- projectile.Pose.Position = prevPos;
hasHit =
hasHitNotByEmitter = true;
}
@@ -1620,18 +1640,16 @@ void HandleProjectile(ItemInfo& projectile, ItemInfo& emitter, const Vector3i& p
DoDamage(itemPtr, damage);
}
}
-
}
else if (itemPtr->ObjectNumber >= ID_SMASH_OBJECT1 &&
itemPtr->ObjectNumber <= ID_SMASH_OBJECT8)
{
doShatter = hasHit = true;
- // Smash objects are legacy objects from TRC. Let's make them explode in the legacy way.
+ // Smash objects are legacy objects from TRC. Make them explode in legacy way.
ExplodeItemNode(itemPtr, 0, 0, 128);
- short currentItemNumber = (itemPtr - CollidedItems[0]);
- SmashObject(currentItemNumber);
- KillItem(currentItemNumber);
+ SmashObject(itemPtr->Index);
+ KillItem(itemPtr->Index);
}
}
@@ -1651,7 +1669,7 @@ void HandleProjectile(ItemInfo& projectile, ItemInfo& emitter, const Vector3i& p
}
else if (doShatter)
{
- ExplodeItemNode(&projectile, 0, 0, BODY_EXPLODE);
+ ExplodeItemNode(&projectile, 0, 0, BODY_DO_EXPLOSION);
}
switch (type)
diff --git a/TombEngine/Game/Lara/lara_one_gun.h b/TombEngine/Game/Lara/lara_one_gun.h
index 003bac6e6..382d76567 100644
--- a/TombEngine/Game/Lara/lara_one_gun.h
+++ b/TombEngine/Game/Lara/lara_one_gun.h
@@ -1,9 +1,9 @@
#pragma once
+#include "Math/Math.h"
+
+using namespace TEN::Math;
enum class LaraWeaponType;
-class GameVector;
-class Pose;
-class Vector3i;
struct ItemInfo;
enum class GrenadeType
@@ -34,13 +34,13 @@ void UndrawShotgun(ItemInfo& laraItem, LaraWeaponType weaponType);
void DrawShotgunMeshes(ItemInfo& laraItem, LaraWeaponType weaponType);
void UndrawShotgunMeshes(ItemInfo& laraItem, LaraWeaponType weaponType);
-ItemInfo* FireHarpoon(ItemInfo& laraItem);
+bool FireHarpoon(ItemInfo& laraItem, const std::optional& pose = std::nullopt);
void HarpoonBoltControl(short itemNumber);
void FireGrenade(ItemInfo& laraItem);
void GrenadeControl(short itemNumber);
void FireRocket(ItemInfo& laraItem);
void RocketControl(short itemNumber);
-void FireCrossbow(ItemInfo& laraItem, Pose* pos);
+void FireCrossbow(ItemInfo& laraItem, const std::optional& pose = std::nullopt);
void FireCrossBowFromLaserSight(ItemInfo& laraItem, GameVector* origin, GameVector* target);
void CrossbowBoltControl(short itemNumber);
diff --git a/TombEngine/Game/Lara/lara_overhang.cpp b/TombEngine/Game/Lara/lara_overhang.cpp
index e62d84b4e..d30eac91e 100644
--- a/TombEngine/Game/Lara/lara_overhang.cpp
+++ b/TombEngine/Game/Lara/lara_overhang.cpp
@@ -361,7 +361,7 @@ void lara_col_slopeclimb(ItemInfo* item, CollisionInfo* coll)
if (GetClimbFlags(probeUp.BottomBlock) & slopeData.ClimbOrient &&
InStrip(item->Pose.Position.x, item->Pose.Position.z, item->Pose.Orientation.y, CLICK(3), CLICK(4)))
{
- if (GetCollision(probeUp.Block, up.x, up.y, up.z).Position.Ceiling - item->Pose.Position.y <= (SECTOR(1.5f) - 80)) // Check if a wall is actually there.
+ if (GetCollision(probeUp.Block, up.x, up.y, up.z).Position.Ceiling - item->Pose.Position.y <= (BLOCK(1.5f) - 80)) // Check if a wall is actually there.
{
AlignToEdge(item, FORWARD_ALIGNMENT);
SetAnimation(item, LA_OVERHANG_SLOPE_LADDER_CONVEX_START);
@@ -451,7 +451,7 @@ void lara_as_slopeclimb(ItemInfo* item, CollisionInfo* coll)
return;
Camera.targetElevation = -ANGLE(16.75f);
- Camera.targetDistance = SECTOR(1.75f);
+ Camera.targetDistance = BLOCK(1.75f);
Camera.speed = 15;
}
@@ -470,7 +470,7 @@ void lara_as_slopefall(ItemInfo* item, CollisionInfo* coll)
return;
Camera.targetElevation = -ANGLE(16.75f);
- Camera.targetDistance = SECTOR(1.75f);
+ Camera.targetDistance = BLOCK(1.75f);
Camera.speed = 15;
}
@@ -547,7 +547,7 @@ void lara_as_slopehang(ItemInfo* item, CollisionInfo* coll)
if (Camera.type != CameraType::Chase)
return;
- Camera.targetElevation = -SECTOR(1);
+ Camera.targetElevation = -BLOCK(1);
Camera.targetDistance = CLICK(6.5f);
Camera.speed = 15;
}
@@ -604,7 +604,7 @@ void lara_as_slopeshimmy(ItemInfo* item, CollisionInfo* coll)
if (Camera.type != CameraType::Chase)
return;
- Camera.targetElevation = -SECTOR(1);
+ Camera.targetElevation = -BLOCK(1);
Camera.targetDistance = CLICK(6.5f);
Camera.speed = 15;
@@ -634,7 +634,7 @@ void lara_as_slopeclimbup(ItemInfo* item, CollisionInfo* coll)
if (Camera.type != CameraType::Chase)
return; // If camera mode isn't chase (0) then don't change camera angles.
- Camera.targetElevation = SECTOR(2);
+ Camera.targetElevation = BLOCK(2);
Camera.targetDistance = CLICK(7);
Camera.speed = 15;
@@ -697,12 +697,12 @@ void lara_as_sclimbstart(ItemInfo* item, CollisionInfo* coll)
Camera.flags = CF_FOLLOW_CENTER;
- int distance = TestLaraWall(item, 0, SECTOR(1.5f), 0) ? SECTOR(1) : CLICK(6.5f);
+ int distance = TestLaraWall(item, 0, BLOCK(1.5f)) ? BLOCK(1) : CLICK(6.5f);
if (item->Animation.FrameNumber < GetAnimData(item).frameEnd)
{
Camera.targetDistance = distance;
- Camera.targetElevation = int(SECTOR(3) * frac);
+ Camera.targetElevation = int(BLOCK(3) * frac);
Camera.targetAngle = int(-ANGLE(180.0f) * frac);
Camera.targetspeed = 15;
}
@@ -710,7 +710,7 @@ void lara_as_sclimbstart(ItemInfo* item, CollisionInfo* coll)
{
Camera.targetDistance = distance;
- Camera.targetElevation = SECTOR(3);
+ Camera.targetElevation = BLOCK(3);
Camera.targetAngle = 0;
Camera.targetspeed = 15;
}
@@ -757,13 +757,13 @@ void lara_as_sclimbstop(ItemInfo* item, CollisionInfo* coll)
{
Camera.targetAngle = (short)(-ANGLE(90.0f) * frac);
- Camera.targetDistance = SECTOR(1.75f) - int(CLICK(2) * frac);
+ Camera.targetDistance = BLOCK(1.75f) - int(CLICK(2) * frac);
Camera.targetspeed = 15;
}
else
{
Camera.targetAngle = ANGLE(90.0f);
- Camera.targetDistance = SECTOR(1.25f);
+ Camera.targetDistance = BLOCK(1.25f);
Camera.targetspeed = 15;
}
}
diff --git a/TombEngine/Game/Lara/lara_slide.cpp b/TombEngine/Game/Lara/lara_slide.cpp
index cd92300bc..878023427 100644
--- a/TombEngine/Game/Lara/lara_slide.cpp
+++ b/TombEngine/Game/Lara/lara_slide.cpp
@@ -66,7 +66,7 @@ void lara_as_slide_forward(ItemInfo* item, CollisionInfo* coll)
else
ApproachLaraTargetOrientation(item, direction);*/
- if (TrInput & IN_JUMP && TestLaraSlideJump(item, coll))
+ if (IsHeld(In::Jump) && TestLaraSlideJump(item, coll))
{
item->Animation.TargetState = LS_JUMP_FORWARD;
StopSoundEffect(SFX_TR4_LARA_SLIPPING);
@@ -175,7 +175,7 @@ void lara_as_slide_back(ItemInfo* item, CollisionInfo* coll)
else
ApproachLaraTargetOrientation(item, direction);*/
- if (TrInput & IN_JUMP && TestLaraSlideJump(item, coll))
+ if (IsHeld(In::Jump) && TestLaraSlideJump(item, coll))
{
item->Animation.TargetState = LS_JUMP_BACK;
StopSoundEffect(SFX_TR4_LARA_SLIPPING);
diff --git a/TombEngine/Game/Lara/lara_struct.h b/TombEngine/Game/Lara/lara_struct.h
index 773fd9102..3cfb03399 100644
--- a/TombEngine/Game/Lara/lara_struct.h
+++ b/TombEngine/Game/Lara/lara_struct.h
@@ -1280,7 +1280,7 @@ struct PlayerContextData
int ProjectedFloorHeight = 0;
float CalcJumpVelocity = 0;
Pose NextCornerPos = Pose::Zero;
- EulerAngles TargetOrientation = EulerAngles::Zero;
+ EulerAngles TargetOrientation = EulerAngles::Zero; // TargetOrient
int WaterSurfaceDist = 0;
short WaterCurrentActive = 0; // Sink number? Often used as bool.
@@ -1300,8 +1300,6 @@ struct LaraInfo
{
static constexpr auto TARGET_COUNT_MAX = 8;
- int ItemNumber = 0; // TODO: Remove. No longer necessary since ItemInfo already has it. -- Sezz 2023.04.09
-
LaraControlData Control = {};
PlayerContextData Context = {};
PlayerStatusData Status = {};
@@ -1319,13 +1317,12 @@ struct LaraInfo
ArmInfo RightArm = {};
ItemInfo* TargetEntity = nullptr; // TargetEntityPtr. Should use item number instead?
- std::array TargetList = {};
- std::array LastTargets = {};
+ std::array TargetList = {};
+ std::array LastTargets = {};
// TODO: Rewrite and restore spasm effect. Also move to PlayerEffectData?
- int HitFrame = 0; // Frame index.
- int HitDirection = 0; // Cardinal direction.
- FX_INFO* SpasmEffect = nullptr; // Not saved.
+ int HitFrame = 0; // Frame index.
+ int HitDirection = 0; // Cardinal direction.
int ExtraAnim = 0; // Item number? Only ever set to NO_ITEM or 1.
diff --git a/TombEngine/Game/Lara/lara_surface.cpp b/TombEngine/Game/Lara/lara_surface.cpp
index ad3404a93..b22e81b92 100644
--- a/TombEngine/Game/Lara/lara_surface.cpp
+++ b/TombEngine/Game/Lara/lara_surface.cpp
@@ -60,7 +60,7 @@ void lara_as_surface_idle(ItemInfo* item, CollisionInfo* coll)
if (TrInput & (IN_LEFT | IN_RIGHT))
ModulateLaraTurnRateY(item, LARA_TURN_RATE_ACCEL * 1.25f, 0, LARA_MED_TURN_RATE_MAX);
- if (DbInput & IN_JUMP)
+ if (IsClicked(In::Jump))
{
SetLaraSwimDiveAnimation(item);
return;
@@ -125,7 +125,7 @@ void lara_as_surface_swim_forward(ItemInfo* item, CollisionInfo* coll)
if (!(TrInput & IN_FORWARD))
item->Animation.TargetState = LS_ONWATER_IDLE;
- if (DbInput & IN_JUMP)
+ if (IsClicked(In::Jump))
SetLaraSwimDiveAnimation(item);
item->Animation.Velocity.y += LARA_SWIM_VELOCITY_ACCEL;
@@ -167,7 +167,7 @@ void lara_as_surface_swim_left(ItemInfo* item, CollisionInfo* coll)
if (!(TrInput & IN_LSTEP || (TrInput & IN_WALK && TrInput & IN_LEFT)))
item->Animation.TargetState = LS_ONWATER_IDLE;
- if (DbInput & IN_JUMP)
+ if (IsClicked(In::Jump))
SetLaraSwimDiveAnimation(item);
item->Animation.Velocity.y += LARA_SWIM_VELOCITY_ACCEL;
@@ -206,7 +206,7 @@ void lara_as_surface_swim_right(ItemInfo* item, CollisionInfo* coll)
if (!(TrInput & IN_RSTEP || (TrInput & IN_WALK && TrInput & IN_RIGHT)))
item->Animation.TargetState = LS_ONWATER_IDLE;
- if (DbInput & IN_JUMP)
+ if (IsClicked(In::Jump))
SetLaraSwimDiveAnimation(item);
item->Animation.Velocity.y += LARA_SWIM_VELOCITY_ACCEL;
@@ -239,7 +239,7 @@ void lara_as_surface_swim_back(ItemInfo* item, CollisionInfo* coll)
if (TrInput & (IN_LEFT | IN_RIGHT))
ModulateLaraTurnRateY(item, LARA_TURN_RATE_ACCEL * 1.25f, 0, LARA_SLOW_MED_TURN_RATE_MAX);
- if (DbInput & IN_JUMP)
+ if (IsClicked(In::Jump))
SetLaraSwimDiveAnimation(item);
if (!(TrInput & IN_BACK))
diff --git a/TombEngine/Game/Lara/lara_swim.cpp b/TombEngine/Game/Lara/lara_swim.cpp
index 0bdf94215..6af906db7 100644
--- a/TombEngine/Game/Lara/lara_swim.cpp
+++ b/TombEngine/Game/Lara/lara_swim.cpp
@@ -51,7 +51,7 @@ void lara_as_underwater_idle(ItemInfo* item, CollisionInfo* coll)
else
ModulateLaraSwimTurnRates(item, coll);
- if (TrInput & IN_JUMP)
+ if (IsHeld(In::Jump))
item->Animation.TargetState = LS_UNDERWATER_SWIM_FORWARD;
item->Animation.Velocity.y -= LARA_SWIM_VELOCITY_DECEL;
@@ -96,7 +96,7 @@ void lara_as_underwater_swim_forward(ItemInfo* item, CollisionInfo* coll)
if (item->Animation.Velocity.y > LARA_SWIM_VELOCITY_MAX)
item->Animation.Velocity.y = LARA_SWIM_VELOCITY_MAX;
- if (!(TrInput & IN_JUMP))
+ if (!(IsHeld(In::Jump)))
item->Animation.TargetState = LS_UNDERWATER_INERTIA;
}
@@ -130,7 +130,7 @@ void lara_as_underwater_inertia(ItemInfo* item, CollisionInfo* coll)
else
ModulateLaraSubsuitSwimTurnRates(item);
- if (TrInput & IN_JUMP)
+ if (IsHeld(In::Jump))
item->Animation.TargetState = LS_UNDERWATER_SWIM_FORWARD;
item->Animation.Velocity.y -= LARA_SWIM_VELOCITY_DECEL;
diff --git a/TombEngine/Game/Lara/lara_tests.cpp b/TombEngine/Game/Lara/lara_tests.cpp
index acc0effee..e75075589 100644
--- a/TombEngine/Game/Lara/lara_tests.cpp
+++ b/TombEngine/Game/Lara/lara_tests.cpp
@@ -53,8 +53,8 @@ bool TestValidLedge(ItemInfo* item, CollisionInfo* coll, bool ignoreHeadroom, bo
if (frontLeft.Position.Ceiling > (item->Pose.Position.y - coll->Setup.Height) || frontRight.Position.Ceiling > (item->Pose.Position.y - coll->Setup.Height))
return false;
- //g_Renderer.AddDebugSphere(Vector3(item->pos.Position.x + xl, left, item->pos.Position.z + zl), 64, Vector4::One, RENDERER_DEBUG_PAGE::LARA_STATS);
- //g_Renderer.AddDebugSphere(Vector3(item->pos.Position.x + xr, right, item->pos.Position.z + zr), 64, Vector4::One, RENDERER_DEBUG_PAGE::LARA_STATS);
+ //g_Renderer.AddDebugSphere(Vector3(item->pos.Position.x + xl, left, item->pos.Position.z + zl), 64, Vector4::One, RendererDebugPage::CollisionStats);
+ //g_Renderer.AddDebugSphere(Vector3(item->pos.Position.x + xr, right, item->pos.Position.z + zr), 64, Vector4::One, RendererDebugPage::CollisionStats);
// Determine ledge probe embed offset.
// We use 0.2f radius extents here for two purposes. First - we can't guarantee that shifts weren't already applied
@@ -71,7 +71,7 @@ bool TestValidLedge(ItemInfo* item, CollisionInfo* coll, bool ignoreHeadroom, bo
return false;
// Determine allowed slope difference for a given collision radius
- auto slopeDelta = ((float)STEPUP_HEIGHT / (float)SECTOR(1)) * (coll->Setup.Radius * 2);
+ auto slopeDelta = ((float)STEPUP_HEIGHT / (float)BLOCK(1)) * (coll->Setup.Radius * 2);
// Discard if there is a slope beyond tolerance delta
if (abs(left - right) >= slopeDelta)
@@ -773,24 +773,16 @@ bool TestLaraHangSideways(ItemInfo* item, CollisionInfo* coll, short angle)
return !res;
}
-bool TestLaraWall(ItemInfo* item, int distance, int height, int side)
+bool TestLaraWall(ItemInfo* item, float dist, float height)
{
- float s = phd_sin(item->Pose.Orientation.y);
- float c = phd_cos(item->Pose.Orientation.y);
-
- auto start = GameVector(
- item->Pose.Position.x + (side * c),
- item->Pose.Position.y + height,
- item->Pose.Position.z + (-side * s),
+ auto origin = GameVector(
+ Geometry::TranslatePoint(item->Pose.Position, item->Pose.Orientation.y, 0.0f, height),
+ item->RoomNumber);
+ auto target = GameVector(
+ Geometry::TranslatePoint(item->Pose.Position, item->Pose.Orientation.y, dist, height),
item->RoomNumber);
- auto end = GameVector(
- item->Pose.Position.x + (distance * s) + (side * c),
- item->Pose.Position.y + height,
- item->Pose.Position.z + (distance * c) + (-side * s),
- item->RoomNumber);
-
- return !LOS(&start, &end);
+ return !LOS(&origin, &target);
}
bool TestLaraFacingCorner(ItemInfo* item, short angle, int distance)
@@ -1046,11 +1038,11 @@ bool TestLaraLadderClimbOut(ItemInfo* item, CollisionInfo* coll) // NEW function
break;
case SOUTH:
- item->Pose.Position.z = (item->Pose.Position.z & -SECTOR(1)) + LARA_RADIUS + 1;
+ item->Pose.Position.z = (item->Pose.Position.z & -BLOCK(1)) + LARA_RADIUS + 1;
break;
case WEST:
- item->Pose.Position.x = (item->Pose.Position.x & -SECTOR(1)) + LARA_RADIUS + 1;
+ item->Pose.Position.x = (item->Pose.Position.x & -BLOCK(1)) + LARA_RADIUS + 1;
break;
}
@@ -1202,11 +1194,11 @@ bool TestLaraPose(ItemInfo* item, CollisionInfo* coll)
if (TestEnvironment(ENV_FLAG_SWAMP, item))
return false;
- if (!(TrInput & (IN_FLARE | IN_DRAW)) && // Avoid unsightly concurrent actions.
+ if (!IsHeld(In::Draw) && !IsHeld(In::Flare) && // Avoid unsightly concurrent actions.
lara->Control.HandStatus == HandStatus::Free && // Hands are free.
(lara->Control.Weapon.GunType != LaraWeaponType::Flare || // Flare is not being handled.
lara->Flare.Life) &&
- lara->Context.Vehicle == NO_ITEM) // Not in a vehicle.
+ lara->Context.Vehicle == NO_ITEM) // Not in a vehicle.
{
return true;
}
@@ -1638,7 +1630,7 @@ bool TestLaraCrouchRoll(ItemInfo* item, CollisionInfo* coll)
// Assess continuity of path.
int distance = 0;
auto probeA = GetCollision(item);
- while (distance < SECTOR(1))
+ while (distance < BLOCK(1))
{
distance += CLICK(1);
auto probeB = GetCollision(item, item->Pose.Orientation.y, distance, -LARA_HEIGHT_CRAWL);
@@ -1673,7 +1665,7 @@ bool TestLaraCrouchToCrawl(ItemInfo* item)
{
auto* lara = GetLaraInfo(item);
- if (!(TrInput & (IN_FLARE | IN_DRAW)) && // Avoid unsightly concurrent actions.
+ if (!IsHeld(In::Draw) && !IsHeld(In::Flare) && // Avoid unsightly concurrent actions.
lara->Control.HandStatus == HandStatus::Free && // Hands are free.
(lara->Control.Weapon.GunType != LaraWeaponType::Flare || // Not handling flare. TODO: Should be allowed, but the flare animation bugs out right now. @Sezz 2022.03.18
lara->Flare.Life))
@@ -2292,7 +2284,7 @@ CrawlVaultTestResult TestLaraCrawlExitJump(ItemInfo* item, CollisionInfo* coll)
CrawlVaultTestResult TestLaraCrawlVault(ItemInfo* item, CollisionInfo* coll)
{
- if (!(TrInput & (IN_ACTION | IN_JUMP)))
+ if (!(IsHeld(In::Action) || IsHeld(In::Jump)))
return CrawlVaultTestResult{ false };
// Crawl vault exit down 1 step.
@@ -2538,7 +2530,7 @@ bool TestLaraPoleCollision(ItemInfo* item, CollisionInfo* coll, bool goingUp, fl
bool atLeastOnePoleCollided = false;
- if (GetCollidedObjects(item, SECTOR(1), true, CollidedItems, nullptr, false) &&
+ if (GetCollidedObjects(item, BLOCK(1), true, CollidedItems, nullptr, false) &&
CollidedItems[0] != nullptr)
{
auto laraBox = GameBoundingBox(item).ToBoundingOrientedBox(item->Pose);
@@ -2555,7 +2547,7 @@ bool TestLaraPoleCollision(ItemInfo* item, CollisionInfo* coll, bool goingUp, fl
auto sphere = BoundingSphere(spherePos, poleProbeCollRadius);
auto offsetSphere = BoundingSphere(spherePos + sphereOffset2D, poleProbeCollRadius);
- //g_Renderer.AddDebugSphere(sphere.Center, 16.0f, Vector4(1, 0, 0, 1), RENDERER_DEBUG_PAGE::LARA_STATS);
+ //g_Renderer.AddDebugSphere(sphere.Center, 16.0f, Vector4(1, 0, 0, 1), RendererDebugPage::CollisionStats);
int i = 0;
while (CollidedItems[i] != nullptr)
@@ -2569,7 +2561,7 @@ bool TestLaraPoleCollision(ItemInfo* item, CollisionInfo* coll, bool goingUp, fl
auto poleBox = GameBoundingBox(object).ToBoundingOrientedBox(object->Pose);
poleBox.Extents = poleBox.Extents + Vector3(coll->Setup.Radius, 0.0f, coll->Setup.Radius);
- //g_Renderer.AddDebugBox(poleBox, Vector4(0, 0, 1, 1), RENDERER_DEBUG_PAGE::LARA_STATS);
+ //g_Renderer.AddDebugBox(poleBox, Vector4(0, 0, 1, 1), RendererDebugPage::CollisionStats);
if (poleBox.Intersects(sphere) || poleBox.Intersects(offsetSphere))
{
diff --git a/TombEngine/Game/Lara/lara_tests.h b/TombEngine/Game/Lara/lara_tests.h
index e6f83ba30..72bd7d42c 100644
--- a/TombEngine/Game/Lara/lara_tests.h
+++ b/TombEngine/Game/Lara/lara_tests.h
@@ -29,7 +29,7 @@ CornerTestResult TestItemAtNextCornerPosition(ItemInfo* item, CollisionInfo* col
bool TestHangSwingIn(ItemInfo* item, CollisionInfo* coll);
bool TestLaraHangSideways(ItemInfo* item, CollisionInfo* coll, short angle);
-bool TestLaraWall(ItemInfo* item, int distance, int height, int side = 0);
+bool TestLaraWall(ItemInfo* item, float dist, float height);
bool TestLaraFacingCorner(ItemInfo* item, short angle, int distance);
bool LaraPositionOnLOS(ItemInfo* item, short angle, int distance);
int LaraFloorFront(ItemInfo* item, short angle, int distance);
diff --git a/TombEngine/Game/Setup.cpp b/TombEngine/Game/Setup.cpp
index 5e259fd78..7cc80311f 100644
--- a/TombEngine/Game/Setup.cpp
+++ b/TombEngine/Game/Setup.cpp
@@ -31,8 +31,9 @@ using namespace TEN::Effects::Hair;
using namespace TEN::Entities;
using namespace TEN::Entities::Switches;
-ObjectInfo Objects[ID_NUMBER_OBJECTS];
-STATIC_INFO StaticObjects[MAX_STATICS];
+ObjectHandler Objects;
+StaticInfo StaticObjects[MAX_STATICS];
+
void InitializeGameFlags()
{
@@ -49,7 +50,6 @@ void InitializeSpecialEffects()
memset(&FireSparks, 0, MAX_SPARKS_FIRE * sizeof(FIRE_SPARKS));
memset(&SmokeSparks, 0, MAX_SPARKS_SMOKE * sizeof(SMOKE_SPARKS));
memset(&Gunshells, 0, MAX_GUNSHELL * sizeof(GUNSHELL_STRUCT));
- memset(&Gunflashes, 0, (MAX_GUNFLASH * sizeof(GUNFLASH_STRUCT)));
memset(&Blood, 0, MAX_SPARKS_BLOOD * sizeof(BLOOD_STRUCT));
memset(&Splashes, 0, MAX_SPLASHES * sizeof(SPLASH_STRUCT));
memset(&ShockWaves, 0, MAX_SHOCKWAVE * sizeof(SHOCKWAVE_STRUCT));
diff --git a/TombEngine/Game/Setup.h b/TombEngine/Game/Setup.h
index 19c69e7da..1441ee2b1 100644
--- a/TombEngine/Game/Setup.h
+++ b/TombEngine/Game/Setup.h
@@ -142,7 +142,58 @@ struct ObjectInfo
}
};
-struct STATIC_INFO
+class ObjectHandler
+{
+ private:
+ ObjectInfo Objects[ID_NUMBER_OBJECTS];
+
+ ObjectInfo& GetFirstAvailableObject()
+ {
+ for (int i = 0; i < ID_NUMBER_OBJECTS; i++)
+ {
+ if (Objects[i].loaded)
+ return Objects[i];
+ }
+
+ return Objects[0];
+ }
+
+ public:
+ void Initialize()
+ {
+ std::memset(Objects, 0, sizeof(ObjectInfo) * GAME_OBJECT_ID::ID_NUMBER_OBJECTS);
+ }
+
+ bool CheckID(int index, bool isSilent = false)
+ {
+ if (index == GAME_OBJECT_ID::ID_NO_OBJECT || index >= GAME_OBJECT_ID::ID_NUMBER_OBJECTS)
+ {
+ if (!isSilent)
+ {
+ TENLog("Attempted to access unavailable slot ID (" + std::to_string(index) + "). " +
+ "Check if last accessed item exists in level.", LogLevel::Warning, LogConfig::Debug);
+ }
+
+ return false;
+ }
+
+ return true;
+ }
+
+ ObjectInfo& operator[](int index)
+ {
+ if (CheckID(index))
+ {
+ return Objects[index];
+ }
+ else
+ {
+ return GetFirstAvailableObject();
+ }
+ }
+};
+
+struct StaticInfo
{
int meshNumber;
int flags;
@@ -158,8 +209,8 @@ constexpr auto SF_SHATTERABLE = 0x02;
constexpr auto GRAVITY = 6.0f;
constexpr auto SWAMP_GRAVITY = GRAVITY / 3.0f;
-extern ObjectInfo Objects[ID_NUMBER_OBJECTS];
-extern STATIC_INFO StaticObjects[MAX_STATICS];
+extern ObjectHandler Objects;
+extern StaticInfo StaticObjects[MAX_STATICS];
void InitializeGameFlags();
void InitializeSpecialEffects();
diff --git a/TombEngine/Game/animation.cpp b/TombEngine/Game/animation.cpp
index 3b211ec2b..fe107924a 100644
--- a/TombEngine/Game/animation.cpp
+++ b/TombEngine/Game/animation.cpp
@@ -234,6 +234,9 @@ void AnimateItem(ItemInfo* item)
unsigned int frameCount = GetNonZeroFrameCount(*animPtr);
int currentFrame = item->Animation.FrameNumber - animPtr->frameBase;
+ auto animAccel = (animPtr->VelocityEnd - animPtr->VelocityStart) / frameCount;
+ auto animVel = animPtr->VelocityStart + (animAccel * currentFrame);
+
if (item->Animation.IsAirborne)
{
if (item->IsLara())
@@ -258,7 +261,7 @@ void AnimateItem(ItemInfo* item)
else
{
item->Animation.Velocity.y += (item->Animation.Velocity.y >= 128.0f) ? 1.0f : GRAVITY;
- item->Animation.Velocity.z += (animPtr->VelocityEnd.z - animPtr->VelocityStart.z) / frameCount;
+ item->Animation.Velocity.z += animAccel.z;
item->Pose.Position.y += item->Animation.Velocity.y;
}
@@ -273,25 +276,23 @@ void AnimateItem(ItemInfo* item)
{
if (item->IsLara())
{
- const auto& player = *GetLaraInfo(item);
+ const auto& player = GetLaraInfo(*item);
- if (player.Control.WaterStatus == WaterStatus::Wade && TestEnvironment(ENV_FLAG_SWAMP, item))
- item->Animation.Velocity.z = (animPtr->VelocityStart.z / 2) + ((((animPtr->VelocityEnd.z - animPtr->VelocityStart.z) / frameCount) * currentFrame) / 4);
- else
- item->Animation.Velocity.z = animPtr->VelocityStart.z + (((animPtr->VelocityEnd.z - animPtr->VelocityStart.z) / frameCount) * currentFrame);
+ bool isInSwamp = (player.Control.WaterStatus == WaterStatus::Wade && TestEnvironment(ENV_FLAG_SWAMP, item));
+ item->Animation.Velocity.z = isInSwamp ? (animVel.z / 2) : animVel.z;
}
else
{
- item->Animation.Velocity.x = animPtr->VelocityStart.x + (((animPtr->VelocityEnd.x - animPtr->VelocityStart.x) / frameCount) * currentFrame);
- item->Animation.Velocity.z = animPtr->VelocityStart.z + (((animPtr->VelocityEnd.z - animPtr->VelocityStart.z) / frameCount) * currentFrame);
+ item->Animation.Velocity.x = animVel.x;
+ item->Animation.Velocity.z = animVel.z;
}
}
if (item->IsLara())
{
- const auto& player = *GetLaraInfo(item);
+ const auto& player = GetLaraInfo(*item);
- item->Animation.Velocity.x = animPtr->VelocityStart.x + (((animPtr->VelocityEnd.x - animPtr->VelocityStart.x) / frameCount) * currentFrame);
+ item->Animation.Velocity.x = animVel.x;
if (player.Control.Rope.Ptr != -1)
DelAlignLaraToRope(item);
diff --git a/TombEngine/Game/camera.cpp b/TombEngine/Game/camera.cpp
index 9eb457a52..2111bd118 100644
--- a/TombEngine/Game/camera.cpp
+++ b/TombEngine/Game/camera.cpp
@@ -26,9 +26,9 @@ using namespace TEN::Effects::Environment;
using namespace TEN::Entities::Generic;
using namespace TEN::Input;
-constexpr auto PARTICLE_FADE_THRESHOLD = SECTOR(14);
-constexpr auto COLL_CHECK_THRESHOLD = SECTOR(4);
-constexpr auto COLL_CANCEL_THRESHOLD = SECTOR(2);
+constexpr auto PARTICLE_FADE_THRESHOLD = BLOCK(14);
+constexpr auto COLL_CHECK_THRESHOLD = BLOCK(4);
+constexpr auto COLL_CANCEL_THRESHOLD = BLOCK(2);
constexpr auto COLL_DISCARD_THRESHOLD = CLICK(0.5f);
constexpr auto CAMERA_RADIUS = CLICK(1);
@@ -93,7 +93,7 @@ void LookAt(CAMERA_INFO* cam, short roll)
float fov = TO_RAD(CurrentFOV / 1.333333f);
float r = TO_RAD(roll);
- float levelFarView = g_GameFlow->GetLevel(CurrentLevel)->GetFarView() * float(SECTOR(1));
+ float levelFarView = g_GameFlow->GetLevel(CurrentLevel)->GetFarView() * float(BLOCK(1));
g_Renderer.UpdateCameraMatrices(cam, r, fov, levelFarView);
}
@@ -119,7 +119,7 @@ inline void RumbleFromBounce()
void InitializeCamera()
{
- Camera.shift = LaraItem->Pose.Position.y - SECTOR(1);
+ Camera.shift = LaraItem->Pose.Position.y - BLOCK(1);
LastTarget.x = LaraItem->Pose.Position.x;
LastTarget.y = Camera.shift;
@@ -136,7 +136,7 @@ void InitializeCamera()
Camera.pos.z = LastTarget.z - 100;
Camera.pos.RoomNumber = LaraItem->RoomNumber;
- Camera.targetDistance = SECTOR(1.5f);
+ Camera.targetDistance = BLOCK(1.5f);
Camera.item = NULL;
Camera.numberFrames = 1;
Camera.type = CameraType::Chase;
@@ -218,7 +218,7 @@ void MoveCamera(GameVector* ideal, int speed)
if (Camera.bounce <= 0)
{
int bounce = -Camera.bounce;
- int bounce2 = -Camera.bounce >> 2;
+ int bounce2 = bounce / 2;
Camera.target.x += GetRandomControl() % bounce - bounce2;
Camera.target.y += GetRandomControl() % bounce - bounce2;
Camera.target.z += GetRandomControl() % bounce - bounce2;
@@ -243,9 +243,9 @@ void MoveCamera(GameVector* ideal, int speed)
{
LOSAndReturnTarget(&Camera.target, &Camera.pos, 0);
- if (abs(Camera.pos.x - ideal->x) < SECTOR(0.5f) &&
- abs(Camera.pos.y - ideal->y) < SECTOR(0.5f) &&
- abs(Camera.pos.z - ideal->z) < SECTOR(0.5f))
+ if (abs(Camera.pos.x - ideal->x) < BLOCK(0.5f) &&
+ abs(Camera.pos.y - ideal->y) < BLOCK(0.5f) &&
+ abs(Camera.pos.z - ideal->z) < BLOCK(0.5f))
{
to.x = Camera.pos.x;
to.y = Camera.pos.y;
@@ -538,7 +538,7 @@ void ChaseCamera(ItemInfo* item)
void DoThumbstickCamera()
{
- if (!g_Configuration.EnableThumbstickCameraControl)
+ if (!g_Configuration.EnableThumbstickCamera)
return;
if (Camera.laraNode == -1 && (Camera.target.x == OldCam.target.x &&
@@ -560,7 +560,7 @@ void UpdateCameraElevation()
if (Camera.laraNode != -1)
{
auto pos = GetJointPosition(LaraItem, Camera.laraNode, Vector3i::Zero);
- auto pos1 = GetJointPosition(LaraItem, Camera.laraNode, Vector3i(0, -CLICK(1), SECTOR(2)));
+ auto pos1 = GetJointPosition(LaraItem, Camera.laraNode, Vector3i(0, -CLICK(1), BLOCK(2)));
pos = pos1 - pos;
Camera.actualAngle = Camera.targetAngle + phd_atan(pos.z, pos.x);
}
@@ -637,7 +637,7 @@ void CombatCamera(ItemInfo* item)
UpdateCameraElevation();
- Camera.targetDistance = SECTOR(1.5f);
+ Camera.targetDistance = BLOCK(1.5f);
int distance = Camera.targetDistance * phd_cos(Camera.actualElevation);
for (int i = 0; i < 5; i++)
@@ -955,7 +955,7 @@ void LookCamera(ItemInfo* item)
}
}
- auto pos2 = GetJointPosition(item, LM_HEAD, Vector3i(0, 0, -SECTOR(1)));
+ auto pos2 = GetJointPosition(item, LM_HEAD, Vector3i(0, 0, -BLOCK(1)));
auto pos3 = GetJointPosition(item, LM_HEAD, Vector3i(0, 0, CLICK(8)));
int dx = (pos2.x - pos.x) >> 3;
@@ -1171,7 +1171,7 @@ void BinocularCamera(ItemInfo* item)
if (!LaserSight)
{
if (IsClicked(In::Deselect) ||
- IsClicked(In::DrawWeapon) ||
+ IsClicked(In::Draw) ||
IsClicked(In::Look) ||
IsHeld(In::Flare))
{
@@ -1216,10 +1216,10 @@ void BinocularCamera(ItemInfo* item)
Camera.pos.z = z;
Camera.pos.RoomNumber = probe.RoomNumber;
- int l = SECTOR(20.25f) * phd_cos(headXRot);
+ int l = BLOCK(20.25f) * phd_cos(headXRot);
int tx = x + l * phd_sin(item->Pose.Orientation.y + headYRot);
- int ty = y - SECTOR(20.25f) * phd_sin(headXRot);
+ int ty = y - BLOCK(20.25f) * phd_sin(headXRot);
int tz = z + l * phd_cos(item->Pose.Orientation.y + headYRot);
if (Camera.oldType == CameraType::Fixed)
@@ -1289,7 +1289,10 @@ void BinocularCamera(ItemInfo* item)
void ConfirmCameraTargetPos()
{
- auto pos = GetJointPosition(LaraItem, LM_TORSO);
+ auto pos = Vector3i(
+ LaraItem->Pose.Position.x,
+ LaraItem->Pose.Position.y - (LaraCollision.Setup.Height / 2),
+ LaraItem->Pose.Position.z);
if (Camera.laraNode != -1)
{
@@ -1529,7 +1532,7 @@ void CalculateCamera()
Camera.item = NULL;
Camera.targetElevation = 0;
Camera.targetAngle = 0;
- Camera.targetDistance = SECTOR(1.5f);
+ Camera.targetDistance = BLOCK(1.5f);
Camera.flags = 0;
Camera.laraNode = -1;
}
@@ -1847,8 +1850,9 @@ void ItemsCollideCamera()
if (TestBoundsCollideCamera(bounds, item->Pose, CAMERA_RADIUS))
ItemPushCamera(&bounds, &item->Pose, rad);
- TEN::Renderer::g_Renderer.AddDebugBox(bounds.ToBoundingOrientedBox(item->Pose),
- Vector4(1.0f, 0.0f, 0.0f, 1.0f), RENDERER_DEBUG_PAGE::LARA_STATS);
+ TEN::Renderer::g_Renderer.AddDebugBox(
+ bounds.ToBoundingOrientedBox(item->Pose),
+ Vector4(1.0f, 0.0f, 0.0f, 1.0f), RendererDebugPage::CollisionStats);
}
itemList.clear(); // Done
@@ -1874,8 +1878,9 @@ void ItemsCollideCamera()
if (TestBoundsCollideCamera(bounds, mesh->pos, CAMERA_RADIUS))
ItemPushCamera(&bounds, &mesh->pos, rad);
- TEN::Renderer::g_Renderer.AddDebugBox(bounds.ToBoundingOrientedBox(mesh->pos),
- Vector4(1.0f, 0.0f, 0.0f, 1.0f), RENDERER_DEBUG_PAGE::LARA_STATS);
+ TEN::Renderer::g_Renderer.AddDebugBox(
+ bounds.ToBoundingOrientedBox(mesh->pos),
+ Vector4(1.0f, 0.0f, 0.0f, 1.0f), RendererDebugPage::CollisionStats);
}
staticList.clear(); // Done
@@ -1896,7 +1901,7 @@ void UpdateMikePos(ItemInfo* item)
}
else
{
- int phdPerspective = g_Configuration.Width / 2 * phd_cos(CurrentFOV / 2) / phd_sin(CurrentFOV / 2);
+ int phdPerspective = g_Configuration.ScreenWidth / 2 * phd_cos(CurrentFOV / 2) / phd_sin(CurrentFOV / 2);
Camera.actualAngle = phd_atan(Camera.target.z - Camera.pos.z, Camera.target.x - Camera.pos.x);
Camera.mikePos.x = Camera.pos.x + phdPerspective * phd_sin(Camera.actualAngle);
diff --git a/TombEngine/Game/collision/collide_item.cpp b/TombEngine/Game/collision/collide_item.cpp
index 57354027e..d870b14cc 100644
--- a/TombEngine/Game/collision/collide_item.cpp
+++ b/TombEngine/Game/collision/collide_item.cpp
@@ -312,19 +312,18 @@ void TestForObjectOnLedge(ItemInfo* item, CollisionInfo* coll)
auto origin = Vector3(
item->Pose.Position.x + (sinHeading * (coll->Setup.Radius)),
item->Pose.Position.y - (height + CLICK(1)),
- item->Pose.Position.z + (cosHeading * (coll->Setup.Radius))
- );
+ item->Pose.Position.z + (cosHeading * (coll->Setup.Radius)));
auto mxR = Matrix::CreateFromYawPitchRoll(TO_RAD(coll->Setup.ForwardAngle), 0.0f, 0.0f);
auto direction = (Matrix::CreateTranslation(Vector3::UnitZ) * mxR).Translation();
- // g_Renderer.AddDebugSphere(origin, 16, Vector4::One, RENDERER_DEBUG_PAGE::DIMENSION_STATS);
+ // g_Renderer.AddDebugSphere(origin, 16, Vector4::One, RendererDebugPage::CollisionStats);
for (auto i : g_Level.Rooms[item->RoomNumber].neighbors)
{
if (!g_Level.Rooms[i].Active())
continue;
- short itemNumber = g_Level.Rooms[i].itemNumber;
+ int itemNumber = g_Level.Rooms[i].itemNumber;
while (itemNumber != NO_ITEM)
{
auto* item2 = &g_Level.Items[itemNumber];
@@ -979,7 +978,7 @@ bool CollideSolidBounds(ItemInfo* item, const GameBoundingBox& box, const Pose&
itemBounds.Extents = itemBounds.Extents - Vector3(BLOCK(1));
// Draw static bounds.
- g_Renderer.AddDebugBox(staticBounds, Vector4(1, 0.3f, 0, 1), RENDERER_DEBUG_PAGE::DIMENSION_STATS);
+ g_Renderer.AddDebugBox(staticBounds, Vector4(1, 0.3f, 0, 1), RendererDebugPage::CollisionStats);
// Calculate horizontal item collision bounds according to radius.
GameBoundingBox collBox;
@@ -1010,7 +1009,7 @@ bool CollideSolidBounds(ItemInfo* item, const GameBoundingBox& box, const Pose&
bool prevHorIntersects = staticBounds.Intersects(prevCollBounds);
// Draw item coll bounds.
- g_Renderer.AddDebugBox(collBounds, intersects ? Vector4(1, 0, 0, 1) : Vector4(0, 1, 0, 1), RENDERER_DEBUG_PAGE::DIMENSION_STATS);
+ g_Renderer.AddDebugBox(collBounds, intersects ? Vector4(1, 0, 0, 1) : Vector4(0, 1, 0, 1), RendererDebugPage::CollisionStats);
// Decompose static bounds into top/bottom plane vertices.
Vector3 corners[8];
@@ -1990,17 +1989,19 @@ void CreatureCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll
}
}
-void TrapCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll)
+void TrapCollision(short itemNumber, ItemInfo* playerItem, CollisionInfo* coll)
{
- auto* item = &g_Level.Items[itemNumber];
+ auto& item = g_Level.Items[itemNumber];
- if (item->Status == ITEM_ACTIVE)
+ if (item.Status == ITEM_ACTIVE)
{
- if (!TestBoundsCollide(item, laraItem, coll->Setup.Radius))
+ if (!TestBoundsCollide(&item, playerItem, coll->Setup.Radius))
return;
- TestCollision(item, laraItem);
+ TestCollision(&item, playerItem);
+ }
+ else if (item.Status != ITEM_INVISIBLE)
+ {
+ ObjectCollision(itemNumber, playerItem, coll);
}
- else if (item->Status != ITEM_INVISIBLE)
- ObjectCollision(itemNumber, laraItem, coll);
}
diff --git a/TombEngine/Game/collision/collide_item.h b/TombEngine/Game/collision/collide_item.h
index c7e93cc6b..7d74906e3 100644
--- a/TombEngine/Game/collision/collide_item.h
+++ b/TombEngine/Game/collision/collide_item.h
@@ -8,7 +8,7 @@ struct ItemInfo;
struct MESH_INFO;
constexpr auto MAX_COLLIDED_OBJECTS = 1024;
-constexpr auto ITEM_RADIUS_YMAX = SECTOR(3);
+constexpr auto ITEM_RADIUS_YMAX = BLOCK(3);
constexpr auto VEHICLE_COLLISION_TERMINAL_VELOCITY = 30.0f;
diff --git a/TombEngine/Game/collision/collide_room.cpp b/TombEngine/Game/collision/collide_room.cpp
index 39befcdf5..48b40a662 100644
--- a/TombEngine/Game/collision/collide_room.cpp
+++ b/TombEngine/Game/collision/collide_room.cpp
@@ -74,13 +74,13 @@ void SnapItemToGrid(ItemInfo* item, CollisionInfo* coll)
int FindGridShift(int x, int z)
{
- if ((x / SECTOR(1)) == (z / SECTOR(1)))
+ if ((x / BLOCK(1)) == (z / BLOCK(1)))
return 0;
- if ((z / SECTOR(1)) <= (x / SECTOR(1)))
+ if ((z / BLOCK(1)) <= (x / BLOCK(1)))
return (-1 - (x & WALL_MASK));
else
- return ((SECTOR(1) + 1) - (x & WALL_MASK));
+ return ((BLOCK(1) + 1) - (x & WALL_MASK));
}
// Test if the axis-aligned bounding box collides with geometry at all.
@@ -114,18 +114,24 @@ bool TestItemRoomCollisionAABB(ItemInfo* item)
return collided;
}
-// Overload used to quickly get point/room collision parameters at a given item's position.
-CollisionResult GetCollision(ItemInfo* item)
+// Overload used to quickly get point collision parameters at a given item's position.
+CollisionResult GetCollision(const ItemInfo& item)
{
- auto newRoomNumber = item->RoomNumber;
- auto floor = GetFloor(item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z, &newRoomNumber);
- auto probe = GetCollision(floor, item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z);
+ auto newRoomNumber = item.RoomNumber;
+ auto floor = GetFloor(item.Pose.Position.x, item.Pose.Position.y, item.Pose.Position.z, &newRoomNumber);
+ auto probe = GetCollision(floor, item.Pose.Position.x, item.Pose.Position.y, item.Pose.Position.z);
probe.RoomNumber = newRoomNumber;
return probe;
}
-// Overload used to probe point/room collision parameters from a given item's position.
+// Deprecated.
+CollisionResult GetCollision(ItemInfo* item)
+{
+ return GetCollision(*item);
+}
+
+// Overload used to probe point collision parameters from a given item's position.
CollisionResult GetCollision(ItemInfo* item, short headingAngle, float forward, float down, float right)
{
short tempRoomNumber = item->RoomNumber;
@@ -140,8 +146,8 @@ CollisionResult GetCollision(ItemInfo* item, short headingAngle, float forward,
return GetCollision(point.x, point.y, point.z, adjacentRoomNumber);
}
-// Overload used to probe point/room collision parameters from a given position.
-CollisionResult GetCollision(Vector3i pos, int roomNumber, short headingAngle, float forward, float down, float right)
+// Overload used to probe point collision parameters from a given position.
+CollisionResult GetCollision(const Vector3i& pos, int roomNumber, short headingAngle, float forward, float down, float right)
{
short tempRoomNumber = roomNumber;
auto location = ROOM_VECTOR{ GetFloor(pos.x, pos.y, pos.z, &tempRoomNumber)->Room, pos.y };
@@ -151,11 +157,17 @@ CollisionResult GetCollision(Vector3i pos, int roomNumber, short headingAngle, f
return GetCollision(point.x, point.y, point.z, adjacentRoomNumber);
}
-// Overload used as a universal wrapper across collisional code to replace
-// triads of roomNumber-GetFloor()-GetFloorHeight() operations.
-// The advantage is that it does NOT modify the incoming roomNumber argument,
-// instead storing one modified by GetFloor() within the returned CollisionResult struct.
+// Overload used as universal wrapper across collisional code replacing
+// triads of roomNumber-GetFloor()-GetFloorHeight() calls.
+// Advantage is that it does NOT modify incoming roomNumber argument,
+// instead storing one modified by GetFloor() within a returned CollisionResult struct.
// This way, no external variables are modified as output arguments.
+CollisionResult GetCollision(const Vector3i& pos, int roomNumber)
+{
+ return GetCollision(pos.x, pos.y, pos.z, roomNumber);
+}
+
+// Deprecated.
CollisionResult GetCollision(int x, int y, int z, short roomNumber)
{
auto room = roomNumber;
@@ -166,9 +178,10 @@ CollisionResult GetCollision(int x, int y, int z, short roomNumber)
return result;
}
-CollisionResult GetCollision(const GameVector& point)
+// NOTE: To be used only when absolutely necessary.
+CollisionResult GetCollision(const GameVector& pos)
{
- return GetCollision(point.x, point.y, point.z, point.RoomNumber);
+ return GetCollision(pos.x, pos.y, pos.z, pos.RoomNumber);
}
// A reworked legacy GetFloorHeight() function which writes data
@@ -218,10 +231,52 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, bool resetRoom)
GetCollisionInfo(coll, item, Vector3i::Zero, resetRoom);
}
-void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offset, bool resetRoom)
+static void SetSectorAttribs(CollisionPosition& sectorAttribs, const CollisionSetup& collSetup, const CollisionResult& pointColl,
+ const Vector3i& probePos, int realRoomNumber)
{
constexpr auto ASPECT_ANGLE_DELTA_MAX = ANGLE(90.0f);
+ auto floorNormal = GetSurfaceNormal(pointColl.FloorTilt, true);
+ short aspectAngle = Geometry::GetSurfaceAspectAngle(floorNormal);
+ short aspectAngleDelta = Geometry::GetShortestAngle(collSetup.ForwardAngle, aspectAngle);
+
+ if (collSetup.BlockFloorSlopeUp &&
+ sectorAttribs.FloorSlope &&
+ sectorAttribs.Floor <= STEPUP_HEIGHT &&
+ sectorAttribs.Floor >= -STEPUP_HEIGHT &&
+ abs(aspectAngleDelta) >= ASPECT_ANGLE_DELTA_MAX)
+ {
+ sectorAttribs.Floor = MAX_HEIGHT;
+ }
+ else if (collSetup.BlockFloorSlopeDown &&
+ sectorAttribs.FloorSlope &&
+ sectorAttribs.Floor <= STEPUP_HEIGHT &&
+ sectorAttribs.Floor >= -STEPUP_HEIGHT &&
+ abs(aspectAngleDelta) <= ASPECT_ANGLE_DELTA_MAX)
+ {
+ sectorAttribs.Floor = MAX_HEIGHT;
+ }
+ else if (collSetup.BlockCeilingSlope &&
+ sectorAttribs.CeilingSlope)
+ {
+ sectorAttribs.Floor = MAX_HEIGHT;
+ }
+ else if (collSetup.BlockDeathFloorDown &&
+ sectorAttribs.Floor >= CLICK(0.5f) &&
+ pointColl.BottomBlock->Flags.Death)
+ {
+ sectorAttribs.Floor = MAX_HEIGHT;
+ }
+ else if (collSetup.BlockMonkeySwingEdge)
+ {
+ auto monkeyPointColl = GetCollision(probePos.x, probePos.y + collSetup.Height, probePos.z, realRoomNumber);
+ if (!monkeyPointColl.BottomBlock->Flags.Monkeyswing)
+ sectorAttribs.Floor = MAX_HEIGHT;
+ }
+}
+
+void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offset, bool resetRoom)
+{
// Player collision has several more precise checks for bridge collisions.
// Therefore, we should differentiate these code paths.
bool doPlayerCollision = item->IsLara();
@@ -357,7 +412,7 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
probePos.x = entityPos.x + xFront;
probePos.z = entityPos.z + zFront;
- g_Renderer.AddDebugSphere(probePos.ToVector3(), 32, Vector4(1, 0, 0, 1), RENDERER_DEBUG_PAGE::LARA_STATS);
+ g_Renderer.AddDebugSphere(probePos.ToVector3(), 32, Vector4(1, 0, 0, 1), RendererDebugPage::CollisionStats);
collResult = GetCollision(probePos.x, probePos.y, probePos.z, topRoomNumber);
@@ -405,46 +460,14 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
if (height != NO_HEIGHT)
height -= (doPlayerCollision ? entityPos.y : probePos.y);
- auto floorNormal = GetSurfaceNormal(collResult.FloorTilt, true);
- short aspectAngle = Geometry::GetSurfaceAspectAngle(floorNormal);
- short aspectAngleDelta = Geometry::GetShortestAngle(coll->Setup.ForwardAngle, aspectAngle);
-
- if (coll->Setup.BlockFloorSlopeUp &&
- coll->Front.FloorSlope &&
- abs(aspectAngleDelta) >= ASPECT_ANGLE_DELTA_MAX)
- {
- coll->Front.Floor = MAX_HEIGHT;
- }
- else if (coll->Setup.BlockFloorSlopeDown &&
- coll->Front.FloorSlope &&
- abs(aspectAngleDelta) <= ASPECT_ANGLE_DELTA_MAX)
- {
- coll->Front.Floor = STOP_SIZE;
- }
- else if (coll->Setup.BlockCeilingSlope &&
- coll->Front.CeilingSlope)
- {
- coll->Front.Floor = MAX_HEIGHT;
- }
- else if (coll->Setup.BlockDeathFloorDown &&
- coll->Front.Floor >= CLICK(0.5f) &&
- collResult.BottomBlock->Flags.Death)
- {
- coll->Front.Floor = STOP_SIZE;
- }
- else if (coll->Setup.BlockMonkeySwingEdge)
- {
- auto monkeyProbe = GetCollision(probePos.x, probePos.y + coll->Setup.Height, probePos.z, realRoomNumber);
- if (!monkeyProbe.BottomBlock->Flags.Monkeyswing)
- coll->Front.Floor = MAX_HEIGHT;
- }
+ SetSectorAttribs(coll->Front, coll->Setup, collResult, probePos, realRoomNumber);
// TEST 4: MIDDLE-LEFT PROBE
probePos.x = entityPos.x + xLeft;
probePos.z = entityPos.z + zLeft;
- g_Renderer.AddDebugSphere(probePos.ToVector3(), 32, Vector4(0, 0, 1, 1), RENDERER_DEBUG_PAGE::LARA_STATS);
+ g_Renderer.AddDebugSphere(probePos.ToVector3(), 32, Vector4(0, 0, 1, 1), RendererDebugPage::CollisionStats);
collResult = GetCollision(probePos.x, probePos.y, probePos.z, item->RoomNumber);
@@ -472,38 +495,7 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
coll->MiddleLeft.Floor = height;
coll->MiddleLeft.Ceiling = ceiling;
- floorNormal = GetSurfaceNormal(collResult.FloorTilt, true);
- aspectAngle = Geometry::GetSurfaceAspectAngle(floorNormal);
- aspectAngleDelta = Geometry::GetShortestAngle(coll->Setup.ForwardAngle, aspectAngle);
-
- if (coll->Setup.BlockFloorSlopeUp &&
- coll->MiddleLeft.FloorSlope &&
- abs(aspectAngleDelta) >= ASPECT_ANGLE_DELTA_MAX)
- {
- coll->MiddleLeft.Floor = MAX_HEIGHT;
- }
- else if (coll->Setup.BlockFloorSlopeDown &&
- coll->MiddleLeft.FloorSlope &&
- abs(aspectAngleDelta) <= ASPECT_ANGLE_DELTA_MAX)
- {
- coll->MiddleLeft.Floor = STOP_SIZE;
- }
- else if (coll->Setup.BlockCeilingSlope &&
- coll->MiddleLeft.CeilingSlope)
- {
- coll->MiddleLeft.Floor = MAX_HEIGHT;
- }
- else if (coll->Setup.BlockDeathFloorDown &&
- coll->MiddleLeft.Floor >= CLICK(0.5f) &&
- collResult.BottomBlock->Flags.Death)
- {
- coll->MiddleLeft.Floor = STOP_SIZE;
- }
- else if (coll->Setup.BlockMonkeySwingEdge &&
- !GetCollision(probePos.x, probePos.y + coll->Setup.Height, probePos.z, item->RoomNumber).BottomBlock->Flags.Monkeyswing)
- {
- coll->MiddleLeft.Floor = MAX_HEIGHT;
- }
+ SetSectorAttribs(coll->MiddleLeft, coll->Setup, collResult, probePos, realRoomNumber);
// TEST 5: FRONT-LEFT PROBE
@@ -533,45 +525,14 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
coll->FrontLeft.Floor = height;
coll->FrontLeft.Ceiling = ceiling;
- floorNormal = GetSurfaceNormal(collResult.FloorTilt, true);
- aspectAngle = Geometry::GetSurfaceAspectAngle(floorNormal);
- aspectAngleDelta = Geometry::GetShortestAngle(coll->Setup.ForwardAngle, aspectAngle);
-
- if (coll->Setup.BlockFloorSlopeUp &&
- coll->FrontLeft.FloorSlope &&
- abs(aspectAngleDelta) >= ASPECT_ANGLE_DELTA_MAX)
- {
- coll->FrontLeft.Floor = MAX_HEIGHT;
- }
- else if (coll->Setup.BlockFloorSlopeDown &&
- coll->FrontLeft.FloorSlope &&
- abs(aspectAngleDelta) <= ASPECT_ANGLE_DELTA_MAX)
- {
- coll->FrontLeft.Floor = STOP_SIZE;
- }
- else if (coll->Setup.BlockCeilingSlope &&
- coll->FrontLeft.CeilingSlope)
- {
- coll->FrontLeft.Floor = MAX_HEIGHT;
- }
- else if (coll->Setup.BlockDeathFloorDown &&
- coll->FrontLeft.Floor >= CLICK(0.5f) &&
- collResult.BottomBlock->Flags.Death)
- {
- coll->FrontLeft.Floor = STOP_SIZE;
- }
- else if (coll->Setup.BlockMonkeySwingEdge &&
- !GetCollision(probePos.x, probePos.y + coll->Setup.Height, probePos.z, item->RoomNumber).BottomBlock->Flags.Monkeyswing)
- {
- coll->FrontLeft.Floor = MAX_HEIGHT;
- }
+ SetSectorAttribs(coll->FrontLeft, coll->Setup, collResult, probePos, realRoomNumber);
// TEST 6: MIDDLE-RIGHT PROBE
probePos.x = entityPos.x + xRight;
probePos.z = entityPos.z + zRight;
- g_Renderer.AddDebugSphere(probePos.ToVector3(), 32, Vector4(0, 1, 0, 1), RENDERER_DEBUG_PAGE::LARA_STATS);
+ g_Renderer.AddDebugSphere(probePos.ToVector3(), 32, Vector4(0, 1, 0, 1), RendererDebugPage::CollisionStats);
collResult = GetCollision(probePos.x, probePos.y, probePos.z, item->RoomNumber);
@@ -599,38 +560,7 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
coll->MiddleRight.Floor = height;
coll->MiddleRight.Ceiling = ceiling;
- floorNormal = GetSurfaceNormal(collResult.FloorTilt, true);
- aspectAngle = Geometry::GetSurfaceAspectAngle(floorNormal);
- aspectAngleDelta = Geometry::GetShortestAngle(coll->Setup.ForwardAngle, aspectAngle);
-
- if (coll->Setup.BlockFloorSlopeUp &&
- coll->MiddleRight.FloorSlope &&
- abs(aspectAngleDelta) >= ASPECT_ANGLE_DELTA_MAX)
- {
- coll->MiddleRight.Floor = MAX_HEIGHT;
- }
- else if (coll->Setup.BlockFloorSlopeDown &&
- coll->MiddleRight.FloorSlope &&
- abs(aspectAngleDelta) <= ASPECT_ANGLE_DELTA_MAX)
- {
- coll->MiddleRight.Floor = STOP_SIZE;
- }
- else if (coll->Setup.BlockCeilingSlope &&
- coll->MiddleRight.CeilingSlope)
- {
- coll->MiddleRight.Floor = MAX_HEIGHT;
- }
- else if (coll->Setup.BlockDeathFloorDown &&
- coll->MiddleRight.Floor >= CLICK(0.5f) &&
- collResult.BottomBlock->Flags.Death)
- {
- coll->MiddleRight.Floor = STOP_SIZE;
- }
- else if (coll->Setup.BlockMonkeySwingEdge &&
- !GetCollision(probePos.x, probePos.y + coll->Setup.Height, probePos.z, item->RoomNumber).BottomBlock->Flags.Monkeyswing)
- {
- coll->MiddleRight.Floor = MAX_HEIGHT;
- }
+ SetSectorAttribs(coll->MiddleRight, coll->Setup, collResult, probePos, realRoomNumber);
// TEST 7: FRONT-RIGHT PROBE
@@ -660,38 +590,7 @@ void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offse
coll->FrontRight.Floor = height;
coll->FrontRight.Ceiling = ceiling;
- floorNormal = GetSurfaceNormal(collResult.FloorTilt, true);
- aspectAngle = Geometry::GetSurfaceAspectAngle(floorNormal);
- aspectAngleDelta = Geometry::GetShortestAngle(coll->Setup.ForwardAngle, aspectAngle);
-
- if (coll->Setup.BlockFloorSlopeUp &&
- coll->FrontRight.FloorSlope &&
- abs(aspectAngleDelta) >= ASPECT_ANGLE_DELTA_MAX)
- {
- coll->FrontRight.Floor = MAX_HEIGHT;
- }
- else if (coll->Setup.BlockFloorSlopeDown &&
- coll->FrontRight.FloorSlope &&
- abs(aspectAngleDelta) <= ASPECT_ANGLE_DELTA_MAX)
- {
- coll->FrontRight.Floor = STOP_SIZE;
- }
- else if (coll->Setup.BlockCeilingSlope &&
- coll->FrontRight.CeilingSlope)
- {
- coll->FrontRight.Floor = MAX_HEIGHT;
- }
- else if (coll->Setup.BlockDeathFloorDown &&
- coll->FrontRight.Floor >= CLICK(0.5f) &&
- collResult.BottomBlock->Flags.Death)
- {
- coll->FrontRight.Floor = STOP_SIZE;
- }
- else if (coll->Setup.BlockMonkeySwingEdge &&
- !GetCollision(probePos.x, probePos.y + coll->Setup.Height, probePos.z, item->RoomNumber).BottomBlock->Flags.Monkeyswing)
- {
- coll->FrontRight.Floor = MAX_HEIGHT;
- }
+ SetSectorAttribs(coll->FrontRight, coll->Setup, collResult, probePos, realRoomNumber);
// TEST 8: SOLID STATIC MESHES
@@ -979,7 +878,7 @@ short GetNearestLedgeAngle(ItemInfo* item, CollisionInfo* coll, float& distance)
}
// Debug probe point
- // g_Renderer.AddDebugSphere(Vector3(eX, y, eZ), 16, Vector4(1, 1, 0, 1), RENDERER_DEBUG_PAGE::LARA_STATS);
+ // g_Renderer.AddDebugSphere(Vector3(eX, y, eZ), 16, Vector4(1, 1, 0, 1), RendererDebugPage::CollisionStats);
// Determine front floor probe offset.
// It is needed to identify if there is bridge or ceiling split in front.
@@ -1021,7 +920,7 @@ short GetNearestLedgeAngle(ItemInfo* item, CollisionInfo* coll, float& distance)
auto fpZ = eZ + floorProbeOffset * cosForwardAngle;
// Debug probe point.
- // g_Renderer.AddDebugSphere(Vector3(fpX, y, fpZ), 16, Vector4(0, 1, 0, 1), RENDERER_DEBUG_PAGE::LARA_STATS);
+ // g_Renderer.AddDebugSphere(Vector3(fpX, y, fpZ), 16, Vector4(0, 1, 0, 1), RendererDebugPage::CollisionStats);
// Get true room number and block, based on derived height
room = GetRoom(item->Location, fpX, height, fpZ).roomNumber;
@@ -1086,17 +985,17 @@ short GetNearestLedgeAngle(ItemInfo* item, CollisionInfo* coll, float& distance)
auto splitAngle = (useCeilingLedge ? block->CeilingCollision.SplitAngle : block->FloorCollision.SplitAngle);
// Get horizontal block corner coordinates.
- auto fX = floor(eX / SECTOR(1)) * SECTOR(1) - 1;
- auto fZ = floor(eZ / SECTOR(1)) * SECTOR(1) - 1;
- auto cX = fX + SECTOR(1) + 1;
- auto cZ = fZ + SECTOR(1) + 1;
+ auto fX = floor(eX / BLOCK(1)) * BLOCK(1) - 1;
+ auto fZ = floor(eZ / BLOCK(1)) * BLOCK(1) - 1;
+ auto cX = fX + BLOCK(1) + 1;
+ auto cZ = fZ + BLOCK(1) + 1;
// Debug used block
- // g_Renderer.AddDebugSphere(Vector3(round(eX / WALL_SIZE) * WALL_SIZE + 512, y, round(eZ / WALL_SIZE) * WALL_SIZE + 512), 16, Vector4(1, 1, 1, 1), RENDERER_DEBUG_PAGE::LARA_STATS);
+ // g_Renderer.AddDebugSphere(Vector3(round(eX / BLOCK(1)) * BLOCK(1) + BLOCK(0.5f), y, round(eZ / BLOCK(1)) * BLOCK(1) + BLOCK(0.5f)), 16, Vector4::One, RendererDebugPage::CollisionStats);
// Get split angle coordinates.
- auto sX = fX + 1 + SECTOR(0.5f);
- auto sZ = fZ + 1 + SECTOR(0.5f);
+ auto sX = fX + 1 + BLOCK(0.5f);
+ auto sZ = fZ + 1 + BLOCK(0.5f);
auto sShiftX = coll->Setup.Radius * sin(splitAngle);
auto sShiftZ = coll->Setup.Radius * cos(splitAngle);
@@ -1267,7 +1166,7 @@ void AlterFloorHeight(ItemInfo* item, int height)
short roomNumber = item->RoomNumber;
FloorInfo* floor = GetFloor(item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z, &roomNumber);
- FloorInfo* ceiling = GetFloor(item->Pose.Position.x, height + item->Pose.Position.y - SECTOR(1), item->Pose.Position.z, &roomNumber);
+ FloorInfo* ceiling = GetFloor(item->Pose.Position.x, height + item->Pose.Position.y - BLOCK(1), item->Pose.Position.z, &roomNumber);
floor->FloorCollision.Planes[0].z += height;
floor->FloorCollision.Planes[1].z += height;
@@ -1328,8 +1227,8 @@ int GetWaterDepth(int x, int y, int z, short roomNumber)
short roomIndex = NO_ROOM;
do
{
- int zFloor = (z - room->z) / SECTOR(1);
- int xFloor = (x - room->x) / SECTOR(1);
+ int zFloor = (z - room->z) / BLOCK(1);
+ int xFloor = (x - room->x) / BLOCK(1);
if (zFloor <= 0)
{
@@ -1416,8 +1315,8 @@ int GetWaterHeight(int x, int y, int z, short roomNumber)
short adjoiningRoom = NO_ROOM;
do
{
- int xBlock = (x - room->x) / SECTOR(1);
- int zBlock = (z - room->z) / SECTOR(1);
+ int xBlock = (x - room->x) / BLOCK(1);
+ int zBlock = (z - room->z) / BLOCK(1);
if (zBlock <= 0)
{
diff --git a/TombEngine/Game/collision/collide_room.h b/TombEngine/Game/collision/collide_room.h
index 62087bd2a..49a6d350f 100644
--- a/TombEngine/Game/collision/collide_room.h
+++ b/TombEngine/Game/collision/collide_room.h
@@ -11,7 +11,7 @@ enum RoomEnvFlags;
constexpr auto NO_LOWER_BOUND = -NO_HEIGHT; // Used by coll->Setup.LowerFloorBound.
constexpr auto NO_UPPER_BOUND = NO_HEIGHT; // Used by coll->Setup.UpperFloorBound.
-constexpr auto COLLISION_CHECK_DISTANCE = SECTOR(8);
+constexpr auto COLLISION_CHECK_DISTANCE = BLOCK(8);
enum CollisionType
{
@@ -126,11 +126,13 @@ struct CollisionInfo
[[nodiscard]] bool TestItemRoomCollisionAABB(ItemInfo* item);
+CollisionResult GetCollision(const ItemInfo& item);
CollisionResult GetCollision(ItemInfo* item);
CollisionResult GetCollision(ItemInfo* item, short headingAngle, float forward, float down = 0.0f, float right = 0.0f);
-CollisionResult GetCollision(Vector3i pos, int roomNumber, short headingAngle, float forward, float down = 0.0f, float right = 0.0f);
+CollisionResult GetCollision(const Vector3i& pos, int roomNumber, short headingAngle, float forward, float down = 0.0f, float right = 0.0f);
+CollisionResult GetCollision(const Vector3i& pos, int roomNumber);
CollisionResult GetCollision(int x, int y, int z, short roomNumber);
-CollisionResult GetCollision(const GameVector& point);
+CollisionResult GetCollision(const GameVector& pos);
CollisionResult GetCollision(FloorInfo* floor, int x, int y, int z);
void GetCollisionInfo(CollisionInfo* coll, ItemInfo* item, const Vector3i& offset, bool resetRoom = false);
diff --git a/TombEngine/Game/collision/floordata.cpp b/TombEngine/Game/collision/floordata.cpp
index 86b6c2ea1..9d26cda94 100644
--- a/TombEngine/Game/collision/floordata.cpp
+++ b/TombEngine/Game/collision/floordata.cpp
@@ -1,10 +1,12 @@
#include "framework.h"
#include "Game/collision/floordata.h"
+#include "Game/collision/collide_room.h"
#include "Game/items.h"
#include "Game/room.h"
#include "Game/Setup.h"
#include "Math/Math.h"
+#include "Renderer/Renderer11.h"
#include "Specific/level.h"
using namespace TEN::Collision::Floordata;
@@ -750,6 +752,10 @@ namespace TEN::Collision::Floordata
void AddBridge(int itemNumber, int x, int z)
{
const auto& item = g_Level.Items[itemNumber];
+
+ if (!Objects.CheckID(item.ObjectNumber))
+ return;
+
x += item.Pose.Position.x;
z += item.Pose.Position.z;
@@ -788,6 +794,10 @@ namespace TEN::Collision::Floordata
void RemoveBridge(int itemNumber, int x, int z)
{
const auto& item = g_Level.Items[itemNumber];
+
+ if (!Objects.CheckID(item.ObjectNumber))
+ return;
+
x += item.Pose.Position.x;
z += item.Pose.Position.z;
@@ -862,7 +872,12 @@ namespace TEN::Collision::Floordata
void UpdateBridgeItem(int itemNumber, bool forceRemoval)
{
auto item = &g_Level.Items[itemNumber];
- if (!Objects[item->ObjectNumber].loaded) return;
+
+ if (!Objects.CheckID(item->ObjectNumber))
+ return;
+
+ if (!Objects[item->ObjectNumber].loaded)
+ return;
// Force removal if object was killed
if (item->Flags & IFLAG_KILLED)
@@ -924,4 +939,103 @@ namespace TEN::Collision::Floordata
return false;
}
+
+ static void DrawSectorFlagLabel(const Vector3& pos, const std::string& string, const Vector4& color, float verticalOffset)
+ {
+ constexpr auto LABEL_SCALE = 0.8f;
+ constexpr auto HALF_BLOCK = BLOCK(0.5f);
+
+ // Get 2D label position.
+ auto labelPos = pos + Vector3(HALF_BLOCK, 0.0f, HALF_BLOCK);
+ auto labelPos2D = g_Renderer.Get2DPosition(labelPos);
+
+ // Draw label.
+ if (labelPos2D.has_value())
+ {
+ *labelPos2D += Vector2(0.0f, verticalOffset);
+ g_Renderer.AddDebugString(string, *labelPos2D, color, LABEL_SCALE, 0, RendererDebugPage::CollisionStats);
+ }
+ }
+
+ void DrawNearbySectorFlags(const ItemInfo& item)
+ {
+ constexpr auto DRAW_RANGE = BLOCK(3);
+ constexpr auto STRING_SPACING = -20.0f;
+
+ constexpr auto STOPPER_COLOR = Vector4(1.0f, 0.4f, 0.4f, 1.0f);
+ constexpr auto DEATH_COLOR = Vector4(0.4f, 1.0f, 0.4f, 1.0f);
+ constexpr auto MONKEY_SWING_COLOR = Vector4(1.0f, 0.4f, 0.4f, 1.0f);
+ constexpr auto BEETLE_MINECART_RIGHT_COLOR = Vector4(0.4f, 0.4f, 1.0f, 1.0f);
+ constexpr auto ACTIVATOR_MINECART_LEFT_COLOR = Vector4(1.0f, 0.4f, 1.0f, 1.0f);
+ constexpr auto MINECART_STOP_COLOR = Vector4(0.4f, 1.0f, 1.0f, 1.0f);
+
+ // Only check sectors in player vicinity.
+ const auto& room = g_Level.Rooms[item.RoomNumber];
+ int minX = std::max(item.Pose.Position.x - DRAW_RANGE, room.x) / BLOCK(1);
+ int maxX = std::min(item.Pose.Position.x + DRAW_RANGE, room.x + (room.xSize * BLOCK(1))) / BLOCK(1);
+ int minZ = std::max(item.Pose.Position.z - DRAW_RANGE, room.z) / BLOCK(1);
+ int maxZ = std::min(item.Pose.Position.z + DRAW_RANGE, room.z + (room.zSize * BLOCK(1))) / BLOCK(1);
+
+ auto pointColl = GetCollision(item);
+ auto pos = item.Pose.Position.ToVector3();
+
+ // Draw sector flag labels.
+ for (int x = minX; x < maxX; x++)
+ {
+ for (int z = minZ; z < maxZ; z++)
+ {
+ pos.x = BLOCK(x);
+ pos.z = BLOCK(z);
+
+ pointColl = GetCollision(pos, item.RoomNumber);
+ pos.y = pointColl.Position.Floor;
+
+ float verticalOffset = STRING_SPACING;
+
+ // Stopper
+ if (pointColl.Block->Stopper)
+ {
+ DrawSectorFlagLabel(pos, "Stopper", STOPPER_COLOR, verticalOffset);
+ verticalOffset += STRING_SPACING;
+ }
+
+ // Death
+ if (pointColl.Block->Flags.Death)
+ {
+ DrawSectorFlagLabel(pos, "Death", DEATH_COLOR, verticalOffset);
+ verticalOffset += STRING_SPACING;
+ }
+
+ // Monkey Swing
+ if (pointColl.Block->Flags.Monkeyswing)
+ {
+ DrawSectorFlagLabel(pos, "Monkey Swing", MONKEY_SWING_COLOR, verticalOffset);
+ verticalOffset += STRING_SPACING;
+ }
+
+ // Beetle / Minecart Right
+ if (pointColl.Block->Flags.MarkBeetle)
+ {
+ auto labelString = std::string("Beetle") + (!pointColl.Block->Flags.MinecartStop() ? " / Minecart Right" : "");
+ DrawSectorFlagLabel(pos, labelString, BEETLE_MINECART_RIGHT_COLOR, verticalOffset);
+ verticalOffset += STRING_SPACING;
+ }
+
+ // Activator / Minecart Left
+ if (pointColl.Block->Flags.MarkTriggerer)
+ {
+ auto labelString = std::string("Activator") + (!pointColl.Block->Flags.MinecartStop() ? " / Minecart Left" : "");
+ DrawSectorFlagLabel(pos, labelString, ACTIVATOR_MINECART_LEFT_COLOR, verticalOffset);
+ verticalOffset += STRING_SPACING;
+ }
+
+ // Minecart Stop
+ if (pointColl.Block->Flags.MinecartStop())
+ {
+ DrawSectorFlagLabel(pos, "Minecart Stop", MINECART_STOP_COLOR, verticalOffset);
+ verticalOffset += STRING_SPACING;
+ }
+ }
+ }
+ }
}
diff --git a/TombEngine/Game/collision/floordata.h b/TombEngine/Game/collision/floordata.h
index 59cc4be66..0692dbaaf 100644
--- a/TombEngine/Game/collision/floordata.h
+++ b/TombEngine/Game/collision/floordata.h
@@ -189,4 +189,6 @@ namespace TEN::Collision::Floordata
void UpdateBridgeItem(int itemNumber, bool forceRemoval = false);
bool TestMaterial(MaterialType refMaterial, const std::vector& materialList);
+
+ void DrawNearbySectorFlags(const ItemInfo& item);
}
diff --git a/TombEngine/Game/collision/sphere.cpp b/TombEngine/Game/collision/sphere.cpp
index 0c4026b2f..6db6de0d4 100644
--- a/TombEngine/Game/collision/sphere.cpp
+++ b/TombEngine/Game/collision/sphere.cpp
@@ -19,9 +19,7 @@ int GetSpheres(ItemInfo* item, SPHERE* ptr, int worldSpace, Matrix local)
return 0;
BoundingSphere spheres[MAX_SPHERES];
- short itemNumber = (item - g_Level.Items.data());
-
- int num = g_Renderer.GetSpheres(itemNumber, spheres, worldSpace, local);
+ int num = g_Renderer.GetSpheres(item->Index, spheres, worldSpace, local);
for (int i = 0; i < MAX_SPHERES; i++)
{
diff --git a/TombEngine/Game/control/box.cpp b/TombEngine/Game/control/box.cpp
index c58e0f070..37b44690d 100644
--- a/TombEngine/Game/control/box.cpp
+++ b/TombEngine/Game/control/box.cpp
@@ -24,10 +24,10 @@
using namespace TEN::Effects::Smoke;
-constexpr auto ESCAPE_DIST = SECTOR(5);
-constexpr auto STALK_DIST = SECTOR(3);
+constexpr auto ESCAPE_DIST = BLOCK(5);
+constexpr auto STALK_DIST = BLOCK(3);
constexpr auto REACHED_GOAL_RADIUS = 640;
-constexpr auto ATTACK_RANGE = SQUARE(SECTOR(3));
+constexpr auto ATTACK_RANGE = SQUARE(BLOCK(3));
constexpr auto ESCAPE_CHANCE = 0x800;
constexpr auto RECOVER_CHANCE = 0x100;
constexpr auto BIFF_AVOID_TURN = ANGLE(11.25f);
@@ -59,14 +59,14 @@ void DrawBox(int boxIndex, Vector3 color)
float z = ((float)currBox.top + (float)(currBox.bottom - currBox.top) / 2.0f) * 1024.0f;
auto center = Vector3(z, y, x);
- auto corner = Vector3(currBox.bottom * SECTOR(1), currBox.height + CLICK(1), currBox.right * SECTOR(1));
+ auto corner = Vector3(currBox.bottom * BLOCK(1), currBox.height + CLICK(1), currBox.right * BLOCK(1));
auto extents = (corner - center) * 0.9f;
auto dBox = BoundingOrientedBox(center, extents, Vector4::UnitY);
for (int i = 0; i <= 10; i++)
{
dBox.Extents = extents + Vector3(i);
- TEN::Renderer::g_Renderer.AddDebugBox(dBox, Vector4(color.x, color.y, color.z, 1), RENDERER_DEBUG_PAGE::LOGIC_STATS);
+ TEN::Renderer::g_Renderer.AddDebugBox(dBox, Vector4(color.x, color.y, color.z, 1), RendererDebugPage::PathfindingStats);
}
}
@@ -75,11 +75,16 @@ void DrawNearbyPathfinding(int boxIndex)
if (boxIndex == NO_BOX)
return;
- DrawBox(boxIndex, Vector3(0, 1, 1));
-
auto& currBox = g_Level.Boxes[boxIndex];
auto index = currBox.overlapIndex;
+ // Grey flag box.
+ auto currentBoxColor = Vector3(0.0f, 1.0f, 1.0f);
+ if (currBox.flags & BLOCKABLE)
+ currentBoxColor = (currBox.flags & BLOCKED) ? Vector3(1.0f, 0.0f, 0.0f) : Vector3(0.0f, 1.0f, 0.0f);
+
+ DrawBox(boxIndex, currentBoxColor);
+
while (true)
{
if (index >= g_Level.Overlaps.size())
@@ -287,10 +292,10 @@ bool CreaturePathfind(ItemInfo* item, Vector3i prevPos, short angle, short tilt)
boxHeight - height > LOT->Step ||
boxHeight - height < LOT->Drop))
{
- xPos = item->Pose.Position.x / SECTOR(1);
- zPos = item->Pose.Position.z / SECTOR(1);
- shiftX = prevPos.x / SECTOR(1);
- shiftZ = prevPos.z / SECTOR(1);
+ xPos = item->Pose.Position.x / BLOCK(1);
+ zPos = item->Pose.Position.z / BLOCK(1);
+ shiftX = prevPos.x / BLOCK(1);
+ shiftZ = prevPos.z / BLOCK(1);
if (xPos < shiftX)
item->Pose.Position.x = prevPos.x & (~WALL_MASK);
@@ -346,23 +351,23 @@ bool CreaturePathfind(ItemInfo* item, Vector3i prevPos, short angle, short tilt)
shiftX = radius - xPos;
}
}
- else if (xPos > SECTOR(1) - radius)
+ else if (xPos > BLOCK(1) - radius)
{
if (BadFloor(x + radius, y, z, height, nextHeight, roomNumber, LOT))
- shiftX = SECTOR(1) - radius - xPos;
+ shiftX = BLOCK(1) - radius - xPos;
else if (!shiftZ && BadFloor(x + radius, y, z - radius, height, nextHeight, roomNumber, LOT))
{
if (item->Pose.Orientation.y > -ANGLE(45.0f) && item->Pose.Orientation.y < ANGLE(135.0f))
shiftZ = radius - zPos;
else
- shiftX = SECTOR(1) - radius - xPos;
+ shiftX = BLOCK(1) - radius - xPos;
}
}
}
- else if (zPos > SECTOR(1) - radius)
+ else if (zPos > BLOCK(1) - radius)
{
if (BadFloor(x, y, z + radius, height, nextHeight, roomNumber, LOT))
- shiftZ = SECTOR(1) - radius - zPos;
+ shiftZ = BLOCK(1) - radius - zPos;
if (xPos < radius)
{
@@ -373,19 +378,19 @@ bool CreaturePathfind(ItemInfo* item, Vector3i prevPos, short angle, short tilt)
if (item->Pose.Orientation.y > -ANGLE(45.0f) && item->Pose.Orientation.y < ANGLE(135.0f))
shiftX = radius - xPos;
else
- shiftZ = SECTOR(1) - radius - zPos;
+ shiftZ = BLOCK(1) - radius - zPos;
}
}
- else if (xPos > SECTOR(1) - radius)
+ else if (xPos > BLOCK(1) - radius)
{
if (BadFloor(x + radius, y, z, height, nextHeight, roomNumber, LOT))
- shiftX = SECTOR(1) - radius - xPos;
+ shiftX = BLOCK(1) - radius - xPos;
else if (!shiftZ && BadFloor(x + radius, y, z + radius, height, nextHeight, roomNumber, LOT))
{
if (item->Pose.Orientation.y > -ANGLE(135.0f) && item->Pose.Orientation.y < ANGLE(45.0f))
- shiftX = SECTOR(1) - radius - xPos;
+ shiftX = BLOCK(1) - radius - xPos;
else
- shiftZ = SECTOR(1) - radius - zPos;
+ shiftZ = BLOCK(1) - radius - zPos;
}
}
}
@@ -394,10 +399,10 @@ bool CreaturePathfind(ItemInfo* item, Vector3i prevPos, short angle, short tilt)
if (BadFloor(x - radius, y, z, height, nextHeight, roomNumber, LOT))
shiftX = radius - xPos;
}
- else if (xPos > SECTOR(1) - radius)
+ else if (xPos > BLOCK(1) - radius)
{
if (BadFloor(x + radius, y, z, height, nextHeight, roomNumber, LOT))
- shiftX = SECTOR(1) - radius - xPos;
+ shiftX = BLOCK(1) - radius - xPos;
}
item->Pose.Position.x += shiftX;
@@ -566,7 +571,7 @@ void CreatureKill(ItemInfo* creatureItem, int creatureAnimNumber, int playerAnim
playerItem.Animation.Velocity = Vector3::Zero;
if (creatureItem->RoomNumber != playerItem.RoomNumber)
- ItemNewRoom(player.ItemNumber, creatureItem->RoomNumber);
+ ItemNewRoom(playerItem.Index, creatureItem->RoomNumber);
AnimateItem(&playerItem);
@@ -788,39 +793,53 @@ void CreatureHealth(ItemInfo* item)
}
}
-void CreatureDie(short itemNumber, bool explode)
+void CreatureDie(int itemNumber, bool doExplosion)
{
- auto* item = &g_Level.Items[itemNumber];
- auto* object = &Objects[item->ObjectNumber];
-
- item->HitPoints = NOT_TARGETABLE;
- item->Collidable = false;
-
- if (explode)
+ int flags = 0;
+ if (doExplosion)
{
- switch (object->hitEffect)
+ const auto& item = g_Level.Items[itemNumber];
+ const auto& object = Objects[item.ObjectNumber];
+
+ switch (object.hitEffect)
{
case HitEffect::Blood:
- ExplodingDeath(itemNumber, BODY_EXPLODE | BODY_GIBS);
+ flags |= BODY_DO_EXPLOSION | BODY_GIBS;
break;
case HitEffect::Smoke:
- ExplodingDeath(itemNumber, BODY_EXPLODE | BODY_NO_BOUNCE);
+ flags |= BODY_DO_EXPLOSION | BODY_NO_BOUNCE;
break;
default:
- ExplodingDeath(itemNumber, BODY_EXPLODE);
+ flags |= BODY_DO_EXPLOSION;
break;
}
+ }
+ CreatureDie(itemNumber, doExplosion, flags);
+}
+
+void CreatureDie(int itemNumber, bool doExplosion, int flags)
+{
+ auto& item = g_Level.Items[itemNumber];
+
+ item.HitPoints = NOT_TARGETABLE;
+ item.Collidable = false;
+
+ if (doExplosion)
+ {
+ ExplodingDeath(itemNumber, flags);
KillItem(itemNumber);
}
else
+ {
RemoveActiveItem(itemNumber);
+ }
DisableEntityAI(itemNumber);
- item->Flags |= IFLAG_KILLED | IFLAG_INVISIBLE;
- DropPickups(item);
+ item.Flags |= IFLAG_KILLED | IFLAG_INVISIBLE;
+ DropPickups(&item);
}
bool BadFloor(int x, int y, int z, int boxHeight, int nextHeight, short roomNumber, LOTInfo* LOT)
@@ -938,8 +957,8 @@ void TargetBox(LOTInfo* LOT, int boxNumber)
auto* box = &g_Level.Boxes[boxNumber];
// Maximize target precision. DO NOT change bracket precedence!
- LOT->Target.x = (int)((box->top * SECTOR(1)) + (float)GetRandomControl() * (((float)(box->bottom - box->top) - 1.0f) / 32.0f) + CLICK(2.0f));
- LOT->Target.z = (int)((box->left * SECTOR(1)) + (float)GetRandomControl() * (((float)(box->right - box->left) - 1.0f) / 32.0f) + CLICK(2.0f));
+ LOT->Target.x = (int)((box->top * BLOCK(1)) + (float)GetRandomControl() * (((float)(box->bottom - box->top) - 1.0f) / 32.0f) + CLICK(2.0f));
+ LOT->Target.z = (int)((box->left * BLOCK(1)) + (float)GetRandomControl() * (((float)(box->right - box->left) - 1.0f) / 32.0f) + CLICK(2.0f));
LOT->RequiredBox = boxNumber;
if (LOT->Fly == NO_FLYING)
@@ -1116,10 +1135,10 @@ bool StalkBox(ItemInfo* item, ItemInfo* enemy, int boxNumber)
return false;
auto* box = &g_Level.Boxes[boxNumber];
- int xRange = STALK_DIST + ((box->bottom - box->top) * SECTOR(1));
- int zRange = STALK_DIST + ((box->right - box->left) * SECTOR(1));
- int x = (box->top + box->bottom) * SECTOR(1) / 2 - enemy->Pose.Position.x;
- int z = (box->left + box->right) * SECTOR(1) / 2 - enemy->Pose.Position.z;
+ int xRange = STALK_DIST + ((box->bottom - box->top) * BLOCK(1));
+ int zRange = STALK_DIST + ((box->right - box->left) * BLOCK(1));
+ int x = (box->top + box->bottom) * BLOCK(1) / 2 - enemy->Pose.Position.x;
+ int z = (box->left + box->right) * BLOCK(1) / 2 - enemy->Pose.Position.z;
if (x > xRange || x < -xRange || z > zRange || z < -zRange)
return false;
@@ -1183,8 +1202,8 @@ int CreatureVault(short itemNumber, short angle, int vault, int shift)
auto* item = &g_Level.Items[itemNumber];
auto* creature = GetCreatureInfo(item);
- int xBlock = item->Pose.Position.x / SECTOR(1);
- int zBlock = item->Pose.Position.z / SECTOR(1);
+ int xBlock = item->Pose.Position.x / BLOCK(1);
+ int zBlock = item->Pose.Position.z / BLOCK(1);
int y = item->Pose.Position.y;
short roomNumber = item->RoomNumber;
@@ -1224,8 +1243,8 @@ int CreatureVault(short itemNumber, short angle, int vault, int shift)
}
// Jump
- int newXblock = item->Pose.Position.x / SECTOR(1);
- int newZblock = item->Pose.Position.z / SECTOR(1);
+ int newXblock = item->Pose.Position.x / BLOCK(1);
+ int newZblock = item->Pose.Position.z / BLOCK(1);
if (zBlock == newZblock)
{
@@ -1234,12 +1253,12 @@ int CreatureVault(short itemNumber, short angle, int vault, int shift)
if (xBlock < newXblock)
{
- item->Pose.Position.x = (newXblock * SECTOR(1)) - shift;
+ item->Pose.Position.x = (newXblock * BLOCK(1)) - shift;
item->Pose.Orientation.y = ANGLE(90.0f);
}
else
{
- item->Pose.Position.x = (xBlock * SECTOR(1)) + shift;
+ item->Pose.Position.x = (xBlock * BLOCK(1)) + shift;
item->Pose.Orientation.y = -ANGLE(90.0f);
}
}
@@ -1247,12 +1266,12 @@ int CreatureVault(short itemNumber, short angle, int vault, int shift)
{
if (zBlock < newZblock)
{
- item->Pose.Position.z = (newZblock * SECTOR(1)) - shift;
+ item->Pose.Position.z = (newZblock * BLOCK(1)) - shift;
item->Pose.Orientation.y = 0;
}
else
{
- item->Pose.Position.z = (zBlock * SECTOR(1)) + shift;
+ item->Pose.Position.z = (zBlock * BLOCK(1)) + shift;
item->Pose.Orientation.y = -ANGLE(180.0f);
}
}
@@ -1550,8 +1569,8 @@ void CreatureAIInfo(ItemInfo* item, AI_INFO* AI)
vector.y = item->Pose.Position.y - enemy->Pose.Position.y;
short angle = phd_atan(vector.z, vector.x);
- if (vector.x > SECTOR(31.25f) || vector.x < -SECTOR(31.25f) ||
- vector.z > SECTOR(31.25f) || vector.z < -SECTOR(31.25f))
+ if (vector.x > BLOCK(31.25f) || vector.x < -BLOCK(31.25f) ||
+ vector.z > BLOCK(31.25f) || vector.z < -BLOCK(31.25f))
{
AI->distance = INT_MAX;
AI->verticalDistance = INT_MAX;
@@ -1809,7 +1828,7 @@ void GetCreatureMood(ItemInfo* item, AI_INFO* AI, bool isViolent)
case MoodType::Stalk:
if (creature->Alerted && AI->zoneNumber != AI->enemyZone)
{
- if (AI->distance > SECTOR(3))
+ if (AI->distance > BLOCK(3))
creature->Mood = MoodType::Stalk;
else
creature->Mood = MoodType::Bored;
@@ -1830,7 +1849,7 @@ void GetCreatureMood(ItemInfo* item, AI_INFO* AI, bool isViolent)
(GetRandomControl() < ESCAPE_CHANCE ||
AI->zoneNumber != AI->enemyZone))
creature->Mood = MoodType::Stalk;
- else if (AI->zoneNumber != AI->enemyZone && AI->distance > SECTOR(6))
+ else if (AI->zoneNumber != AI->enemyZone && AI->distance > BLOCK(6))
creature->Mood = MoodType::Bored;
break;
@@ -1872,10 +1891,10 @@ TARGET_TYPE CalculateTarget(Vector3i* target, ItemInfo* item, LOTInfo* LOT)
auto* box = &g_Level.Boxes[boxNumber];
- int boxLeft = ((int)box->left * SECTOR(1));
- int boxRight = ((int)box->right * SECTOR(1)) - 1;
- int boxTop = ((int)box->top * SECTOR(1));
- int boxBottom = ((int)box->bottom * SECTOR(1)) - 1;
+ int boxLeft = ((int)box->left * BLOCK(1));
+ int boxRight = ((int)box->right * BLOCK(1)) - 1;
+ int boxTop = ((int)box->top * BLOCK(1));
+ int boxBottom = ((int)box->bottom * BLOCK(1)) - 1;
int left = boxLeft;
int right = boxRight;
int top = boxTop;
@@ -1888,26 +1907,26 @@ TARGET_TYPE CalculateTarget(Vector3i* target, ItemInfo* item, LOTInfo* LOT)
if (LOT->Fly != NO_FLYING)
{
- if (target->y > box->height - SECTOR(1))
- target->y = box->height - SECTOR(1);
+ if (target->y > box->height - BLOCK(1))
+ target->y = box->height - BLOCK(1);
}
else if(target->y > box->height)
target->y = box->height;
- boxLeft = ((int)box->left * SECTOR(1));
- boxRight = ((int)box->right * SECTOR(1)) - 1;
- boxTop = ((int)box->top * SECTOR(1));
- boxBottom = ((int)box->bottom * SECTOR(1)) - 1;
+ boxLeft = ((int)box->left * BLOCK(1));
+ boxRight = ((int)box->right * BLOCK(1)) - 1;
+ boxTop = ((int)box->top * BLOCK(1));
+ boxBottom = ((int)box->bottom * BLOCK(1)) - 1;
if (item->Pose.Position.z >= boxLeft &&
item->Pose.Position.z <= boxRight &&
item->Pose.Position.x >= boxTop &&
item->Pose.Position.x <= boxBottom)
{
- left = ((int)box->left * SECTOR(1));
- right = ((int)box->right * SECTOR(1)) - 1;
- top = ((int)box->top * SECTOR(1));
- bottom = ((int)box->bottom * SECTOR(1)) - 1;
+ left = ((int)box->left * BLOCK(1));
+ right = ((int)box->right * BLOCK(1)) - 1;
+ top = ((int)box->top * BLOCK(1));
+ bottom = ((int)box->bottom * BLOCK(1)) - 1;
}
else
{
@@ -2102,8 +2121,8 @@ void AdjustStopperFlag(ItemInfo* item, int direction)
auto* floor = GetSector(room, x - room->x, z - room->z);
floor->Stopper = !floor->Stopper;
- x = item->Pose.Position.x + SECTOR(1) * phd_sin(direction);
- z = item->Pose.Position.z + SECTOR(1) * phd_cos(direction);
+ x = item->Pose.Position.x + BLOCK(1) * phd_sin(direction);
+ z = item->Pose.Position.z + BLOCK(1) * phd_cos(direction);
room = &g_Level.Rooms[GetCollision(x, item->Pose.Position.y, z, item->RoomNumber).RoomNumber];
floor = GetSector(room, x - room->x, z - room->z);
@@ -2124,7 +2143,7 @@ void InitializeItemBoxData()
{
for (const auto& mesh : room.mesh)
{
- long index = ((mesh.pos.Position.z - room.z) / SECTOR(1)) + room.zSize * ((mesh.pos.Position.x - room.x) / SECTOR(1));
+ long index = ((mesh.pos.Position.z - room.z) / BLOCK(1)) + room.zSize * ((mesh.pos.Position.x - room.x) / BLOCK(1));
if (index > room.floor.size())
continue;
diff --git a/TombEngine/Game/control/box.h b/TombEngine/Game/control/box.h
index b5358eed5..98e26ca1e 100644
--- a/TombEngine/Game/control/box.h
+++ b/TombEngine/Game/control/box.h
@@ -98,7 +98,8 @@ void CreatureFloat(short itemNumber);
void CreatureJoint(ItemInfo* item, short joint, short required, short maxAngle = ANGLE(70.0f));
void CreatureTilt(ItemInfo* item, short angle);
short CreatureTurn(ItemInfo* item, short maxTurn);
-void CreatureDie(short itemNumber, bool explode);
+void CreatureDie(int itemNumber, bool doExplosion);
+void CreatureDie(int itemNumber, bool doExplosion, int flags);
bool BadFloor(int x, int y, int z, int boxHeight, int nextHeight, short roomNumber, LOTInfo* LOT);
int CreatureCreature(short itemNumber);
bool ValidBox(ItemInfo* item, short zoneNumber, short boxNumber);
diff --git a/TombEngine/Game/control/control.cpp b/TombEngine/Game/control/control.cpp
index 9b8d7eafe..88b337b10 100644
--- a/TombEngine/Game/control/control.cpp
+++ b/TombEngine/Game/control/control.cpp
@@ -218,7 +218,6 @@ GameStatus ControlPhase(int numFrames)
UpdateSparkParticles();
UpdateSmokeParticles();
UpdateSimpleParticles();
- UpdateDrips();
UpdateExplosionParticles();
UpdateShockwaves();
UpdateBeetleSwarm();
@@ -305,16 +304,12 @@ GameStatus DoLevel(int levelIndex, bool loadGame)
InitializeScripting(levelIndex, loadGame);
InitializeNodeScripts();
+ // Initialize menu and inventory state.
+ g_Gui.Initialize();
+
// Initialize game variables and optionally load game.
InitializeOrLoadGame(loadGame);
- // Prepare title menu, if necessary.
- if (isTitle)
- {
- g_Gui.SetMenuToDisplay(Menu::Title);
- g_Gui.SetSelectedOption(0);
- }
-
// DoGameLoop() returns only when level has ended.
return DoGameLoop(levelIndex);
}
@@ -457,8 +452,8 @@ void InitializeScripting(int levelIndex, bool loadGame)
g_GameStringsHandler->SetCallbackDrawString([](std::string const key, D3DCOLOR col, int x, int y, int flags)
{
g_Renderer.AddString(
- float(x) / float(g_Configuration.Width) * SCREEN_SPACE_RES.x,
- float(y) / float(g_Configuration.Height) * SCREEN_SPACE_RES.y,
+ float(x) / float(g_Configuration.ScreenWidth) * SCREEN_SPACE_RES.x,
+ float(y) / float(g_Configuration.ScreenHeight) * SCREEN_SPACE_RES.y,
key.c_str(), col, flags);
});
}
@@ -638,7 +633,7 @@ GameStatus HandleMenuCalls(bool isTitle)
if (g_Gui.CallPause())
result = GameStatus::ExitToTitle;
}
- else if ((IsClicked(In::Option) || g_Gui.GetEnterInventory() != NO_ITEM) &&
+ else if ((IsClicked(In::Inventory) || g_Gui.GetEnterInventory() != NO_ITEM) &&
LaraItem->HitPoints > 0 && !BinocularOn)
{
if (g_Gui.CallInventory(LaraItem, true))
diff --git a/TombEngine/Game/control/flipeffect.cpp b/TombEngine/Game/control/flipeffect.cpp
index 9e35c2c2f..942428891 100644
--- a/TombEngine/Game/control/flipeffect.cpp
+++ b/TombEngine/Game/control/flipeffect.cpp
@@ -315,11 +315,11 @@ void FloorShake(ItemInfo* item)
int y = abs(item->Pose.Position.y - Camera.pos.y);
int z = abs(item->Pose.Position.z - Camera.pos.z);
- if (x < SECTOR(16) &&
- y < SECTOR(16) &&
- z < SECTOR(16))
+ if (x < BLOCK(16) &&
+ y < BLOCK(16) &&
+ z < BLOCK(16))
{
- Camera.bounce = 66 * ((pow(x, 2) + pow(y, 2) + pow(z, 2)) / CLICK(1) - pow(SECTOR(1), 2)) / pow(SECTOR(1), 2);
+ Camera.bounce = 66 * ((pow(x, 2) + pow(y, 2) + pow(z, 2)) / CLICK(1) - pow(BLOCK(1), 2)) / pow(BLOCK(1), 2);
}
}
diff --git a/TombEngine/Game/control/los.cpp b/TombEngine/Game/control/los.cpp
index 4aa840947..f334b4de8 100644
--- a/TombEngine/Game/control/los.cpp
+++ b/TombEngine/Game/control/los.cpp
@@ -606,7 +606,7 @@ int xLOS(GameVector* origin, GameVector* target)
break;
}
- x -= SECTOR(1);
+ x -= BLOCK(1);
y -= dy;
z -= dz;
}
@@ -656,7 +656,7 @@ int xLOS(GameVector* origin, GameVector* target)
break;
}
- x += SECTOR(1);
+ x += BLOCK(1);
y += dy;
z += dz;
}
@@ -726,7 +726,7 @@ int zLOS(GameVector* origin, GameVector* target)
break;
}
- z -= SECTOR(1);
+ z -= BLOCK(1);
x -= dx;
y -= dy;
}
@@ -776,7 +776,7 @@ int zLOS(GameVector* origin, GameVector* target)
break;
}
- z += SECTOR(1);
+ z += BLOCK(1);
x += dx;
y += dy;
}
diff --git a/TombEngine/Game/control/lot.cpp b/TombEngine/Game/control/lot.cpp
index e1a6bf4ab..66e06c183 100644
--- a/TombEngine/Game/control/lot.cpp
+++ b/TombEngine/Game/control/lot.cpp
@@ -117,16 +117,16 @@ void InitializeSlot(short itemNumber, bool makeTarget)
// Can fly.
case LotType::Flyer:
- creature->LOT.Step = SECTOR(20);
- creature->LOT.Drop = -SECTOR(20);
+ creature->LOT.Step = BLOCK(20);
+ creature->LOT.Drop = -BLOCK(20);
creature->LOT.Fly = DEFAULT_FLY_UPDOWN_SPEED;
creature->LOT.Zone = ZoneType::Flyer;
break;
// Can swim.
case LotType::Water:
- creature->LOT.Step = SECTOR(20);
- creature->LOT.Drop = -SECTOR(20);
+ creature->LOT.Step = BLOCK(20);
+ creature->LOT.Drop = -BLOCK(20);
creature->LOT.Zone = ZoneType::Water;
if (item->ObjectNumber == ID_CROCODILE)
@@ -197,7 +197,7 @@ void InitializeSlot(short itemNumber, bool makeTarget)
}
ClearLOT(&creature->LOT);
- if (itemNumber != Lara.ItemNumber)
+ if (itemNumber != LaraItem->Index)
CreateZone(item);
SlotsUsed++;
diff --git a/TombEngine/Game/control/volume.cpp b/TombEngine/Game/control/volume.cpp
index 1c9e44a8a..29d219a29 100644
--- a/TombEngine/Game/control/volume.cpp
+++ b/TombEngine/Game/control/volume.cpp
@@ -30,7 +30,7 @@ namespace TEN::Control::Volumes
if (roomNumber == Camera.pos.RoomNumber)
{
g_Renderer.AddDebugBox(volume.Box,
- Vector4(color, 0.0f, color, 1.0f), RENDERER_DEBUG_PAGE::LARA_STATS);
+ Vector4(color, 0.0f, color, 1.0f), RendererDebugPage::CollisionStats);
}
return volume.Box.Intersects(box);
@@ -38,7 +38,7 @@ namespace TEN::Control::Volumes
if (roomNumber == Camera.pos.RoomNumber)
{
g_Renderer.AddDebugSphere(volume.Sphere.Center, volume.Sphere.Radius,
- Vector4(color, 0.0f, color, 1.0f), RENDERER_DEBUG_PAGE::LARA_STATS);
+ Vector4(color, 0.0f, color, 1.0f), RendererDebugPage::CollisionStats);
}
return volume.Sphere.Intersects(box);
@@ -171,7 +171,7 @@ namespace TEN::Control::Volumes
auto box = (coll != nullptr) ?
ConstructRoughBox(item, *coll) : GameBoundingBox(&item).ToBoundingOrientedBox(item.Pose);
- g_Renderer.AddDebugBox(box, Vector4(1.0f, 1.0f, 0.0f, 1.0f), RENDERER_DEBUG_PAGE::LARA_STATS);
+ g_Renderer.AddDebugBox(box, Vector4(1.0f, 1.0f, 0.0f, 1.0f), RendererDebugPage::CollisionStats);
if (item.IsLara() || item.Index == Lara.Context.Vehicle)
{
diff --git a/TombEngine/Game/effects/debris.cpp b/TombEngine/Game/effects/debris.cpp
index 79cbe0905..e221f9c48 100644
--- a/TombEngine/Game/effects/debris.cpp
+++ b/TombEngine/Game/effects/debris.cpp
@@ -24,7 +24,7 @@ bool ExplodeItemNode(ItemInfo* item, int node, int noXZVel, int bits)
if (1 << node & item->MeshBits.ToPackedBits())
{
int number = bits;
- if (number == BODY_EXPLODE)
+ if (number == BODY_DO_EXPLOSION)
number = -64;
GetSpheres(item, CreatureSpheres, SPHERES_SPACE_WORLD | SPHERES_SPACE_BONE_ORIGIN, Matrix::Identity);
diff --git a/TombEngine/Game/effects/effects.cpp b/TombEngine/Game/effects/effects.cpp
index c48cbdea6..1d6202e4d 100644
--- a/TombEngine/Game/effects/effects.cpp
+++ b/TombEngine/Game/effects/effects.cpp
@@ -1146,7 +1146,7 @@ void TriggerWaterfallMist(const ItemInfo& item)
if (item.TriggerFlags != 0)
{
size = item.TriggerFlags % 100;
- width = std::clamp(int(round(item.TriggerFlags / 100) * 100) / 2, 0, SECTOR(8));
+ width = std::clamp(int(round(item.TriggerFlags / 100) * 100) / 2, 0, BLOCK(8));
}
float cos = phd_cos(angle);
diff --git a/TombEngine/Game/effects/effects.h b/TombEngine/Game/effects/effects.h
index b2f754e3d..4ac8024c2 100644
--- a/TombEngine/Game/effects/effects.h
+++ b/TombEngine/Game/effects/effects.h
@@ -157,8 +157,8 @@ struct Particle
BLEND_MODES blendMode;
unsigned char extras;
signed char dynamic;
- unsigned char fxObj;
- unsigned char roomNumber;
+ int fxObj;
+ int roomNumber;
unsigned char nodeNumber; // ParticleNodeOffsetIDs enum.
};
@@ -211,9 +211,10 @@ extern FX_INFO EffectList[NUM_EFFECTS];
template
TEffect& GetNewEffect(std::vector& effects, unsigned int countMax)
{
+ assertion(effects.size() <= countMax, "Too many particle effects.");
+
// Add and return new effect.
- assert(effects.size() <= countMax);
- if (effects.size() != countMax)
+ if (effects.size() < countMax)
return effects.emplace_back();
TEffect* effectPtr = nullptr;
diff --git a/TombEngine/Game/effects/hair.cpp b/TombEngine/Game/effects/hair.cpp
index db6ea1b35..495cd73bb 100644
--- a/TombEngine/Game/effects/hair.cpp
+++ b/TombEngine/Game/effects/hair.cpp
@@ -29,7 +29,7 @@ namespace TEN::Effects::Hair
// Get world matrix from head bone.
auto worldMatrix = Matrix::Identity;
- g_Renderer.GetBoneMatrix(player.ItemNumber, LM_HEAD, &worldMatrix);
+ g_Renderer.GetBoneMatrix(item.Index, LM_HEAD, &worldMatrix);
// Apply base offset to world matrix.
auto relOffset = GetRelBaseOffset(hairUnitIndex, isYoung);
diff --git a/TombEngine/Game/effects/tomb4fx.cpp b/TombEngine/Game/effects/tomb4fx.cpp
index 281066859..ba7d5a411 100644
--- a/TombEngine/Game/effects/tomb4fx.cpp
+++ b/TombEngine/Game/effects/tomb4fx.cpp
@@ -30,6 +30,9 @@ using namespace TEN::Collision::Floordata;
using namespace TEN::Math;
using TEN::Renderer::g_Renderer;
+// NOTE: This fixes body part exploding instantly if entity is on ground.
+constexpr auto BODY_PART_SPAWN_VERTICAL_OFFSET = CLICK(1);
+
char LaserSightActive = 0;
char LaserSightCol = 0;
int NextGunshell = 0;
@@ -43,12 +46,11 @@ int NextSmokeSpark = 0;
int NextBlood = 0;
int NextGunShell = 0;
-GUNFLASH_STRUCT Gunflashes[MAX_GUNFLASH];
-FIRE_SPARKS FireSparks[MAX_SPARKS_FIRE];
-SMOKE_SPARKS SmokeSparks[MAX_SPARKS_SMOKE];
-GUNSHELL_STRUCT Gunshells[MAX_GUNSHELL];
-BLOOD_STRUCT Blood[MAX_SPARKS_BLOOD];
-SHOCKWAVE_STRUCT ShockWaves[MAX_SHOCKWAVE];
+FIRE_SPARKS FireSparks[MAX_SPARKS_FIRE];
+SMOKE_SPARKS SmokeSparks[MAX_SPARKS_SMOKE];
+GUNSHELL_STRUCT Gunshells[MAX_GUNSHELL];
+BLOOD_STRUCT Blood[MAX_SPARKS_BLOOD];
+SHOCKWAVE_STRUCT ShockWaves[MAX_SHOCKWAVE];
FIRE_LIST Fires[MAX_FIRE_LIST];
int GetFreeFireSpark()
@@ -1168,7 +1170,7 @@ void ExplodeVehicle(ItemInfo* laraItem, ItemInfo* vehicle)
auto* lara = GetLaraInfo(laraItem);
- ExplodingDeath(lara->Context.Vehicle, BODY_EXPLODE | BODY_STONE_SOUND);
+ ExplodingDeath(lara->Context.Vehicle, BODY_DO_EXPLOSION | BODY_STONE_SOUND);
KillItem(lara->Context.Vehicle);
vehicle->Status = ITEM_DEACTIVATED;
SoundEffect(SFX_TR4_EXPLOSION1, &laraItem->Pose);
@@ -1192,6 +1194,10 @@ void ExplodingDeath(short itemNumber, short flags)
auto world = item->Pose.Orientation.ToRotationMatrix();
+ // If only BODY_PART_EXPLODE flag exists but not BODY_EXPLODE, add it.
+ if ((flags & BODY_PART_EXPLODE) && !(flags & BODY_DO_EXPLOSION))
+ flags |= BODY_DO_EXPLOSION;
+
for (int i = 0; i < obj->nmeshes; i++)
{
Matrix boneMatrix;
@@ -1203,7 +1209,7 @@ void ExplodingDeath(short itemNumber, short flags)
item->MeshBits.Clear(i);
- if (i == 0 || ((GetRandomControl() & 3) != 0 && (flags & BODY_EXPLODE)))
+ if (i == 0 || ((GetRandomControl() & 3) != 0 && (flags & BODY_DO_EXPLOSION)))
{
short fxNumber = CreateNewEffect(item->RoomNumber);
if (fxNumber != NO_ITEM)
@@ -1211,26 +1217,26 @@ void ExplodingDeath(short itemNumber, short flags)
FX_INFO* fx = &EffectList[fxNumber];
fx->pos.Position.x = boneMatrix.Translation().x;
- fx->pos.Position.y = boneMatrix.Translation().y;
+ fx->pos.Position.y = boneMatrix.Translation().y - BODY_PART_SPAWN_VERTICAL_OFFSET;
fx->pos.Position.z = boneMatrix.Translation().z;
fx->roomNumber = item->RoomNumber;
fx->pos.Orientation.x = 0;
- fx->pos.Orientation.y = GetRandomControl() * 2;
+ fx->pos.Orientation.y = Random::GenerateAngle();
- if (!(flags & 0x10))
+ if (!(flags & BODY_NO_RAND_VELOCITY))
{
- if (flags & 0x20)
+ if (flags & BODY_MORE_RAND_VELOCITY)
fx->speed = GetRandomControl() >> 12;
else
fx->speed = GetRandomControl() >> 8;
}
- if (flags & 0x40)
+ if (flags & BODY_NO_VERTICAL_VELOCITY)
fx->fallspeed = 0;
else
{
- if ((flags & 0x80) == 0)
+ if (flags & BODY_LESS_IMPULSE)
fx->fallspeed = -(GetRandomControl() >> 8);
else
fx->fallspeed = -(GetRandomControl() >> 12);
diff --git a/TombEngine/Game/effects/tomb4fx.h b/TombEngine/Game/effects/tomb4fx.h
index d0494a792..df0815c15 100644
--- a/TombEngine/Game/effects/tomb4fx.h
+++ b/TombEngine/Game/effects/tomb4fx.h
@@ -10,20 +10,19 @@ struct ItemInfo;
enum BodyPartFlags
{
- BODY_NO_BOUNCE = (1 << 0),
- BODY_GIBS = (1 << 1),
- BODY_EXPLODE = (1 << 8),
- BODY_NO_BOUNCE_ALT = (1 << 9),
- BODY_STONE_SOUND = (1 << 11)
-};
-
-struct Matrix3D
-{
- short m00, m01, m02;
- short m10, m11, m12;
- short m20, m21, m22;
- short pad;
- int tx, ty, tz;
+ BODY_NO_BOUNCE = (1 << 0), // No bounce.
+ BODY_GIBS = (1 << 1), // Add blood and SFX_TR4_LARA_THUD upon floor collision.
+ BODY_PART_EXPLODE = (1 << 2), // Explode upon impact. Requires BODY_EXPLODE flag.
+ BODY_NO_FLAME = (1 << 3), // No flame.
+ BODY_NO_RAND_VELOCITY = (1 << 4), // No random velocity.
+ BODY_MORE_RAND_VELOCITY = (1 << 5), // Add more randomness to velocity.
+ BODY_NO_VERTICAL_VELOCITY = (1 << 6), // No vertical velocity.
+ BODY_LESS_IMPULSE = (1 << 7), // Add less vertical velocity than normal. TODO: Weird name.
+ BODY_DO_EXPLOSION = (1 << 8), // Explode.
+ BODY_NO_BOUNCE_ALT = (1 << 9), // Same as BODY_NO_BOUNCE, but with delay before despawning.
+ BODY_STONE_SOUND = (1 << 11), // Do impact sound if stone. NOTE: BODY_GIBS also add sound, but this one is prioritary.
+ BODY_NO_SMOKE = (1 << 12), // Remove smoke upon despawn or shatter.
+ BODY_NO_SHATTER_EFFECT = (1 << 13), // Remove shatter effect upon despawn.
};
struct SMOKE_SPARKS
@@ -59,12 +58,6 @@ struct SMOKE_SPARKS
byte mirror;
};
-struct GUNFLASH_STRUCT
-{
- Matrix3D matrix;
- short on;
-};
-
struct SHOCKWAVE_STRUCT
{
int x;
@@ -219,7 +212,6 @@ constexpr auto MAX_GUNFLASH = 4;
constexpr auto MAX_GUNSHELL = 24;
constexpr auto MAX_SHOCKWAVE = 16;
-extern GUNFLASH_STRUCT Gunflashes[MAX_GUNFLASH];
extern FIRE_SPARKS FireSparks[MAX_SPARKS_FIRE];
extern SMOKE_SPARKS SmokeSparks[MAX_SPARKS_SMOKE];
extern GUNSHELL_STRUCT Gunshells[MAX_GUNSHELL];
@@ -254,7 +246,7 @@ int GetFreeGunshell();
void TriggerGunShell(short hand, short objNum, LaraWeaponType weaponType);
void UpdateGunShells();
void AddWaterSparks(int x, int y, int z, int num);
-void ExplodingDeath(short itemNumber, short flags); // EXPLODE_ flags
+void ExplodingDeath(short itemNumber, short flags); // BODY_ flags
int GetFreeShockwave();
void TriggerShockwave(Pose* pos, short innerRad, short outerRad, int speed, unsigned char r, unsigned char g, unsigned char b, unsigned char life, EulerAngles rotation, short damage, bool sound, bool fadein, int style);
void TriggerShockwaveHitEffect(int x, int y, int z, unsigned char r, unsigned char g, unsigned char b, short rot, int vel);
diff --git a/TombEngine/Game/gui.cpp b/TombEngine/Game/gui.cpp
index 8066736fa..91f38f23b 100644
--- a/TombEngine/Game/gui.cpp
+++ b/TombEngine/Game/gui.cpp
@@ -41,7 +41,7 @@ namespace TEN::Gui
GuiController g_Gui;
- const char* OptionStrings[] =
+ std::vector OptionStrings =
{
STRING_USE,
STRING_CHOOSE_AMMO,
@@ -58,31 +58,61 @@ namespace TEN::Gui
// STRING_READ_DIARY
};
- const char* ControlStrings[] =
+ std::vector GeneralActionStrings =
{
- STRING_CONTROLS_MOVE_FORWARD,
- STRING_CONTROLS_MOVE_BACKWARD,
- STRING_CONTROLS_MOVE_LEFT,
- STRING_CONTROLS_MOVE_RIGHT,
- STRING_CONTROLS_CROUCH,
- STRING_CONTROLS_SPRINT,
- STRING_CONTROLS_WALK,
- STRING_CONTROLS_JUMP,
- STRING_CONTROLS_ACTION,
- STRING_CONTROLS_DRAW_WEAPON,
- STRING_CONTROLS_USE_FLARE,
- STRING_CONTROLS_LOOK,
- STRING_CONTROLS_ROLL,
- STRING_CONTROLS_INVENTORY,
- STRING_CONTROLS_PAUSE,
- STRING_CONTROLS_STEP_LEFT,
- STRING_CONTROLS_STEP_RIGHT,
- STRING_CONTROLS_V_ACCELERATE,
- STRING_CONTROLS_V_REVERSE,
- STRING_CONTROLS_V_SPEED,
- STRING_CONTROLS_V_SLOW,
- STRING_CONTROLS_V_BRAKE,
- STRING_CONTROLS_V_FIRE
+ STRING_ACTIONS_FORWARD,
+ STRING_ACTIONS_BACKWARD,
+ STRING_ACTIONS_LEFT,
+ STRING_ACTIONS_RIGHT,
+ STRING_ACTIONS_STEP_LEFT,
+ STRING_ACTIONS_STEP_RIGHT,
+ STRING_ACTIONS_WALK,
+ STRING_ACTIONS_SPRINT,
+ STRING_ACTIONS_CROUCH,
+ STRING_ACTIONS_JUMP,
+ STRING_ACTIONS_ROLL,
+ STRING_ACTIONS_ACTION,
+ STRING_ACTIONS_DRAW,
+ STRING_ACTIONS_LOOK
+ };
+
+ std::vector VehicleActionStrings =
+ {
+ STRING_ACTIONS_ACCELERATE,
+ STRING_ACTIONS_REVERSE,
+ STRING_ACTIONS_SPEED,
+ STRING_ACTIONS_SLOW,
+ STRING_ACTIONS_BRAKE,
+ STRING_ACTIONS_FIRE
+ };
+
+ std::vector QuickActionStrings =
+ {
+ STRING_ACTIONS_FLARE,
+ STRING_ACTIONS_SMALL_MEDIPACK,
+ STRING_ACTIONS_LARGE_MEDIPACK,
+ STRING_ACTIONS_PREVIOUS_WEAPON,
+ STRING_ACTIONS_NEXT_WEAPON,
+ STRING_ACTIONS_WEAPON_1,
+ STRING_ACTIONS_WEAPON_2,
+ STRING_ACTIONS_WEAPON_3,
+ STRING_ACTIONS_WEAPON_4,
+ STRING_ACTIONS_WEAPON_5,
+ STRING_ACTIONS_WEAPON_6,
+ STRING_ACTIONS_WEAPON_7,
+ STRING_ACTIONS_WEAPON_8,
+ STRING_ACTIONS_WEAPON_9,
+ STRING_ACTIONS_WEAPON_10
+ };
+
+ std::vector MenuActionStrings =
+ {
+ STRING_ACTIONS_SELECT,
+ STRING_ACTIONS_DESELECT,
+ STRING_ACTIONS_PAUSE,
+ STRING_ACTIONS_INVENTORY,
+ STRING_ACTIONS_SAVE,
+ STRING_ACTIONS_LOAD
};
bool GuiController::GuiIsPulsed(ActionID actionID) const
@@ -90,7 +120,12 @@ namespace TEN::Gui
constexpr auto DELAY = 0.1f;
constexpr auto INITIAL_DELAY = 0.4f;
- auto oppositeAction = In::None;
+ // Action already held prior to entering menu; lock input.
+ if (GetActionTimeActive(actionID) >= TimeInMenu)
+ return false;
+
+ // Pulse only directional inputs.
+ auto oppositeAction = std::optional(std::nullopt);
switch (actionID)
{
case In::Forward:
@@ -108,25 +143,39 @@ namespace TEN::Gui
case In::Right:
oppositeAction = In::Left;
break;
+
+ default:
+ break;
}
- bool isActionLocked = (oppositeAction == In::None) ? false : IsHeld(oppositeAction);
- return (IsPulsed(actionID, DELAY, INITIAL_DELAY) && !isActionLocked);
+ // Opposite action held; lock input.
+ bool isActionLocked = oppositeAction.has_value() ? IsHeld(*oppositeAction) : false;
+ if (isActionLocked)
+ return false;
+
+ return IsPulsed(actionID, DELAY, INITIAL_DELAY);
}
- bool GuiController::GuiIsSelected() const
+ bool GuiController::GuiIsSelected(bool onClicked) const
{
- return ((IsReleased(In::Select) || IsReleased(In::Action)) && CanSelect());
+ if (onClicked)
+ {
+ return ((IsClicked(In::Select) || IsClicked(In::Action)) && CanSelect());
+ }
+ else
+ {
+ return ((IsReleased(In::Select) || IsReleased(In::Action)) && CanSelect());
+ }
}
bool GuiController::GuiIsDeselected() const
{
- return (IsClicked(In::Deselect) && CanDeselect());
+ return ((IsClicked(In::Deselect) || IsClicked(In::Draw)) && CanDeselect());
}
bool GuiController::CanSelect() const
{
- // Holding Deselect safely cancels input.
+ // Holding Deselect safely cancels select actions.
if (IsHeld(In::Deselect))
return false;
@@ -147,9 +196,9 @@ namespace TEN::Gui
return CurrentSettings;
}
- InventoryRing* GuiController::GetRings(int ringIndex)
+ const InventoryRing& GuiController::GetRing(RingTypes ringType)
{
- return Rings[ringIndex];
+ return Rings[(int)ringType];
}
short GuiController::GetSelectedOption()
@@ -211,6 +260,11 @@ namespace TEN::Gui
return LastInvItem;
}
+ void GuiController::SetLastInventoryItem(int itemNumber)
+ {
+ LastInvItem = itemNumber;
+ }
+
void GuiController::DrawInventory()
{
g_Renderer.RenderInventory();
@@ -260,7 +314,10 @@ namespace TEN::Gui
HandleDisplaySettingsInput(false);
return inventoryResult;
- case Menu::Controls:
+ case Menu::GeneralActions:
+ case Menu::VehicleActions:
+ case Menu::QuickActions:
+ case Menu::MenuActions:
HandleControlSettingsInput(item, false);
return inventoryResult;
@@ -307,8 +364,7 @@ namespace TEN::Gui
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
}
- if (GuiIsDeselected() &&
- MenuToDisplay != Menu::Title)
+ if (GuiIsDeselected() && MenuToDisplay != Menu::Title)
{
MenuToDisplay = Menu::Title;
SelectedOption = selectedOptionBackup;
@@ -378,8 +434,8 @@ namespace TEN::Gui
for (int i = 0; i < g_Configuration.SupportedScreenResolutions.size(); i++)
{
auto screenResolution = g_Configuration.SupportedScreenResolutions[i];
- if (screenResolution.x == CurrentSettings.Configuration.Width &&
- screenResolution.y == CurrentSettings.Configuration.Height)
+ if (screenResolution.x == CurrentSettings.Configuration.ScreenWidth &&
+ screenResolution.y == CurrentSettings.Configuration.ScreenHeight)
{
CurrentSettings.SelectedScreenResolution = i;
break;
@@ -425,7 +481,7 @@ namespace TEN::Gui
case DisplaySettingsOption::Windowed:
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
- CurrentSettings.Configuration.Windowed = !CurrentSettings.Configuration.Windowed;
+ CurrentSettings.Configuration.EnableWindowedMode = !CurrentSettings.Configuration.EnableWindowedMode;
break;
case DisplaySettingsOption::ShadowType:
@@ -446,10 +502,10 @@ namespace TEN::Gui
case DisplaySettingsOption::Antialiasing:
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
- if (CurrentSettings.Configuration.Antialiasing == AntialiasingMode::None)
- CurrentSettings.Configuration.Antialiasing = AntialiasingMode::High;
+ if (CurrentSettings.Configuration.AntialiasingMode == AntialiasingMode::None)
+ CurrentSettings.Configuration.AntialiasingMode = AntialiasingMode::High;
else
- CurrentSettings.Configuration.Antialiasing = AntialiasingMode(int(CurrentSettings.Configuration.Antialiasing) - 1);
+ CurrentSettings.Configuration.AntialiasingMode = AntialiasingMode(int(CurrentSettings.Configuration.AntialiasingMode) - 1);
break;
}
@@ -467,7 +523,7 @@ namespace TEN::Gui
case DisplaySettingsOption::Windowed:
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
- CurrentSettings.Configuration.Windowed = !CurrentSettings.Configuration.Windowed;
+ CurrentSettings.Configuration.EnableWindowedMode = !CurrentSettings.Configuration.EnableWindowedMode;
break;
case DisplaySettingsOption::ShadowType:
@@ -487,10 +543,10 @@ namespace TEN::Gui
case DisplaySettingsOption::Antialiasing:
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
- if (CurrentSettings.Configuration.Antialiasing == AntialiasingMode::High)
- CurrentSettings.Configuration.Antialiasing = AntialiasingMode::None;
+ if (CurrentSettings.Configuration.AntialiasingMode == AntialiasingMode::High)
+ CurrentSettings.Configuration.AntialiasingMode = AntialiasingMode::None;
else
- CurrentSettings.Configuration.Antialiasing = AntialiasingMode(int(CurrentSettings.Configuration.Antialiasing) + 1);
+ CurrentSettings.Configuration.AntialiasingMode = AntialiasingMode(int(CurrentSettings.Configuration.AntialiasingMode) + 1);
break;
}
@@ -524,15 +580,15 @@ namespace TEN::Gui
{
// Save the configuration.
auto screenResolution = g_Configuration.SupportedScreenResolutions[CurrentSettings.SelectedScreenResolution];
- CurrentSettings.Configuration.Width = screenResolution.x;
- CurrentSettings.Configuration.Height = screenResolution.y;
+ CurrentSettings.Configuration.ScreenWidth = screenResolution.x;
+ CurrentSettings.Configuration.ScreenHeight = screenResolution.y;
g_Configuration = CurrentSettings.Configuration;
SaveConfiguration();
// Reset screen and go back.
- g_Renderer.ChangeScreenResolution(CurrentSettings.Configuration.Width, CurrentSettings.Configuration.Height,
- CurrentSettings.Configuration.Windowed);
+ g_Renderer.ChangeScreenResolution(CurrentSettings.Configuration.ScreenWidth, CurrentSettings.Configuration.ScreenHeight,
+ CurrentSettings.Configuration.EnableWindowedMode);
MenuToDisplay = fromPauseMenu ? Menu::Pause : Menu::Options;
SelectedOption = fromPauseMenu ? 1 : 0;
@@ -547,7 +603,26 @@ namespace TEN::Gui
void GuiController::HandleControlSettingsInput(ItemInfo* item, bool fromPauseMenu)
{
- static const int numControlSettingsOptions = KEY_COUNT + 2;
+ unsigned int numControlSettingsOptions = 0;
+ switch (MenuToDisplay)
+ {
+ default:
+ case Menu::GeneralActions:
+ numControlSettingsOptions = (int)GeneralActionStrings.size() + 2;
+ break;
+
+ case Menu::VehicleActions:
+ numControlSettingsOptions = (int)VehicleActionStrings.size() + 2;
+ break;
+
+ case Menu::QuickActions:
+ numControlSettingsOptions = (int)QuickActionStrings.size() + 2;
+ break;
+
+ case Menu::MenuActions:
+ numControlSettingsOptions = (int)MenuActionStrings.size() + 2;
+ break;
+ }
OptionCount = numControlSettingsOptions;
CurrentSettings.WaitingForKey = false;
@@ -593,9 +668,28 @@ namespace TEN::Gui
if (selectedKey == MAX_INPUT_SLOTS)
selectedKey = 0;
- if (selectedKey && g_KeyNames[selectedKey])
+ if (selectedKey && !g_KeyNames[selectedKey].empty())
{
- KeyboardLayout[1][SelectedOption] = selectedKey;
+ unsigned int baseIndex = 0;
+ switch (MenuToDisplay)
+ {
+ case Menu::VehicleActions:
+ baseIndex = (unsigned int)GeneralActionStrings.size();
+ break;
+
+ case Menu::QuickActions:
+ baseIndex = unsigned int(GeneralActionStrings.size() + VehicleActionStrings.size());
+ break;
+
+ case Menu::MenuActions:
+ baseIndex = unsigned int(GeneralActionStrings.size() + VehicleActionStrings.size() + QuickActionStrings.size());
+ break;
+
+ default:
+ break;
+ }
+
+ Bindings[1][baseIndex + SelectedOption] = selectedKey;
DefaultConflict();
CurrentSettings.WaitingForKey = false;
@@ -640,6 +734,43 @@ namespace TEN::Gui
SoundEffect(SFX_TR4_MENU_CHOOSE, nullptr, SoundEnvironment::Always);
}
+ // HACK: Menu screen scroll.
+ if (GuiIsPulsed(In::Left) || GuiIsPulsed(In::Right))
+ {
+ auto menu = std::optional