Merge branch 'MontyTRC89:develop' into develop

This commit is contained in:
davidmarr 2024-10-20 21:38:01 +02:00 committed by GitHub
commit 4fc411abe9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 228 additions and 213 deletions

View file

@ -11,7 +11,11 @@ TombEngine releases are located in this repository (alongside with Tomb Editor):
### Bug fixes ### Bug fixes
* Fixed original issue with classic switch off trigger incorrectly activating some trigger actions. * Fixed original issue with classic switch off trigger incorrectly activating some trigger actions.
* Fixed leveljump vehicle transfer. * 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 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 several binocular bugs.
* Fixed incorrect climbing out of water on bridge objects. * Fixed incorrect climbing out of water on bridge objects.
* Fixed faulty death sectors. * Fixed faulty death sectors.

View file

@ -234,6 +234,10 @@ scripts too.</p>
<td class="summary">Get translated string.</td> <td class="summary">Get translated string.</td>
</tr> </tr>
<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="name" ><a href="#SetLanguageNames">SetLanguageNames(table)</a></td>
<td class="summary">Set language names for translations.</td> <td class="summary">Set language names for translations.</td>
</tr> </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> </dd>
<dt> <dt>
<a name = "SetLanguageNames"></a> <a name = "SetLanguageNames"></a>

View file

@ -108,7 +108,7 @@ pickups, and Lara herself (see also <a href="../2 classes/Objects.LaraObject.htm
<h2><a href="#Functions">Functions</a></h2> <h2><a href="#Functions">Functions</a></h2>
<table class="function_list"> <table class="function_list">
<tr> <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> <td class="summary">Used to generate a new moveable dynamically at runtime.</td>
</tr> </tr>
<tr> <tr>
@ -390,7 +390,7 @@ pickups, and Lara herself (see also <a href="../2 classes/Objects.LaraObject.htm
<dl class="function"> <dl class="function">
<dt> <dt>
<a name = "Moveable"></a> <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> </dt>
<dd> <dd>
Used to generate a new moveable dynamically at runtime. <br/> 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> <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)) rotation rotation about x, y, and z axes (default Rotation(0, 0, 0))
</li> </li>
<li><span class="parameter">roomID</span> <li><span class="parameter">roomNumber</span>
<span class="types"><span class="type">int</span></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>
<li><span class="parameter">animNumber</span> <li><span class="parameter">animNumber</span>
<span class="types"><span class="type">int</span></span> <span class="types"><span class="type">int</span></span>

View file

@ -100,7 +100,7 @@
<div id="content"> <div id="content">
<h1>Class <code>Objects.Room</code></h1> <h1>Class <code>Objects.Room</code></h1>
<p>Rooms</p> <p>Room object.</p>
<p> <p>
</p> </p>
@ -109,8 +109,12 @@
<h2><a href="#Functions">Functions</a></h2> <h2><a href="#Functions">Functions</a></h2>
<table class="function_list"> <table class="function_list">
<tr> <tr>
<td class="name" ><a href="#Room:GetActive">Room:GetActive()</a></td> <td class="name" ><a href="#Room:GetRoomNumber">Room:GetRoomNumber()</a></td>
<td class="summary">Determine whether the room is active or not</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>
<tr> <tr>
<td class="name" ><a href="#Room:GetColor">Room:GetColor()</a></td> <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> <td class="summary">Get the room's reverb type.</td>
</tr> </tr>
<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> <td class="summary">Set the room's reverb type.</td>
</tr> </tr>
<tr> <tr>
<td class="name" ><a href="#Room:GetName">Room:GetName()</a></td> <td class="name" ><a href="#Room:SetFlag">Room:SetFlag(flagID, Boolean)</a></td>
<td class="summary">Get the room's unique string identifier.</td> <td class="summary">Set the room's specified flag.</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>
</tr> </tr>
<tr> <tr>
<td class="name" ><a href="#Room:GetFlag">Room:GetFlag(flagID)</a></td> <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> <td class="summary">Get the room's specified flag value (true or false).</td>
</tr> </tr>
<tr> <tr>
<td class="name" ><a href="#Room:SetFlag">Room:SetFlag(flagID, the)</a></td> <td class="name" ><a href="#Room:IsTagPresent">Room:IsTagPresent(tag)</a></td>
<td class="summary">Set the room's specified flag value.</td> <td class="summary">Check if the specified tag is set for the room.</td>
</tr> </tr>
<tr> <tr>
<td class="name" ><a href="#Room:IsTagPresent">Room:IsTagPresent(tag)</a></td> <td class="name" ><a href="#Room:GetActive">Room:GetActive()</a></td>
<td class="summary">Checks if specified tag is set for this room.</td> <td class="summary">Check if the room is active.</td>
</tr> </tr>
</table> </table>
@ -154,11 +158,11 @@
<dl class="function"> <dl class="function">
<dt> <dt>
<a name = "Room:GetActive"></a> <a name = "Room:GetRoomNumber"></a>
<strong>Room:GetActive()</strong> <strong>Room:GetRoomNumber()</strong>
</dt> </dt>
<dd> <dd>
Determine whether the room is active or not Get the room's number. ()
@ -166,8 +170,29 @@
<h3>Returns:</h3> <h3>Returns:</h3>
<ol> <ol>
<span class="types"><span class="type">bool</span></span> <span class="types"><span class="type">int</span></span>
true if the room is active 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> </ol>
@ -179,7 +204,7 @@
<strong>Room:GetColor()</strong> <strong>Room:GetColor()</strong>
</dt> </dt>
<dd> <dd>
Get the room's ambient light color. Get the room's ambient light color. ()
@ -188,7 +213,7 @@
<ol> <ol>
<span class="types"><a class="type" href="../3 primitive classes/Color.html#">Color</a></span> <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> </ol>
@ -200,7 +225,7 @@
<strong>Room:GetReverbType()</strong> <strong>Room:GetReverbType()</strong>
</dt> </dt>
<dd> <dd>
Get the room's reverb type. Get the room's reverb type. ()
@ -209,50 +234,7 @@
<ol> <ol>
<span class="types"><a class="type" href="../4 enums/Objects.RoomReverb.html#">RoomReverb</a></span> <span class="types"><a class="type" href="../4 enums/Objects.RoomReverb.html#">RoomReverb</a></span>
room's reverb type 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
</ol> </ol>
@ -264,7 +246,7 @@
<strong>Room:SetName(name)</strong> <strong>Room:SetName(name)</strong>
</dt> </dt>
<dd> <dd>
Set the room's name (its unique string identifier). Set the room's unique string identifier. ()
@ -272,7 +254,55 @@
<ul> <ul>
<li><span class="parameter">name</span> <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> <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> </li>
</ul> </ul>
@ -286,7 +316,7 @@
<strong>Room:GetFlag(flagID)</strong> <strong>Room:GetFlag(flagID)</strong>
</dt> </dt>
<dd> <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> <ul>
<li><span class="parameter">flagID</span> <li><span class="parameter">flagID</span>
<span class="types"><a class="type" href="../4 enums/Objects.RoomFlagID.html#">RoomFlagID</a></span> <span class="types"><a class="type" href="../4 enums/Objects.RoomFlagID.html#">RoomFlagID</a></span>
The room's flag ID Room 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
</li> </li>
</ul> </ul>
@ -340,7 +338,7 @@
<strong>Room:IsTagPresent(tag)</strong> <strong>Room:IsTagPresent(tag)</strong>
</dt> </dt>
<dd> <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> <ul>
<li><span class="parameter">tag</span> <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> <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> </li>
</ul> </ul>
@ -356,7 +354,28 @@
<ol> <ol>
<span class="types"><span class="type">bool</span></span> <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> </ol>

View file

@ -171,8 +171,8 @@ LARA_PETROL_MESH
LARA_DIRT_MESH LARA_DIRT_MESH
LARA_CROWBAR_ANIM LARA_CROWBAR_ANIM
LARA_TORCH_ANIM LARA_TORCH_ANIM
SINGLE_BRAID_HAIR HAIR_PRIMARY
DUAL_PIGTAIL_HAIR HAIR_SECONDARY
SNOWMOBILE_LARA_ANIMS SNOWMOBILE_LARA_ANIMS
SNOWMOBILE SNOWMOBILE
QUAD_LARA_ANIMS QUAD_LARA_ANIMS

View file

@ -217,7 +217,7 @@ local door = GetMoveableByName("door_type4_14")
</tr> </tr>
<tr> <tr>
<td class="name" ><a href="2 classes/Objects.Room.html">Objects.Room</a></td> <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>
<tr> <tr>
<td class="name" ><a href="2 classes/Objects.Sink.html">Objects.Sink</a></td> <td class="name" ><a href="2 classes/Objects.Sink.html">Objects.Sink</a></td>

View file

@ -71,7 +71,7 @@ namespace TEN::Entities::Player
PlayerBehaviorStateRoutines[LS_PUSHABLE_PUSH] = std::pair(lara_as_pushable_push, lara_default_col); 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_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_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_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_SWITCH_UP] = std::pair(lara_as_switch_off, lara_default_col);
PlayerBehaviorStateRoutines[LS_INSERT_KEY] = std::pair(lara_as_use_key, 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_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_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_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_JUMP_ROLL_180] = std::pair(lara_void_func, lara_void_func);
PlayerBehaviorStateRoutines[LS_KICK] = 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); PlayerBehaviorStateRoutines[LS_ZIP_LINE] = std::pair(lara_as_zip_line, lara_void_func);

View file

@ -39,17 +39,7 @@ void lara_void_func(ItemInfo* item, CollisionInfo* coll)
void lara_default_col(ItemInfo* item, CollisionInfo* coll) void lara_default_col(ItemInfo* item, CollisionInfo* coll)
{ {
auto& player = GetLaraInfo(*item); LaraDefaultCollision(item, coll);
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);
} }
// Boulder death. // Boulder death.

View file

@ -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) void LaraSwimCollision(ItemInfo* item, CollisionInfo* coll)
{ {
auto* lara = GetLaraInfo(item); auto* lara = GetLaraInfo(item);

View file

@ -25,6 +25,7 @@ void GetLaraDeadlyBounds();
void LaraJumpCollision(ItemInfo* item, CollisionInfo* coll, short moveAngle); void LaraJumpCollision(ItemInfo* item, CollisionInfo* coll, short moveAngle);
void LaraSurfaceCollision(ItemInfo* item, CollisionInfo* coll); void LaraSurfaceCollision(ItemInfo* item, CollisionInfo* coll);
void LaraSwimCollision(ItemInfo* item, CollisionInfo* coll); void LaraSwimCollision(ItemInfo* item, CollisionInfo* coll);
void LaraDefaultCollision(ItemInfo* item, CollisionInfo* coll);
void LaraWaterCurrent(ItemInfo* item, CollisionInfo* coll); void LaraWaterCurrent(ItemInfo* item, CollisionInfo* coll);

View file

@ -182,7 +182,7 @@ void InitializeLaraStartPosition(ItemInfo& playerItem)
playerItem.Location.Height = playerItem.Pose.Position.y; playerItem.Location.Height = playerItem.Pose.Position.y;
} }
static void InitializePlayerVehicle(ItemInfo& playerItem) void InitializePlayerVehicle(ItemInfo& playerItem)
{ {
if (PlayerVehicleObjectID == GAME_OBJECT_ID::ID_NO_OBJECT) if (PlayerVehicleObjectID == GAME_OBJECT_ID::ID_NO_OBJECT)
return; return;
@ -194,7 +194,6 @@ static void InitializePlayerVehicle(ItemInfo& playerItem)
// Restore vehicle. // Restore vehicle.
TENLog("Transferring vehicle " + GetObjectName(PlayerVehicleObjectID) + " from the previous level."); TENLog("Transferring vehicle " + GetObjectName(PlayerVehicleObjectID) + " from the previous level.");
vehicle->Pose = playerItem.Pose; vehicle->Pose = playerItem.Pose;
ItemNewRoom(vehicle->Index, playerItem.RoomNumber);
SetLaraVehicle(&playerItem, vehicle); SetLaraVehicle(&playerItem, vehicle);
playerItem.Animation = PlayerAnim; playerItem.Animation = PlayerAnim;
@ -251,7 +250,7 @@ static void InitializePlayerVehicle(ItemInfo& playerItem)
if (vehicle->ObjectNumber == GAME_OBJECT_ID::ID_RUBBER_BOAT || if (vehicle->ObjectNumber == GAME_OBJECT_ID::ID_RUBBER_BOAT ||
vehicle->ObjectNumber == GAME_OBJECT_ID::ID_SPEEDBOAT) vehicle->ObjectNumber == GAME_OBJECT_ID::ID_SPEEDBOAT)
{ {
g_Level.Items[vehicle->Index].Active = false; RemoveActiveItem(vehicle->Index, false);
AddActiveItem(vehicle->Index); AddActiveItem(vehicle->Index);
g_Level.Items[vehicle->Index].Status = ITEM_ACTIVE; g_Level.Items[vehicle->Index].Status = ITEM_ACTIVE;
} }
@ -297,9 +296,6 @@ void InitializeLaraLevelJump(ItemInfo* item, LaraInfo* playerBackup)
// Restore hit points. // Restore hit points.
item->HitPoints = PlayerHitPoints; item->HitPoints = PlayerHitPoints;
// Restore vehicle.
InitializePlayerVehicle(*item);
} }
void InitializeLaraDefaultInventory(ItemInfo& item) void InitializeLaraDefaultInventory(ItemInfo& item)

View file

@ -9,3 +9,4 @@ void InitializeLaraAnims(ItemInfo* item);
void InitializeLaraStartPosition(ItemInfo& playerItem); void InitializeLaraStartPosition(ItemInfo& playerItem);
void InitializeLaraLevelJump(ItemInfo* item, LaraInfo* playerBackup); void InitializeLaraLevelJump(ItemInfo* item, LaraInfo* playerBackup);
void InitializeLaraDefaultInventory(ItemInfo& item); void InitializeLaraDefaultInventory(ItemInfo& item);
void InitializePlayerVehicle(ItemInfo& playerItem);

View file

@ -8,6 +8,7 @@
#include "Game/items.h" #include "Game/items.h"
#include "Game/Lara/PlayerContext.h" #include "Game/Lara/PlayerContext.h"
#include "Game/Lara/lara.h" #include "Game/Lara/lara.h"
#include "Game/Lara/lara_collide.h"
#include "Game/Lara/lara_helpers.h" #include "Game/Lara/lara_helpers.h"
#include "Game/Lara/lara_tests.h" #include "Game/Lara/lara_tests.h"
#include "Objects/Generic/Object/rope.h" #include "Objects/Generic/Object/rope.h"
@ -45,6 +46,12 @@ void lara_as_pickup(ItemInfo* item, CollisionInfo* coll)
item->Animation.TargetState = GetNextAnimState(item); item->Animation.TargetState = GetNextAnimState(item);
} }
void lara_col_pickup(ItemInfo* item, CollisionInfo* coll)
{
LaraDefaultCollision(item, coll);
ShiftItem(item, coll);
}
// State: LS_PICKUP_FLARE (67) // State: LS_PICKUP_FLARE (67)
// Collision: lara_default_col() // Collision: lara_default_col()
void lara_as_pickup_flare(ItemInfo* item, CollisionInfo* coll) void lara_as_pickup_flare(ItemInfo* item, CollisionInfo* coll)

View file

@ -14,6 +14,7 @@ struct CollisionInfo;
void lara_as_pickup(ItemInfo* item, CollisionInfo* coll); void lara_as_pickup(ItemInfo* item, CollisionInfo* coll);
void lara_as_pickup_flare(ItemInfo* item, CollisionInfo* coll); void lara_as_pickup_flare(ItemInfo* item, CollisionInfo* coll);
void lara_col_pickup(ItemInfo* item, CollisionInfo* coll);
// ------ // ------
// SWITCH // SWITCH

View file

@ -566,6 +566,9 @@ bool TestBoundsCollide(ItemInfo* item, ItemInfo* laraItem, int radius)
const auto& bounds = GetBestFrame(*item).BoundingBox; const auto& bounds = GetBestFrame(*item).BoundingBox;
const auto& playerBounds = GetBestFrame(*laraItem).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)) if ((item->Pose.Position.y + bounds.Y2) <= (laraItem->Pose.Position.y + playerBounds.Y1))
return false; return false;

View file

@ -59,6 +59,7 @@
#include "Specific/Input/Input.h" #include "Specific/Input/Input.h"
#include "Specific/level.h" #include "Specific/level.h"
#include "Specific/winmain.h" #include "Specific/winmain.h"
#include "Game/Lara/lara_initialise.h"
using namespace std::chrono; using namespace std::chrono;
using namespace TEN::Effects; using namespace TEN::Effects;
@ -531,6 +532,10 @@ void InitializeOrLoadGame(bool loadGame)
{ {
SaveGame::LoadHub(CurrentLevel); SaveGame::LoadHub(CurrentLevel);
TENLog("Starting new level.", LogLevel::Info); TENLog("Starting new level.", LogLevel::Info);
// Restore vehicle.
auto* item = FindItem(ID_LARA);
InitializePlayerVehicle(*item);
} }
g_GameScript->OnStart(); g_GameScript->OnStart();

View file

@ -312,7 +312,7 @@ bool GetTargetOnLOS(GameVector* origin, GameVector* target, bool drawTarget, boo
ShatterImpactData.impactDirection = dir; ShatterImpactData.impactDirection = dir;
ShatterImpactData.impactLocation = ShatterItem.sphere.Center; ShatterImpactData.impactLocation = ShatterItem.sphere.Center;
ShatterObject(&ShatterItem, 0, 128, target2.RoomNumber, 0); ShatterObject(&ShatterItem, 0, 128, target2.RoomNumber, 0);
TriggerRicochetSpark(target2, LaraItem->Pose.Orientation.y, 3, 0); TriggerRicochetSpark(target2, LaraItem->Pose.Orientation.y, 3, 0);
} }
else else
{ {
@ -512,91 +512,21 @@ static bool DoRayBox(const GameVector& origin, const GameVector& target, const G
// If mesh is visible. // If mesh is visible.
if (item->MeshBits & (1 << i)) if (item->MeshBits & (1 << i))
{ {
float distance;
const auto& sphere = spheres[i]; const auto& sphere = spheres[i];
// NOTE: Not worth doing what's commented below. *Rewrite completely.* if (sphere.Intersects(rayOrigin, rayDir, distance))
// 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))
{ {
// HACK: Core seems to take in account for distance not the real hit point but the centre of the sphere. // Test for minimum distance.
// 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 min distance if (distance < minDist)
if (newDist < minDistance)
{ {
minDistance = newDist; minDist = distance;
meshPtr = &g_Level.Meshes[obj->meshIndex + i]; meshIndex = object->meshIndex + i;
bit = 1 << i; bit = 1 << i;
sp = 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;
}
}
}
} }
} }

View file

@ -2299,10 +2299,22 @@ static void ParseLevel(const Save::SaveGame* s, bool hubMode)
// Don't load player data in hub mode. // Don't load player data in hub mode.
if (item->ObjectNumber == ID_LARA && hubMode) 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; continue;
}
if (item->Index == Lara.Context.Vehicle && hubMode) 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; continue;
}
// Position // Position
item->Pose = ToPose(*savedItem->pose()); item->Pose = ToPose(*savedItem->pose());

View file

@ -591,9 +591,12 @@ namespace TEN::Entities::Creatures::TR5
void DoGuardianDeath(int itemNumber, ItemInfo& item) void DoGuardianDeath(int itemNumber, ItemInfo& item)
{ {
const auto& guardian = GetGuardianInfo(item); const auto& guardian = GetGuardianInfo(item);
ExplodeItemNode(&g_Level.Items[guardian.BaseItem], 0, 0, 128); if (g_Level.Items[guardian.BaseItem].ObjectNumber == ID_LASERHEAD_BASE)
KillItem(guardian.BaseItem); {
ExplodeItemNode(&g_Level.Items[guardian.BaseItem], 0, 0, 128);
KillItem(guardian.BaseItem);
}
ExplodeItemNode(&item, 0, 0, 128); 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(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); 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); TestTriggers(&item, true);
SoundEffect(SFX_TR5_GOD_HEAD_BLAST, &item.Pose, SoundEnvironment::Land, 0.5f); SoundEffect(SFX_TR5_GOD_HEAD_BLAST, &item.Pose, SoundEnvironment::Land, 0.5f);

View file

@ -21,6 +21,5 @@ namespace TEN::Entities::Creatures::TR5
short yRot; short yRot;
int BaseItem; int BaseItem;
std::array<int, GUARDIAN_TENTACLE_COUNT> Tentacles = {}; std::array<int, GUARDIAN_TENTACLE_COUNT> Tentacles = {};
int PuzzleItem;
}; };
} }

View file

@ -428,6 +428,9 @@ ScriptReserved_GetSlotHP, & Moveable::GetSlotHP,
// @function Moveable:SetOnCollidedWithObject // @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. // @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 // @usage
// -- obj1 is the collision moveable
// -- obj2 is the collider moveable
//
// LevelFuncs.objCollided = function(obj1, obj2) // LevelFuncs.objCollided = function(obj1, obj2)
// print(obj1:GetName() .. " collided with " .. obj2:GetName()) // print(obj1:GetName() .. " collided with " .. obj2:GetName())
// end // end