mirror of
https://github.com/TombEngine/TombEngine.git
synced 2025-04-30 16:57:57 +03:00
Implemented Claw Mutant from TR3 (#1061)
* Foundation commit for ID_MONSTER_MUTANT * Implemented claw mutant from TR3 * Fixed vs2019 project * Fixed scripting for claw mutant * finished plasma ball effect * Improved claw mutant Fixed blood not appearing. Fixed precision for the projectile. * Improved precision for claw mutant Now it take lara being crouch into account. * Demagic and reformat * Formatting; use GetAnimData() * Fix merge error * Refine claw mutant enums and constants * Update Changes.txt * Increased the attack range in idle. --------- Co-authored-by: Stranger1992 <84292688+Stranger1992@users.noreply.github.com> Co-authored-by: Nemoel-Tomo <tomo_669@hotmail.com> Co-authored-by: Sezz <sezzary@outlook.com> Co-authored-by: Kubsy <80340234+Kubsy@users.noreply.github.com>
This commit is contained in:
parent
4419345f93
commit
da2066f51a
11 changed files with 700 additions and 128 deletions
|
@ -2,8 +2,9 @@ Version 1.0.9
|
|||
=============
|
||||
|
||||
- Add TR3 Wall mounted blade.
|
||||
- Add TR3 Claw mutant.
|
||||
- Add removable puzzles from puzzle holes and puzzle dones.
|
||||
- employed by setting the trigger type as "Switch" for either puzzle hole or puzzle done.
|
||||
- employed by setting the trigger type as "Switch" for either puzzle hole or puzzle done.
|
||||
- Can be mixed with puzzle done and puzzle holes of the same or different type.
|
||||
- Fix Cold bar triggered when room is dry (only trigger if and only if the room is water).
|
||||
- Fix spiky wall speed value.
|
||||
|
|
|
@ -11,12 +11,14 @@
|
|||
#include "Game/items.h"
|
||||
#include "Game/Lara/lara.h"
|
||||
#include "Math/Math.h"
|
||||
#include "Objects/TR3/Entity/tr3_claw_mutant.h"
|
||||
#include "Objects/TR4/Entity/tr4_mutant.h"
|
||||
#include "Objects/TR4/Entity/tr4_demigod.h"
|
||||
#include "Renderer/Renderer11Enums.h"
|
||||
#include "Specific/level.h"
|
||||
|
||||
using namespace TEN::Effects::Items;
|
||||
using namespace TEN::Entities::Creatures::TR3;
|
||||
using namespace TEN::Entities::TR4;
|
||||
using namespace TEN::Math;
|
||||
|
||||
|
@ -58,9 +60,13 @@ namespace TEN::Entities::Effects
|
|||
flame.fxObj = fxNumber;
|
||||
|
||||
if (fx.flag1 == 1)
|
||||
{
|
||||
flame.scalar = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
flame.scalar = 2;
|
||||
}
|
||||
|
||||
flame.sSize = flame.size = (GetRandomControl() & 7) + 64;
|
||||
flame.dSize = flame.size / 32;
|
||||
|
@ -92,9 +98,13 @@ namespace TEN::Entities::Effects
|
|||
flame.rotAng = GetRandomControl() & 0xFFF;
|
||||
|
||||
if (GetRandomControl() & 1)
|
||||
{
|
||||
flame.rotAdd = -32 - (GetRandomControl() & 0x1F);
|
||||
}
|
||||
else
|
||||
{
|
||||
flame.rotAdd = (GetRandomControl() & 0x1F) + 32;
|
||||
}
|
||||
|
||||
flame.gravity = 0;
|
||||
flame.maxYvel = 0;
|
||||
|
@ -135,7 +145,7 @@ namespace TEN::Entities::Effects
|
|||
}
|
||||
else
|
||||
{
|
||||
if (fx.flag1 == (int)MissileType::Mutant)
|
||||
if (fx.flag1 == (int)MissileType::CrocgodMutant)
|
||||
{
|
||||
if (fx.counter)
|
||||
fx.counter--;
|
||||
|
@ -152,15 +162,20 @@ namespace TEN::Entities::Effects
|
|||
|
||||
if (fx.speed < maxVelocity)
|
||||
{
|
||||
if (fx.flag1 == (int)MissileType::Mutant)
|
||||
if (fx.flag1 == (int)MissileType::CrocgodMutant)
|
||||
{
|
||||
fx.speed++;
|
||||
}
|
||||
else
|
||||
{
|
||||
fx.speed += 3;
|
||||
}
|
||||
}
|
||||
|
||||
if (fx.speed < maxVelocity &&
|
||||
fx.flag1 != (int)MissileType::SophiaLeighNormal &&
|
||||
fx.flag1 != (int)MissileType::SophiaLeighLarge)
|
||||
fx.flag1 != (int)MissileType::SophiaLeighLarge &&
|
||||
fx.flag1 != (int)MissileType::ClawMutantPlasma)
|
||||
{
|
||||
short dy = orient.y - fx.pos.Orientation.y;
|
||||
if (abs(dy) > abs(ANGLE(180.0f)))
|
||||
|
@ -171,8 +186,6 @@ namespace TEN::Entities::Effects
|
|||
dx = -dx;
|
||||
|
||||
dy >>= 3;
|
||||
dx >>= 3;
|
||||
|
||||
if (dy < -maxRotation)
|
||||
{
|
||||
dy = -maxRotation;
|
||||
|
@ -182,6 +195,7 @@ namespace TEN::Entities::Effects
|
|||
dy = maxRotation;
|
||||
}
|
||||
|
||||
dx >>= 3;
|
||||
if (dx < -maxRotation)
|
||||
{
|
||||
dx = -maxRotation;
|
||||
|
@ -192,85 +206,86 @@ namespace TEN::Entities::Effects
|
|||
}
|
||||
|
||||
fx.pos.Orientation.x += dx;
|
||||
|
||||
if (fx.flag1 != (int)MissileType::Demigod3Radial && (fx.flag1 != (int)MissileType::Mutant || !fx.counter))
|
||||
if (fx.flag1 != (int)MissileType::Demigod3Radial && (fx.flag1 != (int)MissileType::CrocgodMutant || !fx.counter))
|
||||
fx.pos.Orientation.y += dy;
|
||||
}
|
||||
|
||||
fx.pos.Orientation.z += 16 * fx.speed;
|
||||
if (fx.flag1 == (int)MissileType::Mutant)
|
||||
if (fx.flag1 == (int)MissileType::CrocgodMutant)
|
||||
fx.pos.Orientation.z += 16 * fx.speed;
|
||||
|
||||
auto prevPos = fx.pos.Position;
|
||||
|
||||
int speed = (fx.speed * phd_cos(fx.pos.Orientation.x));
|
||||
fx.pos.Position.x += (speed * phd_sin(fx.pos.Orientation.y));
|
||||
fx.pos.Position.x += speed * phd_sin(fx.pos.Orientation.y);
|
||||
fx.pos.Position.y += -((fx.speed * phd_sin(fx.pos.Orientation.x))) + fx.fallspeed;
|
||||
fx.pos.Position.z += (speed * phd_cos(fx.pos.Orientation.y));
|
||||
fx.pos.Position.z += speed * phd_cos(fx.pos.Orientation.y);
|
||||
|
||||
auto probe = GetCollision(fx.pos.Position.x, fx.pos.Position.y, fx.pos.Position.z, fx.roomNumber);
|
||||
auto pointColl = GetCollision(fx.pos.Position.x, fx.pos.Position.y, fx.pos.Position.z, fx.roomNumber);
|
||||
|
||||
if (fx.pos.Position.y >= probe.Position.Floor || fx.pos.Position.y <= probe.Position.Ceiling)
|
||||
if (fx.pos.Position.y >= pointColl.Position.Floor || fx.pos.Position.y <= pointColl.Position.Ceiling)
|
||||
{
|
||||
fx.pos.Position = prevPos;
|
||||
|
||||
if (fx.flag1 != (int)MissileType::Mutant &&
|
||||
fx.flag1 != (int)MissileType::SophiaLeighNormal &&
|
||||
fx.flag1 != (int)MissileType::SophiaLeighLarge)
|
||||
switch ((MissileType)fx.flag1)
|
||||
{
|
||||
case MissileType::SethLarge:
|
||||
TriggerShockwave(&fx.pos, 32, 160, 64, 64, 128, 00, 24, EulerAngles(fx.pos.Orientation.x - ANGLE(90.0f), 0, 0), 0, true, false, (int)ShockwaveStyle::Normal);
|
||||
TriggerExplosionSparks(prevPos.x, prevPos.y, prevPos.z, 3, -2, 2, fx.roomNumber);
|
||||
BubblesShatterFunction(&fx, 0, -32);
|
||||
break;
|
||||
|
||||
if (fx.flag1 == (int)MissileType::SethLarge)
|
||||
{
|
||||
TriggerShockwave(&fx.pos, 32, 160, 64, 64, 128, 00, 24, EulerAngles((((~g_Level.Rooms[fx.roomNumber].flags) / 16) & 2) * 65536, 0.0f, 0.0f), 0, true, false, (int)ShockwaveStyle::Normal);
|
||||
case MissileType::SophiaLeighNormal:
|
||||
TriggerShockwave(&fx.pos, 5, 32, 128, 0, 128, 128, 24, EulerAngles(fx.pos.Orientation.x - ANGLE(90.0f), 0, 0), 0, true, false, (int)ShockwaveStyle::Normal);
|
||||
TriggerExplosionSparks(prevPos.x, prevPos.y, prevPos.z, 3, -2, 2, fx.roomNumber);
|
||||
}
|
||||
else if (fx.flag1 == (int)MissileType::SophiaLeighNormal)
|
||||
{
|
||||
TriggerShockwave(&fx.pos, 5, 32, 128, 0, 128, 128, 24, EulerAngles(fx.pos.Orientation.y + ANGLE(180), 0.0f, 0.0f), 0, true, false, (int)ShockwaveStyle::Normal);
|
||||
TriggerExplosionSparks(prevPos.x, prevPos.y, prevPos.z, 3, -2, 2, fx.roomNumber);
|
||||
}
|
||||
else if (fx.flag1 == (int)MissileType::SophiaLeighLarge)
|
||||
{
|
||||
TriggerShockwave(&fx.pos, 10, 64, 128, 0, 128, 128, 24, EulerAngles(fx.pos.Orientation.y + ANGLE(180), 0.0f, 0.0f), 0, true, false, (int)ShockwaveStyle::Normal);
|
||||
TriggerExplosionSparks(prevPos.x, prevPos.y, prevPos.z, 3, -2, 2, fx.roomNumber);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fx.flag1)
|
||||
{
|
||||
if (fx.flag1 == (int)MissileType::Demigod3Single || fx.flag1 == (int)MissileType::Demigod3Radial)
|
||||
{
|
||||
TriggerShockwave(&fx.pos, 32, 160, 64, 0, 96, 128, 16, EulerAngles::Zero, 0, true, false, (int)ShockwaveStyle::Normal);
|
||||
}
|
||||
else if (fx.flag1 == (int)MissileType::Demigod2)
|
||||
{
|
||||
TriggerShockwave(&fx.pos, 32, 160, 64, 128, 64, 0, 16, EulerAngles::Zero, 0, true, false, (int)ShockwaveStyle::Normal);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fx.flag1 != (int)MissileType::Harpy)
|
||||
{
|
||||
if (fx.flag1 == (int)MissileType::Mutant)
|
||||
{
|
||||
TriggerExplosionSparks(prevPos.x, prevPos.y, prevPos.z, 3, -2, 0, fx.roomNumber);
|
||||
TriggerShockwave(&fx.pos, 48, 240, 64, 128, 96, 0, 24, EulerAngles::Zero, 15, true, false, (int)ShockwaveStyle::Normal);
|
||||
fx.pos.Position.y -= 128;
|
||||
TriggerShockwave(&fx.pos, 48, 240, 48, 128, 112, 0, 16, EulerAngles::Zero, 15, true, false, (int)ShockwaveStyle::Normal);
|
||||
fx.pos.Position.y += 256;
|
||||
TriggerShockwave(&fx.pos, 48, 240, 48, 128, 112, 0, 16, EulerAngles::Zero, 15, true, false, (int)ShockwaveStyle::Normal);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
TriggerShockwave(&fx.pos, 32, 160, 64, 128, 128, 0, 16, EulerAngles::Zero, 0, true, false, (int)ShockwaveStyle::Normal);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
case MissileType::SophiaLeighLarge:
|
||||
TriggerShockwave(&fx.pos, 10, 64, 128, 0, 128, 128, 24, EulerAngles(fx.pos.Orientation.x - ANGLE(90.0f), 0, 0), 0, true, false, (int)ShockwaveStyle::Normal);
|
||||
TriggerExplosionSparks(prevPos.x, prevPos.y, prevPos.z, 3, -2, 2, fx.roomNumber);
|
||||
break;
|
||||
|
||||
case MissileType::Demigod3Single:
|
||||
case MissileType::Demigod3Radial:
|
||||
TriggerShockwave(&fx.pos, 32, 160, 64, 0, 96, 128, 16, EulerAngles::Zero, 0, true, false, (int)ShockwaveStyle::Normal);
|
||||
BubblesShatterFunction(&fx, 0, -32);
|
||||
break;
|
||||
|
||||
case MissileType::Demigod2:
|
||||
TriggerShockwave(&fx.pos, 32, 160, 64, 128, 64, 0, 16, EulerAngles::Zero, 0, true, false, (int)ShockwaveStyle::Normal);
|
||||
BubblesShatterFunction(&fx, 0, -32);
|
||||
break;
|
||||
|
||||
case MissileType::Harpy:
|
||||
TriggerShockwave(&fx.pos, 32, 160, 64, 128, 128, 0, 16, EulerAngles::Zero, 0, true, false, (int)ShockwaveStyle::Normal);
|
||||
BubblesShatterFunction(&fx, 0, -32);
|
||||
break;
|
||||
|
||||
case MissileType::CrocgodMutant:
|
||||
TriggerExplosionSparks(prevPos.x, prevPos.y, prevPos.z, 3, -2, 0, fx.roomNumber);
|
||||
TriggerShockwave(&fx.pos, 48, 240, 64, 128, 96, 0, 24, EulerAngles::Zero, 15, true, false, (int)ShockwaveStyle::Normal);
|
||||
|
||||
fx.pos.Position.y -= 128;
|
||||
TriggerShockwave(&fx.pos, 48, 240, 48, 128, 112, 0, 16, EulerAngles::Zero, 15, true, false, (int)ShockwaveStyle::Normal);
|
||||
|
||||
fx.pos.Position.y += 256;
|
||||
TriggerShockwave(&fx.pos, 48, 240, 48, 128, 112, 0, 16, EulerAngles::Zero, 15, true, false, (int)ShockwaveStyle::Normal);
|
||||
break;
|
||||
|
||||
case MissileType::ClawMutantPlasma:
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
TriggerShockwave(&fx.pos, 32, 160, 64, 0, 128, 64, 16, EulerAngles::Zero, 0, true, false, (int)ShockwaveStyle::Normal);
|
||||
SpawnClawMutantPlasmaFlameBall(fxNumber, Vector3(20.0f, 32.0f, 20.0f), Vector3(Random::GenerateFloat(-115.0f, 185.0f), 0, Random::GenerateFloat(-115.0f, 185.0f)), 24);
|
||||
SpawnClawMutantPlasmaFlameBall(fxNumber, Vector3(20.0f, 32.0f, 20.0f), Vector3(Random::GenerateFloat(-115.0f, 185.0f), 0, Random::GenerateFloat(-115.0f, 185.0f)), 24);
|
||||
SpawnClawMutantPlasmaFlameBall(fxNumber, Vector3(20.0f, 32.0f, 20.0f), Vector3(Random::GenerateFloat(-115.0f, 185.0f), 0, Random::GenerateFloat(-115.0f, 185.0f)), 24);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
TriggerShockwave(&fx.pos, 32, 160, 64, 0, 128, 64, 16, EulerAngles::Zero, 0, true, false, (int)ShockwaveStyle::Normal);
|
||||
BubblesShatterFunction(&fx, 0, -32);
|
||||
break;
|
||||
}
|
||||
|
||||
KillEffect(fxNumber);
|
||||
|
@ -280,93 +295,110 @@ namespace TEN::Entities::Effects
|
|||
if (ItemNearLara(fx.pos.Position, 200))
|
||||
{
|
||||
LaraItem->HitStatus = true;
|
||||
if (fx.flag1 != (int)MissileType::Mutant &&
|
||||
fx.flag1 != (int)MissileType::SophiaLeighNormal &&
|
||||
fx.flag1 != (int)MissileType::SophiaLeighLarge)
|
||||
BubblesShatterFunction(&fx, 0, -32);
|
||||
|
||||
KillEffect(fxNumber);
|
||||
|
||||
if (fx.flag1 == (int)MissileType::SethLarge)
|
||||
switch ((MissileType)fx.flag1)
|
||||
{
|
||||
case MissileType::SethLarge:
|
||||
TriggerShockwave(&fx.pos, 48, 240, 64, 0, 128, 64, 24, EulerAngles::Zero, 0, true, false, (int)ShockwaveStyle::Normal);
|
||||
TriggerExplosionSparks(prevPos.x, prevPos.y, prevPos.z, 3, -2, 2, fx.roomNumber);
|
||||
ItemCustomBurn(LaraItem, Vector3(0.0f, 0.8f, 0.1f), Vector3(0.0f, 0.9f, 0.8f));
|
||||
}
|
||||
else if (fx.flag1 == (int)MissileType::SophiaLeighNormal)
|
||||
{
|
||||
break;
|
||||
|
||||
case MissileType::SophiaLeighLarge:
|
||||
TriggerShockwave(&fx.pos, 5, 32, 128, 0, 128, 128, 24, EulerAngles(fx.pos.Orientation.y, 0.0f, 0.0f), fx.flag2, true, false, (int)ShockwaveStyle::Normal);
|
||||
TriggerExplosionSparks(prevPos.x, prevPos.y, prevPos.z, 3, -2, 2, fx.roomNumber);
|
||||
}
|
||||
else if (fx.flag1 == (int)MissileType::SophiaLeighLarge)
|
||||
{
|
||||
break;
|
||||
|
||||
case MissileType::SophiaLeighNormal:
|
||||
TriggerShockwave(&fx.pos, 10, 64, 128, 0, 128, 128, 24, EulerAngles(fx.pos.Orientation.y, 0.0f, 0.0f), fx.flag2, true, false, (int)ShockwaveStyle::Normal);
|
||||
TriggerExplosionSparks(prevPos.x, prevPos.y, prevPos.z, 3, -2, 2, fx.roomNumber);
|
||||
}
|
||||
else if (fx.flag1)
|
||||
{
|
||||
switch (fx.flag1)
|
||||
break;
|
||||
|
||||
case MissileType::Demigod3Single:
|
||||
case MissileType::Demigod3Radial:
|
||||
TriggerShockwave(&fx.pos, 32, 160, 64, 0, 96, 128, 16, EulerAngles::Zero, 10, true, false, (int)ShockwaveStyle::Normal);
|
||||
BubblesShatterFunction(&fx, 0, -32);
|
||||
break;
|
||||
|
||||
case MissileType::Demigod2:
|
||||
TriggerShockwave(&fx.pos, 32, 160, 64, 128, 64, 0, 16, EulerAngles::Zero, 5, true, false, (int)ShockwaveStyle::Normal);
|
||||
BubblesShatterFunction(&fx, 0, -32);
|
||||
break;
|
||||
|
||||
case MissileType::ClawMutantPlasma:
|
||||
DoDamage(LaraItem, fx.flag2);
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
case (int)MissileType::Demigod3Single:
|
||||
case (int)MissileType::Demigod3Radial:
|
||||
TriggerShockwave(&fx.pos, 32, 160, 64, 0, 96, 128, 16, EulerAngles::Zero, 10, true, false, (int)ShockwaveStyle::Normal);
|
||||
break;
|
||||
|
||||
case (int)MissileType::Demigod2:
|
||||
TriggerShockwave(&fx.pos, 32, 160, 64, 128, 64, 0, 16, EulerAngles::Zero, 5, true, false, (int)ShockwaveStyle::Normal);
|
||||
break;
|
||||
|
||||
case (int)MissileType::Harpy:
|
||||
TriggerShockwave(&fx.pos, 32, 160, 64, 128, 128, 0, 16, EulerAngles::Zero, 3, true, false, (int)ShockwaveStyle::Normal);
|
||||
break;
|
||||
|
||||
case (int)MissileType::Mutant:
|
||||
TriggerExplosionSparks(prevPos.x, prevPos.y, prevPos.z, 3, -2, 0, fx.roomNumber);
|
||||
TriggerShockwave(&fx.pos, 48, 240, 64, 128, 96, 0, 24, EulerAngles::Zero, 0, true, false, (int)ShockwaveStyle::Normal);
|
||||
fx.pos.Position.y -= 128;
|
||||
TriggerShockwave(&fx.pos, 48, 240, 48, 128, 112, 0, 16, EulerAngles::Zero, 0, true, false, (int)ShockwaveStyle::Normal);
|
||||
fx.pos.Position.y += 256;
|
||||
TriggerShockwave(&fx.pos, 48, 240, 48, 128, 112, 0, 16, EulerAngles::Zero, 0, true, false, (int)ShockwaveStyle::Normal);
|
||||
ItemBurn(LaraItem);
|
||||
break;
|
||||
SpawnClawMutantPlasmaFlameBall(fxNumber, Vector3(20.0f, 32.0f, 20.0f), Vector3(Random::GenerateFloat(-115.0f, 185.0f), 0, Random::GenerateFloat(-115.0f, 185.0f)), 24);
|
||||
SpawnClawMutantPlasmaFlameBall(fxNumber, Vector3(20.0f, 32.0f, 20.0f), Vector3(Random::GenerateFloat(-115.0f, 185.0f), 0, Random::GenerateFloat(-115.0f, 185.0f)), 24);
|
||||
SpawnClawMutantPlasmaFlameBall(fxNumber, Vector3(20.0f, 32.0f, 20.0f), Vector3(Random::GenerateFloat(-115.0f, 185.0f), 0, Random::GenerateFloat(-115.0f, 185.0f)), 24);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case MissileType::Harpy:
|
||||
TriggerShockwave(&fx.pos, 32, 160, 64, 128, 128, 0, 16, EulerAngles::Zero, 3, true, false, (int)ShockwaveStyle::Normal);
|
||||
BubblesShatterFunction(&fx, 0, -32);
|
||||
break;
|
||||
|
||||
case MissileType::CrocgodMutant:
|
||||
TriggerExplosionSparks(prevPos.x, prevPos.y, prevPos.z, 3, -2, 0, fx.roomNumber);
|
||||
TriggerShockwave(&fx.pos, 48, 240, 64, 128, 96, 0, 24, EulerAngles::Zero, 0, true, false, (int)ShockwaveStyle::Normal);
|
||||
|
||||
fx.pos.Position.y -= 128;
|
||||
TriggerShockwave(&fx.pos, 48, 240, 48, 128, 112, 0, 16, EulerAngles::Zero, 0, true, false, (int)ShockwaveStyle::Normal);
|
||||
|
||||
fx.pos.Position.y += 256;
|
||||
TriggerShockwave(&fx.pos, 48, 240, 48, 128, 112, 0, 16, EulerAngles::Zero, 0, true, false, (int)ShockwaveStyle::Normal);
|
||||
ItemBurn(LaraItem);
|
||||
break;
|
||||
|
||||
default:
|
||||
TriggerShockwave(&fx.pos, 24, 88, 48, 0, 128, 64, 16, EulerAngles::Zero, 1, true, false, (int)ShockwaveStyle::Normal);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
TriggerShockwave(&fx.pos, 24, 88, 48, 0, 128, 64, 16, EulerAngles((((~g_Level.Rooms[fx.roomNumber].flags) / 16) & 2) * 65536, 0.0f, 0.0f), 1, true, false, (int)ShockwaveStyle::Normal);
|
||||
}
|
||||
|
||||
KillEffect(fxNumber);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (probe.RoomNumber != fx.roomNumber)
|
||||
EffectNewRoom(fxNumber, probe.RoomNumber);
|
||||
if (pointColl.RoomNumber != fx.roomNumber)
|
||||
EffectNewRoom(fxNumber, pointColl.RoomNumber);
|
||||
|
||||
auto deltaPos = prevPos - fx.pos.Position;
|
||||
|
||||
if (Wibble & 4)
|
||||
{
|
||||
switch (fx.flag1)
|
||||
switch ((MissileType)fx.flag1)
|
||||
{
|
||||
default:
|
||||
case (int)MissileType::SethLarge:
|
||||
TriggerSethMissileFlame(fxNumber, 32 * deltaPos.x, 32 * deltaPos.y, 32 * deltaPos.z);
|
||||
case MissileType::SethLarge:
|
||||
TriggerSethMissileFlame(fxNumber, deltaPos.x * 32, deltaPos.y * 32, deltaPos.z * 32);
|
||||
break;
|
||||
|
||||
case (int)MissileType::Harpy:
|
||||
TriggerHarpyFlameFlame(fxNumber, 16 * deltaPos.x, 16 * deltaPos.y, 16 * deltaPos.z);
|
||||
case MissileType::Harpy:
|
||||
TriggerHarpyFlameFlame(fxNumber, deltaPos.x * 16, deltaPos.y * 16, deltaPos.z * 16);
|
||||
break;
|
||||
|
||||
case (int)MissileType::Demigod3Single:
|
||||
case (int)MissileType::Demigod3Radial:
|
||||
case (int)MissileType::Demigod2:
|
||||
TriggerDemigodMissileFlame(fxNumber, 16 * deltaPos.x, 16 * deltaPos.y, 16 * deltaPos.z);
|
||||
case MissileType::Demigod3Single:
|
||||
case MissileType::Demigod3Radial:
|
||||
case MissileType::Demigod2:
|
||||
TriggerDemigodMissileFlame(fxNumber, deltaPos.x * 16, deltaPos.y * 16, deltaPos.z * 16);
|
||||
break;
|
||||
|
||||
case (int)MissileType::Mutant:
|
||||
TriggerCrocgodMissileFlame(fxNumber, 16 * deltaPos.x, 16 * deltaPos.y, 16 * deltaPos.z);
|
||||
case MissileType::ClawMutantPlasma:
|
||||
for (int i = 0; i < 3; i++)
|
||||
SpawnClawMutantPlasmaFlameBall(fxNumber, Vector3(deltaPos.x, deltaPos.y * 16, deltaPos.z), Vector3::Zero, 10.0f);
|
||||
|
||||
break;
|
||||
|
||||
case MissileType::CrocgodMutant:
|
||||
TriggerCrocgodMissileFlame(fxNumber, deltaPos.x * 16, deltaPos.y * 16, deltaPos.z * 16);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fx.flag1 == (int)MissileType::ClawMutantPlasma)
|
||||
TriggerDynamicLight(fx.pos.Position.x, fx.pos.Position.y, fx.pos.Position.z, 8, 0, 64, 128);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,9 +10,10 @@ namespace TEN::Entities::Effects
|
|||
Demigod3Single = 3,
|
||||
Demigod3Radial = 4,
|
||||
Demigod2 = 5,
|
||||
Mutant = 6,
|
||||
CrocgodMutant = 6,
|
||||
SophiaLeighNormal = 7,
|
||||
SophiaLeighLarge = 8
|
||||
SophiaLeighLarge = 8,
|
||||
ClawMutantPlasma = 9
|
||||
};
|
||||
|
||||
void ControlEnemyMissile(short fxNumber);
|
||||
|
|
510
TombEngine/Objects/TR3/Entity/tr3_claw_mutant.cpp
Normal file
510
TombEngine/Objects/TR3/Entity/tr3_claw_mutant.cpp
Normal file
|
@ -0,0 +1,510 @@
|
|||
#include "framework.h"
|
||||
#include "Objects/TR3/Entity/tr3_claw_mutant.h"
|
||||
|
||||
#include "Game/animation.h"
|
||||
#include "Game/control/box.h"
|
||||
#include "Game/effects/effects.h"
|
||||
#include "Game/Lara/lara_helpers.h"
|
||||
#include "Math/Math.h"
|
||||
#include "Objects/Effects/enemy_missile.h"
|
||||
#include "Game/misc.h"
|
||||
#include "Game/people.h"
|
||||
#include "Specific/setup.h"
|
||||
|
||||
using namespace TEN::Entities::Effects;
|
||||
using namespace TEN::Math;
|
||||
|
||||
// ItemFlags[5] flag enables damage left (0 = enabled, 1 = disabled).
|
||||
// ItemFlags[6] flag enables damage right (0 = enabled, 1 = disabled).
|
||||
|
||||
namespace TEN::Entities::Creatures::TR3
|
||||
{
|
||||
constexpr auto CLAW_MUTANT_CLAW_ATTACK_DAMAGE = 100;
|
||||
constexpr auto CLAW_MUTANT_PLASMA_ATTACK_DAMAGE = 200;
|
||||
|
||||
constexpr auto CLAW_MUTANT_WALK_CHANCE = 1 / 64.0f;
|
||||
|
||||
constexpr auto CLAW_MUTANT_IDLE_CLAW_ATTACK_RANGE = SQUARE(BLOCK(1.5f));
|
||||
constexpr auto CLAW_MUTANT_IDLE_DUAL_CLAW_ATTACK_RANGE = SQUARE(BLOCK(1.5f));
|
||||
constexpr auto CLAW_MUTANT_WALK_CLAW_ATTACK_RANGE = SQUARE(BLOCK(1));
|
||||
constexpr auto CLAW_MUTANT_RUN_CLAW_ATTACK_RANGE = SQUARE(BLOCK(2));
|
||||
constexpr auto CLAW_MUTANT_PLASMA_ATTACK_RANGE = SQUARE(BLOCK(3));
|
||||
|
||||
constexpr auto CLAW_MUTANT_PLASMA_VELOCITY = 250;
|
||||
|
||||
constexpr auto CLAW_MUTANT_WALK_TURN_RATE_MAX = ANGLE(3.0f);
|
||||
constexpr auto CLAW_MUTANT_RUN_TURN_RATE_MAX = ANGLE(4.0f);
|
||||
|
||||
const auto ClawMutantLeftBite = BiteInfo(Vector3(19.0f, -13.0f, 3.0f), 7);
|
||||
const auto ClawMutantRightBite = BiteInfo(Vector3(19.0f, -13.0f, 3.0f), 4);
|
||||
const auto ClawMutantTailBite = BiteInfo(Vector3(-32.0f, -16.0f, -119.0f), 13);
|
||||
|
||||
enum ClawMutantState
|
||||
{
|
||||
CLAW_MUTANT_STATE_IDLE = 0,
|
||||
CLAW_MUTANT_STATE_WALK = 1,
|
||||
CLAW_MUTANT_STATE_RUN = 2,
|
||||
CLAW_MUTANT_STATE_RUN_CLAW_ATTACK = 3,
|
||||
CLAW_MUTANT_STATE_WALK_CLAW_ATTACK_LEFT = 4,
|
||||
CLAW_MUTANT_STATE_WALK_CLAW_ATTACK_RIGHT = 5,
|
||||
CLAW_MUTANT_STATE_IDLE_CLAW_ATTACK_LEFT = 6,
|
||||
CLAW_MUTANT_STATE_IDLE_CLAW_ATTACK_RIGHT = 7,
|
||||
CLAW_MUTANT_STATE_DEATH = 8,
|
||||
CLAW_MUTANT_STATE_IDLE_DUAL_CLAW_ATTACK = 9,
|
||||
CLAW_MUTANT_STATE_PLASMA_ATTACK = 10
|
||||
};
|
||||
|
||||
enum ClawMutantAnim
|
||||
{
|
||||
CLAW_MUTANT_ANIM_IDLE = 0,
|
||||
CLAW_MUTANT_ANIM_IDLE_TO_WALK_LEFT = 1,
|
||||
CLAW_MUTANT_ANIM_IDLE_TO_RUN_LEFT = 2,
|
||||
CLAW_MUTANT_ANIM_WALK_TO_IDLE_RIGHT = 3,
|
||||
CLAW_MUTANT_ANIM_WALK_TO_IDLE_LEFT = 4,
|
||||
CLAW_MUTANT_ANIM_RUN_TO_IDLE_RIGHT = 5,
|
||||
CLAW_MUTANT_ANIM_RUN_TO_IDLE_LEFT = 6,
|
||||
CLAW_MUTANT_ANIM_WALK = 7,
|
||||
CLAW_MUTANT_ANIM_WALK_TO_RUN = 8,
|
||||
CLAW_MUTANT_ANIM_RUN = 9,
|
||||
CLAW_MUTANT_ANIM_RUN_TO_WALK_LEFT = 10,
|
||||
CLAW_MUTANT_ANIM_RUN_TO_WALK_RIGHT = 11,
|
||||
CLAW_MUTANT_ANIM_RUN_CLAW_ATTACK = 12,
|
||||
CLAW_MUTANT_ANIM_RUN_CLAW_ATTACK_CANCEL = 13,
|
||||
CLAW_MUTANT_ANIM_IDLE_CLAW_ATTACK_LEFT = 14,
|
||||
CLAW_MUTANT_ANIM_IDLE_CLAW_ATTACK_RIGHT = 15,
|
||||
CLAW_MUTANT_ANIM_IDLE_DUAL_CLAW_ATTACK = 16,
|
||||
CLAW_MUTANT_ANIM_WALK_CLAW_ATTACK_LEFT = 17,
|
||||
CLAW_MUTANT_ANIM_WALK_CLAW_ATTACK_RIGHT = 18,
|
||||
CLAW_MUTANT_ANIM_PLASMA_ATTACK = 19,
|
||||
CLAW_MUTANT_ANIM_DEATH = 20
|
||||
};
|
||||
|
||||
static void SpawnClawMutantPlasma(int itemNumber)
|
||||
{
|
||||
auto& plasma = *GetFreeParticle();
|
||||
|
||||
plasma.on = true;
|
||||
plasma.sB = 255;
|
||||
plasma.sG = 48 + (GetRandomControl() & 31);
|
||||
plasma.sR = 48;
|
||||
|
||||
plasma.dB = 192 + (GetRandomControl() & 63);
|
||||
plasma.dG = 128 + (GetRandomControl() & 63);
|
||||
plasma.dR = 32;
|
||||
|
||||
plasma.colFadeSpeed = 12 + (GetRandomControl() & 3);
|
||||
plasma.fadeToBlack = 8;
|
||||
plasma.sLife =
|
||||
plasma.life = (GetRandomControl() & 7) + 24;
|
||||
|
||||
plasma.blendMode = BLEND_MODES::BLENDMODE_ADDITIVE;
|
||||
|
||||
plasma.extras = 0;
|
||||
plasma.dynamic = -1;
|
||||
|
||||
plasma.x = ((GetRandomControl() & 15) - 8);
|
||||
plasma.y = 0;
|
||||
plasma.z = ((GetRandomControl() & 15) - 8);
|
||||
|
||||
plasma.xVel = ((GetRandomControl() & 31) - 16);
|
||||
plasma.yVel = (GetRandomControl() & 15) + 16;
|
||||
plasma.zVel = ((GetRandomControl() & 31) - 16);
|
||||
plasma.friction = 3;
|
||||
|
||||
if (Random::TestProbability(1 / 2.0f))
|
||||
{
|
||||
plasma.flags = SP_SCALE | SP_DEF | SP_ROTATE | SP_EXPDEF | SP_ITEM | SP_NODEATTACH;
|
||||
plasma.rotAng = GetRandomControl() & 4095;
|
||||
|
||||
if (Random::TestProbability(1 / 2.0f))
|
||||
{
|
||||
plasma.rotAdd = -(GetRandomControl() & 15) - 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
plasma.rotAdd = (GetRandomControl() & 15) + 16;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
plasma.flags = SP_SCALE | SP_DEF | SP_EXPDEF | SP_ITEM | SP_NODEATTACH;
|
||||
}
|
||||
|
||||
plasma.gravity = (GetRandomControl() & 31) + 16;
|
||||
plasma.maxYvel = (GetRandomControl() & 7) + 16;
|
||||
|
||||
plasma.fxObj = itemNumber;
|
||||
plasma.nodeNumber = ParticleNodeOffsetIDs::NodeClawMutantPlasma;
|
||||
|
||||
plasma.spriteIndex = Objects[ID_DEFAULT_SPRITES].meshIndex;
|
||||
plasma.scalar = 1;
|
||||
int size = (GetRandomControl() & 31) + 64;
|
||||
plasma.size =
|
||||
plasma.sSize = size;
|
||||
plasma.dSize = size / 4;
|
||||
}
|
||||
|
||||
static void SpawnClawMutantPlasmaBall(ItemInfo& item)
|
||||
{
|
||||
const auto& creature = *GetCreatureInfo(&item);
|
||||
|
||||
int plasmaBall = CreateNewEffect(item.RoomNumber);
|
||||
if (plasmaBall == NO_ITEM)
|
||||
return;
|
||||
|
||||
auto enemyPos = creature.Enemy->Pose.Position;
|
||||
if (creature.Enemy->IsLara() && GetLaraInfo(creature.Enemy)->Control.IsLow)
|
||||
{
|
||||
enemyPos.y -= CLICK(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
enemyPos.y -= CLICK(2);
|
||||
}
|
||||
|
||||
auto& fx = EffectList[plasmaBall];
|
||||
|
||||
auto jointPos = GetJointPosition(item, ClawMutantTailBite.meshNum, ClawMutantTailBite.Position);
|
||||
auto orient = Geometry::GetOrientToPoint(jointPos.ToVector3(), enemyPos.ToVector3());
|
||||
|
||||
fx.pos.Position = jointPos;
|
||||
fx.pos.Orientation.x = orient.x;
|
||||
fx.pos.Orientation.y = orient.y;
|
||||
fx.objectNumber = ID_ENERGY_BUBBLES;
|
||||
fx.color = Vector4::Zero;
|
||||
fx.speed = CLAW_MUTANT_PLASMA_VELOCITY;
|
||||
fx.flag2 = CLAW_MUTANT_PLASMA_ATTACK_DAMAGE;
|
||||
fx.flag1 = (int)MissileType::ClawMutantPlasma;
|
||||
fx.fallspeed = 0;
|
||||
}
|
||||
|
||||
static void SpawnMutantPlasmaLight(ItemInfo& item)
|
||||
{
|
||||
int bright = item.Animation.FrameNumber - GetAnimData(item).frameBase;
|
||||
if (bright > 16)
|
||||
{
|
||||
bright = GetAnimData(item).frameBase + 28 + 16 - item.Animation.FrameNumber;
|
||||
if (bright > 16)
|
||||
bright = 16;
|
||||
}
|
||||
|
||||
if (bright > 0)
|
||||
{
|
||||
auto pos = GetJointPosition(item, 13, Vector3i(-32, -16, -192));
|
||||
int rnd = GetRandomControl();
|
||||
byte r, g, b;
|
||||
|
||||
b = 31 - ((rnd / 16) & 3);
|
||||
g = 24 - ((rnd / 64) & 3);
|
||||
r = rnd & 7;
|
||||
|
||||
r = (r * bright) / 16;
|
||||
g = (g * bright) / 16;
|
||||
b = (b * bright) / 16;
|
||||
TriggerDynamicLight(pos.x, pos.y, pos.z, bright, r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
static void DamageTargetWithClaw(ItemInfo& source, ItemInfo& target)
|
||||
{
|
||||
if (source.ItemFlags[5] == 0 && source.TouchBits.Test(ClawMutantLeftBite.meshNum))
|
||||
{
|
||||
DoDamage(&target, CLAW_MUTANT_CLAW_ATTACK_DAMAGE / 2);
|
||||
CreatureEffect2(&source, ClawMutantLeftBite, 10, source.Pose.Orientation.y, DoBloodSplat);
|
||||
source.ItemFlags[5] = 1;
|
||||
}
|
||||
|
||||
if (source.ItemFlags[6] == 0 && source.TouchBits.Test(ClawMutantRightBite.meshNum))
|
||||
{
|
||||
DoDamage(&target, CLAW_MUTANT_CLAW_ATTACK_DAMAGE / 2);
|
||||
CreatureEffect2(&source, ClawMutantRightBite, 10, source.Pose.Orientation.y, DoBloodSplat);
|
||||
source.ItemFlags[6] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void SpawnClawMutantPlasmaFlameBall(int fxNumber, const Vector3& vel, const Vector3& offset, float life)
|
||||
{
|
||||
auto& plasma = *GetFreeParticle();
|
||||
|
||||
plasma.on = true;
|
||||
plasma.sB = 255;
|
||||
plasma.sG = 48 + (GetRandomControl() & 31);
|
||||
plasma.sR = 48;
|
||||
|
||||
plasma.dB = 192 + (GetRandomControl() & 63);
|
||||
plasma.dG = 128 + (GetRandomControl() & 63);
|
||||
plasma.dR = 32;
|
||||
|
||||
plasma.colFadeSpeed = 12 + (GetRandomControl() & 3);
|
||||
plasma.fadeToBlack = 8;
|
||||
plasma.sLife =
|
||||
plasma.life = (GetRandomControl() & 7) + life;
|
||||
|
||||
plasma.blendMode = BLENDMODE_ADDITIVE;
|
||||
|
||||
plasma.extras = 0;
|
||||
plasma.dynamic = -1;
|
||||
|
||||
plasma.x = offset.x + ((GetRandomControl() & 15) - 8);
|
||||
plasma.y = 0;
|
||||
plasma.z = offset.z + ((GetRandomControl() & 15) - 8);
|
||||
|
||||
plasma.xVel = vel.x;
|
||||
plasma.yVel = vel.y;
|
||||
plasma.zVel = vel.z;
|
||||
plasma.friction = 5;
|
||||
|
||||
if (Random::TestProbability(1 / 2.0f))
|
||||
{
|
||||
plasma.flags = SP_SCALE | SP_DEF | SP_ROTATE | SP_EXPDEF | SP_FX;
|
||||
plasma.rotAng = GetRandomControl() & 4095;
|
||||
|
||||
if (Random::TestProbability(1 / 2.0f))
|
||||
{
|
||||
plasma.rotAdd = -(GetRandomControl() & 15) - 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
plasma.rotAdd = (GetRandomControl() & 15) + 16;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
plasma.flags = SP_SCALE | SP_DEF | SP_EXPDEF | SP_FX;
|
||||
}
|
||||
|
||||
plasma.fxObj = fxNumber;
|
||||
plasma.spriteIndex = Objects[ID_DEFAULT_SPRITES].meshIndex;
|
||||
plasma.scalar = 1;
|
||||
plasma.gravity =
|
||||
plasma.maxYvel = 0;
|
||||
|
||||
int size = (GetRandomControl() & 31) + 64;
|
||||
plasma.size =
|
||||
plasma.sSize = size;
|
||||
plasma.dSize /= 16;
|
||||
|
||||
plasma.yVel = (GetRandomControl() & 511) - 256;
|
||||
plasma.xVel *= 2;
|
||||
plasma.zVel *= 2;
|
||||
plasma.scalar = 2;
|
||||
plasma.friction = 85;
|
||||
plasma.gravity = 22;
|
||||
}
|
||||
|
||||
void ClawMutantControl(short itemNumber)
|
||||
{
|
||||
if (!CreatureActive(itemNumber))
|
||||
return;
|
||||
|
||||
auto& item = g_Level.Items[itemNumber];
|
||||
auto& object = Objects[item.ObjectNumber];
|
||||
auto& creature = *GetCreatureInfo(&item);
|
||||
|
||||
short headingAngle = 0;
|
||||
auto extraHeadRot = EulerAngles::Zero;
|
||||
auto extraTorsoRot = EulerAngles::Zero;
|
||||
|
||||
if (item.HitPoints <= 0)
|
||||
{
|
||||
if (item.Animation.ActiveState != CLAW_MUTANT_STATE_DEATH)
|
||||
SetAnimation(&item, CLAW_MUTANT_ANIM_DEATH);
|
||||
|
||||
int frameEnd = GetAnimData(item, CLAW_MUTANT_ANIM_DEATH).frameEnd;
|
||||
if (item.Animation.FrameNumber >= frameEnd)
|
||||
CreatureDie(itemNumber, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (item.AIBits)
|
||||
GetAITarget(&creature);
|
||||
|
||||
AI_INFO ai;
|
||||
CreatureAIInfo(&item, &ai);
|
||||
GetCreatureMood(&item, &ai, ai.zoneNumber == ai.enemyZone ? true : false);
|
||||
CreatureMood(&item, &ai, ai.zoneNumber == ai.enemyZone ? true : false);
|
||||
|
||||
headingAngle = CreatureTurn(&item, creature.MaxTurn);
|
||||
bool canShoot = (Targetable(&item, &ai) &&
|
||||
((ai.distance > CLAW_MUTANT_PLASMA_ATTACK_RANGE && !item.ItemFlags[0]) || ai.zoneNumber != ai.enemyZone));
|
||||
|
||||
switch (item.Animation.ActiveState)
|
||||
{
|
||||
case CLAW_MUTANT_STATE_IDLE:
|
||||
item.ItemFlags[5] = 0;
|
||||
item.ItemFlags[6] = 0;
|
||||
creature.MaxTurn = 0;
|
||||
|
||||
if (item.AIBits & GUARD)
|
||||
{
|
||||
extraHeadRot.y = AIGuard(&creature);
|
||||
item.Animation.TargetState = CLAW_MUTANT_STATE_IDLE;
|
||||
break;
|
||||
}
|
||||
else if (item.AIBits & PATROL1)
|
||||
{
|
||||
extraHeadRot.y = 0;
|
||||
item.Animation.TargetState = CLAW_MUTANT_STATE_WALK;
|
||||
}
|
||||
else if (creature.Mood == MoodType::Escape)
|
||||
{
|
||||
item.Animation.TargetState = CLAW_MUTANT_STATE_RUN;
|
||||
}
|
||||
else if (ai.bite && ai.distance < CLAW_MUTANT_IDLE_CLAW_ATTACK_RANGE)
|
||||
{
|
||||
extraTorsoRot.x = ai.xAngle;
|
||||
extraTorsoRot.y = ai.angle;
|
||||
|
||||
if (ai.angle < 0)
|
||||
{
|
||||
item.Animation.TargetState = CLAW_MUTANT_STATE_IDLE_CLAW_ATTACK_LEFT;
|
||||
}
|
||||
else
|
||||
{
|
||||
item.Animation.TargetState = CLAW_MUTANT_STATE_IDLE_CLAW_ATTACK_RIGHT;
|
||||
}
|
||||
}
|
||||
else if (ai.bite && ai.distance < CLAW_MUTANT_IDLE_DUAL_CLAW_ATTACK_RANGE)
|
||||
{
|
||||
extraTorsoRot.x = ai.xAngle;
|
||||
extraTorsoRot.y = ai.angle;
|
||||
item.Animation.TargetState = CLAW_MUTANT_STATE_IDLE_DUAL_CLAW_ATTACK;
|
||||
}
|
||||
else if (canShoot)
|
||||
{
|
||||
item.Animation.TargetState = CLAW_MUTANT_STATE_PLASMA_ATTACK;
|
||||
}
|
||||
else if (creature.Mood == MoodType::Bored)
|
||||
{
|
||||
if (Random::TestProbability(CLAW_MUTANT_WALK_CHANCE))
|
||||
item.Animation.TargetState = CLAW_MUTANT_STATE_WALK;
|
||||
}
|
||||
else if (item.Animation.RequiredState != NO_STATE)
|
||||
{
|
||||
item.Animation.TargetState = item.Animation.RequiredState;
|
||||
}
|
||||
else
|
||||
{
|
||||
item.Animation.TargetState = CLAW_MUTANT_STATE_RUN;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case CLAW_MUTANT_STATE_WALK:
|
||||
item.ItemFlags[5] = 0;
|
||||
item.ItemFlags[6] = 0;
|
||||
creature.MaxTurn = CLAW_MUTANT_WALK_TURN_RATE_MAX;
|
||||
|
||||
if (ai.ahead)
|
||||
extraHeadRot.y = ai.angle;
|
||||
|
||||
if (item.AIBits & PATROL1)
|
||||
{
|
||||
item.Animation.TargetState = CLAW_MUTANT_STATE_WALK;
|
||||
extraHeadRot.y = 0;
|
||||
}
|
||||
else if (ai.bite && ai.distance < CLAW_MUTANT_WALK_CLAW_ATTACK_RANGE)
|
||||
{
|
||||
if (ai.angle < 0)
|
||||
{
|
||||
item.Animation.TargetState = CLAW_MUTANT_STATE_WALK_CLAW_ATTACK_LEFT;
|
||||
}
|
||||
else
|
||||
{
|
||||
item.Animation.TargetState = CLAW_MUTANT_STATE_WALK_CLAW_ATTACK_RIGHT;
|
||||
}
|
||||
}
|
||||
else if (canShoot)
|
||||
{
|
||||
item.Animation.TargetState = CLAW_MUTANT_STATE_IDLE;
|
||||
}
|
||||
else if (creature.Mood == MoodType::Escape || creature.Mood == MoodType::Attack)
|
||||
{
|
||||
item.Animation.TargetState = CLAW_MUTANT_STATE_RUN;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case CLAW_MUTANT_STATE_RUN:
|
||||
item.ItemFlags[5] = 0;
|
||||
item.ItemFlags[6] = 0;
|
||||
creature.MaxTurn = CLAW_MUTANT_RUN_TURN_RATE_MAX;
|
||||
|
||||
if (ai.ahead)
|
||||
extraHeadRot.y = ai.angle;
|
||||
|
||||
if (item.AIBits & GUARD)
|
||||
{
|
||||
item.Animation.TargetState = CLAW_MUTANT_STATE_IDLE;
|
||||
}
|
||||
else if (creature.Mood == MoodType::Bored)
|
||||
{
|
||||
item.Animation.TargetState = CLAW_MUTANT_STATE_IDLE;
|
||||
}
|
||||
else if (creature.Flags != 0 && ai.ahead)
|
||||
{
|
||||
item.Animation.TargetState = CLAW_MUTANT_STATE_IDLE;
|
||||
}
|
||||
else if (ai.bite && ai.distance < CLAW_MUTANT_RUN_CLAW_ATTACK_RANGE)
|
||||
{
|
||||
if (creature.Enemy != nullptr && creature.Enemy->Animation.Velocity.z == 0.0f)
|
||||
{
|
||||
item.Animation.TargetState = CLAW_MUTANT_STATE_IDLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
item.Animation.TargetState = CLAW_MUTANT_STATE_RUN_CLAW_ATTACK;
|
||||
}
|
||||
}
|
||||
else if (canShoot)
|
||||
{
|
||||
item.Animation.TargetState = CLAW_MUTANT_STATE_IDLE;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case CLAW_MUTANT_STATE_WALK_CLAW_ATTACK_LEFT:
|
||||
case CLAW_MUTANT_STATE_WALK_CLAW_ATTACK_RIGHT:
|
||||
case CLAW_MUTANT_STATE_RUN_CLAW_ATTACK:
|
||||
case CLAW_MUTANT_STATE_IDLE_DUAL_CLAW_ATTACK:
|
||||
case CLAW_MUTANT_STATE_IDLE_CLAW_ATTACK_LEFT:
|
||||
case CLAW_MUTANT_STATE_IDLE_CLAW_ATTACK_RIGHT:
|
||||
if (ai.ahead)
|
||||
{
|
||||
extraTorsoRot.x = ai.xAngle;
|
||||
extraTorsoRot.y = ai.angle;
|
||||
}
|
||||
|
||||
DamageTargetWithClaw(item, *creature.Enemy);
|
||||
break;
|
||||
|
||||
case CLAW_MUTANT_STATE_PLASMA_ATTACK:
|
||||
if (ai.ahead)
|
||||
{
|
||||
extraTorsoRot.x = ai.xAngle;
|
||||
extraTorsoRot.y = ai.angle;
|
||||
}
|
||||
|
||||
if (item.Animation.FrameNumber == GetFrameIndex(&item, 0) && Random::TestProbability(1 / 4.0f) == 0)
|
||||
item.ItemFlags[0] = 1;
|
||||
|
||||
if (item.Animation.FrameNumber < GetFrameIndex(&item, 28))
|
||||
{
|
||||
SpawnClawMutantPlasma(itemNumber);
|
||||
}
|
||||
else if (item.Animation.FrameNumber == GetFrameIndex(&item, 28))
|
||||
{
|
||||
SpawnClawMutantPlasmaBall(item);
|
||||
}
|
||||
|
||||
SpawnMutantPlasmaLight(item);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CreatureJoint(&item, 0, extraTorsoRot.x);
|
||||
CreatureJoint(&item, 1, extraTorsoRot.y);
|
||||
CreatureJoint(&item, 2, extraHeadRot.y);
|
||||
CreatureAnimation(itemNumber, headingAngle, 0);
|
||||
}
|
||||
}
|
7
TombEngine/Objects/TR3/Entity/tr3_claw_mutant.h
Normal file
7
TombEngine/Objects/TR3/Entity/tr3_claw_mutant.h
Normal file
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
namespace TEN::Entities::Creatures::TR3
|
||||
{
|
||||
void ClawMutantControl(short itemNumber);
|
||||
void SpawnClawMutantPlasmaFlameBall(int fxNumber, const Vector3& vel, const Vector3& offset, float life);
|
||||
}
|
|
@ -17,11 +17,11 @@
|
|||
#include "Objects/TR3/Entity/WaspMutant.h" // OK
|
||||
#include "Objects/TR3/Entity/tr3_tony.h" // OK
|
||||
#include "Objects/TR3/Entity/tr3_civvy.h" // OK
|
||||
#include "Objects/TR3/Entity/tr3_claw_mutant.h" // OK
|
||||
#include "Objects/TR3/Entity/tr3_cobra.h" // OK
|
||||
#include "Objects/TR3/Entity/tr3_fish_emitter.h" // OK
|
||||
#include "Objects/TR3/Entity/tr3_flamethrower.h" // OK
|
||||
#include "Objects/TR3/Entity/tr3_monkey.h" // OK
|
||||
|
||||
#include "Objects/TR3/Entity/tr3_mp_gun.h" // OK
|
||||
#include "Objects/TR3/Entity/tr3_mp_stick.h" // OK
|
||||
#include "Objects/TR3/Entity/tr3_raptor.h" // OK
|
||||
|
@ -381,6 +381,22 @@ static void StartEntity(ObjectInfo* obj)
|
|||
obj->SetBoneRotationFlags(1, ROT_X | ROT_Z);
|
||||
obj->SetupHitEffect();
|
||||
}
|
||||
|
||||
obj = &Objects[ID_CLAW_MUTANT];
|
||||
if (obj->loaded)
|
||||
{
|
||||
obj->initialise = InitialiseCreature;
|
||||
obj->control = ClawMutantControl;
|
||||
obj->collision = CreatureCollision;
|
||||
obj->shadowType = ShadowMode::All;
|
||||
obj->HitPoints = 130;
|
||||
obj->intelligent = true;
|
||||
obj->radius = 204;
|
||||
obj->pivotLength = 0;
|
||||
obj->SetBoneRotationFlags(0, ROT_X | ROT_Z);
|
||||
obj->SetBoneRotationFlags(7, ROT_Y);
|
||||
obj->SetupHitEffect();
|
||||
}
|
||||
}
|
||||
|
||||
static void StartObject(ObjectInfo* obj)
|
||||
|
|
|
@ -228,8 +228,8 @@ enum GAME_OBJECT_ID : short
|
|||
ID_BOSS_SHIELD,
|
||||
ID_BOSS_EXPLOSION_SHOCKWAVE,
|
||||
ID_BOSS_EXPLOSION_RING,
|
||||
|
||||
ID_WASP_MUTANT = 294,
|
||||
ID_CLAW_MUTANT = 293,
|
||||
ID_WASP_MUTANT,
|
||||
|
||||
ID_SPRINGBOARD = 320,
|
||||
ID_ROLLING_SPINDLE,
|
||||
|
|
|
@ -756,8 +756,7 @@ namespace TEN::Renderer
|
|||
for (fxNum = r->fxNumber; fxNum != NO_ITEM; fxNum = EffectList[fxNum].nextFx)
|
||||
{
|
||||
FX_INFO *fx = &EffectList[fxNum];
|
||||
|
||||
if (fx->objectNumber < 0)
|
||||
if (fx->objectNumber < 0 || fx->color.w <= 0)
|
||||
continue;
|
||||
|
||||
ObjectInfo *obj = &Objects[fx->objectNumber];
|
||||
|
|
|
@ -235,6 +235,7 @@ The following constants are inside ObjID.
|
|||
BOSS_SHIELD
|
||||
BOSS_EXPLOSION_SHOCKWAVE
|
||||
BOSS_EXPLOSION_RING
|
||||
CLAW_MUTANT
|
||||
WASP_MUTANT
|
||||
SPRINGBOARD
|
||||
ROLLING_SPINDLE
|
||||
|
@ -1406,6 +1407,7 @@ static const std::unordered_map<std::string, GAME_OBJECT_ID> kObjIDs {
|
|||
{ "BOSS_SHIELD", ID_BOSS_SHIELD },
|
||||
{ "BOSS_EXPLOSION_SHOCKWAVE", ID_BOSS_EXPLOSION_SHOCKWAVE },
|
||||
{ "BOSS_EXPLOSION_RING", ID_BOSS_EXPLOSION_RING },
|
||||
{ "CLAW_MUTANT", ID_CLAW_MUTANT },
|
||||
{ "WASP_MUTANT", ID_WASP_MUTANT },
|
||||
{ "SPRINGBOARD", ID_SPRINGBOARD },
|
||||
{ "ROLLING_SPINDLE", ID_ROLLING_SPINDLE },
|
||||
|
|
|
@ -321,6 +321,7 @@ CALL gen.bat</Command>
|
|||
<ClInclude Include="Objects\TR3\Entity\PunaBoss.h" />
|
||||
<ClInclude Include="Objects\TR3\Entity\Shiva.h" />
|
||||
<ClInclude Include="Objects\TR3\Entity\SophiaLeigh.h" />
|
||||
<ClInclude Include="Objects\TR3\Entity\tr3_claw_mutant.h" />
|
||||
<ClInclude Include="Objects\TR3\Entity\WaspMutant.h" />
|
||||
<ClInclude Include="Objects\TR3\Entity\tr3_civvy.h" />
|
||||
<ClInclude Include="Objects\TR3\Entity\tr3_cobra.h" />
|
||||
|
@ -757,6 +758,7 @@ CALL gen.bat</Command>
|
|||
<ClCompile Include="Objects\TR3\Entity\Shiva.cpp" />
|
||||
<ClCompile Include="Objects\TR3\Entity\SophiaLeigh.cpp" />
|
||||
<ClCompile Include="Objects\TR3\Entity\tr3_civvy.cpp" />
|
||||
<ClCompile Include="Objects\TR3\Entity\tr3_claw_mutant.cpp" />
|
||||
<ClCompile Include="Objects\TR3\Entity\tr3_cobra.cpp" />
|
||||
<ClCompile Include="Objects\TR3\Entity\tr3_fish_emitter.cpp" />
|
||||
<ClCompile Include="Objects\TR3\Entity\tr3_flamethrower.cpp" />
|
||||
|
|
|
@ -329,6 +329,7 @@ CALL gen.bat</Command>
|
|||
<ClInclude Include="Objects\TR3\Entity\tr3_fish_emitter.h" />
|
||||
<ClInclude Include="Objects\TR3\Entity\tr3_flamethrower.h" />
|
||||
<ClInclude Include="Objects\TR3\Entity\tr3_monkey.h" />
|
||||
<ClInclude Include="Objects\TR3\Entity\tr3_claw_mutant.h" />
|
||||
<ClInclude Include="Objects\TR3\Entity\tr3_mp_gun.h" />
|
||||
<ClInclude Include="Objects\TR3\Entity\tr3_mp_stick.h" />
|
||||
<ClInclude Include="Objects\TR3\Entity\tr3_raptor.h" />
|
||||
|
@ -760,6 +761,7 @@ CALL gen.bat</Command>
|
|||
<ClCompile Include="Objects\TR3\Entity\tr3_fish_emitter.cpp" />
|
||||
<ClCompile Include="Objects\TR3\Entity\tr3_flamethrower.cpp" />
|
||||
<ClCompile Include="Objects\TR3\Entity\tr3_monkey.cpp" />
|
||||
<ClCompile Include="Objects\TR3\Entity\tr3_claw_mutant.cpp" />
|
||||
<ClCompile Include="Objects\TR3\Entity\tr3_mp_gun.cpp" />
|
||||
<ClCompile Include="Objects\TR3\Entity\tr3_mp_stick.cpp" />
|
||||
<ClCompile Include="Objects\TR3\Entity\tr3_raptor.cpp" />
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue