2020-12-21 13:16:29 -03:00
|
|
|
#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"
|
2021-01-18 13:41:59 +01:00
|
|
|
#define GET_PUSHABLEINFO(item) ((PUSHABLE_INFO*) item->data)
|
2020-12-21 13:16:29 -03:00
|
|
|
|
|
|
|
OBJECT_COLLISION_BOUNDS PushableBlockBounds = {
|
|
|
|
0x0000, 0x0000, 0xFF00, 0x0000,
|
|
|
|
0x0000, 0x0000, 0xF8E4, 0x071C,
|
|
|
|
0xEAAC, 0x1554, 0xF8E4, 0x071C
|
|
|
|
};
|
|
|
|
|
|
|
|
PHD_VECTOR PushableBlockPos = { 0, 0, 0 };
|
|
|
|
int 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;
|
2020-12-30 02:12:14 +01:00
|
|
|
|
2020-12-21 13:16:29 -03:00
|
|
|
floor = GetFloor(x + 1024, 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 + 1024, y, z, roomNumber);
|
|
|
|
}
|
|
|
|
|
|
|
|
roomNumber = baseRoomNumber;
|
|
|
|
floor = GetFloor(x - 1024, 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 - 1024, y, z, roomNumber);
|
|
|
|
}
|
|
|
|
|
|
|
|
roomNumber = baseRoomNumber;
|
|
|
|
floor = GetFloor(x, y, z + 1024, &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 + 1024, roomNumber);
|
|
|
|
}
|
|
|
|
|
|
|
|
roomNumber = baseRoomNumber;
|
|
|
|
floor = GetFloor(x, y, z - 1024, &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 - 1024, roomNumber);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void InitialisePushableBlock(short itemNum)
|
|
|
|
{
|
|
|
|
ITEM_INFO* item = &g_Level.Items[itemNum];
|
2020-12-30 02:12:14 +01:00
|
|
|
item->itemFlags[1] = NO_ITEM; // need to use itemFlags[1] to hold linked index for now
|
2020-12-21 13:16:29 -03:00
|
|
|
|
|
|
|
ClearMovableBlockSplitters(item->pos.xPos, item->pos.yPos, item->pos.zPos, item->roomNumber);
|
2020-12-30 02:12:14 +01:00
|
|
|
|
2021-01-16 18:38:16 +01:00
|
|
|
// allocate new pushable info
|
2020-12-30 02:12:14 +01:00
|
|
|
PUSHABLE_INFO* pushable = new PUSHABLE_INFO;
|
2020-12-31 06:50:16 +01:00
|
|
|
|
2020-12-30 02:12:14 +01:00
|
|
|
pushable->stackLimit = 3; // LUA
|
|
|
|
pushable->gravity = 9; // LUA
|
|
|
|
pushable->weight = 100; // LUA
|
2020-12-31 06:50:16 +01:00
|
|
|
pushable->moveX = item->pos.xPos;
|
|
|
|
pushable->moveZ = item->pos.zPos;
|
2020-12-30 02:12:14 +01:00
|
|
|
|
|
|
|
// read flags from OCB
|
|
|
|
int OCB = item->triggerFlags;
|
|
|
|
|
|
|
|
pushable->canFall = OCB & 0x20;
|
|
|
|
pushable->hasFloorCeiling = OCB & 0x40;
|
|
|
|
pushable->disablePull = OCB & 0x80;
|
|
|
|
pushable->disablePush = OCB & 0x100;
|
|
|
|
pushable->disableW = pushable->disableE = OCB & 0x200;
|
|
|
|
pushable->disableN = pushable->disableS = OCB & 0x400;
|
|
|
|
|
|
|
|
pushable->climb = 0; // maybe there will be better way to handle this than OCBs?
|
|
|
|
/*
|
|
|
|
pushable->climb |= (OCB & 0x800) ? CLIMB_WEST : 0;
|
|
|
|
pushable->climb |= (OCB & 0x1000) ? CLIMB_NORTH : 0;
|
|
|
|
pushable->climb |= (OCB & 0x2000) ? CLIMB_EAST : 0;
|
|
|
|
pushable->climb |= (OCB & 0x4000) ? CLIMB_SOUTH : 0;
|
|
|
|
*/
|
|
|
|
|
|
|
|
int height;
|
|
|
|
if (pushable->hasFloorCeiling)
|
2021-02-01 17:29:33 +01:00
|
|
|
{
|
2020-12-30 02:12:14 +01:00
|
|
|
height = (OCB & 0x1F) * CLICK(1);
|
2021-02-01 17:29:33 +01:00
|
|
|
T5M::Floordata::AddBridge(itemNum);
|
|
|
|
}
|
2020-12-30 02:12:14 +01:00
|
|
|
else
|
|
|
|
height = -GetBoundsAccurate(item)->Y1;
|
|
|
|
|
|
|
|
pushable->height = height;
|
|
|
|
|
|
|
|
pushable->loopSound = SFX_PUSHABLE_SOUND; // LUA
|
|
|
|
pushable->stopSound = SFX_PUSH_BLOCK_END; // LUA
|
|
|
|
pushable->fallSound = SFX_TR4_BOULDER_FALL; // LUA
|
|
|
|
|
|
|
|
item->data = (void*) pushable;
|
|
|
|
|
2021-01-16 18:38:16 +01:00
|
|
|
FindStack(itemNum); // check for stack formation on init
|
2020-12-21 13:16:29 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
void PushableBlockControl(short itemNumber)
|
|
|
|
{
|
|
|
|
ITEM_INFO* item = &g_Level.Items[itemNumber];
|
2020-12-30 02:12:14 +01:00
|
|
|
Lara.generalPtr = (void*)itemNumber;
|
|
|
|
|
2020-12-21 13:16:29 -03:00
|
|
|
PHD_VECTOR pos;
|
|
|
|
pos.x = 0;
|
|
|
|
pos.y = 0;
|
|
|
|
pos.z = 0;
|
|
|
|
|
|
|
|
short quadrant = (unsigned short)(LaraItem->pos.yRot + ANGLE(45)) / ANGLE(90);
|
|
|
|
|
|
|
|
int x, z;
|
2020-12-30 02:12:14 +01:00
|
|
|
short roomNumber;
|
2020-12-21 13:16:29 -03:00
|
|
|
FLOOR_INFO* floor;
|
|
|
|
ROOM_INFO* r;
|
2021-01-18 13:41:59 +01:00
|
|
|
PUSHABLE_INFO* pushable = GET_PUSHABLEINFO(item);
|
2020-12-30 02:12:14 +01:00
|
|
|
int blockHeight = GetStackHeight(item);
|
2020-12-25 01:36:28 +01:00
|
|
|
|
2020-12-30 02:12:14 +01:00
|
|
|
// do sound effects, it works for now
|
|
|
|
if (DoPushPull > 0)
|
2020-12-24 03:53:36 +01:00
|
|
|
{
|
2021-01-18 13:41:59 +01:00
|
|
|
SoundEffect(pushable->loopSound, &item->pos, 2);
|
2020-12-30 02:12:14 +01:00
|
|
|
}
|
|
|
|
else if (DoPushPull < 0)
|
|
|
|
{
|
|
|
|
DoPushPull = 0;
|
2021-01-18 13:41:59 +01:00
|
|
|
SoundEffect(pushable->stopSound, &item->pos, 2);
|
2020-12-24 03:53:36 +01:00
|
|
|
}
|
2020-12-21 13:16:29 -03:00
|
|
|
|
2020-12-30 02:12:14 +01:00
|
|
|
// control block falling
|
|
|
|
if (item->gravityStatus)
|
2020-12-21 13:16:29 -03:00
|
|
|
{
|
2020-12-30 02:12:14 +01:00
|
|
|
roomNumber = item->roomNumber;
|
|
|
|
floor = GetFloor(item->pos.xPos, item->pos.yPos, item->pos.zPos, &roomNumber);
|
|
|
|
int floorHeight = GetFloorHeight(floor, item->pos.xPos, item->pos.yPos + 10, item->pos.zPos);
|
|
|
|
|
|
|
|
if (item->pos.yPos < floorHeight - item->fallspeed)
|
2020-12-21 13:16:29 -03:00
|
|
|
{
|
2020-12-30 02:12:14 +01:00
|
|
|
if (item->fallspeed + pushable->gravity < 128)
|
|
|
|
item->fallspeed += pushable->gravity;
|
|
|
|
else
|
|
|
|
item->fallspeed = 128;
|
|
|
|
item->pos.yPos += item->fallspeed;
|
|
|
|
|
|
|
|
MoveStackY(itemNumber, item->fallspeed);
|
2020-12-21 13:16:29 -03:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-12-30 02:12:14 +01:00
|
|
|
item->gravityStatus = false;
|
|
|
|
int relY = floorHeight - item->pos.yPos;
|
|
|
|
item->pos.yPos = floorHeight;
|
|
|
|
if (item->fallspeed >= 128)
|
|
|
|
floor_shake_effect(item);
|
|
|
|
item->fallspeed = 0;
|
|
|
|
SoundEffect(pushable->fallSound, &item->pos, 2);
|
|
|
|
|
|
|
|
MoveStackY(itemNumber, relY);
|
2021-01-16 18:38:16 +01:00
|
|
|
AddBridgeStack(itemNumber);
|
2020-12-30 02:12:14 +01:00
|
|
|
|
|
|
|
if (FindStack(itemNumber) == NO_ITEM) // if fallen on some existing pushables, don't test triggers
|
|
|
|
{
|
|
|
|
roomNumber = item->roomNumber;
|
|
|
|
TestTriggersAtXYZ(item->pos.xPos, item->pos.yPos, item->pos.zPos, roomNumber, 1, item->flags & 0x3E00);
|
|
|
|
}
|
|
|
|
|
|
|
|
RemoveActiveItem(itemNumber);
|
|
|
|
item->status = ITEM_NOT_ACTIVE;
|
|
|
|
|
|
|
|
if (pushable->hasFloorCeiling)
|
|
|
|
{
|
|
|
|
//AlterFloorHeight(item, -((item->triggerFlags - 64) * 256));
|
|
|
|
AdjustStopperFlag(item, item->itemFlags[0] + 0x8000, 0);
|
|
|
|
}
|
2020-12-21 13:16:29 -03:00
|
|
|
}
|
|
|
|
|
2020-12-30 02:12:14 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-12-31 06:50:16 +01:00
|
|
|
int displaceBox = GetBoundsAccurate(LaraItem)->Z2 - 80; // move pushable based on bbox->Z2 of Lara
|
|
|
|
|
2020-12-30 02:12:14 +01:00
|
|
|
switch (LaraItem->animNumber)
|
|
|
|
{
|
|
|
|
case LA_PUSHABLE_PUSH:
|
|
|
|
|
|
|
|
if (LaraItem->frameNumber == g_Level.Anims[LaraItem->animNumber].frameBase)
|
2021-01-16 18:38:16 +01:00
|
|
|
{
|
2020-12-30 02:12:14 +01:00
|
|
|
RemoveFromStack(itemNumber);
|
2021-01-16 18:38:16 +01:00
|
|
|
RemoveBridgeStack(itemNumber);
|
|
|
|
}
|
2020-12-30 02:12:14 +01:00
|
|
|
|
|
|
|
switch (quadrant)
|
2020-12-21 13:16:29 -03:00
|
|
|
{
|
|
|
|
case 0:
|
2020-12-31 06:50:16 +01:00
|
|
|
z = pushable->moveZ + displaceBox;
|
2020-12-21 13:16:29 -03:00
|
|
|
if (abs(item->pos.zPos - z) < 512 && item->pos.zPos < z)
|
|
|
|
item->pos.zPos = z;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1:
|
2020-12-31 06:50:16 +01:00
|
|
|
x = pushable->moveX + displaceBox;
|
2020-12-21 13:16:29 -03:00
|
|
|
if (abs(item->pos.xPos - x) < 512 && item->pos.xPos < x)
|
|
|
|
item->pos.xPos = x;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 2:
|
2020-12-31 06:50:16 +01:00
|
|
|
z = pushable->moveZ - displaceBox;
|
2020-12-21 13:16:29 -03:00
|
|
|
if (abs(item->pos.zPos - z) < 512 && item->pos.zPos > z)
|
|
|
|
item->pos.zPos = z;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 3:
|
2020-12-31 06:50:16 +01:00
|
|
|
x = pushable->moveX - displaceBox;
|
2020-12-21 13:16:29 -03:00
|
|
|
if (abs(item->pos.xPos - x) < 512 && item->pos.xPos > x)
|
|
|
|
item->pos.xPos = x;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-12-30 02:12:14 +01:00
|
|
|
MoveStackXZ(itemNumber);
|
2020-12-21 13:16:29 -03:00
|
|
|
|
2021-01-16 18:38:16 +01:00
|
|
|
|
|
|
|
if (LaraItem->frameNumber == g_Level.Anims[LaraItem->animNumber].frameEnd - 1)
|
2020-12-21 13:16:29 -03:00
|
|
|
{
|
2021-01-16 18:38:16 +01:00
|
|
|
if (pushable->canFall) // check if pushable is about to fall
|
2020-12-21 13:16:29 -03:00
|
|
|
{
|
2020-12-30 02:12:14 +01:00
|
|
|
roomNumber = item->roomNumber;
|
|
|
|
floor = GetFloor(item->pos.xPos, item->pos.yPos, item->pos.zPos, &roomNumber);
|
|
|
|
if (GetFloorHeight(floor, item->pos.xPos, item->pos.yPos + 10, item->pos.zPos) > item->pos.yPos)
|
2020-12-21 13:16:29 -03:00
|
|
|
{
|
2020-12-30 02:12:14 +01:00
|
|
|
item->pos.xPos = item->pos.xPos & 0xFFFFFE00 | 0x200;
|
|
|
|
item->pos.zPos = item->pos.zPos & 0xFFFFFE00 | 0x200;
|
|
|
|
MoveStackXZ(itemNumber);
|
2021-01-18 13:41:59 +01:00
|
|
|
//SoundEffect(pushable->stopSound, &item->pos, 2);
|
2020-12-30 02:12:14 +01:00
|
|
|
DoPushPull = 0;
|
|
|
|
LaraItem->goalAnimState = LS_STOP;
|
|
|
|
|
|
|
|
item->gravityStatus = true; // do fall
|
2021-01-16 18:38:16 +01:00
|
|
|
return;
|
2020-12-21 13:16:29 -03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-16 18:38:16 +01:00
|
|
|
|
2020-12-21 13:16:29 -03:00
|
|
|
if (TrInput & IN_ACTION)
|
|
|
|
{
|
2020-12-24 03:53:36 +01:00
|
|
|
if (!TestBlockPush(item, blockHeight, quadrant))
|
2020-12-30 02:12:14 +01:00
|
|
|
{
|
2020-12-21 13:16:29 -03:00
|
|
|
LaraItem->goalAnimState = LS_STOP;
|
2020-12-30 02:12:14 +01:00
|
|
|
}
|
2020-12-21 13:16:29 -03:00
|
|
|
else
|
|
|
|
{
|
|
|
|
TestTriggersAtXYZ(item->pos.xPos, item->pos.yPos, item->pos.zPos, item->roomNumber, 1, item->flags & 0x3E00);
|
2020-12-31 06:50:16 +01:00
|
|
|
pushable->moveX = item->pos.xPos;
|
|
|
|
pushable->moveZ = item->pos.zPos;
|
2020-12-21 13:16:29 -03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LaraItem->goalAnimState = LS_STOP;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case LA_PUSHABLE_PULL:
|
2020-12-30 02:12:14 +01:00
|
|
|
|
|
|
|
if (LaraItem->frameNumber == g_Level.Anims[LaraItem->animNumber].frameBase)
|
2021-01-16 18:38:16 +01:00
|
|
|
{
|
2020-12-30 02:12:14 +01:00
|
|
|
RemoveFromStack(itemNumber);
|
2021-01-16 18:38:16 +01:00
|
|
|
RemoveBridgeStack(itemNumber);
|
|
|
|
}
|
2020-12-21 13:16:29 -03:00
|
|
|
|
|
|
|
switch (quadrant)
|
|
|
|
{
|
|
|
|
case NORTH:
|
2020-12-31 06:50:16 +01:00
|
|
|
z = pushable->moveZ + displaceBox;
|
2020-12-21 13:16:29 -03:00
|
|
|
if (abs(item->pos.zPos - z) < 512 && item->pos.zPos > z)
|
|
|
|
item->pos.zPos = z;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case EAST:
|
2020-12-31 06:50:16 +01:00
|
|
|
x = pushable->moveX + displaceBox;
|
2020-12-21 13:16:29 -03:00
|
|
|
if (abs(item->pos.xPos - x) < 512 && item->pos.xPos > x)
|
|
|
|
item->pos.xPos = x;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SOUTH:
|
2020-12-31 06:50:16 +01:00
|
|
|
z = pushable->moveZ - displaceBox;
|
2020-12-21 13:16:29 -03:00
|
|
|
if (abs(item->pos.zPos - z) < 512 && item->pos.zPos < z)
|
|
|
|
item->pos.zPos = z;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WEST:
|
2020-12-31 06:50:16 +01:00
|
|
|
x = pushable->moveX - displaceBox;
|
2020-12-21 13:16:29 -03:00
|
|
|
if (abs(item->pos.xPos - x) < 512 && item->pos.xPos < x)
|
|
|
|
item->pos.xPos = x;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2020-12-30 02:12:14 +01:00
|
|
|
MoveStackXZ(itemNumber);
|
2020-12-21 13:16:29 -03:00
|
|
|
|
|
|
|
if (LaraItem->frameNumber == g_Level.Anims[LaraItem->animNumber].frameEnd - 1)
|
|
|
|
{
|
|
|
|
if (TrInput & IN_ACTION)
|
|
|
|
{
|
2020-12-24 03:53:36 +01:00
|
|
|
if (!TestBlockPull(item, blockHeight, quadrant))
|
2020-12-30 02:12:14 +01:00
|
|
|
{
|
2020-12-21 13:16:29 -03:00
|
|
|
LaraItem->goalAnimState = LS_STOP;
|
2020-12-30 02:12:14 +01:00
|
|
|
}
|
2020-12-21 13:16:29 -03:00
|
|
|
else
|
|
|
|
{
|
|
|
|
TestTriggersAtXYZ(item->pos.xPos, item->pos.yPos, item->pos.zPos, item->roomNumber, 1, item->flags & 0x3E00);
|
2020-12-31 06:50:16 +01:00
|
|
|
pushable->moveX = item->pos.xPos;
|
|
|
|
pushable->moveZ = item->pos.zPos;
|
2020-12-21 13:16:29 -03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
LaraItem->goalAnimState = LS_STOP;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2020-12-30 02:12:14 +01:00
|
|
|
|
2020-12-21 13:16:29 -03:00
|
|
|
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;
|
|
|
|
|
2020-12-30 02:12:14 +01:00
|
|
|
MoveStackXZ(itemNumber);
|
|
|
|
FindStack(itemNumber);
|
2021-01-16 18:38:16 +01:00
|
|
|
AddBridgeStack(itemNumber);
|
2020-12-21 13:16:29 -03:00
|
|
|
|
2020-12-30 02:12:14 +01:00
|
|
|
roomNumber = item->roomNumber;
|
|
|
|
TestTriggersAtXYZ(item->pos.xPos, item->pos.yPos, item->pos.zPos, roomNumber, 1, item->flags & 0x3E00);
|
2020-12-21 13:16:29 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (LaraItem->frameNumber == g_Level.Anims[LaraItem->animNumber].frameEnd)
|
|
|
|
{
|
|
|
|
RemoveActiveItem(itemNumber);
|
|
|
|
item->status = ITEM_NOT_ACTIVE;
|
|
|
|
|
2020-12-30 02:12:14 +01:00
|
|
|
if (pushable->hasFloorCeiling)
|
2020-12-21 13:16:29 -03:00
|
|
|
{
|
|
|
|
//AlterFloorHeight(item, -((item->triggerFlags - 64) * 256));
|
|
|
|
AdjustStopperFlag(item, item->itemFlags[0] + 0x8000, 0);
|
|
|
|
}
|
|
|
|
}
|
2021-01-16 18:38:16 +01:00
|
|
|
|
2020-12-21 13:16:29 -03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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 - 256, item->pos.zPos, &roomNumber);
|
2021-01-18 13:41:59 +01:00
|
|
|
PUSHABLE_INFO* pushable = GET_PUSHABLEINFO(item);
|
2020-12-21 13:16:29 -03:00
|
|
|
|
2020-12-30 02:12:14 +01:00
|
|
|
int blockHeight = GetStackHeight(item);
|
|
|
|
|
2020-12-21 13:16:29 -03:00
|
|
|
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))
|
|
|
|
{
|
|
|
|
if ((l->currentAnimState != LS_PUSHABLE_GRAB
|
|
|
|
|| (l->frameNumber != g_Level.Anims[LA_PUSHABLE_GRAB].frameBase + 19)
|
|
|
|
|| Lara.cornerX != (int)item))
|
|
|
|
{
|
2020-12-30 02:12:14 +01:00
|
|
|
if (!pushable->hasFloorCeiling)
|
2020-12-21 13:16:29 -03:00
|
|
|
ObjectCollision(itemNum, l, coll);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
short quadrant = (unsigned short)(LaraItem->pos.yRot + ANGLE(45)) / ANGLE(90);
|
|
|
|
|
2020-12-30 02:12:14 +01:00
|
|
|
bool quadrantDisabled = false;
|
|
|
|
switch (quadrant)
|
|
|
|
{
|
|
|
|
case NORTH:
|
|
|
|
quadrantDisabled = pushable->disableN;
|
|
|
|
break;
|
|
|
|
case EAST:
|
|
|
|
quadrantDisabled = pushable->disableE;
|
|
|
|
break;
|
|
|
|
case SOUTH:
|
|
|
|
quadrantDisabled = pushable->disableS;
|
|
|
|
break;
|
|
|
|
case WEST:
|
|
|
|
quadrantDisabled = pushable->disableW;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (quadrantDisabled)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!CheckStackLimit(item))
|
|
|
|
return;
|
|
|
|
|
2020-12-21 13:16:29 -03:00
|
|
|
if (TrInput & IN_FORWARD)
|
|
|
|
{
|
2020-12-30 02:12:14 +01:00
|
|
|
if (!TestBlockPush(item, blockHeight, quadrant) || pushable->disablePush)
|
2020-12-21 13:16:29 -03:00
|
|
|
return;
|
|
|
|
l->goalAnimState = LS_PUSHABLE_PUSH;
|
|
|
|
}
|
|
|
|
else if (TrInput & IN_BACK)
|
|
|
|
{
|
2020-12-30 02:12:14 +01:00
|
|
|
if (!TestBlockPull(item, blockHeight, quadrant) || pushable->disablePull)
|
2020-12-21 13:16:29 -03:00
|
|
|
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-12-30 02:12:14 +01:00
|
|
|
|
2020-12-31 06:50:16 +01:00
|
|
|
pushable->moveX = item->pos.xPos;
|
|
|
|
pushable->moveZ = item->pos.zPos;
|
2020-12-21 13:16:29 -03:00
|
|
|
|
2020-12-30 02:12:14 +01:00
|
|
|
if (pushable->hasFloorCeiling)
|
2020-12-21 13:16:29 -03:00
|
|
|
{
|
|
|
|
//AlterFloorHeight(item, ((item->triggerFlags - 64) * 256));
|
|
|
|
AdjustStopperFlag(item, item->itemFlags[0], 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-02-01 19:12:22 +01:00
|
|
|
BOUNDING_BOX* bounds = GetBoundsAccurate(item);
|
2020-12-21 13:16:29 -03:00
|
|
|
|
2021-02-01 19:12:22 +01:00
|
|
|
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-12-21 13:16:29 -03:00
|
|
|
|
2021-02-01 19:12:22 +01:00
|
|
|
short rot = item->pos.yRot;
|
|
|
|
item->pos.yRot = (l->pos.yRot + ANGLE(45)) & 0xC000;
|
2020-12-21 13:16:29 -03:00
|
|
|
|
2021-02-01 19:12:22 +01:00
|
|
|
if (TestLaraPosition(&PushableBlockBounds, item, l))
|
|
|
|
{
|
|
|
|
unsigned short quadrant = (unsigned short)((item->pos.yRot / 0x4000) + ((rot + 0x2000) / 0x4000));
|
|
|
|
if (quadrant & 1)
|
|
|
|
PushableBlockPos.z = bounds->X1 - 35;
|
|
|
|
else
|
|
|
|
PushableBlockPos.z = bounds->Z1 - 35;
|
2020-12-21 13:16:29 -03:00
|
|
|
|
2021-02-01 19:12:22 +01:00
|
|
|
if (pushable->hasFloorCeiling)
|
|
|
|
{
|
|
|
|
// For now don't use auto-align function because it can collide with climb up moves of Lara
|
|
|
|
|
|
|
|
LaraItem->pos.xRot = item->pos.xRot;
|
|
|
|
LaraItem->pos.yRot = item->pos.yRot;
|
|
|
|
LaraItem->pos.zRot = item->pos.zRot;
|
|
|
|
|
|
|
|
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
|
|
|
|
{
|
|
|
|
if (MoveLaraPosition(&PushableBlockPos, item, l))
|
|
|
|
{
|
2020-12-21 13:16:29 -03:00
|
|
|
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
|
|
|
|
{
|
2021-02-01 19:12:22 +01:00
|
|
|
Lara.generalPtr = item;
|
|
|
|
item->pos.yRot = rot;
|
2020-12-21 13:16:29 -03:00
|
|
|
}
|
|
|
|
}
|
2021-02-01 19:12:22 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (Lara.isMoving && Lara.generalPtr == item)
|
2020-12-21 13:16:29 -03:00
|
|
|
{
|
2021-02-01 19:12:22 +01:00
|
|
|
Lara.isMoving = false;
|
|
|
|
Lara.gunStatus = LG_NO_ARMS;
|
2020-12-21 13:16:29 -03:00
|
|
|
}
|
2021-02-01 19:12:22 +01:00
|
|
|
item->pos.yRot = rot;
|
2020-12-21 13:16:29 -03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-30 02:12:14 +01:00
|
|
|
void pushLoop(ITEM_INFO* item) // Do Flipeffect 18 in anims
|
|
|
|
{
|
|
|
|
DoPushPull = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void pushEnd(ITEM_INFO* item) // Do Flipeffect 19 in anims
|
|
|
|
{
|
|
|
|
if (DoPushPull == 1)
|
|
|
|
{
|
|
|
|
DoPushPull = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-21 13:16:29 -03:00
|
|
|
int TestBlockMovable(ITEM_INFO* item, int blokhite)
|
|
|
|
{
|
|
|
|
short roomNumber = item->roomNumber;
|
|
|
|
FLOOR_INFO* floor = GetFloor(item->pos.xPos, item->pos.yPos, item->pos.zPos, &roomNumber);
|
|
|
|
if (floor->floor == NO_HEIGHT / 256)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
if (floor->floor * 256 != item->pos.yPos - blokhite)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int TestBlockPush(ITEM_INFO* item, int blockhite, unsigned short quadrant)
|
|
|
|
{
|
|
|
|
int x = item->pos.xPos;
|
|
|
|
int y = item->pos.yPos;
|
|
|
|
int z = item->pos.zPos;
|
|
|
|
|
|
|
|
short roomNum = item->roomNumber;
|
|
|
|
switch (quadrant)
|
|
|
|
{
|
|
|
|
case NORTH:
|
|
|
|
z += 1024;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case EAST:
|
|
|
|
x += 1024;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SOUTH:
|
|
|
|
z -= 1024;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WEST:
|
|
|
|
x -= 1024;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2021-01-18 13:41:59 +01:00
|
|
|
FLOOR_INFO* floor = GetFloor(x, y - blockhite, z, &roomNum);
|
2020-12-21 13:16:29 -03:00
|
|
|
ROOM_INFO* r = &g_Level.Rooms[roomNum];
|
|
|
|
if (XZ_GET_SECTOR(r, x - r->x, z - r->z).stopper)
|
|
|
|
return 0;
|
|
|
|
|
2021-01-18 13:41:59 +01:00
|
|
|
int floorHeight = GetFloorHeight(floor, x, y - blockhite, z);
|
|
|
|
if (HeightType)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (GET_PUSHABLEINFO(item)->canFall)
|
2020-12-30 02:12:14 +01:00
|
|
|
{
|
|
|
|
if (floorHeight < y)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (floorHeight != y)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-12-21 13:16:29 -03:00
|
|
|
|
|
|
|
int ceiling = y - blockhite + 100;
|
|
|
|
floor = GetFloor(x, ceiling, z, &roomNum);
|
|
|
|
if (GetCeiling(floor, x, ceiling, z) > ceiling)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
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, 1);
|
|
|
|
item->pos.xPos = oldX;
|
|
|
|
item->pos.zPos = oldZ;
|
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
while (CollidedItems[i] != NULL)
|
|
|
|
{
|
|
|
|
if (Objects[CollidedItems[i]->objectNumber].floor == NULL)
|
|
|
|
return 0;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int TestBlockPull(ITEM_INFO* item, int blockhite, short quadrant)
|
|
|
|
{
|
|
|
|
int xadd = 0;
|
|
|
|
int zadd = 0;
|
|
|
|
|
|
|
|
switch (quadrant)
|
|
|
|
{
|
|
|
|
case NORTH:
|
|
|
|
zadd = -1024;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case EAST:
|
|
|
|
xadd = -1024;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SOUTH:
|
|
|
|
zadd = 1024;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WEST:
|
|
|
|
xadd = 1024;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
int x = item->pos.xPos + xadd;
|
|
|
|
int y = item->pos.yPos;
|
|
|
|
int z = item->pos.zPos + zadd;
|
|
|
|
short roomNum = item->roomNumber;
|
2021-01-18 13:41:59 +01:00
|
|
|
FLOOR_INFO* floor = GetFloor(x, y - blockhite, z, &roomNum);
|
2020-12-21 13:16:29 -03:00
|
|
|
|
|
|
|
ROOM_INFO* r = &g_Level.Rooms[roomNum];
|
|
|
|
if (XZ_GET_SECTOR(r, x - r->x, z - r->z).stopper)
|
|
|
|
return 0;
|
|
|
|
|
2021-01-18 13:41:59 +01:00
|
|
|
if (GetFloorHeight(floor, x, y - blockhite, z) != y)
|
2020-12-21 13:16:29 -03:00
|
|
|
return 0;
|
|
|
|
|
2021-01-18 13:41:59 +01:00
|
|
|
if (floor->ceiling * 256 > y - blockhite)
|
2020-12-21 13:16:29 -03:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
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, 1);
|
|
|
|
item->pos.xPos = oldX;
|
|
|
|
item->pos.zPos = oldZ;
|
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
while (CollidedItems[i] != NULL)
|
|
|
|
{
|
|
|
|
if (Objects[CollidedItems[i]->objectNumber].floor == NULL)
|
|
|
|
return 0;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
x += xadd;
|
|
|
|
z += zadd;
|
|
|
|
roomNum = item->roomNumber;
|
2021-01-18 13:41:59 +01:00
|
|
|
floor = GetFloor(x, y - blockhite, z, &roomNum);
|
2020-12-21 13:16:29 -03:00
|
|
|
|
2021-01-18 13:41:59 +01:00
|
|
|
if (GetFloorHeight(floor, x, y - blockhite, z) != y)
|
2020-12-21 13:16:29 -03:00
|
|
|
return 0;
|
|
|
|
|
2021-01-18 13:41:59 +01:00
|
|
|
if (floor->ceiling * 256 > y - LARA_HITE)
|
2020-12-21 13:16:29 -03:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
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 0;
|
|
|
|
|
|
|
|
oldX = LaraItem->pos.xPos;
|
|
|
|
oldZ = LaraItem->pos.zPos;
|
|
|
|
LaraItem->pos.xPos = x;
|
|
|
|
LaraItem->pos.zPos = z;
|
|
|
|
GetCollidedObjects(LaraItem, 256, 1, &CollidedItems[0], 0, 1);
|
|
|
|
LaraItem->pos.xPos = oldX;
|
|
|
|
LaraItem->pos.zPos = oldZ;
|
|
|
|
|
|
|
|
i = 0;
|
|
|
|
while (CollidedItems[i] != NULL)
|
|
|
|
{
|
|
|
|
if (Objects[CollidedItems[i]->objectNumber].floor == NULL)
|
|
|
|
return 0;
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2021-01-16 18:38:16 +01:00
|
|
|
void MoveStackXZ(short itemNum)
|
2020-12-30 02:12:14 +01:00
|
|
|
{
|
|
|
|
auto item = &g_Level.Items[itemNum];
|
|
|
|
|
2021-01-16 18:38:16 +01:00
|
|
|
short newRoomNumber = item->roomNumber;
|
|
|
|
GetFloor(item->pos.xPos, item->pos.yPos, item->pos.zPos, &newRoomNumber);
|
2020-12-30 02:12:14 +01:00
|
|
|
if (newRoomNumber != item->roomNumber)
|
|
|
|
ItemNewRoom(itemNum, newRoomNumber);
|
|
|
|
|
|
|
|
auto stackItem = item;
|
|
|
|
while (stackItem->itemFlags[1] != NO_ITEM) // move pushblock stack together with bottom pushblock
|
|
|
|
{
|
|
|
|
int stackIndex = stackItem->itemFlags[1];
|
|
|
|
stackItem = &g_Level.Items[stackIndex];
|
|
|
|
|
|
|
|
stackItem->pos.xPos = item->pos.xPos;
|
|
|
|
stackItem->pos.zPos = item->pos.zPos;
|
|
|
|
|
2021-01-16 18:38:16 +01:00
|
|
|
newRoomNumber = stackItem->roomNumber;
|
|
|
|
GetFloor(stackItem->pos.xPos, stackItem->pos.yPos, stackItem->pos.zPos, &newRoomNumber);
|
2020-12-30 02:12:14 +01:00
|
|
|
if (newRoomNumber != stackItem->roomNumber)
|
|
|
|
ItemNewRoom(stackIndex, newRoomNumber);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-16 18:38:16 +01:00
|
|
|
void MoveStackY(short itemNum, int y)
|
2020-12-30 02:12:14 +01:00
|
|
|
{
|
|
|
|
auto item = &g_Level.Items[itemNum];
|
|
|
|
|
2021-01-16 18:38:16 +01:00
|
|
|
short newRoomNumber = item->roomNumber;
|
|
|
|
GetFloor(item->pos.xPos, item->pos.yPos, item->pos.zPos, &newRoomNumber);
|
2020-12-30 02:12:14 +01:00
|
|
|
if (newRoomNumber != item->roomNumber)
|
|
|
|
ItemNewRoom(itemNum, newRoomNumber);
|
|
|
|
|
|
|
|
while (item->itemFlags[1] != NO_ITEM) // move pushblock stack together with bottom pushblock
|
|
|
|
{
|
|
|
|
int stackIndex = item->itemFlags[1];
|
|
|
|
item = &g_Level.Items[stackIndex];
|
|
|
|
|
|
|
|
item->pos.yPos += y;
|
|
|
|
|
2021-01-16 18:38:16 +01:00
|
|
|
short newRoomNumber = item->roomNumber;
|
|
|
|
GetFloor(item->pos.xPos, item->pos.yPos, item->pos.zPos, &newRoomNumber);
|
2020-12-30 02:12:14 +01:00
|
|
|
if (newRoomNumber != item->roomNumber)
|
|
|
|
ItemNewRoom(stackIndex, newRoomNumber);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-16 18:38:16 +01:00
|
|
|
void AddBridgeStack(short itemNum)
|
|
|
|
{
|
2021-02-01 17:29:33 +01:00
|
|
|
auto item = &g_Level.Items[itemNum];
|
|
|
|
|
|
|
|
if (GET_PUSHABLEINFO(item)->hasFloorCeiling)
|
|
|
|
T5M::Floordata::AddBridge(itemNum);
|
2021-01-16 18:38:16 +01:00
|
|
|
|
|
|
|
int stackIndex = g_Level.Items[itemNum].itemFlags[1];
|
|
|
|
while (stackIndex != NO_ITEM)
|
|
|
|
{
|
2021-02-01 17:29:33 +01:00
|
|
|
auto stackItem = &g_Level.Items[stackIndex];
|
|
|
|
|
|
|
|
if (GET_PUSHABLEINFO(stackItem)->hasFloorCeiling)
|
|
|
|
T5M::Floordata::AddBridge(stackIndex);
|
|
|
|
|
2021-01-16 18:38:16 +01:00
|
|
|
stackIndex = g_Level.Items[stackIndex].itemFlags[1];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void RemoveBridgeStack(short itemNum)
|
|
|
|
{
|
2021-02-01 17:29:33 +01:00
|
|
|
auto item = &g_Level.Items[itemNum];
|
|
|
|
|
|
|
|
if (GET_PUSHABLEINFO(item)->hasFloorCeiling)
|
|
|
|
T5M::Floordata::RemoveBridge(itemNum);
|
2021-01-16 18:38:16 +01:00
|
|
|
|
|
|
|
int stackIndex = g_Level.Items[itemNum].itemFlags[1];
|
|
|
|
while (stackIndex != NO_ITEM)
|
|
|
|
{
|
2021-02-01 17:29:33 +01:00
|
|
|
auto stackItem = &g_Level.Items[stackIndex];
|
|
|
|
|
|
|
|
if (GET_PUSHABLEINFO(stackItem)->hasFloorCeiling)
|
|
|
|
T5M::Floordata::RemoveBridge(stackIndex);
|
|
|
|
|
2021-01-16 18:38:16 +01:00
|
|
|
stackIndex = g_Level.Items[stackIndex].itemFlags[1];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void RemoveFromStack(short itemNum) // unlink pushable from stack if linked
|
2020-12-30 02:12:14 +01:00
|
|
|
{
|
|
|
|
for (int i = 0; i < g_Level.NumItems; i++)
|
|
|
|
{
|
|
|
|
if (i == itemNum)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
auto belowItem = &g_Level.Items[i];
|
|
|
|
|
|
|
|
int objectNum = belowItem->objectNumber;
|
|
|
|
if (objectNum >= ID_PUSHABLE_OBJECT1 && objectNum <= ID_PUSHABLE_OBJECT10)
|
|
|
|
{
|
|
|
|
if (belowItem->itemFlags[1] == itemNum)
|
|
|
|
belowItem->itemFlags[1] = NO_ITEM;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-16 18:38:16 +01:00
|
|
|
int FindStack(short itemNum)
|
2020-12-30 02:12:14 +01:00
|
|
|
{
|
|
|
|
int stackTop = NO_ITEM; // index of heighest (yPos) pushable in stack
|
|
|
|
int stackYmin = CLICK(256); // set starting height
|
|
|
|
|
|
|
|
//Check for pushable directly below current one in same sector
|
|
|
|
for (int i = 0; i < g_Level.NumItems; i++)
|
|
|
|
{
|
|
|
|
if (i == itemNum)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
auto belowItem = &g_Level.Items[i];
|
|
|
|
|
|
|
|
int objectNum = belowItem->objectNumber;
|
|
|
|
if (objectNum >= ID_PUSHABLE_OBJECT1 && objectNum <= ID_PUSHABLE_OBJECT10)
|
|
|
|
{
|
|
|
|
auto item = &g_Level.Items[itemNum];
|
|
|
|
int x = item->pos.xPos;
|
|
|
|
int y = item->pos.yPos;
|
|
|
|
int z = item->pos.zPos;
|
|
|
|
|
|
|
|
if (belowItem->pos.xPos == x && belowItem->pos.zPos == z)
|
|
|
|
{
|
|
|
|
int belowY = belowItem->pos.yPos;
|
|
|
|
if (belowY > y && belowY < stackYmin)
|
|
|
|
{
|
|
|
|
// set heighest pushable so far as top of stack
|
|
|
|
stackTop = i;
|
|
|
|
stackYmin = belowItem->pos.yPos;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stackTop != NO_ITEM)
|
|
|
|
g_Level.Items[stackTop].itemFlags[1] = itemNum;
|
|
|
|
|
|
|
|
return stackTop;
|
|
|
|
}
|
|
|
|
|
|
|
|
int GetStackHeight(ITEM_INFO* item)
|
|
|
|
{
|
2021-01-18 13:41:59 +01:00
|
|
|
int height = GET_PUSHABLEINFO(item)->height;
|
2020-12-30 02:12:14 +01:00
|
|
|
|
|
|
|
auto stackItem = item;
|
|
|
|
while (stackItem->itemFlags[1] != NO_ITEM)
|
|
|
|
{
|
|
|
|
stackItem = &g_Level.Items[stackItem->itemFlags[1]];
|
2021-01-18 13:41:59 +01:00
|
|
|
height += GET_PUSHABLEINFO(stackItem)->height;
|
2020-12-30 02:12:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return height;
|
|
|
|
}
|
|
|
|
|
2021-01-16 18:38:16 +01:00
|
|
|
bool CheckStackLimit(ITEM_INFO* item)
|
2020-12-30 02:12:14 +01:00
|
|
|
{
|
2021-01-18 13:41:59 +01:00
|
|
|
int limit = GET_PUSHABLEINFO(item)->stackLimit;
|
2020-12-30 02:12:14 +01:00
|
|
|
|
|
|
|
int count = 1;
|
|
|
|
auto stackItem = item;
|
|
|
|
while (stackItem->itemFlags[1] != NO_ITEM)
|
|
|
|
{
|
|
|
|
stackItem = &g_Level.Items[stackItem->itemFlags[1]];
|
|
|
|
count++;
|
|
|
|
|
|
|
|
if (count > limit)
|
2021-01-16 18:38:16 +01:00
|
|
|
return false;
|
2020-12-30 02:12:14 +01:00
|
|
|
}
|
|
|
|
|
2021-01-16 18:38:16 +01:00
|
|
|
return true;
|
2020-12-30 02:12:14 +01:00
|
|
|
}
|
|
|
|
|
2021-01-06 17:53:13 -03:00
|
|
|
std::optional<int> PushableBlockFloor(short itemNumber, int x, int y, int z)
|
2020-12-21 13:16:29 -03:00
|
|
|
{
|
|
|
|
const auto& item = g_Level.Items[itemNumber];
|
2021-02-01 19:12:22 +01:00
|
|
|
if (item.status != ITEM_INVISIBLE)
|
2020-12-21 13:16:29 -03:00
|
|
|
{
|
2021-01-16 18:38:16 +01:00
|
|
|
const auto height = item.pos.yPos - (item.triggerFlags & 0x1F) * CLICK(1);
|
2021-01-06 17:53:13 -03:00
|
|
|
return std::optional{height};
|
2020-12-21 13:16:29 -03:00
|
|
|
}
|
2021-01-06 17:53:13 -03:00
|
|
|
return std::nullopt;
|
2020-12-21 13:16:29 -03:00
|
|
|
}
|
|
|
|
|
2021-01-06 17:53:13 -03:00
|
|
|
std::optional<int> PushableBlockCeiling(short itemNumber, int x, int y, int z)
|
2020-12-21 13:16:29 -03:00
|
|
|
{
|
|
|
|
const auto& item = g_Level.Items[itemNumber];
|
2021-02-01 19:12:22 +01:00
|
|
|
if (item.status != ITEM_INVISIBLE)
|
2021-01-06 17:53:13 -03:00
|
|
|
return std::optional{item.pos.yPos};
|
|
|
|
return std::nullopt;
|
2020-12-21 13:16:29 -03:00
|
|
|
}
|
2021-01-27 01:04:31 -03:00
|
|
|
|
|
|
|
int PushableBlockFloorBorder(short itemNumber)
|
|
|
|
{
|
|
|
|
const auto& item = g_Level.Items[itemNumber];
|
|
|
|
const auto height = item.pos.yPos - (item.triggerFlags & 0x1F) * CLICK(1);
|
|
|
|
return height;
|
|
|
|
}
|
|
|
|
|
|
|
|
int PushableBlockCeilingBorder(short itemNumber)
|
|
|
|
{
|
|
|
|
const auto& item = g_Level.Items[itemNumber];
|
|
|
|
return item.pos.yPos;
|
|
|
|
}
|