TombEngine/TR5Main/Objects/Generic/Object/objects.cpp

403 lines
10 KiB
C++
Raw Normal View History

2020-12-21 13:16:29 -03:00
#include "framework.h"
#include "Objects/Generic/Object/objects.h"
2021-12-22 16:23:57 +03:00
#include "Game/items.h"
#include "Game/effects/effects.h"
#include "Game/animation.h"
#include "Game/Lara/lara.h"
#include "Game/Lara/lara_helpers.h"
2021-12-22 16:23:57 +03:00
#include "Game/collision/sphere.h"
#include "Game/control/control.h"
#include "Specific/setup.h"
#include "Specific/level.h"
#include "Specific/input.h"
2021-09-25 16:00:30 +03:00
#include "Sound/sound.h"
2021-12-22 16:23:57 +03:00
#include "Game/collision/collide_item.h"
2021-09-25 11:27:47 +02:00
2020-12-21 13:16:29 -03:00
OBJECT_TEXTURE* WaterfallTextures[6];
float WaterfallY[6];
int lastWaterfallY = 0;
2021-10-27 19:00:30 +03:00
2020-12-21 13:16:29 -03:00
PHD_VECTOR TightRopePos = { 0, 0, 0 };
2021-10-27 19:00:30 +03:00
OBJECT_COLLISION_BOUNDS TightRopeBounds =
{ -256, 256, 0, 0, -256, 256, ANGLE(-10), ANGLE(10), ANGLE(-30), ANGLE(30), ANGLE(-10), ANGLE(10) };
2020-12-21 13:16:29 -03:00
OBJECT_COLLISION_BOUNDS ParallelBarsBounds =
2021-10-27 19:00:30 +03:00
{ -640, 640, 704, 832, -96, 96, ANGLE(-10), ANGLE(10), ANGLE(-30), ANGLE(30), ANGLE(-10), ANGLE(10) };
2020-12-21 13:16:29 -03:00
void ControlAnimatingSlots(short itemNumber)
{
// TODO: TR5 has here a series of hardcoded OCB codes, this function actually is just a placeholder
ITEM_INFO* item = &g_Level.Items[itemNumber];
if (TriggerActive(item))
AnimateItem(item);
}
void ControlTriggerTriggerer(short itemNumber)
{
ITEM_INFO* item = &g_Level.Items[itemNumber];
FLOOR_INFO* floor = GetFloor(item->Position.xPos, item->Position.yPos, item->Position.zPos, &item->RoomNumber);
2021-08-20 15:26:12 +03:00
if (floor->Flags.MarkTriggerer)
2020-12-21 13:16:29 -03:00
{
2021-08-20 15:26:12 +03:00
if (TriggerActive(item))
floor->Flags.MarkTriggererActive = true;
else
floor->Flags.MarkTriggererActive = false;
2020-12-21 13:16:29 -03:00
}
}
void AnimateWaterfalls()
{
2021-05-21 05:38:20 +02:00
return;
2020-12-21 13:16:29 -03:00
lastWaterfallY = (lastWaterfallY - 7) & 0x3F;
float y = lastWaterfallY * 0.00390625f;
float theY;
for (int i = 0; i < 6; i++)
{
if (Objects[ID_WATERFALL1 + i].loaded)
{
OBJECT_TEXTURE* texture = WaterfallTextures[i];
texture->vertices[0].y = y + WaterfallY[i];
texture->vertices[1].y = y + WaterfallY[i];
texture->vertices[2].y = y + WaterfallY[i] + 0.24609375f;
texture->vertices[3].y = y + WaterfallY[i] + 0.24609375f;
if (i < 5)
{
texture++;
texture->vertices[0].y = y + WaterfallY[i];
texture->vertices[1].y = y + WaterfallY[i];
texture->vertices[2].y = y + WaterfallY[i] + 0.24609375f;
texture->vertices[3].y = y + WaterfallY[i] + 0.24609375f;
}
}
}
}
void ControlWaterfall(short itemNumber)
2020-12-21 13:16:29 -03:00
{
ITEM_INFO* item = &g_Level.Items[itemNumber];
int dx = item->Position.xPos - LaraItem->Position.xPos;
int dy = item->Position.yPos - LaraItem->Position.yPos;
int dz = item->Position.zPos - LaraItem->Position.zPos;
2020-12-21 13:16:29 -03:00
if (dx >= -16384 && dx <= 16384 && dy >= -16384 && dy <= 16384 && dz >= -16384 && dz <= 16384)
2020-12-21 13:16:29 -03:00
{
if (!(Wibble & 0xC))
2020-12-21 13:16:29 -03:00
{
TriggerWaterfallMist(
item->Position.xPos + 68 * phd_sin(item->Position.yRot),
item->Position.yPos,
item->Position.zPos + 68 * phd_cos(item->Position.yRot),
item->Position.yRot >> 4);
2020-12-21 13:16:29 -03:00
}
SoundEffect(SFX_TR4_WATERFALL_LOOP, &item->Position, 0);
2020-12-21 13:16:29 -03:00
}
}
void TightRopeCollision(short itemNum, ITEM_INFO* l, COLL_INFO* coll)
{
ITEM_INFO* item = &g_Level.Items[itemNum];
if (((TrInput & IN_ACTION) == 0
|| l->ActiveState != LS_IDLE
|| l->AnimNumber != LA_STAND_IDLE
|| l->Status == ITEM_INVISIBLE
2020-12-21 13:16:29 -03:00
|| Lara.gunStatus)
&& (!Lara.Control.IsMoving || Lara.interactedItem !=itemNum))
2020-12-21 13:16:29 -03:00
{
#ifdef NEW_TIGHTROPE
if(l->ActiveState == LS_TIGHTROPE_FORWARD &&
l->TargetState != LS_TIGHTROPE_EXIT &&
!Lara.tightrope.canGoOff)
2020-12-21 13:16:29 -03:00
{
if(item->Position.yRot == l->Position.yRot)
2020-12-21 13:16:29 -03:00
{
if(abs(item->Position.xPos - l->Position.xPos) + abs(item->Position.zPos - l->Position.zPos) < 640)
Lara.tightrope.canGoOff = true;
}
}
#else // NEW_TIGHTROPE
if(l->ActiveState == LS_TIGHTROPE_FORWARD &&
l->TargetState != LS_TIGHTROPE_EXIT &&
!Lara.tightRopeOff)
{
if(item->Position.yRot == l->Position.yRot)
{
if(abs(item->Position.xPos - l->Position.xPos) + abs(item->Position.zPos - l->Position.zPos) < 640)
2020-12-21 13:16:29 -03:00
Lara.tightRopeOff = 1;
}
}
#endif
2020-12-21 13:16:29 -03:00
}
else
{
item->Position.yRot += -ANGLE(180);
2020-12-21 13:16:29 -03:00
if (TestLaraPosition(&TightRopeBounds, item, l))
{
if (MoveLaraPosition(&TightRopePos, item, l))
{
l->ActiveState = LS_TIGHTROPE_ENTER;
l->AnimNumber = LA_TIGHTROPE_START;
l->FrameNumber = g_Level.Anims[l->AnimNumber].frameBase;
Lara.Control.IsMoving = false;
ResetLaraFlex(l);
#ifdef NEW_TIGHTROPE
Lara.tightrope.balance = 0;
Lara.tightrope.canGoOff = false;
Lara.tightrope.tightropeItem = itemNum;
Lara.tightrope.timeOnTightrope = 0;
#else // !NEW_TIGHTROPE
2020-12-21 13:16:29 -03:00
Lara.tightRopeOnCount = 60;
Lara.tightRopeOff = 0;
Lara.tightRopeFall = 0;
#endif
2020-12-21 13:16:29 -03:00
}
else
{
Lara.interactedItem = itemNum;
2020-12-21 13:16:29 -03:00
}
item->Position.yRot += -ANGLE(180);
2020-12-21 13:16:29 -03:00
}
else
{
if (Lara.Control.IsMoving && Lara.interactedItem == itemNum)
Lara.Control.IsMoving = false;
item->Position.yRot += -ANGLE(180);
2020-12-21 13:16:29 -03:00
}
}
}
void ParallelBarsCollision(short itemNumber, ITEM_INFO* l, COLL_INFO* coll)
{
ITEM_INFO* item = &g_Level.Items[itemNumber];
if (TrInput & IN_ACTION && l->ActiveState == LS_REACH && l->AnimNumber == LA_REACH)
2020-12-21 13:16:29 -03:00
{
int test1 = TestLaraPosition(&ParallelBarsBounds, item, l);
int test2 = 0;
if (!test1)
{
item->Position.yRot += -ANGLE(180);
2020-12-21 13:16:29 -03:00
test2 = TestLaraPosition(&ParallelBarsBounds, item, l);
item->Position.yRot += -ANGLE(180);
2020-12-21 13:16:29 -03:00
}
if (test1 || test2)
{
l->ActiveState = LS_MISC_CONTROL;
l->AnimNumber = LA_SWINGBAR_GRAB;
l->FrameNumber = g_Level.Anims[l->AnimNumber].frameBase;
l->VerticalVelocity = false;
l->Airborne = false;
2020-12-21 13:16:29 -03:00
ResetLaraFlex(item);
2020-12-21 13:16:29 -03:00
if (test1)
l->Position.yRot = item->Position.yRot;
2020-12-21 13:16:29 -03:00
else
l->Position.yRot = item->Position.yRot + -ANGLE(180);
2020-12-21 13:16:29 -03:00
PHD_VECTOR pos1;
pos1.x = 0;
pos1.y = -128;
pos1.z = 512;
PHD_VECTOR pos2;
pos2.x = 0;
pos2.y = -128;
pos2.z = 512;
GetLaraJointPosition(&pos1, LM_LHAND);
GetLaraJointPosition(&pos2, LM_RHAND);
if (l->Position.yRot & 0x4000)
l->Position.xPos += item->Position.xPos - ((pos1.x + pos2.x) >> 1);
2020-12-21 13:16:29 -03:00
else
l->Position.zPos += item->Position.zPos - ((pos1.z + pos2.z) / 2);
l->Position.yPos += item->Position.yPos - ((pos1.y + pos2.y) / 2);
2020-12-21 13:16:29 -03:00
Lara.interactedItem = itemNumber;
2020-12-21 13:16:29 -03:00
}
else
{
ObjectCollision(itemNumber, l, coll);
}
}
else if (l->ActiveState != LS_BARS_SWING)
2020-12-21 13:16:29 -03:00
{
ObjectCollision(itemNumber, l, coll);
}
}
void CutsceneRopeControl(short itemNumber)
{
ITEM_INFO* item;
PHD_VECTOR pos1;
PHD_VECTOR pos2;
int dx;
int dy;
int dz;
item = &g_Level.Items[itemNumber];
pos1.x = -128;
pos1.y = -72;
pos1.z = -16;
GetJointAbsPosition(&g_Level.Items[item->ItemFlags[2]], &pos1, 0);
2020-12-21 13:16:29 -03:00
pos2.x = 830;
pos2.z = -12;
pos2.y = 0;
GetJointAbsPosition(&g_Level.Items[item->ItemFlags[3]], &pos2, 0);
2020-12-21 13:16:29 -03:00
item->Position.xPos = pos2.x;
item->Position.yPos = pos2.y;
item->Position.zPos = pos2.z;
2020-12-21 13:16:29 -03:00
dx = (pos2.x - pos1.x) * (pos2.x - pos1.x);
dy = (pos2.y - pos1.y) * (pos2.y - pos1.y);
dz = (pos2.z - pos1.z) * (pos2.z - pos1.z);
item->ItemFlags[1] = ((sqrt(dx + dy + dz) * 2) + sqrt(dx + dy + dz)) * 2;
item->Position.xRot = -4869;
2020-12-21 13:16:29 -03:00
}
void HybridCollision(short itemNum, ITEM_INFO* laraitem, COLL_INFO* coll)
{
ITEM_INFO* item;
item = &g_Level.Items[itemNum];
/*if (gfCurrentLevel == LVL5_SINKING_SUBMARINE)
{
if (item->frameNumber < g_Level.Anims[item->animNumber].frame_end)
{
ObjectCollision(itemNum, laraitem, coll);
}
}*/
}
void InitialiseTightRope(short itemNumber)
{
ITEM_INFO* item = &g_Level.Items[itemNumber];
if (item->Position.yRot > 0)
2020-12-21 13:16:29 -03:00
{
if (item->Position.yRot == ANGLE(90))
item->Position.xPos -= 256;
2020-12-21 13:16:29 -03:00
}
else if (item->Position.yRot)
2020-12-21 13:16:29 -03:00
{
if (item->Position.yRot == -ANGLE(180))
2020-12-21 13:16:29 -03:00
{
item->Position.zPos += 256;
2020-12-21 13:16:29 -03:00
}
else if (item->Position.yRot == -ANGLE(90))
2020-12-21 13:16:29 -03:00
{
item->Position.xPos += 256;
2020-12-21 13:16:29 -03:00
}
}
else
{
item->Position.zPos -= 256;
2020-12-21 13:16:29 -03:00
}
}
void InitialiseAnimating(short itemNumber)
{
/*ITEM_INFO* item = &g_Level.Items[itemNumber];
item->ActiveState = 0;
2020-12-21 13:16:29 -03:00
item->animNumber = Objects[item->objectNumber].animIndex;
item->frameNumber = g_Level.Anims[item->animNumber].frameBase;*/
}
void AnimatingControl(short itemNumber)
{
ITEM_INFO* item = &g_Level.Items[itemNumber];
if (!TriggerActive(item))
return;
item->Status = ITEM_ACTIVE;
2020-12-21 13:16:29 -03:00
AnimateItem(item);
// TODO: ID_SHOOT_SWITCH2 probably the bell in Trajan Markets, use LUA for that
/*if (item->frameNumber >= g_Level.Anims[item->animNumber].frameEnd)
{
item->frameNumber = g_Level.Anims[item->animNumber].frameBase;
RemoveActiveItem(itemNumber);
item->aiBits = 0;
item->status = ITEM_NOT_ACTIVE;
}*/
}
void HighObject2Control(short itemNumber)
{
ITEM_INFO* item = &g_Level.Items[itemNumber];
if (!TriggerActive(item))
return;
if (!item->ItemFlags[2])
2020-12-21 13:16:29 -03:00
{
int div = item->TriggerFlags % 10 << 10;
int mod = item->TriggerFlags / 10 << 10;
item->ItemFlags[0] = GetRandomControl() % div;
item->ItemFlags[1] = GetRandomControl() % mod;
item->ItemFlags[2] = (GetRandomControl() & 0xF) + 15;
2020-12-21 13:16:29 -03:00
}
if (--item->ItemFlags[2] < 15)
2020-12-21 13:16:29 -03:00
{
SPARKS* spark = &Sparks[GetFreeSpark()];
spark->on = 1;
spark->sR = -1;
spark->sB = 16;
spark->sG = (GetRandomControl() & 0x1F) + 48;
spark->dR = (GetRandomControl() & 0x3F) - 64;
spark->dB = 0;
spark->dG = (GetRandomControl() & 0x3F) + -128;
spark->fadeToBlack = 4;
spark->colFadeSpeed = (GetRandomControl() & 3) + 4;
2021-10-27 19:00:30 +03:00
spark->transType = TransTypeEnum::COLADD;
2020-12-21 13:16:29 -03:00
spark->life = spark->sLife = (GetRandomControl() & 3) + 24;
spark->x = item->ItemFlags[1] + (GetRandomControl() & 0x3F) + item->Position.xPos - 544;
spark->y = item->Position.yPos;
spark->z = item->ItemFlags[0] + (GetRandomControl() & 0x3F) + item->Position.zPos - 544;
2020-12-21 13:16:29 -03:00
spark->xVel = (GetRandomControl() & 0x1FF) - 256;
spark->friction = 6;
spark->zVel = (GetRandomControl() & 0x1FF) - 256;
spark->rotAng = GetRandomControl() & 0xFFF;
spark->rotAdd = (GetRandomControl() & 0x3F) - 32;
spark->maxYvel = 0;
spark->yVel = -512 - (GetRandomControl() & 0x3FF);
spark->sSize = spark->size = (GetRandomControl() & 0xF) + 32;
spark->dSize = spark->size / 4;
if (GetRandomControl() & 3)
{
spark->flags = SP_ROTATE | SP_DEF | SP_SCALE | SP_EXPDEF;
spark->scalar = 3;
spark->gravity = (GetRandomControl() & 0x3F) + 32;
}
else
{
spark->flags = SP_ROTATE | SP_DEF | SP_SCALE;
spark->def = Objects[ID_DEFAULT_SPRITES].meshIndex + SPR_UNDERWATERDUST;
spark->scalar = 1;
spark->gravity = (GetRandomControl() & 0xF) + 64;
}
}
}