TombEngine/TR5Main/Objects/TR5/Object/tr5_pushableblock.cpp

598 lines
15 KiB
C++
Raw Normal View History

#include "framework.h"
#include "tr5_pushableblock.h"
#include "lara.h"
#include "draw.h"
#include "items.h"
#include "collide.h"
#include "effect.h"
#include "box.h"
#include "level.h"
#include "input.h"
#include "sound.h"
2020-07-25 18:02:35 +02:00
OBJECT_COLLISION_BOUNDS MovingBlockBounds = {
-300, 300, 0, 0, -692, -512,
-ANGLE(10.0f), ANGLE(10.0f),
-ANGLE(30.0f), ANGLE(30.0f),
-ANGLE(10.0f), ANGLE(10.0f)
};
2020-07-25 18:02:35 +02:00
OBJECT_COLLISION_BOUNDS PushableBlockBounds = {
0x0000, 0x0000, 0xFF00, 0x0000,
0x0000, 0x0000, 0xF8E4, 0x071C,
0xEAAC, 0x1554, 0xF8E4, 0x071C
};
PHD_VECTOR PushableBlockPos = { 0, 0, 0 };
bool DoPushPull = 0;
void ClearMovableBlockSplitters(int x, int y, int z, short roomNumber)
{
FLOOR_INFO* floor = GetFloor(x, y, z, &roomNumber);
g_Level.Boxes[floor->box].flags &= (~BLOCKED);
short height = g_Level.Boxes[floor->box].height;
short baseRoomNumber = roomNumber;
floor = GetFloor(x + SECTOR(1), y, z, &roomNumber);
if (floor->box != NO_BOX)
{
if (g_Level.Boxes[floor->box].height == height && (g_Level.Boxes[floor->box].flags & BLOCKABLE) && (g_Level.Boxes[floor->box].flags & BLOCKED))
ClearMovableBlockSplitters(x + SECTOR(1), y, z, roomNumber);
}
roomNumber = baseRoomNumber;
floor = GetFloor(x - SECTOR(1), y, z, &roomNumber);
if (floor->box != NO_BOX)
{
if (g_Level.Boxes[floor->box].height == height && (g_Level.Boxes[floor->box].flags & BLOCKABLE) && (g_Level.Boxes[floor->box].flags & BLOCKED))
ClearMovableBlockSplitters(x - SECTOR(1), y, z, roomNumber);
}
roomNumber = baseRoomNumber;
floor = GetFloor(x, y, z + SECTOR(1), &roomNumber);
if (floor->box != NO_BOX)
{
if (g_Level.Boxes[floor->box].height == height && (g_Level.Boxes[floor->box].flags & BLOCKABLE) && (g_Level.Boxes[floor->box].flags & BLOCKED))
ClearMovableBlockSplitters(x, y, z + SECTOR(1), roomNumber);
}
roomNumber = baseRoomNumber;
floor = GetFloor(x, y, z - SECTOR(1), &roomNumber);
if (floor->box != NO_BOX)
{
if (g_Level.Boxes[floor->box].height == height && (g_Level.Boxes[floor->box].flags & BLOCKABLE) && (g_Level.Boxes[floor->box].flags & BLOCKED))
ClearMovableBlockSplitters(x, y, z - SECTOR(1), roomNumber);
}
}
void InitialisePushableBlock(short itemNum)
{
ITEM_INFO* item = &g_Level.Items[itemNum];
ClearMovableBlockSplitters(item->pos.xPos, item->pos.yPos, item->pos.zPos, item->roomNumber);
2020-09-07 20:01:28 +02:00
if (item->triggerFlags > 64 && item->status != ITEM_INVISIBLE)
AlterFloorHeight(item, -(item->triggerFlags - 64) * CLICK(1));
}
void PushableBlockControl(short itemNumber)
{
ITEM_INFO* item = &g_Level.Items[itemNumber];
PHD_VECTOR pos;
pos.x = 0;
pos.y = 0;
pos.z = 0;
short quadrant = GetQuadrant(LaraItem->pos.yRot);
int x, z;
FLOOR_INFO* floor;
ROOM_INFO* r;
int height;
short roomNumber;
switch (LaraItem->animNumber)
{
case LA_PUSHABLE_PUSH:
if ((LaraItem->frameNumber < g_Level.Anims[LaraItem->animNumber].frameBase + 30
2020-09-07 20:01:28 +02:00
|| LaraItem->frameNumber > g_Level.Anims[LaraItem->animNumber].frameBase + 67)
&& (LaraItem->frameNumber < g_Level.Anims[LaraItem->animNumber].frameBase + 78
|| LaraItem->frameNumber > g_Level.Anims[LaraItem->animNumber].frameBase + 125)
&& (LaraItem->frameNumber < g_Level.Anims[LaraItem->animNumber].frameBase + 140
|| LaraItem->frameNumber > g_Level.Anims[LaraItem->animNumber].frameBase + 160))
{
if (DoPushPull)
{
SoundEffect(SFX_PUSH_BLOCK_END, &item->pos, 2);
DoPushPull = 0;
}
}
else
{
SoundEffect(SFX_PUSHABLE_SOUND, &item->pos, 2);
DoPushPull = 1;
}
GetLaraJointPosition(&pos, LM_LHAND);
switch (quadrant)
{
case NORTH:
z = pos.z + item->itemFlags[2] - LaraItem->itemFlags[2];
if (abs(item->pos.zPos - z) < SECTOR(1) / 2 && item->pos.zPos < z)
item->pos.zPos = z;
break;
case EAST:
x = pos.x + item->itemFlags[0] - LaraItem->itemFlags[0];
if (abs(item->pos.xPos - x) < SECTOR(1) / 2 && item->pos.xPos < x)
item->pos.xPos = x;
break;
case SOUTH:
z = pos.z + item->itemFlags[2] - LaraItem->itemFlags[2];
if (abs(item->pos.zPos - z) < SECTOR(1) / 2 && item->pos.zPos > z)
item->pos.zPos = z;
break;
case WEST:
x = pos.x + item->itemFlags[0] - LaraItem->itemFlags[0];
if (abs(item->pos.xPos - x) < SECTOR(1) / 2 && item->pos.xPos > x)
item->pos.xPos = x;
break;
default:
break;
}
if (LaraItem->frameNumber == g_Level.Anims[LaraItem->animNumber].frameEnd - 1)
{
if (TrInput & IN_ACTION)
{
if (!TestBlockPush(item, CLICK(4), quadrant))
LaraItem->goalAnimState = LS_STOP;
}
else
{
LaraItem->goalAnimState = LS_STOP;
}
}
break;
case LA_PUSHABLE_PULL:
if ((LaraItem->frameNumber < g_Level.Anims[LaraItem->animNumber].frameBase + 40
|| LaraItem->frameNumber > g_Level.Anims[LaraItem->animNumber].frameBase + 122)
&& (LaraItem->frameNumber < g_Level.Anims[LaraItem->animNumber].frameBase + 130
|| LaraItem->frameNumber > g_Level.Anims[LaraItem->animNumber].frameBase + 170))
{
if (DoPushPull)
{
SoundEffect(SFX_PUSH_BLOCK_END, &item->pos, 2);
DoPushPull = false;
}
}
else
{
SoundEffect(SFX_PUSHABLE_SOUND, &item->pos, 2);
DoPushPull = true;
}
GetLaraJointPosition(&pos, LM_LHAND);
2020-09-07 20:01:28 +02:00
switch (quadrant)
{
2020-09-07 20:01:28 +02:00
case NORTH:
z = pos.z + item->itemFlags[2] - LaraItem->itemFlags[2];
if (abs(item->pos.zPos - z) < SECTOR(1) / 2 && item->pos.zPos > z)
item->pos.zPos = z;
break;
2020-09-07 20:01:28 +02:00
case EAST:
x = pos.x + item->itemFlags[0] - LaraItem->itemFlags[0];
if (abs(item->pos.xPos - x) < SECTOR(1) / 2 && item->pos.xPos > x)
item->pos.xPos = x;
break;
2020-09-07 20:01:28 +02:00
case SOUTH:
z = pos.z + item->itemFlags[2] - LaraItem->itemFlags[2];
if (abs(item->pos.zPos - z) < SECTOR(1) / 2 && item->pos.zPos < z)
item->pos.zPos = z;
break;
2020-09-07 20:01:28 +02:00
case WEST:
x = pos.x + item->itemFlags[0] - LaraItem->itemFlags[0];
if (abs(item->pos.xPos - x) < SECTOR(1) / 2 && item->pos.xPos < x)
item->pos.xPos = x;
break;
default:
break;
}
if (LaraItem->frameNumber == g_Level.Anims[LaraItem->animNumber].frameEnd - 1)
{
if (TrInput & IN_ACTION)
{
if (!TestBlockPull(item, CLICK(4), quadrant))
LaraItem->goalAnimState = LS_STOP;
}
else
{
LaraItem->goalAnimState = LS_STOP;
}
}
break;
case LA_PUSHABLE_PUSH_TO_STAND:
case LA_PUSHABLE_PULL_TO_STAND:
if (LaraItem->frameNumber == g_Level.Anims[LA_PUSHABLE_PUSH_TO_STAND].frameBase
|| LaraItem->frameNumber == g_Level.Anims[LA_PUSHABLE_PULL_TO_STAND].frameBase)
{
item->pos.xPos = item->pos.xPos & 0xFFFFFE00 | 0x200;
item->pos.zPos = item->pos.zPos & 0xFFFFFE00 | 0x200;
}
if (LaraItem->frameNumber == g_Level.Anims[LaraItem->animNumber].frameEnd)
{
2020-09-07 20:01:28 +02:00
if (item->triggerFlags > 64)
{
AlterFloorHeight(item, -(item->triggerFlags - 64) * CLICK(1));
2020-09-07 20:01:28 +02:00
AdjustStopperFlag(item, item->itemFlags[7] + 0x8000, 0);
}
roomNumber = item->roomNumber;
floor = GetFloor(item->pos.xPos, item->pos.yPos - CLICK(1), item->pos.zPos, &roomNumber);
GetFloorHeight(floor, item->pos.xPos, item->pos.yPos - CLICK(1), item->pos.zPos);
TestTriggers(TriggerIndex, 1, item->flags & 0x3E00);
RemoveActiveItem(itemNumber);
item->status = ITEM_NOT_ACTIVE;
}
2020-09-07 20:01:28 +02:00
/*if (item->status == ITEM_DEACTIVATED)
{
item->status = ITEM_NOT_ACTIVE;
RemoveActiveItem(itemNumber);
2020-09-07 20:01:28 +02:00
if (item->triggerFlags > 64)
{
AlterFloorHeight(item, -1024);
AdjustStopperFlag(item, item->itemFlags[7] + 0x8000, 0);
}
2020-09-07 20:01:28 +02:00
roomNumber = item->roomNumber;
floor = GetFloor(item->pos.xPos, item->pos.yPos, item->pos.zPos, &roomNumber);
GetFloorHeight(floor, item->pos.xPos, item->pos.yPos, item->pos.zPos);
TestTriggers(TriggerIndex, 1, 0);
}*/
2020-09-07 20:01:28 +02:00
break;
}
}
2020-09-07 20:01:28 +02:00
void PushableBlockCollision(short itemNum, ITEM_INFO* l, COLL_INFO* coll)
{
ITEM_INFO* item = &g_Level.Items[itemNum];
short roomNumber = item->roomNumber;
FLOOR_INFO* floor = GetFloor(item->pos.xPos, item->pos.yPos - CLICK(1), item->pos.zPos, &roomNumber);
2020-09-07 20:01:28 +02:00
if (item->triggerFlags < 64)
{
item->pos.yPos = GetFloorHeight(floor, item->pos.xPos, item->pos.yPos - CLICK(1), item->pos.zPos);
2020-09-07 20:01:28 +02:00
if (item->roomNumber != roomNumber)
ItemNewRoom(itemNum, roomNumber);
}
if ((!(TrInput & IN_ACTION)
|| l->currentAnimState != LS_STOP
|| l->animNumber != LA_STAND_IDLE
|| l->gravityStatus
|| Lara.gunStatus
|| item->status == ITEM_INVISIBLE
|| item->triggerFlags < 0)
&& (!Lara.isMoving || Lara.generalPtr != item))
{
2020-09-07 20:01:28 +02:00
if (item->triggerFlags < 64 &&
(l->currentAnimState != LS_PUSHABLE_GRAB
|| (l->frameNumber != g_Level.Anims[LA_PUSHABLE_GRAB].frameBase + 19)
2020-09-07 20:01:28 +02:00
|| Lara.cornerX != (int)item))
{
ObjectCollision(itemNum, l, coll);
return;
}
short quadrant = GetQuadrant(LaraItem->pos.yRot);
if (TrInput & IN_FORWARD)
{
if (!TestBlockPush(item, CLICK(4), quadrant))
return;
l->goalAnimState = LS_PUSHABLE_PUSH;
}
else if (TrInput & IN_BACK)
{
if (!TestBlockPull(item, CLICK(4), quadrant))
return;
l->goalAnimState = LS_PUSHABLE_PULL;
}
else
{
return;
}
item->status = ITEM_ACTIVE;
AddActiveItem(itemNum);
Lara.headYrot = 0;
Lara.headXrot = 0;
Lara.torsoYrot = 0;
Lara.torsoXrot = 0;
2020-09-07 20:01:28 +02:00
PHD_VECTOR pos;
pos.x = 0;
pos.y = 0;
pos.z = 0;
GetLaraJointPosition(&pos, LM_LHAND);
l->itemFlags[0] = pos.x;
l->itemFlags[2] = pos.z;
item->itemFlags[0] = item->pos.xPos;
item->itemFlags[2] = item->pos.zPos;
2020-09-07 20:01:28 +02:00
if (item->triggerFlags > 64
&& (TrInput & IN_ACTION)
&& ((l->animNumber == LA_PUSHABLE_PULL || l->animNumber == LA_PUSHABLE_PUSH)
&& l->frameNumber == g_Level.Anims[l->animNumber].frameBase))
{
AlterFloorHeight(item, 1024);
AdjustStopperFlag(item, item->itemFlags[7], 1);
}
}
else
{
short roomNumber = l->roomNumber;
FLOOR_INFO* floor = GetFloor(item->pos.xPos, item->pos.yPos - CLICK(1), item->pos.zPos, &roomNumber);
if (roomNumber == item->roomNumber)
{
2020-09-07 20:01:28 +02:00
//if (item->triggerFlags < 64)
//{
BOUNDING_BOX* bounds = GetBoundsAccurate(item);
PushableBlockBounds.boundingBox.X1 = (bounds->X1 / 2) - 100;
PushableBlockBounds.boundingBox.X2 = (bounds->X2 / 2) + 100;
PushableBlockBounds.boundingBox.Z1 = bounds->Z1 - 200;
PushableBlockBounds.boundingBox.Z2 = 0;
2020-09-07 20:01:28 +02:00
short rot = item->pos.yRot;
item->pos.yRot = (l->pos.yRot + ANGLE(45)) & 0xC000;
if (TestLaraPosition(&PushableBlockBounds, item, l))
{
2020-09-07 20:01:28 +02:00
if (((item->pos.yRot / 0x4000) + ((rot + 0x2000) / 0x4000)) & 1)
PushableBlockPos.z = bounds->X1 - 35;
else
PushableBlockPos.z = bounds->Z1 - 35;
if (MoveLaraPosition(&PushableBlockPos, item, l))
{
l->animNumber = LA_PUSHABLE_GRAB;
l->frameNumber = g_Level.Anims[l->animNumber].frameBase;
l->currentAnimState = LS_PUSHABLE_GRAB;
l->goalAnimState = LS_PUSHABLE_GRAB;
Lara.isMoving = false;
Lara.gunStatus = LG_HANDS_BUSY;
Lara.cornerX = (int)item;
item->pos.yRot = rot;
}
else
{
Lara.generalPtr = item;
item->pos.yRot = rot;
}
}
else
{
2020-09-07 20:01:28 +02:00
if (Lara.isMoving && Lara.generalPtr == item)
{
Lara.isMoving = false;
Lara.gunStatus = LG_NO_ARMS;
}
item->pos.yRot = rot;
}
2020-09-07 20:01:28 +02:00
/*}
else
{
2020-09-07 20:01:28 +02:00
short rot = item->pos.yRot;
item->pos.yRot = (l->pos.yRot + ANGLE(45)) & 0xC000;
if (TestLaraPosition(&MovingBlockBounds, item, l))
{
2020-09-07 20:01:28 +02:00
if (MoveLaraPosition(&PushableBlockPos, item, l))
{
l->animNumber = LA_PUSHABLE_GRAB;
l->frameNumber = g_Level.Anims[l->animNumber].frameBase;
l->currentAnimState = LS_PUSHABLE_GRAB;
l->goalAnimState = LS_PUSHABLE_GRAB;
Lara.isMoving = false;
Lara.gunStatus = LG_HANDS_BUSY;
Lara.cornerX = (int)item;
item->pos.yRot = rot;
}
else
{
Lara.generalPtr = item;
item->pos.yRot = rot;
}
}
2020-09-07 20:01:28 +02:00
else
{
if (Lara.isMoving && Lara.generalPtr == item)
{
Lara.isMoving = false;
Lara.gunStatus = LG_NO_ARMS;
}
item->pos.yRot = rot;
}
}*/
}
}
}
bool TestBlockMovable(ITEM_INFO* item, int blockHeight)
{
short roomNum = item->roomNumber;
FLOOR_INFO* floor = GetFloor(item->pos.xPos, item->pos.yPos, item->pos.zPos, &roomNum);
if (floor->floor == NO_HEIGHT / CLICK(1))
return true;
else if (floor->floor * CLICK(1) != item->pos.yPos - blockHeight)
return false;
return true;
}
bool TestBlockPush(ITEM_INFO* item, int blockHeight, unsigned short quadrant)
{
//if (!TestBlockMovable(item, blokhite))
// return 0;
int x = item->pos.xPos;
int y = item->pos.yPos;
int z = item->pos.zPos;
short roomNum = item->roomNumber;
switch (quadrant)
{
case NORTH:
z += SECTOR(1);
break;
case EAST:
x += SECTOR(1);
break;
case SOUTH:
z -= SECTOR(1);
break;
case WEST:
x -= SECTOR(1);
break;
}
FLOOR_INFO* floor = GetFloor(x, y, z, &roomNum);
ROOM_INFO* r = &g_Level.Rooms[roomNum];
if (XZ_GET_SECTOR(r, x - r->x, z - r->z).stopper)
return false;
if (GetFloorHeight(floor, x, y - CLICK(1), z) != y)
return false;
GetFloorHeight(floor, x, y, z);
if (HeightType)
return false;
int ceiling = y - blockHeight + 100;
floor = GetFloor(x, ceiling, z, &roomNum);
if (GetCeiling(floor, x, ceiling, z) > ceiling)
return false;
int oldX = item->pos.xPos;
int oldZ = item->pos.zPos;
item->pos.xPos = x;
item->pos.zPos = z;
GetCollidedObjects(item, 256, 1, &CollidedItems[0], 0, 0);
item->pos.xPos = oldX;
item->pos.zPos = oldZ;
2020-09-07 20:01:28 +02:00
item->itemFlags[7] = LaraItem->pos.yRot;
2020-09-07 20:01:28 +02:00
return CollidedItems[0] == NULL;
}
bool TestBlockPull(ITEM_INFO * item, int blockHeight, short quadrant)
{
//if (!TestBlockMovable(item, blokhite))
// return (0);
int xadd = 0;
int zadd = 0;
switch (quadrant)
{
case NORTH:
zadd = -SECTOR(1);
break;
case EAST:
xadd = -SECTOR(1);
break;
case SOUTH:
zadd = SECTOR(1);
break;
case WEST:
xadd = SECTOR(1);
break;
}
int x = item->pos.xPos + xadd;
int y = item->pos.yPos;
int z = item->pos.zPos + zadd;
short roomNum = item->roomNumber;
FLOOR_INFO* floor = GetFloor(x, y - CLICK(1), z, &roomNum);
ROOM_INFO* r = &g_Level.Rooms[roomNum];
if (XZ_GET_SECTOR(r, x - r->x, z - r->z).stopper)
return false;
if (GetFloorHeight(floor, x, y - CLICK(1), z) != y)
return false;
if (GetFloor(x, y - blockHeight, z, &quadrant)->ceiling * CLICK(1) > y - blockHeight)
return false;
int oldX = item->pos.xPos;
int oldZ = item->pos.zPos;
item->pos.xPos = x;
item->pos.zPos = z;
GetCollidedObjects(item, 256, 1, &CollidedItems[0], 0, 0);
item->pos.xPos = oldX;
item->pos.zPos = oldZ;
if (CollidedItems[0] != NULL)
return false;
x += xadd;
z += zadd;
roomNum = item->roomNumber;
floor = GetFloor(x, y - CLICK(1), z, &roomNum);
if (GetFloorHeight(floor, x, y - CLICK(1), z) != y)
return false;
if (GetFloor(x, y - 762, z, &roomNum)->ceiling * CLICK(1) > y - 762)
return false;
x = LaraItem->pos.xPos + xadd;
z = LaraItem->pos.zPos + zadd;
roomNum = LaraItem->roomNumber;
GetFloor(x, y, z, &roomNum);
r = &g_Level.Rooms[roomNum];
if (XZ_GET_SECTOR(r, x - r->x, z - r->z).stopper)
return false;
oldX = LaraItem->pos.xPos;
oldZ = LaraItem->pos.zPos;
LaraItem->pos.xPos = x;
LaraItem->pos.zPos = z;
GetCollidedObjects(LaraItem, 256, 1, &CollidedItems[0], 0, 0);
LaraItem->pos.xPos = oldX;
LaraItem->pos.zPos = oldZ;
return (CollidedItems[0] == NULL);
}