TombEngine/TR5Main/Objects/Generic/Doors/generic_doors.cpp

442 lines
11 KiB
C++
Raw Normal View History

2021-09-05 05:52:50 +02:00
#include "framework.h"
2021-12-24 03:32:19 +03:00
#include "Objects/Generic/Doors/generic_doors.h"
2021-12-22 16:23:57 +03:00
#include "Specific/level.h"
#include "Game/control/control.h"
#include "Game/control/box.h"
#include "Game/items.h"
#include "Game/control/lot.h"
#include "Game/gui.h"
#include "Specific/input.h"
#include "Game/pickup/pickup.h"
#include "Sound/sound.h"
#include "Game/animation.h"
#include "Game/collision/sphere.h"
2021-12-24 11:08:16 +03:00
#include "Objects/Generic/Switches/cog_switch.h"
2021-12-22 16:23:57 +03:00
#include "Objects/objectslist.h"
#include "Game/Lara/lara_struct.h"
#include "Game/Lara/lara.h"
#include "Specific/trmath.h"
#include "Game/misc.h"
#include "Game/itemdata/door_data.h"
#include "Game/collision/collide_room.h"
#include "Game/collision/collide_item.h"
#include "Game/itemdata/itemdata.h"
2021-09-05 05:52:50 +02:00
namespace TEN::Entities::Doors
{
PHD_VECTOR CrowbarDoorPos(-412, 0, 256);
OBJECT_COLLISION_BOUNDS CrowbarDoorBounds =
{
-512, 512,
-1024, 0,
0, 512,
-ANGLE(80), ANGLE(80),
-ANGLE(80), ANGLE(80),
-ANGLE(80), ANGLE(80)
};
void InitialiseDoor(short itemNumber)
{
ITEM_INFO* item = &g_Level.Items[itemNumber];
if (item->ObjectNumber == ID_SEQUENCE_DOOR1)
item->Flags &= 0xBFFFu;
2021-09-05 05:52:50 +02:00
if (item->ObjectNumber == ID_LIFT_DOORS1 || item->ObjectNumber == ID_LIFT_DOORS2)
item->ItemFlags[0] = 4096;
2021-09-05 05:52:50 +02:00
item->Data = ITEM_DATA(DOOR_DATA());
DOOR_DATA* door = item->Data;
2021-09-05 05:52:50 +02:00
door->opened = false;
2021-09-11 22:43:29 +03:00
door->dptr1 = nullptr;
door->dptr2 = nullptr;
door->dptr3 = nullptr;
door->dptr4 = nullptr;
2021-09-05 05:52:50 +02:00
short boxNumber, twoRoom;
2021-09-05 05:52:50 +02:00
int xOffset = 0;
int zOffset = 0;
2021-09-05 05:52:50 +02:00
if (item->Position.yRot == 0)
zOffset = -WALL_SIZE;
else if (item->Position.yRot == ANGLE(180))
zOffset = WALL_SIZE;
else if (item->Position.yRot == ANGLE(90))
xOffset = -WALL_SIZE;
2021-09-05 05:52:50 +02:00
else
xOffset = WALL_SIZE;
2021-09-05 05:52:50 +02:00
auto r = &g_Level.Rooms[item->RoomNumber];
door->d1.floor = GetSector(r, item->Position.xPos - r->x + xOffset, item->Position.zPos - r->z + zOffset);
2021-09-05 05:52:50 +02:00
auto roomNumber = door->d1.floor->WallPortal;
2021-09-05 05:52:50 +02:00
if (roomNumber == NO_ROOM)
2021-09-13 02:46:48 +03:00
boxNumber = door->d1.floor->Box;
2021-09-05 05:52:50 +02:00
else
{
auto b = &g_Level.Rooms[roomNumber];
boxNumber = GetSector(b, item->Position.xPos - b->x + xOffset, item->Position.zPos - b->z + zOffset)->Box;
2021-09-05 05:52:50 +02:00
}
2021-09-11 22:43:29 +03:00
door->d1.block = (boxNumber != NO_BOX && g_Level.Boxes[boxNumber].flags & BLOCKABLE) ? boxNumber : NO_BOX;
door->d1.data = *door->d1.floor;
2021-09-05 05:52:50 +02:00
if (r->flippedRoom != -1)
{
r = &g_Level.Rooms[r->flippedRoom];
door->d1flip.floor = GetSector(r, item->Position.xPos - r->x + xOffset, item->Position.zPos - r->z + zOffset);
2021-09-17 01:46:06 +03:00
2021-09-11 22:43:29 +03:00
roomNumber = door->d1flip.floor->WallPortal;
2021-09-05 05:52:50 +02:00
if (roomNumber == NO_ROOM)
2021-09-13 02:46:48 +03:00
boxNumber = door->d1flip.floor->Box;
2021-09-05 05:52:50 +02:00
else
{
auto b = &g_Level.Rooms[roomNumber];
boxNumber = GetSector(b, item->Position.xPos - b->x + xOffset, item->Position.zPos - b->z + zOffset)->Box;
2021-09-05 05:52:50 +02:00
}
2021-09-11 22:43:29 +03:00
door->d1flip.block = (boxNumber != NO_BOX && g_Level.Boxes[boxNumber].flags & BLOCKABLE) ? boxNumber : NO_BOX;
door->d1flip.data = *door->d1flip.floor;
2021-09-05 05:52:50 +02:00
}
else
door->d1flip.floor = NULL;
2021-09-11 22:43:29 +03:00
twoRoom = door->d1.floor->WallPortal;
2021-09-05 05:52:50 +02:00
ShutThatDoor(&door->d1, door);
ShutThatDoor(&door->d1flip, door);
if (twoRoom == NO_ROOM)
{
door->d2.floor = NULL;
door->d2flip.floor = NULL;
}
else
{
r = &g_Level.Rooms[twoRoom];
door->d2.floor = GetSector(r, item->Position.xPos - r->x, item->Position.zPos - r->z);
2021-09-05 05:52:50 +02:00
2021-09-11 22:43:29 +03:00
roomNumber = door->d2.floor->WallPortal;
2021-09-05 05:52:50 +02:00
if (roomNumber == NO_ROOM)
2021-09-13 02:46:48 +03:00
boxNumber = door->d2.floor->Box;
2021-09-05 05:52:50 +02:00
else
{
auto b = &g_Level.Rooms[roomNumber];
boxNumber = GetSector(b, item->Position.xPos - b->x, item->Position.zPos - b->z)->Box;
2021-09-05 05:52:50 +02:00
}
2021-09-11 22:43:29 +03:00
door->d2.block = (boxNumber != NO_BOX && g_Level.Boxes[boxNumber].flags & BLOCKABLE) ? boxNumber : NO_BOX;
door->d2.data = *door->d2.floor;
2021-09-05 05:52:50 +02:00
if (r->flippedRoom != -1)
{
r = &g_Level.Rooms[r->flippedRoom];
door->d2flip.floor = GetSector(r, item->Position.xPos - r->x, item->Position.zPos - r->z);
2021-09-05 05:52:50 +02:00
2021-09-11 22:43:29 +03:00
roomNumber = door->d2flip.floor->WallPortal;
2021-09-05 05:52:50 +02:00
if (roomNumber == NO_ROOM)
2021-09-13 02:46:48 +03:00
boxNumber = door->d2flip.floor->Box;
2021-09-05 05:52:50 +02:00
else
{
auto b = &g_Level.Rooms[roomNumber];
boxNumber = GetSector(b, item->Position.xPos - b->x, item->Position.zPos - b->z)->Box;
2021-09-05 05:52:50 +02:00
}
2021-09-11 22:43:29 +03:00
door->d2flip.block = (boxNumber != NO_BOX && g_Level.Boxes[boxNumber].flags & BLOCKABLE) ? boxNumber : NO_BOX;
door->d2flip.data = *door->d2flip.floor;
2021-09-05 05:52:50 +02:00
}
else
door->d2flip.floor = NULL;
ShutThatDoor(&door->d2, door);
ShutThatDoor(&door->d2flip, door);
roomNumber = item->RoomNumber;
2021-09-05 05:52:50 +02:00
ItemNewRoom(itemNumber, twoRoom);
item->RoomNumber = roomNumber;
item->InDrawRoom = true;
2021-09-05 05:52:50 +02:00
}
}
void DoorCollision(short itemNum, ITEM_INFO* l, COLL_INFO* coll)
{
ITEM_INFO* item = &g_Level.Items[itemNum];
if (item->TriggerFlags == 2
&& item->Status == ITEM_NOT_ACTIVE && !item->Airborne // CHECK
2021-11-16 15:51:50 +03:00
&& ((TrInput & IN_ACTION || g_Gui.GetInventoryItemChosen() == ID_CROWBAR_ITEM)
&& l->ActiveState == LS_IDLE
&& l->AnimNumber == LA_STAND_IDLE
&& !l->HitStatus
&& Lara.Control.HandStatus == HandStatus::Free
|| Lara.Control.IsMoving && Lara.interactedItem == itemNum))
2021-09-05 05:52:50 +02:00
{
item->Position.yRot ^= ANGLE(180);
2021-09-05 05:52:50 +02:00
if (TestLaraPosition(&CrowbarDoorBounds, item, l))
{
if (!Lara.Control.IsMoving)
2021-09-05 05:52:50 +02:00
{
2021-11-16 15:51:50 +03:00
if (g_Gui.GetInventoryItemChosen() == NO_ITEM)
2021-09-05 05:52:50 +02:00
{
2021-11-16 15:51:50 +03:00
if (g_Gui.IsObjectInInventory(ID_CROWBAR_ITEM))
2021-09-05 05:52:50 +02:00
{
2021-11-16 15:51:50 +03:00
g_Gui.SetEnterInventory(ID_CROWBAR_ITEM);
item->Position.yRot ^= ANGLE(180);
2021-09-05 05:52:50 +02:00
}
else
{
if (OldPickupPos.x != l->Position.xPos || OldPickupPos.y != l->Position.yPos || OldPickupPos.z != l->Position.zPos)
2021-09-05 05:52:50 +02:00
{
OldPickupPos.x = l->Position.xPos;
OldPickupPos.y = l->Position.yPos;
OldPickupPos.z = l->Position.zPos;
2021-09-05 05:52:50 +02:00
SayNo();
}
item->Position.yRot ^= ANGLE(180);
2021-09-05 05:52:50 +02:00
}
return;
}
2021-10-12 00:26:46 -05:00
2021-11-16 15:51:50 +03:00
if (g_Gui.GetInventoryItemChosen() != ID_CROWBAR_ITEM)
2021-09-05 05:52:50 +02:00
{
item->Position.yRot ^= ANGLE(180);
2021-09-05 05:52:50 +02:00
return;
}
}
2021-10-12 00:26:46 -05:00
2021-11-16 15:51:50 +03:00
g_Gui.SetInventoryItemChosen(NO_ITEM);
2021-10-12 00:26:46 -05:00
2021-09-05 05:52:50 +02:00
if (MoveLaraPosition(&CrowbarDoorPos, item, l))
{
SetAnimation(l, LA_DOOR_OPEN_CROWBAR);
item->Position.yRot ^= ANGLE(180);
2021-09-05 05:52:50 +02:00
AddActiveItem(itemNum);
item->Flags |= IFLAG_ACTIVATION_MASK;
item->Status = ITEM_ACTIVE;
item->TargetState = LS_RUN_FORWARD;
Lara.Control.IsMoving = 0;
Lara.Control.HandStatus = HandStatus::Busy;
2021-09-05 05:52:50 +02:00
return;
}
Lara.interactedItem = itemNum;
2021-09-05 05:52:50 +02:00
}
else if (Lara.Control.IsMoving && Lara.interactedItem == itemNum)
2021-09-05 05:52:50 +02:00
{
Lara.Control.IsMoving = 0;
Lara.Control.HandStatus = HandStatus::Free;
2021-09-05 05:52:50 +02:00
}
item->Position.yRot ^= ANGLE(180);
2021-09-05 05:52:50 +02:00
}
2021-09-11 22:40:35 +03:00
if (TestBoundsCollide(item, l, coll->Setup.Radius))
2021-09-05 05:52:50 +02:00
{
if (TestCollision(item, l))
{
2021-09-11 22:40:35 +03:00
if (coll->Setup.EnableObjectPush)
2021-09-05 05:52:50 +02:00
{
if (!(item->ObjectNumber >= ID_LIFT_DOORS1 && item->ObjectNumber <= ID_LIFT_DOORS2) || item->ItemFlags[0])
2021-09-05 05:52:50 +02:00
{
ItemPushItem(item, l, coll, FALSE, TRUE);
}
}
}
}
}
void DoorControl(short itemNumber)
{
ITEM_INFO* item = &g_Level.Items[itemNumber];
DOOR_DATA* door = (DOOR_DATA*)item->Data;
2021-09-05 05:52:50 +02:00
2021-09-06 05:41:03 +02:00
// Doors with OCB = 1 are raisable with cog switchs
if (item->TriggerFlags == 1)
2021-09-05 05:52:50 +02:00
{
if (item->ItemFlags[0])
2021-09-05 05:52:50 +02:00
{
BOUNDING_BOX* bounds = GetBoundsAccurate(item);
2021-09-06 05:41:03 +02:00
item->ItemFlags[0]--;
item->Position.yPos -= TEN::Entities::Switches::COG_DOOR_SPEED;
2021-09-06 05:41:03 +02:00
int y = bounds->Y1 + item->ItemFlags[2] - STEP_SIZE;
if (item->Position.yPos < y)
2021-09-05 05:52:50 +02:00
{
item->Position.yPos = y;
item->ItemFlags[0] = 0;
2021-09-05 05:52:50 +02:00
}
if (!door->opened)
{
OpenThatDoor(&door->d1, door);
OpenThatDoor(&door->d2, door);
OpenThatDoor(&door->d1flip, door);
OpenThatDoor(&door->d2flip, door);
door->opened = true;
}
}
else
{
if (item->Position.yPos < item->StartPosition.yPos)
item->Position.yPos += 4;
if (item->Position.yPos >= item->StartPosition.yPos)
2021-09-05 05:52:50 +02:00
{
item->Position.yPos = item->StartPosition.yPos;
2021-09-05 05:52:50 +02:00
if (door->opened)
{
ShutThatDoor(&door->d1, door);
ShutThatDoor(&door->d2, door);
ShutThatDoor(&door->d1flip, door);
ShutThatDoor(&door->d2flip, door);
door->opened = false;
}
}
}
2021-09-06 05:41:03 +02:00
return;
2021-09-05 05:52:50 +02:00
}
if (item->ObjectNumber < ID_LIFT_DOORS1 || item->ObjectNumber > ID_LIFT_DOORS2)
2021-09-05 05:52:50 +02:00
{
if (TriggerActive(item))
{
if (item->ActiveState == 0)
2021-09-05 05:52:50 +02:00
{
item->TargetState = 1;
2021-09-05 05:52:50 +02:00
}
else if (!door->opened)
2021-09-05 05:52:50 +02:00
{
OpenThatDoor(&door->d1, door);
OpenThatDoor(&door->d2, door);
OpenThatDoor(&door->d1flip, door);
OpenThatDoor(&door->d2flip, door);
door->opened = true;
}
}
else
{
item->Status = ITEM_ACTIVE;
2021-09-05 05:52:50 +02:00
if (item->ActiveState == 1)
2021-09-05 05:52:50 +02:00
{
item->TargetState = 0;
2021-09-05 05:52:50 +02:00
}
else if (door->opened)
2021-09-05 05:52:50 +02:00
{
ShutThatDoor(&door->d1, door);
ShutThatDoor(&door->d2, door);
ShutThatDoor(&door->d1flip, door);
ShutThatDoor(&door->d2flip, door);
door->opened = false;
}
}
}
else
2021-09-05 05:52:50 +02:00
{
// TR5 lift doors
/*if (!TriggerActive(item))
2021-09-05 05:52:50 +02:00
{
if (item->itemFlags[0] >= SECTOR(4))
2021-09-05 05:52:50 +02:00
{
if (door->opened)
{
ShutThatDoor(&door->d1, door);
ShutThatDoor(&door->d2, door);
ShutThatDoor(&door->d1flip, door);
ShutThatDoor(&door->d2flip, door);
door->opened = false;
}
}
else
{
if (!item->itemFlags[0])
SoundEffect(SFX_TR5_LIFT_DOORS, &item->pos, 0);
item->itemFlags[0] += STEP_SIZE;
2021-09-05 05:52:50 +02:00
}
}
else
{
if (item->itemFlags[0] > 0)
{
if (item->itemFlags[0] == SECTOR(4))
SoundEffect(SFX_TR5_LIFT_DOORS, &item->pos, 0);
item->itemFlags[0] -= STEP_SIZE;
}
if (!door->opened)
{
DontUnlockBox = true;
OpenThatDoor(&door->d1, door);
OpenThatDoor(&door->d2, door);
OpenThatDoor(&door->d1flip, door);
OpenThatDoor(&door->d2flip, door);
DontUnlockBox = false;
door->opened = true;
}
}*/
2021-09-05 05:52:50 +02:00
}
AnimateItem(item);
2021-09-05 05:52:50 +02:00
}
void OpenThatDoor(DOORPOS_DATA* doorPos, DOOR_DATA* dd)
{
FLOOR_INFO* floor = doorPos->floor;
if (floor != NULL)
{
*doorPos->floor = doorPos->data;
2021-09-05 05:52:50 +02:00
short boxIndex = doorPos->block;
if (boxIndex != NO_BOX)
{
g_Level.Boxes[boxIndex].flags &= ~BLOCKED;
2021-09-05 05:52:50 +02:00
for (int i = 0; i < ActiveCreatures.size(); i++)
2021-09-05 05:52:50 +02:00
{
ActiveCreatures[i]->LOT.targetBox = NO_BOX;
2021-09-05 05:52:50 +02:00
}
}
}
}
void ShutThatDoor(DOORPOS_DATA* doorPos, DOOR_DATA* dd)
{
FLOOR_INFO* floor = doorPos->floor;
if (floor)
{
2021-09-13 02:46:48 +03:00
floor->Box = NO_BOX;
floor->TriggerIndex = 0;
2021-09-11 23:50:54 +03:00
// FIXME: HACK!!!!!!!
2021-09-14 11:09:29 +03:00
// We should find a better way of dealing with doors using new floordata.
2021-09-14 10:59:09 +03:00
floor->WallPortal = -1;
2021-09-15 10:12:42 +03:00
floor->FloorCollision.Portals[0] = NO_ROOM;
floor->FloorCollision.Portals[1] = NO_ROOM;
2021-09-11 23:50:54 +03:00
floor->CeilingCollision.Portals[0] = NO_ROOM;
floor->CeilingCollision.Portals[1] = NO_ROOM;
2021-09-15 10:12:42 +03:00
floor->FloorCollision.Planes[0] = WALL_PLANE;
floor->FloorCollision.Planes[1] = WALL_PLANE;
floor->CeilingCollision.Planes[0] = WALL_PLANE;
floor->CeilingCollision.Planes[1] = WALL_PLANE;
2021-09-05 05:52:50 +02:00
short boxIndex = doorPos->block;
if (boxIndex != NO_BOX)
{
g_Level.Boxes[boxIndex].flags |= BLOCKED;
for (int i = 0; i < ActiveCreatures.size(); i++)
2021-09-05 05:52:50 +02:00
{
ActiveCreatures[i]->LOT.targetBox = NO_BOX;
2021-09-05 05:52:50 +02:00
}
}
}
}
}