TombEngine/TR5Main/Game/Lara/lara_climb.cpp

987 lines
21 KiB
C++
Raw Normal View History

#include "framework.h"
2020-08-09 22:09:14 -03:00
#include "lara_climb.h"
2019-12-01 08:13:19 +01:00
#include "Lara.h"
2021-09-19 23:41:26 +03:00
#include "control/control.h"
#include "animation.h"
2019-12-01 08:13:19 +01:00
#include "sphere.h"
#include "camera.h"
#include "level.h"
#include "input.h"
2021-09-25 16:00:30 +03:00
#include "items.h"
2021-09-25 11:27:47 +02:00
2021-08-20 02:01:50 +03:00
short GetClimbFlags(int x, int y, int z, short roomNumber)
2019-12-01 08:13:19 +01:00
{
2021-08-20 02:01:50 +03:00
return GetClimbFlags(GetFloor(x, y, z, &roomNumber));
}
2019-12-01 08:13:19 +01:00
2021-08-20 02:01:50 +03:00
short GetClimbFlags(FLOOR_INFO* floor)
{
short result = 0;
2019-12-01 08:13:19 +01:00
2021-08-20 02:01:50 +03:00
if (floor->Flags.ClimbEast)
result |= (short)CLIMB_DIRECTION::East;
if (floor->Flags.ClimbWest)
result |= (short)CLIMB_DIRECTION::West;
if (floor->Flags.ClimbNorth)
result |= (short)CLIMB_DIRECTION::North;
if (floor->Flags.ClimbSouth)
result |= (short)CLIMB_DIRECTION::South;
2019-12-01 08:13:19 +01:00
2021-08-20 02:01:50 +03:00
return result;
2019-12-01 08:13:19 +01:00
}
2021-02-03 01:50:59 -03:00
void lara_col_climbend(ITEM_INFO* item, COLL_INFO* coll)
{
return;
2019-12-01 08:13:19 +01:00
}
2021-02-03 01:50:59 -03:00
void lara_as_climbend(ITEM_INFO* item, COLL_INFO* coll)
2019-12-01 08:13:19 +01:00
{
2021-09-10 00:20:59 +03:00
coll->Setup.EnableObjectPush = false;
coll->Setup.EnableSpaz = false;
2019-12-01 08:13:19 +01:00
Camera.flags = CF_FOLLOW_CENTER;
Camera.targetAngle = -ANGLE(45);
2019-12-01 08:13:19 +01:00
}
2021-02-03 01:50:59 -03:00
void lara_col_climbdown(ITEM_INFO* item, COLL_INFO* coll)
2019-12-01 08:13:19 +01:00
{
if (LaraCheckForLetGo(item, coll)
|| item->animNumber != LA_LADDER_DOWN)
2019-12-01 08:13:19 +01:00
return;
int frame = item->frameNumber - g_Level.Anims[LA_LADDER_DOWN].frameBase;
2019-12-02 09:11:21 +01:00
int xShift;
int yShift;
2019-12-01 08:13:19 +01:00
switch (frame)
{
case 0:
yShift = 0;
break;
case 28:
case 29:
yShift = 256;
break;
case 57:
yShift = 512;
break;
default:
return;
}
item->pos.yPos += yShift + 256;
2019-12-02 09:11:21 +01:00
int shiftLeft = 0;
int shiftRight = 0;
2021-09-10 00:20:59 +03:00
int resultRight = LaraTestClimbPos(item, coll->Setup.Radius, coll->Setup.Radius + 120, -512, 512, &shiftRight);
int resultLeft = LaraTestClimbPos(item, coll->Setup.Radius, -(coll->Setup.Radius + 120), -512, 512, &shiftLeft);
2019-12-01 08:13:19 +01:00
item->pos.yPos -= 256;
if (resultRight != 0 && resultLeft != 0 &&
resultRight != -2 && resultLeft != -2 &&
TrInput & IN_BACK)
{
if (shiftRight && shiftLeft)
{
if (shiftRight < 0 != shiftLeft < 0)
{
item->goalAnimState = LS_LADDER_IDLE;
2019-12-01 08:13:19 +01:00
AnimateLara(item);
return;
}
if (shiftRight < 0 && shiftRight < shiftLeft ||
shiftRight > 0 && shiftRight > shiftLeft)
{
shiftLeft = shiftRight;
}
}
if (resultRight == -1 || resultLeft == -1)
{
2021-11-16 17:25:17 +03:00
SetAnimation(item, LA_LADDER_IDLE);
item->goalAnimState = LS_HANG;
2019-12-01 08:13:19 +01:00
AnimateLara(item);
}
else
{
item->goalAnimState = LS_LADDER_DOWN;
2019-12-01 08:13:19 +01:00
item->pos.yPos -= yShift;
}
return;
}
item->goalAnimState = LS_LADDER_IDLE;
2019-12-01 08:13:19 +01:00
if (yShift != 0)
AnimateLara(item);
}
2021-02-03 01:50:59 -03:00
void lara_as_climbdown(ITEM_INFO* item, COLL_INFO* coll)
2019-12-01 08:13:19 +01:00
{
2021-09-10 00:20:59 +03:00
coll->Setup.EnableObjectPush = false;
coll->Setup.EnableSpaz = false;
2019-12-01 08:13:19 +01:00
Camera.targetElevation = -ANGLE(45);
}
2021-02-03 01:50:59 -03:00
void lara_col_climbing(ITEM_INFO* item, COLL_INFO* coll)
2019-12-01 08:13:19 +01:00
{
if (!LaraCheckForLetGo(item, coll) && item->animNumber == LA_LADDER_UP)
2019-12-01 08:13:19 +01:00
{
int frame = item->frameNumber - g_Level.Anims[LA_LADDER_UP].frameBase;
2019-12-02 09:11:21 +01:00
int yShift;
int resultRight, resultLeft;
int shiftRight, shiftLeft;
int ledgeRight, ledgeLeft;
2019-12-01 08:13:19 +01:00
if (frame == 0)
{
yShift = 0;
}
else if (frame == 28 || frame == 29)
{
yShift = -256;
}
else if (frame == 57)
{
yShift = -512;
}
else
{
return;
}
item->pos.yPos += yShift - 256;
2021-09-10 00:20:59 +03:00
resultRight = LaraTestClimbUpPos(item, coll->Setup.Radius, coll->Setup.Radius + 120, &shiftRight, &ledgeRight);
resultLeft = LaraTestClimbUpPos(item, coll->Setup.Radius, -(coll->Setup.Radius + 120), &shiftLeft, &ledgeLeft);
2019-12-01 08:13:19 +01:00
2019-12-12 08:07:09 +01:00
item->pos.yPos += 256;
2019-12-01 08:13:19 +01:00
if (resultRight && resultLeft && TrInput & IN_FORWARD)
{
if (resultRight < 0 || resultLeft < 0)
{
item->goalAnimState = LS_LADDER_IDLE;
2019-12-01 08:13:19 +01:00
AnimateLara(item);
if (abs(ledgeRight - ledgeLeft) <= 120)
{
if (resultRight != -1 || resultLeft != -1)
{
2021-11-10 14:30:58 +03:00
item->goalAnimState = LS_LADDER_TO_CROUCH;
item->requiredAnimState = LS_CROUCH_IDLE;
2019-12-01 08:13:19 +01:00
}
else
{
item->goalAnimState = LS_GRABBING;
2019-12-01 08:13:19 +01:00
item->pos.yPos += (ledgeRight + ledgeLeft) / 2 - 256;
}
}
}
else
{
item->goalAnimState = LS_LADDER_UP;
2019-12-12 08:07:09 +01:00
item->pos.yPos -= yShift;
2019-12-01 08:13:19 +01:00
}
}
else
{
item->goalAnimState = LS_LADDER_IDLE;
2019-12-01 08:13:19 +01:00
if (yShift != 0)
AnimateLara(item);
}
}
}
2021-02-03 01:50:59 -03:00
void lara_as_climbing(ITEM_INFO* item, COLL_INFO* coll)
2019-12-01 08:13:19 +01:00
{
2021-09-10 00:20:59 +03:00
coll->Setup.EnableObjectPush = false;
coll->Setup.EnableSpaz = false;
Camera.targetElevation = ANGLE(30);
2019-12-01 08:13:19 +01:00
}
2021-02-03 01:50:59 -03:00
void lara_col_climbright(ITEM_INFO* item, COLL_INFO* coll)
2019-12-01 08:13:19 +01:00
{
if (!LaraCheckForLetGo(item, coll))
{
2019-12-02 09:11:21 +01:00
int shift = 0;
Lara.moveAngle = item->pos.yRot + ANGLE(90);
2021-09-10 00:20:59 +03:00
LaraDoClimbLeftRight(item, coll, LaraTestClimbPos(item, coll->Setup.Radius, coll->Setup.Radius + 120, -512, 512, &shift), shift);
2019-12-01 08:13:19 +01:00
}
}
2021-02-03 01:50:59 -03:00
void lara_as_climbright(ITEM_INFO* item, COLL_INFO* coll)
2019-12-01 08:13:19 +01:00
{
2021-09-10 00:20:59 +03:00
coll->Setup.EnableObjectPush = false;
coll->Setup.EnableSpaz = false;
2019-12-01 08:13:19 +01:00
Camera.targetAngle = ANGLE(30);
Camera.targetElevation = -ANGLE(15);
2019-12-01 08:13:19 +01:00
if (!(TrInput & (IN_RIGHT | IN_RSTEP)))
item->goalAnimState = LS_LADDER_IDLE;
2019-12-01 08:13:19 +01:00
}
2021-02-03 01:50:59 -03:00
void lara_col_climbleft(ITEM_INFO* item, COLL_INFO* coll)
2019-12-01 08:13:19 +01:00
{
if (!LaraCheckForLetGo(item, coll))
{
2019-12-02 09:11:21 +01:00
int shift = 0;
Lara.moveAngle = item->pos.yRot - ANGLE(90);
2021-09-10 00:20:59 +03:00
LaraDoClimbLeftRight(item, coll, LaraTestClimbPos(item, coll->Setup.Radius, -(coll->Setup.Radius + 120), -512, 512, &shift), shift);
2019-12-01 08:13:19 +01:00
}
}
2021-02-03 01:50:59 -03:00
void lara_as_climbleft(ITEM_INFO* item, COLL_INFO* coll)
2019-12-01 08:13:19 +01:00
{
2021-09-10 00:20:59 +03:00
coll->Setup.EnableObjectPush = false;
coll->Setup.EnableSpaz = false;
2019-12-01 08:13:19 +01:00
Camera.targetAngle = -ANGLE(30);
Camera.targetElevation = -ANGLE(15);
2019-12-01 08:13:19 +01:00
if (!(TrInput & (IN_LEFT | IN_LSTEP)))
item->goalAnimState = LS_LADDER_IDLE;
2019-12-01 08:13:19 +01:00
}
2021-02-03 01:50:59 -03:00
void lara_col_climbstnc(ITEM_INFO* item, COLL_INFO* coll)
2019-12-01 08:13:19 +01:00
{
2019-12-02 09:11:21 +01:00
int yShift;
int resultRight, resultLeft;
int shiftRight, shiftLeft;
int ledgeRight, ledgeLeft;
2019-12-01 08:13:19 +01:00
if (LaraCheckForLetGo(item, coll) || item->animNumber != LA_LADDER_IDLE)
2019-12-01 08:13:19 +01:00
return;
if (!(TrInput & IN_FORWARD))
{
if (!(TrInput & IN_BACK))
return;
if (item->goalAnimState == LS_HANG)
2019-12-01 08:13:19 +01:00
return;
item->goalAnimState = LS_LADDER_IDLE;
2019-12-01 08:13:19 +01:00
item->pos.yPos += 256;
2021-09-10 00:20:59 +03:00
resultRight = LaraTestClimbPos(item, coll->Setup.Radius, coll->Setup.Radius + 120, -512, 512, &ledgeRight);
resultLeft = LaraTestClimbPos(item, coll->Setup.Radius, -120 - coll->Setup.Radius, -512, 512, &ledgeLeft);
2019-12-01 08:13:19 +01:00
item->pos.yPos -= 256;
if (!resultRight || !resultLeft || resultLeft == -2 || resultRight == -2)
return;
yShift = ledgeLeft;
if (ledgeRight && ledgeLeft)
2019-12-01 08:13:19 +01:00
{
if (ledgeLeft < 0 != ledgeRight < 0)
return;
if (ledgeRight < 0 == ledgeRight < ledgeLeft)
yShift = ledgeRight;
2019-12-01 08:13:19 +01:00
}
if (resultRight == 1 && resultLeft == 1)
2019-12-01 08:13:19 +01:00
{
item->goalAnimState = LS_LADDER_DOWN;
item->pos.yPos += yShift;
2019-12-01 08:13:19 +01:00
}
else
2019-12-01 08:13:19 +01:00
{
item->goalAnimState = LS_HANG;
2019-12-01 08:13:19 +01:00
}
}
else if (item->goalAnimState != LS_GRABBING)
2019-12-01 08:13:19 +01:00
{
item->goalAnimState = LS_LADDER_IDLE;
2021-09-10 00:20:59 +03:00
resultRight = LaraTestClimbUpPos(item, coll->Setup.Radius, coll->Setup.Radius + 120, &shiftRight, &ledgeRight);
resultLeft = LaraTestClimbUpPos(item, coll->Setup.Radius, -120 - coll->Setup.Radius, &shiftLeft, &ledgeLeft);
if (!resultRight || !resultLeft)
return;
if (resultRight >= 0 && resultLeft >= 0)
2019-12-01 08:13:19 +01:00
{
yShift = shiftLeft;
if (shiftRight)
2019-12-01 08:13:19 +01:00
{
if (shiftLeft)
2019-12-01 08:13:19 +01:00
{
if (shiftLeft < 0 != shiftRight < 0)
return;
if (shiftRight < 0 == shiftRight < shiftLeft)
yShift = shiftRight;
2019-12-01 08:13:19 +01:00
}
else
{
yShift = shiftRight;
2019-12-01 08:13:19 +01:00
}
}
item->goalAnimState = LS_LADDER_UP;
item->pos.yPos += yShift;
}
else if (abs(ledgeLeft - ledgeRight) <= 120)
{
if (resultRight == -1 && resultLeft == -1)
{
item->goalAnimState = LS_GRABBING;
item->pos.yPos += (ledgeRight + ledgeLeft) / 2 - 256;
}
else
{
2021-11-10 14:30:58 +03:00
item->goalAnimState = LS_LADDER_TO_CROUCH;
item->requiredAnimState = LS_CROUCH_IDLE;
}
2019-12-01 08:13:19 +01:00
}
}
}
2019-12-01 08:13:19 +01:00
2021-02-03 01:50:59 -03:00
void lara_as_climbstnc(ITEM_INFO* item, COLL_INFO* coll)
2019-12-01 08:13:19 +01:00
{
Lara.isClimbing = true;
2021-09-10 00:20:59 +03:00
coll->Setup.EnableSpaz = false;
coll->Setup.EnableObjectPush = false;
2019-12-01 08:13:19 +01:00
Camera.targetElevation = -ANGLE(20);
2019-12-01 08:13:19 +01:00
if (item->animNumber == LA_LADDER_DISMOUNT_LEFT_START)
Camera.targetAngle = -ANGLE(60.0f);
if (item->animNumber == LA_LADDER_DISMOUNT_RIGHT_START)
Camera.targetAngle = ANGLE(60.0f);
2019-12-01 08:13:19 +01:00
if (TrInput & IN_LOOK)
{
LookUpDown();
}
if (TrInput & IN_LEFT || TrInput & IN_LSTEP)
{
item->goalAnimState = LS_LADDER_LEFT;
Lara.moveAngle = item->pos.yRot - ANGLE(90);
2019-12-01 08:13:19 +01:00
}
else if (TrInput & IN_RIGHT || TrInput & IN_RSTEP)
{
item->goalAnimState = LS_LADDER_RIGHT;
Lara.moveAngle = item->pos.yRot + ANGLE(90);
2019-12-01 08:13:19 +01:00
}
else if (TrInput & IN_JUMP)
{
if (item->animNumber == LA_LADDER_IDLE)
2019-12-01 08:13:19 +01:00
{
item->goalAnimState = LS_JUMP_BACK;
2019-12-01 08:13:19 +01:00
Lara.gunStatus = LG_NO_ARMS;
Lara.moveAngle = item->pos.yRot + ANGLE(180);
2019-12-01 08:13:19 +01:00
}
}
}
void lara_as_stepoff_left(ITEM_INFO* item, COLL_INFO* coll)
{
2021-09-10 00:20:59 +03:00
coll->Setup.EnableObjectPush = false;
coll->Setup.EnableSpaz = false;
Camera.targetAngle = -ANGLE(60.0f);
Camera.targetElevation = -ANGLE(15.0f);
item->pos.yRot -= ANGLE(90.0f);
}
void lara_as_stepoff_right(ITEM_INFO* item, COLL_INFO* coll)
{
2021-09-10 00:20:59 +03:00
coll->Setup.EnableObjectPush = false;
coll->Setup.EnableSpaz = false;
Camera.targetAngle = ANGLE(60.0f);
Camera.targetElevation = -ANGLE(15.0f);
item->pos.yRot += ANGLE(90.0f);
}
2021-02-03 01:50:59 -03:00
int LaraTestClimbPos(ITEM_INFO* item, int front, int right, int origin, int height, int* shift)
2019-12-01 08:13:19 +01:00
{
int x;
int z;
int xFront = 0;
int zFront = 0;
2019-12-01 08:13:19 +01:00
switch (GetQuadrant(item->pos.yRot))
2019-12-01 08:13:19 +01:00
{
case NORTH:
x = item->pos.xPos + right;
z = item->pos.zPos + front;
zFront = 256;
2019-12-01 08:13:19 +01:00
break;
case EAST:
x = item->pos.xPos + front;
z = item->pos.zPos - right;
xFront = 256;
2019-12-01 08:13:19 +01:00
break;
case SOUTH:
x = item->pos.xPos - right;
z = item->pos.zPos - front;
zFront = -256;
2019-12-01 08:13:19 +01:00
break;
case WEST:
default:
x = item->pos.xPos - front;
z = item->pos.zPos + right;
xFront = -256;
2019-12-01 08:13:19 +01:00
break;
}
return LaraTestClimb(x, item->pos.yPos + origin, z, xFront, zFront, height, item->roomNumber, shift);
2019-12-01 08:13:19 +01:00
}
2021-02-03 01:50:59 -03:00
void LaraDoClimbLeftRight(ITEM_INFO* item, COLL_INFO* coll, int result, int shift)
2019-12-01 08:13:19 +01:00
{
if (result == 1)
{
if (TrInput & IN_LEFT)
{
item->goalAnimState = LS_LADDER_LEFT;
2019-12-01 08:13:19 +01:00
}
else if (TrInput & IN_RIGHT)
{
item->goalAnimState = LS_LADDER_RIGHT;
2019-12-01 08:13:19 +01:00
}
else
{
item->goalAnimState = LS_LADDER_IDLE;
2019-12-01 08:13:19 +01:00
}
item->pos.yPos += shift;
return;
}
if (result != 0)
{
item->goalAnimState = LS_HANG;
2019-12-01 08:13:19 +01:00
do
{
AnimateItem(item);
} while (item->currentAnimState != LS_HANG);
2019-12-01 08:13:19 +01:00
2021-09-10 00:20:59 +03:00
item->pos.xPos = coll->Setup.OldPosition.x;
item->pos.zPos = coll->Setup.OldPosition.z;
2019-12-01 08:13:19 +01:00
return;
}
2021-09-10 00:20:59 +03:00
item->pos.xPos = coll->Setup.OldPosition.x;
item->pos.zPos = coll->Setup.OldPosition.z;
2019-12-01 08:13:19 +01:00
item->goalAnimState = LS_LADDER_IDLE;
item->currentAnimState = LS_LADDER_IDLE;
2019-12-01 08:13:19 +01:00
2021-09-10 00:20:59 +03:00
if (coll->Setup.OldAnimState != LS_LADDER_IDLE)
{
2021-11-16 17:25:17 +03:00
SetAnimation(item, LA_LADDER_IDLE);
2019-12-01 08:13:19 +01:00
return;
}
if (TrInput & IN_LEFT)
{
short troomnumber = item->roomNumber;
int dx = int(sin(TO_RAD(item->pos.yRot - ANGLE(90.0f))) * 10);
int dz = int(cos(TO_RAD(item->pos.yRot - ANGLE(90.0f))) * 10);
int height = GetFloorHeight(GetFloor(item->pos.xPos + dx, item->pos.yPos, item->pos.zPos + dz, &troomnumber),
item->pos.xPos, item->pos.yPos, item->pos.zPos) - item->pos.yPos;
if (height < 3 * STEP_SIZE / 2) // LADDER dismounts (left/right)
{
item->goalAnimState = LS_LADDER_DISMOUNT_LEFT;
item->currentAnimState = LS_MISC_CONTROL;
}
}
else if (TrInput & IN_RIGHT)
{
short troomnumber = item->roomNumber;
int dx = int(sin(TO_RAD(item->pos.yRot + ANGLE(90.0f))) * 10);
int dz = int(cos(TO_RAD(item->pos.yRot + ANGLE(90.0f))) * 10);
int height = GetFloorHeight(GetFloor(item->pos.xPos + dx, item->pos.yPos, item->pos.zPos + dz, &troomnumber),
item->pos.xPos, item->pos.yPos, item->pos.zPos) - item->pos.yPos;
if (height < 3 * STEP_SIZE / 2) // LADDER dismounts (left/right)
{
item->goalAnimState = LS_LADDER_DISMOUNT_RIGHT;
item->currentAnimState = LS_MISC_CONTROL;
}
}
2019-12-01 08:13:19 +01:00
if (TrInput & IN_LEFT)
{
2019-12-02 09:11:21 +01:00
int flag = LaraClimbLeftCornerTest(item, coll);
2019-12-01 08:13:19 +01:00
if (flag)
{
if (flag <= 0)
2021-11-16 17:25:17 +03:00
SetAnimation(item, LA_LADDER_LEFT_CORNER_INNER_START);
2019-12-01 08:13:19 +01:00
else
2021-11-16 17:25:17 +03:00
SetAnimation(item, LA_LADDER_LEFT_CORNER_OUTER_START);
2019-12-01 08:13:19 +01:00
return;
}
}
else if (TrInput & IN_RIGHT)
{
2019-12-02 09:11:21 +01:00
int flag = LaraClimbRightCornerTest(item, coll);
2019-12-01 08:13:19 +01:00
if (flag)
{
if (flag <= 0)
2021-11-16 17:25:17 +03:00
SetAnimation(item, LA_LADDER_RIGHT_CORNER_INNER_START);
2019-12-01 08:13:19 +01:00
else
2021-11-16 17:25:17 +03:00
SetAnimation(item, LA_LADDER_RIGHT_CORNER_OUTER_START);
2019-12-01 08:13:19 +01:00
return;
}
}
2021-09-10 00:20:59 +03:00
item->animNumber = coll->Setup.OldAnimNumber;
item->frameNumber = coll->Setup.OldFrameNumber;
2019-12-01 08:13:19 +01:00
AnimateLara(item);
}
2021-02-03 01:50:59 -03:00
int LaraClimbRightCornerTest(ITEM_INFO* item, COLL_INFO* coll)
2019-12-01 08:13:19 +01:00
{
2019-12-02 09:11:21 +01:00
int result = 0;
2019-12-01 08:13:19 +01:00
if (item->animNumber != LA_LADDER_RIGHT)
2019-12-01 08:13:19 +01:00
return 0;
2019-12-02 09:11:21 +01:00
int oldYrot = item->pos.yRot;
int oldX = item->pos.xPos;
int oldY = item->pos.yPos;
int oldZ = item->pos.zPos;
2019-12-01 08:13:19 +01:00
short angle = GetQuadrant(item->pos.yRot);
2019-12-02 09:11:21 +01:00
int x, z;
2019-12-01 08:13:19 +01:00
if (angle && angle != SOUTH)
{
x = (item->pos.xPos & 0xFFFFFC00) - (item->pos.zPos % 1024) + 1024;
z = (item->pos.zPos & 0xFFFFFC00) - (item->pos.xPos % 1024) + 1024;
2019-12-01 08:13:19 +01:00
}
else
{
x = item->pos.xPos ^ (item->pos.xPos ^ item->pos.zPos) & 0x3FF;
z = item->pos.zPos ^ (item->pos.xPos ^ item->pos.zPos) & 0x3FF;
}
2019-12-02 09:11:21 +01:00
int shift = 0;
2019-12-01 08:13:19 +01:00
2021-08-20 02:01:50 +03:00
if (GetClimbFlags(x, item->pos.yPos, z, item->roomNumber) & (short)LeftExtRightIntTab[angle])
{
item->pos.xPos = x;
item->pos.zPos = z;
Lara.nextCornerPos.x = x;
Lara.nextCornerPos.y = item->pos.yPos;
Lara.nextCornerPos.z = z;
item->pos.yRot += ANGLE(90);
Lara.moveAngle = item->pos.yRot;
2021-09-10 00:20:59 +03:00
result = LaraTestClimbPos(item, coll->Setup.Radius, coll->Setup.Radius + 120, -512, 512, &shift);
}
if (!result)
2019-12-01 08:13:19 +01:00
{
item->pos.xPos = oldX;
Lara.moveAngle = oldYrot;
item->pos.yRot = oldYrot;
2019-12-01 08:13:19 +01:00
item->pos.zPos = oldZ;
2019-12-02 09:11:21 +01:00
int newX, newZ;
2019-12-01 08:13:19 +01:00
switch (angle)
{
case NORTH:
2019-12-13 23:30:25 -03:00
newX = ((item->pos.xPos + 1024) & 0xFFFFFC00) - (item->pos.zPos % 1024) + 1024;
newZ = ((item->pos.zPos + 1024) & 0xFFFFFC00) - (item->pos.xPos % 1024) + 1024;
2019-12-01 08:13:19 +01:00
break;
case SOUTH:
2019-12-13 23:30:25 -03:00
newX = ((item->pos.xPos - 1024) & 0xFFFFFC00) - (item->pos.zPos % 1024) + 1024;
newZ = ((item->pos.zPos - 1024) & 0xFFFFFC00) - (item->pos.xPos % 1024) + 1024;
2019-12-01 08:13:19 +01:00
break;
case EAST:
2019-12-13 23:30:25 -03:00
newX = ((item->pos.zPos ^ item->pos.xPos) % 1024) ^ (item->pos.xPos + 1024);
newZ = (item->pos.zPos ^ ((item->pos.zPos ^ item->pos.xPos) % 1024)) - 1024;
2019-12-01 08:13:19 +01:00
break;
case WEST:
default:
2019-12-13 23:30:25 -03:00
newX = (item->pos.xPos ^ (item->pos.zPos ^ item->pos.xPos) % 1024) - 1024;
newZ = ((item->pos.zPos ^ item->pos.xPos) % 1024) ^ (item->pos.zPos + 1024);
2019-12-01 08:13:19 +01:00
break;
}
2021-08-20 02:01:50 +03:00
if (GetClimbFlags(newX, item->pos.yPos, newZ, item->roomNumber) & (short)LeftIntRightExtTab[angle])
2019-12-01 08:13:19 +01:00
{
item->pos.xPos = newX;
item->pos.zPos = newZ;
Lara.nextCornerPos.x = newX;
Lara.nextCornerPos.y = item->pos.yPos;
Lara.nextCornerPos.z = newZ;
item->pos.yRot -= ANGLE(90);
Lara.moveAngle = item->pos.yRot;
2021-09-10 00:20:59 +03:00
result = LaraTestClimbPos(item, coll->Setup.Radius, coll->Setup.Radius + 120, -512, 512, &shift) != 0;
2019-12-01 08:13:19 +01:00
}
}
else
{
result = -1;
}
item->pos.xPos = oldX;
2019-12-13 23:30:25 -03:00
item->pos.yRot = oldYrot;
2019-12-01 08:13:19 +01:00
item->pos.zPos = oldZ;
Lara.moveAngle = oldYrot;
2019-12-01 08:13:19 +01:00
return result;
}
2021-02-03 01:50:59 -03:00
int LaraClimbLeftCornerTest(ITEM_INFO* item, COLL_INFO* coll)
2019-12-01 08:13:19 +01:00
{
2019-12-02 09:11:21 +01:00
int result = 0;
2019-12-01 08:13:19 +01:00
if (item->animNumber != LA_LADDER_LEFT)
2019-12-01 08:13:19 +01:00
return 0;
2019-12-02 09:11:21 +01:00
int oldYrot = item->pos.yRot;
int oldX = item->pos.xPos;
int oldY = item->pos.yPos;
int oldZ = item->pos.zPos;
2019-12-01 08:13:19 +01:00
short angle = GetQuadrant(item->pos.yRot);
2019-12-02 09:11:21 +01:00
int x, z;
2019-12-01 08:13:19 +01:00
if (angle && angle != SOUTH)
{
x = item->pos.xPos ^ (item->pos.xPos ^ item->pos.zPos) & 0x3FF;
z = item->pos.zPos ^ (item->pos.xPos ^ item->pos.zPos) & 0x3FF;
}
else
{
x = (item->pos.xPos & 0xFFFFFC00) - (item->pos.zPos & 0x3FF) + 1024;
z = (item->pos.zPos & 0xFFFFFC00) - (item->pos.xPos & 0x3FF) + 1024;
}
2019-12-02 09:11:21 +01:00
int shift = 0;
2019-12-01 08:13:19 +01:00
2021-08-20 02:01:50 +03:00
if (GetClimbFlags(x, item->pos.yPos, z, item->roomNumber) & (short)LeftIntRightExtTab[angle])
2019-12-13 23:30:25 -03:00
{
item->pos.xPos = x;
item->pos.zPos = z;
Lara.nextCornerPos.x = x;
Lara.nextCornerPos.y = item->pos.yPos;
Lara.nextCornerPos.z = z;
item->pos.yRot -= ANGLE(90);
Lara.moveAngle = item->pos.yRot;
2019-12-13 23:30:25 -03:00
2021-09-10 00:20:59 +03:00
result = LaraTestClimbPos(item, coll->Setup.Radius, -coll->Setup.Radius - 120, -512, 512, &shift);
2019-12-13 23:30:25 -03:00
item->itemFlags[3] = result;
}
if (!result)
2019-12-01 08:13:19 +01:00
{
item->pos.xPos = oldX;
Lara.moveAngle = oldYrot;
2019-12-13 23:30:25 -03:00
item->pos.yRot = oldYrot;
2019-12-01 08:13:19 +01:00
item->pos.zPos = oldZ;
2019-12-02 09:11:21 +01:00
int newX, newZ;
2019-12-01 08:13:19 +01:00
switch (angle)
{
case NORTH:
2019-12-13 23:30:25 -03:00
newX = (item->pos.xPos ^ ((item->pos.zPos ^ item->pos.xPos) & 0x3FF)) - 1024;
newZ = ((item->pos.zPos ^ item->pos.xPos) & 0x3FF) ^ (item->pos.zPos + 1024);
2019-12-01 08:13:19 +01:00
break;
case SOUTH:
2019-12-13 23:30:25 -03:00
newX = ((item->pos.zPos ^ item->pos.xPos) & 0x3FF) ^ (item->pos.xPos + 1024);
newZ = ((item->pos.zPos ^ item->pos.xPos) & 0x3FF) ^ (item->pos.zPos - 1024);
2019-12-01 08:13:19 +01:00
break;
case EAST:
2019-12-13 23:30:25 -03:00
newX = ((item->pos.xPos + 1024) & 0xFFFFFC00) - (item->pos.zPos & 0x3FF) + 1024;
newZ = ((item->pos.zPos + 1024) & 0xFFFFFC00) - (item->pos.xPos & 0x3FF) + 1024;
2019-12-01 08:13:19 +01:00
break;
case WEST:
default:
2019-12-13 23:30:25 -03:00
newX = (item->pos.xPos & 0xFFFFFC00) - (item->pos.zPos & 0x3FF);
newZ = (item->pos.zPos & 0xFFFFFC00) - (item->pos.xPos & 0x3FF);
2019-12-01 08:13:19 +01:00
break;
}
2021-08-20 02:01:50 +03:00
if (GetClimbFlags(newX, item->pos.yPos, newZ, item->roomNumber) & (short)LeftExtRightIntTab[angle])
2019-12-01 08:13:19 +01:00
{
item->pos.xPos = Lara.nextCornerPos.x = newX;
item->pos.yPos = Lara.nextCornerPos.y = item->pos.yPos;
item->pos.zPos = Lara.nextCornerPos.z = newZ;
item->pos.yRot += ANGLE(90);
Lara.moveAngle = item->pos.yRot;
2021-09-10 00:20:59 +03:00
item->itemFlags[3] = LaraTestClimbPos(item, coll->Setup.Radius, -coll->Setup.Radius - 120, -512, 512, &shift);
2019-12-01 08:13:19 +01:00
result = item->itemFlags[3] != 0;
}
}
else
{
result = -1;
}
item->pos.xPos = oldX;
2019-12-13 23:30:25 -03:00
item->pos.yRot = oldYrot;
2019-12-01 08:13:19 +01:00
item->pos.zPos = oldZ;
Lara.moveAngle = oldYrot;
2019-12-01 08:13:19 +01:00
return result;
}
2021-02-03 01:50:59 -03:00
int LaraTestClimb(int x, int y, int z, int xFront, int zFront, int itemHeight, int itemRoom, int* shift)
2019-12-01 08:13:19 +01:00
{
*shift = 0;
2019-12-02 09:11:21 +01:00
int hang = 1;
2019-12-01 08:13:19 +01:00
if (!Lara.climbStatus)
return 0;
2019-12-02 09:11:21 +01:00
short roomNumber = itemRoom;
2019-12-01 08:13:19 +01:00
FLOOR_INFO* floor = GetFloor(x, y - 128, z, &roomNumber);
2019-12-02 09:11:21 +01:00
int height = GetFloorHeight(floor, x, y, z);
2019-12-01 08:13:19 +01:00
if (height == NO_HEIGHT)
return 0;
height -= (128 + y + itemHeight);
if (height < -70)
return 0;
if (height < 0)
*shift = height;
2019-12-02 09:11:21 +01:00
int ceiling = GetCeiling(floor, x, y, z) - y;
2019-12-01 08:13:19 +01:00
if (ceiling > 70)
return 0;
if (ceiling > 0)
{
if (*shift)
return 0;
*shift = ceiling;
}
if (itemHeight + height < 900)
hang = 0;
2019-12-02 09:11:21 +01:00
int dz = zFront + z;
int dx = xFront + x;
2019-12-01 08:13:19 +01:00
floor = GetFloor(dx, y, dz, &roomNumber);
height = GetFloorHeight(floor, dx, y, dz);
if (height != NO_HEIGHT)
{
height -= y;
}
if (height <= 70)
{
if (height > 0)
{
if (*shift < 0)
return 0;
if (height > *shift)
*shift = height;
}
roomNumber = itemRoom;
GetFloor(x, y + itemHeight, z, &roomNumber);
FLOOR_INFO* floor2 = GetFloor(dx, y + itemHeight, dz, &roomNumber);
ceiling = GetCeiling(floor2, dx, y + itemHeight, dz);
if (ceiling == NO_HEIGHT)
return 1;
if (ceiling - y <= height)
return 1;
if (ceiling - y >= 512)
return 1;
if (ceiling - y <= 442)
return -(hang != 0);
if (*shift > 0)
return -(hang != 0);
*shift = ceiling - y - 512;
return 1;
}
ceiling = GetCeiling(floor, dx, y, dz) - y;
if (ceiling >= 512)
return 1;
if (ceiling > 442)
{
if (*shift > 0)
return -(hang != 0);
*shift = ceiling - 512;
return 1;
}
if (ceiling > 0)
return -(hang != 0);
if (ceiling <= -70 || !hang || *shift > 0)
return 0;
if (*shift > ceiling)
*shift = ceiling;
return -1;
}
2021-02-03 01:50:59 -03:00
int LaraTestClimbUpPos(ITEM_INFO* item, int front, int right, int* shift, int* ledge)
2019-12-01 08:13:19 +01:00
{
2019-12-02 09:11:21 +01:00
int y = item->pos.yPos - 768;
2019-12-01 08:13:19 +01:00
2019-12-02 09:11:21 +01:00
int x, z;
int xFront = 0;
int zFront = 0;
2019-12-01 08:13:19 +01:00
switch (GetQuadrant(item->pos.yRot))
2019-12-01 08:13:19 +01:00
{
case NORTH:
x = item->pos.xPos + right;
z = item->pos.zPos + front;
zFront = 4;
break;
case EAST:
x = item->pos.xPos + front;
z = item->pos.zPos - right;
xFront = 4;
break;
case SOUTH:
x = item->pos.xPos - right;
z = item->pos.zPos - front;
zFront = -4;
break;
default:
x = item->pos.xPos - front;
z = item->pos.zPos + right;
xFront = -4;
break;
}
*shift = 0;
2019-12-02 09:11:21 +01:00
short roomNumber = item->roomNumber;
2019-12-01 08:13:19 +01:00
FLOOR_INFO* floor = GetFloor(x, y, z, &roomNumber);
2019-12-02 09:11:21 +01:00
int ceiling = 256 - y + GetCeiling(floor, x, y, z);
2019-12-01 08:13:19 +01:00
if (ceiling > 70)
return 0;
if (ceiling > 0)
*shift = ceiling;
floor = GetFloor(x + xFront, y, z + zFront, &roomNumber);
2019-12-02 09:11:21 +01:00
int height = GetFloorHeight(floor, x + xFront, y, z + zFront);
2019-12-01 08:13:19 +01:00
if (height == NO_HEIGHT)
{
*ledge = NO_HEIGHT;
return 1;
}
else
{
height -= y;
*ledge = height;
if (height <= 128)
{
if (height > 0 && height > *shift)
*shift = height;
roomNumber = item->roomNumber;
GetFloor(x, y + 512, z, &roomNumber);
floor = GetFloor(x + xFront, y + 512, z + zFront, &roomNumber);
ceiling = GetCeiling(floor, x + xFront, y + 512, z + zFront) - y;
if (ceiling <= height)
return 1;
if (ceiling >= 512)
return 1;
else
return 0;
}
else
{
ceiling = GetCeiling(floor, x + xFront, y, z + zFront) - y;
if (ceiling < 512)
{
if (height - ceiling <= LARA_HEIGHT)
2019-12-01 08:13:19 +01:00
{
if (height - ceiling < 512)
return 0;
*shift = height;
return -2;
}
else
{
*shift = height;
return -1;
}
}
else
{
return 1;
}
}
}
return -2;
}
2021-02-03 01:50:59 -03:00
int LaraCheckForLetGo(ITEM_INFO* item, COLL_INFO* coll)
{
short roomNumber = item->roomNumber;
item->gravityStatus = false;
item->fallspeed = 0;
if (TrInput & IN_ACTION && item->hitPoints > 0 || item->animNumber == LA_ONWATER_TO_LADDER)//can't let go on this anim
return 0;
Lara.torsoYrot = 0;
Lara.torsoXrot = 0;
Lara.headYrot = 0;
Lara.headXrot = 0;
2021-11-16 17:25:17 +03:00
SetAnimation(item, LA_FALL_START);
item->speed = 2;
item->gravityStatus = true;
item->fallspeed = 1;
Lara.gunStatus = LG_NO_ARMS;
return 1;
}