mirror of
https://github.com/TombEngine/TombEngine.git
synced 2025-05-06 19:01:06 +03:00
Implemented Mutant and Locusts
- Added ItemNearTarget().
This commit is contained in:
parent
b58fc1473e
commit
2b2a58d44c
17 changed files with 816 additions and 140 deletions
|
@ -36,6 +36,54 @@ typedef enum ZoneType
|
||||||
ZONE_APE, // only 2 click climb
|
ZONE_APE, // only 2 click climb
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct OBJECT_BONES
|
||||||
|
{
|
||||||
|
short bone0;
|
||||||
|
short bone1;
|
||||||
|
short bone2;
|
||||||
|
short bone3;
|
||||||
|
|
||||||
|
OBJECT_BONES()
|
||||||
|
{
|
||||||
|
this->bone0 = 0;
|
||||||
|
this->bone1 = 0;
|
||||||
|
this->bone2 = 0;
|
||||||
|
this->bone3 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
OBJECT_BONES(short all)
|
||||||
|
{
|
||||||
|
this->bone0 = all;
|
||||||
|
this->bone1 = all;
|
||||||
|
this->bone2 = -all;
|
||||||
|
this->bone3 = -all;
|
||||||
|
}
|
||||||
|
|
||||||
|
OBJECT_BONES(short angleY, short angleX)
|
||||||
|
{
|
||||||
|
this->bone0 = angleY;
|
||||||
|
this->bone1 = angleX;
|
||||||
|
this->bone2 = angleY;
|
||||||
|
this->bone3 = angleX;
|
||||||
|
}
|
||||||
|
|
||||||
|
OBJECT_BONES(short angleY, short angleX, bool total)
|
||||||
|
{
|
||||||
|
this->bone0 = angleY;
|
||||||
|
this->bone1 = angleX;
|
||||||
|
if (total)
|
||||||
|
{
|
||||||
|
this->bone2 = angleY;
|
||||||
|
this->bone3 = angleX;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this->bone2 = 0;
|
||||||
|
this->bone3 = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct BOX_NODE
|
typedef struct BOX_NODE
|
||||||
{
|
{
|
||||||
short exitBox;
|
short exitBox;
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
#include "tr5_rats_emitter.h"
|
#include "tr5_rats_emitter.h"
|
||||||
#include "tr5_bats_emitter.h"
|
#include "tr5_bats_emitter.h"
|
||||||
#include "tr5_spider_emitter.h"
|
#include "tr5_spider_emitter.h"
|
||||||
|
#include "tr4_locusts.h"
|
||||||
|
|
||||||
short ShatterSounds[18][10] =
|
short ShatterSounds[18][10] =
|
||||||
{
|
{
|
||||||
|
@ -512,6 +513,7 @@ GAME_STATUS ControlPhase(int numFrames, int demoMode)
|
||||||
UpdateBats();
|
UpdateBats();
|
||||||
UpdateSpiders();
|
UpdateSpiders();
|
||||||
UpdateShockwaves();
|
UpdateShockwaves();
|
||||||
|
UpdateLocusts();
|
||||||
//Legacy_UpdateLightning();
|
//Legacy_UpdateLightning();
|
||||||
AnimateWaterfalls();
|
AnimateWaterfalls();
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "tr5_bats_emitter.h"
|
#include "tr5_bats_emitter.h"
|
||||||
#include "tr5_spider_emitter.h"
|
#include "tr5_spider_emitter.h"
|
||||||
|
|
||||||
|
constexpr auto ITEM_RADIUS_YMAX = SECTOR(3);
|
||||||
int wf = 256;
|
int wf = 256;
|
||||||
extern std::deque<FOOTPRINT_STRUCT> footprints;
|
extern std::deque<FOOTPRINT_STRUCT> footprints;
|
||||||
short FXType;
|
short FXType;
|
||||||
|
@ -474,51 +475,85 @@ void ControlWaterfallMist(short itemNumber) // ControlWaterfallMist
|
||||||
|
|
||||||
short DoBloodSplat(int x, int y, int z, short a4, short a5, short roomNumber)
|
short DoBloodSplat(int x, int y, int z, short a4, short a5, short roomNumber)
|
||||||
{
|
{
|
||||||
GetFloor(x, y, z, &roomNumber);
|
short roomNum = roomNumber;
|
||||||
if (Rooms[roomNumber].flags & ENV_FLAG_WATER)
|
GetFloor(x, y, z, &roomNum);
|
||||||
|
if (Rooms[roomNum].flags & ENV_FLAG_WATER)
|
||||||
TriggerUnderwaterBlood(x, y, z, a4);
|
TriggerUnderwaterBlood(x, y, z, a4);
|
||||||
else
|
else
|
||||||
TriggerBlood(x, y, z, a5 >> 4, a4);
|
TriggerBlood(x, y, z, a5 >> 4, a4);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ItemNearLara(PHD_3DPOS* pos, int radius)
|
static bool ItemCollide(int value, int radius)
|
||||||
{
|
{
|
||||||
int dx = pos->xPos - LaraItem->pos.xPos;
|
return value >= -radius && value <= radius;
|
||||||
int dy = pos->yPos - LaraItem->pos.yPos;
|
}
|
||||||
int dz = pos->zPos - LaraItem->pos.zPos;
|
|
||||||
|
|
||||||
if (dx >= -radius
|
static bool ItemInRange(int x, int z, int radius)
|
||||||
&& dx <= radius
|
{
|
||||||
&& dz >= -radius
|
return (SQUARE(x) + SQUARE(z)) <= SQUARE(radius);
|
||||||
&& dz <= radius
|
}
|
||||||
&& dy >= -3072
|
|
||||||
&& dy <= 3072
|
|
||||||
&& SQUARE(dx) + SQUARE(dz) <= SQUARE(radius))
|
|
||||||
{
|
|
||||||
short* bounds = GetBoundsAccurate(LaraItem);
|
|
||||||
if (dy >= bounds[2] && dy <= bounds[3] + 100)
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
bool ItemNearLara(PHD_3DPOS* pos, int radius)
|
||||||
|
{
|
||||||
|
ANIM_FRAME* bounds;
|
||||||
|
GAME_VECTOR target;
|
||||||
|
target.x = pos->xPos - LaraItem->pos.xPos;
|
||||||
|
target.y = pos->yPos - LaraItem->pos.yPos;
|
||||||
|
target.z = pos->zPos - LaraItem->pos.zPos;
|
||||||
|
if (!ItemCollide(target.y, ITEM_RADIUS_YMAX))
|
||||||
|
return false;
|
||||||
|
if (!ItemCollide(target.x, radius) || !ItemCollide(target.z, radius))
|
||||||
|
return false;
|
||||||
|
if (!ItemInRange(target.x, target.z, radius))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bounds = (ANIM_FRAME*)GetBoundsAccurate(LaraItem);
|
||||||
|
if (target.y >= bounds->MinY && target.y <= (bounds->MaxY + LARA_RAD))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ItemNearTarget(PHD_3DPOS* src, ITEM_INFO* target, int radius)
|
||||||
|
{
|
||||||
|
ANIM_FRAME* bounds;
|
||||||
|
PHD_VECTOR pos;
|
||||||
|
pos.x = src->xPos - target->pos.xPos;
|
||||||
|
pos.y = src->yPos - target->pos.yPos;
|
||||||
|
pos.z = src->zPos - target->pos.zPos;
|
||||||
|
if (!ItemCollide(pos.y, ITEM_RADIUS_YMAX))
|
||||||
|
return false;
|
||||||
|
if (!ItemCollide(pos.x, radius) || !ItemCollide(pos.z, radius))
|
||||||
|
return false;
|
||||||
|
if (!ItemInRange(pos.x, pos.z, radius))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bounds = (ANIM_FRAME*)GetBoundsAccurate(target);
|
||||||
|
if (pos.y >= bounds->MinY && pos.y <= bounds->MaxY)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Richochet(PHD_3DPOS* pos)
|
void Richochet(PHD_3DPOS* pos)
|
||||||
{
|
{
|
||||||
short angle = mGetAngle(pos->zPos, pos->xPos, LaraItem->pos.zPos, LaraItem->pos.xPos);
|
short angle = mGetAngle(pos->zPos, pos->xPos, LaraItem->pos.zPos, LaraItem->pos.xPos);
|
||||||
TriggerRicochetSpark((GAME_VECTOR*)pos, angle / 16, 3, 0);
|
GAME_VECTOR target;
|
||||||
|
target.x = pos->xPos;
|
||||||
|
target.y = pos->yPos;
|
||||||
|
target.z = pos->zPos;
|
||||||
|
TriggerRicochetSpark(&target, angle / 16, 3, 0);
|
||||||
SoundEffect(SFX_LARA_RICOCHET, pos, 0);
|
SoundEffect(SFX_LARA_RICOCHET, pos, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DoLotsOfBlood(int x, int y, int z, int speed, short direction, short roomNumber, int count)
|
void DoLotsOfBlood(int x, int y, int z, int speed, short direction, short roomNumber, int count)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
DoBloodSplat(x + 256 - (GetRandomControl() * 512 / 0x8000),
|
DoBloodSplat(x + 256 - (GetRandomControl() * 512 / 0x8000),
|
||||||
y + 256 - (GetRandomControl() * 512 / 0x8000),
|
y + 256 - (GetRandomControl() * 512 / 0x8000),
|
||||||
z + 256 - (GetRandomControl() * 512 / 0x8000),
|
z + 256 - (GetRandomControl() * 512 / 0x8000),
|
||||||
speed, direction, roomNumber);
|
speed, direction, roomNumber);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,8 @@ struct FX_INFO
|
||||||
extern function<EffectFunction> effect_routines[];
|
extern function<EffectFunction> effect_routines[];
|
||||||
extern FX_INFO* Effects;
|
extern FX_INFO* Effects;
|
||||||
|
|
||||||
int ItemNearLara(PHD_3DPOS* pos, int radius);
|
bool ItemNearLara(PHD_3DPOS* pos, int radius);
|
||||||
|
bool ItemNearTarget(PHD_3DPOS* src, ITEM_INFO* target, int radius);
|
||||||
void StopSoundEffect(short sampleIndex);
|
void StopSoundEffect(short sampleIndex);
|
||||||
short DoBloodSplat(int x, int y, int z, short speed, short yRot, short roomNumber);
|
short DoBloodSplat(int x, int y, int z, short speed, short yRot, short roomNumber);
|
||||||
//void SoundEffects();
|
//void SoundEffects();
|
||||||
|
|
|
@ -20,6 +20,34 @@ CREATURE_INFO* GetCreatureInfo(ITEM_INFO* item)
|
||||||
return (CREATURE_INFO*)item->data;
|
return (CREATURE_INFO*)item->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TargetNearestEntity(ITEM_INFO* item, CREATURE_INFO* creature)
|
||||||
|
{
|
||||||
|
ITEM_INFO* target;
|
||||||
|
int bestdistance;
|
||||||
|
int distance;
|
||||||
|
int x, z;
|
||||||
|
|
||||||
|
bestdistance = MAXINT;
|
||||||
|
for (int i = 0; i < LevelItems; i++)
|
||||||
|
{
|
||||||
|
target = &Items[i];
|
||||||
|
if (target != nullptr)
|
||||||
|
{
|
||||||
|
if (target != item && target->hitPoints > 0 && target->status != ITEM_INVISIBLE)
|
||||||
|
{
|
||||||
|
x = target->pos.xPos - item->pos.xPos;
|
||||||
|
z = target->pos.zPos - item->pos.zPos;
|
||||||
|
distance = SQUARE(z) + SQUARE(x);
|
||||||
|
if (distance < bestdistance)
|
||||||
|
{
|
||||||
|
creature->enemy = target;
|
||||||
|
bestdistance = distance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GetRoomList(short roomNumber, short* roomArray, short* numRooms)
|
void GetRoomList(short roomNumber, short* roomArray, short* numRooms)
|
||||||
{
|
{
|
||||||
short numDoors, *door, adjoiningRoom;
|
short numDoors, *door, adjoiningRoom;
|
||||||
|
|
|
@ -21,6 +21,7 @@ enum LARA_MESH_MASK
|
||||||
short GF(short animIndex, short frameToStart); // for lara
|
short GF(short animIndex, short frameToStart); // for lara
|
||||||
short GF2(short objectID, short animIndex, short frameToStart); // for entity
|
short GF2(short objectID, short animIndex, short frameToStart); // for entity
|
||||||
CREATURE_INFO* GetCreatureInfo(ITEM_INFO* item);
|
CREATURE_INFO* GetCreatureInfo(ITEM_INFO* item);
|
||||||
|
void TargetNearestEntity(ITEM_INFO* item, CREATURE_INFO* creature);
|
||||||
|
|
||||||
void GetRoomList(short roomNumber, short* roomArray, short* numRooms); // return the value via roomArray and numRooms
|
void GetRoomList(short roomNumber, short* roomArray, short* numRooms); // return the value via roomArray and numRooms
|
||||||
void GetRoomList(short roomNumber, vector<short>* DestRoomList); // return the value via DestRoomList
|
void GetRoomList(short roomNumber, vector<short>* DestRoomList); // return the value via DestRoomList
|
|
@ -9,6 +9,7 @@
|
||||||
#include "effect.h"
|
#include "effect.h"
|
||||||
#include "level.h"
|
#include "level.h"
|
||||||
#include "lara.h"
|
#include "lara.h"
|
||||||
|
#include "tr4_mutant.h"
|
||||||
|
|
||||||
void BubblesEffect1(short fxNum, short xVel, short yVel, short zVel)
|
void BubblesEffect1(short fxNum, short xVel, short yVel, short zVel)
|
||||||
{
|
{
|
||||||
|
@ -112,58 +113,6 @@ void BubblesEffect2(short fxNum, short xVel, short yVel, short zVel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BubblesEffect3(short fxNum, short xVel, short yVel, short zVel)
|
|
||||||
{
|
|
||||||
FX_INFO* fx = &Effects[fxNum];
|
|
||||||
|
|
||||||
int dx = LaraItem->pos.xPos - fx->pos.xPos;
|
|
||||||
int dz = LaraItem->pos.zPos - fx->pos.zPos;
|
|
||||||
|
|
||||||
if (dx >= -16384 && dx <= 16384 && dz >= -16384 && dz <= 16384)
|
|
||||||
{
|
|
||||||
SPARKS* spark = &Sparks[GetFreeSpark()];
|
|
||||||
|
|
||||||
spark->on = 1;
|
|
||||||
spark->sB = 0;
|
|
||||||
spark->sR = (GetRandomControl() & 0x3F) + -128;
|
|
||||||
spark->sG = spark->sG >> 1;
|
|
||||||
spark->dB = 0;
|
|
||||||
spark->dR = (GetRandomControl() & 0x3F) + -128;
|
|
||||||
spark->dG = spark->dG >> 1;
|
|
||||||
spark->fadeToBlack = 8;
|
|
||||||
spark->colFadeSpeed = (GetRandomControl() & 3) + 8;
|
|
||||||
spark->transType = COLADD;
|
|
||||||
spark->dynamic = -1;
|
|
||||||
spark->life = spark->sLife = (GetRandomControl() & 7) + 32;
|
|
||||||
spark->y = 0;
|
|
||||||
spark->x = (GetRandomControl() & 0xF) - 8;
|
|
||||||
spark->z = (GetRandomControl() & 0xF) - 8;
|
|
||||||
spark->x += fx->pos.xPos;
|
|
||||||
spark->y += fx->pos.yPos;
|
|
||||||
spark->z += fx->pos.zPos;
|
|
||||||
spark->xVel = xVel;
|
|
||||||
spark->yVel = yVel;
|
|
||||||
spark->zVel = zVel;
|
|
||||||
spark->friction = 34;
|
|
||||||
spark->flags = 538;
|
|
||||||
spark->rotAng = GetRandomControl() & 0xFFF;
|
|
||||||
if (GetRandomControl() & 1)
|
|
||||||
{
|
|
||||||
spark->rotAdd = -32 - (GetRandomControl() & 0x1F);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
spark->rotAdd = (GetRandomControl() & 0x1F) + 32;
|
|
||||||
}
|
|
||||||
spark->gravity = 0;
|
|
||||||
spark->maxYvel = 0;
|
|
||||||
spark->fxObj = fxNum;
|
|
||||||
spark->scalar = 2;
|
|
||||||
spark->sSize = spark->size = (GetRandomControl() & 0xF) + 128;
|
|
||||||
spark->dSize = spark->size >> 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BubblesEffect4(short fxNum, short xVel, short yVel, short zVel)
|
void BubblesEffect4(short fxNum, short xVel, short yVel, short zVel)
|
||||||
{
|
{
|
||||||
FX_INFO* fx = &Effects[fxNum];
|
FX_INFO* fx = &Effects[fxNum];
|
||||||
|
@ -463,29 +412,25 @@ void BubblesControl(short fxNum)
|
||||||
int dy = oldY - fx->pos.yPos;
|
int dy = oldY - fx->pos.yPos;
|
||||||
int dz = oldZ - fx->pos.zPos;
|
int dz = oldZ - fx->pos.zPos;
|
||||||
|
|
||||||
if (Wibble & 4 || fx->flag1 == 1 || fx->flag1 == 5 || fx->flag1 == 2)
|
if (Wibble & 4)
|
||||||
{
|
{
|
||||||
if (fx->flag1)
|
switch (fx->flag1)
|
||||||
{
|
{
|
||||||
if (fx->flag1 == 1)
|
default:
|
||||||
{
|
case 1:
|
||||||
BubblesEffect1(fxNum, 32 * dx, 32 * dy, 32 * dz);
|
BubblesEffect1(fxNum, 32 * dx, 32 * dy, 32 * dz);
|
||||||
}
|
break;
|
||||||
else if (fx->flag1 < 3 || fx->flag1 > 5)
|
case 2:
|
||||||
{
|
BubblesEffect2(fxNum, 16 * dx, 16 * dy, 16 * dz);
|
||||||
if (fx->flag1 == 2)
|
break;
|
||||||
BubblesEffect2(fxNum, 16 * dx, 16 * dy, 16 * dz);
|
case 3:
|
||||||
else if (fx->flag1 == 6)
|
case 4:
|
||||||
BubblesEffect3(fxNum, 16 * dx, 16 * dy, 16 * dz);
|
case 5:
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
BubblesEffect4(fxNum, 16 * dx, 16 * dy, 16 * dz);
|
BubblesEffect4(fxNum, 16 * dx, 16 * dy, 16 * dz);
|
||||||
}
|
break;
|
||||||
}
|
case 6:
|
||||||
else
|
TriggerMutantRocketEffects(fxNum, 16 * dx, 16 * dy, 16 * dz);
|
||||||
{
|
break;
|
||||||
BubblesEffect1(fxNum, 16 * dx, 16 * dy, 16 * dz);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
231
TR5Main/Objects/Effects/tr4_locusts.cpp
Normal file
231
TR5Main/Objects/Effects/tr4_locusts.cpp
Normal file
|
@ -0,0 +1,231 @@
|
||||||
|
#include "framework.h"
|
||||||
|
#include "tr4_locusts.h"
|
||||||
|
#include "sound.h"
|
||||||
|
#include "trmath.h"
|
||||||
|
#include "sphere.h"
|
||||||
|
#include "misc.h"
|
||||||
|
#include "lara.h"
|
||||||
|
#include "tomb4fx.h"
|
||||||
|
|
||||||
|
constexpr auto MAX_LOCUSTS = 64;
|
||||||
|
struct LOCUST_INFO
|
||||||
|
{
|
||||||
|
bool on;
|
||||||
|
PHD_3DPOS pos;
|
||||||
|
ITEM_INFO* target;
|
||||||
|
short roomNumber;
|
||||||
|
short randomRotation;
|
||||||
|
short escapeXrot;
|
||||||
|
short escapeYrot;
|
||||||
|
short escapeZrot;
|
||||||
|
BYTE counter;
|
||||||
|
};
|
||||||
|
LOCUST_INFO Locusts[MAX_LOCUSTS];
|
||||||
|
constexpr auto LOCUST_LARA_DAMAGE = 3;
|
||||||
|
constexpr auto LOCUST_ENTITY_DAMAGE = 1;
|
||||||
|
|
||||||
|
int CreateLocust(void)
|
||||||
|
{
|
||||||
|
LOCUST_INFO* locust;
|
||||||
|
|
||||||
|
for (int i = 0; i < MAX_LOCUSTS; i++)
|
||||||
|
{
|
||||||
|
locust = &Locusts[i];
|
||||||
|
if (!locust->on)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NO_ITEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpawnLocust(ITEM_INFO* item)
|
||||||
|
{
|
||||||
|
LOCUST_INFO* locust;
|
||||||
|
ITEM_INFO* target;
|
||||||
|
PHD_VECTOR start, end;
|
||||||
|
short angles[2];
|
||||||
|
short locustNumber = NO_ITEM;
|
||||||
|
|
||||||
|
locustNumber = CreateLocust();
|
||||||
|
if (locustNumber != NO_ITEM)
|
||||||
|
{
|
||||||
|
locust = &Locusts[locustNumber];
|
||||||
|
// emitter
|
||||||
|
if (item->objectNumber == ID_LOCUSTS_EMITTER)
|
||||||
|
{
|
||||||
|
end.x = item->pos.xPos;
|
||||||
|
end.y = item->pos.yPos;
|
||||||
|
end.z = item->pos.zPos;
|
||||||
|
angles[0] = item->pos.yRot - ANGLE(180.0f);
|
||||||
|
angles[1] = 0;
|
||||||
|
}
|
||||||
|
// mutant
|
||||||
|
else
|
||||||
|
{
|
||||||
|
start.x = 0;
|
||||||
|
start.y = -96;
|
||||||
|
start.z = 144;
|
||||||
|
GetJointAbsPosition(item, &start, 9);
|
||||||
|
end.x = 0;
|
||||||
|
end.y = -128;
|
||||||
|
end.z = 288;
|
||||||
|
GetJointAbsPosition(item, &end, 9);
|
||||||
|
phd_GetVectorAngles(end.x - start.x, end.y - start.y, end.z - start.z, angles);
|
||||||
|
}
|
||||||
|
|
||||||
|
target = GetCreatureInfo(item)->enemy;
|
||||||
|
|
||||||
|
locust->on = true;
|
||||||
|
locust->target = target != nullptr ? target : nullptr;
|
||||||
|
locust->pos.xPos = end.x;
|
||||||
|
locust->pos.yPos = end.y;
|
||||||
|
locust->pos.zPos = end.z;
|
||||||
|
locust->pos.yRot = (GetRandomControl() & 0x7FF) + angles[0] - 0x400;
|
||||||
|
locust->pos.xRot = (GetRandomControl() & 0x3FF) + angles[1] - 0x200;
|
||||||
|
locust->roomNumber = item->roomNumber;
|
||||||
|
locust->randomRotation = (GetRandomControl() & 0x1F) + 0x10;
|
||||||
|
locust->escapeYrot = (GetRandomControl() & 0x1FF);
|
||||||
|
locust->escapeXrot = ((GetRandomControl() & 0x7) + 0xF) * 20;
|
||||||
|
locust->counter = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitialiseLocust(short itemNumber)
|
||||||
|
{
|
||||||
|
ITEM_INFO* item = &Items[itemNumber];
|
||||||
|
|
||||||
|
if (item->pos.yRot > 0)
|
||||||
|
{
|
||||||
|
if (item->pos.yRot == 0x4000)
|
||||||
|
item->pos.xPos += CLICK(2);
|
||||||
|
}
|
||||||
|
else if (item->pos.yRot < 0)
|
||||||
|
{
|
||||||
|
if (item->pos.yRot == -0x8000)
|
||||||
|
item->pos.zPos -= CLICK(2);
|
||||||
|
else if (item->pos.yRot == -0x4000)
|
||||||
|
item->pos.xPos -= CLICK(2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
item->pos.zPos += CLICK(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LocustControl(short itemNumber)
|
||||||
|
{
|
||||||
|
ITEM_INFO* item = &Items[itemNumber];
|
||||||
|
|
||||||
|
if (TriggerActive(item))
|
||||||
|
{
|
||||||
|
if (item->triggerFlags)
|
||||||
|
{
|
||||||
|
SpawnLocust(item);
|
||||||
|
item->triggerFlags--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
KillItem(itemNumber);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateLocusts(void)
|
||||||
|
{
|
||||||
|
LOCUST_INFO* locust;
|
||||||
|
ITEM_INFO* target;
|
||||||
|
PHD_VECTOR posAngle;
|
||||||
|
int distance;
|
||||||
|
int square;
|
||||||
|
short angles[2];
|
||||||
|
|
||||||
|
for (int i = 0; i < MAX_LOCUSTS; i++)
|
||||||
|
{
|
||||||
|
locust = &Locusts[i];
|
||||||
|
if (locust->on)
|
||||||
|
{
|
||||||
|
if (locust->target == nullptr)
|
||||||
|
locust->target = LaraItem;
|
||||||
|
if (locust->target->hitPoints <= 0 && locust->counter >= 90 && !(GetRandomControl() & 7))
|
||||||
|
locust->counter = 90;
|
||||||
|
|
||||||
|
locust->counter--;
|
||||||
|
if (locust->counter == 0)
|
||||||
|
{
|
||||||
|
locust->on = FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(GetRandomControl() & 7))
|
||||||
|
{
|
||||||
|
locust->escapeYrot = GetRandomControl() % 640 + 128;
|
||||||
|
locust->escapeXrot = (GetRandomControl() & 0x7F) - 64;
|
||||||
|
locust->escapeZrot = (GetRandomControl() & 0x7F) - 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
phd_GetVectorAngles(
|
||||||
|
locust->target->pos.xPos + 8 * locust->escapeXrot - locust->pos.xPos,
|
||||||
|
locust->target->pos.yPos - locust->escapeYrot - locust->pos.yPos,
|
||||||
|
locust->target->pos.zPos + 8 * locust->escapeZrot - locust->pos.zPos,
|
||||||
|
angles);
|
||||||
|
|
||||||
|
distance = SQUARE(locust->target->pos.zPos - locust->pos.zPos) + SQUARE(locust->target->pos.xPos - locust->pos.xPos);
|
||||||
|
square = int(sqrt(distance)) >> 3;
|
||||||
|
if (square <= 128)
|
||||||
|
{
|
||||||
|
if (square < 48)
|
||||||
|
square = 48;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
square = 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (locust->randomRotation < square)
|
||||||
|
locust->randomRotation += 1;
|
||||||
|
else if (locust->randomRotation > square)
|
||||||
|
locust->randomRotation -= 1;
|
||||||
|
|
||||||
|
if (locust->counter > 90)
|
||||||
|
{
|
||||||
|
short resultYrot, resultXrot;
|
||||||
|
int shiftYrot, shiftXrot;
|
||||||
|
int random = locust->randomRotation << 7;
|
||||||
|
resultYrot = angles[0] - locust->pos.yRot;
|
||||||
|
if (abs(resultYrot) > 0x8000)
|
||||||
|
resultYrot = locust->pos.yRot - angles[0];
|
||||||
|
resultXrot = angles[1] - locust->pos.xRot;
|
||||||
|
if (abs(resultXrot) > 0x8000)
|
||||||
|
resultXrot = locust->pos.xRot - angles[0];
|
||||||
|
shiftYrot = resultYrot >> 3;
|
||||||
|
shiftXrot = resultXrot >> 3;
|
||||||
|
if (shiftYrot > random || shiftYrot < -random)
|
||||||
|
shiftYrot = -random;
|
||||||
|
if (shiftXrot > random || shiftXrot < -random)
|
||||||
|
shiftXrot = -random;
|
||||||
|
locust->pos.yRot += shiftYrot;
|
||||||
|
locust->pos.xRot += shiftXrot;
|
||||||
|
}
|
||||||
|
|
||||||
|
locust->pos.xPos += (locust->randomRotation * phd_cos(locust->pos.xRot) >> W2V_SHIFT) * phd_sin(locust->pos.yRot) >> W2V_SHIFT;
|
||||||
|
locust->pos.yPos += locust->randomRotation * phd_sin(-locust->pos.xRot) >> W2V_SHIFT;
|
||||||
|
locust->pos.zPos += (locust->randomRotation * phd_cos(locust->pos.xRot) >> W2V_SHIFT) * phd_cos(locust->pos.yRot) >> W2V_SHIFT;
|
||||||
|
if (ItemNearTarget(&locust->pos, locust->target, CLICK(1) / 2))
|
||||||
|
{
|
||||||
|
TriggerBlood(locust->pos.xPos, locust->pos.yPos, locust->pos.zPos, 2 * GetRandomControl(), 2);
|
||||||
|
if (locust->target == LaraItem)
|
||||||
|
locust->target->hitPoints -= LOCUST_LARA_DAMAGE;
|
||||||
|
else
|
||||||
|
locust->target->hitPoints -= LOCUST_ENTITY_DAMAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (locust->counter > 0)
|
||||||
|
SoundEffect(SFX_TR4_LOCUSTS_LOOP, &locust->pos, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawLocust(void)
|
||||||
|
{
|
||||||
|
// TODO: no render for the locusts !
|
||||||
|
}
|
10
TR5Main/Objects/Effects/tr4_locusts.h
Normal file
10
TR5Main/Objects/Effects/tr4_locusts.h
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#pragma once
|
||||||
|
#include "phd_global.h"
|
||||||
|
#include "items.h"
|
||||||
|
|
||||||
|
extern int CreateLocust(void);
|
||||||
|
extern void SpawnLocust(ITEM_INFO* item);
|
||||||
|
extern void InitialiseLocust(short itemNumber);
|
||||||
|
extern void LocustControl(short itemNumber);
|
||||||
|
extern void UpdateLocusts(void);
|
||||||
|
extern void DrawLocust(void);
|
|
@ -10,38 +10,6 @@
|
||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
|
|
||||||
struct CROCODILE_BONE
|
|
||||||
{
|
|
||||||
short torsoY;
|
|
||||||
short torsoX;
|
|
||||||
short hipsY;
|
|
||||||
short hipsX;
|
|
||||||
|
|
||||||
CROCODILE_BONE()
|
|
||||||
{
|
|
||||||
this->torsoY = 0;
|
|
||||||
this->torsoX = 0;
|
|
||||||
this->hipsY = 0;
|
|
||||||
this->hipsX = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
CROCODILE_BONE(short angle)
|
|
||||||
{
|
|
||||||
this->torsoY = angle;
|
|
||||||
this->torsoX = angle;
|
|
||||||
this->hipsY = -angle;
|
|
||||||
this->hipsX = -angle;
|
|
||||||
}
|
|
||||||
|
|
||||||
CROCODILE_BONE(short torsoY, short torsoX)
|
|
||||||
{
|
|
||||||
this->torsoY = torsoY;
|
|
||||||
this->torsoX = torsoX;
|
|
||||||
this->hipsY = 0;
|
|
||||||
this->hipsX = 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
enum CROCODILE_STATE
|
enum CROCODILE_STATE
|
||||||
{
|
{
|
||||||
CROC_EMPTY,
|
CROC_EMPTY,
|
||||||
|
@ -136,7 +104,7 @@ void CrocodileControl(short itemNumber)
|
||||||
ObjectInfo* obj;
|
ObjectInfo* obj;
|
||||||
CREATURE_INFO* crocodile;
|
CREATURE_INFO* crocodile;
|
||||||
AI_INFO info;
|
AI_INFO info;
|
||||||
CROCODILE_BONE boneRot;
|
OBJECT_BONES boneRot;
|
||||||
short angle;
|
short angle;
|
||||||
short bone_angle;
|
short bone_angle;
|
||||||
|
|
||||||
|
@ -330,15 +298,15 @@ void CrocodileControl(short itemNumber)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item->currentAnimState == CROC_IDLE || item->currentAnimState == CROC_ATK || item->currentAnimState == WCROC_ATK)
|
if (item->currentAnimState == CROC_IDLE || item->currentAnimState == CROC_ATK || item->currentAnimState == WCROC_ATK)
|
||||||
boneRot = CROCODILE_BONE(info.angle, info.xAngle);
|
boneRot = OBJECT_BONES(info.angle, info.xAngle);
|
||||||
else
|
else
|
||||||
boneRot = CROCODILE_BONE(bone_angle);
|
boneRot = OBJECT_BONES(bone_angle);
|
||||||
|
|
||||||
CreatureTilt(item, 0);
|
CreatureTilt(item, 0);
|
||||||
CreatureJoint(item, 0, boneRot.torsoY);
|
CreatureJoint(item, 0, boneRot.bone0);
|
||||||
CreatureJoint(item, 1, boneRot.torsoX);
|
CreatureJoint(item, 1, boneRot.bone1);
|
||||||
CreatureJoint(item, 2, boneRot.hipsY);
|
CreatureJoint(item, 2, boneRot.bone2);
|
||||||
CreatureJoint(item, 3, boneRot.hipsX);
|
CreatureJoint(item, 3, boneRot.bone3);
|
||||||
|
|
||||||
if (item->currentAnimState < WCROC_SWIM)
|
if (item->currentAnimState < WCROC_SWIM)
|
||||||
CalcItemToFloorRotation(item, 2);
|
CalcItemToFloorRotation(item, 2);
|
||||||
|
|
350
TR5Main/Objects/TR4/Entity/tr4_mutant.cpp
Normal file
350
TR5Main/Objects/TR4/Entity/tr4_mutant.cpp
Normal file
|
@ -0,0 +1,350 @@
|
||||||
|
#include "framework.h"
|
||||||
|
#include "tr4_mutant.h"
|
||||||
|
#include "tr4_locusts.h"
|
||||||
|
#include "effect.h"
|
||||||
|
#include "effect2.h"
|
||||||
|
#include "misc.h"
|
||||||
|
#include "lara.h"
|
||||||
|
#include "setup.h"
|
||||||
|
#include "sphere.h"
|
||||||
|
#include "objectslist.h"
|
||||||
|
#include "trmath.h"
|
||||||
|
|
||||||
|
enum MUTANT_STATE
|
||||||
|
{
|
||||||
|
MUTANT_EMPTY,
|
||||||
|
MUTANT_APPEAR,
|
||||||
|
MUTANT_IDLE,
|
||||||
|
MUTANT_SHOOT,
|
||||||
|
MUTANT_LOCUST1,
|
||||||
|
MUTANT_LOCUST2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class MissileRotationType
|
||||||
|
{
|
||||||
|
M_FRONT,
|
||||||
|
M_LEFT,
|
||||||
|
M_RIGHT
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr auto MUTANT_ANIM_APPEAR = 0;
|
||||||
|
constexpr auto MUTANT_SHOOT_RANGE = SQUARE(SECTOR(10));
|
||||||
|
constexpr auto MUTANT_LOCUST1_RANGE = SQUARE(SECTOR(15));
|
||||||
|
constexpr auto MUTANT_LOCUST2_RANGE = SQUARE(SECTOR(30));
|
||||||
|
|
||||||
|
static void TriggerMutantRocket(PHD_3DPOS* src, short roomNumber, short counter)
|
||||||
|
{
|
||||||
|
FX_INFO* fx;
|
||||||
|
short fxNumber = NO_ITEM;
|
||||||
|
|
||||||
|
fxNumber = CreateNewEffect(roomNumber);
|
||||||
|
if (fxNumber != NO_ITEM)
|
||||||
|
{
|
||||||
|
fx = &Effects[fxNumber];
|
||||||
|
fx->pos.xPos = src->xPos;
|
||||||
|
fx->pos.yPos = src->yPos - (GetRandomControl() & 0x3F) - 32;
|
||||||
|
fx->pos.zPos = src->zPos;
|
||||||
|
fx->pos.xRot = src->xRot;
|
||||||
|
fx->pos.yRot = src->yRot;
|
||||||
|
fx->pos.zRot = 0;
|
||||||
|
fx->roomNumber = roomNumber;
|
||||||
|
fx->counter = 16 * counter + 15;
|
||||||
|
fx->objectNumber = ID_ENERGY_BUBBLES;
|
||||||
|
fx->frameNumber = Objects[fx->objectNumber].meshIndex + 5 * 2;
|
||||||
|
fx->speed = (GetRandomControl() & 0x1F) + 96;
|
||||||
|
fx->flag1 = 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TriggerMutantRocketEffects(short fxNumber, short xVel, short yVel, short zVel)
|
||||||
|
{
|
||||||
|
FX_INFO* fx;
|
||||||
|
SPARKS* sptr;
|
||||||
|
BYTE color, life, size;
|
||||||
|
|
||||||
|
//x = LaraItem->pos.xPos - Effects[m_fxNumber].pos.xPos;
|
||||||
|
//z = LaraItem->pos.zPos - Effects[m_fxNumber].pos.zPos;
|
||||||
|
//if (x >= -0x4000u && x <= 0x4000 && z >= -0x4000u && z <= 0x4000)
|
||||||
|
|
||||||
|
fx = &Effects[fxNumber];
|
||||||
|
sptr = &Sparks[GetFreeSpark()];
|
||||||
|
sptr->on = TRUE;
|
||||||
|
color = (GetRandomControl() & 0x3F) - 128;
|
||||||
|
sptr->sB = 0;
|
||||||
|
sptr->sR = color;
|
||||||
|
sptr->sG = color >> 1;
|
||||||
|
color = (GetRandomControl() & 0x3F) - 128;
|
||||||
|
sptr->dB = 0;
|
||||||
|
sptr->dR = color;
|
||||||
|
sptr->dG = color >> 1;
|
||||||
|
sptr->fadeToBlack = 8;
|
||||||
|
sptr->colFadeSpeed = (GetRandomControl() & 3) + 8;
|
||||||
|
sptr->transType = COLADD;
|
||||||
|
sptr->dynamic = -1;
|
||||||
|
life = (GetRandomControl() & 7) + 32;
|
||||||
|
sptr->life = life;
|
||||||
|
sptr->sLife = life;
|
||||||
|
sptr->x = (GetRandomControl() & 0xF) - 8;
|
||||||
|
sptr->y = 0;
|
||||||
|
sptr->z = (GetRandomControl() & 0xF) - 8;
|
||||||
|
sptr->x += fx->pos.xPos;
|
||||||
|
sptr->y += fx->pos.yPos;
|
||||||
|
sptr->z += fx->pos.zPos;
|
||||||
|
sptr->xVel = xVel;
|
||||||
|
sptr->yVel = yVel;
|
||||||
|
sptr->zVel = zVel;
|
||||||
|
sptr->friction = 34;
|
||||||
|
sptr->flags = SP_EXPDEF | SP_ROTATE | SP_DEF | SP_SCALE;
|
||||||
|
sptr->rotAng = GetRandomControl() & 0xFFF;
|
||||||
|
if (GetRandomControl() & 1)
|
||||||
|
sptr->rotAdd = (GetRandomControl() & 0x1F) - 32;
|
||||||
|
else
|
||||||
|
sptr->rotAdd = (GetRandomControl() & 0x1F) + 32;
|
||||||
|
sptr->gravity = 0;
|
||||||
|
sptr->maxYvel = 0;
|
||||||
|
sptr->fxObj = byte(fxNumber);
|
||||||
|
sptr->scalar = 2;
|
||||||
|
size = (GetRandomControl() & 0xF) + 128;
|
||||||
|
sptr->size = size;
|
||||||
|
sptr->sSize = size;
|
||||||
|
sptr->dSize = size >> 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ShootFireball(PHD_3DPOS* src, MissileRotationType rotation, short roomNumber, int timer)
|
||||||
|
{
|
||||||
|
switch (rotation)
|
||||||
|
{
|
||||||
|
case MissileRotationType::M_LEFT:
|
||||||
|
src->yRot -= GetRandomControl() % 0x2000;
|
||||||
|
break;
|
||||||
|
case MissileRotationType::M_RIGHT:
|
||||||
|
src->yRot += GetRandomControl() % 0x2000;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
TriggerMutantRocket(src, roomNumber, timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ShootFrame(ITEM_INFO* item)
|
||||||
|
{
|
||||||
|
short frameNumber = (item->frameNumber - Anims[item->objectNumber].frameBase);
|
||||||
|
if (frameNumber == 45
|
||||||
|
//|| frameNumber == 50
|
||||||
|
//|| frameNumber == 55
|
||||||
|
|| frameNumber == 60
|
||||||
|
//|| frameNumber == 65
|
||||||
|
//|| frameNumber == 70
|
||||||
|
|| frameNumber == 75)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void RotateHeadToTarget(ITEM_INFO* item, CREATURE_INFO* creature, int joint, short& headAngle)
|
||||||
|
{
|
||||||
|
if (creature->enemy == nullptr)
|
||||||
|
{
|
||||||
|
headAngle = item->pos.yRot;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ITEM_INFO* enemy = creature->enemy;
|
||||||
|
PHD_VECTOR pos;
|
||||||
|
int x, z;
|
||||||
|
pos.x = 0;
|
||||||
|
pos.y = 0;
|
||||||
|
pos.z = 0;
|
||||||
|
GetJointAbsPosition(item, &pos, joint);
|
||||||
|
x = enemy->pos.xPos - pos.x;
|
||||||
|
z = enemy->pos.zPos - pos.z;
|
||||||
|
headAngle = (short)(phd_atan(z, x) - item->pos.yRot) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void GetTargetPosition(ITEM_INFO* item, PHD_3DPOS* target)
|
||||||
|
{
|
||||||
|
PHD_VECTOR start, end;
|
||||||
|
short angles[2];
|
||||||
|
start.x = 0;
|
||||||
|
start.y = -96;
|
||||||
|
start.z = 144;
|
||||||
|
GetJointAbsPosition(item, &start, 9);
|
||||||
|
end.x = 0;
|
||||||
|
end.y = -128;
|
||||||
|
end.z = 288;
|
||||||
|
GetJointAbsPosition(item, &end, 9);
|
||||||
|
phd_GetVectorAngles(end.x - start.x, end.y - start.y, end.z - start.z, angles);
|
||||||
|
target->xPos = end.x;
|
||||||
|
target->yPos = end.y;
|
||||||
|
target->zPos = end.z;
|
||||||
|
target->yRot = angles[0];
|
||||||
|
target->xRot = angles[1];
|
||||||
|
target->zRot = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum CARDINAL_POINT
|
||||||
|
{
|
||||||
|
C_NORTH = 0,
|
||||||
|
C_NORTH_EAST = 45,
|
||||||
|
C_EAST = 90,
|
||||||
|
C_EAST_SOUTH = 135,
|
||||||
|
C_SOUTH = 180,
|
||||||
|
C_SOUTH_WEST = 225,
|
||||||
|
C_WEST = 270,
|
||||||
|
C_WEST_NORTH = 315
|
||||||
|
};
|
||||||
|
|
||||||
|
static void MoveItemFront(ITEM_INFO* item, int distance)
|
||||||
|
{
|
||||||
|
short degree = short(TO_DEGREES(item->pos.yRot));
|
||||||
|
switch (degree)
|
||||||
|
{
|
||||||
|
case C_NORTH:
|
||||||
|
item->pos.zPos += distance;
|
||||||
|
break;
|
||||||
|
case C_EAST:
|
||||||
|
item->pos.xPos += distance;
|
||||||
|
break;
|
||||||
|
case C_SOUTH:
|
||||||
|
item->pos.zPos -= distance;
|
||||||
|
break;
|
||||||
|
case C_WEST:
|
||||||
|
item->pos.xPos -= distance;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void MoveItemBack(ITEM_INFO* item, int distance)
|
||||||
|
{
|
||||||
|
short degree = short(TO_DEGREES(item->pos.yRot));
|
||||||
|
switch (degree)
|
||||||
|
{
|
||||||
|
case C_NORTH:
|
||||||
|
item->pos.zPos -= distance;
|
||||||
|
break;
|
||||||
|
case C_EAST:
|
||||||
|
item->pos.xPos -= distance;
|
||||||
|
break;
|
||||||
|
case C_SOUTH:
|
||||||
|
item->pos.zPos += distance;
|
||||||
|
break;
|
||||||
|
case C_WEST:
|
||||||
|
item->pos.xPos += distance;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void MutantAIFix(ITEM_INFO* item, AI_INFO* info)
|
||||||
|
{
|
||||||
|
MoveItemFront(item, SECTOR(2));
|
||||||
|
item->pos.yPos -= CLICK(3);
|
||||||
|
CreatureAIInfo(item, info);
|
||||||
|
item->pos.yPos += CLICK(3);
|
||||||
|
MoveItemBack(item, SECTOR(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitialiseMutant(short itemNumber)
|
||||||
|
{
|
||||||
|
ITEM_INFO* item;
|
||||||
|
InitialiseCreature(itemNumber);
|
||||||
|
|
||||||
|
item = &Items[itemNumber];
|
||||||
|
item->animNumber = Objects[item->objectNumber].animIndex + MUTANT_ANIM_APPEAR;
|
||||||
|
item->frameNumber = Anims[item->animNumber].frameBase;
|
||||||
|
item->currentAnimState = MUTANT_APPEAR;
|
||||||
|
item->goalAnimState = MUTANT_APPEAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MutantControl(short itemNumber)
|
||||||
|
{
|
||||||
|
if (!CreatureActive(itemNumber))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ITEM_INFO* item;
|
||||||
|
CREATURE_INFO* mutant;
|
||||||
|
AI_INFO info;
|
||||||
|
OBJECT_BONES mutant_joint;
|
||||||
|
short frameNumber;
|
||||||
|
short headY;
|
||||||
|
short angle;
|
||||||
|
|
||||||
|
item = &Items[itemNumber];
|
||||||
|
mutant = GetCreatureInfo(item);
|
||||||
|
angle = 0;
|
||||||
|
headY = 0;
|
||||||
|
|
||||||
|
if (item->aiBits & ALL_AIOBJ)
|
||||||
|
GetAITarget(mutant);
|
||||||
|
else if (mutant->hurtByLara)
|
||||||
|
mutant->enemy = LaraItem;
|
||||||
|
else
|
||||||
|
TargetNearestEntity(item, mutant);
|
||||||
|
|
||||||
|
MutantAIFix(item, &info);
|
||||||
|
RotateHeadToTarget(item, mutant, 9, headY);
|
||||||
|
GetCreatureMood(item, &info, VIOLENT);
|
||||||
|
CreatureMood(item, &info, VIOLENT);
|
||||||
|
mutant->maximumTurn = 0;
|
||||||
|
angle = CreatureTurn(item, 0);
|
||||||
|
|
||||||
|
switch (item->currentAnimState)
|
||||||
|
{
|
||||||
|
case MUTANT_IDLE:
|
||||||
|
if (info.ahead)
|
||||||
|
{
|
||||||
|
int random = GetRandomControl() & 31;
|
||||||
|
if ((random > 0 && random < 10) && info.distance <= MUTANT_SHOOT_RANGE)
|
||||||
|
item->goalAnimState = MUTANT_SHOOT;
|
||||||
|
else if ((random > 10 && random < 20) && info.distance <= MUTANT_LOCUST1_RANGE)
|
||||||
|
item->goalAnimState = MUTANT_LOCUST1;
|
||||||
|
else if ((random > 20 && random < 30) && info.distance <= MUTANT_LOCUST2_RANGE)
|
||||||
|
item->goalAnimState = MUTANT_LOCUST2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MUTANT_SHOOT:
|
||||||
|
frameNumber = (item->frameNumber - Anims[item->objectNumber].frameBase);
|
||||||
|
if (frameNumber >= 94 && frameNumber <= 96)
|
||||||
|
{
|
||||||
|
PHD_3DPOS src;
|
||||||
|
GetTargetPosition(item, &src);
|
||||||
|
if (frameNumber == 94)
|
||||||
|
{
|
||||||
|
ShootFireball(&src, MissileRotationType::M_FRONT, item->roomNumber, 0);
|
||||||
|
}
|
||||||
|
else if (frameNumber == 95)
|
||||||
|
{
|
||||||
|
ShootFireball(&src, MissileRotationType::M_LEFT, item->roomNumber, 1);
|
||||||
|
//ShootFireball(&src, MissileRotationType::M_LEFT, item->roomNumber, 1);
|
||||||
|
}
|
||||||
|
else if (frameNumber == 96)
|
||||||
|
{
|
||||||
|
ShootFireball(&src, MissileRotationType::M_RIGHT, item->roomNumber, 1);
|
||||||
|
//ShootFireball(&src, MissileRotationType::M_RIGHT, item->roomNumber, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MUTANT_LOCUST1:
|
||||||
|
frameNumber = (item->frameNumber - Anims[item->objectNumber].frameBase);
|
||||||
|
if (frameNumber >= 60 && frameNumber <= 120)
|
||||||
|
SpawnLocust(item);
|
||||||
|
break;
|
||||||
|
case MUTANT_LOCUST2:
|
||||||
|
if (ShootFrame(item))
|
||||||
|
{
|
||||||
|
PHD_3DPOS src;
|
||||||
|
GetTargetPosition(item, &src);
|
||||||
|
ShootFireball(&src, MissileRotationType::M_FRONT, item->roomNumber, 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item->currentAnimState != MUTANT_LOCUST1)
|
||||||
|
mutant_joint = OBJECT_BONES(headY, info.xAngle, true);
|
||||||
|
else
|
||||||
|
mutant_joint = OBJECT_BONES(0);
|
||||||
|
|
||||||
|
CreatureJoint(item, 0, mutant_joint.bone0);
|
||||||
|
CreatureJoint(item, 1, mutant_joint.bone1);
|
||||||
|
CreatureJoint(item, 2, mutant_joint.bone2);
|
||||||
|
CreatureJoint(item, 3, mutant_joint.bone3);
|
||||||
|
CreatureAnimation(itemNumber, angle, 0);
|
||||||
|
}
|
||||||
|
|
5
TR5Main/Objects/TR4/Entity/tr4_mutant.h
Normal file
5
TR5Main/Objects/TR4/Entity/tr4_mutant.h
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
void InitialiseMutant(short itemNumber);
|
||||||
|
void MutantControl(short itemNumber);
|
||||||
|
void TriggerMutantRocketEffects(short fxNumber, short xVel, short yVel, short zVel);
|
|
@ -23,6 +23,8 @@
|
||||||
#include "tr4_wildboar.h" // OK
|
#include "tr4_wildboar.h" // OK
|
||||||
#include "tr4_wraith.h" // OFF
|
#include "tr4_wraith.h" // OFF
|
||||||
#include "tr4_baboon.h" // OK
|
#include "tr4_baboon.h" // OK
|
||||||
|
#include "tr4_mutant.h" // OK
|
||||||
|
#include "tr4_locusts.h" // OK
|
||||||
/// objects
|
/// objects
|
||||||
#include "tr4_sarcophagus.h"
|
#include "tr4_sarcophagus.h"
|
||||||
/// puzzle
|
/// puzzle
|
||||||
|
@ -49,7 +51,6 @@
|
||||||
/// vehicles
|
/// vehicles
|
||||||
#include "motorbike.h"
|
#include "motorbike.h"
|
||||||
#include "jeep.h"
|
#include "jeep.h"
|
||||||
|
|
||||||
/// necessary import
|
/// necessary import
|
||||||
#include "collide.h"
|
#include "collide.h"
|
||||||
#include "objects.h"
|
#include "objects.h"
|
||||||
|
@ -527,6 +528,36 @@ static void StartBaddy(ObjectInfo* obj)
|
||||||
if (Objects[ID_BABOON_NORMAL].loaded)
|
if (Objects[ID_BABOON_NORMAL].loaded)
|
||||||
Objects[ID_BABOON_SILENT].animIndex = Objects[ID_BABOON_NORMAL].animIndex;
|
Objects[ID_BABOON_SILENT].animIndex = Objects[ID_BABOON_NORMAL].animIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
obj = &Objects[ID_CROCODILE_GOD];
|
||||||
|
if (obj->loaded)
|
||||||
|
{
|
||||||
|
obj->initialise = InitialiseMutant;
|
||||||
|
obj->control = MutantControl;
|
||||||
|
obj->collision = CreatureCollision;
|
||||||
|
obj->shadowSize = UNIT_SHADOW / 2;
|
||||||
|
obj->hitPoints = NOT_TARGETABLE;
|
||||||
|
obj->pivotLength = 50;
|
||||||
|
obj->radius = 128;
|
||||||
|
obj->intelligent = TRUE;
|
||||||
|
obj->saveAnim = TRUE;
|
||||||
|
obj->saveFlags = TRUE;
|
||||||
|
obj->saveMesh = TRUE;
|
||||||
|
obj->savePosition = TRUE;
|
||||||
|
obj->undead = TRUE;
|
||||||
|
obj->hitEffect = HIT_SMOKE;
|
||||||
|
Bones[obj->boneIndex + 6 * 4] |= ROT_Y | ROT_X;
|
||||||
|
Bones[obj->boneIndex + 7 * 4] |= ROT_Y | ROT_X;
|
||||||
|
}
|
||||||
|
|
||||||
|
obj = &Objects[ID_LOCUSTS_EMITTER];
|
||||||
|
if (obj->loaded)
|
||||||
|
{
|
||||||
|
obj->initialise = InitialiseLocust;
|
||||||
|
obj->control = LocustControl;
|
||||||
|
obj->drawRoutine = NULL;
|
||||||
|
obj->saveFlags = TRUE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void StartObject(ObjectInfo* obj)
|
static void StartObject(ObjectInfo* obj)
|
||||||
|
|
|
@ -105,6 +105,9 @@ typedef enum GAME_OBJECT_ID
|
||||||
ID_SPIDERS_EMITTER,
|
ID_SPIDERS_EMITTER,
|
||||||
ID_LION,
|
ID_LION,
|
||||||
ID_DOBERMAN,
|
ID_DOBERMAN,
|
||||||
|
ID_HAMMERHEAD,
|
||||||
|
ID_CROCODILE_GOD, // TR4 Citadel Gate Mutant
|
||||||
|
ID_LOCUSTS_EMITTER,
|
||||||
|
|
||||||
/* Humans */
|
/* Humans */
|
||||||
ID_SCUBA_HARPOON = 150,
|
ID_SCUBA_HARPOON = 150,
|
||||||
|
|
|
@ -116,6 +116,8 @@ GameScript::GameScript(sol::state* lua)
|
||||||
{"SPIDERS_EMITTER", ID_SPIDERS_EMITTER},
|
{"SPIDERS_EMITTER", ID_SPIDERS_EMITTER},
|
||||||
{"LION", ID_LION},
|
{"LION", ID_LION},
|
||||||
{"DOBERMAN", ID_DOBERMAN},
|
{"DOBERMAN", ID_DOBERMAN},
|
||||||
|
{"HAMMERHEAD", ID_HAMMERHEAD},
|
||||||
|
{"CROCODILE_GOD", ID_CROCODILE_GOD},
|
||||||
{"SCUBA_HARPOON", ID_SCUBA_HARPOON},
|
{"SCUBA_HARPOON", ID_SCUBA_HARPOON},
|
||||||
{"SCUBA_DIVER", ID_SCUBA_DIVER},
|
{"SCUBA_DIVER", ID_SCUBA_DIVER},
|
||||||
{"GOON_SILENCER1", ID_GOON_SILENCER1},
|
{"GOON_SILENCER1", ID_GOON_SILENCER1},
|
||||||
|
|
|
@ -148,9 +148,11 @@ xcopy /Y "$(ProjectDir)Scripting\Scripts\*.lua" "$(TargetDir)\Scripts"</Command>
|
||||||
<ClInclude Include="Libs\zlib\zip.h" />
|
<ClInclude Include="Libs\zlib\zip.h" />
|
||||||
<ClInclude Include="Libs\zlib\zlib.h" />
|
<ClInclude Include="Libs\zlib\zlib.h" />
|
||||||
<ClInclude Include="Objects\Effects\tr4_bubbles.h" />
|
<ClInclude Include="Objects\Effects\tr4_bubbles.h" />
|
||||||
|
<ClInclude Include="Objects\Effects\tr4_locusts.h" />
|
||||||
<ClInclude Include="Objects\Effects\tr5_electricity.h" />
|
<ClInclude Include="Objects\Effects\tr5_electricity.h" />
|
||||||
<ClInclude Include="Objects\TR1\Entity\tr1_bigrat.h" />
|
<ClInclude Include="Objects\TR1\Entity\tr1_bigrat.h" />
|
||||||
<ClInclude Include="Objects\TR4\Entity\tr4_baboon.h" />
|
<ClInclude Include="Objects\TR4\Entity\tr4_baboon.h" />
|
||||||
|
<ClInclude Include="Objects\TR4\Entity\tr4_mutant.h" />
|
||||||
<ClInclude Include="Objects\TR4\Object\tr4_laradouble.h" />
|
<ClInclude Include="Objects\TR4\Object\tr4_laradouble.h" />
|
||||||
<ClInclude Include="Objects\TR4\Object\tr4_sarcophagus.h" />
|
<ClInclude Include="Objects\TR4\Object\tr4_sarcophagus.h" />
|
||||||
<ClInclude Include="Objects\TR4\Object\tr4_scales.h" />
|
<ClInclude Include="Objects\TR4\Object\tr4_scales.h" />
|
||||||
|
@ -390,9 +392,11 @@ xcopy /Y "$(ProjectDir)Scripting\Scripts\*.lua" "$(TargetDir)\Scripts"</Command>
|
||||||
<ClCompile Include="Game\footprint.cpp" />
|
<ClCompile Include="Game\footprint.cpp" />
|
||||||
<ClCompile Include="Game\misc.cpp" />
|
<ClCompile Include="Game\misc.cpp" />
|
||||||
<ClCompile Include="Game\trmath.cpp" />
|
<ClCompile Include="Game\trmath.cpp" />
|
||||||
|
<ClCompile Include="Objects\Effects\tr4_locusts.cpp" />
|
||||||
<ClCompile Include="Objects\Effects\tr5_electricity.cpp" />
|
<ClCompile Include="Objects\Effects\tr5_electricity.cpp" />
|
||||||
<ClCompile Include="Objects\TR1\Entity\tr1_bigrat.cpp" />
|
<ClCompile Include="Objects\TR1\Entity\tr1_bigrat.cpp" />
|
||||||
<ClCompile Include="Objects\TR4\Entity\tr4_baboon.cpp" />
|
<ClCompile Include="Objects\TR4\Entity\tr4_baboon.cpp" />
|
||||||
|
<ClCompile Include="Objects\TR4\Entity\tr4_mutant.cpp" />
|
||||||
<ClCompile Include="Objects\TR4\Object\tr4_laradouble.cpp" />
|
<ClCompile Include="Objects\TR4\Object\tr4_laradouble.cpp" />
|
||||||
<ClCompile Include="Objects\TR4\Object\tr4_sarcophagus.cpp" />
|
<ClCompile Include="Objects\TR4\Object\tr4_sarcophagus.cpp" />
|
||||||
<ClCompile Include="Objects\TR4\Object\tr4_scales.cpp" />
|
<ClCompile Include="Objects\TR4\Object\tr4_scales.cpp" />
|
||||||
|
|
|
@ -780,6 +780,12 @@
|
||||||
<ClInclude Include="Objects\TR1\Entity\tr1_bigrat.h">
|
<ClInclude Include="Objects\TR1\Entity\tr1_bigrat.h">
|
||||||
<Filter>File di intestazione</Filter>
|
<Filter>File di intestazione</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="Objects\Effects\tr4_locusts.h">
|
||||||
|
<Filter>File di intestazione</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="Objects\TR4\Entity\tr4_mutant.h">
|
||||||
|
<Filter>File di intestazione</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="Game\box.cpp">
|
<ClCompile Include="Game\box.cpp">
|
||||||
|
@ -1427,6 +1433,12 @@
|
||||||
<ClCompile Include="Objects\TR1\Entity\tr1_bigrat.cpp">
|
<ClCompile Include="Objects\TR1\Entity\tr1_bigrat.cpp">
|
||||||
<Filter>File di origine</Filter>
|
<Filter>File di origine</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="Objects\Effects\tr4_locusts.cpp">
|
||||||
|
<Filter>File di origine</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="Objects\TR4\Entity\tr4_mutant.cpp">
|
||||||
|
<Filter>File di origine</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="packages.config" />
|
<None Include="packages.config" />
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue