Tomo - fireflies (#1597)

* tests only - nothing to see

* update

* update

* update

* update corpse

* update savegame, formatting

* import develop

* formatting

* fix broken streamer vertex

* update firefly streamer spawn

* update effect

* Add in objects for fireflies

* fixed all reviews, formatting, changing on-off cycle

* formatting

* reduced the emitted light to two lights per cluster

* adding antitrigger

* formatting

* fixed corpse

* fixed a bug with corpse

* fixed corpse fall bug

* formatting

* Small refactors

* Fix merge

---------

Co-authored-by: Stranger1992 <84292688+Stranger1992@users.noreply.github.com>
Co-authored-by: Lwmte <3331699+Lwmte@users.noreply.github.com>
This commit is contained in:
Nemoel-Tomo 2025-03-28 06:44:07 +01:00 committed by GitHub
parent 8e5f045d02
commit 9469a0e63a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 1220 additions and 71 deletions

View file

@ -952,6 +952,7 @@ DOPPELGANGER_ORIGIN
CORPSE CORPSE
WRAITH_TRAP WRAITH_TRAP
WATERFALL_EMITTER WATERFALL_EMITTER
FIREFLY_EMITTER
MESHSWAP1 MESHSWAP1
MESHSWAP2 MESHSWAP2
MESHSWAP3 MESHSWAP3
@ -1132,6 +1133,7 @@ AIR_BAR_TEXTURE
DASH_BAR_TEXTURE DASH_BAR_TEXTURE
SFX_BAR_TEXTURE SFX_BAR_TEXTURE
WATERFALL_SPRITES WATERFALL_SPRITES
FIREFLY_SPRITES
CROSSHAIR_GRAPHICS CROSSHAIR_GRAPHICS
SPEEDOMETER_GRAPHICS SPEEDOMETER_GRAPHICS
CUSTOM_BAR_GRAPHICS CUSTOM_BAR_GRAPHICS
@ -1410,6 +1412,7 @@ AIR_BAR_TEXTURE
DASH_BAR_TEXTURE DASH_BAR_TEXTURE
SFX_BAR_TEXTURE SFX_BAR_TEXTURE
WATERFALL_SPRITES WATERFALL_SPRITES
FIREFLY_SPRITES
CROSSHAIR_GRAPHICS CROSSHAIR_GRAPHICS
SPEEDOMETER_GRAPHICS SPEEDOMETER_GRAPHICS
CUSTOM_BAR_GRAPHICS CUSTOM_BAR_GRAPHICS

View file

@ -27,6 +27,7 @@
#include "Objects/TR4/Entity/tr4_beetle_swarm.h" #include "Objects/TR4/Entity/tr4_beetle_swarm.h"
#include "Objects/Utils/object_helper.h" #include "Objects/Utils/object_helper.h"
#include "Specific/level.h" #include "Specific/level.h"
#include "Objects/Effects/Fireflies.h"
using namespace TEN::Effects::Hair; using namespace TEN::Effects::Hair;
using namespace TEN::Entities; using namespace TEN::Entities;
@ -200,6 +201,7 @@ void InitializeSpecialEffects()
TEN::Entities::TR4::ClearBeetleSwarm(); TEN::Entities::TR4::ClearBeetleSwarm();
TEN::Entities::Creatures::TR3::ClearFishSwarm(); TEN::Entities::Creatures::TR3::ClearFishSwarm();
TEN::Effects::Fireflies::ClearFireflySwarm();
} }
void CustomObjects() void CustomObjects()

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 "Objects/Effects/Fireflies.h"
using namespace std::chrono; using namespace std::chrono;
using namespace TEN::Effects; using namespace TEN::Effects;
@ -89,6 +90,7 @@ using namespace TEN::Math;
using namespace TEN::Renderer; using namespace TEN::Renderer;
using namespace TEN::Entities::Creatures::TR3; using namespace TEN::Entities::Creatures::TR3;
using namespace TEN::Entities::Effects; using namespace TEN::Entities::Effects;
using namespace TEN::Effects::Fireflies;
constexpr auto DEATH_NO_INPUT_TIMEOUT = 10 * FPS; constexpr auto DEATH_NO_INPUT_TIMEOUT = 10 * FPS;
constexpr auto DEATH_INPUT_TIMEOUT = 3 * FPS; constexpr auto DEATH_INPUT_TIMEOUT = 3 * FPS;
@ -211,6 +213,7 @@ GameStatus GamePhase(bool insideMenu)
UpdateLocusts(); UpdateLocusts();
UpdateUnderwaterBloodParticles(); UpdateUnderwaterBloodParticles();
UpdateFishSwarm(); UpdateFishSwarm();
UpdateFireflySwarm();
UpdateGlobalLensFlare(); UpdateGlobalLensFlare();
// Update HUD. // Update HUD.

View file

@ -17,6 +17,7 @@
#include "Game/Setup.h" #include "Game/Setup.h"
#include "Sound/sound.h" #include "Sound/sound.h"
#include "Specific/level.h" #include "Specific/level.h"
#include "Objects/Effects/Fireflies.h"
#include "Objects/Generic/puzzles_keys.h" #include "Objects/Generic/puzzles_keys.h"
#include "Objects/TR3/Entity/FishSwarm.h" #include "Objects/TR3/Entity/FishSwarm.h"
#include "Objects/TR4/Entity/tr4_beetle_swarm.h" #include "Objects/TR4/Entity/tr4_beetle_swarm.h"
@ -29,6 +30,7 @@ using namespace TEN::Effects::Environment;
using namespace TEN::Effects::Footprint; using namespace TEN::Effects::Footprint;
using namespace TEN::Effects::Hair; using namespace TEN::Effects::Hair;
using namespace TEN::Entities::Creatures::TR3; using namespace TEN::Entities::Creatures::TR3;
using namespace TEN::Effects::Fireflies;
int FlipEffect; int FlipEffect;
@ -90,6 +92,7 @@ void ClearSwarmEnemies(ItemInfo* item)
ClearBeetleSwarm(); ClearBeetleSwarm();
ClearLocusts(); ClearLocusts();
ClearFishSwarm(); ClearFishSwarm();
ClearFireflySwarm();
} }
void FlashOrange(ItemInfo* item) void FlashOrange(ItemInfo* item)

View file

@ -10,6 +10,7 @@
#include "Game/control/flipeffect.h" #include "Game/control/flipeffect.h"
#include "Game/control/lot.h" #include "Game/control/lot.h"
#include "Game/control/volume.h" #include "Game/control/volume.h"
#include "Objects/Effects/Fireflies.h"
#include "Game/effects/item_fx.h" #include "Game/effects/item_fx.h"
#include "Game/effects/effects.h" #include "Game/effects/effects.h"
#include "Game/effects/weather.h" #include "Game/effects/weather.h"
@ -43,8 +44,9 @@
using namespace flatbuffers; using namespace flatbuffers;
using namespace TEN::Collision::Floordata; using namespace TEN::Collision::Floordata;
using namespace TEN::Control::Volumes; using namespace TEN::Control::Volumes;
using namespace TEN::Effects::Items;
using namespace TEN::Effects::Environment; using namespace TEN::Effects::Environment;
using namespace TEN::Effects::Fireflies;
using namespace TEN::Effects::Items;
using namespace TEN::Entities::Creatures::TR3; using namespace TEN::Entities::Creatures::TR3;
using namespace TEN::Entities::Generic; using namespace TEN::Entities::Generic;
using namespace TEN::Entities::Switches; using namespace TEN::Entities::Switches;
@ -924,6 +926,38 @@ const std::vector<byte> SaveGame::Build()
} }
auto fishSwarmOffset = fbb.CreateVector(fishSwarm); auto fishSwarmOffset = fbb.CreateVector(fishSwarm);
std::vector<flatbuffers::Offset<Save::FireflyData>> fireflySwarm;
for (const auto& firefly : FireflySwarm)
{
Save::FireflyDataBuilder fireflySave{ fbb };
fireflySave.add_sprite_index(firefly.SpriteSeqID);
fireflySave.add_sprite_id(firefly.SpriteID);
fireflySave.add_blend_mode((int)firefly.blendMode);
fireflySave.add_scalar(firefly.scalar);
fireflySave.add_position(&FromVector3(firefly.Position));
fireflySave.add_room_number(firefly.RoomNumber);
fireflySave.add_position_target(&FromVector3(firefly.PositionTarget));
fireflySave.add_orientation(&FromEulerAngles(firefly.Orientation));
fireflySave.add_velocity(firefly.Velocity);
fireflySave.add_target_item_number((firefly.TargetItemPtr == nullptr) ? -1 : firefly.TargetItemPtr->Index);
fireflySave.add_z_vel(firefly.zVel);
fireflySave.add_life(firefly.Life);
fireflySave.add_number(firefly.Number);
fireflySave.add_d_r(firefly.rB);
fireflySave.add_d_g(firefly.gB);
fireflySave.add_d_b(firefly.bB);
fireflySave.add_r(firefly.r);
fireflySave.add_g(firefly.g);
fireflySave.add_b(firefly.b);
fireflySave.add_on(firefly.on);
fireflySave.add_size(firefly.size);
fireflySave.add_rot_Ang(firefly.rotAng);
auto fireflySaveOffset = fireflySave.Finish();
fireflySwarm.push_back(fireflySaveOffset);
}
auto fireflySwarmOffset = fbb.CreateVector(fireflySwarm);
// TODO: In future, we should save only active FX, not whole array. // TODO: In future, we should save only active FX, not whole array.
// This may come together with Monty's branch merge -- Lwmte, 10.07.22 // This may come together with Monty's branch merge -- Lwmte, 10.07.22
@ -1545,6 +1579,7 @@ const std::vector<byte> SaveGame::Build()
sgb.add_next_item_active(NextItemActive); sgb.add_next_item_active(NextItemActive);
sgb.add_items(serializedItemsOffset); sgb.add_items(serializedItemsOffset);
sgb.add_fish_swarm(fishSwarmOffset); sgb.add_fish_swarm(fishSwarmOffset);
sgb.add_firefly_swarm(fireflySwarmOffset);
sgb.add_fxinfos(serializedEffectsOffset); sgb.add_fxinfos(serializedEffectsOffset);
sgb.add_next_fx_free(NextFxFree); sgb.add_next_fx_free(NextFxFree);
sgb.add_next_fx_active(NextFxActive); sgb.add_next_fx_active(NextFxActive);
@ -2289,6 +2324,38 @@ static void ParseEffects(const Save::SaveGame* s)
FishSwarm.push_back(fish); FishSwarm.push_back(fish);
} }
// Load firefly swarm.
for (int i = 0; i < s->firefly_swarm()->size(); i++)
{
const auto& fireflySave = s->firefly_swarm()->Get(i);
auto firefly = FireflyData{};
firefly.SpriteSeqID = fireflySave->sprite_index();
firefly.SpriteID = fireflySave->sprite_id();
firefly.blendMode = (BlendMode)fireflySave->blend_mode();
firefly.scalar = fireflySave->scalar();
firefly.Position = ToVector3(fireflySave->position());
firefly.RoomNumber = fireflySave->room_number();
firefly.PositionTarget = ToVector3(fireflySave->position_target());
firefly.Orientation = ToEulerAngles(fireflySave->orientation());
firefly.Velocity = fireflySave->velocity();
firefly.TargetItemPtr = (fireflySave->target_item_number() == -1) ? nullptr : &g_Level.Items[fireflySave->target_item_number()];
firefly.zVel = fireflySave->z_vel();
firefly.Life = fireflySave->life();
firefly.Number = fireflySave->number();
firefly.rB = fireflySave->d_r();
firefly.gB = fireflySave->d_g();
firefly.bB = fireflySave->d_b();
firefly.r = fireflySave->r();
firefly.g = fireflySave->g();
firefly.b = fireflySave->b();
firefly.on = fireflySave->on();
firefly.size = fireflySave->size();
firefly.rotAng = fireflySave->rot_Ang();
FireflySwarm.push_back(firefly);
}
// Load particles. // Load particles.
for (int i = 0; i < s->particles()->size(); i++) for (int i = 0; i < s->particles()->size(); i++)
{ {

View file

@ -0,0 +1,445 @@
#include "framework.h"
#include "Objects/Effects/Fireflies.h"
#include "Game/collision/collide_item.h"
#include "Game/collision/collide_room.h"
#include "Game/collision/Point.h"
#include "Game/control/box.h"
#include "Game/control/flipeffect.h"
#include "Game/effects/effects.h"
#include "Game/effects/Streamer.h"
#include "Game/effects/tomb4fx.h"
#include "Game/items.h"
#include "Game/Lara/lara.h"
#include "Game/Lara/lara_helpers.h"
#include "Game/misc.h"
#include "Game/Setup.h"
#include "Math/Math.h"
#include "Renderer/Renderer.h"
#include "Specific/clock.h"
#include "Specific/level.h"
using namespace TEN::Collision::Point;
using namespace TEN::Math;
using namespace TEN::Renderer;
using namespace TEN::Effects::Streamer;
namespace TEN::Effects::Fireflies
{
constexpr auto FIREFLY_COHESION_FACTOR = 600.1f;
constexpr auto FIREFLY_SPACING_FACTOR = 600.0f;
constexpr auto FIREFLY_CATCH_UP_FACTOR = 0.2f;
constexpr auto FIREFLY_TARGET_DISTANCE_MAX = SQUARE(BLOCK(1.0f));
constexpr auto FIREFLY_BASE_SEPARATION_DISTANCE = 10.0f;
constexpr auto FIREFLY_FLEE_DISTANCE = BLOCK(0.7);
constexpr auto MAX_FIREFLIES = 92;
constexpr auto DEFAULT_FIREFLY_COUNT = 20;
constexpr auto FIREFLY_RISE_UP_FACTOR = 200;
constexpr auto MAX_AREA_RANGE = 8;
constexpr auto LIGHT_ALPHA_CYCLE_DURATION = 120.0f;
std::vector<FireflyData> FireflySwarm = {};
std::unordered_map<int, int> nextFireflyNumberMap; // Numbering the Fireflies for Streamer effect.
void InitializeFireflySwarm(short itemNumber)
{
auto& item = g_Level.Items[itemNumber];
item.Animation.Velocity.z = Random::GenerateFloat(32.0f, 160.0f);
item.HitPoints = DEFAULT_FIREFLY_COUNT;
item.ItemFlags[FirefliesItemFlags::TargetItemPtr] = item.Index;
item.ItemFlags[FirefliesItemFlags::Light] = 1; // 0 = Turn off light effect, 1 = turn on light (DEFAULT).
item.ItemFlags[FirefliesItemFlags::TriggerFlags] = std::clamp((int)item.TriggerFlags, -MAX_AREA_RANGE, MAX_AREA_RANGE);
item.ItemFlags[FirefliesItemFlags::Spawncounter] = 0;
item.ItemFlags[FirefliesItemFlags::RemoveFliesEffect] = 0;
// Firefly numbers that has the light.
item.ItemFlags[FirefliesItemFlags::LightIndex1] = NO_VALUE;
item.ItemFlags[FirefliesItemFlags::LightIndex2] = NO_VALUE;
}
void SpawnFireflySwarm(ItemInfo& item, int triggerFlags)
{
constexpr auto VEL_MAX = 34.0f;
constexpr auto VEL_MIN = 6.0f;
// Create new firefly.
auto& firefly = GetNewEffect(FireflySwarm, MAX_FIREFLIES);
unsigned char r = 255;
unsigned char g = 255;
unsigned char b = 255;
if (triggerFlags >= 0)
{
float brightnessShift = Random::GenerateFloat(-0.1f, 0.1f);
r = std::clamp(item.Model.Color.x / 2.0f + brightnessShift, 0.0f, 1.0f) * UCHAR_MAX;
g = std::clamp(item.Model.Color.y / 2.0f + brightnessShift, 0.0f, 1.0f) * UCHAR_MAX;
b = std::clamp(item.Model.Color.z / 2.0f + brightnessShift, 0.0f, 1.0f) * UCHAR_MAX;
firefly.SpriteSeqID = ID_FIREFLY_SPRITES;
firefly.SpriteID = 0;
firefly.blendMode = BlendMode::Additive;
firefly.scalar = 3.0f;
firefly.size = 1.0f;
}
else
{
firefly.SpriteSeqID = ID_FIREFLY_SPRITES;
firefly.SpriteID = 1;
firefly.blendMode = BlendMode::Subtractive;
firefly.scalar = 1.2f;
firefly.size = 1.2f;
}
firefly.r = firefly.rB = r;
firefly.g = firefly.gB = g;
firefly.b = firefly.bB = b;
firefly.rotAng = ANGLE(0.0f);
if (item.TriggerFlags > 8)
firefly.rotAng = ANGLE(90.0f);
firefly.on = true;
firefly.Position = item.Pose.Position.ToVector3();
firefly.RoomNumber = item.RoomNumber;
firefly.Orientation = item.Pose.Orientation;
firefly.Velocity = Random::GenerateFloat(VEL_MIN, VEL_MAX);
firefly.zVel = 0.3f;
firefly.Life = Random::GenerateInt(1, 400);
firefly.TargetItemPtr = &g_Level.Items[item.ItemFlags[FirefliesItemFlags::TargetItemPtr]];
int& nextFireflyNumber = nextFireflyNumberMap[item.Index];
firefly.Number = nextFireflyNumber++;
}
void ControlFireflySwarm(short itemNumber)
{
auto& item = g_Level.Items[itemNumber];
if (!TriggerActive(&item))
{
// Remove all fireflies associated with this item.
RemoveFireflies(item);
// Reset ItemFlags.
if (item.HitPoints == NOT_TARGETABLE)
item.HitPoints = item.ItemFlags[FirefliesItemFlags::Spawncounter];
item.ItemFlags[FirefliesItemFlags::Spawncounter] = 0;
item.ItemFlags[FirefliesItemFlags::LightIndex1] = NO_VALUE;
item.ItemFlags[FirefliesItemFlags::LightIndex2] = NO_VALUE;
return;
}
constexpr auto ALPHA_PAUSE_DURATION = 2.0f;
static float frameCounter = 0.0f;
// Increment the counter variable in each frame.
frameCounter += 1.0f;
if (item.HitPoints != NOT_TARGETABLE)
{
int fireflyCount = item.HitPoints - item.ItemFlags[FirefliesItemFlags::Spawncounter];
if (fireflyCount < 0)
{
int firefliesToTurnOff = -fireflyCount;
for (auto& firefly : FireflySwarm)
{
if (firefly.TargetItemPtr == &item && firefly.Life > 0.0f)
{
firefly.Life = 0.0f;
firefly.on = false;
firefliesToTurnOff--;
if (firefliesToTurnOff == 0)
break;
}
}
}
else if (fireflyCount > 0)
{
for (int i = 0; i < fireflyCount; i++)
{
SpawnFireflySwarm(item, item.TriggerFlags);
}
}
item.ItemFlags[FirefliesItemFlags::Spawncounter] = item.HitPoints;
item.HitPoints = NOT_TARGETABLE;
}
// Update color values for blinking effect.
float alphaFactor;
for (auto& firefly : FireflySwarm)
{
auto targetItem = firefly.TargetItemPtr;
if (targetItem == &item)
{
// Choose one of the available firefly number that has the light.
if (targetItem->ItemFlags[FirefliesItemFlags::LightIndex1] == NO_VALUE && targetItem->ItemFlags[FirefliesItemFlags::TriggerFlags] >= 0)
{
targetItem->ItemFlags[FirefliesItemFlags::LightIndex1] = Random::GenerateInt(0, targetItem->TriggerFlags);
}
// Two lights max for each cluster.
if (targetItem->ItemFlags[FirefliesItemFlags::LightIndex2] == NO_VALUE && targetItem->ItemFlags[FirefliesItemFlags::TriggerFlags] >= 0)
{
targetItem->ItemFlags[FirefliesItemFlags::LightIndex2] = Random::GenerateInt(0, targetItem->TriggerFlags);
}
auto posBase = firefly.Position;
auto rotMatrix = firefly.Orientation.ToRotationMatrix();
auto pos = posBase + Vector3::Transform(Vector3(0, 0, 30), rotMatrix);
auto direction0 = Geometry::RotatePoint(posBase, EulerAngles::Identity);
short orient2D = firefly.Orientation.z;
if (targetItem->ItemFlags[FirefliesItemFlags::TriggerFlags] >= 0)
{
StreamerEffect.Spawn(targetItem->Index, firefly.Number, pos, direction0, orient2D,
Vector4(firefly.r / (float)UCHAR_MAX, firefly.g / (float)UCHAR_MAX, firefly.b / (float)UCHAR_MAX, 1.0f),
Vector4::Zero,
6.3f - (firefly.zVel / 12), ((firefly.Velocity / 8) + firefly.zVel * 3) / (float)UCHAR_MAX, 0.0f, -0.1f, 90.0f, StreamerFeatherMode::None, BlendMode::Additive);
}
else if (targetItem->ItemFlags[FirefliesItemFlags::TriggerFlags] < 0)
{
StreamerEffect.Spawn(targetItem->Index, firefly.Number, pos, direction0, orient2D,
Vector4((firefly.r / 2) / (float)UCHAR_MAX, (firefly.g / 2) / (float)UCHAR_MAX, (firefly.b / 2) / (float)UCHAR_MAX, 0.2f),
Vector4((firefly.r / 3) / (float)UCHAR_MAX, (firefly.g / 3) / (float)UCHAR_MAX, (firefly.b / 3) / (float)UCHAR_MAX, 0.2f),
0.0f, 0.4f, 0.0f, 0.2f, 0.0f, StreamerFeatherMode::None, BlendMode::Subtractive);
}
if ((targetItem->ItemFlags[FirefliesItemFlags::LightIndex1] == firefly.Number || targetItem->ItemFlags[FirefliesItemFlags::LightIndex2] == firefly.Number) &&
targetItem->ItemFlags[FirefliesItemFlags::Light] == 1)
{
float totalCycleDuration = 2 * (LIGHT_ALPHA_CYCLE_DURATION + ALPHA_PAUSE_DURATION);
float alphaTime = fmod(frameCounter, totalCycleDuration);
if (alphaTime < ALPHA_PAUSE_DURATION)
{
alphaFactor = 1.0f; // Pause on Alpha 1.
}
else if (alphaTime < ALPHA_PAUSE_DURATION + LIGHT_ALPHA_CYCLE_DURATION)
{
alphaFactor = 1.0f - ((alphaTime - ALPHA_PAUSE_DURATION) / LIGHT_ALPHA_CYCLE_DURATION);
}
else if (alphaTime < 2 * ALPHA_PAUSE_DURATION + LIGHT_ALPHA_CYCLE_DURATION)
{
alphaFactor = 0.0f; // Pause on Alpha 0.
targetItem->ItemFlags[FirefliesItemFlags::LightIndex1] = NO_VALUE;
targetItem->ItemFlags[FirefliesItemFlags::LightIndex2] = NO_VALUE;
}
else
{
alphaFactor = (alphaTime - 2 * ALPHA_PAUSE_DURATION - LIGHT_ALPHA_CYCLE_DURATION) / LIGHT_ALPHA_CYCLE_DURATION;
}
SpawnDynamicLight(firefly.Position.x, firefly.Position.y, firefly.Position.z, 3,
static_cast<unsigned char>(std::clamp(firefly.r * alphaFactor, 0.0f, (float)firefly.r)),
static_cast<unsigned char>(std::clamp(firefly.g * alphaFactor, 0.0f, (float)firefly.g)),
static_cast<unsigned char>(std::clamp(firefly.b * alphaFactor, 0.0f, (float)firefly.b)));
}
}
}
}
void UpdateFireflySwarm()
{
constexpr auto FLEE_VEL = 1.5f;
constexpr auto ALPHA_PAUSE_DURATION = 100.0f;
static const auto SPHERE = BoundingSphere(Vector3::Zero, BLOCK(1 / 8.0f));
if (FireflySwarm.empty())
return;
const auto& playerItem = *LaraItem;
static float frameCounter = 0.0f;
// Increment the counter variable in each frame.
frameCounter += 1.0f;
for (auto& firefly : FireflySwarm)
{
if (firefly.Life <= 0.0f || !firefly.on)
continue;
auto targetItem = firefly.TargetItemPtr;
if (targetItem->ItemFlags[FirefliesItemFlags::RemoveFliesEffect])
{
firefly.r = 0;
firefly.g = 0;
firefly.b = 0;
continue;
}
firefly.StoreInterpolationData();
firefly.PositionTarget = Random::GeneratePointInSphere(SPHERE);
int multiplierX = CLICK(targetItem->ItemFlags[FirefliesItemFlags::TriggerFlags] * 2);
int multiplierY = CLICK(targetItem->ItemFlags[FirefliesItemFlags::TriggerFlags] * 4);
int multiplierZ = CLICK(targetItem->ItemFlags[FirefliesItemFlags::TriggerFlags] * 2);
auto spheroidAxis = Vector3(multiplierX, multiplierY, multiplierZ);
auto itemPos = Vector3i(targetItem->Pose.Position.x, targetItem->Pose.Position.y - FIREFLY_RISE_UP_FACTOR, targetItem->Pose.Position.z);
// Calculate desired position based on target object and random offsets.
auto desiredPos = itemPos + Random::GeneratePointInSpheroid(firefly.PositionTarget, EulerAngles::Identity, spheroidAxis);
auto dir = desiredPos - firefly.Position;
auto dirs = dir.ToVector3();
dirs.Normalize();
auto dirNorm = dirs;
// Define cohesion factor to keep fireflies close together.
float distToTarget = dirs.Length();
float targetVel = (distToTarget * FIREFLY_COHESION_FACTOR) + Random::GenerateFloat(3.0f, 5.0f);
firefly.Velocity = std::min(targetVel, targetItem->Animation.Velocity.z - 21.0f);
// If firefly is too far from target, increase velocity to catch up.
if (distToTarget > FIREFLY_TARGET_DISTANCE_MAX)
firefly.Velocity += FIREFLY_CATCH_UP_FACTOR;
// Translate.
auto moveDir = firefly.Orientation.ToDirection();
moveDir.Normalize();
firefly.Position += (moveDir * firefly.Velocity) / 26.0f;
firefly.Position += (moveDir * FIREFLY_SPACING_FACTOR) / 26.0f;
auto orientTo = Geometry::GetOrientToPoint(firefly.Position, desiredPos.ToVector3());
firefly.Orientation.Lerp(orientTo, 0.1f);
// Update color values for blinking effect.
float totalCycleDuration = 2 * (LIGHT_ALPHA_CYCLE_DURATION + ALPHA_PAUSE_DURATION);
float alphaTime = fmod(frameCounter + firefly.Life, totalCycleDuration);
float alphaFactor;
if (alphaTime < ALPHA_PAUSE_DURATION)
{
alphaFactor = 1.0f;
}
else if (alphaTime < ALPHA_PAUSE_DURATION + LIGHT_ALPHA_CYCLE_DURATION)
{
alphaFactor = 1.0f - ((alphaTime - ALPHA_PAUSE_DURATION) / LIGHT_ALPHA_CYCLE_DURATION);
}
else if (alphaTime < 2 * ALPHA_PAUSE_DURATION + LIGHT_ALPHA_CYCLE_DURATION)
{
alphaFactor = 0.0f;
}
else
{
alphaFactor = (alphaTime - 2 * ALPHA_PAUSE_DURATION - LIGHT_ALPHA_CYCLE_DURATION) / LIGHT_ALPHA_CYCLE_DURATION;
}
firefly.r = static_cast<unsigned char>(firefly.rB * alphaFactor);
firefly.g = static_cast<unsigned char>(firefly.gB * alphaFactor);
firefly.b = static_cast<unsigned char>(firefly.bB * alphaFactor);
for (const auto& otherFirefly : FireflySwarm)
{
if (&firefly == &otherFirefly)
continue;
float distToOtherFirefly = Vector3i::Distance(firefly.Position, otherFirefly.Position);
float distToPlayer = Vector3i::Distance(firefly.Position, playerItem.Pose.Position);
// If player is too close, flee.
if (distToPlayer < FIREFLY_FLEE_DISTANCE && playerItem.Animation.ActiveState != 2)
{
auto separationDir = firefly.Position - playerItem.Pose.Position.ToVector3();
separationDir.Normalize();
// Reduce the Y component of the escape direction.
separationDir.y *= Random::GenerateFloat(0.0f, 0.4f);
// Normalize the direction again to get the length of the vector.
separationDir.Normalize();
firefly.Position += separationDir * FLEE_VEL;
auto orientTo = Geometry::GetOrientToPoint(firefly.Position, separationDir);
firefly.Orientation.Lerp(orientTo, 0.05f);
firefly.Velocity -= std::min(FLEE_VEL, firefly.TargetItemPtr->Animation.Velocity.z - 1.0f);
if (Random::TestProbability(1.0f / 700.0f) &&
targetItem->ItemFlags[FirefliesItemFlags::Light] == 1 &&
targetItem->ItemFlags[FirefliesItemFlags::TriggerFlags] >= 0)
{
if (firefly.zVel == 0.3f)
{
firefly.zVel = 50.0f;
}
}
if (firefly.zVel > 50.0f)
firefly.zVel = 0.3f;
}
if (distToOtherFirefly < FIREFLY_BASE_SEPARATION_DISTANCE)
{
auto separationDir = firefly.Position - otherFirefly.Position;
separationDir.Normalize();
firefly.Position += separationDir * (FIREFLY_BASE_SEPARATION_DISTANCE - distToOtherFirefly);
}
}
auto pointColl = GetPointCollision(firefly.Position, firefly.RoomNumber);
// Update firefly room number.
if (pointColl.GetRoomNumber() != firefly.RoomNumber &&
pointColl.GetRoomNumber() != NO_VALUE)
{
firefly.RoomNumber = pointColl.GetRoomNumber();
}
if (targetItem->ItemFlags[FirefliesItemFlags::Light] == 1 && targetItem->ItemFlags[FirefliesItemFlags::TriggerFlags] >= 0)
{
if (Random::TestProbability(1.0f / (700.0f - (float)(targetItem->ItemFlags[FirefliesItemFlags::Spawncounter] * 2))))
firefly.zVel = 100.0f;
if (firefly.zVel > 1.0f)
firefly.zVel -= 2.0f;
if (firefly.zVel <= 1.0f)
firefly.zVel = 0.3f;
}
}
}
void RemoveFireflies(ItemInfo& item)
{
FireflySwarm.erase(std::remove_if(FireflySwarm.begin(), FireflySwarm.end(),
[&item](FireflyData& firefly)
{
if (firefly.TargetItemPtr == &item)
{
firefly.Life = 0.0f;
firefly.on = false;
return true;
}
return false;
}), FireflySwarm.end());
nextFireflyNumberMap.erase(item.Index);
}
void ClearFireflySwarm()
{
FireflySwarm.clear();
nextFireflyNumberMap.clear();
}
}

View file

@ -0,0 +1,76 @@
#pragma once
#include "Game/items.h"
#include "Math/Math.h"
using namespace TEN::Math;
namespace TEN::Effects::Fireflies
{
enum FirefliesItemFlags
{
TargetItemPtr,
Light,
TriggerFlags,
Spawncounter,
RemoveFliesEffect,
LightIndex1,
LightIndex2
};
struct FireflyData
{
int SpriteSeqID = ID_DEFAULT_SPRITES;
int SpriteID = SPR_UNDERWATERDUST;
BlendMode blendMode;
unsigned int scalar;
Vector3 Position = Vector3::Zero;
int RoomNumber = 0;
Vector3 PositionTarget = Vector3::Zero;
EulerAngles Orientation = EulerAngles::Identity;
float Velocity = 0.0f;
ItemInfo* TargetItemPtr = nullptr;
float zVel;
float Life = 0.0f;
int Number = 0;
unsigned char rB;
unsigned char gB;
unsigned char bB;
unsigned char r;
unsigned char g;
unsigned char b;
bool on;
float size;
short rotAng;
int PrevX;
int PrevY;
int PrevZ;
byte PrevR;
byte PrevG;
byte PrevB;
void StoreInterpolationData()
{
PrevX = Position.x;
PrevY = Position.y;
PrevZ = Position.z;
PrevR = r;
PrevG = g;
PrevB = b;
}
};
extern std::vector<FireflyData> FireflySwarm;
void InitializeFireflySwarm(short itemNumber);
void ControlFireflySwarm(short itemNumber);
void UpdateFireflySwarm();
void ClearFireflySwarm();
void SpawnFireflySwarm(ItemInfo& item, int triggerFlags);
void RemoveFireflies(ItemInfo& item);
}

View file

@ -17,6 +17,7 @@
#include "Game/Lara/lara_helpers.h" #include "Game/Lara/lara_helpers.h"
#include "Game/Setup.h" #include "Game/Setup.h"
#include "Math/Math.h" #include "Math/Math.h"
#include "Objects/Effects/Fireflies.h"
#include "Scripting/Include/Flow/ScriptInterfaceFlowHandler.h" #include "Scripting/Include/Flow/ScriptInterfaceFlowHandler.h"
#include "Sound/sound.h" #include "Sound/sound.h"
#include "Specific/level.h" #include "Specific/level.h"
@ -25,9 +26,13 @@ using namespace TEN::Collision::Point;
using namespace TEN::Effects::Ripple; using namespace TEN::Effects::Ripple;
using namespace TEN::Effects::Splash; using namespace TEN::Effects::Splash;
using namespace TEN::Math; using namespace TEN::Math;
using namespace TEN::Effects::Fireflies;
namespace TEN::Entities::TR3 namespace TEN::Entities::TR3
{ {
constexpr auto FLY_EFFECT_MAX_WIDTH = -1;
constexpr auto FLY_AMOUNT = 16;
enum CorpseState enum CorpseState
{ {
CORPSE_STATE_GROUNDED = 0, CORPSE_STATE_GROUNDED = 0,
@ -51,19 +56,25 @@ namespace TEN::Entities::TR3
if (item.TriggerFlags == 1) if (item.TriggerFlags == 1)
{ {
item.ItemFlags[1] = (int)CorpseFlag::Hang; item.ItemFlags[7] = (int)CorpseFlag::Hang;
item.Animation.AnimNumber = object.animIndex + CORPSE_ANIM_HANG; item.Animation.AnimNumber = object.animIndex + CORPSE_ANIM_HANG;
item.Animation.ActiveState = CORPSE_STATE_HANG; item.Animation.ActiveState = CORPSE_STATE_HANG;
} }
else else
{ {
item.ItemFlags[1] = (int)CorpseFlag::Grounded; item.ItemFlags[7] = (int)CorpseFlag::Grounded;
item.Animation.AnimNumber = object.animIndex + CORPSE_ANIM_GROUNDED; item.Animation.AnimNumber = object.animIndex + CORPSE_ANIM_GROUNDED;
item.Animation.ActiveState = CORPSE_STATE_GROUNDED; item.Animation.ActiveState = CORPSE_STATE_GROUNDED;
} }
item.ItemFlags[FirefliesItemFlags::RemoveFliesEffect] = 0;
AddActiveItem(itemNumber); AddActiveItem(itemNumber);
item.Status = ITEM_ACTIVE; item.Status = ITEM_ACTIVE;
item.ItemFlags[FirefliesItemFlags::TargetItemPtr] = item.Index;
item.ItemFlags[FirefliesItemFlags::TriggerFlags] = -1;
item.HitPoints = FLY_AMOUNT;
} }
void ControlCorpse(short itemNumber) void ControlCorpse(short itemNumber)
@ -71,9 +82,11 @@ namespace TEN::Entities::TR3
auto& item = g_Level.Items[itemNumber]; auto& item = g_Level.Items[itemNumber];
const auto& object = Objects[item.ObjectNumber]; const auto& object = Objects[item.ObjectNumber];
if (item.ItemFlags[1] == (int)CorpseFlag::Fall) if (item.ItemFlags[7] == (int)CorpseFlag::Fall)
{ {
bool isWater = TestEnvironment(RoomEnvFlags::ENV_FLAG_WATER, item.RoomNumber); bool isWater = TestEnvironment(RoomEnvFlags::ENV_FLAG_WATER, item.RoomNumber);
bool isSwamp = TestEnvironment(RoomEnvFlags::ENV_FLAG_SWAMP, item.RoomNumber);
float verticalVelCoeff = isWater ? 81.0f : 1.0f; float verticalVelCoeff = isWater ? 81.0f : 1.0f;
auto pointColl = GetPointCollision(item); auto pointColl = GetPointCollision(item);
@ -94,31 +107,37 @@ namespace TEN::Entities::TR3
ItemNewRoom(itemNumber, pointColl.GetRoomNumber()); ItemNewRoom(itemNumber, pointColl.GetRoomNumber());
} }
pointColl = GetPointCollision(item); // Remove fly effect when in water.
if (isWater || isSwamp)
{
item.ItemFlags[FirefliesItemFlags::RemoveFliesEffect] = 1;
}
auto bounds = GameBoundingBox(&item);
item.Animation.IsAirborne = true; item.Animation.IsAirborne = true;
if (pointColl.GetFloorHeight() < item.Pose.Position.y) if (pointColl.GetFloorHeight() <= item.Pose.Position.y - bounds.Y2)
{ {
if (!isWater) if (!isWater)
{ {
item.Pose.Position.y = item.Pose.Position.y - item.Animation.Velocity.y; item.Pose.Position.y = pointColl.GetFloorHeight();
SoundEffect(SFX_TR4_CROCGOD_LAND, &item.Pose); SoundEffect(SFX_TR4_CROCGOD_LAND, &item.Pose);
} }
else else
{ {
item.Pose.Position.y = item.Pose.Position.y; item.Pose.Position.y = pointColl.GetFloorHeight();
} }
item.Animation.IsAirborne = false; item.Animation.IsAirborne = false;
item.Animation.Velocity = Vector3::Zero; item.Animation.Velocity = Vector3::Zero;
item.Animation.TargetState = CORPSE_STATE_LAND; item.Animation.TargetState = CORPSE_STATE_LAND;
item.Animation.AnimNumber = object.animIndex + CORPSE_ANIM_LAND; item.Animation.AnimNumber = object.animIndex + CORPSE_ANIM_LAND;
AlignEntityToSurface(&item, Vector2(object.radius));
item.ItemFlags[1] = (int)CorpseFlag::Grounded; item.ItemFlags[7] = (int)CorpseFlag::Grounded;
return; return;
} }
else else if (item.Animation.ActiveState == CORPSE_STATE_FALL)
{ {
if (isWater) if (isWater)
{ {
@ -133,17 +152,56 @@ namespace TEN::Entities::TR3
AnimateItem(&item); AnimateItem(&item);
if (!TriggerActive(&item)) if (!TriggerActive(&item) || item.ItemFlags[FirefliesItemFlags::RemoveFliesEffect] == 1)
return;
int meshCount = object.nmeshes;
for (int i = 0; i < meshCount; i++)
{ {
if (Random::TestProbability(1 / 72.0f)) // Remove all fireflies associated with this item.
RemoveFireflies(item);
// Reset ItemFlags.
if (item.HitPoints == NOT_TARGETABLE)
item.HitPoints = FLY_AMOUNT;
item.ItemFlags[FirefliesItemFlags::Spawncounter] = 0;
return;
}
else
{
AddActiveItem(itemNumber);
item.Status = ITEM_ACTIVE;
}
// Spawn fly effect.
if (item.HitPoints != NOT_TARGETABLE)
{
int fireflyCount = item.HitPoints - item.ItemFlags[FirefliesItemFlags::Spawncounter];
if (fireflyCount < 0)
{ {
auto pos = GetJointPosition(&item, i).ToVector3(); int firefliesToTurnOff = -fireflyCount;
SpawnCorpseEffect(pos); for (auto& firefly : FireflySwarm)
{
if (firefly.TargetItemPtr == &item && firefly.Life > 0.0f)
{
firefly.Life = 0.0f;
firefly.on = false;
firefliesToTurnOff--;
if (firefliesToTurnOff == 0)
break;
}
}
} }
else if (fireflyCount > 0)
{
for (int i = 0; i < fireflyCount; i++)
{
SpawnFireflySwarm(item, FLY_EFFECT_MAX_WIDTH);
}
}
item.ItemFlags[FirefliesItemFlags::Spawncounter] = item.HitPoints;
item.HitPoints = NOT_TARGETABLE;
} }
} }
@ -160,9 +218,9 @@ namespace TEN::Entities::TR3
{ {
DoBloodSplat(pos->x, pos->y, pos->z, Random::GenerateInt(4, 8), source.Pose.Orientation.y, pos->RoomNumber); DoBloodSplat(pos->x, pos->y, pos->z, Random::GenerateInt(4, 8), source.Pose.Orientation.y, pos->RoomNumber);
if (target.ItemFlags[1] == (int)CorpseFlag::Hang) if (target.ItemFlags[7] == (int)CorpseFlag::Hang)
{ {
target.ItemFlags[1] = (int)CorpseFlag::Fall; target.ItemFlags[7] = (int)CorpseFlag::Fall;
target.Animation.AnimNumber = object.animIndex + CORPSE_ANIM_FALL; target.Animation.AnimNumber = object.animIndex + CORPSE_ANIM_FALL;
target.Animation.ActiveState = CORPSE_STATE_FALL; target.Animation.ActiveState = CORPSE_STATE_FALL;
} }

View file

@ -42,6 +42,7 @@
#include "Objects/TR5/Emitter/tr5_spider_emitter.h" #include "Objects/TR5/Emitter/tr5_spider_emitter.h"
#include "Objects/TR5/Emitter/tr5_smoke_emitter.h" #include "Objects/TR5/Emitter/tr5_smoke_emitter.h"
#include "Objects/TR5/Emitter/Waterfall.h" #include "Objects/TR5/Emitter/Waterfall.h"
#include "Objects/Effects/Fireflies.h"
// Objects // Objects
#include "Objects/TR5/Light/tr5_light.h" #include "Objects/TR5/Light/tr5_light.h"
@ -81,6 +82,7 @@ using namespace TEN::Effects::WaterfallEmitter;
using namespace TEN::Entities::Creatures::TR5; using namespace TEN::Entities::Creatures::TR5;
using namespace TEN::Entities::Switches; using namespace TEN::Entities::Switches;
using namespace TEN::Entities::Traps; using namespace TEN::Entities::Traps;
using namespace TEN::Effects::Fireflies;
static void StartEntity(ObjectInfo *obj) static void StartEntity(ObjectInfo *obj)
{ {
@ -796,6 +798,14 @@ static void StartObject(ObjectInfo *obj)
obj->control = ControlEmberEmitter; obj->control = ControlEmberEmitter;
} }
obj = &Objects[ID_FIREFLY_EMITTER];
if (obj->loaded)
{
obj->Initialize = InitializeFireflySwarm;
obj->control = ControlFireflySwarm;
obj->drawRoutine = NULL;
}
obj = &Objects[ID_GEN_SLOT1]; obj = &Objects[ID_GEN_SLOT1];
if (obj->loaded) if (obj->loaded)
{ {

View file

@ -817,6 +817,7 @@ enum GAME_OBJECT_ID : short
ID_CORPSE, ID_CORPSE,
ID_WRAITH_TRAP, ID_WRAITH_TRAP,
ID_WATERFALL_EMITTER, ID_WATERFALL_EMITTER,
ID_FIREFLY_EMITTER,
ID_MESHSWAP1 = 1100, ID_MESHSWAP1 = 1100,
ID_MESHSWAP2, ID_MESHSWAP2,
@ -1006,8 +1007,8 @@ enum GAME_OBJECT_ID : short
ID_DASH_BAR_TEXTURE, ID_DASH_BAR_TEXTURE,
ID_SFX_BAR_TEXTURE, ID_SFX_BAR_TEXTURE,
ID_WATERFALL_SPRITES, ID_WATERFALL_SPRITES,
// 1379 ID_FIREFLY_SPRITES,
ID_CROSSHAIR_GRAPHICS = 1380, ID_CROSSHAIR_GRAPHICS,
ID_SPEEDOMETER_GRAPHICS, ID_SPEEDOMETER_GRAPHICS,
ID_CUSTOM_BAR_GRAPHICS, ID_CUSTOM_BAR_GRAPHICS,
ID_CUSTOM_AMMO_GRAPHICS, ID_CUSTOM_AMMO_GRAPHICS,

View file

@ -409,6 +409,7 @@ namespace TEN::Renderer
void PrepareFires(RenderView& view); void PrepareFires(RenderView& view);
void PrepareParticles(RenderView& view); void PrepareParticles(RenderView& view);
void PrepareSmokes(RenderView& view); void PrepareSmokes(RenderView& view);
void PrepareFireflies(RenderView& view);
void PrepareElectricity(RenderView& view); void PrepareElectricity(RenderView& view);
void PrepareHelicalLasers(RenderView& view); void PrepareHelicalLasers(RenderView& view);
void PrepareBlood(RenderView& view); void PrepareBlood(RenderView& view);

View file

@ -1759,6 +1759,7 @@ namespace TEN::Renderer
PrepareStreamers(view); PrepareStreamers(view);
PrepareLaserBarriers(view); PrepareLaserBarriers(view);
PrepareSingleLaserBeam(view); PrepareSingleLaserBeam(view);
PrepareFireflies(view);
// Sprites grouped in buckets for instancing. Non-commutative sprites are collected at a later stage. // Sprites grouped in buckets for instancing. Non-commutative sprites are collected at a later stage.
SortAndPrepareSprites(view); SortAndPrepareSprites(view);

View file

@ -35,6 +35,7 @@
#include "Scripting/Include/Flow/ScriptInterfaceFlowHandler.h" #include "Scripting/Include/Flow/ScriptInterfaceFlowHandler.h"
#include "Specific/level.h" #include "Specific/level.h"
#include "Structures/RendererSpriteBucket.h" #include "Structures/RendererSpriteBucket.h"
#include "Objects/Effects/Fireflies.h"
using namespace TEN::Effects::Blood; using namespace TEN::Effects::Blood;
using namespace TEN::Effects::Bubble; using namespace TEN::Effects::Bubble;
@ -48,6 +49,7 @@ using namespace TEN::Effects::Streamer;
using namespace TEN::Entities::Creatures::TR5; using namespace TEN::Entities::Creatures::TR5;
using namespace TEN::Entities::Traps; using namespace TEN::Entities::Traps;
using namespace TEN::Math; using namespace TEN::Math;
using namespace TEN::Effects::Fireflies;
extern BLOOD_STRUCT Blood[MAX_SPARKS_BLOOD]; extern BLOOD_STRUCT Blood[MAX_SPARKS_BLOOD];
extern FIRE_SPARKS FireSparks[MAX_SPARKS_FIRE]; extern FIRE_SPARKS FireSparks[MAX_SPARKS_FIRE];
@ -330,6 +332,49 @@ namespace TEN::Renderer
} }
} }
void Renderer::PrepareFireflies(RenderView& view)
{
if (!Objects[ID_FIREFLY_EMITTER].loaded)
return;
for (auto& firefly : FireflySwarm)
{
if (!firefly.on)
continue;
if (!CheckIfSlotExists(ID_SPARK_SPRITE, "Particle rendering"))
continue;
auto axis = Vector3(0,0,0);
axis.Normalize();
firefly.scalar = 3;
firefly.size = 3;
auto pos = Vector3::Lerp(
Vector3(firefly.PrevX, firefly.PrevY, firefly.PrevZ),
Vector3(firefly.Position.x, firefly.Position.y, firefly.Position.z),
GetInterpolationFactor());
pos = Vector3(firefly.Position.x, firefly.Position.y, firefly.Position.z);
// Disallow sprites out of bounds.
int spriteIndex = Objects[firefly.SpriteSeqID].meshIndex + firefly.SpriteID;
spriteIndex = std::clamp(spriteIndex, 0, (int)_sprites.size());
AddSpriteBillboard(
&_sprites[spriteIndex],
pos,
Color(firefly.r / (float)UCHAR_MAX, firefly.g / (float)UCHAR_MAX, firefly.b / (float)UCHAR_MAX, 1.0f),
TO_RAD(firefly.rotAng << 4), firefly.scalar,
Vector2(firefly.size, firefly.size),
firefly.blendMode, true, view);
}
}
void Renderer::PrepareSmokes(RenderView& view) void Renderer::PrepareSmokes(RenderView& view)
{ {
for (const auto& smoke : SmokeSparks) for (const auto& smoke : SmokeSparks)

View file

@ -1,7 +1,7 @@
#pragma once #pragma once
// This file is generated automatically, do not edit it. // This file is generated automatically, do not edit it.
// Last generated on 13/03/2025. // Last generated on 17/03/2025.
#include <unordered_map> #include <unordered_map>
#include <string> #include <string>
@ -815,6 +815,7 @@ The following constants are inside ObjID.
CORPSE CORPSE
WRAITH_TRAP WRAITH_TRAP
WATERFALL_EMITTER WATERFALL_EMITTER
FIREFLY_EMITTER
MESHSWAP1 MESHSWAP1
MESHSWAP2 MESHSWAP2
MESHSWAP3 MESHSWAP3
@ -995,6 +996,7 @@ The following constants are inside ObjID.
DASH_BAR_TEXTURE DASH_BAR_TEXTURE
SFX_BAR_TEXTURE SFX_BAR_TEXTURE
WATERFALL_SPRITES WATERFALL_SPRITES
FIREFLY_SPRITES
CROSSHAIR_GRAPHICS CROSSHAIR_GRAPHICS
SPEEDOMETER_GRAPHICS SPEEDOMETER_GRAPHICS
CUSTOM_BAR_GRAPHICS CUSTOM_BAR_GRAPHICS
@ -1245,6 +1247,7 @@ The following ObjID members refer to sprites.
DASH_BAR_TEXTURE DASH_BAR_TEXTURE
SFX_BAR_TEXTURE SFX_BAR_TEXTURE
WATERFALL_SPRITES WATERFALL_SPRITES
FIREFLY_SPRITES
CROSSHAIR_GRAPHICS CROSSHAIR_GRAPHICS
SPEEDOMETER_GRAPHICS SPEEDOMETER_GRAPHICS
CUSTOM_BAR_GRAPHICS CUSTOM_BAR_GRAPHICS
@ -2052,6 +2055,7 @@ static const std::unordered_map<std::string, GAME_OBJECT_ID> GAME_OBJECT_IDS {
{ "CORPSE", ID_CORPSE }, { "CORPSE", ID_CORPSE },
{ "WRAITH_TRAP", ID_WRAITH_TRAP }, { "WRAITH_TRAP", ID_WRAITH_TRAP },
{ "WATERFALL_EMITTER", ID_WATERFALL_EMITTER }, { "WATERFALL_EMITTER", ID_WATERFALL_EMITTER },
{ "FIREFLY_EMITTER", ID_FIREFLY_EMITTER },
{ "MESHSWAP1", ID_MESHSWAP1 }, { "MESHSWAP1", ID_MESHSWAP1 },
{ "MESHSWAP2", ID_MESHSWAP2 }, { "MESHSWAP2", ID_MESHSWAP2 },
{ "MESHSWAP3", ID_MESHSWAP3 }, { "MESHSWAP3", ID_MESHSWAP3 },
@ -2232,6 +2236,7 @@ static const std::unordered_map<std::string, GAME_OBJECT_ID> GAME_OBJECT_IDS {
{ "DASH_BAR_TEXTURE", ID_DASH_BAR_TEXTURE }, { "DASH_BAR_TEXTURE", ID_DASH_BAR_TEXTURE },
{ "SFX_BAR_TEXTURE", ID_SFX_BAR_TEXTURE }, { "SFX_BAR_TEXTURE", ID_SFX_BAR_TEXTURE },
{ "WATERFALL_SPRITES", ID_WATERFALL_SPRITES }, { "WATERFALL_SPRITES", ID_WATERFALL_SPRITES },
{ "FIREFLY_SPRITES", ID_FIREFLY_SPRITES },
{ "CROSSHAIR_GRAPHICS", ID_CROSSHAIR_GRAPHICS }, { "CROSSHAIR_GRAPHICS", ID_CROSSHAIR_GRAPHICS },
{ "SPEEDOMETER_GRAPHICS", ID_SPEEDOMETER_GRAPHICS }, { "SPEEDOMETER_GRAPHICS", ID_SPEEDOMETER_GRAPHICS },
{ "CUSTOM_BAR_GRAPHICS", ID_CUSTOM_BAR_GRAPHICS }, { "CUSTOM_BAR_GRAPHICS", ID_CUSTOM_BAR_GRAPHICS },

View file

@ -169,6 +169,10 @@ struct FishData;
struct FishDataBuilder; struct FishDataBuilder;
struct FishDataT; struct FishDataT;
struct FireflyData;
struct FireflyDataBuilder;
struct FireflyDataT;
struct KeyValPair; struct KeyValPair;
struct ScriptTable; struct ScriptTable;
@ -6861,6 +6865,295 @@ struct FishData::Traits {
flatbuffers::Offset<FishData> CreateFishData(flatbuffers::FlatBufferBuilder &_fbb, const FishDataT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr); flatbuffers::Offset<FishData> CreateFishData(flatbuffers::FlatBufferBuilder &_fbb, const FishDataT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
struct FireflyDataT : public flatbuffers::NativeTable {
typedef FireflyData TableType;
int32_t sprite_index = 0;
int32_t sprite_id = 0;
int32_t blend_mode = 0;
int32_t scalar = 0;
std::unique_ptr<TEN::Save::Vector3> position{};
int32_t room_number = 0;
std::unique_ptr<TEN::Save::Vector3> position_target{};
std::unique_ptr<TEN::Save::EulerAngles> orientation{};
float velocity = 0.0f;
int32_t target_item_number = 0;
float z_vel = 0.0f;
float life = 0.0f;
int32_t number = 0;
int32_t d_r = 0;
int32_t d_g = 0;
int32_t d_b = 0;
int32_t r = 0;
int32_t g = 0;
int32_t b = 0;
bool on = false;
float size = 0.0f;
int32_t rot_Ang = 0;
};
struct FireflyData FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
typedef FireflyDataT NativeTableType;
typedef FireflyDataBuilder Builder;
struct Traits;
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
VT_SPRITE_INDEX = 4,
VT_SPRITE_ID = 6,
VT_BLEND_MODE = 8,
VT_SCALAR = 10,
VT_POSITION = 12,
VT_ROOM_NUMBER = 14,
VT_POSITION_TARGET = 16,
VT_ORIENTATION = 18,
VT_VELOCITY = 20,
VT_TARGET_ITEM_NUMBER = 22,
VT_Z_VEL = 24,
VT_LIFE = 26,
VT_NUMBER = 28,
VT_D_R = 30,
VT_D_G = 32,
VT_D_B = 34,
VT_R = 36,
VT_G = 38,
VT_B = 40,
VT_ON = 42,
VT_SIZE = 44,
VT_ROT_ANG = 46
};
int32_t sprite_index() const {
return GetField<int32_t>(VT_SPRITE_INDEX, 0);
}
int32_t sprite_id() const {
return GetField<int32_t>(VT_SPRITE_ID, 0);
}
int32_t blend_mode() const {
return GetField<int32_t>(VT_BLEND_MODE, 0);
}
int32_t scalar() const {
return GetField<int32_t>(VT_SCALAR, 0);
}
const TEN::Save::Vector3 *position() const {
return GetStruct<const TEN::Save::Vector3 *>(VT_POSITION);
}
int32_t room_number() const {
return GetField<int32_t>(VT_ROOM_NUMBER, 0);
}
const TEN::Save::Vector3 *position_target() const {
return GetStruct<const TEN::Save::Vector3 *>(VT_POSITION_TARGET);
}
const TEN::Save::EulerAngles *orientation() const {
return GetStruct<const TEN::Save::EulerAngles *>(VT_ORIENTATION);
}
float velocity() const {
return GetField<float>(VT_VELOCITY, 0.0f);
}
int32_t target_item_number() const {
return GetField<int32_t>(VT_TARGET_ITEM_NUMBER, 0);
}
float z_vel() const {
return GetField<float>(VT_Z_VEL, 0.0f);
}
float life() const {
return GetField<float>(VT_LIFE, 0.0f);
}
int32_t number() const {
return GetField<int32_t>(VT_NUMBER, 0);
}
int32_t d_r() const {
return GetField<int32_t>(VT_D_R, 0);
}
int32_t d_g() const {
return GetField<int32_t>(VT_D_G, 0);
}
int32_t d_b() const {
return GetField<int32_t>(VT_D_B, 0);
}
int32_t r() const {
return GetField<int32_t>(VT_R, 0);
}
int32_t g() const {
return GetField<int32_t>(VT_G, 0);
}
int32_t b() const {
return GetField<int32_t>(VT_B, 0);
}
bool on() const {
return GetField<uint8_t>(VT_ON, 0) != 0;
}
float size() const {
return GetField<float>(VT_SIZE, 0.0f);
}
int32_t rot_Ang() const {
return GetField<int32_t>(VT_ROT_ANG, 0);
}
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyField<int32_t>(verifier, VT_SPRITE_INDEX) &&
VerifyField<int32_t>(verifier, VT_SPRITE_ID) &&
VerifyField<int32_t>(verifier, VT_BLEND_MODE) &&
VerifyField<int32_t>(verifier, VT_SCALAR) &&
VerifyField<TEN::Save::Vector3>(verifier, VT_POSITION) &&
VerifyField<int32_t>(verifier, VT_ROOM_NUMBER) &&
VerifyField<TEN::Save::Vector3>(verifier, VT_POSITION_TARGET) &&
VerifyField<TEN::Save::EulerAngles>(verifier, VT_ORIENTATION) &&
VerifyField<float>(verifier, VT_VELOCITY) &&
VerifyField<int32_t>(verifier, VT_TARGET_ITEM_NUMBER) &&
VerifyField<float>(verifier, VT_Z_VEL) &&
VerifyField<float>(verifier, VT_LIFE) &&
VerifyField<int32_t>(verifier, VT_NUMBER) &&
VerifyField<int32_t>(verifier, VT_D_R) &&
VerifyField<int32_t>(verifier, VT_D_G) &&
VerifyField<int32_t>(verifier, VT_D_B) &&
VerifyField<int32_t>(verifier, VT_R) &&
VerifyField<int32_t>(verifier, VT_G) &&
VerifyField<int32_t>(verifier, VT_B) &&
VerifyField<uint8_t>(verifier, VT_ON) &&
VerifyField<float>(verifier, VT_SIZE) &&
VerifyField<int32_t>(verifier, VT_ROT_ANG) &&
verifier.EndTable();
}
FireflyDataT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const;
void UnPackTo(FireflyDataT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const;
static flatbuffers::Offset<FireflyData> Pack(flatbuffers::FlatBufferBuilder &_fbb, const FireflyDataT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
};
struct FireflyDataBuilder {
typedef FireflyData Table;
flatbuffers::FlatBufferBuilder &fbb_;
flatbuffers::uoffset_t start_;
void add_sprite_index(int32_t sprite_index) {
fbb_.AddElement<int32_t>(FireflyData::VT_SPRITE_INDEX, sprite_index, 0);
}
void add_sprite_id(int32_t sprite_id) {
fbb_.AddElement<int32_t>(FireflyData::VT_SPRITE_ID, sprite_id, 0);
}
void add_blend_mode(int32_t blend_mode) {
fbb_.AddElement<int32_t>(FireflyData::VT_BLEND_MODE, blend_mode, 0);
}
void add_scalar(int32_t scalar) {
fbb_.AddElement<int32_t>(FireflyData::VT_SCALAR, scalar, 0);
}
void add_position(const TEN::Save::Vector3 *position) {
fbb_.AddStruct(FireflyData::VT_POSITION, position);
}
void add_room_number(int32_t room_number) {
fbb_.AddElement<int32_t>(FireflyData::VT_ROOM_NUMBER, room_number, 0);
}
void add_position_target(const TEN::Save::Vector3 *position_target) {
fbb_.AddStruct(FireflyData::VT_POSITION_TARGET, position_target);
}
void add_orientation(const TEN::Save::EulerAngles *orientation) {
fbb_.AddStruct(FireflyData::VT_ORIENTATION, orientation);
}
void add_velocity(float velocity) {
fbb_.AddElement<float>(FireflyData::VT_VELOCITY, velocity, 0.0f);
}
void add_target_item_number(int32_t target_item_number) {
fbb_.AddElement<int32_t>(FireflyData::VT_TARGET_ITEM_NUMBER, target_item_number, 0);
}
void add_z_vel(float z_vel) {
fbb_.AddElement<float>(FireflyData::VT_Z_VEL, z_vel, 0.0f);
}
void add_life(float life) {
fbb_.AddElement<float>(FireflyData::VT_LIFE, life, 0.0f);
}
void add_number(int32_t number) {
fbb_.AddElement<int32_t>(FireflyData::VT_NUMBER, number, 0);
}
void add_d_r(int32_t d_r) {
fbb_.AddElement<int32_t>(FireflyData::VT_D_R, d_r, 0);
}
void add_d_g(int32_t d_g) {
fbb_.AddElement<int32_t>(FireflyData::VT_D_G, d_g, 0);
}
void add_d_b(int32_t d_b) {
fbb_.AddElement<int32_t>(FireflyData::VT_D_B, d_b, 0);
}
void add_r(int32_t r) {
fbb_.AddElement<int32_t>(FireflyData::VT_R, r, 0);
}
void add_g(int32_t g) {
fbb_.AddElement<int32_t>(FireflyData::VT_G, g, 0);
}
void add_b(int32_t b) {
fbb_.AddElement<int32_t>(FireflyData::VT_B, b, 0);
}
void add_on(bool on) {
fbb_.AddElement<uint8_t>(FireflyData::VT_ON, static_cast<uint8_t>(on), 0);
}
void add_size(float size) {
fbb_.AddElement<float>(FireflyData::VT_SIZE, size, 0.0f);
}
void add_rot_Ang(int32_t rot_Ang) {
fbb_.AddElement<int32_t>(FireflyData::VT_ROT_ANG, rot_Ang, 0);
}
explicit FireflyDataBuilder(flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
flatbuffers::Offset<FireflyData> Finish() {
const auto end = fbb_.EndTable(start_);
auto o = flatbuffers::Offset<FireflyData>(end);
return o;
}
};
inline flatbuffers::Offset<FireflyData> CreateFireflyData(
flatbuffers::FlatBufferBuilder &_fbb,
int32_t sprite_index = 0,
int32_t sprite_id = 0,
int32_t blend_mode = 0,
int32_t scalar = 0,
const TEN::Save::Vector3 *position = 0,
int32_t room_number = 0,
const TEN::Save::Vector3 *position_target = 0,
const TEN::Save::EulerAngles *orientation = 0,
float velocity = 0.0f,
int32_t target_item_number = 0,
float z_vel = 0.0f,
float life = 0.0f,
int32_t number = 0,
int32_t d_r = 0,
int32_t d_g = 0,
int32_t d_b = 0,
int32_t r = 0,
int32_t g = 0,
int32_t b = 0,
bool on = false,
float size = 0.0f,
int32_t rot_Ang = 0) {
FireflyDataBuilder builder_(_fbb);
builder_.add_rot_Ang(rot_Ang);
builder_.add_size(size);
builder_.add_b(b);
builder_.add_g(g);
builder_.add_r(r);
builder_.add_d_b(d_b);
builder_.add_d_g(d_g);
builder_.add_d_r(d_r);
builder_.add_number(number);
builder_.add_life(life);
builder_.add_z_vel(z_vel);
builder_.add_target_item_number(target_item_number);
builder_.add_velocity(velocity);
builder_.add_orientation(orientation);
builder_.add_position_target(position_target);
builder_.add_room_number(room_number);
builder_.add_position(position);
builder_.add_scalar(scalar);
builder_.add_blend_mode(blend_mode);
builder_.add_sprite_id(sprite_id);
builder_.add_sprite_index(sprite_index);
builder_.add_on(on);
return builder_.Finish();
}
struct FireflyData::Traits {
using type = FireflyData;
static auto constexpr Create = CreateFireflyData;
};
flatbuffers::Offset<FireflyData> CreateFireflyData(flatbuffers::FlatBufferBuilder &_fbb, const FireflyDataT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
struct ScriptTableT : public flatbuffers::NativeTable { struct ScriptTableT : public flatbuffers::NativeTable {
typedef ScriptTable TableType; typedef ScriptTable TableType;
std::vector<TEN::Save::KeyValPair> keys_vals{}; std::vector<TEN::Save::KeyValPair> keys_vals{};
@ -8000,6 +8293,7 @@ struct SaveGameT : public flatbuffers::NativeTable {
int32_t next_item_active = 0; int32_t next_item_active = 0;
std::vector<int32_t> room_items{}; std::vector<int32_t> room_items{};
std::vector<std::unique_ptr<TEN::Save::FishDataT>> fish_swarm{}; std::vector<std::unique_ptr<TEN::Save::FishDataT>> fish_swarm{};
std::vector<std::unique_ptr<TEN::Save::FireflyDataT>> firefly_swarm{};
std::vector<std::unique_ptr<TEN::Save::FXInfoT>> fxinfos{}; std::vector<std::unique_ptr<TEN::Save::FXInfoT>> fxinfos{};
int32_t next_fx_free = 0; int32_t next_fx_free = 0;
int32_t next_fx_active = 0; int32_t next_fx_active = 0;
@ -8066,52 +8360,53 @@ struct SaveGame FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
VT_NEXT_ITEM_ACTIVE = 24, VT_NEXT_ITEM_ACTIVE = 24,
VT_ROOM_ITEMS = 26, VT_ROOM_ITEMS = 26,
VT_FISH_SWARM = 28, VT_FISH_SWARM = 28,
VT_FXINFOS = 30, VT_FIREFLY_SWARM = 30,
VT_NEXT_FX_FREE = 32, VT_FXINFOS = 32,
VT_NEXT_FX_ACTIVE = 34, VT_NEXT_FX_FREE = 34,
VT_FIXED_CAMERAS = 36, VT_NEXT_FX_ACTIVE = 36,
VT_SINKS = 38, VT_FIXED_CAMERAS = 38,
VT_STATIC_MESHES = 40, VT_SINKS = 40,
VT_FLYBY_CAMERAS = 42, VT_STATIC_MESHES = 42,
VT_PARTICLES = 44, VT_FLYBY_CAMERAS = 44,
VT_RATS = 46, VT_PARTICLES = 46,
VT_SPIDERS = 48, VT_RATS = 48,
VT_SCARABS = 50, VT_SPIDERS = 50,
VT_BATS = 52, VT_SCARABS = 52,
VT_FLIP_MAPS = 54, VT_BATS = 54,
VT_FLIP_STATS = 56, VT_FLIP_MAPS = 56,
VT_FLIP_EFFECT = 58, VT_FLIP_STATS = 58,
VT_FLIP_TIMER = 60, VT_FLIP_EFFECT = 60,
VT_FLIP_STATUS = 62, VT_FLIP_TIMER = 62,
VT_CURRENT_FOV = 64, VT_FLIP_STATUS = 64,
VT_LAST_INV_ITEM = 66, VT_CURRENT_FOV = 66,
VT_ACTION_QUEUE = 68, VT_LAST_INV_ITEM = 68,
VT_SOUNDTRACKS = 70, VT_ACTION_QUEUE = 70,
VT_CD_FLAGS = 72, VT_SOUNDTRACKS = 72,
VT_POSTPROCESS_MODE = 74, VT_CD_FLAGS = 74,
VT_POSTPROCESS_STRENGTH = 76, VT_POSTPROCESS_MODE = 76,
VT_POSTPROCESS_TINT = 78, VT_POSTPROCESS_STRENGTH = 78,
VT_ROPE = 80, VT_POSTPROCESS_TINT = 80,
VT_PENDULUM = 82, VT_ROPE = 82,
VT_ALTERNATE_PENDULUM = 84, VT_PENDULUM = 84,
VT_VOLUMES = 86, VT_ALTERNATE_PENDULUM = 86,
VT_GLOBAL_EVENT_SETS = 88, VT_VOLUMES = 88,
VT_VOLUME_EVENT_SETS = 90, VT_GLOBAL_EVENT_SETS = 90,
VT_SCRIPT_VARS = 92, VT_VOLUME_EVENT_SETS = 92,
VT_CALLBACKS_PRE_START = 94, VT_SCRIPT_VARS = 94,
VT_CALLBACKS_POST_START = 96, VT_CALLBACKS_PRE_START = 96,
VT_CALLBACKS_PRE_END = 98, VT_CALLBACKS_POST_START = 98,
VT_CALLBACKS_POST_END = 100, VT_CALLBACKS_PRE_END = 100,
VT_CALLBACKS_PRE_SAVE = 102, VT_CALLBACKS_POST_END = 102,
VT_CALLBACKS_POST_SAVE = 104, VT_CALLBACKS_PRE_SAVE = 104,
VT_CALLBACKS_PRE_LOAD = 106, VT_CALLBACKS_POST_SAVE = 106,
VT_CALLBACKS_POST_LOAD = 108, VT_CALLBACKS_PRE_LOAD = 108,
VT_CALLBACKS_PRE_LOOP = 110, VT_CALLBACKS_POST_LOAD = 110,
VT_CALLBACKS_POST_LOOP = 112, VT_CALLBACKS_PRE_LOOP = 112,
VT_CALLBACKS_PRE_USEITEM = 114, VT_CALLBACKS_POST_LOOP = 114,
VT_CALLBACKS_POST_USEITEM = 116, VT_CALLBACKS_PRE_USEITEM = 116,
VT_CALLBACKS_PRE_FREEZE = 118, VT_CALLBACKS_POST_USEITEM = 118,
VT_CALLBACKS_POST_FREEZE = 120 VT_CALLBACKS_PRE_FREEZE = 120,
VT_CALLBACKS_POST_FREEZE = 122
}; };
const TEN::Save::SaveGameHeader *header() const { const TEN::Save::SaveGameHeader *header() const {
return GetPointer<const TEN::Save::SaveGameHeader *>(VT_HEADER); return GetPointer<const TEN::Save::SaveGameHeader *>(VT_HEADER);
@ -8152,6 +8447,9 @@ struct SaveGame FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
const flatbuffers::Vector<flatbuffers::Offset<TEN::Save::FishData>> *fish_swarm() const { const flatbuffers::Vector<flatbuffers::Offset<TEN::Save::FishData>> *fish_swarm() const {
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<TEN::Save::FishData>> *>(VT_FISH_SWARM); return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<TEN::Save::FishData>> *>(VT_FISH_SWARM);
} }
const flatbuffers::Vector<flatbuffers::Offset<TEN::Save::FireflyData>> *firefly_swarm() const {
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<TEN::Save::FireflyData>> *>(VT_FIREFLY_SWARM);
}
const flatbuffers::Vector<flatbuffers::Offset<TEN::Save::FXInfo>> *fxinfos() const { const flatbuffers::Vector<flatbuffers::Offset<TEN::Save::FXInfo>> *fxinfos() const {
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<TEN::Save::FXInfo>> *>(VT_FXINFOS); return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<TEN::Save::FXInfo>> *>(VT_FXINFOS);
} }
@ -8318,6 +8616,9 @@ struct SaveGame FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
VerifyOffset(verifier, VT_FISH_SWARM) && VerifyOffset(verifier, VT_FISH_SWARM) &&
verifier.VerifyVector(fish_swarm()) && verifier.VerifyVector(fish_swarm()) &&
verifier.VerifyVectorOfTables(fish_swarm()) && verifier.VerifyVectorOfTables(fish_swarm()) &&
VerifyOffset(verifier, VT_FIREFLY_SWARM) &&
verifier.VerifyVector(firefly_swarm()) &&
verifier.VerifyVectorOfTables(firefly_swarm()) &&
VerifyOffset(verifier, VT_FXINFOS) && VerifyOffset(verifier, VT_FXINFOS) &&
verifier.VerifyVector(fxinfos()) && verifier.VerifyVector(fxinfos()) &&
verifier.VerifyVectorOfTables(fxinfos()) && verifier.VerifyVectorOfTables(fxinfos()) &&
@ -8478,6 +8779,9 @@ struct SaveGameBuilder {
void add_fish_swarm(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<TEN::Save::FishData>>> fish_swarm) { void add_fish_swarm(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<TEN::Save::FishData>>> fish_swarm) {
fbb_.AddOffset(SaveGame::VT_FISH_SWARM, fish_swarm); fbb_.AddOffset(SaveGame::VT_FISH_SWARM, fish_swarm);
} }
void add_firefly_swarm(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<TEN::Save::FireflyData>>> firefly_swarm) {
fbb_.AddOffset(SaveGame::VT_FIREFLY_SWARM, firefly_swarm);
}
void add_fxinfos(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<TEN::Save::FXInfo>>> fxinfos) { void add_fxinfos(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<TEN::Save::FXInfo>>> fxinfos) {
fbb_.AddOffset(SaveGame::VT_FXINFOS, fxinfos); fbb_.AddOffset(SaveGame::VT_FXINFOS, fxinfos);
} }
@ -8642,6 +8946,7 @@ inline flatbuffers::Offset<SaveGame> CreateSaveGame(
int32_t next_item_active = 0, int32_t next_item_active = 0,
flatbuffers::Offset<flatbuffers::Vector<int32_t>> room_items = 0, flatbuffers::Offset<flatbuffers::Vector<int32_t>> room_items = 0,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<TEN::Save::FishData>>> fish_swarm = 0, flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<TEN::Save::FishData>>> fish_swarm = 0,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<TEN::Save::FireflyData>>> firefly_swarm = 0,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<TEN::Save::FXInfo>>> fxinfos = 0, flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<TEN::Save::FXInfo>>> fxinfos = 0,
int32_t next_fx_free = 0, int32_t next_fx_free = 0,
int32_t next_fx_active = 0, int32_t next_fx_active = 0,
@ -8734,6 +9039,7 @@ inline flatbuffers::Offset<SaveGame> CreateSaveGame(
builder_.add_next_fx_active(next_fx_active); builder_.add_next_fx_active(next_fx_active);
builder_.add_next_fx_free(next_fx_free); builder_.add_next_fx_free(next_fx_free);
builder_.add_fxinfos(fxinfos); builder_.add_fxinfos(fxinfos);
builder_.add_firefly_swarm(firefly_swarm);
builder_.add_fish_swarm(fish_swarm); builder_.add_fish_swarm(fish_swarm);
builder_.add_room_items(room_items); builder_.add_room_items(room_items);
builder_.add_next_item_active(next_item_active); builder_.add_next_item_active(next_item_active);
@ -8771,6 +9077,7 @@ inline flatbuffers::Offset<SaveGame> CreateSaveGameDirect(
int32_t next_item_active = 0, int32_t next_item_active = 0,
const std::vector<int32_t> *room_items = nullptr, const std::vector<int32_t> *room_items = nullptr,
const std::vector<flatbuffers::Offset<TEN::Save::FishData>> *fish_swarm = nullptr, const std::vector<flatbuffers::Offset<TEN::Save::FishData>> *fish_swarm = nullptr,
const std::vector<flatbuffers::Offset<TEN::Save::FireflyData>> *firefly_swarm = nullptr,
const std::vector<flatbuffers::Offset<TEN::Save::FXInfo>> *fxinfos = nullptr, const std::vector<flatbuffers::Offset<TEN::Save::FXInfo>> *fxinfos = nullptr,
int32_t next_fx_free = 0, int32_t next_fx_free = 0,
int32_t next_fx_active = 0, int32_t next_fx_active = 0,
@ -8821,6 +9128,7 @@ inline flatbuffers::Offset<SaveGame> CreateSaveGameDirect(
auto items__ = items ? _fbb.CreateVector<flatbuffers::Offset<TEN::Save::Item>>(*items) : 0; auto items__ = items ? _fbb.CreateVector<flatbuffers::Offset<TEN::Save::Item>>(*items) : 0;
auto room_items__ = room_items ? _fbb.CreateVector<int32_t>(*room_items) : 0; auto room_items__ = room_items ? _fbb.CreateVector<int32_t>(*room_items) : 0;
auto fish_swarm__ = fish_swarm ? _fbb.CreateVector<flatbuffers::Offset<TEN::Save::FishData>>(*fish_swarm) : 0; auto fish_swarm__ = fish_swarm ? _fbb.CreateVector<flatbuffers::Offset<TEN::Save::FishData>>(*fish_swarm) : 0;
auto firefly_swarm__ = firefly_swarm ? _fbb.CreateVector<flatbuffers::Offset<TEN::Save::FireflyData>>(*firefly_swarm) : 0;
auto fxinfos__ = fxinfos ? _fbb.CreateVector<flatbuffers::Offset<TEN::Save::FXInfo>>(*fxinfos) : 0; auto fxinfos__ = fxinfos ? _fbb.CreateVector<flatbuffers::Offset<TEN::Save::FXInfo>>(*fxinfos) : 0;
auto fixed_cameras__ = fixed_cameras ? _fbb.CreateVector<flatbuffers::Offset<TEN::Save::FixedCamera>>(*fixed_cameras) : 0; auto fixed_cameras__ = fixed_cameras ? _fbb.CreateVector<flatbuffers::Offset<TEN::Save::FixedCamera>>(*fixed_cameras) : 0;
auto sinks__ = sinks ? _fbb.CreateVector<flatbuffers::Offset<TEN::Save::Sink>>(*sinks) : 0; auto sinks__ = sinks ? _fbb.CreateVector<flatbuffers::Offset<TEN::Save::Sink>>(*sinks) : 0;
@ -8868,6 +9176,7 @@ inline flatbuffers::Offset<SaveGame> CreateSaveGameDirect(
next_item_active, next_item_active,
room_items__, room_items__,
fish_swarm__, fish_swarm__,
firefly_swarm__,
fxinfos__, fxinfos__,
next_fx_free, next_fx_free,
next_fx_active, next_fx_active,
@ -10889,6 +11198,95 @@ inline flatbuffers::Offset<FishData> CreateFishData(flatbuffers::FlatBufferBuild
_velocity); _velocity);
} }
inline FireflyDataT *FireflyData::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
auto _o = std::make_unique<FireflyDataT>();
UnPackTo(_o.get(), _resolver);
return _o.release();
}
inline void FireflyData::UnPackTo(FireflyDataT *_o, const flatbuffers::resolver_function_t *_resolver) const {
(void)_o;
(void)_resolver;
{ auto _e = sprite_index(); _o->sprite_index = _e; }
{ auto _e = sprite_id(); _o->sprite_id = _e; }
{ auto _e = blend_mode(); _o->blend_mode = _e; }
{ auto _e = scalar(); _o->scalar = _e; }
{ auto _e = position(); if (_e) _o->position = std::unique_ptr<TEN::Save::Vector3>(new TEN::Save::Vector3(*_e)); }
{ auto _e = room_number(); _o->room_number = _e; }
{ auto _e = position_target(); if (_e) _o->position_target = std::unique_ptr<TEN::Save::Vector3>(new TEN::Save::Vector3(*_e)); }
{ auto _e = orientation(); if (_e) _o->orientation = std::unique_ptr<TEN::Save::EulerAngles>(new TEN::Save::EulerAngles(*_e)); }
{ auto _e = velocity(); _o->velocity = _e; }
{ auto _e = target_item_number(); _o->target_item_number = _e; }
{ auto _e = z_vel(); _o->z_vel = _e; }
{ auto _e = life(); _o->life = _e; }
{ auto _e = number(); _o->number = _e; }
{ auto _e = d_r(); _o->d_r = _e; }
{ auto _e = d_g(); _o->d_g = _e; }
{ auto _e = d_b(); _o->d_b = _e; }
{ auto _e = r(); _o->r = _e; }
{ auto _e = g(); _o->g = _e; }
{ auto _e = b(); _o->b = _e; }
{ auto _e = on(); _o->on = _e; }
{ auto _e = size(); _o->size = _e; }
{ auto _e = rot_Ang(); _o->rot_Ang = _e; }
}
inline flatbuffers::Offset<FireflyData> FireflyData::Pack(flatbuffers::FlatBufferBuilder &_fbb, const FireflyDataT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
return CreateFireflyData(_fbb, _o, _rehasher);
}
inline flatbuffers::Offset<FireflyData> CreateFireflyData(flatbuffers::FlatBufferBuilder &_fbb, const FireflyDataT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
(void)_rehasher;
(void)_o;
struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const FireflyDataT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
auto _sprite_index = _o->sprite_index;
auto _sprite_id = _o->sprite_id;
auto _blend_mode = _o->blend_mode;
auto _scalar = _o->scalar;
auto _position = _o->position ? _o->position.get() : 0;
auto _room_number = _o->room_number;
auto _position_target = _o->position_target ? _o->position_target.get() : 0;
auto _orientation = _o->orientation ? _o->orientation.get() : 0;
auto _velocity = _o->velocity;
auto _target_item_number = _o->target_item_number;
auto _z_vel = _o->z_vel;
auto _life = _o->life;
auto _number = _o->number;
auto _d_r = _o->d_r;
auto _d_g = _o->d_g;
auto _d_b = _o->d_b;
auto _r = _o->r;
auto _g = _o->g;
auto _b = _o->b;
auto _on = _o->on;
auto _size = _o->size;
auto _rot_Ang = _o->rot_Ang;
return TEN::Save::CreateFireflyData(
_fbb,
_sprite_index,
_sprite_id,
_blend_mode,
_scalar,
_position,
_room_number,
_position_target,
_orientation,
_velocity,
_target_item_number,
_z_vel,
_life,
_number,
_d_r,
_d_g,
_d_b,
_r,
_g,
_b,
_on,
_size,
_rot_Ang);
}
inline ScriptTableT *ScriptTable::UnPack(const flatbuffers::resolver_function_t *_resolver) const { inline ScriptTableT *ScriptTable::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
auto _o = std::make_unique<ScriptTableT>(); auto _o = std::make_unique<ScriptTableT>();
UnPackTo(_o.get(), _resolver); UnPackTo(_o.get(), _resolver);
@ -11323,6 +11721,7 @@ inline void SaveGame::UnPackTo(SaveGameT *_o, const flatbuffers::resolver_functi
{ auto _e = next_item_active(); _o->next_item_active = _e; } { auto _e = next_item_active(); _o->next_item_active = _e; }
{ auto _e = room_items(); if (_e) { _o->room_items.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->room_items[_i] = _e->Get(_i); } } } { auto _e = room_items(); if (_e) { _o->room_items.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->room_items[_i] = _e->Get(_i); } } }
{ auto _e = fish_swarm(); if (_e) { _o->fish_swarm.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->fish_swarm[_i] = std::unique_ptr<TEN::Save::FishDataT>(_e->Get(_i)->UnPack(_resolver)); } } } { auto _e = fish_swarm(); if (_e) { _o->fish_swarm.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->fish_swarm[_i] = std::unique_ptr<TEN::Save::FishDataT>(_e->Get(_i)->UnPack(_resolver)); } } }
{ auto _e = firefly_swarm(); if (_e) { _o->firefly_swarm.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->firefly_swarm[_i] = std::unique_ptr<TEN::Save::FireflyDataT>(_e->Get(_i)->UnPack(_resolver)); } } }
{ auto _e = fxinfos(); if (_e) { _o->fxinfos.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->fxinfos[_i] = std::unique_ptr<TEN::Save::FXInfoT>(_e->Get(_i)->UnPack(_resolver)); } } } { auto _e = fxinfos(); if (_e) { _o->fxinfos.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->fxinfos[_i] = std::unique_ptr<TEN::Save::FXInfoT>(_e->Get(_i)->UnPack(_resolver)); } } }
{ auto _e = next_fx_free(); _o->next_fx_free = _e; } { auto _e = next_fx_free(); _o->next_fx_free = _e; }
{ auto _e = next_fx_active(); _o->next_fx_active = _e; } { auto _e = next_fx_active(); _o->next_fx_active = _e; }
@ -11392,6 +11791,7 @@ inline flatbuffers::Offset<SaveGame> CreateSaveGame(flatbuffers::FlatBufferBuild
auto _next_item_active = _o->next_item_active; auto _next_item_active = _o->next_item_active;
auto _room_items = _fbb.CreateVector(_o->room_items); auto _room_items = _fbb.CreateVector(_o->room_items);
auto _fish_swarm = _fbb.CreateVector<flatbuffers::Offset<TEN::Save::FishData>> (_o->fish_swarm.size(), [](size_t i, _VectorArgs *__va) { return CreateFishData(*__va->__fbb, __va->__o->fish_swarm[i].get(), __va->__rehasher); }, &_va ); auto _fish_swarm = _fbb.CreateVector<flatbuffers::Offset<TEN::Save::FishData>> (_o->fish_swarm.size(), [](size_t i, _VectorArgs *__va) { return CreateFishData(*__va->__fbb, __va->__o->fish_swarm[i].get(), __va->__rehasher); }, &_va );
auto _firefly_swarm = _fbb.CreateVector<flatbuffers::Offset<TEN::Save::FireflyData>> (_o->firefly_swarm.size(), [](size_t i, _VectorArgs *__va) { return CreateFireflyData(*__va->__fbb, __va->__o->firefly_swarm[i].get(), __va->__rehasher); }, &_va );
auto _fxinfos = _fbb.CreateVector<flatbuffers::Offset<TEN::Save::FXInfo>> (_o->fxinfos.size(), [](size_t i, _VectorArgs *__va) { return CreateFXInfo(*__va->__fbb, __va->__o->fxinfos[i].get(), __va->__rehasher); }, &_va ); auto _fxinfos = _fbb.CreateVector<flatbuffers::Offset<TEN::Save::FXInfo>> (_o->fxinfos.size(), [](size_t i, _VectorArgs *__va) { return CreateFXInfo(*__va->__fbb, __va->__o->fxinfos[i].get(), __va->__rehasher); }, &_va );
auto _next_fx_free = _o->next_fx_free; auto _next_fx_free = _o->next_fx_free;
auto _next_fx_active = _o->next_fx_active; auto _next_fx_active = _o->next_fx_active;
@ -11453,6 +11853,7 @@ inline flatbuffers::Offset<SaveGame> CreateSaveGame(flatbuffers::FlatBufferBuild
_next_item_active, _next_item_active,
_room_items, _room_items,
_fish_swarm, _fish_swarm,
_firefly_swarm,
_fxinfos, _fxinfos,
_next_fx_free, _next_fx_free,
_next_fx_active, _next_fx_active,

View file

@ -499,6 +499,31 @@ table FishData {
velocity: float; velocity: float;
} }
table FireflyData {
sprite_index: int32;
sprite_id: int32;
blend_mode: int32;
scalar: int32;
position: Vector3;
room_number: int32;
position_target: Vector3;
orientation: EulerAngles;
velocity: float;
target_item_number: int32;
z_vel: float;
life: float;
number: int32;
d_r: int32;
d_g: int32;
d_b: int32;
r: int32;
g: int32;
b: int32;
on: bool;
size: float;
rot_Ang: int32;
}
struct KeyValPair { struct KeyValPair {
key: uint32; key: uint32;
val: uint32; val: uint32;
@ -602,6 +627,7 @@ table SaveGame {
next_item_active: int32; next_item_active: int32;
room_items: [int32]; room_items: [int32];
fish_swarm: [FishData]; fish_swarm: [FishData];
firefly_swarm: [FireflyData];
fxinfos: [FXInfo]; fxinfos: [FXInfo];
next_fx_free: int32; next_fx_free: int32;
next_fx_active: int32; next_fx_active: int32;

View file

@ -506,6 +506,7 @@ if not exist "%ScriptsDir%\Strings.lua" xcopy /Y "$(SolutionDir)Scripts\Strings.
<ClInclude Include="Objects\Effects\effect_objects.h" /> <ClInclude Include="Objects\Effects\effect_objects.h" />
<ClInclude Include="Objects\Effects\EmberEmitter.h" /> <ClInclude Include="Objects\Effects\EmberEmitter.h" />
<ClInclude Include="Objects\Effects\enemy_missile.h" /> <ClInclude Include="Objects\Effects\enemy_missile.h" />
<ClInclude Include="Objects\Effects\Fireflies.h" />
<ClInclude Include="Objects\Effects\flame_emitters.h" /> <ClInclude Include="Objects\Effects\flame_emitters.h" />
<ClInclude Include="Objects\Effects\LensFlare.h" /> <ClInclude Include="Objects\Effects\LensFlare.h" />
<ClInclude Include="Objects\Effects\tr4_locusts.h" /> <ClInclude Include="Objects\Effects\tr4_locusts.h" />
@ -1044,6 +1045,7 @@ if not exist "%ScriptsDir%\Strings.lua" xcopy /Y "$(SolutionDir)Scripts\Strings.
<ClCompile Include="Objects\Effects\effect_objects.cpp" /> <ClCompile Include="Objects\Effects\effect_objects.cpp" />
<ClCompile Include="Objects\Effects\EmberEmitter.cpp" /> <ClCompile Include="Objects\Effects\EmberEmitter.cpp" />
<ClCompile Include="Objects\Effects\enemy_missile.cpp" /> <ClCompile Include="Objects\Effects\enemy_missile.cpp" />
<ClCompile Include="Objects\Effects\Fireflies.cpp" />
<ClCompile Include="Objects\Effects\flame_emitters.cpp" /> <ClCompile Include="Objects\Effects\flame_emitters.cpp" />
<ClCompile Include="Objects\Effects\LensFlare.cpp" /> <ClCompile Include="Objects\Effects\LensFlare.cpp" />
<ClCompile Include="Objects\Effects\tr4_locusts.cpp" /> <ClCompile Include="Objects\Effects\tr4_locusts.cpp" />