mirror of
https://github.com/TombEngine/TombEngine.git
synced 2025-04-28 15:57:59 +03:00
Merge branch 'develop' into voncroy_reworked
This commit is contained in:
commit
c9ec3150ec
77 changed files with 916 additions and 774 deletions
61
CHANGELOG.md
61
CHANGELOG.md
|
@ -1,6 +1,6 @@
|
|||
# Changelog
|
||||
|
||||
Here you will find the full changelog of TEN's releases from Version 1.0 and up
|
||||
Here you will find the full changelog of TEN's releases from Version 1.0 and up
|
||||
|
||||
The dates are in European standard format where date is presented as **YYYY-MM-DD**
|
||||
|
||||
|
@ -10,6 +10,16 @@ TombEngine releases are located in this repository (alongside with Tomb Editor):
|
|||
|
||||
### Bug fixes
|
||||
* Fixed original issue with classic switch off trigger incorrectly activating some trigger actions.
|
||||
* Fixed moveable status after antitriggering.
|
||||
* Fixed leveljump vehicle transfer.
|
||||
* Fixed weapons not properly hitting enemies.
|
||||
* Fixed laserhead teleporting Lara and making her invisible on death.
|
||||
* Fixed sarcophagus pick-ups.
|
||||
* Fixed issue with Lara not rotating together with bridges while picking up items.
|
||||
* Fixed ghost collision with moveables with zero bounds.
|
||||
* Fixed several binocular bugs.
|
||||
* Fixed incorrect climbing out of water on bridge objects.
|
||||
* Fixed faulty death sectors.
|
||||
* Fixed incorrect diving animation when swandiving from a high place.
|
||||
* Fixed camera rotating with the player's hips when climbing out of water.
|
||||
* Fixed AI for TR2 skidoo driver and worker with shotgun.
|
||||
|
@ -26,36 +36,45 @@ TombEngine releases are located in this repository (alongside with Tomb Editor):
|
|||
* Fixed teeth spikes not triggering the player impale animation.
|
||||
* Fixed TR4 mine crash with OCB 1 when triggered.
|
||||
* Fixed cases where Atlantean mutant's bombs cause the game to crash.
|
||||
* Fixed young hair drawing.
|
||||
* Fixed young Lara hair drawing. https://tombengine.com/docs/level-settings/#young_lara
|
||||
|
||||
### Features/Amendments
|
||||
* Changed Rome Hammer to not hurt player whilst deactivated.
|
||||
* Changed Statue with blade damage, from 20 to 200.
|
||||
* Enhanced Rolling Spindle detection to avoid them going down through pits.
|
||||
* Enhanced Sentry Guns, with a new ItemFlags[3], to contain the ID of the inventory item that deactivates the sentry guns ( by default PUZZLE_ITEM5 )
|
||||
* Enhanced Dart Emitter, with a new ItemFlags[0], to contain the number of frames between shots ( by default 32 in dart emitter, and 24 in homing dar emitter ).
|
||||
* Enhanced raptor behaviour and handling.
|
||||
- OCB 0: Classic behaviour
|
||||
- OCB 1: Can jump up/down up to 4 steps and jump across gaps up to 2 blocks wide.
|
||||
- You must use this version: https://github.com/TombEngine/Resources/raw/main/Wad2%20Objects/Enemies/TEN_Raptor.wad2
|
||||
* Added TR3 seal mutant.
|
||||
- OCB 0: Normal enemy behaviour. (TR3 RX-Tech mines level)
|
||||
- OCB 1: Trap like behaviour. (TR3 Antarctica level)
|
||||
|
||||
* Added variable framerate , that allows the engine to run at an unlocked framerate for a much smoother experience. Setting can be toggled on or off in the graphical settings menu.
|
||||
* Added a customisable global lensflare effect. https://tombengine.com/docs/level-settings/#lensflare
|
||||
* Added a customisable starry sky and meteor effect (based on TR5). https://tombengine.com/docs/level-settings/#stars
|
||||
* Added the ability to display "Lara's Home" entry in the main menu.
|
||||
* Added F12 as alternative to PrtSc for screenshots.
|
||||
* Added option to enable or disable menu option looping.
|
||||
- Menu scrolling using held inputs will stop at the last option until a new input is made.
|
||||
* Added TR3 seal mutant. https://tombengine.com/docs/ocb-and-setup-instructions/#sealmutant
|
||||
- You must use this version: https://github.com/TombEngine/Resources/raw/main/Wad2%20Objects/Enemies/TEN_Seal_Mutant.wad2
|
||||
* Add new sound conditions: Quicksand and Underwater.
|
||||
- Quicksand - sound effect plays when a moveable is in quicksand.
|
||||
- Underwater - sound plays when the camera is submerged.
|
||||
* Added TR4 Enemy_Jeep https://tombengine.com/docs/ocb-and-setup-instructions/#enemy_jeep
|
||||
* Changed Rome Hammer to not hurt player whilst deactivated.
|
||||
* Changed Statue with blade damage, from 20 to 200.
|
||||
* Changed sound effect that is triggered when using the `level.rumble` feature in a level. Sound effect now part of the default soundmap (ID 359) and additional hardcoded pitch shift has been removed.
|
||||
* Changed hardcoded sound for RAISING_BLOCKS back to the soundID used in TRLE (ID 149)
|
||||
* Changed Water sound condition to ShallowWater.
|
||||
* Added option to enable or disable menu option looping.
|
||||
* Menu scrolling using held inputs will stop at the last option until a new input is made.
|
||||
* Added the ability to display "Lara's Home" entry in the main menu.
|
||||
|
||||
* Enhanced Rolling Spindle detection to avoid them going down through pits.
|
||||
* Enhanced Sentry Guns, with a new ItemFlags[3], to contain the ID of the inventory item that deactivates the sentry guns ( by default PUZZLE_ITEM5 )
|
||||
* Enhanced Dart Emitter, with a new ItemFlags[0], to contain the number of frames between shots ( by default 32 in dart emitter, and 24 in homing-dart emitter ).
|
||||
* Enhanced raptor behaviour and handling. https://tombengine.com/docs/ocb-and-setup-instructions/#raptor
|
||||
- You must use this version: https://github.com/TombEngine/Resources/raw/main/Wad2%20Objects/Enemies/TEN_Raptor.wad2
|
||||
* The limit of 32 active Flame Emitters has been removed.
|
||||
|
||||
### Lua API changes
|
||||
* Added Flow.EnableHomeLevel() function.
|
||||
* Added Flow.IsStringPresent() function.
|
||||
* Added Flow.LensFlare() and Flow.Starfield() classes.
|
||||
* Added Inventory.GetUsedItem(), Inventory.SetUsedItem() and Inventory.ClearUsedItem() functions.
|
||||
* Added Input.KeyClearAll()
|
||||
* Added Flow.EnableHomeLevel()
|
||||
* Added Input.KeyClearAll() function.
|
||||
* Added Moveable.GetJointRotation() and optional 'offset' parameter for Moveable.GetJointPosition().
|
||||
* Added Room:GetRoomNumber() function.
|
||||
* Removed anims.monkeyAutoJump. It is now a player menu configuration.
|
||||
* Fixed Volume:GetActive() method
|
||||
* Fixed Volume:GetActive() method.
|
||||
|
||||
## [Version 1.4](https://github.com/TombEngine/TombEditorReleases/releases/tag/v1.7.1) - 2024-04-21
|
||||
|
||||
|
|
|
@ -234,6 +234,10 @@ scripts too.</p>
|
|||
<td class="summary">Get translated string.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#IsStringPresent">IsStringPresent(string)</a></td>
|
||||
<td class="summary">Check if translated string is present.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#SetLanguageNames">SetLanguageNames(table)</a></td>
|
||||
<td class="summary">Set language names for translations.</td>
|
||||
</tr>
|
||||
|
@ -927,6 +931,28 @@ You will not need to call them manually.
|
|||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "IsStringPresent"></a>
|
||||
<strong>IsStringPresent(string)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Check if translated string is present.
|
||||
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">string</span>
|
||||
<span class="types"><span class="type">key</span></span>
|
||||
key for translated string
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "SetLanguageNames"></a>
|
||||
|
|
|
@ -108,7 +108,7 @@ pickups, and Lara herself (see also <a href="../2 classes/Objects.LaraObject.htm
|
|||
<h2><a href="#Functions">Functions</a></h2>
|
||||
<table class="function_list">
|
||||
<tr>
|
||||
<td class="name" ><a href="#Moveable">Moveable(object, name, position, rotation, roomID, animNumber, frameNumber, hp, OCB, AIBits)</a></td>
|
||||
<td class="name" ><a href="#Moveable">Moveable(object, name, position, rotation, roomNumber, animNumber, frameNumber, hp, OCB, AIBits)</a></td>
|
||||
<td class="summary">Used to generate a new moveable dynamically at runtime.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -390,7 +390,7 @@ pickups, and Lara herself (see also <a href="../2 classes/Objects.LaraObject.htm
|
|||
<dl class="function">
|
||||
<dt>
|
||||
<a name = "Moveable"></a>
|
||||
<strong>Moveable(object, name, position, rotation, roomID, animNumber, frameNumber, hp, OCB, AIBits)</strong>
|
||||
<strong>Moveable(object, name, position, rotation, roomNumber, animNumber, frameNumber, hp, OCB, AIBits)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Used to generate a new moveable dynamically at runtime. <br/>
|
||||
|
@ -418,9 +418,9 @@ most can just be ignored (see usage).
|
|||
<span class="types"><a class="type" href="../3 primitive classes/Rotation.html#">Rotation</a></span>
|
||||
rotation rotation about x, y, and z axes (default Rotation(0, 0, 0))
|
||||
</li>
|
||||
<li><span class="parameter">roomID</span>
|
||||
<li><span class="parameter">roomNumber</span>
|
||||
<span class="types"><span class="type">int</span></span>
|
||||
room ID item is in (default: calculated automatically)
|
||||
the room number the moveable is in (default: calculated automatically).
|
||||
</li>
|
||||
<li><span class="parameter">animNumber</span>
|
||||
<span class="types"><span class="type">int</span></span>
|
||||
|
|
|
@ -100,7 +100,7 @@
|
|||
<div id="content">
|
||||
|
||||
<h1>Class <code>Objects.Room</code></h1>
|
||||
<p>Rooms</p>
|
||||
<p>Room object.</p>
|
||||
<p>
|
||||
|
||||
</p>
|
||||
|
@ -109,8 +109,12 @@
|
|||
<h2><a href="#Functions">Functions</a></h2>
|
||||
<table class="function_list">
|
||||
<tr>
|
||||
<td class="name" ><a href="#Room:GetActive">Room:GetActive()</a></td>
|
||||
<td class="summary">Determine whether the room is active or not</td>
|
||||
<td class="name" ><a href="#Room:GetRoomNumber">Room:GetRoomNumber()</a></td>
|
||||
<td class="summary">Get the room's number.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Room:GetName">Room:GetName()</a></td>
|
||||
<td class="summary">Get the room's unique string identifier.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Room:GetColor">Room:GetColor()</a></td>
|
||||
|
@ -121,28 +125,28 @@
|
|||
<td class="summary">Get the room's reverb type.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Room:SetReverbType">Room:SetReverbType(new)</a></td>
|
||||
<td class="name" ><a href="#Room:SetName">Room:SetName(name)</a></td>
|
||||
<td class="summary">Set the room's unique string identifier.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Room:SetReverbType">Room:SetReverbType(Reverb)</a></td>
|
||||
<td class="summary">Set the room's reverb type.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Room:GetName">Room:GetName()</a></td>
|
||||
<td class="summary">Get the room's unique string identifier.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Room:SetName">Room:SetName(name)</a></td>
|
||||
<td class="summary">Set the room's name (its unique string identifier).</td>
|
||||
<td class="name" ><a href="#Room:SetFlag">Room:SetFlag(flagID, Boolean)</a></td>
|
||||
<td class="summary">Set the room's specified flag.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Room:GetFlag">Room:GetFlag(flagID)</a></td>
|
||||
<td class="summary">Get the room's specified flag value (true or false).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Room:SetFlag">Room:SetFlag(flagID, the)</a></td>
|
||||
<td class="summary">Set the room's specified flag value.</td>
|
||||
<td class="name" ><a href="#Room:IsTagPresent">Room:IsTagPresent(tag)</a></td>
|
||||
<td class="summary">Check if the specified tag is set for the room.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="#Room:IsTagPresent">Room:IsTagPresent(tag)</a></td>
|
||||
<td class="summary">Checks if specified tag is set for this room.</td>
|
||||
<td class="name" ><a href="#Room:GetActive">Room:GetActive()</a></td>
|
||||
<td class="summary">Check if the room is active.</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
@ -154,11 +158,11 @@
|
|||
|
||||
<dl class="function">
|
||||
<dt>
|
||||
<a name = "Room:GetActive"></a>
|
||||
<strong>Room:GetActive()</strong>
|
||||
<a name = "Room:GetRoomNumber"></a>
|
||||
<strong>Room:GetRoomNumber()</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Determine whether the room is active or not
|
||||
Get the room's number. ()
|
||||
|
||||
|
||||
|
||||
|
@ -166,8 +170,29 @@
|
|||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><span class="type">bool</span></span>
|
||||
true if the room is active
|
||||
<span class="types"><span class="type">int</span></span>
|
||||
Room number.
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "Room:GetName"></a>
|
||||
<strong>Room:GetName()</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Get the room's unique string identifier. ()
|
||||
|
||||
|
||||
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span>
|
||||
Room name.
|
||||
</ol>
|
||||
|
||||
|
||||
|
@ -179,7 +204,7 @@
|
|||
<strong>Room:GetColor()</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Get the room's ambient light color.
|
||||
Get the room's ambient light color. ()
|
||||
|
||||
|
||||
|
||||
|
@ -188,7 +213,7 @@
|
|||
<ol>
|
||||
|
||||
<span class="types"><a class="type" href="../3 primitive classes/Color.html#">Color</a></span>
|
||||
ambient light color of the room
|
||||
Ambient light color.
|
||||
</ol>
|
||||
|
||||
|
||||
|
@ -200,7 +225,7 @@
|
|||
<strong>Room:GetReverbType()</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Get the room's reverb type.
|
||||
Get the room's reverb type. ()
|
||||
|
||||
|
||||
|
||||
|
@ -209,50 +234,7 @@
|
|||
<ol>
|
||||
|
||||
<span class="types"><a class="type" href="../4 enums/Objects.RoomReverb.html#">RoomReverb</a></span>
|
||||
room's reverb type
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "Room:SetReverbType"></a>
|
||||
<strong>Room:SetReverbType(new)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Set the room's reverb type.
|
||||
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">new</span>
|
||||
<span class="types"><a class="type" href="../4 enums/Objects.RoomReverb.html#">RoomReverb</a></span>
|
||||
reverb type of the room
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "Room:GetName"></a>
|
||||
<strong>Room:GetName()</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Get the room's unique string identifier.
|
||||
|
||||
|
||||
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span>
|
||||
the room's name
|
||||
Reverb type.
|
||||
</ol>
|
||||
|
||||
|
||||
|
@ -264,7 +246,7 @@
|
|||
<strong>Room:SetName(name)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Set the room's name (its unique string identifier).
|
||||
Set the room's unique string identifier. ()
|
||||
|
||||
|
||||
|
||||
|
@ -272,7 +254,55 @@
|
|||
<ul>
|
||||
<li><span class="parameter">name</span>
|
||||
<span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span>
|
||||
The room's new name
|
||||
New name.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "Room:SetReverbType"></a>
|
||||
<strong>Room:SetReverbType(Reverb)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Set the room's reverb type. ()
|
||||
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">Reverb</span>
|
||||
<span class="types"><a class="type" href="../4 enums/Objects.RoomReverb.html#">RoomReverb</a></span>
|
||||
type.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "Room:SetFlag"></a>
|
||||
<strong>Room:SetFlag(flagID, Boolean)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Set the room's specified flag. ()
|
||||
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">flagID</span>
|
||||
<span class="types"><a class="type" href="../4 enums/Objects.RoomFlagID.html#">RoomFlagID</a></span>
|
||||
Room flag ID.
|
||||
</li>
|
||||
<li><span class="parameter">Boolean</span>
|
||||
<span class="types"><span class="type">bool</span></span>
|
||||
to set the flag to.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
@ -286,7 +316,7 @@
|
|||
<strong>Room:GetFlag(flagID)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Get the room's specified flag value (true or false).
|
||||
Get the room's specified flag value (true or false). ()
|
||||
|
||||
|
||||
|
||||
|
@ -294,39 +324,7 @@
|
|||
<ul>
|
||||
<li><span class="parameter">flagID</span>
|
||||
<span class="types"><a class="type" href="../4 enums/Objects.RoomFlagID.html#">RoomFlagID</a></span>
|
||||
The room's flag ID
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><span class="type">bool</span></span>
|
||||
the room's specified flag value
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "Room:SetFlag"></a>
|
||||
<strong>Room:SetFlag(flagID, the)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Set the room's specified flag value.
|
||||
|
||||
|
||||
|
||||
<h3>Parameters:</h3>
|
||||
<ul>
|
||||
<li><span class="parameter">flagID</span>
|
||||
<span class="types"><a class="type" href="../4 enums/Objects.RoomFlagID.html#">RoomFlagID</a></span>
|
||||
The room's flag ID
|
||||
</li>
|
||||
<li><span class="parameter">the</span>
|
||||
<span class="types"><span class="type">bool</span></span>
|
||||
room's new flag value
|
||||
Room flag ID.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
@ -340,7 +338,7 @@
|
|||
<strong>Room:IsTagPresent(tag)</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Checks if specified tag is set for this room.
|
||||
Check if the specified tag is set for the room. ()
|
||||
|
||||
|
||||
|
||||
|
@ -348,7 +346,7 @@
|
|||
<ul>
|
||||
<li><span class="parameter">tag</span>
|
||||
<span class="types"><a class="type" href="https://www.lua.org/manual/5.4/manual.html#6.4">string</a></span>
|
||||
A text tag to check (case sensitive)
|
||||
Text tag to check (case sensitive).
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
@ -356,7 +354,28 @@
|
|||
<ol>
|
||||
|
||||
<span class="types"><span class="type">bool</span></span>
|
||||
true if tag is present, false if not
|
||||
Boolean of the tag's presence.
|
||||
</ol>
|
||||
|
||||
|
||||
|
||||
|
||||
</dd>
|
||||
<dt>
|
||||
<a name = "Room:GetActive"></a>
|
||||
<strong>Room:GetActive()</strong>
|
||||
</dt>
|
||||
<dd>
|
||||
Check if the room is active. ()
|
||||
|
||||
|
||||
|
||||
|
||||
<h3>Returns:</h3>
|
||||
<ol>
|
||||
|
||||
<span class="types"><span class="type">bool</span></span>
|
||||
Boolean of the room's active status.
|
||||
</ol>
|
||||
|
||||
|
||||
|
|
|
@ -171,8 +171,8 @@ LARA_PETROL_MESH
|
|||
LARA_DIRT_MESH
|
||||
LARA_CROWBAR_ANIM
|
||||
LARA_TORCH_ANIM
|
||||
SINGLE_BRAID_HAIR
|
||||
DUAL_PIGTAIL_HAIR
|
||||
HAIR_PRIMARY
|
||||
HAIR_SECONDARY
|
||||
SNOWMOBILE_LARA_ANIMS
|
||||
SNOWMOBILE
|
||||
QUAD_LARA_ANIMS
|
||||
|
|
|
@ -217,7 +217,7 @@ local door = GetMoveableByName("door_type4_14")
|
|||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="2 classes/Objects.Room.html">Objects.Room</a></td>
|
||||
<td class="summary">Rooms</td>
|
||||
<td class="summary">Room object.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="name" ><a href="2 classes/Objects.Sink.html">Objects.Sink</a></td>
|
||||
|
|
|
@ -71,7 +71,7 @@ namespace TEN::Entities::Player
|
|||
PlayerBehaviorStateRoutines[LS_PUSHABLE_PUSH] = std::pair(lara_as_pushable_push, lara_default_col);
|
||||
PlayerBehaviorStateRoutines[LS_PUSHABLE_PULL] = std::pair(lara_as_pushable_pull, lara_default_col);
|
||||
PlayerBehaviorStateRoutines[LS_PUSHABLE_GRAB] = std::pair(lara_as_pushable_grab, lara_default_col);
|
||||
PlayerBehaviorStateRoutines[LS_PICKUP] = std::pair(lara_as_pickup, lara_default_col);
|
||||
PlayerBehaviorStateRoutines[LS_PICKUP] = std::pair(lara_as_pickup, lara_col_pickup);
|
||||
PlayerBehaviorStateRoutines[LS_SWITCH_DOWN] = std::pair(lara_as_switch_on, lara_default_col);
|
||||
PlayerBehaviorStateRoutines[LS_SWITCH_UP] = std::pair(lara_as_switch_off, lara_default_col);
|
||||
PlayerBehaviorStateRoutines[LS_INSERT_KEY] = std::pair(lara_as_use_key, lara_default_col);
|
||||
|
@ -99,7 +99,7 @@ namespace TEN::Entities::Player
|
|||
PlayerBehaviorStateRoutines[LS_TEST_3] = std::pair(lara_void_func, lara_void_func);
|
||||
PlayerBehaviorStateRoutines[LS_WADE_FORWARD] = std::pair(lara_as_wade_forward, lara_col_wade_forward);
|
||||
PlayerBehaviorStateRoutines[LS_UNDERWATER_ROLL] = std::pair(lara_as_underwater_roll_180, lara_col_underwater_roll_180);
|
||||
PlayerBehaviorStateRoutines[LS_PICKUP_FLARE] = std::pair(lara_as_pickup_flare, lara_default_col);
|
||||
PlayerBehaviorStateRoutines[LS_PICKUP_FLARE] = std::pair(lara_as_pickup_flare, lara_col_pickup);
|
||||
PlayerBehaviorStateRoutines[LS_JUMP_ROLL_180] = std::pair(lara_void_func, lara_void_func);
|
||||
PlayerBehaviorStateRoutines[LS_KICK] = std::pair(lara_void_func, lara_void_func);
|
||||
PlayerBehaviorStateRoutines[LS_ZIP_LINE] = std::pair(lara_as_zip_line, lara_void_func);
|
||||
|
|
|
@ -362,8 +362,6 @@ void LaraAboveWater(ItemInfo* item, CollisionInfo* coll)
|
|||
coll->Setup.PrevFrameNumber = item->Animation.FrameNumber;
|
||||
coll->Setup.PrevState = item->Animation.ActiveState;
|
||||
|
||||
UpdateLaraRoom(item, -LARA_HEIGHT / 2);
|
||||
|
||||
// Handle look-around.
|
||||
if (((IsHeld(In::Look) && CanPlayerLookAround(*item)) ||
|
||||
(player.Control.Look.IsUsingBinoculars || player.Control.Look.IsUsingLasersight)) &&
|
||||
|
@ -378,6 +376,8 @@ void LaraAboveWater(ItemInfo* item, CollisionInfo* coll)
|
|||
}
|
||||
player.Control.Look.Mode = LookMode::None;
|
||||
|
||||
UpdateLaraRoom(item, -LARA_HEIGHT / 2);
|
||||
|
||||
// Process vehicles.
|
||||
if (HandleLaraVehicle(item, coll))
|
||||
return;
|
||||
|
|
|
@ -39,17 +39,7 @@ void lara_void_func(ItemInfo* item, CollisionInfo* coll)
|
|||
|
||||
void lara_default_col(ItemInfo* item, CollisionInfo* coll)
|
||||
{
|
||||
auto& player = GetLaraInfo(*item);
|
||||
|
||||
player.Control.MoveAngle = item->Pose.Orientation.y;
|
||||
coll->Setup.LowerFloorBound = STEPUP_HEIGHT;
|
||||
coll->Setup.UpperFloorBound = -STEPUP_HEIGHT;
|
||||
coll->Setup.LowerCeilingBound = 0;
|
||||
coll->Setup.BlockFloorSlopeDown = true;
|
||||
coll->Setup.BlockFloorSlopeUp = true;
|
||||
coll->Setup.ForwardAngle = player.Control.MoveAngle;
|
||||
GetCollisionInfo(coll, item);
|
||||
LaraResetGravityStatus(item, coll);
|
||||
LaraDefaultCollision(item, coll);
|
||||
}
|
||||
|
||||
// Boulder death.
|
||||
|
|
|
@ -507,6 +507,22 @@ void LaraSurfaceCollision(ItemInfo* item, CollisionInfo* coll)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void LaraDefaultCollision(ItemInfo* item, CollisionInfo* coll)
|
||||
{
|
||||
auto& player = GetLaraInfo(*item);
|
||||
|
||||
player.Control.MoveAngle = item->Pose.Orientation.y;
|
||||
coll->Setup.LowerFloorBound = STEPUP_HEIGHT;
|
||||
coll->Setup.UpperFloorBound = -STEPUP_HEIGHT;
|
||||
coll->Setup.LowerCeilingBound = 0;
|
||||
coll->Setup.BlockFloorSlopeDown = true;
|
||||
coll->Setup.BlockFloorSlopeUp = true;
|
||||
coll->Setup.ForwardAngle = player.Control.MoveAngle;
|
||||
GetCollisionInfo(coll, item);
|
||||
LaraResetGravityStatus(item, coll);
|
||||
}
|
||||
|
||||
void LaraSwimCollision(ItemInfo* item, CollisionInfo* coll)
|
||||
{
|
||||
auto* lara = GetLaraInfo(item);
|
||||
|
|
|
@ -25,6 +25,7 @@ void GetLaraDeadlyBounds();
|
|||
void LaraJumpCollision(ItemInfo* item, CollisionInfo* coll, short moveAngle);
|
||||
void LaraSurfaceCollision(ItemInfo* item, CollisionInfo* coll);
|
||||
void LaraSwimCollision(ItemInfo* item, CollisionInfo* coll);
|
||||
void LaraDefaultCollision(ItemInfo* item, CollisionInfo* coll);
|
||||
|
||||
void LaraWaterCurrent(ItemInfo* item, CollisionInfo* coll);
|
||||
|
||||
|
|
|
@ -13,8 +13,12 @@
|
|||
#include "Game/Lara/PlayerStateMachine.h"
|
||||
#include "Game/Setup.h"
|
||||
#include "Objects/TR2/Vehicles/skidoo.h"
|
||||
#include "Objects/TR2/Vehicles/speedboat.h"
|
||||
#include "Objects/TR3/Vehicles/kayak.h"
|
||||
#include "Objects/TR3/Vehicles/minecart.h"
|
||||
#include "Objects/TR3/Vehicles/quad_bike.h"
|
||||
#include "Objects/TR3/Vehicles/rubber_boat.h"
|
||||
#include "Objects/TR3/Vehicles/upv.h"
|
||||
#include "Objects/TR4/Vehicles/jeep.h"
|
||||
#include "Objects/TR4/Vehicles/motorbike.h"
|
||||
#include "Specific/level.h"
|
||||
|
@ -122,6 +126,9 @@ void InitializeLaraAnims(ItemInfo* item)
|
|||
player.LeftArm.Locked = false;
|
||||
player.RightArm.Locked = false;
|
||||
|
||||
if (PlayerVehicleObjectID != GAME_OBJECT_ID::ID_NO_OBJECT)
|
||||
return;
|
||||
|
||||
if (TestEnvironment(ENV_FLAG_WATER, item))
|
||||
{
|
||||
SetAnimation(item, LA_UNDERWATER_IDLE);
|
||||
|
@ -175,7 +182,7 @@ void InitializeLaraStartPosition(ItemInfo& playerItem)
|
|||
playerItem.Location.Height = playerItem.Pose.Position.y;
|
||||
}
|
||||
|
||||
static void InitializePlayerVehicle(ItemInfo& playerItem)
|
||||
void InitializePlayerVehicle(ItemInfo& playerItem)
|
||||
{
|
||||
if (PlayerVehicleObjectID == GAME_OBJECT_ID::ID_NO_OBJECT)
|
||||
return;
|
||||
|
@ -187,7 +194,6 @@ static void InitializePlayerVehicle(ItemInfo& playerItem)
|
|||
// Restore vehicle.
|
||||
TENLog("Transferring vehicle " + GetObjectName(PlayerVehicleObjectID) + " from the previous level.");
|
||||
vehicle->Pose = playerItem.Pose;
|
||||
ItemNewRoom(vehicle->Index, playerItem.RoomNumber);
|
||||
SetLaraVehicle(&playerItem, vehicle);
|
||||
playerItem.Animation = PlayerAnim;
|
||||
|
||||
|
@ -197,6 +203,7 @@ static void InitializePlayerVehicle(ItemInfo& playerItem)
|
|||
{
|
||||
case GAME_OBJECT_ID::ID_KAYAK:
|
||||
InitializeKayak(vehicle->Index);
|
||||
KayakPaddleTake(GetKayakInfo(&g_Level.Items[vehicle->Index]), &playerItem);
|
||||
break;
|
||||
|
||||
case GAME_OBJECT_ID::ID_MOTORBIKE:
|
||||
|
@ -215,9 +222,38 @@ static void InitializePlayerVehicle(ItemInfo& playerItem)
|
|||
InitializeSkidoo(vehicle->Index);
|
||||
break;
|
||||
|
||||
case GAME_OBJECT_ID::ID_MINECART:
|
||||
MinecartWrenchTake(GetMinecartInfo(&g_Level.Items[vehicle->Index]), &playerItem);
|
||||
break;
|
||||
|
||||
case GAME_OBJECT_ID::ID_SPEEDBOAT:
|
||||
InitializeSpeedboat(vehicle->Index);
|
||||
DoSpeedboatMount(&g_Level.Items[vehicle->Index], &playerItem, VehicleMountType::LevelStart);
|
||||
break;
|
||||
|
||||
case GAME_OBJECT_ID::ID_RUBBER_BOAT:
|
||||
InitializeRubberBoat(vehicle->Index);
|
||||
DoRubberBoatMount(&g_Level.Items[vehicle->Index], &playerItem, VehicleMountType::LevelStart);
|
||||
break;
|
||||
|
||||
case GAME_OBJECT_ID::ID_UPV:
|
||||
DoUPVMount(&g_Level.Items[vehicle->Index], &playerItem, VehicleMountType::LevelStart);
|
||||
GetUPVInfo(&g_Level.Items[vehicle->Index])->Flags = UPVFlags::UPV_FLAG_CONTROL;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// HACK: Reset activity status because boats need to be on active item linked list.
|
||||
|
||||
if (vehicle->ObjectNumber == GAME_OBJECT_ID::ID_RUBBER_BOAT ||
|
||||
vehicle->ObjectNumber == GAME_OBJECT_ID::ID_SPEEDBOAT)
|
||||
{
|
||||
RemoveActiveItem(vehicle->Index, false);
|
||||
AddActiveItem(vehicle->Index);
|
||||
g_Level.Items[vehicle->Index].Status = ITEM_ACTIVE;
|
||||
}
|
||||
}
|
||||
|
||||
void InitializeLaraLevelJump(ItemInfo* item, LaraInfo* playerBackup)
|
||||
|
@ -260,9 +296,6 @@ void InitializeLaraLevelJump(ItemInfo* item, LaraInfo* playerBackup)
|
|||
|
||||
// Restore hit points.
|
||||
item->HitPoints = PlayerHitPoints;
|
||||
|
||||
// Restore vehicle.
|
||||
InitializePlayerVehicle(*item);
|
||||
}
|
||||
|
||||
void InitializeLaraDefaultInventory(ItemInfo& item)
|
||||
|
|
|
@ -9,3 +9,4 @@ void InitializeLaraAnims(ItemInfo* item);
|
|||
void InitializeLaraStartPosition(ItemInfo& playerItem);
|
||||
void InitializeLaraLevelJump(ItemInfo* item, LaraInfo* playerBackup);
|
||||
void InitializeLaraDefaultInventory(ItemInfo& item);
|
||||
void InitializePlayerVehicle(ItemInfo& playerItem);
|
|
@ -8,6 +8,7 @@
|
|||
#include "Game/items.h"
|
||||
#include "Game/Lara/PlayerContext.h"
|
||||
#include "Game/Lara/lara.h"
|
||||
#include "Game/Lara/lara_collide.h"
|
||||
#include "Game/Lara/lara_helpers.h"
|
||||
#include "Game/Lara/lara_tests.h"
|
||||
#include "Objects/Generic/Object/rope.h"
|
||||
|
@ -45,6 +46,12 @@ void lara_as_pickup(ItemInfo* item, CollisionInfo* coll)
|
|||
item->Animation.TargetState = GetNextAnimState(item);
|
||||
}
|
||||
|
||||
void lara_col_pickup(ItemInfo* item, CollisionInfo* coll)
|
||||
{
|
||||
LaraDefaultCollision(item, coll);
|
||||
ShiftItem(item, coll);
|
||||
}
|
||||
|
||||
// State: LS_PICKUP_FLARE (67)
|
||||
// Collision: lara_default_col()
|
||||
void lara_as_pickup_flare(ItemInfo* item, CollisionInfo* coll)
|
||||
|
|
|
@ -14,6 +14,7 @@ struct CollisionInfo;
|
|||
|
||||
void lara_as_pickup(ItemInfo* item, CollisionInfo* coll);
|
||||
void lara_as_pickup_flare(ItemInfo* item, CollisionInfo* coll);
|
||||
void lara_col_pickup(ItemInfo* item, CollisionInfo* coll);
|
||||
|
||||
// ------
|
||||
// SWITCH
|
||||
|
|
|
@ -935,11 +935,11 @@ bool TestLaraWaterClimbOut(ItemInfo* item, CollisionInfo* coll)
|
|||
// Extra bridge check.
|
||||
if (coll->Front.Bridge != NO_VALUE)
|
||||
{
|
||||
int bridgeBorder = GetBridgeBorder(g_Level.Items[coll->Front.Bridge], false) - item->Pose.Position.y;
|
||||
frontFloor = GetBridgeBorder(g_Level.Items[coll->Front.Bridge], false) - item->Pose.Position.y;
|
||||
|
||||
frontFloor = bridgeBorder - CLICK(0.5f);
|
||||
if (frontFloor <= -CLICK(2) ||
|
||||
frontFloor > CLICK(1.25f) - 4)
|
||||
int bridgeBorder = frontFloor - CLICK(0.5f);
|
||||
if (bridgeBorder <= -CLICK(2) ||
|
||||
bridgeBorder > CLICK(1.25f) - 4)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -952,9 +952,19 @@ void BinocularCamera(ItemInfo* item)
|
|||
player.Inventory.IsBusy = false;
|
||||
|
||||
Camera.type = BinocularOldCamera;
|
||||
Camera.target = LastTarget;
|
||||
AlterFOV(LastFOV);
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsHeld(In::Action))
|
||||
{
|
||||
ClearAction(In::Action);
|
||||
|
||||
auto origin = Camera.pos.ToVector3i();
|
||||
auto target = Camera.target.ToVector3i();
|
||||
LaraTorch(&origin, &target, player.ExtraHeadRot.y, 192);
|
||||
}
|
||||
}
|
||||
|
||||
AlterFOV(7 * (ANGLE(11.5f) - player.Control.Look.OpticRange), false);
|
||||
|
@ -1022,13 +1032,6 @@ void BinocularCamera(ItemInfo* item)
|
|||
Camera.oldType = Camera.type;
|
||||
|
||||
GetTargetOnLOS(&Camera.pos, &Camera.target, false, false);
|
||||
|
||||
if (IsHeld(In::Action))
|
||||
{
|
||||
auto origin = Camera.pos.ToVector3i();
|
||||
auto target = Camera.target.ToVector3i();
|
||||
LaraTorch(&origin, &target, player.ExtraHeadRot.y, 192);
|
||||
}
|
||||
}
|
||||
|
||||
void ConfirmCameraTargetPos()
|
||||
|
@ -1518,6 +1521,21 @@ void ItemsCollideCamera()
|
|||
staticList.clear();
|
||||
}
|
||||
|
||||
void UpdateCamera()
|
||||
{
|
||||
if (UseSpotCam)
|
||||
{
|
||||
// Draw flyby cameras.
|
||||
CalculateSpotCameras();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Do the standard camera.
|
||||
TrackCameraInit = false;
|
||||
CalculateCamera(LaraCollision);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateMikePos(const ItemInfo& item)
|
||||
{
|
||||
if (Camera.mikeAtLara)
|
||||
|
@ -1545,7 +1563,8 @@ void UpdateMikePos(const ItemInfo& item)
|
|||
void RumbleScreen()
|
||||
{
|
||||
if (!(GlobalCounter & 0x1FF))
|
||||
SoundEffect(SFX_TR5_KLAXON, nullptr, SoundEnvironment::Land, 0.25f);
|
||||
// SFX Enum Changed from TR5 and pitch shift removed. User can set this in their sound XML. Stranger1992 31st August 2024
|
||||
SoundEffect(SFX_TR4_ENVIORONMENT_RUMBLE, nullptr, SoundEnvironment::Land);
|
||||
|
||||
if (RumbleTimer >= 0)
|
||||
RumbleTimer++;
|
||||
|
|
|
@ -103,16 +103,18 @@ void RumbleScreen();
|
|||
bool TestBoundsCollideCamera(const GameBoundingBox& bounds, const Pose& pose, short radius);
|
||||
void ItemPushCamera(GameBoundingBox* bounds, Pose* pos, short radius);
|
||||
void ItemsCollideCamera();
|
||||
void RefreshFixedCamera(short camNumber);
|
||||
|
||||
void ObjCamera(ItemInfo* camSlotId, int camMeshID, ItemInfo* targetItem, int targetMeshID, bool cond);
|
||||
void MoveObjCamera(GameVector* ideal, ItemInfo* camSlotId, int camMeshID, ItemInfo* targetItem, int targetMeshID);
|
||||
void RefreshFixedCamera(short camNumber);
|
||||
void ClearObjCamera();
|
||||
|
||||
void SetScreenFadeOut(float speed, bool force = false);
|
||||
void SetScreenFadeIn(float speed, bool force = false);
|
||||
void SetCinematicBars(float height, float speed);
|
||||
void ClearCinematicBars();
|
||||
void UpdateCamera();
|
||||
void UpdateFadeScreenAndCinematicBars();
|
||||
void UpdateMikePos(const ItemInfo& item);
|
||||
void ClearObjCamera();
|
||||
|
||||
float GetParticleDistanceFade(const Vector3i& pos);
|
||||
|
|
|
@ -566,6 +566,9 @@ bool TestBoundsCollide(ItemInfo* item, ItemInfo* laraItem, int radius)
|
|||
const auto& bounds = GetBestFrame(*item).BoundingBox;
|
||||
const auto& playerBounds = GetBestFrame(*laraItem).BoundingBox;
|
||||
|
||||
if (bounds.GetExtents() == Vector3::Zero || playerBounds.GetExtents() == Vector3::Zero)
|
||||
return false;
|
||||
|
||||
if ((item->Pose.Position.y + bounds.Y2) <= (laraItem->Pose.Position.y + playerBounds.Y1))
|
||||
return false;
|
||||
|
||||
|
|
|
@ -182,6 +182,10 @@ int FloorInfo::GetSurfaceHeight(int x, int z, bool isFloor) const
|
|||
auto normal = tri.Plane.Normal();
|
||||
float relPlaneHeight = -((normal.x * sectorPoint.x) + (normal.z * sectorPoint.y)) / normal.y;
|
||||
|
||||
// Due to precision loss, we can't recover NO_HEIGHT constant from the plane, and must return original integer constant.
|
||||
if (tri.Plane.D() == (float)NO_HEIGHT)
|
||||
return NO_HEIGHT;
|
||||
|
||||
// Return sector floor or ceiling height. NOTE: Bridges ignored.
|
||||
return (tri.Plane.D() + relPlaneHeight);
|
||||
}
|
||||
|
|
|
@ -27,13 +27,11 @@ using namespace TEN::Effects::Smoke;
|
|||
|
||||
constexpr auto ESCAPE_DIST = BLOCK(5);
|
||||
constexpr auto STALK_DIST = BLOCK(3);
|
||||
constexpr auto REACHED_GOAL_RADIUS = 640;
|
||||
constexpr auto REACHED_GOAL_RADIUS = BLOCK(0.625);
|
||||
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);
|
||||
constexpr auto FEELER_DISTANCE = CLICK(2);
|
||||
constexpr auto FEELER_ANGLE = ANGLE(45.0f);
|
||||
constexpr auto CREATURE_AI_ROTATION_MAX = ANGLE(90.0f);
|
||||
constexpr auto CREATURE_JOINT_ROTATION_MAX = ANGLE(70.0f);
|
||||
|
||||
|
@ -681,14 +679,13 @@ void CreatureJoint(ItemInfo* item, short joint, short required, short maxAngle)
|
|||
if (!item->IsCreature())
|
||||
return;
|
||||
|
||||
constexpr auto MAX_CHANGE = ANGLE(5.0f);
|
||||
auto* creature = GetCreatureInfo(item);
|
||||
|
||||
short change = required - creature->JointRotation[joint];
|
||||
if (change > MAX_CHANGE)
|
||||
change = MAX_CHANGE;
|
||||
else if (change < -MAX_CHANGE)
|
||||
change = -MAX_CHANGE;
|
||||
if (change > ANGLE(3.0f))
|
||||
change = ANGLE(3.0f);
|
||||
else if (change < ANGLE(-3.0f))
|
||||
change = ANGLE(-3.0f);
|
||||
|
||||
creature->JointRotation[joint] += change;
|
||||
if (creature->JointRotation[joint] > maxAngle)
|
||||
|
@ -896,7 +893,7 @@ int CreatureCreature(short itemNumber)
|
|||
{
|
||||
auto* linked = &g_Level.Items[link];
|
||||
|
||||
if (link != itemNumber && linked != LaraItem && linked->Status == ITEM_ACTIVE && linked->HitPoints > 0) // TODO: deal with LaraItem global.
|
||||
if (link != itemNumber && linked != LaraItem && linked->IsCreature() && linked->Status == ITEM_ACTIVE && linked->HitPoints > 0) // TODO: deal with LaraItem global.
|
||||
{
|
||||
int xDistance = abs(linked->Pose.Position.x - x);
|
||||
int zDistance = abs(linked->Pose.Position.z - z);
|
||||
|
@ -1044,7 +1041,7 @@ bool SearchLOT(LOTInfo* LOT, int depth)
|
|||
if ((node->searchNumber & SEARCH_NUMBER) < (expand->searchNumber & SEARCH_NUMBER))
|
||||
continue;
|
||||
|
||||
if (node->searchNumber & BLOCKED_SEARCH)
|
||||
if (node->searchNumber & SEARCH_BLOCKED)
|
||||
{
|
||||
if ((node->searchNumber & SEARCH_NUMBER) == (expand->searchNumber & SEARCH_NUMBER))
|
||||
continue;
|
||||
|
@ -1053,12 +1050,12 @@ bool SearchLOT(LOTInfo* LOT, int depth)
|
|||
}
|
||||
else
|
||||
{
|
||||
if ((node->searchNumber & SEARCH_NUMBER) == (expand->searchNumber & SEARCH_NUMBER) && !(expand->searchNumber & BLOCKED_SEARCH))
|
||||
if ((node->searchNumber & SEARCH_NUMBER) == (expand->searchNumber & SEARCH_NUMBER) && !(expand->searchNumber & SEARCH_BLOCKED))
|
||||
continue;
|
||||
|
||||
if (g_Level.PathfindingBoxes[boxNumber].flags & LOT->BlockMask)
|
||||
{
|
||||
expand->searchNumber = node->searchNumber | BLOCKED_SEARCH;
|
||||
expand->searchNumber = node->searchNumber | SEARCH_BLOCKED;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1191,8 +1188,7 @@ bool IsCreatureVaultAvailable(ItemInfo* item, int stepCount)
|
|||
item->ObjectNumber != ID_LIZARD &&
|
||||
item->ObjectNumber != ID_APE &&
|
||||
item->ObjectNumber != ID_SMALL_SPIDER &&
|
||||
item->ObjectNumber != ID_SOPHIA_LEIGH_BOSS &&
|
||||
item->ObjectNumber != ID_VON_CROY);
|
||||
item->ObjectNumber != ID_SOPHIA_LEIGH_BOSS);
|
||||
|
||||
case -2:
|
||||
return (item->ObjectNumber != ID_BADDY1 &&
|
||||
|
@ -1203,8 +1199,7 @@ bool IsCreatureVaultAvailable(ItemInfo* item, int stepCount)
|
|||
item->ObjectNumber != ID_LIZARD &&
|
||||
item->ObjectNumber != ID_APE &&
|
||||
item->ObjectNumber != ID_SMALL_SPIDER &&
|
||||
item->ObjectNumber != ID_SOPHIA_LEIGH_BOSS &&
|
||||
item->ObjectNumber != ID_VON_CROY);
|
||||
item->ObjectNumber != ID_SOPHIA_LEIGH_BOSS);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -1440,94 +1435,50 @@ void FindAITarget(CreatureInfo* creature, short objectNumber)
|
|||
void FindAITargetObject(CreatureInfo* creature, int objectNumber)
|
||||
{
|
||||
const auto& item = g_Level.Items[creature->ItemNumber];
|
||||
AITargetFlags data = {};
|
||||
data.checkDistance = false;
|
||||
data.checkOcb = item.ItemFlags[3] != 0;
|
||||
data.objectNumber = objectNumber;
|
||||
data.ocb = item.ItemFlags[3];
|
||||
data.checkSameZone = true;
|
||||
if (FindAITargetObject(creature, &data))
|
||||
{
|
||||
*creature->AITarget = data.foundItem;
|
||||
creature->Enemy = creature->AITarget;
|
||||
}
|
||||
|
||||
FindAITargetObject(creature, objectNumber, item.ItemFlags[3], true);
|
||||
}
|
||||
|
||||
void FindAITargetObject(CreatureInfo* creature, int objectNumber, int ocb, bool checkSameZone)
|
||||
{
|
||||
AITargetFlags data = {};
|
||||
data.checkDistance = false;
|
||||
data.checkOcb = ocb != NO_VALUE;
|
||||
data.objectNumber = objectNumber;
|
||||
data.ocb = ocb;
|
||||
data.checkSameZone = checkSameZone;
|
||||
if (FindAITargetObject(creature, &data))
|
||||
{
|
||||
*creature->AITarget = data.foundItem;
|
||||
creature->Enemy = creature->AITarget;
|
||||
}
|
||||
}
|
||||
|
||||
bool FindAITargetObject(CreatureInfo* creature, AITargetFlags* data)
|
||||
{
|
||||
if (g_Level.AIObjects.empty())
|
||||
return false;
|
||||
|
||||
auto& item = g_Level.Items[creature->ItemNumber];
|
||||
|
||||
if (g_Level.AIObjects.empty())
|
||||
return;
|
||||
|
||||
AI_OBJECT* foundObject = nullptr;
|
||||
|
||||
for (auto& aiObject : g_Level.AIObjects)
|
||||
{
|
||||
// Check if the objectNumber match.
|
||||
if (aiObject.objectNumber != data->objectNumber)
|
||||
continue;
|
||||
|
||||
// Check if the room is valid.
|
||||
if (aiObject.roomNumber == NO_VALUE)
|
||||
continue;
|
||||
|
||||
// Check if distance is valid.
|
||||
if (data->checkDistance)
|
||||
{
|
||||
if (Vector3i::Distance(item.Pose.Position, aiObject.pos.Position) > data->maxDistance)
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if the ocb is the same, useful for paths.
|
||||
if (data->checkOcb)
|
||||
{
|
||||
if (aiObject.triggerFlags != data->ocb)
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if the zone number is the same.
|
||||
if (data->checkSameZone)
|
||||
if (aiObject.objectNumber == objectNumber &&
|
||||
aiObject.triggerFlags == ocb &&
|
||||
aiObject.roomNumber != NO_VALUE)
|
||||
{
|
||||
int* zone = g_Level.Zones[(int)creature->LOT.Zone][(int)FlipStatus].data();
|
||||
auto* room = &g_Level.Rooms[item.RoomNumber];
|
||||
|
||||
// NOTE: Avoid changing the boxNumber of the item/ai_item, so a local variable is required !
|
||||
// Where just searching for AIobject near him.
|
||||
int boxNum = GetSector(room, item.Pose.Position.x - room->Position.x, item.Pose.Position.z - room->Position.z)->PathfindingBoxID;
|
||||
item.BoxNumber = GetSector(room, item.Pose.Position.x - room->Position.x, item.Pose.Position.z - room->Position.z)->PathfindingBoxID;
|
||||
room = &g_Level.Rooms[aiObject.roomNumber];
|
||||
int aiBoxNum = GetSector(room, aiObject.pos.Position.x - room->Position.x, aiObject.pos.Position.z - room->Position.z)->PathfindingBoxID;
|
||||
aiObject.boxNumber = GetSector(room, aiObject.pos.Position.x - room->Position.x, aiObject.pos.Position.z - room->Position.z)->PathfindingBoxID;
|
||||
|
||||
// If box is invalid or zone is not the same, go next.
|
||||
if (boxNum == NO_VALUE || aiBoxNum == NO_VALUE)
|
||||
continue;
|
||||
// If the zone is invalid, go next.
|
||||
if (zone[boxNum] != zone[aiBoxNum])
|
||||
continue;
|
||||
if (item.BoxNumber == NO_VALUE || aiObject.boxNumber == NO_VALUE)
|
||||
return;
|
||||
|
||||
if (checkSameZone && (zone[item.BoxNumber] != zone[aiObject.boxNumber]))
|
||||
return;
|
||||
|
||||
// Don't check for same zone. Needed for Sophia Leigh.
|
||||
foundObject = &aiObject;
|
||||
}
|
||||
|
||||
// Don't check for same zone.
|
||||
// Needed for Sophia Leigh.
|
||||
foundObject = &aiObject;
|
||||
}
|
||||
if (foundObject == nullptr)
|
||||
return false;
|
||||
|
||||
ItemInfo aiItem = {};
|
||||
if (foundObject == nullptr)
|
||||
return;
|
||||
|
||||
auto& aiItem = *creature->AITarget;
|
||||
|
||||
creature->Enemy = &aiItem;
|
||||
|
||||
aiItem.ObjectNumber = foundObject->objectNumber;
|
||||
aiItem.RoomNumber = foundObject->roomNumber;
|
||||
aiItem.Pose.Position = foundObject->pos.Position;
|
||||
|
@ -1536,14 +1487,14 @@ bool FindAITargetObject(CreatureInfo* creature, AITargetFlags* data)
|
|||
aiItem.TriggerFlags = foundObject->triggerFlags;
|
||||
aiItem.BoxNumber = foundObject->boxNumber;
|
||||
|
||||
if (!(aiItem.Flags & IFLAG_TRIGGERED))
|
||||
if (!(creature->AITarget->Flags & ItemFlags::IFLAG_TRIGGERED))
|
||||
{
|
||||
aiItem.Pose.Position.x += CLICK(1) * phd_sin(aiItem.Pose.Orientation.y);
|
||||
aiItem.Pose.Position.z += CLICK(1) * phd_cos(aiItem.Pose.Orientation.y);
|
||||
}
|
||||
float sinY = phd_sin(creature->AITarget->Pose.Orientation.y);
|
||||
float cosY = phd_cos(creature->AITarget->Pose.Orientation.y);
|
||||
|
||||
data->foundItem = aiItem;
|
||||
return true;
|
||||
creature->AITarget->Pose.Position.x += CLICK(1) * sinY;
|
||||
creature->AITarget->Pose.Position.z += CLICK(1) * cosY;
|
||||
}
|
||||
}
|
||||
|
||||
int TargetReachable(ItemInfo* item, ItemInfo* enemy)
|
||||
|
@ -1604,7 +1555,7 @@ void CreatureAIInfo(ItemInfo* item, AI_INFO* AI)
|
|||
AI->enemyZone |= BLOCKED;
|
||||
}
|
||||
else if (item->BoxNumber != NO_VALUE &&
|
||||
creature->LOT.Node[item->BoxNumber].searchNumber == (creature->LOT.SearchNumber | BLOCKED_SEARCH))
|
||||
creature->LOT.Node[item->BoxNumber].searchNumber == (creature->LOT.SearchNumber | SEARCH_BLOCKED))
|
||||
{
|
||||
AI->enemyZone |= BLOCKED;
|
||||
}
|
||||
|
@ -1833,7 +1784,7 @@ void GetCreatureMood(ItemInfo* item, AI_INFO* AI, bool isViolent)
|
|||
auto* enemy = creature->Enemy;
|
||||
auto* LOT = &creature->LOT;
|
||||
|
||||
if (item->BoxNumber == NO_VALUE || creature->LOT.Node[item->BoxNumber].searchNumber == (creature->LOT.SearchNumber | BLOCKED_SEARCH))
|
||||
if (item->BoxNumber == NO_VALUE || creature->LOT.Node[item->BoxNumber].searchNumber == (creature->LOT.SearchNumber | SEARCH_BLOCKED))
|
||||
creature->LOT.RequiredBox = NO_VALUE;
|
||||
|
||||
if (creature->Mood != MoodType::Attack && creature->LOT.RequiredBox != NO_VALUE && !ValidBox(item, AI->zoneNumber, creature->LOT.TargetBox))
|
||||
|
@ -1956,7 +1907,7 @@ TARGET_TYPE CalculateTarget(Vector3i* target, ItemInfo* item, LOTInfo* LOT)
|
|||
int right = boxRight;
|
||||
int top = boxTop;
|
||||
int bottom = boxBottom;
|
||||
int direction = ALL_CLIP;
|
||||
int direction = CLIP_ALL;
|
||||
|
||||
do
|
||||
{
|
||||
|
@ -1996,7 +1947,7 @@ TARGET_TYPE CalculateTarget(Vector3i* target, ItemInfo* item, LOTInfo* LOT)
|
|||
if (target->z < (boxLeft + CLICK(2)))
|
||||
target->z = boxLeft + CLICK(2);
|
||||
|
||||
if (direction & SECONDARY_CLIP)
|
||||
if (direction & CLIP_SECONDARY)
|
||||
return TARGET_TYPE::SECONDARY_TARGET;
|
||||
|
||||
if (boxTop > top)
|
||||
|
@ -2011,10 +1962,10 @@ TARGET_TYPE CalculateTarget(Vector3i* target, ItemInfo* item, LOTInfo* LOT)
|
|||
{
|
||||
target->z = (right - CLICK(2));
|
||||
|
||||
if (direction != ALL_CLIP)
|
||||
if (direction != CLIP_ALL)
|
||||
return TARGET_TYPE::SECONDARY_TARGET;
|
||||
|
||||
direction |= (ALL_CLIP | SECONDARY_CLIP);
|
||||
direction |= (CLIP_ALL | CLIP_SECONDARY);
|
||||
}
|
||||
}
|
||||
else if (item->Pose.Position.z > boxRight && direction != CLIP_LEFT)
|
||||
|
@ -2026,7 +1977,7 @@ TARGET_TYPE CalculateTarget(Vector3i* target, ItemInfo* item, LOTInfo* LOT)
|
|||
if (target->z > boxRight - CLICK(2))
|
||||
target->z = boxRight - CLICK(2);
|
||||
|
||||
if (direction & SECONDARY_CLIP)
|
||||
if (direction & CLIP_SECONDARY)
|
||||
return TARGET_TYPE::SECONDARY_TARGET;
|
||||
|
||||
if (boxTop > top)
|
||||
|
@ -2041,10 +1992,10 @@ TARGET_TYPE CalculateTarget(Vector3i* target, ItemInfo* item, LOTInfo* LOT)
|
|||
{
|
||||
target->z = left + CLICK(2);
|
||||
|
||||
if (direction != ALL_CLIP)
|
||||
if (direction != CLIP_ALL)
|
||||
return TARGET_TYPE::SECONDARY_TARGET;
|
||||
|
||||
direction |= (ALL_CLIP | SECONDARY_CLIP);
|
||||
direction |= (CLIP_ALL | CLIP_SECONDARY);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2057,7 +2008,7 @@ TARGET_TYPE CalculateTarget(Vector3i* target, ItemInfo* item, LOTInfo* LOT)
|
|||
if (target->x < boxTop + CLICK(2))
|
||||
target->x = boxTop + CLICK(2);
|
||||
|
||||
if (direction & SECONDARY_CLIP)
|
||||
if (direction & CLIP_SECONDARY)
|
||||
return TARGET_TYPE::SECONDARY_TARGET;
|
||||
|
||||
if (boxLeft > left)
|
||||
|
@ -2072,10 +2023,10 @@ TARGET_TYPE CalculateTarget(Vector3i* target, ItemInfo* item, LOTInfo* LOT)
|
|||
{
|
||||
target->x = bottom - CLICK(2);
|
||||
|
||||
if (direction != ALL_CLIP)
|
||||
if (direction != CLIP_ALL)
|
||||
return TARGET_TYPE::SECONDARY_TARGET;
|
||||
|
||||
direction |= (ALL_CLIP | SECONDARY_CLIP);
|
||||
direction |= (CLIP_ALL | CLIP_SECONDARY);
|
||||
}
|
||||
}
|
||||
else if (item->Pose.Position.x > boxBottom && direction != CLIP_TOP)
|
||||
|
@ -2087,7 +2038,7 @@ TARGET_TYPE CalculateTarget(Vector3i* target, ItemInfo* item, LOTInfo* LOT)
|
|||
if (target->x > (boxBottom - CLICK(2)))
|
||||
target->x = (boxBottom - CLICK(2));
|
||||
|
||||
if (direction & SECONDARY_CLIP)
|
||||
if (direction & CLIP_SECONDARY)
|
||||
return TARGET_TYPE::SECONDARY_TARGET;
|
||||
|
||||
if (boxLeft > left)
|
||||
|
@ -2102,10 +2053,10 @@ TARGET_TYPE CalculateTarget(Vector3i* target, ItemInfo* item, LOTInfo* LOT)
|
|||
{
|
||||
target->x = top + CLICK(2);
|
||||
|
||||
if (direction != ALL_CLIP)
|
||||
if (direction != CLIP_ALL)
|
||||
return TARGET_TYPE::SECONDARY_TARGET;
|
||||
|
||||
direction |= (ALL_CLIP | SECONDARY_CLIP);
|
||||
direction |= (CLIP_ALL | CLIP_SECONDARY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2116,7 +2067,7 @@ TARGET_TYPE CalculateTarget(Vector3i* target, ItemInfo* item, LOTInfo* LOT)
|
|||
{
|
||||
target->z = LOT->Target.z;
|
||||
}
|
||||
else if (!(direction & SECONDARY_CLIP))
|
||||
else if (!(direction & CLIP_SECONDARY))
|
||||
{
|
||||
if (target->z < (boxLeft + CLICK(2)))
|
||||
target->z = boxLeft + CLICK(2);
|
||||
|
@ -2128,7 +2079,7 @@ TARGET_TYPE CalculateTarget(Vector3i* target, ItemInfo* item, LOTInfo* LOT)
|
|||
{
|
||||
target->x = LOT->Target.x;
|
||||
}
|
||||
else if (!(direction & SECONDARY_CLIP))
|
||||
else if (!(direction & CLIP_SECONDARY))
|
||||
{
|
||||
if (target->x < (boxTop + CLICK(2)))
|
||||
target->x = boxTop + CLICK(2);
|
||||
|
@ -2145,7 +2096,7 @@ TARGET_TYPE CalculateTarget(Vector3i* target, ItemInfo* item, LOTInfo* LOT)
|
|||
break;
|
||||
} while (boxNumber != NO_VALUE);
|
||||
|
||||
if (!(direction & SECONDARY_CLIP))
|
||||
if (!(direction & CLIP_SECONDARY))
|
||||
{
|
||||
if (target->z < (boxLeft + CLICK(2)))
|
||||
target->z = boxLeft + CLICK(2);
|
||||
|
@ -2153,7 +2104,7 @@ TARGET_TYPE CalculateTarget(Vector3i* target, ItemInfo* item, LOTInfo* LOT)
|
|||
target->z = boxRight - CLICK(2);
|
||||
}
|
||||
|
||||
if (!(direction & SECONDARY_CLIP))
|
||||
if (!(direction & CLIP_SECONDARY))
|
||||
{
|
||||
if (target->x < (boxTop + CLICK(2)))
|
||||
target->x = boxTop + CLICK(2);
|
||||
|
@ -2224,26 +2175,29 @@ void InitializeItemBoxData()
|
|||
}
|
||||
}
|
||||
|
||||
bool CanCreatureJump(ItemInfo& item, float stepDist, JumpDistance jumpDistType)
|
||||
bool CanCreatureJump(ItemInfo& item, JumpDistance jumpDistType)
|
||||
{
|
||||
const auto& creature = *GetCreatureInfo(&item);
|
||||
if (creature.Enemy == nullptr)
|
||||
return false;
|
||||
|
||||
float stepDist = BLOCK(0.92f);
|
||||
|
||||
int vPos = item.Pose.Position.y;
|
||||
auto height1 = GetPointCollision(item, item.Pose.Orientation.y, stepDist ).GetFloorHeight();
|
||||
auto height2 = GetPointCollision(item, item.Pose.Orientation.y, stepDist * 2).GetFloorHeight();
|
||||
auto height3 = GetPointCollision(item, item.Pose.Orientation.y, stepDist * 3).GetFloorHeight();
|
||||
auto height4 = GetPointCollision(item, item.Pose.Orientation.y, stepDist * 4).GetFloorHeight();
|
||||
auto pointCollA = GetPointCollision(item, item.Pose.Orientation.y, stepDist);
|
||||
auto pointCollB = GetPointCollision(item, item.Pose.Orientation.y, stepDist * 2);
|
||||
auto pointCollC = GetPointCollision(item, item.Pose.Orientation.y, stepDist * 3);
|
||||
|
||||
switch (jumpDistType)
|
||||
{
|
||||
default:
|
||||
case JumpDistance::Block1:
|
||||
if (item.BoxNumber == creature.Enemy->BoxNumber ||
|
||||
vPos >= (height1 - STEPUP_HEIGHT) ||
|
||||
vPos >= (height2 + CLICK(1)) ||
|
||||
vPos <= (height2 - CLICK(1)))
|
||||
vPos >= (pointCollA.GetFloorHeight() - STEPUP_HEIGHT) ||
|
||||
vPos >= (pointCollB.GetFloorHeight() + CLICK(1)) ||
|
||||
vPos <= (pointCollB.GetFloorHeight() - CLICK(1)) ||
|
||||
pointCollA.GetSector().PathfindingBoxID == NO_VALUE ||
|
||||
pointCollB.GetSector().PathfindingBoxID == NO_VALUE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -2252,27 +2206,18 @@ bool CanCreatureJump(ItemInfo& item, float stepDist, JumpDistance jumpDistType)
|
|||
|
||||
case JumpDistance::Block2:
|
||||
if (item.BoxNumber == creature.Enemy->BoxNumber ||
|
||||
vPos >= (height1 - STEPUP_HEIGHT) ||
|
||||
vPos >= (height2 - STEPUP_HEIGHT) ||
|
||||
vPos >= (height3 + CLICK(1)) ||
|
||||
vPos <= (height3 - CLICK(1)))
|
||||
vPos >= (pointCollA.GetFloorHeight() - STEPUP_HEIGHT) ||
|
||||
vPos >= (pointCollB.GetFloorHeight() - STEPUP_HEIGHT) ||
|
||||
vPos >= (pointCollC.GetFloorHeight() + CLICK(1)) ||
|
||||
vPos <= (pointCollC.GetFloorHeight() - CLICK(1)) ||
|
||||
pointCollA.GetSector().PathfindingBoxID == NO_VALUE ||
|
||||
pointCollB.GetSector().PathfindingBoxID == NO_VALUE ||
|
||||
pointCollC.GetSector().PathfindingBoxID == NO_VALUE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case JumpDistance::Block3:
|
||||
if (item.BoxNumber == creature.Enemy->BoxNumber ||
|
||||
vPos >= height1 - STEPUP_HEIGHT ||
|
||||
vPos >= height2 - STEPUP_HEIGHT ||
|
||||
vPos >= height3 - STEPUP_HEIGHT ||
|
||||
vPos >= height4 + CLICK(1) ||
|
||||
vPos <= height4 - CLICK(1))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -56,29 +56,33 @@ struct OVERLAP
|
|||
|
||||
#define CreatureEffectFunction short(int x, int y, int z, short speed, short yRot, short roomNumber)
|
||||
|
||||
constexpr auto BOX_BLOCKED = (1 << 14); // unpassable for other enemies, always set for movable blocks & closed doors
|
||||
constexpr auto BOX_LAST = (1 << 15); // unpassable by large enemies (T-Rex, Centaur, etc), always set behind doors
|
||||
// TODO: Following constants can be moved to new flag enums for improved clarity.
|
||||
|
||||
constexpr auto REVERSE = 0x4000;
|
||||
constexpr auto BLOCKABLE = 0x8000;
|
||||
constexpr auto BLOCKED = 0x4000;
|
||||
constexpr auto SEARCH_NUMBER = 0x7FFF;
|
||||
constexpr auto BLOCKED_SEARCH = 0x8000;
|
||||
constexpr auto BOX_JUMP = 0x800;
|
||||
constexpr auto BOX_MONKEY = 0x2000;
|
||||
constexpr auto BLOCKED = 0x4000;
|
||||
|
||||
constexpr auto SEARCH_NUMBER = INT_MAX;
|
||||
constexpr auto SEARCH_BLOCKED = (1 << 31);
|
||||
|
||||
constexpr auto BOX_JUMP = 0x800;
|
||||
constexpr auto BOX_MONKEY = 0x2000;
|
||||
constexpr auto BOX_END_BIT = 0x8000;
|
||||
constexpr auto EXPAND_LEFT = 0x1;
|
||||
constexpr auto EXPAND_RIGHT = 0x2;
|
||||
constexpr auto EXPAND_TOP = 0x4;
|
||||
|
||||
constexpr auto EXPAND_LEFT = 0x1;
|
||||
constexpr auto EXPAND_RIGHT = 0x2;
|
||||
constexpr auto EXPAND_TOP = 0x4;
|
||||
constexpr auto EXPAND_BOTTOM = 0x8;
|
||||
|
||||
constexpr auto NO_FLYING = 0;
|
||||
constexpr auto FLY_ZONE = 0x2000;
|
||||
constexpr auto CLIP_LEFT = 0x1;
|
||||
constexpr auto CLIP_RIGHT = 0x2;
|
||||
constexpr auto CLIP_TOP = 0x4;
|
||||
constexpr auto FLY_ZONE = 0x2000;
|
||||
|
||||
constexpr auto CLIP_LEFT = 0x1;
|
||||
constexpr auto CLIP_RIGHT = 0x2;
|
||||
constexpr auto CLIP_TOP = 0x4;
|
||||
constexpr auto CLIP_BOTTOM = 0x8;
|
||||
constexpr auto SECONDARY_CLIP = 0x10;
|
||||
constexpr auto ALL_CLIP = (CLIP_LEFT | CLIP_RIGHT | CLIP_TOP | CLIP_BOTTOM);
|
||||
constexpr auto CLIP_ALL = (CLIP_LEFT | CLIP_RIGHT | CLIP_TOP | CLIP_BOTTOM);
|
||||
|
||||
constexpr auto CLIP_SECONDARY = 0x10;
|
||||
|
||||
struct AITargetFlags
|
||||
{
|
||||
|
|
|
@ -59,6 +59,7 @@
|
|||
#include "Specific/Input/Input.h"
|
||||
#include "Specific/level.h"
|
||||
#include "Specific/winmain.h"
|
||||
#include "Game/Lara/lara_initialise.h"
|
||||
|
||||
using namespace std::chrono;
|
||||
using namespace TEN::Effects;
|
||||
|
@ -89,7 +90,6 @@ using namespace TEN::Renderer;
|
|||
|
||||
int GameTimer = 0;
|
||||
int GlobalCounter = 0;
|
||||
int Wibble = 0;
|
||||
|
||||
bool InitializeGame;
|
||||
bool DoTheGame;
|
||||
|
@ -185,27 +185,13 @@ GameStatus ControlPhase(int numFrames)
|
|||
ApplyActionQueue();
|
||||
ClearActionQueue();
|
||||
|
||||
UpdateCamera();
|
||||
UpdateAllItems();
|
||||
UpdateAllEffects();
|
||||
UpdateLara(LaraItem, isTitle);
|
||||
|
||||
g_GameScriptEntities->TestCollidingObjects();
|
||||
|
||||
if (UseSpotCam)
|
||||
{
|
||||
// Draw flyby cameras.
|
||||
CalculateSpotCameras();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Do the standard camera.
|
||||
TrackCameraInit = false;
|
||||
CalculateCamera(LaraCollision);
|
||||
}
|
||||
|
||||
// Update oscillator seed.
|
||||
Wibble = (Wibble + WIBBLE_SPEED) & WIBBLE_MAX;
|
||||
|
||||
// Smash shatters and clear stopper flags under them.
|
||||
UpdateShatters();
|
||||
|
||||
|
@ -213,6 +199,7 @@ GameStatus ControlPhase(int numFrames)
|
|||
Weather.Update();
|
||||
|
||||
// Update effects.
|
||||
UpdateWibble();
|
||||
StreamerEffect.Update();
|
||||
UpdateSparks();
|
||||
UpdateFireSparks();
|
||||
|
@ -545,6 +532,10 @@ void InitializeOrLoadGame(bool loadGame)
|
|||
{
|
||||
SaveGame::LoadHub(CurrentLevel);
|
||||
TENLog("Starting new level.", LogLevel::Info);
|
||||
|
||||
// Restore vehicle.
|
||||
auto* item = FindItem(ID_LARA);
|
||||
InitializePlayerVehicle(*item);
|
||||
}
|
||||
|
||||
g_GameScript->OnStart();
|
||||
|
|
|
@ -50,15 +50,11 @@ enum FadeStatus
|
|||
|
||||
constexpr int MAX_ROOMS = 1024;
|
||||
|
||||
constexpr int WIBBLE_SPEED = 4;
|
||||
constexpr int WIBBLE_MAX = UCHAR_MAX - WIBBLE_SPEED + 1;
|
||||
|
||||
constexpr int LOOP_FRAME_COUNT = 2;
|
||||
|
||||
extern int GameTimer;
|
||||
extern int RumbleTimer;
|
||||
extern int GlobalCounter;
|
||||
extern int Wibble;
|
||||
|
||||
extern bool InitializeGame;
|
||||
extern bool DoTheGame;
|
||||
|
|
|
@ -312,7 +312,7 @@ bool GetTargetOnLOS(GameVector* origin, GameVector* target, bool drawTarget, boo
|
|||
ShatterImpactData.impactDirection = dir;
|
||||
ShatterImpactData.impactLocation = ShatterItem.sphere.Center;
|
||||
ShatterObject(&ShatterItem, 0, 128, target2.RoomNumber, 0);
|
||||
TriggerRicochetSpark(target2, LaraItem->Pose.Orientation.y, 3, 0);
|
||||
TriggerRicochetSpark(target2, LaraItem->Pose.Orientation.y, 3, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -512,91 +512,21 @@ static bool DoRayBox(const GameVector& origin, const GameVector& target, const G
|
|||
// If mesh is visible.
|
||||
if (item->MeshBits & (1 << i))
|
||||
{
|
||||
float distance;
|
||||
const auto& sphere = spheres[i];
|
||||
|
||||
// NOTE: Not worth doing what's commented below. *Rewrite completely.*
|
||||
// TODO: this approach is the correct one but, again, Core's math is a mystery and this test was meant
|
||||
// to fail deliberately in some way. I've so added again Core's legacy test for allowing the current game logic
|
||||
// but after more testing we should trash it in the future and restore the new way.
|
||||
#if 0
|
||||
// Create the bounding sphere and test it against the ray
|
||||
BoundingSphere sph = BoundingSphere(Vector3(sphere->x, sphere->y, sphere->z), sphere->r);
|
||||
float newDist;
|
||||
if (sph.Intersects(rayStart, rayDirNormalized, newDist))
|
||||
if (sphere.Intersects(rayOrigin, rayDir, distance))
|
||||
{
|
||||
// HACK: Core seems to take in account for distance not the real hit point but the centre of the sphere.
|
||||
// This can work well for example for GUARDIAN because the head sphere is so big that would always be hit
|
||||
// and eyes would not be destroyed.
|
||||
newDist = sqrt(SQUARE(sphere->x - start->x) + SQUARE(sphere->y - start->y) + SQUARE(sphere->z - start->z));
|
||||
// Test for minimum distance.
|
||||
|
||||
// Test for min distance
|
||||
if (newDist < minDistance)
|
||||
if (distance < minDist)
|
||||
{
|
||||
minDistance = newDist;
|
||||
meshPtr = &g_Level.Meshes[obj->meshIndex + i];
|
||||
minDist = distance;
|
||||
meshIndex = object->meshIndex + i;
|
||||
bit = 1 << i;
|
||||
sp = i;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
Vector3i p[4];
|
||||
|
||||
p[1].x = origin.x;
|
||||
p[1].y = origin.y;
|
||||
p[1].z = origin.z;
|
||||
p[2].x = target.x;
|
||||
p[2].y = target.y;
|
||||
p[2].z = target.z;
|
||||
p[3].x = sphere.Center.x;
|
||||
p[3].y = sphere.Center.y;
|
||||
p[3].z = sphere.Center.z;
|
||||
|
||||
int r0 = (p[3].x - p[1].x) * (p[2].x - p[1].x) +
|
||||
(p[3].y - p[1].y) * (p[2].y - p[1].y) +
|
||||
(p[3].z - p[1].z) * (p[2].z - p[1].z);
|
||||
|
||||
int r1 = SQUARE(p[2].x - p[1].x) +
|
||||
SQUARE(p[2].y - p[1].y) +
|
||||
SQUARE(p[2].z - p[1].z);
|
||||
|
||||
if (((r0 < 0 && r1 < 0) ||
|
||||
(r1 > 0 && r0 > 0)) &&
|
||||
(abs(r0) <= abs(r1)))
|
||||
{
|
||||
r1 >>= 16;
|
||||
if (r1)
|
||||
r0 /= r1;
|
||||
else
|
||||
r0 = 0;
|
||||
|
||||
p[0].x = p[1].x + ((r0 * (p[2].x - p[1].x)) >> 16);
|
||||
p[0].y = p[1].y + ((r0 * (p[2].y - p[1].y)) >> 16);
|
||||
p[0].z = p[1].z + ((r0 * (p[2].z - p[1].z)) >> 16);
|
||||
|
||||
int dx = SQUARE(p[0].x - p[3].x);
|
||||
int dy = SQUARE(p[0].y - p[3].y);
|
||||
int dz = SQUARE(p[0].z - p[3].z);
|
||||
|
||||
int distance = dx + dy + dz;
|
||||
|
||||
if (distance < SQUARE(sphere.Radius))
|
||||
{
|
||||
dx = SQUARE(sphere.Center.x - origin.x);
|
||||
dy = SQUARE(sphere.Center.y - origin.y);
|
||||
dz = SQUARE(sphere.Center.z - origin.z);
|
||||
|
||||
distance = dx + dy + dz;
|
||||
|
||||
if (distance < minDist)
|
||||
{
|
||||
minDist = distance;
|
||||
meshIndex = object->meshIndex + i;
|
||||
bit = 1 << i;
|
||||
sp = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "Game/Lara/lara.h"
|
||||
#include "Game/Setup.h"
|
||||
#include "Specific/level.h"
|
||||
#include "Specific/trutils.h"
|
||||
|
||||
using namespace TEN::Collision::Room;
|
||||
|
||||
|
@ -205,6 +206,41 @@ void InitializeSlot(short itemNumber, bool makeTarget)
|
|||
SlotsUsed++;
|
||||
}
|
||||
|
||||
void TargetNearestEntity(ItemInfo& item, const std::vector<GAME_OBJECT_ID>& keyObjectIds, bool ignoreKeyObjectIds)
|
||||
{
|
||||
auto& creature = *GetCreatureInfo(&item);
|
||||
|
||||
float closestDistSqr = INFINITY;
|
||||
for (auto& target : ActiveCreatures)
|
||||
{
|
||||
auto& targetItem = g_Level.Items[target->ItemNumber];
|
||||
if (targetItem.Index == item.Index)
|
||||
continue;
|
||||
|
||||
// Ignore or specifically target key object IDs.
|
||||
if (!keyObjectIds.empty() && (ignoreKeyObjectIds ? Contains(keyObjectIds, targetItem.ObjectNumber) : !Contains(keyObjectIds, targetItem.ObjectNumber)))
|
||||
continue;
|
||||
|
||||
if (&targetItem != &item && targetItem.HitPoints > 0 && targetItem.Status != ITEM_INVISIBLE)
|
||||
{
|
||||
float distSqr = Vector3i::DistanceSquared(item.Pose.Position, targetItem.Pose.Position);
|
||||
if (distSqr < closestDistSqr)
|
||||
{
|
||||
creature.Enemy = &targetItem;
|
||||
closestDistSqr = distSqr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle player as special case.
|
||||
if (!keyObjectIds.empty() && (ignoreKeyObjectIds ? Contains(keyObjectIds, ID_LARA) : !Contains(keyObjectIds, ID_LARA)))
|
||||
return;
|
||||
|
||||
float distToPlayerSqr = Vector3i::DistanceSquared(item.Pose.Position, LaraItem->Pose.Position);
|
||||
if (distToPlayerSqr < closestDistSqr)
|
||||
creature.Enemy = LaraItem;
|
||||
}
|
||||
|
||||
void SetEntityTarget(short itemNum, short target)
|
||||
{
|
||||
auto* item = &g_Level.Items[itemNum];
|
||||
|
|
|
@ -7,6 +7,7 @@ void InitializeLOTarray(int allocMem);
|
|||
bool EnableEntityAI(short itemNum, bool always, bool makeTarget = true);
|
||||
void InitializeSlot(short itemNum, bool makeTarget);
|
||||
void SetEntityTarget(short itemNum, short target);
|
||||
void TargetNearestEntity(ItemInfo& item, const std::vector<GAME_OBJECT_ID>& keyObjectIds = {}, bool ignoreKeyObjectIds = true);
|
||||
void DisableEntityAI(short itemNumber);
|
||||
void ClearLOT(LOTInfo* LOT);
|
||||
void CreateZone(ItemInfo* item);
|
||||
|
|
|
@ -339,17 +339,23 @@ void Antitrigger(short const value, short const flags)
|
|||
item->ItemFlags[1] = 100;
|
||||
}
|
||||
|
||||
item->Flags &= ~(CODE_BITS | REVERSE);
|
||||
item->Flags &= ~(CODE_BITS | IFLAG_REVERSE);
|
||||
|
||||
if (flags & ONESHOT)
|
||||
item->Flags |= ATONESHOT;
|
||||
|
||||
if (item->Active && Objects[item->ObjectNumber].intelligent)
|
||||
if (item->Active)
|
||||
{
|
||||
DisableEntityAI(value);
|
||||
RemoveActiveItem(value, false);
|
||||
item->Active = false;
|
||||
item->Status = ITEM_INVISIBLE;
|
||||
item->Status = ITEM_DEACTIVATED;
|
||||
|
||||
if (Objects[item->ObjectNumber].intelligent)
|
||||
{
|
||||
DisableEntityAI(value);
|
||||
RemoveActiveItem(value, false);
|
||||
|
||||
item->Status = ITEM_INVISIBLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,9 @@ using namespace TEN::Math::Random;
|
|||
|
||||
using TEN::Renderer::g_Renderer;
|
||||
|
||||
constexpr int WIBBLE_SPEED = 4;
|
||||
constexpr int WIBBLE_MAX = UCHAR_MAX - WIBBLE_SPEED + 1;
|
||||
|
||||
// New particle class
|
||||
Particle Particles[MAX_PARTICLES];
|
||||
ParticleDynamic ParticleDynamics[MAX_PARTICLE_DYNAMICS];
|
||||
|
@ -49,7 +52,9 @@ FX_INFO EffectList[NUM_EFFECTS];
|
|||
GameBoundingBox DeadlyBounds;
|
||||
SPLASH_SETUP SplashSetup;
|
||||
SPLASH_STRUCT Splashes[MAX_SPLASHES];
|
||||
|
||||
int SplashCount = 0;
|
||||
int Wibble = 0;
|
||||
|
||||
Vector3i NodeVectors[ParticleNodeOffsetIDs::NodeMax];
|
||||
NODEOFFSET_INFO NodeOffsets[ParticleNodeOffsetIDs::NodeMax] =
|
||||
|
@ -180,6 +185,13 @@ void SetSpriteSequence(Particle& particle, GAME_OBJECT_ID objectID)
|
|||
particle.spriteIndex = Objects[objectID].meshIndex + (int)round(Lerp(0.0f, numSprites, normalizedAge));
|
||||
}
|
||||
|
||||
void UpdateWibble()
|
||||
{
|
||||
// Update oscillator seed.
|
||||
Wibble = (Wibble + WIBBLE_SPEED) & WIBBLE_MAX;
|
||||
|
||||
}
|
||||
|
||||
void UpdateSparks()
|
||||
{
|
||||
auto bounds = GameBoundingBox(LaraItem);
|
||||
|
|
|
@ -18,6 +18,8 @@ constexpr auto NUM_EFFECTS = 256;
|
|||
constexpr auto MAX_PARTICLES = 1024;
|
||||
constexpr auto MAX_PARTICLE_DYNAMICS = 8;
|
||||
|
||||
extern int Wibble;
|
||||
|
||||
enum SpriteEnumFlag
|
||||
{
|
||||
SP_NONE = 0,
|
||||
|
@ -279,5 +281,6 @@ void TriggerRocketFire(int x, int y, int z);
|
|||
void TriggerExplosionBubbles(int x, int y, int z, short roomNumber);
|
||||
void Ricochet(Pose& pos);
|
||||
void ProcessEffects(ItemInfo* item);
|
||||
void UpdateWibble();
|
||||
|
||||
void TriggerDynamicLight(const Vector3& pos, const Color& color, float falloff);
|
||||
|
|
|
@ -321,7 +321,7 @@ namespace TEN::Effects::Hair
|
|||
{
|
||||
auto& unit = Units[i];
|
||||
|
||||
auto objectID = (i == 0) ? ID_SINGLE_BRAID_HAIR : ID_DUAL_PIGTAIL_HAIR;
|
||||
auto objectID = (i == 0) ? ID_HAIR_PRIMARY : ID_HAIR_SECONDARY;
|
||||
const auto& object = Objects[objectID];
|
||||
|
||||
unit.IsEnabled = (object.loaded && (i == 0 || (i == 1 && isYoung)));
|
||||
|
|
|
@ -53,7 +53,7 @@ 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];
|
||||
std::vector<FIRE_LIST> Fires;
|
||||
|
||||
int GetFreeFireSpark()
|
||||
{
|
||||
|
@ -371,31 +371,21 @@ void UpdateFireProgress()
|
|||
|
||||
void AddFire(int x, int y, int z, short roomNum, float size, short fade)
|
||||
{
|
||||
FIRE_LIST* fptr = &Fires[0];
|
||||
int i = 0;
|
||||
while (fptr->on)
|
||||
{
|
||||
fptr++;
|
||||
if (++i >= MAX_FIRE_LIST)
|
||||
return;
|
||||
}
|
||||
FIRE_LIST newFire;
|
||||
|
||||
if (fade)
|
||||
fptr->on = fade;
|
||||
else
|
||||
fptr->on = 1;
|
||||
newFire.fade = (fade == 0 ? 1 : (unsigned char)fade);
|
||||
newFire.x = x;
|
||||
newFire.y = y;
|
||||
newFire.z = z;
|
||||
newFire.roomNumber = roomNum;
|
||||
newFire.size = size;
|
||||
|
||||
fptr->x = x;
|
||||
fptr->y = y;
|
||||
fptr->z = z;
|
||||
fptr->roomNumber = roomNum;
|
||||
fptr->size = size;
|
||||
Fires.push_back(newFire);
|
||||
}
|
||||
|
||||
void ClearFires()
|
||||
{
|
||||
for (int i = 0; i < MAX_FIRE_LIST; i++)
|
||||
Fires[i].on = false;
|
||||
Fires.clear();
|
||||
}
|
||||
|
||||
void UpdateFireSparks()
|
||||
|
|
|
@ -119,7 +119,7 @@ struct FIRE_LIST
|
|||
int x;
|
||||
int y;
|
||||
int z;
|
||||
byte on;
|
||||
unsigned char fade;
|
||||
float size;
|
||||
short roomNumber;
|
||||
};
|
||||
|
@ -209,7 +209,6 @@ extern int NextSpider;
|
|||
extern int NextGunShell;
|
||||
|
||||
constexpr auto MAX_SPARKS_FIRE = 20;
|
||||
constexpr auto MAX_FIRE_LIST = 32;
|
||||
constexpr auto MAX_SPARKS_SMOKE = 32;
|
||||
constexpr auto MAX_SPARKS_BLOOD = 32;
|
||||
constexpr auto MAX_GUNFLASH = 4;
|
||||
|
@ -221,7 +220,7 @@ extern SMOKE_SPARKS SmokeSparks[MAX_SPARKS_SMOKE];
|
|||
extern GUNSHELL_STRUCT Gunshells[MAX_GUNSHELL];
|
||||
extern BLOOD_STRUCT Blood[MAX_SPARKS_BLOOD];
|
||||
extern SHOCKWAVE_STRUCT ShockWaves[MAX_SHOCKWAVE];
|
||||
extern FIRE_LIST Fires[MAX_FIRE_LIST];
|
||||
extern std::vector<FIRE_LIST> Fires;
|
||||
|
||||
void TriggerBlood(int x, int y, int z, int unk, int num);
|
||||
void TriggerExplosionBubble(int x, int y, int z, short roomNumber);
|
||||
|
@ -236,7 +235,7 @@ void ThrowPoison(const ItemInfo& item, int boneID, const Vector3& offset, const
|
|||
void ThrowPoison(const ItemInfo& item, const CreatureBiteInfo& bite, const Vector3& vel, const Color& colorStart, const Color& colorEnd, int spriteID = 0);
|
||||
void UpdateFireProgress();
|
||||
void ClearFires();
|
||||
void AddFire(int x, int y, int z, short roomNum, float size, short fade);
|
||||
void AddFire(int x, int y, int z, short roomNum, float size, short fade = 1);
|
||||
void UpdateFireSparks();
|
||||
int GetFreeSmokeSpark();
|
||||
void UpdateSmoke();
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#include "Game/items.h"
|
||||
#include "Game/Setup.h"
|
||||
#include "Specific/level.h"
|
||||
#include "Specific/trutils.h"
|
||||
|
||||
using namespace TEN::Collision::Point;
|
||||
using namespace TEN::Utils;
|
||||
|
@ -18,31 +17,6 @@ CreatureInfo* GetCreatureInfo(ItemInfo* item)
|
|||
return (CreatureInfo*)item->Data;
|
||||
}
|
||||
|
||||
void TargetNearestEntity(ItemInfo* item, CreatureInfo* creature, const std::vector<GAME_OBJECT_ID>& keyObjectIds, bool ignoreKeyObjectIds)
|
||||
{
|
||||
float closestDistSqr = INFINITY;
|
||||
for (int itemNumber = 0; itemNumber < g_Level.NumItems; itemNumber++)
|
||||
{
|
||||
auto* targetItem = &g_Level.Items[itemNumber];
|
||||
if (targetItem == nullptr || targetItem->Index == item->Index)
|
||||
continue;
|
||||
|
||||
// Ignore or specifically target key object IDs.
|
||||
if (ignoreKeyObjectIds ? Contains(keyObjectIds, targetItem->ObjectNumber) : !Contains(keyObjectIds, targetItem->ObjectNumber))
|
||||
continue;
|
||||
|
||||
if (targetItem != item && targetItem->HitPoints > 0 && targetItem->Status != ITEM_INVISIBLE)
|
||||
{
|
||||
float distSqr = Vector3i::DistanceSquared(item->Pose.Position, targetItem->Pose.Position);
|
||||
if (distSqr < closestDistSqr)
|
||||
{
|
||||
creature->Enemy = targetItem;
|
||||
closestDistSqr = distSqr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool IsNextSectorValid(const ItemInfo& item, const Vector3& dir, float dist, bool canFloat)
|
||||
{
|
||||
auto projectedPos = Geometry::TranslatePoint(item.Pose.Position, dir, dist);
|
||||
|
|
|
@ -18,5 +18,4 @@ enum LaraMeshMask
|
|||
};
|
||||
|
||||
CreatureInfo* GetCreatureInfo(ItemInfo* item);
|
||||
void TargetNearestEntity(ItemInfo* item, CreatureInfo* creature, const std::vector<GAME_OBJECT_ID>& keyObjectIds = {}, bool ignoreKeyObjectIds = true);
|
||||
bool IsNextSectorValid(const ItemInfo& item, const Vector3& dir, float dist, bool canFloat);
|
||||
|
|
|
@ -2299,10 +2299,22 @@ static void ParseLevel(const Save::SaveGame* s, bool hubMode)
|
|||
|
||||
// Don't load player data in hub mode.
|
||||
if (item->ObjectNumber == ID_LARA && hubMode)
|
||||
{
|
||||
//item->Pose = ToPose(*savedItem->pose());
|
||||
item->RoomNumber = savedItem->room_number();
|
||||
item->Floor = savedItem->floor();
|
||||
item->BoxNumber = savedItem->box_number();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item->Index == Lara.Context.Vehicle && hubMode)
|
||||
{
|
||||
//item->Pose = ToPose(*savedItem->pose());
|
||||
item->RoomNumber = savedItem->room_number();
|
||||
item->Floor = savedItem->floor();
|
||||
item->BoxNumber = savedItem->box_number();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Position
|
||||
item->Pose = ToPose(*savedItem->pose());
|
||||
|
|
|
@ -182,7 +182,7 @@ namespace TEN::Entities::Effects
|
|||
else
|
||||
{
|
||||
// Normal flames.
|
||||
AddFire(item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z, item->RoomNumber, 2.0f, 0);
|
||||
AddFire(item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z, item->RoomNumber, 2.0f);
|
||||
|
||||
TriggerDynamicLight(item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z,
|
||||
16 - (GetRandomControl() & 1),
|
||||
|
|
|
@ -411,7 +411,7 @@ namespace TEN::Entities::Doors
|
|||
|
||||
void ShutThatDoor(DOORPOS_DATA* doorPos, DOOR_DATA* dd)
|
||||
{
|
||||
static const auto WALL_PLANE = Plane(-Vector3::UnitY, -CLICK(127));
|
||||
static const auto WALL_PLANE = Plane(-Vector3::UnitY, (float)NO_HEIGHT);
|
||||
|
||||
FloorInfo* floor = doorPos->floor;
|
||||
|
||||
|
|
|
@ -124,7 +124,7 @@ namespace TEN::Entities::Creatures::TR3
|
|||
else
|
||||
{
|
||||
// NOTE: Ignores other small dinosaurs.
|
||||
TargetNearestEntity(&item, &creature, RaptorIgnoredObjectIds);
|
||||
TargetNearestEntity(item, RaptorIgnoredObjectIds);
|
||||
|
||||
AI_INFO ai;
|
||||
if (item.AIBits)
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "Game/animation.h"
|
||||
#include "Game/control/box.h"
|
||||
#include "Game/control/lot.h"
|
||||
#include "Game/effects/effects.h"
|
||||
#include "Game/effects/tomb4fx.h"
|
||||
#include "Game/Lara/lara.h"
|
||||
|
@ -205,7 +206,7 @@ namespace TEN::Entities::Creatures::TR3
|
|||
}
|
||||
else
|
||||
{
|
||||
TargetNearestEntity(&item, &creature, SealMutantAttackTargetObjectIds, false);
|
||||
TargetNearestEntity(item, SealMutantAttackTargetObjectIds, false);
|
||||
}
|
||||
|
||||
AI_INFO ai;
|
||||
|
|
|
@ -95,7 +95,7 @@ namespace TEN::Entities::Creatures::TR3
|
|||
}
|
||||
else
|
||||
{
|
||||
TargetNearestEntity(item, creature, FlamethrowerTargetIds, false);
|
||||
TargetNearestEntity(*item, FlamethrowerTargetIds, false);
|
||||
}
|
||||
|
||||
AI_INFO AI;
|
||||
|
|
|
@ -33,9 +33,9 @@ namespace TEN::Entities::Vehicles
|
|||
constexpr int KAYAK_VELOCITY_LR_ACCEL = 16 * VEHICLE_VELOCITY_SCALE;
|
||||
constexpr int KAYAK_VELOCITY_HOLD_TURN_DECEL = 0.5f * VEHICLE_VELOCITY_SCALE;
|
||||
constexpr int KAYAK_VELOCITY_FRICTION_DECEL = 0.5f * VEHICLE_VELOCITY_SCALE;
|
||||
|
||||
constexpr int KAYAK_VELOCITY_MAX = 56 * VEHICLE_VELOCITY_SCALE;
|
||||
|
||||
constexpr auto KAYAK_FLAG_PADDLE_MESH = 0x80;
|
||||
constexpr auto KAYAK_WAKE_OFFSET = Vector3(BLOCK(0.1f), 0.0f, BLOCK(0.25f));
|
||||
|
||||
// TODO: Very confusing.
|
||||
|
@ -221,6 +221,20 @@ namespace TEN::Entities::Vehicles
|
|||
// SetupRipple(x, kayakItem->Pose.Position.y, z, -2 - (GetRandomControl() & 1), 0, Objects[ID_KAYAK_PADDLE_TRAIL_SPRITE].meshIndex,TO_RAD(kayakItem->Pose.Orientation.y));
|
||||
}
|
||||
|
||||
void KayakPaddleTake(KayakInfo* kayak, ItemInfo* laraItem)
|
||||
{
|
||||
kayak->Flags |= KAYAK_FLAG_PADDLE_MESH;
|
||||
laraItem->Model.MeshIndex[LM_RHAND] = Objects[ID_KAYAK_LARA_ANIMS].meshIndex + LM_RHAND;
|
||||
laraItem->MeshBits.Clear(KayakLaraLegJoints);
|
||||
}
|
||||
|
||||
void KayakPaddlePut(KayakInfo* kayak, ItemInfo* laraItem)
|
||||
{
|
||||
kayak->Flags &= ~KAYAK_FLAG_PADDLE_MESH;
|
||||
laraItem->Model.MeshIndex[LM_RHAND] = laraItem->Model.BaseMesh + LM_RHAND;
|
||||
laraItem->MeshBits.Set(KayakLaraLegJoints);
|
||||
}
|
||||
|
||||
int KayakGetCollisionAnim(ItemInfo* kayakItem, int xDiff, int zDiff)
|
||||
{
|
||||
xDiff = kayakItem->Pose.Position.x - xDiff;
|
||||
|
@ -897,28 +911,14 @@ namespace TEN::Entities::Vehicles
|
|||
break;
|
||||
|
||||
case KAYAK_STATE_MOUNT_LEFT:
|
||||
if (TestAnimNumber(*laraItem, KAYAK_ANIM_GET_PADDLE) &&
|
||||
frame == 24 &&
|
||||
!(kayak->Flags & 0x80))
|
||||
{
|
||||
kayak->Flags |= 0x80;
|
||||
laraItem->Model.MeshIndex[LM_RHAND] = Objects[ID_KAYAK_LARA_ANIMS].meshIndex + LM_RHAND;
|
||||
laraItem->MeshBits.Clear(KayakLaraLegJoints);
|
||||
}
|
||||
|
||||
if (TestAnimNumber(*laraItem, KAYAK_ANIM_GET_PADDLE) && frame == 24 && !(kayak->Flags & KAYAK_FLAG_PADDLE_MESH))
|
||||
KayakPaddleTake(kayak, laraItem);
|
||||
break;
|
||||
|
||||
case KAYAK_STATE_DISMOUNT:
|
||||
if (TestAnimNumber(*laraItem, KAYAK_ANIM_DISMOUNT_START) &&
|
||||
frame == 27 &&
|
||||
kayak->Flags & 0x80)
|
||||
{
|
||||
kayak->Flags &= ~0x80;
|
||||
laraItem->Model.MeshIndex[LM_RHAND] = laraItem->Model.BaseMesh + LM_RHAND;
|
||||
laraItem->MeshBits.Set(KayakLaraLegJoints);
|
||||
}
|
||||
|
||||
laraItem->Animation.TargetState = laraItem->Animation.RequiredState;
|
||||
if (TestAnimNumber(*laraItem, KAYAK_ANIM_DISMOUNT_START) && frame == 27 && kayak->Flags & KAYAK_FLAG_PADDLE_MESH)
|
||||
KayakPaddlePut(kayak, laraItem);
|
||||
break;
|
||||
|
||||
case KAYAK_STATE_DISMOUNT_LEFT:
|
||||
|
|
|
@ -6,24 +6,27 @@ struct ItemInfo;
|
|||
|
||||
namespace TEN::Entities::Vehicles
|
||||
{
|
||||
KayakInfo* GetKayakInfo(ItemInfo* kayakItem);
|
||||
void InitializeKayak(short itemNumber);
|
||||
|
||||
void KayakPlayerCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll);
|
||||
void DoKayakMount(ItemInfo* kayakItem, ItemInfo* laraItem, VehicleMountType mountType);
|
||||
|
||||
void KayakPaddleTake(KayakInfo* kayak, ItemInfo* laraItem);
|
||||
void KayakPaddlePut(KayakInfo* kayak, ItemInfo* laraItem);
|
||||
|
||||
void KayakDraw(ItemInfo* kayakItem);
|
||||
|
||||
void KayakDoRipple(ItemInfo* kayakItem, int xOffset, int zOffset);
|
||||
|
||||
int KayakGetCollisionAnim(ItemInfo* kayakItem, int xDiff, int zDiff);
|
||||
int KayakDoDynamics(int height, int verticalVelocity, int* y);
|
||||
int KayakGetCollisionAnim(ItemInfo* kayakItem, int xDiff, int zDiff);
|
||||
int KayakDoDynamics(int height, int verticalVelocity, int* y);
|
||||
void KayakDoCurrent(ItemInfo* kayakItem, ItemInfo* laraItem);
|
||||
bool KayakCanGetOut(ItemInfo* kayakItem, int dir);
|
||||
int KayakDoShift(ItemInfo* kayakItem, Vector3i* pos, Vector3i* old);
|
||||
int KayakDoShift(ItemInfo* kayakItem, Vector3i* pos, Vector3i* old);
|
||||
void KayakToBackground(ItemInfo* kayakItem, ItemInfo* laraItem);
|
||||
void KayakUserInput(ItemInfo* kayakItem, ItemInfo* laraItem);
|
||||
void KayakToItemCollision(ItemInfo* kayakItem, ItemInfo* laraItem);
|
||||
void KayakLaraRapidsDrown(ItemInfo* laraItem);
|
||||
void PreDrawWakeFx(ItemInfo* kayakItem);
|
||||
bool KayakControl(ItemInfo* laraItem);
|
||||
}
|
||||
|
|
|
@ -241,6 +241,18 @@ namespace TEN::Entities::Vehicles
|
|||
}
|
||||
}
|
||||
|
||||
void MinecartWrenchTake(MinecartInfo* minecart, ItemInfo* laraItem)
|
||||
{
|
||||
laraItem->Model.MeshIndex[LM_RHAND] = Objects[ID_MINECART_LARA_ANIMS].meshIndex + LM_RHAND;
|
||||
minecart->Flags |= MINECART_FLAG_WRENCH_MESH;
|
||||
}
|
||||
|
||||
void MinecartWrenchPut(MinecartInfo* minecart, ItemInfo* laraItem)
|
||||
{
|
||||
laraItem->Model.MeshIndex[LM_RHAND] = laraItem->Model.BaseMesh + LM_RHAND;
|
||||
minecart->Flags &= ~MINECART_FLAG_WRENCH_MESH;
|
||||
}
|
||||
|
||||
static int GetMinecartCollision(ItemInfo* minecartItem, short angle, int distance)
|
||||
{
|
||||
auto probe = GetPointCollision(*minecartItem, angle, distance, -LARA_HEIGHT);
|
||||
|
@ -755,8 +767,7 @@ namespace TEN::Entities::Vehicles
|
|||
if (laraItem->Animation.FrameNumber == GetFrameIndex(minecartItem, MINECART_WRENCH_MESH_TOGGLE_FRAME) &&
|
||||
minecart->Flags & MINECART_FLAG_WRENCH_MESH)
|
||||
{
|
||||
laraItem->Model.MeshIndex[LM_RHAND] = laraItem->Model.BaseMesh + LM_RHAND;
|
||||
minecart->Flags &= ~MINECART_FLAG_WRENCH_MESH;
|
||||
MinecartWrenchPut(minecart, laraItem);
|
||||
}
|
||||
|
||||
if (minecart->Flags & MINECART_FLAG_DISMOUNT_RIGHT)
|
||||
|
@ -804,8 +815,7 @@ namespace TEN::Entities::Vehicles
|
|||
if (!(minecart->Flags & MINECART_FLAG_WRENCH_MESH) &&
|
||||
laraItem->Animation.FrameNumber == GetFrameIndex(minecartItem, MINECART_WRENCH_MESH_TOGGLE_FRAME))
|
||||
{
|
||||
laraItem->Model.MeshIndex[LM_RHAND] = Objects[ID_MINECART_LARA_ANIMS].meshIndex + LM_RHAND;
|
||||
minecart->Flags |= MINECART_FLAG_WRENCH_MESH;
|
||||
MinecartWrenchTake(minecart, laraItem);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,9 +7,13 @@ struct ItemInfo;
|
|||
namespace TEN::Entities::Vehicles
|
||||
{
|
||||
void InitializeMinecart(short itemNumber);
|
||||
MinecartInfo* GetMinecartInfo(ItemInfo* minecartItem);
|
||||
|
||||
void MinecartPlayerCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll);
|
||||
void DoMinecartMount(ItemInfo* minecartItem, ItemInfo* laraItem, VehicleMountType mountType);
|
||||
|
||||
bool MinecartControl(ItemInfo* laraItem);
|
||||
|
||||
void MinecartWrenchTake(MinecartInfo* minecart, ItemInfo* laraItem);
|
||||
void MinecartWrenchPut(MinecartInfo* minecart, ItemInfo* laraItem);
|
||||
}
|
||||
|
|
|
@ -151,21 +151,13 @@ namespace TEN::Entities::Vehicles
|
|||
UPV_BITE_RIGHT_RUDDER_RIGHT = 4,
|
||||
UPV_BITE_RIGHT_RUDDER_LEFT = 5 // Unused.
|
||||
};
|
||||
enum UPVFlags
|
||||
{
|
||||
UPV_FLAG_CONTROL = (1 << 0),
|
||||
UPV_FLAG_SURFACE = (1 << 1),
|
||||
UPV_FLAG_DIVE = (1 << 2),
|
||||
UPV_FLAG_DEAD = (1 << 3)
|
||||
};
|
||||
|
||||
|
||||
UPVInfo* GetUPVInfo(ItemInfo* UPVItem)
|
||||
{
|
||||
return (UPVInfo*)UPVItem->Data;
|
||||
}
|
||||
|
||||
void UPVInitialize(short itemNumber)
|
||||
void InitializeUPV(short itemNumber)
|
||||
{
|
||||
auto* UPVItem = &g_Level.Items[itemNumber];
|
||||
UPVItem->Data = UPVInfo();
|
||||
|
|
|
@ -6,7 +6,16 @@ struct ItemInfo;
|
|||
|
||||
namespace TEN::Entities::Vehicles
|
||||
{
|
||||
void UPVInitialize(short itemNumber);
|
||||
enum UPVFlags
|
||||
{
|
||||
UPV_FLAG_CONTROL = (1 << 0),
|
||||
UPV_FLAG_SURFACE = (1 << 1),
|
||||
UPV_FLAG_DIVE = (1 << 2),
|
||||
UPV_FLAG_DEAD = (1 << 3)
|
||||
};
|
||||
|
||||
void InitializeUPV(short itemNumber);
|
||||
UPVInfo* GetUPVInfo(ItemInfo* UPVItem);
|
||||
|
||||
void UPVPlayerCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* coll);
|
||||
void DoUPVMount(ItemInfo* UPVItem, ItemInfo* laraItem, VehicleMountType mountType);
|
||||
|
|
|
@ -583,7 +583,7 @@ static void StartVehicles(ObjectInfo* obj)
|
|||
obj = &Objects[ID_UPV];
|
||||
if (obj->loaded)
|
||||
{
|
||||
obj->Initialize = UPVInitialize;
|
||||
obj->Initialize = InitializeUPV;
|
||||
obj->control = UPVEffects;
|
||||
obj->collision = UPVPlayerCollision;
|
||||
obj->shadowType = ShadowMode::Lara;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "Game/collision/collide_room.h"
|
||||
#include "Game/control/flipeffect.h"
|
||||
#include "Game/effects/effects.h"
|
||||
#include "Game/items.h"
|
||||
#include "Game/Lara/lara.h"
|
||||
#include "Game/Setup.h"
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "Game/animation.h"
|
||||
#include "Game/control/control.h"
|
||||
#include "Game/control/lot.h"
|
||||
#include "Game/effects/effects.h"
|
||||
#include "Game/itemdata/creature_info.h"
|
||||
#include "Game/items.h"
|
||||
|
@ -286,7 +287,7 @@ namespace TEN::Entities::TR4
|
|||
}
|
||||
else
|
||||
{
|
||||
TargetNearestEntity(item, creature);
|
||||
TargetNearestEntity(*item);
|
||||
}
|
||||
|
||||
AI_INFO ai;
|
||||
|
|
|
@ -73,6 +73,6 @@ void SarcophagusCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* c
|
|||
}
|
||||
else
|
||||
{
|
||||
CollectMultiplePickups(sarcItem->Index);
|
||||
CollectCarriedItems(sarcItem);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -591,9 +591,12 @@ namespace TEN::Entities::Creatures::TR5
|
|||
void DoGuardianDeath(int itemNumber, ItemInfo& item)
|
||||
{
|
||||
const auto& guardian = GetGuardianInfo(item);
|
||||
|
||||
ExplodeItemNode(&g_Level.Items[guardian.BaseItem], 0, 0, 128);
|
||||
KillItem(guardian.BaseItem);
|
||||
|
||||
if (g_Level.Items[guardian.BaseItem].ObjectNumber == ID_LASERHEAD_BASE)
|
||||
{
|
||||
ExplodeItemNode(&g_Level.Items[guardian.BaseItem], 0, 0, 128);
|
||||
KillItem(guardian.BaseItem);
|
||||
}
|
||||
|
||||
ExplodeItemNode(&item, 0, 0, 128);
|
||||
|
||||
|
@ -605,7 +608,6 @@ namespace TEN::Entities::Creatures::TR5
|
|||
TriggerShockwave(&item.Pose, 32, 160, 64, 0, 128, 64, 36, EulerAngles(0x3000, 0.0f, 0.0f), 0, true, false, false, (int)ShockwaveStyle::Normal);
|
||||
TriggerShockwave(&item.Pose, 32, 160, 64, 0, 128, 64, 36, EulerAngles(0x6000, 0.0f, 0.0f), 0, true, false, false, (int)ShockwaveStyle::Normal);
|
||||
|
||||
g_Level.Items[guardian.PuzzleItem].Pose.Position.y = item.Pose.Position.y;
|
||||
TestTriggers(&item, true);
|
||||
|
||||
SoundEffect(SFX_TR5_GOD_HEAD_BLAST, &item.Pose, SoundEnvironment::Land, 0.5f);
|
||||
|
|
|
@ -21,6 +21,5 @@ namespace TEN::Entities::Creatures::TR5
|
|||
short yRot;
|
||||
int BaseItem;
|
||||
std::array<int, GUARDIAN_TENTACLE_COUNT> Tentacles = {};
|
||||
int PuzzleItem;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -93,7 +93,7 @@ namespace TEN::Entities::Generic
|
|||
|
||||
void ShakeRaisingBlock(ItemInfo* item)
|
||||
{
|
||||
SoundEffect(SFX_TR4_RAISING_BLOCK, &item->Pose);
|
||||
SoundEffect(SFX_TR4_RAISING_BLOCK_2, &item->Pose);
|
||||
|
||||
if (item->TriggerFlags == 0)
|
||||
return;
|
||||
|
|
|
@ -128,7 +128,7 @@ namespace TEN::Entities::Generic
|
|||
}
|
||||
else
|
||||
{
|
||||
SoundEffect(SFX_TR4_RUMBLE_NEXTDOOR, &item->Pose);
|
||||
SoundEffect(SFX_TR4_RAISING_BLOCK_2, &item->Pose);
|
||||
item->Pose.Position.y -= 4;
|
||||
}
|
||||
}
|
||||
|
@ -140,7 +140,7 @@ namespace TEN::Entities::Generic
|
|||
}
|
||||
else
|
||||
{
|
||||
SoundEffect(SFX_TR4_RUMBLE_NEXTDOOR, &item->Pose);
|
||||
SoundEffect(SFX_TR4_RAISING_BLOCK_2, &item->Pose);
|
||||
item->Pose.Position.y += 4;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ void SmashObject(short itemNumber)
|
|||
|
||||
auto* box = &g_Level.PathfindingBoxes[room->Sectors[sector].PathfindingBoxID];
|
||||
if (box->flags & 0x8000)
|
||||
box->flags &= ~BOX_BLOCKED;
|
||||
box->flags &= ~BLOCKED;
|
||||
|
||||
SoundEffect(SFX_TR5_SMASH_GLASS, &item->Pose);
|
||||
|
||||
|
|
|
@ -40,8 +40,8 @@ enum GAME_OBJECT_ID : short
|
|||
ID_LARA_DIRT_MESH,
|
||||
ID_LARA_CROWBAR_ANIM,
|
||||
ID_LARA_TORCH_ANIM,
|
||||
ID_SINGLE_BRAID_HAIR,
|
||||
ID_DUAL_PIGTAIL_HAIR,
|
||||
ID_HAIR_PRIMARY,
|
||||
ID_HAIR_SECONDARY,
|
||||
|
||||
ID_SNOWMOBILE_LARA_ANIMS = 50,
|
||||
ID_SNOWMOBILE,
|
||||
|
|
|
@ -516,7 +516,7 @@ namespace TEN::Renderer
|
|||
&moveable,
|
||||
&g_Level.Meshes[obj->meshIndex + j],
|
||||
j, MoveablesIds[i] == ID_LARA_SKIN_JOINTS,
|
||||
MoveablesIds[i] == ID_SINGLE_BRAID_HAIR || MoveablesIds[i] == ID_DUAL_PIGTAIL_HAIR, &lastVertex, &lastIndex);
|
||||
MoveablesIds[i] == ID_HAIR_PRIMARY || MoveablesIds[i] == ID_HAIR_SECONDARY, &lastVertex, &lastIndex);
|
||||
|
||||
moveable.ObjectMeshes.push_back(mesh);
|
||||
_meshes.push_back(mesh);
|
||||
|
@ -687,7 +687,7 @@ namespace TEN::Renderer
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (MoveablesIds[i] == ID_SINGLE_BRAID_HAIR && isSkinPresent)
|
||||
else if (MoveablesIds[i] == ID_HAIR_PRIMARY && isSkinPresent)
|
||||
{
|
||||
for (int j = 0; j < obj->nmeshes; j++)
|
||||
{
|
||||
|
@ -776,7 +776,7 @@ namespace TEN::Renderer
|
|||
}
|
||||
}
|
||||
}
|
||||
else if (MoveablesIds[i] == ID_DUAL_PIGTAIL_HAIR && isSkinPresent)
|
||||
else if (MoveablesIds[i] == ID_HAIR_SECONDARY && isSkinPresent)
|
||||
{
|
||||
for (int j = 0; j < obj->nmeshes; j++)
|
||||
{
|
||||
|
|
|
@ -50,7 +50,6 @@ extern BLOOD_STRUCT Blood[MAX_SPARKS_BLOOD];
|
|||
extern FIRE_SPARKS FireSparks[MAX_SPARKS_FIRE];
|
||||
extern SMOKE_SPARKS SmokeSparks[MAX_SPARKS_SMOKE];
|
||||
extern SHOCKWAVE_STRUCT ShockWaves[MAX_SHOCKWAVE];
|
||||
extern FIRE_LIST Fires[MAX_FIRE_LIST];
|
||||
extern Particle Particles[MAX_PARTICLES];
|
||||
extern SPLASH_STRUCT Splashes[MAX_SPLASHES];
|
||||
extern std::array<DebrisFragment, MAX_DEBRIS> DebrisFragments;
|
||||
|
@ -293,26 +292,22 @@ namespace TEN::Renderer
|
|||
|
||||
void Renderer::PrepareFires(RenderView& view)
|
||||
{
|
||||
for (int k = 0; k < MAX_FIRE_LIST; k++)
|
||||
for (const auto& fire : Fires)
|
||||
{
|
||||
auto* fire = &Fires[k];
|
||||
if (fire->on)
|
||||
{
|
||||
auto fade = fire->on == 1 ? 1.0f : (float)(255 - fire->on) / 255.0f;
|
||||
auto fade = (fire.fade == 1 ? 1.0f : (float)(255 - fire.fade) / 255.0f);
|
||||
|
||||
for (int i = 0; i < MAX_SPARKS_FIRE; i++)
|
||||
for (int i = 0; i < MAX_SPARKS_FIRE; i++)
|
||||
{
|
||||
auto* spark = &FireSparks[i];
|
||||
if (spark->on)
|
||||
{
|
||||
auto* spark = &FireSparks[i];
|
||||
if (spark->on)
|
||||
{
|
||||
AddSpriteBillboard(
|
||||
&_sprites[spark->def],
|
||||
Vector3(fire->x + spark->x * fire->size / 2, fire->y + spark->y * fire->size / 2, fire->z + spark->z * fire->size / 2),
|
||||
Vector4(spark->r / 255.0f * fade, spark->g / 255.0f * fade, spark->b / 255.0f * fade, 1.0f),
|
||||
TO_RAD(spark->rotAng << 4),
|
||||
spark->scalar,
|
||||
Vector2(spark->size * fire->size, spark->size * fire->size), BlendMode::Additive, true, view);
|
||||
}
|
||||
AddSpriteBillboard(
|
||||
&_sprites[spark->def],
|
||||
Vector3(fire.x + spark->x * fire.size / 2, fire.y + spark->y * fire.size / 2, fire.z + spark->z * fire.size / 2),
|
||||
Vector4(spark->r / 255.0f * fade, spark->g / 255.0f * fade, spark->b / 255.0f * fade, 1.0f),
|
||||
TO_RAD(spark->rotAng << 4),
|
||||
spark->scalar,
|
||||
Vector2(spark->size * fire.size, spark->size * fire.size), BlendMode::Additive, true, view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1260,8 +1260,8 @@ namespace TEN::Renderer
|
|||
case RendererDebugPage::PlayerStats:
|
||||
PrintDebugMessage("PLAYER STATS");
|
||||
PrintDebugMessage("AnimObjectID: %d", LaraItem->Animation.AnimObjectID);
|
||||
PrintDebugMessage("AnimNumber: %d", LaraItem->Animation.AnimNumber);
|
||||
PrintDebugMessage("FrameNumber: %d", LaraItem->Animation.FrameNumber);
|
||||
PrintDebugMessage("AnimNumber: %d", LaraItem->Animation.AnimNumber - Objects[LaraItem->Animation.AnimObjectID].animIndex);
|
||||
PrintDebugMessage("FrameNumber: %d", LaraItem->Animation.FrameNumber - GetAnimData(LaraItem).frameBase);
|
||||
PrintDebugMessage("ActiveState: %d", LaraItem->Animation.ActiveState);
|
||||
PrintDebugMessage("TargetState: %d", LaraItem->Animation.TargetState);
|
||||
PrintDebugMessage("Velocity: %.3f, %.3f, %.3f", LaraItem->Animation.Velocity.z, LaraItem->Animation.Velocity.y, LaraItem->Animation.Velocity.x);
|
||||
|
|
|
@ -85,6 +85,9 @@ void Renderer::UpdateLaraAnimations(bool force)
|
|||
if (!force && rItem.DoneAnimations)
|
||||
return;
|
||||
|
||||
if (_moveableObjects.empty())
|
||||
return;
|
||||
|
||||
auto& playerObject = *_moveableObjects[ID_LARA];
|
||||
|
||||
// Clear extra rotations.
|
||||
|
|
|
@ -22,10 +22,8 @@ static constexpr char ScriptReserved_Sink[] = "Sink";
|
|||
static constexpr char ScriptReserved_SoundSource[] = "SoundSource";
|
||||
static constexpr char ScriptReserved_AIObject[] = "AIObject";
|
||||
static constexpr char ScriptReserved_Volume[] = "Volume";
|
||||
static constexpr char ScriptReserved_Room[] = "Room";
|
||||
static constexpr char ScriptReserved_Color[] = "Color";
|
||||
static constexpr char ScriptReserved_DisplayString[] = "DisplayString";
|
||||
static constexpr char ScriptReserved_Vec2[] = "Vec2";
|
||||
static constexpr char ScriptReserved_Rotation[] = "Rotation";
|
||||
static constexpr char ScriptReserved_LevelFunc[] = "LevelFunc";
|
||||
|
||||
|
@ -122,6 +120,7 @@ static constexpr char ScriptReserved_SetFlags[] = "SetFlags";
|
|||
static constexpr char ScriptReserved_SetTranslated[] = "SetTranslated";
|
||||
static constexpr char ScriptReserved_GetPosition[] = "GetPosition";
|
||||
static constexpr char ScriptReserved_GetJointPosition[] = "GetJointPosition";
|
||||
static constexpr char ScriptReserved_GetJointRotation[] = "GetJointRotation";
|
||||
static constexpr char ScriptReserved_SetPosition[] = "SetPosition";
|
||||
static constexpr char ScriptReserved_GetRotation[] = "GetRotation";
|
||||
static constexpr char ScriptReserved_SetRotation[] = "SetRotation";
|
||||
|
@ -198,7 +197,6 @@ static constexpr char ScriptReserved_IsMoveableInside[] = "IsMoveableInside";
|
|||
static constexpr char ScriptReserved_GetFlag[] = "GetFlag";
|
||||
static constexpr char ScriptReserved_SetFlag[] = "SetFlag";
|
||||
static constexpr char ScriptReserved_IsTagPresent[] = "IsTagPresent";
|
||||
static constexpr char ScriptReserved_SetReverbType[] = "SetReverbType";
|
||||
|
||||
// Flow Functions
|
||||
static constexpr char ScriptReserved_AddLevel[] = "AddLevel";
|
||||
|
@ -230,6 +228,7 @@ static constexpr char ScriptReserved_EnablePointFilter[] = "EnablePointFilter";
|
|||
// Flow Functions
|
||||
static constexpr char ScriptReserved_SetStrings[] = "SetStrings";
|
||||
static constexpr char ScriptReserved_GetString[] = "GetString";
|
||||
static constexpr char ScriptReserved_IsStringPresent[] = "IsStringPresent";
|
||||
static constexpr char ScriptReserved_SetLanguageNames[] = "SetLanguageNames";
|
||||
|
||||
// Flow Tables
|
||||
|
@ -372,22 +371,39 @@ static constexpr char ScriptReserved_LogLevelError[] = "ERROR";
|
|||
// Internal
|
||||
static constexpr char ScriptReserved_LaraObject[] = "LaraObject";
|
||||
|
||||
// Room
|
||||
|
||||
constexpr char ScriptReserved_Room[] = "Room";
|
||||
constexpr char ScriptReserved_RoomGetActive[] = "GetActive";
|
||||
constexpr char ScriptReserved_RoomGetColor[] = "GetColor";
|
||||
constexpr char ScriptReserved_RoomGetFlag[] = "GetFlag";
|
||||
constexpr char ScriptReserved_RoomGetName[] = "GetName";
|
||||
constexpr char ScriptReserved_RoomGetReverbType[] = "GetReverbType";
|
||||
constexpr char ScriptReserved_RoomGetRoomNumber[] = "GetRoomNumber";
|
||||
constexpr char ScriptReserved_RoomIsTagPresent[] = "IsTagPresent";
|
||||
constexpr char ScriptReserved_RoomSetFlag[] = "SetFlag";
|
||||
constexpr char ScriptReserved_RoomSetName[] = "SetName";
|
||||
constexpr char ScriptReserved_RoomSetReverbType[] = "SetReverbType";
|
||||
|
||||
// Vec2
|
||||
|
||||
constexpr char ScriptReserved_Vec2[] = "Vec2";
|
||||
constexpr char ScriptReserved_Vec2Cross[] = "Cross";
|
||||
constexpr char ScriptReserved_Vec2Distance[] = "Distance";
|
||||
constexpr char ScriptReserved_Vec2Dot[] = "Dot";
|
||||
constexpr char ScriptReserved_Vec2Length[] = "Length";
|
||||
constexpr char ScriptReserved_Vec2Lerp[] = "Lerp";
|
||||
constexpr char ScriptReserved_Vec2SetLength[] = "ToLength";
|
||||
constexpr char ScriptReserved_Vec2Normalize[] = "Normalize";
|
||||
constexpr char ScriptReserved_Vec2Rotate[] = "Rotate";
|
||||
constexpr char ScriptReserved_Vec2Lerp[] = "Lerp";
|
||||
constexpr char ScriptReserved_Vec2Cross[] = "Cross";
|
||||
constexpr char ScriptReserved_Vec2Dot[] = "Dot";
|
||||
constexpr char ScriptReserved_Vec2Distance[] = "Distance";
|
||||
constexpr char ScriptReserved_Vec2Length[] = "Length";
|
||||
|
||||
// Vec3
|
||||
|
||||
constexpr char ScriptReserved_Vec3[] = "Vec3";
|
||||
constexpr char ScriptReserved_Vec3Cross[] = "Cross";
|
||||
constexpr char ScriptReserved_Vec3Distance[] = "Distance";
|
||||
constexpr char ScriptReserved_Vec3Dot[] = "Dot";
|
||||
constexpr char ScriptReserved_Vec3Length[] = "Length";
|
||||
constexpr char ScriptReserved_Vec3Lerp[] = "Lerp";
|
||||
constexpr char ScriptReserved_Vec3Normalize[] = "Normalize";
|
||||
constexpr char ScriptReserved_Vec3Rotate[] = "Rotate";
|
||||
constexpr char ScriptReserved_Vec3Lerp[] = "Lerp";
|
||||
constexpr char ScriptReserved_Vec3Cross[] = "Cross";
|
||||
constexpr char ScriptReserved_Vec3Dot[] = "Dot";
|
||||
constexpr char ScriptReserved_Vec3Distance[] = "Distance";
|
||||
constexpr char ScriptReserved_Vec3Length[] = "Length";
|
||||
|
|
|
@ -284,7 +284,7 @@ namespace TEN::Scripting::Effects
|
|||
*/
|
||||
static void EmitFire(Vec3 pos, TypeOrNil<float> size)
|
||||
{
|
||||
AddFire(pos.x, pos.y, pos.z, FindRoomNumber(Vector3i(pos.x, pos.y, pos.z)), USE_IF_HAVE(float, size, 1), 0);
|
||||
AddFire(pos.x, pos.y, pos.z, FindRoomNumber(Vector3i(pos.x, pos.y, pos.z)), USE_IF_HAVE(float, size, 1));
|
||||
}
|
||||
|
||||
/***Make an explosion. Does not hurt Lara
|
||||
|
|
|
@ -248,6 +248,12 @@ You will not need to call them manually.
|
|||
*/
|
||||
tableFlow.set_function(ScriptReserved_GetString, &FlowHandler::GetString, this);
|
||||
|
||||
/*** Check if translated string is present.
|
||||
@function IsStringPresent
|
||||
@tparam key string key for translated string
|
||||
*/
|
||||
tableFlow.set_function(ScriptReserved_IsStringPresent, &FlowHandler::IsStringPresent, this);
|
||||
|
||||
/*** Set language names for translations.
|
||||
Specify which translations in the strings table correspond to which languages.
|
||||
@function SetLanguageNames
|
||||
|
@ -371,6 +377,11 @@ char const * FlowHandler::GetString(const char* id) const
|
|||
}
|
||||
}
|
||||
|
||||
bool FlowHandler::IsStringPresent(const char* id) const
|
||||
{
|
||||
return _translationMap.find(id) != _translationMap.end();
|
||||
}
|
||||
|
||||
Settings* FlowHandler::GetSettings()
|
||||
{
|
||||
return &_settings;
|
||||
|
|
|
@ -51,6 +51,7 @@ public:
|
|||
void AddLevel(Level const& level);
|
||||
void LoadFlowScript();
|
||||
char const* GetString(const char* id) const;
|
||||
bool IsStringPresent(const char* id) const;
|
||||
void SetStrings(sol::nested<std::unordered_map<std::string, std::vector<std::string>>>&& src);
|
||||
void SetLanguageNames(sol::as_table_t<std::vector<std::string>>&& src);
|
||||
void SetAnimations(const Animations& src);
|
||||
|
|
|
@ -79,7 +79,7 @@ most can just be ignored (see usage).
|
|||
@tparam string name Lua name of the item
|
||||
@tparam Vec3 position position in level
|
||||
@tparam Rotation rotation rotation rotation about x, y, and z axes (default Rotation(0, 0, 0))
|
||||
@tparam int roomID room ID item is in (default: calculated automatically)
|
||||
@tparam int roomNumber the room number the moveable is in (default: calculated automatically).
|
||||
@tparam int animNumber animation number
|
||||
@tparam int frameNumber frame number
|
||||
@tparam int hp HP of item
|
||||
|
@ -179,14 +179,14 @@ void Moveable::Register(sol::state& state, sol::table& parent)
|
|||
/// Set effect to moveable
|
||||
// @function Moveable:SetEffect
|
||||
// @tparam Effects.EffectID effect Type of effect to assign.
|
||||
// @tparam float timeout time (in seconds) after which effect turns off (optional).
|
||||
// @tparam[opt] float timeout time (in seconds) after which effect turns off.
|
||||
ScriptReserved_SetEffect, &Moveable::SetEffect,
|
||||
|
||||
/// Set custom colored burn effect to moveable
|
||||
// @function Moveable:SetCustomEffect
|
||||
// @tparam Color Color1 color the primary color of the effect (also used for lighting).
|
||||
// @tparam Color Color2 color the secondary color of the effect.
|
||||
// @tparam float timeout time (in seconds) after which effect turns off (optional).
|
||||
// @tparam[opt] float timeout time (in seconds) after which effect turns off.
|
||||
ScriptReserved_SetCustomEffect, &Moveable::SetCustomEffect,
|
||||
|
||||
/// Get current moveable effect
|
||||
|
@ -365,9 +365,16 @@ ScriptReserved_GetSlotHP, & Moveable::GetSlotHP,
|
|||
/// Get the object's joint position
|
||||
// @function Moveable:GetJointPosition
|
||||
// @tparam int index of a joint to get position
|
||||
// @treturn Vec3 a copy of the moveable's position
|
||||
// @tparam[opt] Vec3 offset a pre-rotation offset to the joint
|
||||
// @treturn Vec3 a copy of the moveable's joint position
|
||||
ScriptReserved_GetJointPosition, & Moveable::GetJointPos,
|
||||
|
||||
/// Get the object's joint rotation
|
||||
// @function Moveable:GetJointRotation
|
||||
// @tparam int index of a joint to get rotation
|
||||
// @treturn Rotation a calculated copy of the moveable's joint rotation
|
||||
ScriptReserved_GetJointRotation, & Moveable::GetJointRot,
|
||||
|
||||
ScriptReserved_SetPosition, & Moveable::SetPos,
|
||||
|
||||
/// Get the moveable's rotation
|
||||
|
@ -428,6 +435,9 @@ ScriptReserved_GetSlotHP, & Moveable::GetSlotHP,
|
|||
// @function Moveable:SetOnCollidedWithObject
|
||||
// @tparam function func callback function to be called (must be in LevelFuncs hierarchy). This function can take two arguments; these will store the two @{Moveable}s taking part in the collision.
|
||||
// @usage
|
||||
// -- obj1 is the collision moveable
|
||||
// -- obj2 is the collider moveable
|
||||
//
|
||||
// LevelFuncs.objCollided = function(obj1, obj2)
|
||||
// print(obj1:GetName() .. " collided with " .. obj2:GetName())
|
||||
// end
|
||||
|
@ -603,12 +613,18 @@ void Moveable::SetPos(const Vec3& pos, sol::optional<bool> updateRoom)
|
|||
UpdateBridgeItem(*m_item);
|
||||
}
|
||||
|
||||
Vec3 Moveable::GetJointPos(int jointIndex) const
|
||||
Vec3 Moveable::GetJointPos(int jointIndex, sol::optional<Vec3> offset) const
|
||||
{
|
||||
auto result = GetJointPosition(m_item, jointIndex);
|
||||
Vector3i vec = offset.has_value() ? offset->ToVector3i() : Vector3i(0, 0, 0);
|
||||
auto result = GetJointPosition(m_item, jointIndex, vec);
|
||||
return Vec3(result.x, result.y, result.z);
|
||||
}
|
||||
|
||||
Rotation Moveable::GetJointRot(int jointIndex) const
|
||||
{
|
||||
return GetBoneOrientation(*m_item, jointIndex);
|
||||
}
|
||||
|
||||
// This does not guarantee that the returned value will be identical
|
||||
// to a value written in via SetRot - only that the angle measures
|
||||
// will be mathematically equal
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include "Scripting/Internal/ScriptUtil.h"
|
||||
#include "Scripting/Internal/TEN/Objects/NamedBase.h"
|
||||
#include "Scripting/Internal/TEN/Objects/Room/RoomObject.h"
|
||||
|
@ -47,9 +48,10 @@ public:
|
|||
void Destroy();
|
||||
|
||||
[[nodiscard]] Vec3 GetPos() const;
|
||||
[[nodiscard]] Vec3 GetJointPos(int index) const;
|
||||
[[nodiscard]] Vec3 GetJointPos(int index, sol::optional<Vec3> offset) const;
|
||||
void SetPos(const Vec3& pos, sol::optional<bool> updateRoom);
|
||||
|
||||
[[nodiscard]] Rotation GetJointRot(int index) const;
|
||||
[[nodiscard]] Rotation GetRot() const;
|
||||
void SetRot(const Rotation& rot);
|
||||
|
||||
|
|
|
@ -53,8 +53,8 @@ The following constants are inside ObjID.
|
|||
LARA_DIRT_MESH
|
||||
LARA_CROWBAR_ANIM
|
||||
LARA_TORCH_ANIM
|
||||
SINGLE_BRAID_HAIR
|
||||
DUAL_PIGTAIL_HAIR
|
||||
HAIR_PRIMARY
|
||||
HAIR_SECONDARY
|
||||
SNOWMOBILE_LARA_ANIMS
|
||||
SNOWMOBILE
|
||||
QUAD_LARA_ANIMS
|
||||
|
@ -1231,8 +1231,8 @@ static const std::unordered_map<std::string, GAME_OBJECT_ID> kObjIDs {
|
|||
{ "LARA_DIRT_MESH", ID_LARA_DIRT_MESH },
|
||||
{ "LARA_CROWBAR_ANIM", ID_LARA_CROWBAR_ANIM },
|
||||
{ "LARA_TORCH_ANIM", ID_LARA_TORCH_ANIM },
|
||||
{ "SINGLE_BRAID_HAIR", ID_SINGLE_BRAID_HAIR },
|
||||
{ "DUAL_PIGTAIL_HAIR", ID_DUAL_PIGTAIL_HAIR },
|
||||
{ "HAIR_PRIMARY", ID_HAIR_PRIMARY },
|
||||
{ "HAIR_SECONDARY", ID_HAIR_SECONDARY },
|
||||
{ "SNOWMOBILE_LARA_ANIMS", ID_SNOWMOBILE_LARA_ANIMS },
|
||||
{ "SNOWMOBILE", ID_SNOWMOBILE },
|
||||
{ "QUAD_LARA_ANIMS", ID_QUAD_LARA_ANIMS },
|
||||
|
|
|
@ -13,141 +13,148 @@
|
|||
#include "Specific/level.h"
|
||||
#include "Specific/trutils.h"
|
||||
|
||||
/***
|
||||
Rooms
|
||||
/// Room object.
|
||||
// @tenclass Objects.Room
|
||||
// @pragma nostrip
|
||||
|
||||
@tenclass Objects.Room
|
||||
@pragma nostrip
|
||||
*/
|
||||
//namespace TEN::Scripting
|
||||
//{
|
||||
static auto IndexError = index_error_maker(Room, ScriptReserved_Volume);
|
||||
static auto NewIndexError = newindex_error_maker(Room, ScriptReserved_Volume);
|
||||
|
||||
static auto IndexError = index_error_maker(Room, ScriptReserved_Volume);
|
||||
static auto NewIndexError = newindex_error_maker(Room, ScriptReserved_Volume);
|
||||
|
||||
Room::Room(ROOM_INFO& room) : m_room{ room }
|
||||
{};
|
||||
|
||||
void Room::Register(sol::table& parent)
|
||||
{
|
||||
parent.new_usertype<Room>(ScriptReserved_Room,
|
||||
sol::no_constructor,
|
||||
sol::meta_function::index, IndexError,
|
||||
sol::meta_function::new_index, NewIndexError,
|
||||
|
||||
/// Determine whether the room is active or not
|
||||
// @function Room:GetActive
|
||||
// @treturn bool true if the room is active
|
||||
ScriptReserved_GetActive, &Room::GetActive,
|
||||
|
||||
/// Get the room's ambient light color.
|
||||
// @function Room:GetColor
|
||||
// @treturn Color ambient light color of the room
|
||||
ScriptReserved_GetColor, & Room::GetColor,
|
||||
|
||||
/// Get the room's reverb type.
|
||||
// @function Room:GetReverbType
|
||||
// @treturn Objects.RoomReverb room's reverb type
|
||||
ScriptReserved_GetPosition, &Room::GetReverbType,
|
||||
|
||||
/// Set the room's reverb type.
|
||||
// @function Room:SetReverbType
|
||||
// @tparam Objects.RoomReverb new reverb type of the room
|
||||
ScriptReserved_SetReverbType, &Room::SetReverbType,
|
||||
|
||||
/// Get the room's unique string identifier.
|
||||
// @function Room:GetName
|
||||
// @treturn string the room's name
|
||||
ScriptReserved_GetName, &Room::GetName,
|
||||
|
||||
/// Set the room's name (its unique string identifier).
|
||||
// @function Room:SetName
|
||||
// @tparam string name The room's new name
|
||||
ScriptReserved_SetName, &Room::SetName,
|
||||
|
||||
/// Get the room's specified flag value (true or false).
|
||||
// @function Room:GetFlag
|
||||
// @tparam Objects.RoomFlagID flagID The room's flag ID
|
||||
// @treturn bool the room's specified flag value
|
||||
ScriptReserved_GetFlag, &Room::GetFlag,
|
||||
|
||||
/// Set the room's specified flag value.
|
||||
// @function Room:SetFlag
|
||||
// @tparam Objects.RoomFlagID flagID The room's flag ID
|
||||
// @tparam bool the room's new flag value
|
||||
ScriptReserved_SetFlag, &Room::SetFlag,
|
||||
|
||||
/// Checks if specified tag is set for this room.
|
||||
// @function Room:IsTagPresent
|
||||
// @tparam string tag A text tag to check (case sensitive)
|
||||
// @treturn bool true if tag is present, false if not
|
||||
ScriptReserved_IsTagPresent, &Room::IsTagPresent);
|
||||
}
|
||||
|
||||
bool Room::GetActive() const
|
||||
{
|
||||
return m_room.Active();
|
||||
}
|
||||
|
||||
ScriptColor Room::GetColor() const
|
||||
{
|
||||
return ScriptColor{ m_room.ambient };
|
||||
}
|
||||
|
||||
ReverbType Room::GetReverbType() const
|
||||
{
|
||||
return m_room.reverbType;
|
||||
}
|
||||
|
||||
void Room::SetReverbType(ReverbType reverb)
|
||||
{
|
||||
m_room.reverbType = reverb;
|
||||
}
|
||||
|
||||
std::string Room::GetName() const
|
||||
{
|
||||
return m_room.Name;
|
||||
}
|
||||
|
||||
void Room::SetName(const std::string& name)
|
||||
{
|
||||
if (!ScriptAssert(!name.empty(), "Unable to set name. Name cannot be blank."))
|
||||
return;
|
||||
|
||||
// Remove old name if it already exists.
|
||||
if (s_callbackSetName(name, m_room))
|
||||
Room::Room(ROOM_INFO& room) :
|
||||
_room(room)
|
||||
{
|
||||
s_callbackRemoveName(m_room.Name);
|
||||
m_room.Name = name;
|
||||
}
|
||||
else
|
||||
};
|
||||
|
||||
void Room::Register(sol::table& parent)
|
||||
{
|
||||
ScriptAssertF(false, "Could not add name {} - does an object with this name already exist?", name);
|
||||
TENLog("Name will not be set", LogLevel::Warning, LogConfig::All);
|
||||
// Register type.
|
||||
parent.new_usertype<Room>(
|
||||
ScriptReserved_Room,
|
||||
sol::no_constructor,
|
||||
sol::meta_function::index, IndexError,
|
||||
sol::meta_function::new_index, NewIndexError,
|
||||
|
||||
ScriptReserved_RoomGetRoomNumber, &Room::GetRoomNumber,
|
||||
ScriptReserved_RoomGetName, &Room::GetName,
|
||||
ScriptReserved_RoomGetColor, &Room::GetColor,
|
||||
ScriptReserved_RoomGetReverbType, &Room::GetReverbType,
|
||||
ScriptReserved_RoomSetName, &Room::SetName,
|
||||
ScriptReserved_RoomSetReverbType, &Room::SetReverbType,
|
||||
ScriptReserved_RoomSetFlag, &Room::SetFlag,
|
||||
ScriptReserved_RoomIsTagPresent, &Room::IsTagPresent,
|
||||
ScriptReserved_RoomGetActive, &Room::GetActive,
|
||||
ScriptReserved_RoomGetFlag, &Room::GetFlag);
|
||||
}
|
||||
}
|
||||
|
||||
bool Room::GetFlag(RoomEnvFlags flag) const
|
||||
{
|
||||
return ((m_room.flags & flag) == flag);
|
||||
}
|
||||
|
||||
void Room::SetFlag(RoomEnvFlags flag, bool value)
|
||||
{
|
||||
if (value)
|
||||
/// Get the room's number.
|
||||
// @function Room:GetRoomNumber()
|
||||
// @treturn int Room number.
|
||||
int Room::GetRoomNumber() const
|
||||
{
|
||||
m_room.flags |= flag;
|
||||
return _room.RoomNumber;
|
||||
}
|
||||
else
|
||||
|
||||
/// Get the room's unique string identifier.
|
||||
// @function Room:GetName()
|
||||
// @treturn string Room name.
|
||||
std::string Room::GetName() const
|
||||
{
|
||||
m_room.flags &= ~flag;
|
||||
return _room.Name;
|
||||
}
|
||||
}
|
||||
|
||||
bool Room::IsTagPresent(const std::string& tag) const
|
||||
{
|
||||
if (m_room.Tags.empty())
|
||||
return false;
|
||||
/// Get the room's ambient light color.
|
||||
// @function Room:GetColor()
|
||||
// @treturn Color Ambient light color.
|
||||
ScriptColor Room::GetColor() const
|
||||
{
|
||||
return ScriptColor(_room.ambient);
|
||||
}
|
||||
|
||||
return std::any_of(
|
||||
m_room.Tags.begin(), m_room.Tags.end(),
|
||||
[&tag](const std::string& value) { return (value == tag); });
|
||||
}
|
||||
/// Get the room's reverb type.
|
||||
// @function Room:GetReverbType()
|
||||
// @treturn Objects.RoomReverb Reverb type.
|
||||
ReverbType Room::GetReverbType() const
|
||||
{
|
||||
return _room.reverbType;
|
||||
}
|
||||
|
||||
/// Set the room's unique string identifier.
|
||||
// @function Room:SetName()
|
||||
// @tparam string name New name.
|
||||
void Room::SetName(const std::string& name)
|
||||
{
|
||||
if (!ScriptAssert(!name.empty(), "Unable to set name. Name cannot be blank."))
|
||||
return;
|
||||
|
||||
// Remove previous name if it already exists.
|
||||
if (s_callbackSetName(name, _room))
|
||||
{
|
||||
s_callbackRemoveName(_room.Name);
|
||||
_room.Name = name;
|
||||
}
|
||||
else
|
||||
{
|
||||
ScriptAssertF(false, "Could not add name {} - does an object with this name already exist?", name);
|
||||
TENLog("Name will not be set", LogLevel::Warning, LogConfig::All);
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the room's reverb type.
|
||||
// @function Room:SetReverbType()
|
||||
// @tparam Objects.RoomReverb Reverb type.
|
||||
void Room::SetReverbType(ReverbType reverb)
|
||||
{
|
||||
_room.reverbType = reverb;
|
||||
}
|
||||
|
||||
/// Set the room's specified flag.
|
||||
// @function Room:SetFlag()
|
||||
// @tparam Objects.RoomFlagID flagID Room flag ID.
|
||||
// @tparam bool Boolean to set the flag to.
|
||||
void Room::SetFlag(RoomEnvFlags flag, bool value)
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
_room.flags |= flag;
|
||||
}
|
||||
else
|
||||
{
|
||||
_room.flags &= ~flag;
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the room's specified flag value (true or false).
|
||||
// @function Room:GetFlag()
|
||||
// @tparam Objects.RoomFlagID flagID Room flag ID.
|
||||
bool Room::IsTagPresent(const std::string& tag) const
|
||||
{
|
||||
if (_room.Tags.empty())
|
||||
return false;
|
||||
|
||||
return std::any_of(
|
||||
_room.Tags.begin(), _room.Tags.end(),
|
||||
[&tag](const std::string& value)
|
||||
{
|
||||
return (value == tag);
|
||||
});
|
||||
}
|
||||
|
||||
/// Check if the specified tag is set for the room.
|
||||
// @function Room:IsTagPresent()
|
||||
// @tparam string tag Text tag to check (case sensitive).
|
||||
// @treturn bool Boolean of the tag's presence.
|
||||
bool Room::GetActive() const
|
||||
{
|
||||
return _room.Active();
|
||||
}
|
||||
|
||||
/// Check if the room is active.
|
||||
// @function Room:GetActive()
|
||||
// @treturn bool Boolean of the room's active status.
|
||||
bool Room::GetFlag(RoomEnvFlags flag) const
|
||||
{
|
||||
return ((_room.flags & flag) == flag);
|
||||
}
|
||||
//}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include "Game/room.h"
|
||||
#include "Scripting/Internal/TEN/Objects/NamedBase.h"
|
||||
|
||||
|
@ -7,32 +8,50 @@ enum class ReverbType;
|
|||
class ScriptColor;
|
||||
class Vec3;
|
||||
|
||||
class Room : public NamedBase<Room, ROOM_INFO&>
|
||||
{
|
||||
public:
|
||||
using IdentifierType = std::reference_wrapper<ROOM_INFO>;
|
||||
Room(ROOM_INFO& room);
|
||||
~Room() = default;
|
||||
//namespace TEN::Scripting
|
||||
//{
|
||||
class Room : public NamedBase<Room, ROOM_INFO&>
|
||||
{
|
||||
private:
|
||||
// Members
|
||||
|
||||
Room& operator =(const Room& other) = delete;
|
||||
Room(const Room& other) = delete;
|
||||
ROOM_INFO& _room;
|
||||
|
||||
static void Register(sol::table& parent);
|
||||
public:
|
||||
using IdentifierType = std::reference_wrapper<ROOM_INFO>;
|
||||
|
||||
[[nodiscard]] bool GetActive() const;
|
||||
[[nodiscard]] ScriptColor GetColor() const;
|
||||
static void Register(sol::table& parent);
|
||||
|
||||
[[nodiscard]] std::string GetName() const;
|
||||
void SetName(const std::string& name);
|
||||
// Constructors
|
||||
|
||||
[[nodiscard]] bool GetFlag(RoomEnvFlags flag) const;
|
||||
void SetFlag(RoomEnvFlags flag, bool value);
|
||||
Room(ROOM_INFO& room);
|
||||
Room(const Room& room) = delete;
|
||||
|
||||
[[nodiscard]] ReverbType GetReverbType() const;
|
||||
void SetReverbType(ReverbType reverbType);
|
||||
// Destructors
|
||||
|
||||
[[nodiscard]] bool IsTagPresent(const std::string& tag) const;
|
||||
~Room() = default;
|
||||
|
||||
private:
|
||||
ROOM_INFO& m_room;
|
||||
};
|
||||
// Getters
|
||||
|
||||
int GetRoomNumber() const;
|
||||
std::string GetName() const;
|
||||
ScriptColor GetColor() const;
|
||||
ReverbType GetReverbType() const;
|
||||
|
||||
// Setters
|
||||
|
||||
void SetName(const std::string& name);
|
||||
void SetReverbType(ReverbType reverbType);
|
||||
void SetFlag(RoomEnvFlags flag, bool value);
|
||||
|
||||
// Inquirers
|
||||
|
||||
bool IsTagPresent(const std::string& tag) const;
|
||||
bool GetActive() const; // TODO: Rename to IsActive().
|
||||
bool GetFlag(RoomEnvFlags flag) const; // TODO: Rename to HasFlag().
|
||||
|
||||
// Operators
|
||||
|
||||
Room& operator =(const Room& room) = delete;
|
||||
};
|
||||
//}
|
||||
|
|
|
@ -9,10 +9,12 @@ public:
|
|||
static void Register(sol::table& parent);
|
||||
|
||||
// Members
|
||||
|
||||
float x = 0;
|
||||
float y = 0;
|
||||
|
||||
// Constructors
|
||||
|
||||
Vec2(float x, float y);
|
||||
Vec2(float value);
|
||||
Vec2(const Vector2& vector);
|
||||
|
@ -28,6 +30,7 @@ public:
|
|||
float Length() const;
|
||||
|
||||
// Meta functions
|
||||
|
||||
std::string ToString() const;
|
||||
static Vec2 Add(const Vec2& vector0, const Vec2& vector1);
|
||||
static Vec2 Subtract(const Vec2& vector0, const Vec2& vector1);
|
||||
|
@ -38,9 +41,11 @@ public:
|
|||
static bool IsEqualTo(const Vec2& vector0, const Vec2& vector1);
|
||||
|
||||
// Converters
|
||||
|
||||
Vector2 ToVector2() const;
|
||||
//Vector2i ToVector2i() const;
|
||||
|
||||
// Operators
|
||||
|
||||
operator Vector2() const;
|
||||
};
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
namespace sol { class state; }
|
||||
class GameVector;
|
||||
class Pose;
|
||||
class Rotation;
|
||||
class Vector3i;
|
||||
namespace sol { class state; }
|
||||
|
||||
class Vec3
|
||||
{
|
||||
|
@ -12,11 +12,13 @@ public:
|
|||
static void Register(sol::table& parent);
|
||||
|
||||
// Members
|
||||
|
||||
float x = 0;
|
||||
float y = 0;
|
||||
float z = 0;
|
||||
|
||||
// Constructors
|
||||
|
||||
Vec3() {};
|
||||
Vec3(float x, float y, float z);
|
||||
Vec3(float value);
|
||||
|
@ -24,6 +26,7 @@ public:
|
|||
Vec3(const Vector3i& vector);
|
||||
|
||||
// Utilities
|
||||
|
||||
Vec3 Normalize() const;
|
||||
Vec3 Rotate(const Rotation& rot) const;
|
||||
Vec3 Lerp(const Vec3& vector, float alpha) const;
|
||||
|
@ -33,6 +36,7 @@ public:
|
|||
float Length() const;
|
||||
|
||||
// Meta functions
|
||||
|
||||
std::string ToString() const;
|
||||
static Vec3 Add(const Vec3& vector0, const Vec3& vector1);
|
||||
static Vec3 Subtract(const Vec3& vector0, const Vec3& vector1);
|
||||
|
@ -43,10 +47,12 @@ public:
|
|||
static bool IsEqualTo(const Vec3& vector0, const Vec3& vector1);
|
||||
|
||||
// Converters
|
||||
|
||||
Vector3 ToVector3() const;
|
||||
Vector3i ToVector3i() const;
|
||||
GameVector ToGameVector() const;
|
||||
|
||||
// Operators
|
||||
|
||||
operator Vector3() const;
|
||||
};
|
||||
|
|
|
@ -151,7 +151,7 @@ enum SOUND_EFFECTS
|
|||
SFX_TR4_LARA_DEATH3 = 146,
|
||||
SFX_TR4_ROLLING_BALL = 147,
|
||||
SFX_TR4_RAISING_BLOCK = 148,
|
||||
SFX_TR4_RUMBLE_NEXTDOOR = 149,
|
||||
SFX_TR4_RAISING_BLOCK_2 = 149,
|
||||
SFX_TR4_LOOP_FOR_SMALL_FIRES = 150,
|
||||
SFX_TR4_CHAINS_LIBRARY = 151,
|
||||
SFX_TR4_VEHICLE_JEEP_START = 152,
|
||||
|
@ -361,7 +361,7 @@ enum SOUND_EFFECTS
|
|||
SFX_TR4_LIGHT_BEAM_LOOP = 356,
|
||||
SFX_TR4_GUIDE_FIRE_LIGHT = 357,
|
||||
SFX_TR4_AUTOGUNS = 358,
|
||||
SFX_TR4_EMPTY8 = 359,
|
||||
SFX_TR4_ENVIORONMENT_RUMBLE = 359,
|
||||
SFX_TR4_STEAM = 360,
|
||||
SFX_TR4_GARAGE_DOOR = 361,
|
||||
SFX_TR4_WIND = 362,
|
||||
|
|
|
@ -632,9 +632,9 @@ namespace TEN::Input
|
|||
{
|
||||
// Save screenshot.
|
||||
static bool dbScreenshot = true;
|
||||
if (KeyMap[KC_SYSRQ] && dbScreenshot)
|
||||
if ((KeyMap[KC_SYSRQ] || KeyMap[KC_F12]) && dbScreenshot)
|
||||
g_Renderer.SaveScreenshot();
|
||||
dbScreenshot = !KeyMap[KC_SYSRQ];
|
||||
dbScreenshot = !(KeyMap[KC_SYSRQ] || KeyMap[KC_F12]);
|
||||
|
||||
// Toggle fullscreen.
|
||||
static bool dbFullscreen = true;
|
||||
|
|
|
@ -3,43 +3,42 @@
|
|||
|
||||
#include "Specific/clock.h"
|
||||
|
||||
|
||||
namespace TEN::Input
|
||||
{
|
||||
InputAction::InputAction(ActionID actionID)
|
||||
{
|
||||
ID = actionID;
|
||||
_id = actionID;
|
||||
}
|
||||
|
||||
ActionID InputAction::GetID() const
|
||||
{
|
||||
return ID;
|
||||
return _id;
|
||||
}
|
||||
|
||||
float InputAction::GetValue() const
|
||||
{
|
||||
return Value;
|
||||
return _value;
|
||||
}
|
||||
|
||||
float InputAction::GetTimeActive() const
|
||||
{
|
||||
return TimeActive;
|
||||
return _timeActive;
|
||||
}
|
||||
|
||||
float InputAction::GetTimeInactive() const
|
||||
{
|
||||
return TimeInactive;
|
||||
return _timeInactive;
|
||||
}
|
||||
|
||||
bool InputAction::IsClicked() const
|
||||
{
|
||||
return ((Value != 0.0f) && (PrevValue == 0.0f));
|
||||
return ((_value != 0.0f) && (_prevValue == 0.0f));
|
||||
}
|
||||
|
||||
bool InputAction::IsHeld(float delayInSec) const
|
||||
{
|
||||
float delayInFrameTime = (delayInSec == 0.0f) ? 0.0f : round(delayInSec / DELTA_TIME);
|
||||
return ((Value != 0.0f) && (TimeActive >= delayInFrameTime));
|
||||
return ((_value != 0.0f) && (_timeActive >= delayInFrameTime));
|
||||
}
|
||||
|
||||
// NOTE: To avoid stutter on second pulse, ensure initialDelayInSec is multiple of delayInSec.
|
||||
|
@ -48,12 +47,12 @@ namespace TEN::Input
|
|||
if (IsClicked())
|
||||
return true;
|
||||
|
||||
if (!IsHeld() || PrevTimeActive == 0.0f || TimeActive == PrevTimeActive)
|
||||
if (!IsHeld() || _prevTimeActive == 0.0f || _timeActive == _prevTimeActive)
|
||||
return false;
|
||||
|
||||
float activeDelayInFrameTime = (TimeActive > round(initialDelayInSec / DELTA_TIME)) ? round(delayInSec / DELTA_TIME) : round(initialDelayInSec / DELTA_TIME);
|
||||
float delayInFrameTime = std::floor(TimeActive / activeDelayInFrameTime) * activeDelayInFrameTime;
|
||||
if (delayInFrameTime > (std::floor(PrevTimeActive / activeDelayInFrameTime) * activeDelayInFrameTime))
|
||||
float activeDelayInFrameTime = (_timeActive > round(initialDelayInSec / DELTA_TIME)) ? round(delayInSec / DELTA_TIME) : round(initialDelayInSec / DELTA_TIME);
|
||||
float delayInFrameTime = std::floor(_timeActive / activeDelayInFrameTime) * activeDelayInFrameTime;
|
||||
if (delayInFrameTime > (std::floor(_prevTimeActive / activeDelayInFrameTime) * activeDelayInFrameTime))
|
||||
return true;
|
||||
|
||||
// Keeping version counting real time for future reference. -- Sezz 2022.10.01
|
||||
|
@ -70,7 +69,7 @@ namespace TEN::Input
|
|||
bool InputAction::IsReleased(float maxDelayInSec) const
|
||||
{
|
||||
float maxDelayInFrameTime = (maxDelayInSec == INFINITY) ? INFINITY : round(maxDelayInSec / DELTA_TIME);
|
||||
return ((Value == 0.0f) && (PrevValue != 0.0f) && (TimeActive <= maxDelayInFrameTime));
|
||||
return ((_value == 0.0f) && (_prevValue != 0.0f) && (_timeActive <= maxDelayInFrameTime));
|
||||
}
|
||||
|
||||
void InputAction::Update(bool value)
|
||||
|
@ -89,57 +88,57 @@ namespace TEN::Input
|
|||
|
||||
if (IsClicked())
|
||||
{
|
||||
PrevTimeActive = 0.0f;
|
||||
TimeActive = 0.0f;
|
||||
TimeInactive += FRAME_TIME;// DELTA_TIME;
|
||||
_prevTimeActive = 0.0f;
|
||||
_timeActive = 0.0f;
|
||||
_timeInactive += FRAME_TIME;// DELTA_TIME;
|
||||
}
|
||||
else if (IsReleased())
|
||||
{
|
||||
PrevTimeActive = TimeActive;
|
||||
TimeActive += FRAME_TIME;// DELTA_TIME;
|
||||
TimeInactive = 0.0f;
|
||||
_prevTimeActive = _timeActive;
|
||||
_timeActive += FRAME_TIME;// DELTA_TIME;
|
||||
_timeInactive = 0.0f;
|
||||
}
|
||||
else if (IsHeld())
|
||||
{
|
||||
PrevTimeActive = TimeActive;
|
||||
TimeActive += FRAME_TIME;// DELTA_TIME;
|
||||
TimeInactive = 0.0f;
|
||||
_prevTimeActive = _timeActive;
|
||||
_timeActive += FRAME_TIME;// DELTA_TIME;
|
||||
_timeInactive = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
PrevTimeActive = 0.0f;
|
||||
TimeActive = 0.0f;
|
||||
TimeInactive += FRAME_TIME;// DELTA_TIME;
|
||||
_prevTimeActive = 0.0f;
|
||||
_timeActive = 0.0f;
|
||||
_timeInactive += FRAME_TIME;// DELTA_TIME;
|
||||
}
|
||||
}
|
||||
|
||||
void InputAction::Clear()
|
||||
{
|
||||
Value = 0.0f;
|
||||
PrevValue = 0.0f;
|
||||
TimeActive = 0.0f;
|
||||
PrevTimeActive = 0.0f;
|
||||
TimeInactive = 0.0f;
|
||||
_value = 0.0f;
|
||||
_prevValue = 0.0f;
|
||||
_timeActive = 0.0f;
|
||||
_prevTimeActive = 0.0f;
|
||||
_timeInactive = 0.0f;
|
||||
}
|
||||
|
||||
void InputAction::DrawDebug() const
|
||||
{
|
||||
PrintDebugMessage("ID: %d", (int)ID);
|
||||
PrintDebugMessage("ID: %d", (int)_id);
|
||||
PrintDebugMessage("IsClicked: %d", IsClicked());
|
||||
PrintDebugMessage("IsHeld: %d", IsHeld());
|
||||
PrintDebugMessage("IsPulsed (.2s, .6s): %d", IsPulsed(0.2f, 0.6f));
|
||||
PrintDebugMessage("IsReleased: %d", IsReleased());
|
||||
PrintDebugMessage("");
|
||||
PrintDebugMessage("Value: %.3f", Value);
|
||||
PrintDebugMessage("PrevValue: %.3f", PrevValue);
|
||||
PrintDebugMessage("TimeActive: %.3f", TimeActive);
|
||||
PrintDebugMessage("PrevTimeActive: %.3f", PrevTimeActive);
|
||||
PrintDebugMessage("TimeInactive: %.3f", TimeInactive);
|
||||
PrintDebugMessage("Value: %.3f", _value);
|
||||
PrintDebugMessage("PrevValue: %.3f", _prevValue);
|
||||
PrintDebugMessage("TimeActive: %.3f", _timeActive);
|
||||
PrintDebugMessage("PrevTimeActive: %.3f", _prevTimeActive);
|
||||
PrintDebugMessage("TimeInactive: %.3f", _timeInactive);
|
||||
}
|
||||
|
||||
void InputAction::UpdateValue(float value)
|
||||
{
|
||||
PrevValue = Value;
|
||||
Value = value;
|
||||
_prevValue = _value;
|
||||
_value = value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,12 +65,12 @@ namespace TEN::Input
|
|||
private:
|
||||
// Members
|
||||
|
||||
ActionID ID = In::Forward;
|
||||
float Value = 0.0f;
|
||||
float PrevValue = 0.0f;
|
||||
float TimeActive = 0.0f;
|
||||
float PrevTimeActive = 0.0f;
|
||||
float TimeInactive = 0.0f;
|
||||
ActionID _id = In::Forward;
|
||||
float _value = 0.0f;
|
||||
float _prevValue = 0.0f;
|
||||
float _timeActive = 0.0f;
|
||||
float _prevTimeActive = 0.0f;
|
||||
float _timeInactive = 0.0f;
|
||||
|
||||
public:
|
||||
// Constructors
|
||||
|
|
|
@ -1471,7 +1471,8 @@ void GetCarriedItems()
|
|||
const auto& object = Objects[item.ObjectNumber];
|
||||
|
||||
if (object.intelligent ||
|
||||
(item.ObjectNumber >= ID_SEARCH_OBJECT1 && item.ObjectNumber <= ID_SEARCH_OBJECT3))
|
||||
(item.ObjectNumber >= ID_SEARCH_OBJECT1 && item.ObjectNumber <= ID_SEARCH_OBJECT3) ||
|
||||
(item.ObjectNumber == ID_SARCOPHAGUS))
|
||||
{
|
||||
for (short linkNumber = g_Level.Rooms[item.RoomNumber].itemNumber; linkNumber != NO_VALUE; linkNumber = g_Level.Items[linkNumber].NextItem)
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue