Merge branch 'master' into Enemy-fix

This commit is contained in:
TokyoSU 2023-01-22 10:35:21 +01:00
commit 5d53e50f52
12 changed files with 471 additions and 160 deletions

View file

@ -2,6 +2,7 @@ Version 1.0.6
=============
* Fix major pathfinding bug which could have caused lots of issues with enemy behaviour.
* Fix potential random crashes due to incorrect rendering behaviour.
* Fix savegame crash for disabled enemies with partially set activation mask.
* Fix certain enemies not damaging Lara if binoculars or lasersight mode is active.
* Fix invisible Lara after starting a new game from title flyby with hidden Lara.
@ -13,6 +14,8 @@ Version 1.0.6
* Fix TR1 BIG_RAT which crashed the game when it was killed.
* Fix TR4 SKELETON spawn when used with OCB 3
* Fix TR4 SAS teleporting over the blocks he walks by.
* Fix enemy projectile effect colours.
* Restore original volumetric explosion effects.
* Add undead flag to TR4 sphinx to prevent it from becoming bugged after receiving a lot of damage.
* Add an option to activate Lua or node events from legacy triggers.
* Antitriggering an enemy will now cause it to vanish and pause.

View file

@ -1399,7 +1399,7 @@ void ExplodeProjectile(ItemInfo& item, const Vector3i& prevPos)
}
else
{
TriggerShockwave(&item.Pose, 48, 304, 96, 0, 96, 128, 24, 0, 0);
TriggerShockwave(&item.Pose, 48, 304, 96, 128, 96, 0, 24, 0, 0);
item.Pose.Position.y += CLICK(1.0f / 2);
TriggerExplosionSparks(prevPos.x, prevPos.y, prevPos.z, 3, -2, 0, item.RoomNumber);

View file

@ -160,6 +160,23 @@ Particle* GetFreeParticle()
return spark;
}
void SetSpriteSequence(Particle& particle, GAME_OBJECT_ID objectID)
{
if (particle.life <= 0)
{
particle.on = false;
ParticleDynamics[particle.dynamic].On = false;
}
float particleAge = particle.sLife - particle.life;
if (particleAge > particle.life )
return;
int numSprites = -Objects[objectID].nmeshes - 1;
float normalizedAge = particleAge / particle.life;
particle.spriteIndex = Objects[objectID].meshIndex + (int)round(Lerp(0.0f, numSprites, normalizedAge));
}
void UpdateSparks()
{
auto bounds = GameBoundingBox(LaraItem);
@ -169,8 +186,7 @@ void UpdateSparks()
LaraItem->Pose.Position.y + bounds.Y1,
LaraItem->Pose.Position.y + bounds.Y2,
LaraItem->Pose.Position.z + bounds.Z1,
LaraItem->Pose.Position.z + bounds.Z2
);
LaraItem->Pose.Position.z + bounds.Z2);
for (int i = 0; i < MAX_PARTICLES; i++)
{
@ -228,11 +244,19 @@ void UpdateSparks()
if (spark->sLife - spark->life == spark->extras >> 3 &&
spark->extras & 7)
{
int unk;
int explosionType;
if (spark->flags & SP_UNDERWEXP)
unk = 1;
{
explosionType = 1;
}
else if (spark->flags & SP_PLASMAEXP)
{
explosionType = 2;
}
else
unk = (spark->flags & SP_PLASMAEXP) >> 12;
{
explosionType = 0;
}
for (int j = 0; j < (spark->extras & 7); j++)
{
@ -241,13 +265,13 @@ void UpdateSparks()
spark->z,
(spark->extras & 7) - 1,
spark->dynamic,
unk,
(spark->extras & 7));
explosionType,
spark->roomNumber);
spark->dynamic = -1;
}
if (unk == 1)
if (explosionType == 1)
{
TriggerExplosionBubble(
spark->x,
@ -285,16 +309,17 @@ void UpdateSparks()
spark->z += Weather.Wind().z;
}
int dl = (spark->sLife - spark->life << 16) / spark->sLife;
int ds = dl * (spark->dSize - spark->sSize);
float alpha = (spark->sLife - spark->life) / (float)spark->sLife;
spark->size = Lerp(spark->sSize, spark->dSize, alpha);
int dl = ((spark->sLife - spark->life) * 65536) / spark->sLife;
spark->size = (spark->sSize + ((dl * (spark->dSize - spark->sSize)) / 65536));
if (spark->flags & SP_EXPLOSION)
SetSpriteSequence(*spark, ID_EXPLOSION_SPRITES);
if ((spark->flags & SP_FIRE && LaraItem->Effect.Type == EffectType::None) ||
(spark->flags & SP_DAMAGE) ||
(spark->flags & SP_POISON))
{
ds = spark->size * (spark->scalar / 2.0);
int ds = spark->size * (spark->scalar / 2.0);
if (spark->x + ds > DeadlyBounds.X1 && spark->x - ds < DeadlyBounds.X2)
{
@ -324,13 +349,14 @@ void UpdateSparks()
if (spark->on && spark->dynamic != -1)
{
auto* dynsp = &ParticleDynamics[spark->dynamic];
if (dynsp->Flags & 3)
{
int random = GetRandomControl();
byte x = spark->x + 16 * (random & 0xF);
byte y = spark->y + (random & 0xF0);
byte z = spark->z + ((random >> 4) & 0xF0);
int x = spark->x + 16 * (random & 0xF);
int y = spark->y + (random & 0xF0);
int z = spark->z + ((random >> 4) & 0xF0);
byte r, g, b;
@ -354,6 +380,7 @@ void UpdateSparks()
b = -8 * dl + 128;
g = -8 * dl - (random & 0x1F) + 255;
r = 32 * (4 - dl);
if (32 * (4 - dl) < 0)
r = 0;
}
@ -368,7 +395,7 @@ void UpdateSparks()
r = 255 - (dl << 6) - (random & 0x1F);
}
if (spark->flags & 0x2000)
if (spark->flags & SP_PLASMAEXP)
{
int falloff;
if (dynsp->Falloff <= 28)
@ -403,7 +430,8 @@ void TriggerCyborgSpark(int x, int y, int z, short xv, short yv, short zv)
int dx = LaraItem->Pose.Position.x - x;
int dz = LaraItem->Pose.Position.z - z;
if (dx >= -16384 && dx <= 16384 && dz >= -16384 && dz <= 16384)
if (dx >= -BLOCK(16) && dx <= BLOCK(16) &&
dz >= -BLOCK(16) && dz <= BLOCK(16))
{
auto* spark = GetFreeParticle();
@ -439,7 +467,164 @@ void TriggerCyborgSpark(int x, int y, int z, short xv, short yv, short zv)
void TriggerExplosionSparks(int x, int y, int z, int extraTrig, int dynamic, int uw, int roomNumber)
{
TriggerExplosion(Vector3(x, y, z), 512, true, false, true, roomNumber);
static constexpr auto rotationMax = 30;
static constexpr auto lifeMax = 44;
static const auto extrasTable = std::array<unsigned char, 4>{ 0, 4, 7, 10 };
int dx = LaraItem->Pose.Position.x - x;
int dz = LaraItem->Pose.Position.z - z;
int scalar = 1;
if (dx < -BLOCK(16) || dx > BLOCK(16) ||
dz < -BLOCK(16) || dz > BLOCK(16))
{
return;
}
if (roomNumber < 0)
{
roomNumber = -roomNumber;
scalar = 1;
}
auto& spark = *GetFreeParticle();
spark.on = true;
spark.sR = 255;
if (uw == 1)
{
spark.sG = (GetRandomControl() & 0x3F) + 128;
spark.sB = 32;
spark.dR = 192;
spark.dG = (GetRandomControl() & 0x1F) + 64;
spark.dB = 0;
spark.colFadeSpeed = 7;
spark.fadeToBlack = 8;
spark.life = (GetRandomControl() & 7) + 16;
spark.sLife = spark.life;
spark.roomNumber = roomNumber;
}
else
{
spark.sG = (GetRandomControl() & 0xF) + 32;
spark.sB = 0;
spark.dR = (GetRandomControl() & 0x3F) + 192;
spark.dG = (GetRandomControl() & 0x3F) + 128;
spark.dB = 32;
spark.colFadeSpeed = 8;
spark.fadeToBlack = 16;
spark.life = (GetRandomControl() & 7) + lifeMax;
spark.sLife = spark.life;
}
spark.extras = unsigned char(extraTrig | ((extrasTable[extraTrig] + (GetRandomControl() & 7) + 28) << 3));
spark.dynamic = (char)dynamic;
if (dynamic == -2)
{
int i = 0;
for (i = 0; i < 8; i++)
{
auto dynsp = &ParticleDynamics[i];
if (!dynsp->On)
{
dynsp->On = true;
dynsp->Falloff = 4;
if (uw == 1)
dynsp->Flags = 2;
else
dynsp->Flags = 1;
spark.dynamic = (char)i;
break;
}
}
if (i == 8)
spark.dynamic = -1;
}
spark.xVel = (GetRandomControl() & 0xFFF) - 2048;
spark.yVel = (GetRandomControl() & 0xFFF) - 2048;
spark.zVel = (GetRandomControl() & 0xFFF) - 2048;
if (dynamic != -2 || uw == 1)
{
spark.x = (GetRandomControl() & 0x1F) + x - 16;
spark.y = (GetRandomControl() & 0x1F) + y - 16;
spark.z = (GetRandomControl() & 0x1F) + z - 16;
}
else
{
spark.x = (GetRandomControl() & 0x1FF) + x - 256;
spark.y = (GetRandomControl() & 0x1FF) + y - 256;
spark.z = (GetRandomControl() & 0x1FF) + z - 256;
}
if (uw == 1)
{
spark.friction = 17;
}
else
spark.friction = 51;
if (GetRandomControl() & 1)
{
if (uw == 1)
spark.flags = SP_SCALE | SP_DEF | SP_ROTATE | SP_EXPDEF | SP_UNDERWEXP;
else
spark.flags = SP_SCALE | SP_DEF | SP_ROTATE | SP_EXPDEF | SP_EXPLOSION;
spark.rotAng = GetRandomControl() & 0xF;
spark.rotAdd = (GetRandomControl() & 0xF) + rotationMax;
}
else if (uw == 1)
{
spark.flags = SP_SCALE | SP_DEF | SP_EXPDEF | SP_UNDERWEXP;
}
else
{
spark.flags = SP_SCALE | SP_DEF | SP_EXPDEF | SP_EXPLOSION;
}
spark.scalar = 3;
spark.gravity = 0;
spark.size = (GetRandomControl() & 0xF) + 40;
spark.sSize = spark.size * scalar;
spark.dSize = spark.size * (scalar + 1);
spark.size *= scalar;
GetRandomControl();
spark.maxYvel = 0;
if (uw == 2)
{
unsigned char r = spark.sR;
unsigned char g = spark.sG;
unsigned char b = spark.sB;
spark.sR = b;
spark.sG = r;
spark.sB = g;
r = spark.dR;
g = spark.dG;
b = spark.dB;
spark.dR = b;
spark.dG = r;
spark.dB = g;
spark.flags |= SP_PLASMAEXP;
}
else if (extraTrig)
{
TriggerExplosionSmoke(x, y, z, uw);
}
else
{
TriggerExplosionSmokeEnd(x, y, z, uw);
}
}
void TriggerExplosionBubbles(int x, int y, int z, short roomNumber)
@ -447,7 +632,8 @@ void TriggerExplosionBubbles(int x, int y, int z, short roomNumber)
int dx = LaraItem->Pose.Position.x - x;
int dz = LaraItem->Pose.Position.z - z;
if (dx >= -ANGLE(90.0f) && dx <= ANGLE(90.0f) && dz >= -ANGLE(90.0f) && dz <= ANGLE(90.0f))
if (dx >= -BLOCK(16) && dx <= BLOCK(16) &&
dz >= -BLOCK(16) && dz <= BLOCK(16))
{
auto* spark = GetFreeParticle();
@ -573,7 +759,8 @@ void TriggerExplosionSmoke(int x, int y, int z, int uw)
int dx = LaraItem->Pose.Position.x - x;
int dz = LaraItem->Pose.Position.z - z;
if (dx >= -16384 && dx <= 16384 && dz >= -16384 && dz <= 16384)
if (dx >= -BLOCK(16) && dx <= BLOCK(16) &&
dz >= -BLOCK(16) && dz <= BLOCK(16))
{
auto* spark = GetFreeParticle();
@ -617,7 +804,8 @@ void TriggerSuperJetFlame(ItemInfo* item, int yvel, int deadly)
long dx = LaraItem->Pose.Position.x - item->Pose.Position.x;
long dz = LaraItem->Pose.Position.z - item->Pose.Position.z;
if (dx >= -16384 && dx <= 16384 && dz >= -16384 && dz <= 16384)
if (dx >= -BLOCK(16) && dx <= BLOCK(16) &&
dz >= -BLOCK(16) && dz <= BLOCK(16))
{
int size = (GetRandomControl() & 0x1FF) - yvel;
auto* sptr = GetFreeParticle();
@ -666,14 +854,22 @@ void TriggerSuperJetFlame(ItemInfo* item, int yvel, int deadly)
sptr->zVel = (GetRandomControl() & 0xFF) - 128;
if (item->Pose.Orientation.y == 0)
{
sptr->zVel = -(size - (size >> 2));
}
else if (item->Pose.Orientation.y == ANGLE(90.0f))
{
sptr->xVel = -(size - (size >> 2));
else if (item->Pose.Orientation.y == -ANGLE(180.0f))
}
else if (item->Pose.Orientation.y == ANGLE(-180.0f))
{
sptr->zVel = size - (size >> 2);
}
else
{
sptr->xVel = size - (size >> 2);
}
}
}
void SetupSplash(const SPLASH_SETUP* const setup, int room)
@ -685,6 +881,7 @@ void SetupSplash(const SPLASH_SETUP* const setup, int room)
for (int i = 0; i < MAX_SPLASHES; i++)
{
SPLASH_STRUCT& splash = Splashes[i];
if (!splash.isActive)
{
if (numSplashesSetup == 0)
@ -703,8 +900,8 @@ void SetupSplash(const SPLASH_SETUP* const setup, int room)
splash.height = 0;
splash.heightVel = -16;
splash.outerRad = setup->innerRadius / 3;
splash.outerRadVel = splashVelocity*1.5f;
splash.spriteSequenceStart = 8; //Splash Texture
splash.outerRadVel = splashVelocity * 1.5f;
splash.spriteSequenceStart = 8; // Splash texture.
numSplashesSetup++;
}
else
@ -734,12 +931,13 @@ void SetupSplash(const SPLASH_SETUP* const setup, int room)
float t = vel / (splashVelocity / 2) + 16;
t = fmax(0, fmin(t, 1));
splash.life = Lerp(48.0f, 70.0f, t);
splash.spriteSequenceStart = 4; //Splash Texture
splash.spriteSequenceEnd = 7; //Splash Texture
splash.spriteSequenceStart = 4; // Splash texture.
splash.spriteSequenceEnd = 7; // Splash texture.
splash.animationSpeed = fmin(0.6f,(1 / splash.outerRadVel)*2);
numSplashesSetup++;
}
if (numSplashesSetup == NUM_SPLASHES)
break;

View file

@ -3,8 +3,9 @@
#include "Renderer/Renderer11Enums.h"
enum class LaraWeaponType;
struct ItemInfo;
enum GAME_OBJECT_ID : short;
struct CollisionInfo;
struct ItemInfo;
enum RIPPLE_TYPE
{
@ -198,6 +199,8 @@ extern FX_INFO EffectList[NUM_EFFECTS];
Particle* GetFreeParticle();
void SetSpriteSequence(Particle& particle, GAME_OBJECT_ID objectID);
void DetatchSpark(int num, SpriteEnumFlag type);
void UpdateSparks();
void TriggerRicochetSpark(const GameVector& pos, short angle, int count, int unk);

View file

@ -22,15 +22,26 @@ using namespace TEN::Math;
namespace TEN::Entities::Effects
{
void TriggerSethMissileFlame(short fxNum, short xVel, short yVel, short zVel)
enum class MissileType
{
auto* fx = &EffectList[fxNum];
SethNormal = 0,
SethLarge = 1,
Harpy = 2,
Demigod3Single = 3,
Demigod3Radial = 4,
Demigod2 = 5,
Mutant = 6
};
void TriggerSethMissileFlame(short fxNumber, short xVel, short yVel, short zVel)
{
auto* fx = &EffectList[fxNumber];
int dx = LaraItem->Pose.Position.x - fx->pos.Position.x;
int dz = LaraItem->Pose.Position.z - fx->pos.Position.z;
if (dx >= -SECTOR(16) && dx <= SECTOR(16) &&
dz >= -SECTOR(16) && dz <= SECTOR(16))
if (dx >= -BLOCK(16) && dx <= BLOCK(16) &&
dz >= -BLOCK(16) && dz <= BLOCK(16))
{
auto* spark = GetFreeParticle();
@ -62,7 +73,7 @@ namespace TEN::Entities::Effects
spark->gravity = 0;
spark->maxYvel = 0;
spark->fxObj = fxNum;
spark->fxObj = fxNumber;
if (fx->flag1 == 1)
spark->scalar = 3;
@ -81,7 +92,8 @@ namespace TEN::Entities::Effects
int dx = LaraItem->Pose.Position.x - fx->pos.Position.x;
int dz = LaraItem->Pose.Position.z - fx->pos.Position.z;
if (dx >= -16384 && dx <= 16384 && dz >= -16384 && dz <= 16384)
if (dx >= -BLOCK(16) && dx <= BLOCK(16) &&
dz >= -BLOCK(16) && dz <= BLOCK(16))
{
auto* spark = GetFreeParticle();
@ -143,14 +155,14 @@ namespace TEN::Entities::Effects
int maxRotation = 0;
int maxVelocity = 0;
if (fx->flag1 == 1)
if (fx->flag1 == (int)MissileType::SethLarge)
{
maxRotation = ANGLE(2.8f);
maxVelocity = CLICK(1);
}
else
{
if (fx->flag1 == 6)
if (fx->flag1 == (int)MissileType::Mutant)
{
if (fx->counter)
fx->counter--;
@ -158,14 +170,16 @@ namespace TEN::Entities::Effects
maxRotation = ANGLE(1.4f);
}
else
{
maxRotation = ANGLE(4.5f);
}
maxVelocity = CLICK(0.75f);
}
if (fx->speed < maxVelocity)
{
if (fx->flag1 == 6)
if (fx->flag1 == (int)MissileType::Mutant)
fx->speed++;
else
fx->speed += 3;
@ -182,24 +196,31 @@ namespace TEN::Entities::Effects
dx >>= 3;
if (dy < -maxRotation)
{
dy = -maxRotation;
}
else if (dy > maxRotation)
{
dy = maxRotation;
}
if (dx < -maxRotation)
{
dx = -maxRotation;
}
else if (dx > maxRotation)
{
dx = maxRotation;
}
fx->pos.Orientation.x += dx;
if (fx->flag1 != 4 && (fx->flag1 != 6 || !fx->counter))
if (fx->flag1 != (int)MissileType::Demigod3Radial && (fx->flag1 != (int)MissileType::Mutant || !fx->counter))
fx->pos.Orientation.y += dy;
}
fx->pos.Orientation.z += 16 * fx->speed;
if (fx->flag1 == 6)
if (fx->flag1 == (int)MissileType::Mutant)
fx->pos.Orientation.z += 16 * fx->speed;
int oldX = fx->pos.Position.x;
@ -219,10 +240,10 @@ namespace TEN::Entities::Effects
fx->pos.Position.y = oldY;
fx->pos.Position.z = oldZ;
if (fx->flag1 != 6)
if (fx->flag1 != (int)MissileType::Mutant)
BubblesShatterFunction(fx, 0, -32);
if (fx->flag1 == 1)
if (fx->flag1 == (int)MissileType::SethLarge)
{
TriggerShockwave(&fx->pos, 32, 160, 64, 64, 128, 00, 24, (((~g_Level.Rooms[fx->roomNumber].flags) / 16) & 2) * 65536, 0);
TriggerExplosionSparks(oldX, oldY, oldZ, 3, -2, 2, fx->roomNumber);
@ -231,31 +252,39 @@ namespace TEN::Entities::Effects
{
if (fx->flag1)
{
if (fx->flag1 == 3 || fx->flag1 == 4)
TriggerShockwave(&fx->pos, 32, 160, 64, 128, 64, 0, 16, 0, 0);
else if (fx->flag1 == 5)
if (fx->flag1 == (int)MissileType::Demigod3Single || fx->flag1 == (int)MissileType::Demigod3Radial)
{
TriggerShockwave(&fx->pos, 32, 160, 64, 0, 96, 128, 16, 0, 0);
}
else if (fx->flag1 == (int)MissileType::Demigod2)
{
TriggerShockwave(&fx->pos, 32, 160, 64, 128, 64, 0, 16, 0, 0);
}
else
{
if (fx->flag1 != 2)
if (fx->flag1 != (int)MissileType::Harpy)
{
if (fx->flag1 == 6)
if (fx->flag1 == (int)MissileType::Mutant)
{
TriggerExplosionSparks(oldX, oldY, oldZ, 3, -2, 0, fx->roomNumber);
TriggerShockwave(&fx->pos, 48, 240, 64, 0, 96, 128, 24, 0, 15);
TriggerShockwave(&fx->pos, 48, 240, 64, 128, 96, 0, 24, 0, 15);
fx->pos.Position.y -= 128;
TriggerShockwave(&fx->pos, 48, 240, 48, 0, 112, 128, 16, 0, 15);
TriggerShockwave(&fx->pos, 48, 240, 48, 128, 112, 0, 16, 0, 15);
fx->pos.Position.y += 256;
TriggerShockwave(&fx->pos, 48, 240, 48, 0, 112, 128, 16, 0, 15);
TriggerShockwave(&fx->pos, 48, 240, 48, 128, 112, 0, 16, 0, 15);
}
}
else
TriggerShockwave(&fx->pos, 32, 160, 64, 0, 128, 128, 16, 0, 0);
{
TriggerShockwave(&fx->pos, 32, 160, 64, 128, 128, 0, 16, 0, 0);
}
}
}
else
TriggerShockwave(&fx->pos, 32, 160, 64, 64, 128, 0, 16, 0, 0);
{
TriggerShockwave(&fx->pos, 32, 160, 64, 0, 128, 64, 16, 0, 0);
}
}
KillEffect(fxNum);
@ -265,14 +294,14 @@ namespace TEN::Entities::Effects
if (ItemNearLara(fx->pos.Position, 200))
{
LaraItem->HitStatus = true;
if (fx->flag1 != 6)
if (fx->flag1 != (int)MissileType::Mutant)
BubblesShatterFunction(fx, 0, -32);
KillEffect(fxNum);
if (fx->flag1 == 1)
if (fx->flag1 == (int)MissileType::SethLarge)
{
TriggerShockwave(&fx->pos, 48, 240, 64, 64, 128, 0, 24, 0, 0);
TriggerShockwave(&fx->pos, 48, 240, 64, 0, 128, 64, 24, 0, 0);
TriggerExplosionSparks(oldX, oldY, oldZ, 3, -2, 2, fx->roomNumber);
ItemCustomBurn(LaraItem, Vector3(0.0f, 0.8f, 0.1f), Vector3(0.0f, 0.9f, 0.8f));
}
@ -280,32 +309,34 @@ namespace TEN::Entities::Effects
{
switch (fx->flag1)
{
case 3:
case 4:
TriggerShockwave(&fx->pos, 32, 160, 64, 128, 64, 0, 16, 0, 10);
case (int)MissileType::Demigod3Single:
case (int)MissileType::Demigod3Radial:
TriggerShockwave(&fx->pos, 32, 160, 64, 0, 96, 128, 16, 0, 10);
break;
case 5:
TriggerShockwave(&fx->pos, 32, 160, 64, 0, 96, 128, 16, 0, 5);
case (int)MissileType::Demigod2:
TriggerShockwave(&fx->pos, 32, 160, 64, 128, 64, 0, 16, 0, 5);
break;
case 2:
TriggerShockwave(&fx->pos, 32, 160, 64, 0, 128, 128, 16, 0, 3);
case (int)MissileType::Harpy:
TriggerShockwave(&fx->pos, 32, 160, 64, 128, 128, 0, 16, 0, 3);
break;
case 6:
case (int)MissileType::Mutant:
TriggerExplosionSparks(oldX, oldY, oldZ, 3, -2, 0, fx->roomNumber);
TriggerShockwave(&fx->pos, 48, 240, 64, 0, 96, 128, 24, 0, 0);
TriggerShockwave(&fx->pos, 48, 240, 64, 128, 96, 0, 24, 0, 0);
fx->pos.Position.y -= 128;
TriggerShockwave(&fx->pos, 48, 240, 48, 0, 112, 128, 16, 0, 0);
TriggerShockwave(&fx->pos, 48, 240, 48, 128, 112, 0, 16, 0, 0);
fx->pos.Position.y += 256;
TriggerShockwave(&fx->pos, 48, 240, 48, 0, 112, 128, 16, 0, 0);
TriggerShockwave(&fx->pos, 48, 240, 48, 128, 112, 0, 16, 0, 0);
ItemBurn(LaraItem);
break;
}
}
else
TriggerShockwave(&fx->pos, 24, 88, 48, 64, 128, 0, 16, (((~g_Level.Rooms[fx->roomNumber].flags) / 16) & 2) * 65536, 1);
{
TriggerShockwave(&fx->pos, 24, 88, 48, 0, 128, 64, 16, (((~g_Level.Rooms[fx->roomNumber].flags) / 16) & 2) * 65536, 1);
}
}
else
{
@ -321,21 +352,21 @@ namespace TEN::Entities::Effects
switch (fx->flag1)
{
default:
case 1:
case (int)MissileType::SethLarge:
TriggerSethMissileFlame(fxNum, 32 * dx, 32 * dy, 32 * dz);
break;
case 2:
case (int)MissileType::Harpy:
TriggerHarpyFlameFlame(fxNum, 16 * dx, 16 * dy, 16 * dz);
break;
case 3:
case 4:
case 5:
case (int)MissileType::Demigod3Single:
case (int)MissileType::Demigod3Radial:
case (int)MissileType::Demigod2:
TriggerDemigodMissileFlame(fxNum, 16 * dx, 16 * dy, 16 * dz);
break;
case 6:
case (int)MissileType::Mutant:
TriggerCrocgodMissileFlame(fxNum, 16 * dx, 16 * dy, 16 * dz);
break;
}

View file

@ -87,17 +87,17 @@ namespace TEN::Entities::Creatures::TR1
if (item->IsCreature())
{
auto* creature = GetCreatureInfo(item);
auto& creature = *GetCreatureInfo(item);
if (waterDepth != NO_HEIGHT)
{
creature->LOT.Step = BLOCK(20);
creature->LOT.Drop = -BLOCK(20);
creature.LOT.Step = BLOCK(20);
creature.LOT.Drop = -BLOCK(20);
}
else
{
creature->LOT.Step = CLICK(1);
creature->LOT.Drop = -CLICK(1);
creature.LOT.Step = CLICK(1);
creature.LOT.Drop = -CLICK(1);
}
}
@ -132,14 +132,14 @@ namespace TEN::Entities::Creatures::TR1
}
else
{
AI_INFO AI;
CreatureAIInfo(item, &AI);
AI_INFO ai;
CreatureAIInfo(item, &ai);
if (AI.ahead)
head = AI.angle;
if (ai.ahead)
head = ai.angle;
GetCreatureMood(item, &AI, false);
CreatureMood(item, &AI, false);
GetCreatureMood(item, &ai, false);
CreatureMood(item, &ai, false);
angle = CreatureTurn(item, creature->MaxTurn);
switch (item->Animation.ActiveState)
@ -147,7 +147,7 @@ namespace TEN::Entities::Creatures::TR1
case BIG_RAT_STATE_IDLE:
if (item->Animation.RequiredState)
item->Animation.TargetState = item->Animation.RequiredState;
else if (AI.bite && AI.distance < BIG_RAT_LAND_BITE_ATTACK_RANGE)
else if (ai.bite && ai.distance < BIG_RAT_LAND_BITE_ATTACK_RANGE)
item->Animation.TargetState = BIG_RAT_STATE_LAND_BITE_ATTACK;
else
item->Animation.TargetState = BIG_RAT_STATE_RUN_FORWARD;
@ -163,15 +163,15 @@ namespace TEN::Entities::Creatures::TR1
break;
}
if (AI.ahead && item->TouchBits.Test(BigRatBite.meshNum))
if (ai.ahead && item->TouchBits.Test(BigRatBite.meshNum))
{
item->Animation.TargetState = BIG_RAT_STATE_IDLE;
}
else if (AI.bite && AI.distance < BIG_RAT_POUNCE_ATTACK_RANGE)
else if (ai.bite && ai.distance < BIG_RAT_POUNCE_ATTACK_RANGE)
{
item->Animation.TargetState = BIG_RAT_STATE_POUNCE_ATTACK;
}
else if (AI.ahead && Random::TestProbability(BIG_RAT_REAR_POSE_CHANCE))
else if (ai.ahead && Random::TestProbability(BIG_RAT_REAR_POSE_CHANCE))
{
item->Animation.TargetState = BIG_RAT_STATE_IDLE;
item->Animation.RequiredState = BIG_RAT_STATE_REAR_POSE;
@ -180,7 +180,7 @@ namespace TEN::Entities::Creatures::TR1
break;
case BIG_RAT_STATE_LAND_BITE_ATTACK:
if (!item->Animation.RequiredState && AI.ahead &&
if (!item->Animation.RequiredState && ai.ahead &&
item->TouchBits.Test(BigRatBite.meshNum))
{
DoDamage(creature->Enemy, BIG_RAT_BITE_ATTACK_DAMAGE);
@ -191,7 +191,7 @@ namespace TEN::Entities::Creatures::TR1
break;
case BIG_RAT_STATE_POUNCE_ATTACK:
if (!item->Animation.RequiredState && AI.ahead &&
if (!item->Animation.RequiredState && ai.ahead &&
item->TouchBits.Test(BigRatBite.meshNum))
{
DoDamage(creature->Enemy, BIG_RAT_POUNCE_ATTACK_DAMAGE);
@ -216,13 +216,13 @@ namespace TEN::Entities::Creatures::TR1
break;
}
if (AI.ahead && item->TouchBits.Test(BigRatBite.meshNum))
if (ai.ahead && item->TouchBits.Test(BigRatBite.meshNum))
item->Animation.TargetState = BIG_RAT_STATE_SWIM_BITE_ATTACK;
break;
case BIG_RAT_STATE_SWIM_BITE_ATTACK:
if (!item->Animation.RequiredState && AI.ahead &&
if (!item->Animation.RequiredState && ai.ahead &&
item->TouchBits.Test(BigRatBite.meshNum))
{
DoDamage(creature->Enemy, BIG_RAT_BITE_ATTACK_DAMAGE);

View file

@ -1067,7 +1067,8 @@ namespace TEN::Entities::Vehicles
if (spark->sLife < 9)
spark->sLife = spark->life = 9;
spark->blendMode = BLEND_MODES::BLENDMODE_SCREEN;
// TODO: Switch back to screen blend mode once rendering for it is refactored. -- Sezz 2023.01.14
spark->blendMode = BLEND_MODES::BLENDMODE_ADDITIVE;
spark->colFadeSpeed = 4;
spark->fadeToBlack = 4;
spark->extras = 0;

View file

@ -23,6 +23,12 @@ using namespace TEN::Math::Random;
namespace TEN::Entities::TR4
{
constexpr auto DEMIGOD_IDLE_RANGE = SQUARE(BLOCK(2));
constexpr auto DEMIGOD_WALK_RANGE = SQUARE(BLOCK(3));
constexpr auto DEMIGOD1_WALK_RANGE = SQUARE(BLOCK(3));
constexpr auto DEMIGOD2_RADIAL_PROJECTILE_ATTACK_RANGE = SQUARE(BLOCK(5));
constexpr auto DEMIGOD3_RADIAL_PROJECTILE_ATTACK_RANGE = SQUARE(BLOCK(5));
enum DemigodState
{
DEMIGOD_STATE_IDLE = 0,
@ -122,8 +128,8 @@ namespace TEN::Entities::TR4
int dx = LaraItem->Pose.Position.x - fx->pos.Position.x;
int dz = LaraItem->Pose.Position.z - fx->pos.Position.z;
if (dx >= -SECTOR(16) && dx <= SECTOR(16) &&
dz >= -SECTOR(16) && dz <= SECTOR(16))
if (dx >= -BLOCK(16) && dx <= BLOCK(16) &&
dz >= -BLOCK(16) && dz <= BLOCK(16))
{
auto* spark = GetFreeParticle();
@ -200,7 +206,7 @@ namespace TEN::Entities::TR4
fx->flag1 = flags;
fx->speed = (GetRandomControl() & 0x1F) + 96;
fx->objectNumber = ID_ENERGY_BUBBLES;
fx->frameNumber = Objects[ID_ENERGY_BUBBLES].meshIndex + (flags >= 4, flags - 1, flags);
fx->frameNumber = Objects[ID_ENERGY_BUBBLES].meshIndex + ((flags >= 4) ? flags - 1 : flags);
}
}
@ -436,7 +442,7 @@ namespace TEN::Entities::TR4
if (item->ObjectNumber == ID_DEMIGOD1)
{
if (AI.distance >= pow(SECTOR(3), 2))
if (AI.distance >= DEMIGOD1_WALK_RANGE)
{
item->Animation.TargetState = DEMIGOD_STATE_WALK_FORWARD;
break;
@ -451,7 +457,7 @@ namespace TEN::Entities::TR4
break;
}
if (AI.distance <= pow(SECTOR(3), 2))
if (AI.distance <= DEMIGOD1_WALK_RANGE)
{
item->Animation.TargetState = DEMIGOD_STATE_WALK_FORWARD;
break;
@ -471,15 +477,15 @@ namespace TEN::Entities::TR4
break;
}
if (AI.distance <= pow(SECTOR(2), 2) ||
AI.distance >= pow(SECTOR(5), 2))
if (item->ObjectNumber == ID_DEMIGOD3)
{
if (AI.distance <= DEMIGOD_IDLE_RANGE ||
AI.distance >= DEMIGOD3_RADIAL_PROJECTILE_ATTACK_RANGE)
{
item->Animation.TargetState = DEMIGOD_STATE_WALK_FORWARD;
break;
}
if (item->ObjectNumber == ID_DEMIGOD3)
{
if (TestProbability(0.25f))
{
item->Animation.TargetState = DEMIGOD3_STATE_RADIAL_AIM;
@ -488,13 +494,17 @@ namespace TEN::Entities::TR4
}
}
item->Animation.TargetState = DEMIGOD2_STATE_RADIAL_PROJECTILE_ATTACK;
if (AI.distance > DEMIGOD_WALK_RANGE && item->ObjectNumber == ID_DEMIGOD2)
item->Animation.TargetState = DEMIGOD2_STATE_RADIAL_AIM;
else
item->Animation.TargetState = DEMIGOD_STATE_WALK_FORWARD;
break;
case DEMIGOD_STATE_WALK_FORWARD:
creature->MaxTurn = ANGLE(7.0f);
if (AI.distance < pow(SECTOR(2), 2))
if (AI.distance < DEMIGOD_IDLE_RANGE)
{
item->Animation.TargetState = DEMIGOD_STATE_IDLE;
break;
@ -502,7 +512,7 @@ namespace TEN::Entities::TR4
if (item->ObjectNumber == ID_DEMIGOD1)
{
if (AI.distance < pow(SECTOR(3), 2))
if (AI.distance < DEMIGOD1_WALK_RANGE)
{
item->Animation.TargetState = DEMIGOD_STATE_IDLE;
break;
@ -517,7 +527,7 @@ namespace TEN::Entities::TR4
}
}
if (AI.distance > pow(SECTOR(3), 2))
if (AI.distance > DEMIGOD_WALK_RANGE)
{
if (item->ObjectNumber == ID_DEMIGOD2)
item->Animation.TargetState = DEMIGOD2_STATE_RADIAL_PROJECTILE_ATTACK;
@ -530,7 +540,7 @@ namespace TEN::Entities::TR4
case DEMIGOD_STATE_RUN_FORWARD:
creature->MaxTurn = ANGLE(7.0f);
if (AI.distance < pow(SECTOR(2), 2))
if (AI.distance < DEMIGOD_IDLE_RANGE)
{
item->Animation.TargetState = DEMIGOD_STATE_IDLE;
break;
@ -538,7 +548,7 @@ namespace TEN::Entities::TR4
if (item->ObjectNumber == ID_DEMIGOD1)
{
if (AI.distance < pow(SECTOR(3), 2))
if (AI.distance < DEMIGOD1_WALK_RANGE)
{
item->Animation.TargetState = DEMIGOD_STATE_IDLE;
break;
@ -546,13 +556,13 @@ namespace TEN::Entities::TR4
}
else
{
if (Targetable(item, &AI) || item->ObjectNumber == ID_DEMIGOD3 && AI.distance > pow(SECTOR(2), 2))
if (Targetable(item, &AI) || item->ObjectNumber == ID_DEMIGOD3 && AI.distance > DEMIGOD_IDLE_RANGE)
{
item->Animation.TargetState = DEMIGOD_STATE_IDLE;
break;
}
if (AI.distance < pow(SECTOR(3), 2))
if (AI.distance < DEMIGOD_WALK_RANGE)
item->Animation.TargetState = DEMIGOD_STATE_WALK_FORWARD;
}
@ -602,17 +612,25 @@ namespace TEN::Entities::TR4
case DEMIGOD3_STATE_RADIAL_AIM:
creature->MaxTurn = ANGLE(7.0f);
if (!Targetable(item, &AI) && AI.distance < pow(SECTOR(5), 2))
if (!Targetable(item, &AI) && AI.distance < DEMIGOD3_RADIAL_PROJECTILE_ATTACK_RANGE)
item->Animation.TargetState = DEMIGOD3_STATE_RADIAL_PROJECTILE_ATTACK;
break;
case DEMIGOD2_STATE_RADIAL_AIM:
creature->MaxTurn = ANGLE(7.0f);
if (!Targetable(item, &AI) && AI.distance < DEMIGOD2_RADIAL_PROJECTILE_ATTACK_RANGE)
item->Animation.TargetState = DEMIGOD2_STATE_RADIAL_PROJECTILE_ATTACK;
break;
case DEMIGOD3_STATE_RADIAL_PROJECTILE_ATTACK:
creature->MaxTurn = ANGLE(7.0f);
DoDemigodEffects(itemNumber);
if (!Targetable(item, &AI) || AI.distance < pow(SECTOR(5), 2) || !GetRandomControl())
if (!Targetable(item, &AI) || AI.distance < DEMIGOD3_RADIAL_PROJECTILE_ATTACK_RANGE || !GetRandomControl())
{
item->Animation.TargetState = DEMIGOD_STATE_IDLE;
break;
@ -663,7 +681,7 @@ namespace TEN::Entities::TR4
else
item->Pose.Orientation.y += AI.angle;
if (AI.distance >= pow(SECTOR(3), 2) ||
if (AI.distance >= DEMIGOD1_WALK_RANGE ||
!AI.bite &&
(LaraItem->Animation.ActiveState < LS_LADDER_IDLE ||
LaraItem->Animation.ActiveState > LS_LADDER_DOWN ||

View file

@ -52,7 +52,7 @@ namespace TEN::Entities::TR4
const auto SethPounceAttackJoints1 = std::vector<unsigned int>{ 13, 14, 15 };
const auto SethPounceAttackJoints2 = std::vector<unsigned int>{ 16, 17, 18 };
constexpr auto LARA_STATE_SETH_DEATH = 13;
constexpr auto LARA_STATE_SETH_DEATH = 14;
constexpr auto LARA_ANIM_SETH_DEATH = 14;
enum SethState
@ -659,7 +659,7 @@ namespace TEN::Entities::TR4
fx.flag1 = flags;
fx.objectNumber = ID_ENERGY_BUBBLES;
fx.speed = Random::GenerateInt(0, 32) - ((flags == 1) ? 64 : 0) + 96;
fx.frameNumber = Objects[ID_ENERGY_BUBBLES].meshIndex + 2 - flags;
fx.frameNumber = Objects[ID_ENERGY_BUBBLES].meshIndex + flags;
}
void SethKillAttack(ItemInfo* item, ItemInfo* laraItem)
@ -673,7 +673,7 @@ namespace TEN::Entities::TR4
laraItem->Animation.ActiveState = LARA_STATE_SETH_DEATH;
laraItem->Animation.TargetState = LARA_STATE_SETH_DEATH;
laraItem->Animation.IsAirborne = false;
laraItem->Pose = Pose(item->Pose.Position, 0, item->Pose.Orientation.y, 0);
laraItem->Pose = Pose(item->Pose.Position, item->Pose.Orientation);
if (item->RoomNumber != laraItem->RoomNumber)
ItemNewRoom(lara.ItemNumber, item->RoomNumber);
@ -687,9 +687,12 @@ namespace TEN::Entities::TR4
lara.Control.Weapon.GunType = LaraWeaponType::None;
Camera.pos.RoomNumber = laraItem->RoomNumber;
Camera.type = CameraType::Chase;
Camera.flags = CF_FOLLOW_CENTER;
Camera.targetAngle = ANGLE(170.0f);
Camera.targetElevation = ANGLE(-25.0f);
Camera.type = CameraType::Fixed;
ForcedFixedCamera.x = item->Pose.Position.x + ((BLOCK(2) * phd_sin(item->Pose.Orientation.y)));
ForcedFixedCamera.y = item->Pose.Position.y - BLOCK(1);
ForcedFixedCamera.z = item->Pose.Position.z + ((BLOCK(2) * phd_cos(item->Pose.Orientation.y)));
ForcedFixedCamera.RoomNumber = item->RoomNumber;
UseForcedFixedCamera = true;
}
}

View file

@ -61,24 +61,38 @@ void ExplosionControl(short itemNumber)
if (TriggerActive(item))
{
item->Flags |= IFLAG_INVISIBLE;
if (item->ItemFlags[0] < item->TriggerFlags)
{
++item->ItemFlags[0];
}
else if (item->ItemFlags[0] == item->TriggerFlags)
{
int flag;
++item->ItemFlags[0];
if (TestEnvironment(ENV_FLAG_WATER, item->RoomNumber))
if (TestEnvironment(ENV_FLAG_WATER, item->RoomNumber) ||
TestEnvironment(ENV_FLAG_SWAMP, item->RoomNumber))
{
flag = 1;
}
else
{
flag = item->ItemFlags[1] == 1 ? 2 : 0;
}
SoundEffect(SFX_TR4_EXPLOSION1, &item->Pose, SoundEnvironment::Land, 1.5f);
SoundEffect(SFX_TR4_EXPLOSION2, &item->Pose);
TriggerExplosionSparks(item->Pose.Position.x, item->Pose.Position.y, item->Pose.Position.z, 3, -2, flag, item->RoomNumber);
for (int i = 0; i < item->ItemFlags[2]; ++i)
TriggerExplosionSparks(item->Pose.Position.x + (GetRandomControl() % 128 - 64) * item->ItemFlags[2], item->Pose.Position.y + (GetRandomControl() % 128 - 64) * item->ItemFlags[2], item->Pose.Position.z + (GetRandomControl() % 128 - 64) * item->ItemFlags[2], 2, 0, i, item->RoomNumber);
{
TriggerExplosionSparks(
item->Pose.Position.x + (GetRandomControl() % 128 - 64) * item->ItemFlags[2],
item->Pose.Position.y + (GetRandomControl() % 128 - 64) * item->ItemFlags[2],
item->Pose.Position.z + (GetRandomControl() % 128 - 64) * item->ItemFlags[2],
2, 0, flag, item->RoomNumber);
}
Pose pos;
pos.Position.x = item->Pose.Position.x;
@ -88,11 +102,12 @@ void ExplosionControl(short itemNumber)
if (item->ItemFlags[3])
{
if (flag == 2)
TriggerShockwave(&pos, 48, 32 * item->ItemFlags[2] + 304, 4 * item->ItemFlags[2] + 96, 128, 96, 0, 24, 2048, 0);
else
TriggerShockwave(&pos, 48, 32 * item->ItemFlags[2] + 304, 4 * item->ItemFlags[2] + 96, 0, 96, 128, 24, 2048, 0);
else
TriggerShockwave(&pos, 48, 32 * item->ItemFlags[2] + 304, 4 * item->ItemFlags[2] + 96, 128, 96, 0, 24, 2048, 0);
}
else if (flag == 2)
if (flag != 2)
{
auto vec = GetJointPosition(LaraItem, LM_HIPS);
@ -100,12 +115,12 @@ void ExplosionControl(short itemNumber)
int dy = vec.y - item->Pose.Position.y;
int dz = vec.z - item->Pose.Position.z;
if (abs(dx) < SECTOR(1) &&
abs(dy) < SECTOR(1) &&
abs(dz) < SECTOR(1))
if (abs(dx) < BLOCK(1) &&
abs(dy) < BLOCK(1) &&
abs(dz) < BLOCK(1))
{
int distance = sqrt(pow(dx, 2) + pow(dy, 2) + pow(dz, 2));
if (distance < SECTOR(2))
if (distance < BLOCK(2))
{
DoDamage(LaraItem, distance / 16);
@ -125,7 +140,7 @@ void ExplosionControl(short itemNumber)
{
TriggerExplosionSparks(CollidedItems[i]->Pose.Position.x, CollidedItems[i]->Pose.Position.y, CollidedItems[i]->Pose.Position.z, 3, -2, 0, CollidedItems[i]->RoomNumber);
CollidedItems[i]->Pose.Position.y -= 128;
TriggerShockwave(&CollidedItems[i]->Pose, 48, 304, 96, 0, 96, 128, 24, 0, 0);
TriggerShockwave(&CollidedItems[i]->Pose, 48, 304, 96, 128, 96, 0, 24, 0, 0);
CollidedItems[i]->Pose.Position.y += 128;
ExplodeItemNode(CollidedItems[i], 0, 0, 80);
SmashObject(CollidedItems[i] - g_Level.Items.data());
@ -151,7 +166,7 @@ void ExplosionControl(short itemNumber)
{
TriggerExplosionSparks(CollidedMeshes[i]->pos.Position.x, CollidedMeshes[i]->pos.Position.y, CollidedMeshes[i]->pos.Position.z, 3, -2, 0, item->RoomNumber);
CollidedMeshes[i]->pos.Position.y -= 128;
TriggerShockwave(&CollidedMeshes[i]->pos, 40, 176, 64, 0, 96, 128, 16, 0, 0);
TriggerShockwave(&CollidedMeshes[i]->pos, 40, 176, 64, 128, 96, 0, 16, 0, 0);
CollidedMeshes[i]->pos.Position.y += 128;
SoundEffect(GetShatterSound(CollidedMeshes[i]->staticNumber), &CollidedMeshes[i]->pos);
ShatterObject(NULL, CollidedMeshes[i], -128, item->RoomNumber, 0);
@ -175,7 +190,9 @@ void ExplosionControl(short itemNumber)
}
}
else
{
KillItem(itemNumber);
}
}
}
}

View file

@ -29,6 +29,26 @@ namespace TEN::Renderer
m_meshes.clear();
TENLog("Allocated renderer object memory.", LogLevel::Info);
m_animatedTextures.resize(g_Level.AnimatedTextures.size());
for (int i = 0; i < g_Level.AnimatedTextures.size(); i++)
{
TEXTURE* texture = &g_Level.AnimatedTextures[i];
Texture2D normal;
if (texture->normalMapData.size() < 1) {
normal = CreateDefaultNormalTexture();
}
else {
normal = Texture2D(m_device.Get(), texture->normalMapData.data(), texture->normalMapData.size());
}
TexturePair tex = std::make_tuple(Texture2D(m_device.Get(), texture->colorMapData.data(), texture->colorMapData.size()), normal);
m_animatedTextures[i] = tex;
}
if (m_animatedTextures.size() > 0)
TENLog("Generated " + std::to_string(m_animatedTextures.size()) + " animated textures.", LogLevel::Info);
std::transform(g_Level.AnimatedTexturesSequences.begin(), g_Level.AnimatedTexturesSequences.end(), std::back_inserter(m_animatedTextureSets), [](ANIMATED_TEXTURES_SEQUENCE& sequence) {
RendererAnimatedTextureSet set{};
set.NumTextures = sequence.numFrames;
@ -48,6 +68,9 @@ namespace TEN::Renderer
return set;
});
if (m_animatedTextureSets.size() > 0)
TENLog("Generated " + std::to_string(m_animatedTextureSets.size()) + " animated texture sets.", LogLevel::Info);
m_roomTextures.resize(g_Level.RoomTextures.size());
for (int i = 0; i < g_Level.RoomTextures.size(); i++)
{
@ -70,20 +93,8 @@ namespace TEN::Renderer
#endif
}
m_animatedTextures.resize(g_Level.AnimatedTextures.size());
for (int i = 0; i < g_Level.AnimatedTextures.size(); i++)
{
TEXTURE *texture = &g_Level.AnimatedTextures[i];
Texture2D normal;
if (texture->normalMapData.size() < 1) {
normal = CreateDefaultNormalTexture();
}
else {
normal = Texture2D(m_device.Get(), texture->normalMapData.data(), texture->normalMapData.size());
}
TexturePair tex = std::make_tuple(Texture2D(m_device.Get(), texture->colorMapData.data(), texture->colorMapData.size()), normal);
m_animatedTextures[i] = tex;
}
if (m_roomTextures.size() > 0)
TENLog("Generated " + std::to_string(m_roomTextures.size()) + " room texture atlases.", LogLevel::Info);
m_moveablesTextures.resize(g_Level.MoveablesTextures.size());
for (int i = 0; i < g_Level.MoveablesTextures.size(); i++)
@ -107,6 +118,9 @@ namespace TEN::Renderer
#endif
}
if (m_moveablesTextures.size() > 0)
TENLog("Generated " + std::to_string(m_moveablesTextures.size()) + " moveable texture atlases.", LogLevel::Info);
m_staticsTextures.resize(g_Level.StaticsTextures.size());
for (int i = 0; i < g_Level.StaticsTextures.size(); i++)
{
@ -129,6 +143,9 @@ namespace TEN::Renderer
#endif
}
if (m_staticsTextures.size() > 0)
TENLog("Generated " + std::to_string(m_staticsTextures.size()) + " static mesh texture atlases.", LogLevel::Info);
m_spritesTextures.resize(g_Level.SpritesTextures.size());
for (int i = 0; i < g_Level.SpritesTextures.size(); i++)
{
@ -136,8 +153,13 @@ namespace TEN::Renderer
m_spritesTextures[i] = Texture2D(m_device.Get(), texture->colorMapData.data(), texture->colorMapData.size());
}
if (m_spritesTextures.size() > 0)
TENLog("Generated " + std::to_string(m_spritesTextures.size()) + " sprite atlases.", LogLevel::Info);
m_skyTexture = Texture2D(m_device.Get(), g_Level.SkyTexture.colorMapData.data(), g_Level.SkyTexture.colorMapData.size());
TENLog("Loaded sky texture.", LogLevel::Info);
int totalVertices = 0;
int totalIndices = 0;
for (auto& room : g_Level.Rooms)
@ -153,9 +175,13 @@ namespace TEN::Renderer
roomsVertices.resize(totalVertices);
roomsIndices.resize(totalIndices);
TENLog("Loaded total " + std::to_string(totalVertices) + " room vertices.", LogLevel::Info);
int lastVertex = 0;
int lastIndex = 0;
TENLog("Preparing room data...", LogLevel::Info);
for (int i = 0; i < g_Level.Rooms.size(); i++)
{
ROOM_INFO& room = g_Level.Rooms[i];
@ -404,6 +430,8 @@ namespace TEN::Renderer
}
);
TENLog("Preparing object data...", LogLevel::Info);
bool skinPresent = false;
bool hairsPresent = false;
@ -707,6 +735,8 @@ namespace TEN::Renderer
m_moveablesVertexBuffer = VertexBuffer(m_device.Get(), moveablesVertices.size(), moveablesVertices.data());
m_moveablesIndexBuffer = IndexBuffer(m_device.Get(), moveablesIndices.size(), moveablesIndices.data());
TENLog("Preparing static mesh data...", LogLevel::Info);
totalVertices = 0;
totalIndices = 0;
for (int i = 0; i < StaticObjectsIds.size(); i++)
@ -753,6 +783,8 @@ namespace TEN::Renderer
m_staticsIndexBuffer = IndexBuffer(m_device.Get(), 1);
}
TENLog("Preparing sprite data...", LogLevel::Info);
// Step 5: prepare sprites
m_sprites.resize(g_Level.Sprites.size());

View file

@ -1264,11 +1264,16 @@ namespace TEN::Renderer
using TEN::Effects::Smoke::SmokeParticles;
using TEN::Effects::Smoke::SmokeParticle;
for (int i = 0; i < SmokeParticles.size(); i++)
for (const auto& smoke : SmokeParticles)
{
SmokeParticle& s = SmokeParticles[i];
if (!s.active) continue;
AddSpriteBillboard(&m_sprites[Objects[ID_SMOKE_SPRITES].meshIndex + s.sprite], s.position, s.color, s.rotation, 1.0f, { s.size, s.size }, BLENDMODE_ALPHABLEND, true, view);
if (!smoke.active)
continue;
// TODO: Switch back to alpha blend mode once rendering for it is refactored. -- Sezz 2023.01.14
AddSpriteBillboard(
&m_sprites[Objects[ID_SMOKE_SPRITES].meshIndex + smoke.sprite],
smoke.position,
smoke.color, smoke.rotation, 1.0f, { smoke.size, smoke.size }, BLENDMODE_ADDITIVE, true, view);
}
}