mirror of
https://github.com/TombEngine/TombEngine.git
synced 2025-05-02 09:47:58 +03:00
Merge branch 'master' into Enemy-fix
This commit is contained in:
commit
5d53e50f52
12 changed files with 471 additions and 160 deletions
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 ||
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue