Merge branch 'develop' into develop_60fps

This commit is contained in:
Lwmte 2024-10-05 00:28:40 +02:00
commit cb0e8fb23e
23 changed files with 141 additions and 65 deletions

View file

@ -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**
@ -11,6 +11,8 @@ 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 leveljump vehicle transfer.
* Fixed sarcophagus pick-ups.
* Fixed several binocular bugs.
* 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.
@ -56,14 +58,14 @@ TombEngine releases are located in this repository (alongside with Tomb Editor):
### Lua API changes
* Added Flow.EnableHomeLevel()
* Added Flow.LensFlare()
* Added Flow.Starfield()
* Added Flow.EnableHomeLevel() function.
* Added Flow.IsStringPresent() function.
* Added Inventory.GetUsedItem(), Inventory.SetUsedItem() and Inventory.ClearUsedItem() functions.
* Added Input.KeyClearAll()
* Added Room:GetRoomNumber()
* Added Flow.LensFlare() and Flow.Starfield() classes.
* Added Input.KeyClearAll() function.
* 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

View file

@ -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"
@ -200,7 +204,7 @@ static void InitializePlayerVehicle(ItemInfo& playerItem)
{
case GAME_OBJECT_ID::ID_KAYAK:
InitializeKayak(vehicle->Index);
KayakPaddleTake(&playerItem);
KayakPaddleTake(GetKayakInfo(&g_Level.Items[vehicle->Index]), &playerItem);
break;
case GAME_OBJECT_ID::ID_MOTORBIKE:
@ -220,12 +224,37 @@ static void InitializePlayerVehicle(ItemInfo& playerItem)
break;
case GAME_OBJECT_ID::ID_MINECART:
playerItem.Model.MeshIndex[LM_RHAND] = Objects[ID_MINECART_LARA_ANIMS].meshIndex + LM_RHAND;
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)
{
g_Level.Items[vehicle->Index].Active = false;
AddActiveItem(vehicle->Index);
g_Level.Items[vehicle->Index].Status = ITEM_ACTIVE;
}
}
void InitializeLaraLevelJump(ItemInfo* item, LaraInfo* playerBackup)

View file

@ -952,6 +952,7 @@ void BinocularCamera(ItemInfo* item)
player.Inventory.IsBusy = false;
Camera.type = BinocularOldCamera;
Camera.target = LastTarget;
AlterFOV(LastFOV);
return;
}
@ -1025,6 +1026,8 @@ void BinocularCamera(ItemInfo* item)
if (IsHeld(In::Action))
{
ClearAction(In::Action);
auto origin = Camera.pos.ToVector3i();
auto target = Camera.target.ToVector3i();
LaraTorch(&origin, &target, player.ExtraHeadRot.y, 192);
@ -1519,6 +1522,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)

View file

@ -105,16 +105,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);

View file

@ -92,7 +92,6 @@ using namespace TEN::Entities::Effects;
int GameTimer = 0;
int GlobalCounter = 0;
int Wibble = 0;
bool InitializeGame;
bool DoTheGame;
@ -179,27 +178,13 @@ GameStatus ControlPhase()
ApplyActionQueue();
ClearActionQueue();
UpdateCamera();
UpdateAllItems();
UpdateAllEffects();
UpdateLara(LaraItem, isTitle);
g_GameScriptEntities->TestCollidingObjects();
// Draw flyby cameras.
if (UseSpotCam)
{
CalculateSpotCameras();
}
// Do standard camera.
else
{
TrackCameraInit = false;
CalculateCamera(LaraCollision);
}
// Update oscillator seed.
Wibble = (Wibble + WIBBLE_SPEED) & WIBBLE_MAX;
// Smash shatters and clear stopper flags under them.
UpdateShatters();
@ -216,6 +201,7 @@ GameStatus ControlPhase()
// Update effects.
StreamerEffect.Update();
UpdateWibble();
UpdateSparks();
UpdateFireSparks();
UpdateSmoke();

View file

@ -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;

View file

@ -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);

View file

@ -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,
@ -310,5 +312,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);

View file

@ -221,14 +221,16 @@ 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(ItemInfo* laraItem)
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(ItemInfo* laraItem)
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);
}
@ -910,21 +912,13 @@ namespace TEN::Entities::Vehicles
case KAYAK_STATE_MOUNT_LEFT:
if (TestAnimNumber(*laraItem, KAYAK_ANIM_GET_PADDLE) && frame == 24 && !(kayak->Flags & KAYAK_FLAG_PADDLE_MESH))
{
kayak->Flags |= KAYAK_FLAG_PADDLE_MESH;
KayakPaddleTake(laraItem);
}
KayakPaddleTake(kayak, laraItem);
break;
case KAYAK_STATE_DISMOUNT:
if (TestAnimNumber(*laraItem, KAYAK_ANIM_DISMOUNT_START) && frame == 27 && kayak->Flags & KAYAK_FLAG_PADDLE_MESH)
{
kayak->Flags &= ~KAYAK_FLAG_PADDLE_MESH;
KayakPaddlePut(laraItem);
}
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:

View file

@ -6,13 +6,14 @@ 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(ItemInfo* laraItem);
void KayakPaddlePut(ItemInfo* laraItem);
void KayakPaddleTake(KayakInfo* kayak, ItemInfo* laraItem);
void KayakPaddlePut(KayakInfo* kayak, ItemInfo* laraItem);
void KayakDraw(ItemInfo* kayakItem);

View file

@ -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);
}
}

View file

@ -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);
}

View file

@ -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();

View file

@ -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);

View file

@ -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;

View file

@ -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"

View file

@ -73,6 +73,6 @@ void SarcophagusCollision(short itemNumber, ItemInfo* laraItem, CollisionInfo* c
}
else
{
CollectMultiplePickups(sarcItem->Index);
CollectCarriedItems(sarcItem);
}
}

View file

@ -1311,8 +1311,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);

View file

@ -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.

View file

@ -227,6 +227,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

View file

@ -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
@ -373,6 +379,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;

View file

@ -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);

View file

@ -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)
{