diff --git a/Documentation/Changes.txt b/Documentation/Changes.txt index 807bf5692..d972b3def 100644 --- a/Documentation/Changes.txt +++ b/Documentation/Changes.txt @@ -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. diff --git a/TombEngine/Game/Lara/lara_one_gun.cpp b/TombEngine/Game/Lara/lara_one_gun.cpp index 63ca03199..1effabf81 100644 --- a/TombEngine/Game/Lara/lara_one_gun.cpp +++ b/TombEngine/Game/Lara/lara_one_gun.cpp @@ -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); diff --git a/TombEngine/Game/effects/effects.cpp b/TombEngine/Game/effects/effects.cpp index 87b70fd16..0b6b33d2d 100644 --- a/TombEngine/Game/effects/effects.cpp +++ b/TombEngine/Game/effects/effects.cpp @@ -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++) { @@ -188,7 +204,7 @@ void UpdateSparks() spark->on = false; continue; } - + int life = spark->sLife - spark->life; if (life < spark->colFadeSpeed) { @@ -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{ 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,13 +854,21 @@ 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); + } } } @@ -685,11 +881,12 @@ 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) { - float splashPower = fmin(256, setup->splashPower); + float splashPower = fmin(256, setup->splashPower); splash.isActive = true; splash.x = setup->x; splash.y = setup->y; @@ -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; diff --git a/TombEngine/Game/effects/effects.h b/TombEngine/Game/effects/effects.h index f7d120678..1829f3268 100644 --- a/TombEngine/Game/effects/effects.h +++ b/TombEngine/Game/effects/effects.h @@ -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); diff --git a/TombEngine/Objects/Effects/enemy_missile.cpp b/TombEngine/Objects/Effects/enemy_missile.cpp index 528dcb99c..fd7723196 100644 --- a/TombEngine/Objects/Effects/enemy_missile.cpp +++ b/TombEngine/Objects/Effects/enemy_missile.cpp @@ -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(); @@ -59,16 +70,16 @@ namespace TEN::Entities::Effects spark->rotAdd = -32 - (GetRandomControl() & 0x1F); else spark->rotAdd = (GetRandomControl() & 0x1F) + 32; - + spark->gravity = 0; spark->maxYvel = 0; - spark->fxObj = fxNum; + spark->fxObj = fxNumber; if (fx->flag1 == 1) spark->scalar = 3; else spark->scalar = 2; - + spark->sSize = spark->size = (GetRandomControl() & 7) + 64; spark->dSize = spark->size / 32; } @@ -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; } diff --git a/TombEngine/Objects/TR1/Entity/tr1_big_rat.cpp b/TombEngine/Objects/TR1/Entity/tr1_big_rat.cpp index 09532f53d..5d58aefb5 100644 --- a/TombEngine/Objects/TR1/Entity/tr1_big_rat.cpp +++ b/TombEngine/Objects/TR1/Entity/tr1_big_rat.cpp @@ -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); diff --git a/TombEngine/Objects/TR3/Vehicles/quad_bike.cpp b/TombEngine/Objects/TR3/Vehicles/quad_bike.cpp index 8f8a271fa..9a9798fa3 100644 --- a/TombEngine/Objects/TR3/Vehicles/quad_bike.cpp +++ b/TombEngine/Objects/TR3/Vehicles/quad_bike.cpp @@ -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; diff --git a/TombEngine/Objects/TR4/Entity/tr4_demigod.cpp b/TombEngine/Objects/TR4/Entity/tr4_demigod.cpp index 187b39831..e4873c697 100644 --- a/TombEngine/Objects/TR4/Entity/tr4_demigod.cpp +++ b/TombEngine/Objects/TR4/Entity/tr4_demigod.cpp @@ -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)) - { - item->Animation.TargetState = DEMIGOD_STATE_WALK_FORWARD; - break; - } - 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 (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; } @@ -594,7 +604,7 @@ namespace TEN::Entities::TR4 case DEMIGOD2_STATE_RADIAL_PROJECTILE_ATTACK: creature->MaxTurn = ANGLE(7.0f); - + if (Targetable(item, &AI)) item->Animation.TargetState = DEMIGOD2_STATE_RADIAL_UNAIM; @@ -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 || diff --git a/TombEngine/Objects/TR4/Entity/tr4_setha.cpp b/TombEngine/Objects/TR4/Entity/tr4_setha.cpp index 5765360b5..2b5bd8dc8 100644 --- a/TombEngine/Objects/TR4/Entity/tr4_setha.cpp +++ b/TombEngine/Objects/TR4/Entity/tr4_setha.cpp @@ -52,7 +52,7 @@ namespace TEN::Entities::TR4 const auto SethPounceAttackJoints1 = std::vector{ 13, 14, 15 }; const auto SethPounceAttackJoints2 = std::vector{ 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; + } } diff --git a/TombEngine/Objects/TR5/Trap/tr5_explosion.cpp b/TombEngine/Objects/TR5/Trap/tr5_explosion.cpp index fff08c365..2bbf66533 100644 --- a/TombEngine/Objects/TR5/Trap/tr5_explosion.cpp +++ b/TombEngine/Objects/TR5/Trap/tr5_explosion.cpp @@ -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); + } } } } diff --git a/TombEngine/Renderer/Renderer11Compatibility.cpp b/TombEngine/Renderer/Renderer11Compatibility.cpp index bc8c75d8e..605441c5e 100644 --- a/TombEngine/Renderer/Renderer11Compatibility.cpp +++ b/TombEngine/Renderer/Renderer11Compatibility.cpp @@ -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++) @@ -752,6 +782,8 @@ namespace TEN::Renderer m_staticsVertexBuffer = VertexBuffer(m_device.Get(), 1); m_staticsIndexBuffer = IndexBuffer(m_device.Get(), 1); } + + TENLog("Preparing sprite data...", LogLevel::Info); // Step 5: prepare sprites m_sprites.resize(g_Level.Sprites.size()); diff --git a/TombEngine/Renderer/Renderer11DrawEffect.cpp b/TombEngine/Renderer/Renderer11DrawEffect.cpp index 64086c2f6..edb7e343d 100644 --- a/TombEngine/Renderer/Renderer11DrawEffect.cpp +++ b/TombEngine/Renderer/Renderer11DrawEffect.cpp @@ -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); } }