Class Flow.Settings
-Settings that will be run on game startup.
-- -
+Global engine settings which don't fall into particular category or can't be assigned to a specific object.
+Can be accessed using Flow.SetSettings and Flow.GetSettings functions.
-Members
+Animations
+crawlExtended | +Extended crawl moveset. | +
crouchRoll | +Crouch roll. | +
crawlspaceSwandive | +Crawlspace dive. | +
sprintJump | +Sprint jump. | +
ledgeJumps | +Ledge jumps. | +
poseTimeout | +Pose timeout. | +
Camera
+binocularLightColor | +Determines highlight color in binocular mode. | +
lasersightLightColor | +Determines highlight color in lasersight mode. | +
objectCollision | +Specify whether camera can collide with objects. | +
Flare
+color | +Flare color. | +
offset | +Muzzle offset. | +
range | +Light range. | +
timeout | +Burn timeout. | +
pickupCount | +Default flare pickup count. | +
lensflareBrightness | +Lens flare brightness. | +
sparks | +Toggle spark effect. | +
smoke | +Toggle smoke effect. | +
flicker | +Toggle flicker effect. | +
Hair
+mesh | +Root mesh to which hair object will attach to. | +
offset | +Relative braid offset to a headmesh. | +
indices | +Braid connection indices. | +
Hud
+statusBars | +Toggle in-game status bars visibility. | +
loadingBar | +Toggle loading bar visibility. | +
speedometer | +Toggle speedometer visibility. | +
pickupNotifier | +Toggle pickup notifier visibility. | +
Physics
+gravity | +Global world gravity. | +
swimVelocity | +Swim velocity. | +
Weapons
+accuracy | +Shooting accuracy. | +
targetingDistance | +Targeting distance. | +
interval | +Shooting interval. | +
damage | +Damage. | +
alternateDamage | +Alternate damage. | +
waterLevel | +Water level. | +
pickupCount | +Default ammo pickup count. | +
flashColor | +Gunflash color. | +
flashRange | +Gunflash range. | +
flashDuration | +Gunflash duration. | +
smoke | +Gun smoke. | +
shell | +Gun shell. | +
muzzleFlash | +Display muzzle flash. | +
colorizeMuzzleFlash | +Colorize muzzle flash. | +
System
errorMode | @@ -126,8 +312,924 @@
2 Classes
View.DisplaySprite | -Represents a display sprite. | -|
Flow.Animations | -New custom animations which Lara can perform. | -|
Flow.Fog | -Fog | -|
Flow.InventoryItem | -Represents the properties of an object as it appears in the inventory. | -|
Flow.LensFlare | -Represents a lens flare. | -|
Flow.Level | Stores level metadata. | |
Flow.Mirror | -A mirror effect. | -|
Flow.Settings | -Settings that will be run on game startup. | -|
Flow.SkyLayer | -Describes a layer of moving clouds. | -|
Flow.Starfield | -Represents a starfield. | +Global engine settings which don't fall into particular category or can't be assigned to a specific object. |
Objects.AIObject | @@ -251,9 +222,41 @@ local door = GetMoveableByName("door_type4_14")Strings.DisplayString | A string appearing on the screen. |
View.DisplaySprite | +Represents a display sprite. | +
3 Primitive Classes
Flow.Fog | +Fog | +||
Flow.InventoryItem | +Represents the properties of an object as it appears in the inventory. | +||
Flow.LensFlare | +Represents a global lens flare (not to be confused with lensflare object). | +||
Flow.Mirror | +A mirror effect. | +||
Flow.SkyLayer | +Describes a layer of moving clouds. | +||
Flow.Starfield | +Represents a starfield. | +||
Flow.Statistics | +A set of gameplay statistics. | +||
Color | Represents an RGBA or RGB color. | @@ -262,6 +265,10 @@ local door = GetMoveableByName("door_type4_14")Rotation | Represents a degree-based 3D rotation. |
Time | +Represents a time value with support for formatting to hours, minutes, seconds, and centiseconds (1/100th of a second). | +||
Vec2 | Represents a float-based 2D vector. | @@ -281,6 +288,10 @@ local door = GetMoveableByName("door_type4_14")Effects.EffectID | Constants for effect IDs. |
Flow.ErrorMode | +Constants for error modes. | +||
Flow.FreezeMode | Constants for freeze modes. | @@ -289,6 +300,10 @@ local door = GetMoveableByName("door_type4_14")Flow.GameStatus | Constants for game statuses. |
Flow.WeaponType | +Constants for weapon types. | +||
Input.ActionID | Constants for action key IDs. | diff --git a/Scripts/Settings.lua b/Scripts/Settings.lua index b6d230a98..bc172443b 100644 --- a/Scripts/Settings.lua +++ b/Scripts/Settings.lua @@ -4,17 +4,145 @@ local Flow = TEN.Flow local settings = Flow.Settings.new() -settings.errorMode = Flow.ErrorMode.WARN -settings.fastReload = true -Flow.SetSettings(settings) -local anims = Flow.Animations.new() -anims.crawlExtended = true -anims.crouchRoll = true -anims.crawlspaceSwandive = true -anims.overhangClimb = false -anims.slideExtended = false -anims.sprintJump = false -anims.pose = false -anims.ledgeJumps = false -Flow.SetAnimations(anims) \ No newline at end of file + settings.Animations.crouchRoll = true + settings.Animations.crawlspaceSwandive = true + settings.Animations.sprintJump = false + settings.Animations.ledgeJumps = false + settings.Animations.poseTimeout = 0 + + settings.Camera.binocularLightColor = Color(192, 192, 96) + settings.Camera.lasersightLightColor = Color(255, 0, 0) + settings.Camera.objectCollision = true + + settings.Flare.color = Color(128, 64, 0) + settings.Flare.offset = Vec3(0, 0, 41) + settings.Flare.range = 9 + settings.Flare.timeout = 60 + settings.Flare.lensflareBrightness = 0.5 + settings.Flare.sparks = true + settings.Flare.smoke = true + settings.Flare.flicker = true + settings.Flare.pickupCount = 12 + + settings.Hud.statusBars = true + settings.Hud.loadingBar = true + settings.Hud.speedometer = true + settings.Hud.pickupNotifier = true + + settings.Physics.gravity = 6 + settings.Physics.swimVelocity = 50 + + settings.System.errorMode = Flow.ErrorMode.WARN + settings.System.fastReload = true + + -- Hair[1] is normal player hair. Types [2] and [3] are for left and right young Lara hair. + + settings.Hair[1].rootMesh = 14 + settings.Hair[1].offset = Vec3(-4, -4, -48) + settings.Hair[1].indices = { 37, 39, 40, 38 } + + settings.Hair[2].rootMesh = 14 + settings.Hair[2].offset = Vec3(-48, -48, -50) + settings.Hair[2].indices = { 79, 78, 76, 77 } + + settings.Hair[3].rootMesh = 14 + settings.Hair[3].offset = Vec3(48, -48, -50) + settings.Hair[3].indices = { 68, 69, 70, 71 } + + -- Not all weapon settings are applicable to every weapon. Those which are not applicable + -- for a particular weapon type are omitted. See documentation for more details. + + settings.Weapons[WeaponType.PISTOLS].accuracy = 8 + settings.Weapons[WeaponType.PISTOLS].targetingDistance = 8192 + settings.Weapons[WeaponType.PISTOLS].interval = 9 + settings.Weapons[WeaponType.PISTOLS].waterLevel = 650 + settings.Weapons[WeaponType.PISTOLS].flashDuration = 3 + settings.Weapons[WeaponType.PISTOLS].flashRange = 12 + settings.Weapons[WeaponType.PISTOLS].flashColor = Color(192, 128, 0) + settings.Weapons[WeaponType.PISTOLS].damage = 1 + settings.Weapons[WeaponType.PISTOLS].smoke = true + settings.Weapons[WeaponType.PISTOLS].shell = true + settings.Weapons[WeaponType.PISTOLS].muzzleFlash = true + settings.Weapons[WeaponType.PISTOLS].colorizeMuzzleFlash = false + settings.Weapons[WeaponType.PISTOLS].pickupCount = 30 + + settings.Weapons[WeaponType.REVOLVER].accuracy = 8 + settings.Weapons[WeaponType.REVOLVER].targetingDistance = 8192 + settings.Weapons[WeaponType.REVOLVER].interval = 16 + settings.Weapons[WeaponType.REVOLVER].waterLevel = 650 + settings.Weapons[WeaponType.REVOLVER].flashDuration = 3 + settings.Weapons[WeaponType.REVOLVER].flashRange = 12 + settings.Weapons[WeaponType.REVOLVER].flashColor = Color(192, 128, 0) + settings.Weapons[WeaponType.REVOLVER].damage = 21 + settings.Weapons[WeaponType.REVOLVER].alternateDamage = 21 + settings.Weapons[WeaponType.REVOLVER].smoke = true + settings.Weapons[WeaponType.REVOLVER].shell = false + settings.Weapons[WeaponType.REVOLVER].muzzleFlash = true + settings.Weapons[WeaponType.REVOLVER].colorizeMuzzleFlash = false + settings.Weapons[WeaponType.REVOLVER].pickupCount = 6 + + settings.Weapons[WeaponType.UZI].accuracy = 8 + settings.Weapons[WeaponType.UZI].targetingDistance = 8192 + settings.Weapons[WeaponType.UZI].interval = 3 + settings.Weapons[WeaponType.UZI].waterLevel = 650 + settings.Weapons[WeaponType.UZI].flashDuration = 2 + settings.Weapons[WeaponType.UZI].flashRange = 12 + settings.Weapons[WeaponType.UZI].flashColor = Color(192, 128, 0) + settings.Weapons[WeaponType.UZI].damage = 1 + settings.Weapons[WeaponType.UZI].smoke = true + settings.Weapons[WeaponType.UZI].shell = true + settings.Weapons[WeaponType.UZI].muzzleFlash = true + settings.Weapons[WeaponType.UZI].colorizeMuzzleFlash = false + settings.Weapons[WeaponType.UZI].pickupCount = 30 + + settings.Weapons[WeaponType.SHOTGUN].accuracy = 10 + settings.Weapons[WeaponType.SHOTGUN].targetingDistance = 8192 + settings.Weapons[WeaponType.SHOTGUN].waterLevel = 500 + settings.Weapons[WeaponType.SHOTGUN].flashDuration = 3 + settings.Weapons[WeaponType.SHOTGUN].flashRange = 12 + settings.Weapons[WeaponType.SHOTGUN].flashColor = Color(192, 128, 0) + settings.Weapons[WeaponType.SHOTGUN].damage = 3 + settings.Weapons[WeaponType.SHOTGUN].smoke = true + settings.Weapons[WeaponType.SHOTGUN].shell = true + settings.Weapons[WeaponType.SHOTGUN].muzzleFlash = false + settings.Weapons[WeaponType.SHOTGUN].colorizeMuzzleFlash = false + settings.Weapons[WeaponType.SHOTGUN].pickupCount = 6 + + settings.Weapons[WeaponType.HK].accuracy = 4 + settings.Weapons[WeaponType.HK].targetingDistance = 12288 + settings.Weapons[WeaponType.HK].waterLevel = 500 + settings.Weapons[WeaponType.HK].flashDuration = 2 + settings.Weapons[WeaponType.HK].flashRange = 12 + settings.Weapons[WeaponType.HK].flashColor = Color(192, 128, 0) + settings.Weapons[WeaponType.HK].damage = 4 + settings.Weapons[WeaponType.HK].alternateDamage = 4 + settings.Weapons[WeaponType.HK].smoke = true + settings.Weapons[WeaponType.HK].shell = true + settings.Weapons[WeaponType.HK].muzzleFlash = true + settings.Weapons[WeaponType.HK].colorizeMuzzleFlash = false + settings.Weapons[WeaponType.HK].pickupCount = 30 + + settings.Weapons[WeaponType.CROSSBOW].targetingDistance = 8192 + settings.Weapons[WeaponType.CROSSBOW].waterLevel = 500 + settings.Weapons[WeaponType.CROSSBOW].damage = 5 + settings.Weapons[WeaponType.CROSSBOW].alternateDamage = 20 + settings.Weapons[WeaponType.CROSSBOW].pickupCount = 10 + + settings.Weapons[WeaponType.GRENADE_LAUNCHER].targetingDistance = 8192 + settings.Weapons[WeaponType.GRENADE_LAUNCHER].waterLevel = 500 + settings.Weapons[WeaponType.GRENADE_LAUNCHER].damage = 20 + settings.Weapons[WeaponType.GRENADE_LAUNCHER].smoke = true + settings.Weapons[WeaponType.GRENADE_LAUNCHER].pickupCount = 10 + + settings.Weapons[WeaponType.ROCKET_LAUNCHER].targetingDistance = 8192 + settings.Weapons[WeaponType.ROCKET_LAUNCHER].waterLevel = 500 + settings.Weapons[WeaponType.ROCKET_LAUNCHER].damage = 30 + settings.Weapons[WeaponType.ROCKET_LAUNCHER].smoke = true + settings.Weapons[WeaponType.ROCKET_LAUNCHER].pickupCount = 1 + + settings.Weapons[WeaponType.HARPOON_GUN].targetingDistance = 8192 + settings.Weapons[WeaponType.HARPOON_GUN].damage = 6 + settings.Weapons[WeaponType.HARPOON_GUN].pickupCount = 10 + +Flow.SetSettings(settings) diff --git a/Scripts/SystemStrings.lua b/Scripts/SystemStrings.lua index fdd9821c2..03d40cd29 100644 --- a/Scripts/SystemStrings.lua +++ b/Scripts/SystemStrings.lua @@ -100,7 +100,7 @@ local strings = reverb = { "Reverb" }, rumble = { "Rumble" }, save_game = { "Save Game" }, - savegame_timestamp = { "%02d Days %02d:%02d:%02d" }, + savegame_timestamp = { "%02d:%02d:%02d" }, screen_resolution = { "Screen Resolution" }, select_level = { "Select Level" }, separate = { "Separate" }, diff --git a/TombEngine/Game/Hud/PickupSummary.cpp b/TombEngine/Game/Hud/PickupSummary.cpp index 4376cf80b..8c9e8b65d 100644 --- a/TombEngine/Game/Hud/PickupSummary.cpp +++ b/TombEngine/Game/Hud/PickupSummary.cpp @@ -6,6 +6,7 @@ #include "Game/pickup/pickup_consumable.h" #include "Math/Math.h" #include "Renderer/Renderer.h" +#include "Scripting/Include/Flow/ScriptInterfaceFlowHandler.h" #include "Specific/clock.h" using namespace TEN::Math; @@ -174,6 +175,9 @@ namespace TEN::Hud { //DrawDebug(); + if (!g_GameFlow->GetSettings()->Hud.PickupNotifier) + return; + if (_displayPickups.empty()) return; diff --git a/TombEngine/Game/Hud/Speedometer.cpp b/TombEngine/Game/Hud/Speedometer.cpp index 58e25c801..6253fc6ac 100644 --- a/TombEngine/Game/Hud/Speedometer.cpp +++ b/TombEngine/Game/Hud/Speedometer.cpp @@ -3,8 +3,9 @@ #include "Game/effects/DisplaySprite.h" #include "Math/Math.h" -#include "Specific/clock.h" #include "Renderer/Renderer.h" +#include "Scripting/Include/Flow/ScriptInterfaceFlowHandler.h" +#include "Specific/clock.h" using namespace TEN::Effects::DisplaySprite; using namespace TEN::Math; @@ -58,6 +59,9 @@ namespace TEN::Hud //DrawDebug(); + if (!g_GameFlow->GetSettings()->Hud.Speedometer) + return; + if (_life <= 0.0f) return; diff --git a/TombEngine/Game/Hud/StatusBars.cpp b/TombEngine/Game/Hud/StatusBars.cpp index b9ab5a415..d819db6f4 100644 --- a/TombEngine/Game/Hud/StatusBars.cpp +++ b/TombEngine/Game/Hud/StatusBars.cpp @@ -8,6 +8,7 @@ #include "Game/Lara/lara_helpers.h" #include "Objects/game_object_ids.h" #include "Renderer/Renderer.h" +#include "Scripting/Include/Flow/ScriptInterfaceFlowHandler.h" #include "Specific/clock.h" using namespace TEN::Renderer; @@ -63,7 +64,7 @@ namespace TEN::Hud constexpr auto FLASH_INTERVAL = 0.2f; // Update flash. - if ((GameTimer % (int)round(FLASH_INTERVAL * FPS)) == 0) + if ((GlobalCounter % (int)round(FLASH_INTERVAL * FPS)) == 0) _doFlash = !_doFlash; // Update bars. @@ -75,6 +76,10 @@ namespace TEN::Hud void StatusBarsController::Draw(const ItemInfo& item) const { + // Avoid drawing if HUD is disabled. + if (!g_GameFlow->GetSettings()->Hud.StatusBars) + return; + // Avoid drawing in title level and during cutscenes. if (CurrentLevel == 0 || CinematicBarsHeight > 0) return; diff --git a/TombEngine/Game/Lara/PlayerContext.cpp b/TombEngine/Game/Lara/PlayerContext.cpp index 99ac6a5b9..423b3007d 100644 --- a/TombEngine/Game/Lara/PlayerContext.cpp +++ b/TombEngine/Game/Lara/PlayerContext.cpp @@ -95,7 +95,7 @@ namespace TEN::Entities::Player const auto& player = GetLaraInfo(item); // 1) Check if AFK posing is enabled. - if (!g_GameFlow->HasAFKPose()) + if (!g_GameFlow->GetSettings()->Animations.PoseTimeout) return false; // 2) Test player hand and water status. @@ -417,7 +417,7 @@ namespace TEN::Entities::Player bool CanSteerOnSlide(const ItemInfo& item, const CollisionInfo& coll) { - return g_GameFlow->HasSlideExtended(); + return g_GameFlow->GetSettings()->Animations.SlideExtended; } bool IsInLowSpace(const ItemInfo& item, const CollisionInfo& coll) @@ -519,7 +519,7 @@ namespace TEN::Entities::Player const auto& player = GetLaraInfo(item); // 1) Check if crouch roll is enabled. - if (!g_GameFlow->HasCrouchRoll()) + if (!g_GameFlow->GetSettings()->Animations.CrouchRoll) return false; // 2) Test water depth. @@ -609,7 +609,7 @@ namespace TEN::Entities::Player auto pointColl = GetPointCollision(item); // 2) Test for slippery ceiling slope and check if overhang climb is disabled. - if (pointColl.IsSteepCeiling() && !g_GameFlow->HasOverhangClimb()) + if (pointColl.IsSteepCeiling() && !g_GameFlow->GetSettings()->Animations.OverhangClimb) return true; // 3) Assess point collision. @@ -963,7 +963,7 @@ namespace TEN::Entities::Player const auto& player = GetLaraInfo(item); // 1) Check if sprint jump is enabled. - if (!g_GameFlow->HasSprintJump()) + if (!g_GameFlow->GetSettings()->Animations.SprintJump) return false; // 2) Check for jump state dispatch. @@ -990,7 +990,7 @@ namespace TEN::Entities::Player return true; // Check whether extended slide mechanics are enabled. - if (!g_GameFlow->HasSlideExtended()) + if (!g_GameFlow->GetSettings()->Animations.SlideExtended) return true; // TODO: Broken on diagonal slides? @@ -1013,7 +1013,7 @@ namespace TEN::Entities::Player constexpr auto LEDGE_HEIGHT_MIN = CLICK(2); // 1) Check if ledge jumps are enabled. - if (!g_GameFlow->HasLedgeJumps()) + if (!g_GameFlow->GetSettings()->Animations.LedgeJumps) return false; // Ray collision setup at minimum ledge height. diff --git a/TombEngine/Game/Lara/lara.cpp b/TombEngine/Game/Lara/lara.cpp index 46b34aec8..8b66a63b1 100644 --- a/TombEngine/Game/Lara/lara.cpp +++ b/TombEngine/Game/Lara/lara.cpp @@ -331,7 +331,9 @@ void LaraControl(ItemInfo* item, CollisionInfo* coll) break; } - SaveGame::Statistics.Game.Distance += (int)round(Vector3i::Distance(prevPos, item->Pose.Position)); + int deltaDist = (int)round(Vector3i::Distance(prevPos, item->Pose.Position)); + SaveGame::Statistics.Game.Distance += deltaDist; + SaveGame::Statistics.Level.Distance += deltaDist; if (DebugMode) { diff --git a/TombEngine/Game/Lara/lara.h b/TombEngine/Game/Lara/lara.h index 0d426f036..69ce7e5f6 100644 --- a/TombEngine/Game/Lara/lara.h +++ b/TombEngine/Game/Lara/lara.h @@ -59,14 +59,12 @@ constexpr auto LARA_DEATH_VELOCITY = 155.0f; constexpr auto LARA_DIVE_DEATH_VELOCITY = 134.0f; constexpr auto LARA_TERMINAL_VELOCITY = CLICK(10); -constexpr auto LARA_SWIM_VELOCITY_ACCEL = 2.0f; -constexpr auto LARA_SWIM_VELOCITY_DECEL = 1.5f; -constexpr auto LARA_TREAD_VELOCITY_MAX = 17.5f; -constexpr auto LARA_SWIM_VELOCITY_MAX = 50.0f; -constexpr auto LARA_SWIM_INTERTIA_VELOCITY_MIN = 33.5f; +constexpr auto LARA_SWIM_VELOCITY_ACCEL_COEFF = 0.04f; +constexpr auto LARA_SWIM_VELOCITY_DECEL_COEFF = 0.03f; +constexpr auto LARA_TREAD_VELOCITY_MAX_COEFF = 0.35f; +constexpr auto LARA_SWIM_INTERTIA_VELOCITY_MIN_COEFF = 0.67f; constexpr auto PLAYER_POSITION_ADJUST_MAX_TIME = 3 * FPS; // 3 seconds allowed for position adjustment. -constexpr auto PLAYER_POSE_TIME = 20 * FPS; // 20 seconds to AFK pose. constexpr auto PLAYER_RUN_JUMP_TIME = 22; // Frames to count before a running jump is possible. constexpr auto PLAYER_SPRINT_JUMP_TIME = 46; // Frames to count before a sprint jump is possible. @@ -92,6 +90,7 @@ constexpr auto SHALLOW_WATER_DEPTH = (int)CLICK(0.5f); constexpr auto WADE_WATER_DEPTH = STEPUP_HEIGHT; constexpr auto SWIM_WATER_DEPTH = CLICK(2.75f); constexpr auto SLOPE_DIFFERENCE = 60; +constexpr auto SWAMP_GRAVITY_COEFF = 3.0f; extern LaraInfo Lara; extern ItemInfo* LaraItem; diff --git a/TombEngine/Game/Lara/lara_basic.cpp b/TombEngine/Game/Lara/lara_basic.cpp index 5e65451a7..7d1563d3f 100644 --- a/TombEngine/Game/Lara/lara_basic.cpp +++ b/TombEngine/Game/Lara/lara_basic.cpp @@ -594,7 +594,7 @@ void lara_as_idle(ItemInfo* item, CollisionInfo* coll) } // TODO: Without animation blending, the AFK state's movement lock interferes with responsiveness. -- Sezz 2021.10.31 - if (CanStrikeAfkPose(*item, *coll) && player.Control.Count.Pose >= PLAYER_POSE_TIME) + if (CanStrikeAfkPose(*item, *coll) && player.Control.Count.Pose >= (g_GameFlow->GetSettings()->Animations.PoseTimeout * FPS)) { item->Animation.TargetState = LS_POSE; return; @@ -1694,7 +1694,7 @@ void lara_as_sprint(ItemInfo* item, CollisionInfo* coll) if (IsHeld(In::Jump) || player.Control.IsRunJumpQueued) { // TODO: CanSprintJumpForward() should handle HasSprintJump() check. - if (IsHeld(In::Walk) || !g_GameFlow->HasSprintJump()) + if (IsHeld(In::Walk) || !g_GameFlow->GetSettings()->Animations.SprintJump) { item->Animation.TargetState = LS_SPRINT_DIVE; return; diff --git a/TombEngine/Game/Lara/lara_cheat.cpp b/TombEngine/Game/Lara/lara_cheat.cpp index 4b52d97fa..3e87b6583 100644 --- a/TombEngine/Game/Lara/lara_cheat.cpp +++ b/TombEngine/Game/Lara/lara_cheat.cpp @@ -8,6 +8,7 @@ #include "Game/Lara/lara_swim.h" #include "Game/Setup.h" #include "Sound/sound.h" +#include "Scripting/Include/Flow/ScriptInterfaceFlowHandler.h" #include "Specific/Input/Input.h" using namespace TEN::Input; @@ -16,6 +17,8 @@ namespace TEN::Entities::Player { void lara_as_fly_cheat(ItemInfo* item, CollisionInfo* coll) { + float baseVel = g_GameFlow->GetSettings()->Physics.SwimVelocity; + if (IsHeld(In::Forward)) { item->Pose.Orientation.x -= ANGLE(3.0f); @@ -41,13 +44,13 @@ namespace TEN::Entities::Player { float velCoeff = IsHeld(In::Sprint) ? 2.5f : 1.0f; - item->Animation.Velocity.y += (LARA_SWIM_VELOCITY_ACCEL * 4) * velCoeff; - if (item->Animation.Velocity.y > (LARA_SWIM_VELOCITY_MAX * 2) * velCoeff) - item->Animation.Velocity.y = (LARA_SWIM_VELOCITY_MAX * 2) * velCoeff; + item->Animation.Velocity.y += ((baseVel * LARA_SWIM_VELOCITY_ACCEL_COEFF) * 4) * velCoeff; + if (item->Animation.Velocity.y > (baseVel * 2) * velCoeff) + item->Animation.Velocity.y = (baseVel * 2) * velCoeff; } else { - if (item->Animation.Velocity.y >= LARA_SWIM_VELOCITY_ACCEL) + if (item->Animation.Velocity.y >= (baseVel * LARA_SWIM_VELOCITY_ACCEL_COEFF)) { item->Animation.Velocity.y -= item->Animation.Velocity.y / 8; } diff --git a/TombEngine/Game/Lara/lara_collide.cpp b/TombEngine/Game/Lara/lara_collide.cpp index e87e37f00..1ab07d0e6 100644 --- a/TombEngine/Game/Lara/lara_collide.cpp +++ b/TombEngine/Game/Lara/lara_collide.cpp @@ -436,7 +436,7 @@ void LaraResetGravityStatus(ItemInfo* item, CollisionInfo* coll) void LaraSnapToHeight(ItemInfo* item, CollisionInfo* coll) { if (TestEnvironment(ENV_FLAG_SWAMP, item) && coll->Middle.Floor > 0) - item->Pose.Position.y += SWAMP_GRAVITY; + item->Pose.Position.y += g_GameFlow->GetSettings()->Physics.Gravity / SWAMP_GRAVITY_COEFF; else if (coll->Middle.Floor != NO_HEIGHT) item->Pose.Position.y += coll->Middle.Floor; } diff --git a/TombEngine/Game/Lara/lara_fire.cpp b/TombEngine/Game/Lara/lara_fire.cpp index 27e0e4d91..0e51dbb7e 100644 --- a/TombEngine/Game/Lara/lara_fire.cpp +++ b/TombEngine/Game/Lara/lara_fire.cpp @@ -25,6 +25,7 @@ #include "Scripting/Include/Objects/ScriptInterfaceObjectsHandler.h" #include "Scripting/Include/ScriptInterfaceGame.h" #include "Scripting/Include/ScriptInterfaceLevel.h" +#include "Scripting/Internal/TEN/Flow/Enums/WeaponTypes.h" #include "Sound/sound.h" #include "Specific/configuration.h" #include "Specific/Input/Input.h" @@ -147,7 +148,7 @@ WeaponInfo Weapons[(int)LaraWeaponType::NumWeapons] = std::pair(EulerAngles(ANGLE(-70.0f), ANGLE(-80.0f), 0), EulerAngles(ANGLE(65.0f), ANGLE(80.0f), 0)), std::pair(EulerAngles(ANGLE(-70.0f), ANGLE(-80.0f), 0), EulerAngles(ANGLE(65.0f), ANGLE(80.0f), 0)), ANGLE(10.0f), - 0, + ANGLE(10.0f), 500, BLOCK(8), 3, @@ -304,6 +305,26 @@ const WeaponInfo& GetWeaponInfo(LaraWeaponType weaponType) return (Weapons[(int)weaponType]); } +void InitializeWeaponInfo(const Settings& settings) +{ + for (const auto& [name, weaponType] : WEAPON_TYPES) + { + if ((int)weaponType <= 0 || (int)weaponType >= (int)LaraWeaponType::NumWeapons) + continue; + + auto& weapon = Weapons[(int)weaponType]; + const auto& weaponSettings = settings.Weapons[(int)weaponType - 1]; // Lua counts from 1. + + weapon.Damage = weaponSettings.Damage; + weapon.AlternateDamage = weaponSettings.AlternateDamage; + weapon.FlashTime = weaponSettings.FlashDuration; + weapon.GunHeight = weaponSettings.WaterLevel; + weapon.ShotAccuracy = ANGLE(weaponSettings.Accuracy); + weapon.TargetDist = weaponSettings.Distance; + weapon.RecoilFrame = weaponSettings.Interval; + } +} + void InitializeNewWeapon(ItemInfo& laraItem) { auto& player = *GetLaraInfo(&laraItem); @@ -539,7 +560,7 @@ void HandleWeapon(ItemInfo& laraItem) player.Control.Weapon.RequestGunType = player.Control.Weapon.LastGunType; } // Draw flare. - else if (IsHeld(In::Flare) && (g_GameFlow->GetLevel(CurrentLevel)->GetLaraType() != LaraType::Young)) + else if (IsHeld(In::Flare)) { if (player.Control.Weapon.GunType == LaraWeaponType::Flare) { @@ -882,7 +903,6 @@ FireWeaponType FireWeapon(LaraWeaponType weaponType, ItemInfo& targetEntity, Ite } else { - SaveGame::Statistics.Game.AmmoHits++; target = origin + (directionNorm * closestDist); auto vTarget = GameVector(target); diff --git a/TombEngine/Game/Lara/lara_fire.h b/TombEngine/Game/Lara/lara_fire.h index 662d4b359..51a6a1934 100644 --- a/TombEngine/Game/Lara/lara_fire.h +++ b/TombEngine/Game/Lara/lara_fire.h @@ -4,6 +4,9 @@ class EulerAngles; struct CollisionInfo; struct ItemInfo; +namespace TEN::Scripting { struct Settings; }; + +using namespace TEN::Scripting; enum class FireWeaponType { @@ -40,13 +43,14 @@ struct WeaponInfo int FlashTime = 0; int DrawFrame = 0; int SampleNum = 0; - int ExplosiveDamage = 0; + int AlternateDamage = 0; }; extern int FlashGrenadeAftershockTimer; extern WeaponInfo Weapons[(int)LaraWeaponType::NumWeapons]; void InitializeNewWeapon(ItemInfo& laraItem); +void InitializeWeaponInfo(const Settings& settings); const WeaponInfo& GetWeaponInfo(LaraWeaponType weaponType); Ammo& GetAmmo(LaraInfo& lara, LaraWeaponType weaponType); diff --git a/TombEngine/Game/Lara/lara_flare.cpp b/TombEngine/Game/Lara/lara_flare.cpp index aae02115e..0e99f0e11 100644 --- a/TombEngine/Game/Lara/lara_flare.cpp +++ b/TombEngine/Game/Lara/lara_flare.cpp @@ -15,14 +15,16 @@ #include "Game/Lara/lara_tests.h" #include "Game/Setup.h" #include "Math/Math.h" +#include "Objects/Effects/LensFlare.h" +#include "Scripting/Include/Flow/ScriptInterfaceFlowHandler.h" #include "Sound/sound.h" #include "Specific/clock.h" #include "Specific/level.h" using namespace TEN::Collision::Point; +using namespace TEN::Entities::Effects; using namespace TEN::Math; -constexpr auto FLARE_LIFE_MAX = 60.0f * FPS; constexpr auto FLARE_DEATH_DELAY = 1.0f * FPS; void FlareControl(short itemNumber) @@ -62,15 +64,17 @@ void FlareControl(short itemNumber) } else { - flareItem.Animation.Velocity.y += 6; + flareItem.Animation.Velocity.y += g_GameFlow->GetSettings()->Physics.Gravity; } flareItem.Pose.Position.y += flareItem.Animation.Velocity.y; DoProjectileDynamics(itemNumber, prevPos.x, prevPos.y, prevPos.z, vel.x, vel.y, vel.z); + const auto& settings = g_GameFlow->GetSettings()->Flare; + int& life = flareItem.Data; life &= 0x7FFF; - if (life >= FLARE_LIFE_MAX) + if (life >= (settings.Timeout * FPS)) { if (flareItem.Animation.Velocity.y == 0.0f && flareItem.Animation.Velocity.z == 0.0f) @@ -84,7 +88,9 @@ void FlareControl(short itemNumber) life++; } - if (DoFlareLight(flareItem.Pose.Position, life)) + auto offset = settings.Offset.ToVector3i() + Vector3i(-6, 6, 0); + auto lightPos = GetJointPosition(flareItem, 0, offset); + if (DoFlareLight(flareItem, lightPos, life)) { TriggerChaffEffects(flareItem, life); life |= 0x8000; @@ -376,10 +382,14 @@ void CreateFlare(ItemInfo& laraItem, GAME_OBJECT_ID objectID, bool isThrown) flareItem.Data = (int)0; int& life = flareItem.Data; - if (DoFlareLight(flareItem.Pose.Position, lara.Flare.Life)) + if (DoFlareLight(flareItem, flareItem.Pose.Position, lara.Flare.Life)) + { life = lara.Flare.Life | 0x8000; + } else + { life = lara.Flare.Life & 0x7FFF; + } } else { @@ -392,14 +402,16 @@ void CreateFlare(ItemInfo& laraItem, GAME_OBJECT_ID objectID, bool isThrown) void DoFlareInHand(ItemInfo& laraItem, int flareLife) { - auto& lara = *GetLaraInfo(&laraItem); + auto& player = *GetLaraInfo(&laraItem); + const auto& settings = g_GameFlow->GetSettings()->Flare; + + auto offset = settings.Offset.ToVector3i() + Vector3i(11, 32, 0); + auto lightPos = GetJointPosition(&laraItem, LM_LHAND, offset); - auto pos = GetJointPosition(&laraItem, LM_LHAND, Vector3i(11, 32, 41)); + if (DoFlareLight(laraItem, lightPos, flareLife)) + TriggerChaffEffects(player.Control.Look.IsUsingBinoculars ? 0 : flareLife); - if (DoFlareLight(pos, flareLife)) - TriggerChaffEffects(lara.Control.Look.IsUsingBinoculars ? 0 : flareLife); - - if (lara.Flare.Life >= FLARE_LIFE_MAX - (FLARE_DEATH_DELAY / 2)) + if (player.Flare.Life >= ((settings.Timeout * FPS) - (FLARE_DEATH_DELAY / 2))) { // Prevent player from intercepting reach/jump states with flare throws. if (laraItem.Animation.IsAirborne || @@ -409,16 +421,16 @@ void DoFlareInHand(ItemInfo& laraItem, int flareLife) return; } - if (lara.Control.HandStatus == HandStatus::Free) - lara.Control.HandStatus = HandStatus::WeaponUndraw; + if (player.Control.HandStatus == HandStatus::Free) + player.Control.HandStatus = HandStatus::WeaponUndraw; } - else if (lara.Flare.Life != 0) + else if (player.Flare.Life != 0) { - lara.Flare.Life++; + player.Flare.Life++; } } -bool DoFlareLight(const Vector3i& pos, int flareLife) +bool DoFlareLight(ItemInfo& item, const Vector3i& pos, int flareLife) { constexpr auto START_DELAY = 0.25f * FPS; constexpr auto END_DELAY = 3.0f * FPS; @@ -427,18 +439,22 @@ bool DoFlareLight(const Vector3i& pos, int flareLife) constexpr auto CHAFF_SPAWN_CHANCE = 4 / 10.0f; constexpr auto CHAFF_SPAWN_ENDING_CHANCE = CHAFF_SPAWN_CHANCE / 2; constexpr auto CHAFF_SPAWN_DYING_CHANCE = CHAFF_SPAWN_CHANCE / 4; - constexpr auto LIGHT_RADIUS = 9.0f; constexpr auto LIGHT_SPHERE_RADIUS = BLOCK(1 / 16.0f); constexpr auto LIGHT_POS_OFFSET = Vector3(0.0f, -BLOCK(1 / 8.0f), 0.0f); - constexpr auto LIGHT_COLOR = Vector3(0.9f, 0.5f, 0.3f); - if (flareLife >= FLARE_LIFE_MAX || flareLife == 0) + auto& settings = g_GameFlow->GetSettings()->Flare; + + float flareRange = settings.Range * BLOCK(0.25f); + auto flareColor = Vector3(settings.Color); + int flareTimeout = settings.Timeout * FPS; + + if (flareLife >= flareTimeout || flareLife == 0) return false; // Determine flare progress. bool isStarting = (flareLife <= START_DELAY); - bool isEnding = (flareLife > (FLARE_LIFE_MAX - END_DELAY)); - bool isDying = (flareLife > (FLARE_LIFE_MAX - FLARE_DEATH_DELAY)); + bool isEnding = (flareLife > (flareTimeout - END_DELAY)); + bool isDying = (flareLife > (flareTimeout - FLARE_DEATH_DELAY)); bool spawnChaff = false; float mult = 1.0f; @@ -450,7 +466,7 @@ bool DoFlareLight(const Vector3i& pos, int flareLife) } else if (isDying) { - mult = (FLARE_LIFE_MAX - (float)flareLife) / FLARE_DEATH_DELAY; + mult = (flareTimeout - (float)flareLife) / FLARE_DEATH_DELAY; spawnChaff = Random::TestProbability(CHAFF_SPAWN_DYING_CHANCE); } else if (isEnding) @@ -464,15 +480,38 @@ bool DoFlareLight(const Vector3i& pos, int flareLife) } // Determine light position. - auto sphere = BoundingSphere(pos.ToVector3() + LIGHT_POS_OFFSET, LIGHT_SPHERE_RADIUS); - auto lightPos = Random::GeneratePointInSphere(sphere); + auto lightPos = pos.ToVector3(); + float intensity = 1.0f; + + // Handle flicker effect if specified. + if (settings.Flicker) + { + auto sphere = BoundingSphere(pos.ToVector3() + LIGHT_POS_OFFSET, LIGHT_SPHERE_RADIUS); + lightPos = Random::GeneratePointInSphere(sphere); + intensity = Random::GenerateFloat(INTENSITY_MIN, INTENSITY_MAX); + } // Calculate color. - float intensity = Random::GenerateFloat(INTENSITY_MIN, INTENSITY_MAX); - float falloff = intensity * mult * LIGHT_RADIUS; - auto color = (LIGHT_COLOR * intensity * std::clamp(mult, 0.0f, 1.0f)) * UCHAR_MAX; + float falloff = intensity * mult * flareRange; + auto color = (flareColor * intensity * std::clamp(mult, 0.0f, 1.0f)); - TriggerDynamicLight(lightPos.x, lightPos.y, lightPos.z, (int)falloff, color.x, color.y, color.z); + // Spawn dynamic light. + TriggerDynamicPointLight(lightPos, Color(color), falloff, false); + + // Spawn lensflare if brightness is not 0. + if (settings.LensflareBrightness > EPSILON) + { + if (item.ObjectNumber == GAME_OBJECT_ID::ID_FLARE_ITEM) + { + float currentIntensity = (float)item.ItemFlags[0] / LENSFLARE_ITEMFLAG_BRIGHTNESS_SCALE; + SetupLensFlare(pos.ToVector3(), item.RoomNumber, Color(color) * settings.LensflareBrightness, ¤tIntensity, 0); + item.ItemFlags[0] = short(currentIntensity * LENSFLARE_ITEMFLAG_BRIGHTNESS_SCALE); + } + else + { + SetupLensFlare(pos.ToVector3(), item.RoomNumber, Color(color) * settings.LensflareBrightness, nullptr, 0); + } + } // Return chaff spawn status. return ((isDying || isEnding) ? spawnChaff : true); diff --git a/TombEngine/Game/Lara/lara_flare.h b/TombEngine/Game/Lara/lara_flare.h index f3aa4d2b8..fa47b0f19 100644 --- a/TombEngine/Game/Lara/lara_flare.h +++ b/TombEngine/Game/Lara/lara_flare.h @@ -18,4 +18,4 @@ void SetFlareArm(ItemInfo& laraItem, int armFrame); void CreateFlare(ItemInfo& laraItem, GAME_OBJECT_ID objectID, bool isThrown); void DoFlareInHand(ItemInfo& laraItem, int flareLife); -bool DoFlareLight(const Vector3i& pos, int flareLife); +bool DoFlareLight(ItemInfo& item, const Vector3i& pos, int flareLife); diff --git a/TombEngine/Game/Lara/lara_helpers.cpp b/TombEngine/Game/Lara/lara_helpers.cpp index b3feabf88..288703527 100644 --- a/TombEngine/Game/Lara/lara_helpers.cpp +++ b/TombEngine/Game/Lara/lara_helpers.cpp @@ -56,9 +56,8 @@ void HandleLaraMovementParameters(ItemInfo* item, CollisionInfo* coll) auto* lara = GetLaraInfo(item); // Update AFK pose timer. - if (lara->Control.Count.Pose < PLAYER_POSE_TIME && - !(IsHeld(In::Look) || IsOpticActionHeld()) && - g_GameFlow->HasAFKPose()) + if (lara->Control.Count.Pose < (g_GameFlow->GetSettings()->Animations.PoseTimeout * FPS) && + !(IsHeld(In::Look) || IsOpticActionHeld())) { lara->Control.Count.Pose++; } @@ -113,7 +112,7 @@ void HandlePlayerStatusEffects(ItemInfo& item, WaterStatus waterStatus, PlayerWa player.Status.Poison = LARA_POISON_MAX; if (!(Wibble & 0xFF)) - item.HitPoints -= player.Status.Poison; + DoDamage(&item, player.Status.Poison, true); } // Update stamina status. @@ -135,7 +134,7 @@ void HandlePlayerStatusEffects(ItemInfo& item, WaterStatus waterStatus, PlayerWa if (player.Status.Air < 0) { player.Status.Air = -1; - item.HitPoints -= 10; + DoDamage(&item, 10, true); } } } @@ -169,7 +168,7 @@ void HandlePlayerStatusEffects(ItemInfo& item, WaterStatus waterStatus, PlayerWa if (player.Status.Exposure <= 0) { player.Status.Exposure = 0; - item.HitPoints -= 10; + DoDamage(&item, 10, true); } } } @@ -189,7 +188,7 @@ void HandlePlayerStatusEffects(ItemInfo& item, WaterStatus waterStatus, PlayerWa if (player.Status.Exposure <= 0) { player.Status.Exposure = 0; - item.HitPoints -= 10; + DoDamage(&item, 10, true); } } else @@ -212,8 +211,8 @@ void HandlePlayerStatusEffects(ItemInfo& item, WaterStatus waterStatus, PlayerWa if (player.Status.Air < 0) { - item.HitPoints -= 5; player.Status.Air = -1; + DoDamage(&item, 5, true); } if (water.IsCold) @@ -222,7 +221,7 @@ void HandlePlayerStatusEffects(ItemInfo& item, WaterStatus waterStatus, PlayerWa if (player.Status.Exposure <= 0) { player.Status.Exposure = 0; - item.HitPoints -= 10; + DoDamage(&item, 10, true); } } else @@ -248,7 +247,7 @@ void HandlePlayerStatusEffects(ItemInfo& item, WaterStatus waterStatus, PlayerWa if (player.Status.Exposure <= 0) { player.Status.Exposure = 0; - item.HitPoints -= 10; + DoDamage(&item, 10, true); } } } @@ -1028,7 +1027,7 @@ void EasePlayerElevation(ItemInfo* item, int relHeight) // Handle swamp case. if (TestEnvironment(ENV_FLAG_SWAMP, item) && relHeight > 0) { - item->Pose.Position.y += SWAMP_GRAVITY; + item->Pose.Position.y += g_GameFlow->GetSettings()->Physics.Gravity / SWAMP_GRAVITY_COEFF; return; } @@ -1172,7 +1171,7 @@ void DoLaraFallDamage(ItemInfo* item) else { float base = item->Animation.Velocity.y - (LARA_DAMAGE_VELOCITY - 1.0f); - item->HitPoints -= LARA_HEALTH_MAX * (SQUARE(base) / 196.0f); + DoDamage(item, LARA_HEALTH_MAX * (SQUARE(base) / 196.0f)); } float rumblePower = (item->Animation.Velocity.y / LARA_DEATH_VELOCITY) * RUMBLE_POWER_COEFF; @@ -1296,7 +1295,7 @@ short GetPlayerSlideHeadingAngle(ItemInfo* item, CollisionInfo* coll) return coll->Setup.ForwardAngle; // Return slide heading angle. - if (g_GameFlow->HasSlideExtended()) + if (g_GameFlow->GetSettings()->Animations.SlideExtended) { return Geometry::GetSurfaceAspectAngle(pointColl.GetFloorNormal()); } @@ -1489,7 +1488,7 @@ void ModulateLaraSlideVelocity(ItemInfo* item, CollisionInfo* coll) constexpr int minVelocity = 50; constexpr int maxVelocity = LARA_TERMINAL_VELOCITY; - if (g_GameFlow->HasSlideExtended()) + if (g_GameFlow->GetSettings()->Animations.SlideExtended) { auto probe = GetPointCollision(*item); short minSlideAngle = ANGLE(33.75f); @@ -1639,7 +1638,7 @@ void newSetLaraSlideAnimation(ItemInfo* item, CollisionInfo* coll) short headinAngle = GetPlayerSlideHeadingAngle(item, coll); short deltaAngle = headinAngle - item->Pose.Orientation.y; - if (!g_GameFlow->HasSlideExtended()) + if (!g_GameFlow->GetSettings()->Animations.SlideExtended) item->Pose.Orientation.y = headinAngle; // Snap to height upon slide entrance. @@ -1702,7 +1701,7 @@ void SetLaraSwimDiveAnimation(ItemInfo* item) SetAnimation(item, LA_ONWATER_DIVE); item->Animation.TargetState = LS_UNDERWATER_SWIM_FORWARD; - item->Animation.Velocity.y = LARA_SWIM_VELOCITY_MAX * 0.4f; + item->Animation.Velocity.y = g_GameFlow->GetSettings()->Physics.SwimVelocity * 0.4f; item->Pose.Orientation.x = -ANGLE(45.0f); lara->Control.WaterStatus = WaterStatus::Underwater; } diff --git a/TombEngine/Game/Lara/lara_jump.cpp b/TombEngine/Game/Lara/lara_jump.cpp index 5b940035f..07d0eff87 100644 --- a/TombEngine/Game/Lara/lara_jump.cpp +++ b/TombEngine/Game/Lara/lara_jump.cpp @@ -744,7 +744,7 @@ void lara_as_swan_dive(ItemInfo* item, CollisionInfo* coll) if (item->HitPoints <= 0) item->Animation.TargetState = LS_DEATH; else if ((IsHeld(In::Crouch) || CanCrawlspaceDive(*item, *coll)) && - g_GameFlow->HasCrawlspaceDive()) + g_GameFlow->GetSettings()->Animations.CrawlspaceDive) { item->Animation.TargetState = LS_CROUCH_IDLE; TranslateItem(item, coll->Setup.ForwardAngle, CLICK(0.5f)); // HACK: Move forward to avoid standing up or falling out on an edge. @@ -773,7 +773,7 @@ void lara_col_swan_dive(ItemInfo* item, CollisionInfo* coll) auto& player = GetLaraInfo(*item); auto bounds = GameBoundingBox(item); - int realHeight = g_GameFlow->HasCrawlspaceDive() ? (bounds.GetHeight() * 0.7f) : LARA_HEIGHT; + int realHeight = g_GameFlow->GetSettings()->Animations.CrawlspaceDive ? (bounds.GetHeight() * 0.7f) : LARA_HEIGHT; player.Control.MoveAngle = item->Pose.Orientation.y; coll->Setup.Height = std::max(LARA_HEIGHT_CRAWL, realHeight); diff --git a/TombEngine/Game/Lara/lara_one_gun.cpp b/TombEngine/Game/Lara/lara_one_gun.cpp index d3771a6cb..b4a494ec3 100644 --- a/TombEngine/Game/Lara/lara_one_gun.cpp +++ b/TombEngine/Game/Lara/lara_one_gun.cpp @@ -63,9 +63,7 @@ constexpr auto HK_BURST_MODE_SHOT_COUNT = 5; constexpr auto HK_BURST_AND_SNIPER_MODE_SHOT_INTERVAL = 12.0f; constexpr auto HK_RAPID_MODE_SHOT_INTERVAL = 3.0f; -constexpr auto SHOTGUN_PELLET_COUNT = 6; -constexpr auto SHOTGUN_NORMAL_PELLET_SCATTER = 10.0f; -constexpr auto SHOTGUN_WIDESHOT_PELLET_SCATTER = 30.0f; +constexpr auto SHOTGUN_PELLET_COUNT = 6; static Vector3i GetWeaponSmokeRelOffset(LaraWeaponType weaponType) { @@ -223,7 +221,7 @@ void AnimateShotgun(ItemInfo& laraItem, LaraWeaponType weaponType) } else { - FireHK(laraItem, 0); + FireHK(laraItem, false); player.Control.Weapon.Timer = 1.0f; item.Animation.TargetState = WEAPON_STATE_RECOIL; @@ -304,7 +302,7 @@ void AnimateShotgun(ItemInfo& laraItem, LaraWeaponType weaponType) } else { - FireHK(laraItem, 1); + FireHK(laraItem, true); player.Control.Weapon.Timer = 1.0f; item.Animation.TargetState = WEAPON_STATE_UNDERWATER_RECOIL; @@ -387,8 +385,8 @@ void FireShotgun(ItemInfo& laraItem) armOrient += EulerAngles(player.ExtraTorsoRot.x, player.ExtraTorsoRot.y, 0); bool hasFired = false; - int scatter = ((player.Weapons[(int)LaraWeaponType::Shotgun].SelectedAmmo == WeaponAmmoType::Ammo1) ? - ANGLE(SHOTGUN_NORMAL_PELLET_SCATTER) : ANGLE(SHOTGUN_WIDESHOT_PELLET_SCATTER)); + int scatter = Weapons[(int)LaraWeaponType::Shotgun].ShotAccuracy * + (player.Weapons[(int)LaraWeaponType::Shotgun].SelectedAmmo == WeaponAmmoType::Ammo1) ? 1 : 3; for (int i = 0; i < SHOTGUN_PELLET_COUNT; i++) { @@ -433,6 +431,7 @@ void FireShotgun(ItemInfo& laraItem) Rumble(0.5f, 0.2f); + SaveGame::Statistics.Level.AmmoUsed++; SaveGame::Statistics.Game.AmmoUsed++; } } @@ -851,7 +850,7 @@ void GrenadeControl(short itemNumber) grenadeItem.Pose.Orientation.y = sYOrient; } - HandleProjectile(grenadeItem, *LaraItem, prevPos, (ProjectileType)grenadeItem.ItemFlags[0], Weapons[(int)LaraWeaponType::GrenadeLauncher].ExplosiveDamage); + HandleProjectile(grenadeItem, *LaraItem, prevPos, (ProjectileType)grenadeItem.ItemFlags[0], Weapons[(int)LaraWeaponType::GrenadeLauncher].Damage); } void FireRocket(ItemInfo& laraItem) @@ -990,7 +989,7 @@ void RocketControl(short itemNumber) auto prevPos = rocketItem.Pose.Position; TranslateItem(&rocketItem, rocketItem.Pose.Orientation, rocketItem.Animation.Velocity.z); - HandleProjectile(rocketItem, *LaraItem, prevPos, ProjectileType::Explosive, Weapons[(int)LaraWeaponType::RocketLauncher].ExplosiveDamage); + HandleProjectile(rocketItem, *LaraItem, prevPos, ProjectileType::Explosive, Weapons[(int)LaraWeaponType::RocketLauncher].Damage); } void FireCrossbow(ItemInfo& laraItem, const std::optional