TombEngine/TR5Main/Objects/TR4/Object/tr4_element_puzzle.cpp
KrysB4k 735e73f1ea Removed duplicate function GetFloorAndTestTriggers, fix pushblock issues
GetFloorAndItemTriggers() was removed in favor of TestTriggersAtXYZ() from switch.cpp, which does the same. All calls to GetFloorAndItemTriggers were replaced with TestTriggersAtXYZ.

Pushables pulling bug was fixed in TestBlockPull(). PushableBlockControl() now calls ItemNewRoom() to signal change of room membership of pushable.
2020-12-19 23:02:55 +01:00

303 lines
No EOL
8.1 KiB
C++

#include "framework.h"
#include "tr4_element_puzzle.h"
#include "level.h"
#include "control.h"
#include <sound.h>
#include <draw.h>
#include <lara.h>
#include <sphere.h>
#include <effect2.h>
#include <tomb4fx.h>
#include <switch.h>
#include <input.h>
OBJECT_COLLISION_BOUNDS ElementPuzzleBounds = {
0x0000, 0x0000, 0xFFC0, 0x0000, 0x0000, 0x0000,
0xF8E4, 0x071C, 0xEAAC, 0x1554, 0xF8E4, 0x071C
};
void ElementPuzzleControl(short itemNumber)
{
ITEM_INFO* item = &g_Level.Items[itemNumber];
if (!TriggerActive(item))
return;
if (item->triggerFlags == 1)
{
SoundEffect(SFX_LOOP_FOR_SMALL_FIRES, &item->pos, 0);
byte r = (GetRandomControl() & 0x3F) + 192;
byte g = (GetRandomControl() & 0x1F) + 96;
byte b = 0;
int on = 0;
if (item->itemFlags[3])
{
item->itemFlags[3]--;
on = 255 - GetRandomControl() % (4 * (91 - item->itemFlags[3]));
if (on < 1)
on = 1;
if (on <= 255)
{
r = (r * on) / 256;
g = (g * on) / 256;
}
}
else
{
on = 0;
}
AddFire(item->pos.xPos, item->pos.yPos - 620, item->pos.zPos, 1, item->roomNumber, on);
TriggerDynamicLight(item->pos.xPos, item->pos.yPos - 768, item->pos.zPos, 12, r, g, b);
return;
}
if (item->triggerFlags != 3)
{
return;
}
if (item->itemFlags[1] > 90)
{
SoundEffect(SFX_TR4_JOBY_WIND, &item->pos, 0);
}
if (item->itemFlags[1] < 60)
{
item->itemFlags[1]++;
return;
}
item->itemFlags[0]++;
if (item->itemFlags[0] == 90)
{
short itemNos[256];
int sw = GetSwitchTrigger(item, itemNos, 0);
if (sw > 0)
{
for (int i = 0; i < sw; i++)
{
AddActiveItem(itemNos[i]);
g_Level.Items[itemNos[i]].status = ITEM_ACTIVE;
g_Level.Items[itemNos[i]].timer |= 0x3E00; // *(_BYTE*)(Items + 5622 * v11[1] + 41) |= 0x3Eu;
}
}
KillItem(itemNumber);
return;
}
short currentItemNumber = g_Level.Rooms[item->roomNumber].itemNumber;
if (currentItemNumber == NO_ITEM)
{
return;
}
while (currentItemNumber != NO_ITEM)
{
ITEM_INFO* currentItem = &g_Level.Items[currentItemNumber];
if (currentItem->objectNumber != ID_FLAME_EMITTER2)
{
if (currentItem->objectNumber == ID_ELEMENT_PUZZLE && currentItem->triggerFlags == 1 && !currentItem->itemFlags[3])
{
currentItem->itemFlags[3] = 90;
}
currentItemNumber = currentItem->nextItem;
continue;
}
if (item->itemFlags[0] != 89)
{
currentItem->itemFlags[3] = 255 - GetRandomControl() % (4 * item->itemFlags[0]);
if (currentItem->itemFlags[3] >= 2)
{
currentItemNumber = currentItem->nextItem;
continue;
}
currentItem->itemFlags[3] = 2;
}
RemoveActiveItem(currentItemNumber);
currentItem->status = ITEM_NOT_ACTIVE;
currentItemNumber = currentItem->nextItem;
};
}
void ElementPuzzleDoCollision(short itemNumber, ITEM_INFO* l, COLL_INFO* c)
{
ITEM_INFO* item = &g_Level.Items[itemNumber];
if (TestBoundsCollide(item, l, c->radius))
{
if (TestCollision(item, l))
{
if (c->enableBaddiePush)
{
ItemPushLara(item, l, c, 0, 0);
}
}
}
}
void ElementPuzzleCollision(short itemNumber, ITEM_INFO* l, COLL_INFO* c)
{
ITEM_INFO* item = &g_Level.Items[itemNumber];
int flags = 0;
if (item->triggerFlags)
{
if (item->triggerFlags == 1)
{
flags = 26;
}
else
{
if (item->triggerFlags != 2)
{
return;
}
flags = 27;
}
}
else
{
flags = 25;
}
if ((l->animNumber == LA_WATERSKIN_POUR_LOW
|| l->animNumber == LA_WATERSKIN_POUR_HIGH)
&& !item->itemFlags[0])
{
BOUNDING_BOX* box = GetBoundsAccurate(item);
ElementPuzzleBounds.boundingBox.X1 = box->X1;
ElementPuzzleBounds.boundingBox.X2 = box->X2;
ElementPuzzleBounds.boundingBox.Z1 = box->Z1 - 200;
ElementPuzzleBounds.boundingBox.Z2 = box->Z2 + 200;
short oldRot = item->pos.yRot;
item->pos.yRot = l->pos.yRot;
if (TestLaraPosition(&ElementPuzzleBounds, item, l))
{
if (l->animNumber == LA_WATERSKIN_POUR_LOW && LaraItem->itemFlags[2] == flags)
{
l->animNumber = LA_WATERSKIN_POUR_HIGH;
l->frameNumber = g_Level.Anims[l->animNumber].frameBase;
}
if (l->frameNumber == g_Level.Anims[LA_WATERSKIN_POUR_HIGH].frameBase + 74
&& LaraItem->itemFlags[2] == flags)
{
if (!item->triggerFlags)
{
item->meshBits = 48;
TestTriggersAtXYZ(item->pos.xPos, item->pos.yPos, item->pos.zPos, item->roomNumber, 1, item->flags & 0x3E00);
item->itemFlags[0] = 1;
item->pos.yRot = oldRot;
return;
}
if (item->triggerFlags == 1)
{
item->meshBits = 3;
Lara.Pickups[1]--;
item->itemFlags[0] = 1;
item->pos.yRot = oldRot;
return;
}
item->meshBits = 12;
TestTriggersAtXYZ(item->pos.xPos, item->pos.yPos, item->pos.zPos, item->roomNumber, 1, item->flags & 0x3E00);
Lara.Pickups[0]--;
item->itemFlags[0] = 1;
}
}
item->pos.yRot = oldRot;
return;
}
if (Lara.gunType != WEAPON_TORCH
|| Lara.gunStatus != LG_READY
|| Lara.leftArm.lock
|| !(TrInput & IN_ACTION)
/*|| (_WORD)v4 != 1*/
|| item->itemFlags[0] != 1
|| l->currentAnimState != LS_STOP
|| l->animNumber != LA_STAND_IDLE
|| !Lara.litTorch
|| l->gravityStatus)
{
if (l->animNumber != LA_TORCH_LIGHT_3
|| g_Level.Anims[LA_TORCH_LIGHT_3].frameBase + 16
|| item->itemFlags[0] != 2)
{
ElementPuzzleDoCollision(itemNumber, l, c);
}
else
{
TestTriggersAtXYZ(item->pos.xPos, item->pos.yPos, item->pos.zPos, item->roomNumber, 1, item->flags & 0x3E00);
AddActiveItem(itemNumber);
item->status = ITEM_ACTIVE;
item->itemFlags[0] = 3;
item->flags |= 0x3E00;
}
}
else
{
BOUNDING_BOX* box = GetBoundsAccurate(item);
ElementPuzzleBounds.boundingBox.X1 = box->X1;
ElementPuzzleBounds.boundingBox.X2 = box->X2;
ElementPuzzleBounds.boundingBox.Z1 = box->Z1 - 200;
ElementPuzzleBounds.boundingBox.Z2 = box->Z2 + 200;
short oldRot = item->pos.yRot;
item->pos.yRot = l->pos.yRot;
if (TestLaraPosition(&ElementPuzzleBounds, item, l))
{
l->animNumber = (abs(item->pos.yPos - l->pos.yPos) >> 8) + LA_TORCH_LIGHT_3;
l->frameNumber = g_Level.Anims[item->animNumber].frameBase;
l->currentAnimState = LS_MISC_CONTROL;
Lara.flareControlLeft = false;
Lara.leftArm.lock = 3;
item->itemFlags[0] = 2;
}
item->pos.yRot = oldRot;
}
}
void InitialiseElementPuzzle(short itemNumber)
{
ITEM_INFO* item = &g_Level.Items[itemNumber];
if (item->triggerFlags)
{
if (item->triggerFlags == 1)
{
item->meshBits = 65;
}
else if (item->triggerFlags == 2)
{
item->meshBits = 68;
}
else
{
item->meshBits = 0;
}
}
else
{
item->meshBits = 80;
}
}