TombEngine/TR5Main/Objects/trap.cpp

1050 lines
25 KiB
C++
Raw Normal View History

#include "newobjects.h"
#include "../Game/Box.h"
#include "../Game/items.h"
#include "../Game/lot.h"
#include "../Game/control.h"
#include "../Game/people.h"
#include "../Game/effects.h"
#include "../Game/effect2.h"
#include "../Game/draw.h"
#include "../Game/sphere.h"
#include "../Game/inventory.h"
#include "../Game/collide.h"
#include "../Game/draw.h"
#include "../Game/tomb4fx.h"
#include "../Game/misc.h"
short StargateBounds[24] =
{
0xFE00, 0x0200, 0xFC00, 0xFC80, 0xFFA0, 0x0060, 0xFE00, 0x0200,
0xFF80, 0x0000, 0xFFA0, 0x0060, 0xFE00, 0xFE80, 0xFC00, 0x0000,
0xFFA0, 0x0060, 0x0180, 0x0200, 0xFC00, 0x0000, 0xFFA0, 0x0060
};
BITE_INFO sentryGunBite = { 0, 0, 0, 8 };
void FourBladesControl(short itemNum)
{
ITEM_INFO* item = &Items[itemNum];
if (!TriggerActive(item))
{
item->frameNumber = Anims[item->animNumber].frameBase;
item->itemFlags[0] = 0;
}
else
{
short frameNumber = item->frameNumber - Anims[item->animNumber].frameBase;
if (frameNumber <= 5 || frameNumber >= 58 || frameNumber >= 8 && frameNumber <= 54)
item->itemFlags[0] = 0;
else
{
if (frameNumber >= 6 && frameNumber <= 7)
{
item->itemFlags[3] = 20;
item->itemFlags[0] = 30;
}
else
{
if (frameNumber >= 55 && frameNumber <= 57)
{
item->itemFlags[3] = 200;
item->itemFlags[0] = 30;
}
}
}
AnimateItem(item);
}
}
void BirdBladeControl(short itemNum)
{
ITEM_INFO* item = &Items[itemNum];
item->itemFlags[3] = 100;
if (!TriggerActive(item))
{
item->frameNumber = Anims[item->animNumber].frameBase;
item->itemFlags[0] = 0;
}
else
{
short frameNumber = item->frameNumber - Anims[item->animNumber].frameBase;
if (frameNumber <= 14 || frameNumber >= 31)
item->itemFlags[0] = 0;
else
item->itemFlags[0] = 6;
AnimateItem(item);
}
}
void CatwalkBlaldeControl(short itemNum)
{
ITEM_INFO* item = &Items[itemNum];
if (!TriggerActive(item))
{
item->frameNumber = Anims[item->animNumber].frameBase;
item->itemFlags[0] = 0;
}
else
{
short frameNumber = item->frameNumber - Anims[item->animNumber].frameBase;
if (item->frameNumber == Anims[item->animNumber].frameEnd || frameNumber < 38)
item->itemFlags[3] = 0;
else
item->itemFlags[3] = 100;
AnimateItem(item);
}
}
void PlinthBladeControl(short itemNum)
{
ITEM_INFO* item = &Items[itemNum];
if (!TriggerActive(item))
{
item->frameNumber = Anims[item->animNumber].frameBase;
}
else
{
short frameNumber = item->frameNumber - Anims[item->animNumber].frameBase;
if (item->frameNumber == Anims[item->animNumber].frameEnd)
item->itemFlags[3] = 0;
else
item->itemFlags[3] = 200;
AnimateItem(item);
}
}
void InitialiseSethBlade(short itemNum)
{
ITEM_INFO* item = &Items[itemNum];
item->animNumber = Objects[ID_SETH_BLADE].animIndex + 1;
item->goalAnimState = 2;
item->currentAnimState = 2;
item->frameNumber = Anims[item->animNumber].frameBase;
item->itemFlags[2] = abs(item->triggerFlags);
}
void SethBladeControl(short itemNum)
{
ITEM_INFO* item = &Items[itemNum];
item->itemFlags[0] = 0;
if (TriggerActive(item))
{
if (item->currentAnimState == 2)
{
if (item->itemFlags[2] > 1)
{
item->itemFlags[2]--;
}
else if (item->itemFlags[2] == 1)
{
item->goalAnimState = 1;
item->itemFlags[2] = 0;
}
else if (!item->itemFlags[2])
{
if (item->triggerFlags > 0)
{
item->itemFlags[2] = item->triggerFlags;
}
}
}
else
{
short frameNumber = item->frameNumber - Anims[item->animNumber].frameBase;
if (item->frameNumber != Anims[item->animNumber].frameBase && frameNumber <= 6)
{
item->itemFlags[0] = -1;
item->itemFlags[3] = 1000;
}
else if (frameNumber >= 7 && frameNumber <= 15)
{
item->itemFlags[0] = 448;
item->itemFlags[3] = 1000;
}
else
{
item->itemFlags[0] = 0;
item->itemFlags[3] = 1000;
}
}
AnimateItem(item);
}
}
void ChainControl(short itemNum)
{
ITEM_INFO* item = &Items[itemNum];
if (item->triggerFlags)
{
item->itemFlags[2] = 1;
item->itemFlags[3] = 75;
if (TriggerActive(item))
{
item->itemFlags[0] = 30846;
AnimateItem(item);
return;
}
}
else
{
item->itemFlags[3] = 25;
if (TriggerActive(item))
{
item->itemFlags[0] = 1920;
AnimateItem(item);
return;
}
}
item->itemFlags[0] = 0;
}
void PloughControl(short itemNum)
{
ITEM_INFO* item = &Items[itemNum];
item->itemFlags[3] = 50;
if (TriggerActive(item))
{
item->itemFlags[0] = 258048;
AnimateItem(item);
}
else
{
item->itemFlags[0] = 0;
}
}
void CogControl(short itemNum)
{
ITEM_INFO* item = &Items[itemNum];
if (TriggerActive(item))
{
item->status = ITEM_ACTIVE;
// *(_DWORD *)&item->gap4C[5526] = *(_DWORD *)&item->gap4C[5526] & 0xFFFFFFFB | 2;
AnimateItem(item);
if (item->triggerFlags == 666)
{
PHD_VECTOR pos;
GetJointAbsPosition(item, &pos, 0);
SoundEffect(65, (PHD_3DPOS *)&pos, 0);
if (item->frameNumber == Anims[item->animNumber].frameEnd)
item->flags &= 0xC1;
}
}
else if (item->triggerFlags == 2)
{
item->status |= ITEM_INVISIBLE;
}
}
void SpikeballControl(short itemNum)
{
ITEM_INFO* item = &Items[itemNum];
if (TriggerActive(item))
{
short frameNumber = item->frameNumber - Anims[item->animNumber].frameBase;
if ((frameNumber <= 14 || frameNumber >= 24) && (frameNumber < 138 || frameNumber > 140))
{
if (frameNumber < 141)
item->itemFlags[0] = 0;
else
{
item->itemFlags[3] = 50;
item->itemFlags[0] = 0x7FF800;
}
}
else
{
item->itemFlags[3] = 150;
item->itemFlags[0] = 0x7FF800;
}
AnimateItem(item);
}
else
{
item->frameNumber = Anims[item->animNumber].frameBase;
item->itemFlags[0] = 0;
}
}
void StargateControl(short itemNum)
{
ITEM_INFO* item = &Items[itemNum];
item->itemFlags[3] = 50;
if (TriggerActive(item))
{
SoundEffect(SFX_TR4_STARGATE_SWIRL, &item->pos, 0);
item->itemFlags[0] = 57521664;
AnimateItem(item);
}
else
item->itemFlags[0] = 0;
}
void StargateCollision(short itemNum, ITEM_INFO* l, COLL_INFO* c)
{
ITEM_INFO* item = &Items[itemNum];
if (item->status == ITEM_INVISIBLE)
return;
if (TestBoundsCollide(item, l, c->radius))
{
for (int i = 0; i < 8; i++)
{
GlobalCollisionBounds.X1 = StargateBounds[3 * i + 0];
GlobalCollisionBounds.Y1 = StargateBounds[3 * i + 1];
GlobalCollisionBounds.Z1 = StargateBounds[3 * i + 2];
if (TestWithGlobalCollisionBounds(item, l, c))
ItemPushLara(item, l, c, 0, 2);
}
int result = TestCollision(item, l);
if (result)
{
result &= item->itemFlags[0];
int flags = item->itemFlags[0];
if (result)
{
int j = 0;
do
{
if (result & 1)
{
GlobalCollisionBounds.X1 = SphereList[j].x - SphereList[j].r - item->pos.xPos;
GlobalCollisionBounds.Y1 = SphereList[j].y - SphereList[j].r - item->pos.yPos;
GlobalCollisionBounds.Z1 = SphereList[j].z - SphereList[j].r - item->pos.zPos;
GlobalCollisionBounds.X2 = SphereList[j].x + SphereList[j].r - item->pos.xPos;
GlobalCollisionBounds.Y2 = SphereList[j].y + SphereList[j].r - item->pos.yPos;
GlobalCollisionBounds.Z2 = SphereList[j].z + SphereList[j].r - item->pos.zPos;
int oldX = LaraItem->pos.xPos;
int oldY = LaraItem->pos.yPos;
int oldZ = LaraItem->pos.zPos;
if (ItemPushLara(item, l, c, flags & 1, 2))
{
if ((flags & 1) &&
(oldX != LaraItem->pos.xPos || oldY != LaraItem->pos.yPos || oldZ != LaraItem->pos.zPos) &&
TriggerActive(item))
{
DoBloodSplat((GetRandomControl() & 0x3F) + l->pos.xPos - 32,
(GetRandomControl() & 0x1F) + SphereList[j].y - 16,
(GetRandomControl() & 0x3F) + l->pos.zPos - 32,
(GetRandomControl() & 3) + 2,
2 * GetRandomControl(),
l->roomNumber);
LaraItem->hitPoints -= 100;
}
}
}
result >>= 1;
j++;
flags >>= 1;
} while (result);
}
}
}
}
void ControlSpikyWall(short itemNum)
{
ITEM_INFO* item = &Items[itemNum];
/* Move wall */
if (TriggerActive(item) && item->status != ITEM_DEACTIVATED)
{
int x = item->pos.xPos + SIN(item->pos.yRot) >> WALL_SHIFT;
int z = item->pos.zPos + COS(item->pos.yRot) >> WALL_SHIFT;
short roomNumber = item->roomNumber;
FLOOR_INFO* floor = GetFloor(x, item->pos.yPos, z, &roomNumber);
if (GetFloorHeight(floor, x, item->pos.yPos, z) != item->pos.yPos)
{
item->status = ITEM_DEACTIVATED;
StopSoundEffect(SFX_ROLLING_BALL);
}
else
{
item->pos.xPos = x;
item->pos.zPos = z;
if (roomNumber != item->roomNumber)
ItemNewRoom(itemNum, roomNumber);
SoundEffect(SFX_ROLLING_BALL, &item->pos, 0);
}
}
if (item->touchBits)
{
LaraItem->hitPoints -= 15;
LaraItem->hitStatus = true;
DoLotsOfBlood(LaraItem->pos.xPos, LaraItem->pos.yPos - 512, LaraItem->pos.zPos, 4, item->pos.yRot, LaraItem->roomNumber, 3);
item->touchBits = 0;
SoundEffect(56, &item->pos, 0);
}
}
void InitialiseSpinningBlade(short item_number)
{
ITEM_INFO* item = &Items[item_number];
item->animNumber = Objects[item->objectNumber].animIndex + 3;
item->frameNumber = Anims[item->animNumber].frameBase;
item->currentAnimState = 1;
}
void SpinningBlade(short item_number)
{
bool spinning = false;
ITEM_INFO* item = &Items[item_number];
if (item->currentAnimState == 2)
{
if (item->goalAnimState != 1)
{
int x = item->pos.xPos + (WALL_SIZE * 3 / 2 * SIN(item->pos.yRot) >> W2V_SHIFT);
int z = item->pos.zPos + (WALL_SIZE * 3 / 2 * COS(item->pos.yRot) >> W2V_SHIFT);
short roomNumber = item->roomNumber;
FLOOR_INFO* floor = GetFloor(x, item->pos.yPos, z, &roomNumber);
int height = GetFloorHeight(floor, x, item->pos.yPos, z);
if (height == NO_HEIGHT)
item->goalAnimState = 1;
}
spinning = true;
if (item->touchBits)
{
LaraItem->hitStatus = true;
LaraItem->hitPoints -= 100;
DoLotsOfBlood(LaraItem->pos.xPos, LaraItem->pos.yPos - STEP_SIZE * 2, LaraItem->pos.zPos, (short)(item->speed * 2), LaraItem->pos.yRot, LaraItem->roomNumber, 2);
}
SoundEffect(231, &item->pos, 0);
}
else
{
if (TriggerActive(item))
item->goalAnimState = 2;
spinning = false;
}
AnimateItem(item);
short roomNumber = item->roomNumber;
FLOOR_INFO* floor = GetFloor(item->pos.xPos, item->pos.yPos, item->pos.zPos, &roomNumber);
item->floor = item->pos.yPos = GetFloorHeight(floor, item->pos.xPos, item->pos.yPos, item->pos.zPos);
if (roomNumber != item->roomNumber)
ItemNewRoom(item_number, roomNumber);
if (spinning && item->currentAnimState == 1)
item->pos.yRot += -ANGLE(180);
}
void InitialiseKillerStatue(short item_number)
{
ITEM_INFO* item = &Items[item_number];
item->animNumber = Objects[item->objectNumber].animIndex + 3;
item->frameNumber = Anims[item->animNumber].frameBase;
item->currentAnimState = 1;
}
void KillerStatueControl(short item_number)
{
ITEM_INFO *item;
int x, y, z;
short d;
item = &Items[item_number];
if (TriggerActive(item) && item->currentAnimState == 1)
item->goalAnimState = 2;
else
item->goalAnimState = 1;
if ((item->touchBits & 0x80) && item->currentAnimState == 2)
{
LaraItem->hitStatus = 1;
LaraItem->hitPoints -= 20;
int x = LaraItem->pos.xPos + (GetRandomControl() - 16384) / 256;
int z = LaraItem->pos.zPos + (GetRandomControl() - 16384) / 256;
int y = LaraItem->pos.yPos - GetRandomControl() / 44;
int d = (GetRandomControl() - 16384) / 8 + LaraItem->pos.yRot;
DoBloodSplat(x, y, z, LaraItem->speed, d, LaraItem->roomNumber);
}
AnimateItem(item);
}
void SpringBoardControl(short item_number)
{
ITEM_INFO* item = &Items[item_number];
if (item->currentAnimState == 0 && LaraItem->pos.yPos == item->pos.yPos &&
(LaraItem->pos.xPos >> WALL_SHIFT) == (item->pos.xPos >> WALL_SHIFT) &&
(LaraItem->pos.zPos >> WALL_SHIFT) == (item->pos.zPos >> WALL_SHIFT))
{
if (LaraItem->hitPoints <= 0)
return;
if (LaraItem->currentAnimState == STATE_LARA_WALK_BACK || LaraItem->currentAnimState == STATE_LARA_RUN_BACK)
LaraItem->speed = -LaraItem->speed;
LaraItem->fallspeed = -240;
LaraItem->gravityStatus = true;
LaraItem->animNumber = ANIMATION_LARA_FREE_FALL_FORWARD;
LaraItem->frameNumber = GF2(ID_LARA, ANIMATION_LARA_FREE_FALL_FORWARD, 0);
LaraItem->currentAnimState = STATE_LARA_JUMP_FORWARD;
LaraItem->goalAnimState = STATE_LARA_JUMP_FORWARD;
item->goalAnimState = 1;
}
AnimateItem(item);
}
void InitialiseSlicerDicer(short itemNum)
{
ITEM_INFO* item = &Items[itemNum];
int dx = SIN(item->pos.yRot + ANGLE(90)) >> 5;
int dz = COS(item->pos.yRot + ANGLE(90)) >> 5;
item->pos.xPos += dx;
item->pos.zPos += dz;
item->itemFlags[0] = item->pos.xPos >> 8;
item->itemFlags[1] = (item->pos.yPos - 4608) >> 8;
item->itemFlags[2] = item->pos.zPos >> 8;
item->itemFlags[3] = 50;
}
void SlicerDicerControl(short itemNum)
{
ITEM_INFO* item = &Items[itemNum];
SoundEffect(SFX_TR4_METAL_SCRAPE_LOOP1, &item->pos, 0);
SoundEffect(SFX_TR4_METAL_SCRAPE_LOOP, &item->pos, 0);
int factor = (9 * COS(item->triggerFlags) << 9 >> W2V_SHIFT) * COS(item->pos.yRot) >> W2V_SHIFT;
item->pos.xPos = (item->itemFlags[0] << 8) + factor;
item->pos.yPos = (item->itemFlags[1] << 8) - 4608 * SIN(item->triggerFlags);
item->pos.zPos = (item->itemFlags[2] << 8) + factor;
item->triggerFlags += 170;
short roomNumber = item->roomNumber;
GetFloor(item->pos.xPos, item->pos.yPos, item->pos.zPos, &roomNumber);
if (item->roomNumber != roomNumber)
ItemNewRoom(itemNum, roomNumber);
AnimateItem(item);
}
void BladeCollision(short itemNum, ITEM_INFO* l, COLL_INFO* coll)
{
ITEM_INFO* item = &Items[itemNum];
if (item->status == ITEM_INVISIBLE)
return;
if (item->itemFlags[3]) // Check this
{
if (TestBoundsCollide(item, l, coll->radius))
{
int oldX = LaraItem->pos.xPos;
int oldY = LaraItem->pos.yPos;
int oldZ = LaraItem->pos.zPos;
int dx = 0;
int dy = 0;
int dz = 0;
if (ItemPushLara(item, l, coll, 1, 1))
{
LaraItem->hitPoints -= item->itemFlags[3];
dx = oldX - LaraItem->pos.xPos;
dy = oldY - LaraItem->pos.yPos;
dz = oldZ - LaraItem->pos.zPos;
if ((dx || dy || dz) && TriggerActive(item))
{
DoBloodSplat((GetRandomControl() & 0x3F) + l->pos.xPos - 32,
l->pos.yPos - (GetRandomControl() & 0x1FF) - 256,
(GetRandomControl() & 0x3F) + l->pos.zPos - 32,
(GetRandomControl() & 3) + (item->itemFlags[3] >> 5) + 2,
2 * GetRandomControl(),
l->roomNumber);
}
if (!coll->enableBaddiePush)
{
LaraItem->pos.xPos += dx;
LaraItem->pos.yPos += dy;
LaraItem->pos.zPos += dz;
}
}
}
}
}
void InitialiseMine(short itemNum)
{
ITEM_INFO* item = &Items[itemNum];
if (item->triggerFlags)
item->meshBits = 0;
}
void MineControl(short itemNum)
{
ITEM_INFO* item = &Items[itemNum];
int num = GetSpheres(item, SphereList, true);
if (item->itemFlags[0] >= 150)
{
SoundEffect(SFX_EXPLOSION1, &item->pos, 0);
SoundEffect(SFX_EXPLOSION2, &item->pos, 0);
SoundEffect(SFX_EXPLOSION1, &item->pos, 0x1800004);
if (num > 0)
{
SPHERE* sphere = &SphereList[0];
for (int i = 0; i < num; i++)
{
if (i >= 7 && i != 9)
{
TriggerExplosionSparks(sphere->x, sphere->y, sphere->z, 3, -2, 0, -item->roomNumber);
TriggerExplosionSparks(sphere->x, sphere->y, sphere->z, 3, -1, 0, -item->roomNumber);
TriggerShockwave((PHD_3DPOS*)sphere, 0x3000, 0x3001, (GetRandomControl() & 0x1F) + 112, 0, 96, 128, 32, 2048, 0);
}
sphere++;
}
for (int i = 0; i < num; i++)
ExplodeItemNode(item, i, 0, -128);
}
FlashFadeR = 255;
FlashFadeG = 192;
FlashFadeB = 64;
FlashFader = 32;
short currentItemNumber = Rooms[item->roomNumber].itemNumber;
// Make the sentry gun explode?
while (currentItemNumber != NO_ITEM)
{
ITEM_INFO* currentItem = &Items[currentItemNumber];
if (currentItem->objectNumber == ID_SENTRY_GUN)
currentItem->meshBits &= ~0x40;
currentItemNumber = currentItem->nextItem;
}
KillItem(itemNum);
}
else
{
item->itemFlags[0]++;
int something = 4 * item->itemFlags[0];
if (something > 255)
something = 0;
for (int i = 0; i < num; i++)
{
SPHERE* sphere = &SphereList[i];
if (i == 0 || i > 5)
AddFire(sphere->x, sphere->y, sphere->z, 2, item->roomNumber, something);
sphere++;
}
SoundEffect(SFX_LOOP_FOR_SMALL_FIRES, &item->pos, 0);
}
}
void MineCollision(short itemNum, ITEM_INFO* l, COLL_INFO* coll)
{
ITEM_INFO* item = &Items[itemNum];
if (item->triggerFlags && !item->itemFlags[3])
{
if (l->animNumber != 432 || l->frameNumber < Anims[item->animNumber].frameBase + 57)
{
if (TestBoundsCollide(item, l, 512))
{
TriggerExplosionSparks(item->pos.xPos, item->pos.yPos, item->pos.zPos, 3, -2, 0, item->roomNumber);
for (int i = 0; i < 2; i++)
TriggerExplosionSparks(item->pos.xPos, item->pos.yPos, item->pos.zPos, 3, -1, 0, item->roomNumber);
item->meshBits = 1;
ExplodeItemNode(item, 0, 0, 128);
KillItem(itemNum);
l->animNumber = 438;
l->frameNumber = Anims[item->animNumber].frameBase;
l->currentAnimState = 8;
l->speed = 0;
SoundEffect(SFX_TR4_MINE_EXP_OVERLAY, &item->pos, 0);
}
}
else
{
for (int i = 0; i < LevelItems; i++)
{
ITEM_INFO* currentItem = &Items[i];
// Explode other mines
if (currentItem->objectNumber == ID_MINE && currentItem->status != ITEM_INVISIBLE && !currentItem->triggerFlags)
{
TriggerExplosionSparks(
currentItem->pos.xPos,
currentItem->pos.yPos,
currentItem->pos.zPos,
3,
-2,
0,
currentItem->roomNumber);
for (int j = 0; j < 2; j++)
TriggerExplosionSparks(
currentItem->pos.xPos,
currentItem->pos.yPos,
currentItem->pos.zPos,
3,
-1,
0,
currentItem->roomNumber);
currentItem->meshBits = 1;
ExplodeItemNode(currentItem, 0, 0, -32);
KillItem(i);
if (!(GetRandomControl() & 3))
SoundEffect(SFX_TR4_MINE_EXP_OVERLAY, &currentItem->pos, 0);
currentItem->status = ITEM_INVISIBLE;
}
}
}
}
}
void InitialiseSentryGun(short itemNum)
{
ITEM_INFO* item = &Items[itemNum];
ClearItem(itemNum);
item->itemFlags[0] = 0;
item->itemFlags[1] = 768;
item->itemFlags[2] = 0;
}
void SentryGunControl(short itemNum)
{
ITEM_INFO* item = &Items[itemNum];
if (!CreatureActive(itemNum))
return;
CREATURE_INFO* creature = (CREATURE_INFO*)item->data;
2018-11-27 11:15:30 +01:00
AI_INFO info;
int c = 0;
if (creature)
{
// Flags set by the ID_MINE object?
if (item->meshBits & 0x40)
{
if (item->itemFlags[0])
{
PHD_VECTOR pos;
pos.x = sentryGunBite.x;
pos.y = sentryGunBite.y;
pos.z = sentryGunBite.z;
GetJointAbsPosition(item, &pos, sentryGunBite.meshNum);
2019-12-01 08:13:19 +01:00
TriggerDynamicLight(pos.x, pos.y, pos.z, 4 * item->itemFlags[0] + 12, 24, 16, 4);
item->itemFlags[0]--;
}
if (item->itemFlags[0] & 1)
item->meshBits |= 0x100;
else
item->meshBits &= ~0x100;
if (item->triggerFlags == 0)
{
item->pos.yPos -= 512;
CreatureAIInfo(item, &info);
item->pos.yPos += 512;
int deltaAngle = info.angle - creature->jointRotation[0];
//printf("Angle: %d\n", (int)TR_ANGLE_TO_DEGREES(info.angle));
info.ahead = true;
2018-11-27 11:15:30 +01:00
if (deltaAngle <= -ANGLE(90) || deltaAngle >= ANGLE(90))
info.ahead = false;
if (Targetable(item, &info))
{
if (info.distance < SQUARE(9 * WALL_SIZE))
{
if (!g_Inventory->IsObjectPresentInInventory(ID_PUZZLE_ITEM5) &&
!item->itemFlags[0])
{
2018-11-27 11:15:30 +01:00
if (info.distance <= SQUARE(2048))
{
// Throw fire
SentryGunThrowFire(item);
c = 4 * rcossin_tbl[(GlobalCounter & 0x1F) << 11 >> 3] >> 2;
}
else
{
// Shot to Lara with bullets
2018-11-27 11:15:30 +01:00
c = 0;
item->itemFlags[0] = 2;
2018-11-27 11:15:30 +01:00
ShotLara(item, &info, &sentryGunBite, creature->jointRotation[0], 5);
SoundEffect(SFX_TR4_AUTOGUNS, &item->pos, 0);
2018-11-27 11:15:30 +01:00
item->itemFlags[2] += 256;
if (item->itemFlags[2] > 6144)
{
item->itemFlags[2] = 6144;
}
2018-11-27 11:15:30 +01:00
}
}
deltaAngle = c + info.angle - creature->jointRotation[0];
if (deltaAngle <= ANGLE(10))
{
if (deltaAngle < -ANGLE(10))
{
deltaAngle = -ANGLE(10);
}
}
2018-11-27 11:15:30 +01:00
else
{
deltaAngle = ANGLE(10);
}
creature->jointRotation[0] += deltaAngle;
2018-11-27 11:15:30 +01:00
CreatureJoint(item, 1, -info.xAngle);
}
}
2018-11-27 11:15:30 +01:00
item->itemFlags[2] -= 32;
if (item->itemFlags[2] < 0)
2018-11-27 11:15:30 +01:00
{
item->itemFlags[2] = 0;
}
creature->jointRotation[3] += item->itemFlags[2];
creature->jointRotation[2] += item->itemFlags[1];
if (creature->jointRotation[2] > ANGLE(90) ||
creature->jointRotation[2] < -ANGLE(90))
{
item->itemFlags[1] = -item->itemFlags[1];
}
}
else
{
// Stuck sentry gun
2018-11-27 11:15:30 +01:00
CreatureJoint(item, 0, (GetRandomControl() & 0x7FF) - 1024);
CreatureJoint(item, 1, ANGLE(45));
CreatureJoint(item, 2, (GetRandomControl() & 0x3FFF) - ANGLE(45));
}
}
2018-11-27 11:15:30 +01:00
else
{
ExplodingDeath(itemNum, -1, 257);
DisableBaddieAI(itemNum);
KillItem(itemNum);
item->flags |= 1u;
item->status = ITEM_DEACTIVATED;
RemoveAllItemsInRoom(item->roomNumber, ID_SMOKE_EMITTER_BLACK);
TriggerExplosionSparks(item->pos.xPos, item->pos.yPos - 768, item->pos.zPos, 3, -2, 0, item->roomNumber);
for (int i = 0; i < 2; i++)
2018-11-27 11:15:30 +01:00
TriggerExplosionSparks(item->pos.xPos, item->pos.yPos - 768, item->pos.zPos, 3, -1, 0, item->roomNumber);
SoundEffect(SFX_EXPLOSION1, &item->pos, 25165828);
SoundEffect(SFX_EXPLOSION2, &item->pos, 0);
2018-11-27 11:15:30 +01:00
}
}
2018-11-27 11:15:30 +01:00
}
void SentryGunThrowFire(ITEM_INFO* item)
2018-11-27 11:15:30 +01:00
{
for (int i = 0; i < 3; i++)
{
2018-11-27 11:15:30 +01:00
SPARKS* spark = &Sparks[GetFreeSpark()];
spark->on = 1;
spark->sR = (GetRandomControl() & 0x1F) + 48;
spark->sG = 48;
spark->sB = 255;
spark->dR = (GetRandomControl() & 0x3F) - 64;
spark->dG = (GetRandomControl() & 0x3F) + -128;
spark->dB = 32;
spark->colFadeSpeed = 12;
spark->fadeToBlack = 8;
spark->transType = 2;
spark->life = spark->sLife = (GetRandomControl() & 0x1F) + 16;
PHD_VECTOR pos1;
pos1.x = -140;
pos1.y = -30;
pos1.z = -4;
GetJointAbsPosition(item, &pos1, 7);
spark->x = (GetRandomControl() & 0x1F) + pos1.x - 16;
spark->y = (GetRandomControl() & 0x1F) + pos1.y - 16;
spark->z = (GetRandomControl() & 0x1F) + pos1.z - 16;
PHD_VECTOR pos2;
pos2.x = -280;
pos2.y = -30;
pos2.z = -4;
GetJointAbsPosition(item, &pos2, 7);
int v = (GetRandomControl() & 0x3F) + 192;
2018-11-27 11:15:30 +01:00
spark->xVel = v * (pos2.x - pos1.x) / 10;
spark->yVel = v * (pos2.y - pos1.y) / 10;
spark->zVel = v * (pos2.z - pos1.z) / 10;
spark->friction = 85;
spark->gravity = -16 - (GetRandomControl() & 0x1F);
spark->maxYvel = 0;
spark->flags = 538;
if ((GlobalCounter & 1) != 0)
{
v = 255;
spark->flags = 539;
}
2018-11-27 11:15:30 +01:00
spark->scalar = 3;
spark->dSize = v * ((GetRandomControl() & 7) + 60) >> 8;
spark->sSize = spark->dSize >> 4;
spark->size = spark->dSize >> 4;
}
}
void InitialiseBurningFloor(short itemNum)
{
Items[itemNum].requiredAnimState = 127;
}
void BurningFloorControl(short itemNum)
{
}
void ControlSpikyCeiling(short itemNumber)
{
ITEM_INFO* item = &Items[itemNumber];
if (TriggerActive(item) && item->status != ITEM_DEACTIVATED)
{
int y = item->pos.yPos + ((item->itemFlags[0] == 1) ? 10 : 5);
short roomNumber = item->roomNumber;
FLOOR_INFO* floor = GetFloor(item->pos.xPos, y, item->pos.zPos, &roomNumber);
if (GetFloorHeight(floor, item->pos.xPos, y, item->pos.zPos) < y + 1024)
{
item->status = ITEM_DEACTIVATED;
StopSoundEffect(147);
}
else
{
item->pos.yPos = y;
if (roomNumber != item->roomNumber)
ItemNewRoom(itemNumber, roomNumber);
SoundEffect(147, &item->pos, 0);
}
}
if (item->touchBits)
{
LaraItem->hitPoints -= 20;
LaraItem->hitStatus = true;
DoLotsOfBlood(LaraItem->pos.xPos, item->pos.yPos + 768, LaraItem->pos.zPos,
4, item->pos.yRot, LaraItem->roomNumber, 3);
item->touchBits = 0;
SoundEffect(56, &item->pos, 0);
}
if (TriggerActive(item) && item->status != ITEM_DEACTIVATED && item->itemFlags[0] == 1)
AnimateItem(item);
}