mirror of
https://github.com/TombEngine/TombEngine.git
synced 2025-05-03 02:07:59 +03:00
986 lines
21 KiB
C++
986 lines
21 KiB
C++
#include "framework.h"
|
|
#include "lara_climb.h"
|
|
#include "Lara.h"
|
|
#include "control/control.h"
|
|
#include "animation.h"
|
|
#include "sphere.h"
|
|
#include "camera.h"
|
|
#include "level.h"
|
|
#include "input.h"
|
|
#include "items.h"
|
|
|
|
short GetClimbFlags(int x, int y, int z, short roomNumber)
|
|
{
|
|
return GetClimbFlags(GetFloor(x, y, z, &roomNumber));
|
|
}
|
|
|
|
short GetClimbFlags(FLOOR_INFO* floor)
|
|
{
|
|
short result = 0;
|
|
|
|
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;
|
|
|
|
return result;
|
|
}
|
|
|
|
void lara_col_climbend(ITEM_INFO* item, COLL_INFO* coll)
|
|
{
|
|
return;
|
|
}
|
|
|
|
void lara_as_climbend(ITEM_INFO* item, COLL_INFO* coll)
|
|
{
|
|
coll->Setup.EnableObjectPush = false;
|
|
coll->Setup.EnableSpaz = false;
|
|
|
|
Camera.flags = CF_FOLLOW_CENTER;
|
|
Camera.targetAngle = -ANGLE(45);
|
|
}
|
|
|
|
void lara_col_climbdown(ITEM_INFO* item, COLL_INFO* coll)
|
|
{
|
|
if (LaraCheckForLetGo(item, coll)
|
|
|| item->animNumber != LA_LADDER_DOWN)
|
|
return;
|
|
|
|
int frame = item->frameNumber - g_Level.Anims[LA_LADDER_DOWN].frameBase;
|
|
int xShift;
|
|
int yShift;
|
|
|
|
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;
|
|
|
|
int shiftLeft = 0;
|
|
int shiftRight = 0;
|
|
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);
|
|
|
|
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;
|
|
AnimateLara(item);
|
|
return;
|
|
}
|
|
|
|
if (shiftRight < 0 && shiftRight < shiftLeft ||
|
|
shiftRight > 0 && shiftRight > shiftLeft)
|
|
{
|
|
shiftLeft = shiftRight;
|
|
}
|
|
}
|
|
|
|
if (resultRight == -1 || resultLeft == -1)
|
|
{
|
|
SetAnimation(item, LA_LADDER_IDLE);
|
|
item->goalAnimState = LS_HANG;
|
|
|
|
AnimateLara(item);
|
|
}
|
|
else
|
|
{
|
|
item->goalAnimState = LS_LADDER_DOWN;
|
|
item->pos.yPos -= yShift;
|
|
}
|
|
return;
|
|
}
|
|
|
|
item->goalAnimState = LS_LADDER_IDLE;
|
|
|
|
if (yShift != 0)
|
|
AnimateLara(item);
|
|
}
|
|
|
|
void lara_as_climbdown(ITEM_INFO* item, COLL_INFO* coll)
|
|
{
|
|
coll->Setup.EnableObjectPush = false;
|
|
coll->Setup.EnableSpaz = false;
|
|
|
|
Camera.targetElevation = -ANGLE(45);
|
|
}
|
|
|
|
void lara_col_climbing(ITEM_INFO* item, COLL_INFO* coll)
|
|
{
|
|
if (!LaraCheckForLetGo(item, coll) && item->animNumber == LA_LADDER_UP)
|
|
{
|
|
int frame = item->frameNumber - g_Level.Anims[LA_LADDER_UP].frameBase;
|
|
int yShift;
|
|
int resultRight, resultLeft;
|
|
int shiftRight, shiftLeft;
|
|
int ledgeRight, ledgeLeft;
|
|
|
|
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;
|
|
|
|
resultRight = LaraTestClimbUpPos(item, coll->Setup.Radius, coll->Setup.Radius + 120, &shiftRight, &ledgeRight);
|
|
resultLeft = LaraTestClimbUpPos(item, coll->Setup.Radius, -(coll->Setup.Radius + 120), &shiftLeft, &ledgeLeft);
|
|
|
|
item->pos.yPos += 256;
|
|
|
|
if (resultRight && resultLeft && TrInput & IN_FORWARD)
|
|
{
|
|
if (resultRight < 0 || resultLeft < 0)
|
|
{
|
|
item->goalAnimState = LS_LADDER_IDLE;
|
|
|
|
AnimateLara(item);
|
|
|
|
if (abs(ledgeRight - ledgeLeft) <= 120)
|
|
{
|
|
if (resultRight != -1 || resultLeft != -1)
|
|
{
|
|
item->goalAnimState = LS_LADDER_TO_CROUCH;
|
|
item->requiredAnimState = LS_CROUCH_IDLE;
|
|
}
|
|
else
|
|
{
|
|
item->goalAnimState = LS_GRABBING;
|
|
item->pos.yPos += (ledgeRight + ledgeLeft) / 2 - 256;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
item->goalAnimState = LS_LADDER_UP;
|
|
item->pos.yPos -= yShift;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
item->goalAnimState = LS_LADDER_IDLE;
|
|
|
|
if (yShift != 0)
|
|
AnimateLara(item);
|
|
}
|
|
}
|
|
}
|
|
|
|
void lara_as_climbing(ITEM_INFO* item, COLL_INFO* coll)
|
|
{
|
|
coll->Setup.EnableObjectPush = false;
|
|
coll->Setup.EnableSpaz = false;
|
|
|
|
Camera.targetElevation = ANGLE(30);
|
|
}
|
|
|
|
void lara_col_climbright(ITEM_INFO* item, COLL_INFO* coll)
|
|
{
|
|
if (!LaraCheckForLetGo(item, coll))
|
|
{
|
|
int shift = 0;
|
|
Lara.moveAngle = item->pos.yRot + ANGLE(90);
|
|
LaraDoClimbLeftRight(item, coll, LaraTestClimbPos(item, coll->Setup.Radius, coll->Setup.Radius + 120, -512, 512, &shift), shift);
|
|
}
|
|
}
|
|
|
|
void lara_as_climbright(ITEM_INFO* item, COLL_INFO* coll)
|
|
{
|
|
coll->Setup.EnableObjectPush = false;
|
|
coll->Setup.EnableSpaz = false;
|
|
|
|
Camera.targetAngle = ANGLE(30);
|
|
Camera.targetElevation = -ANGLE(15);
|
|
|
|
if (!(TrInput & (IN_RIGHT | IN_RSTEP)))
|
|
item->goalAnimState = LS_LADDER_IDLE;
|
|
}
|
|
|
|
void lara_col_climbleft(ITEM_INFO* item, COLL_INFO* coll)
|
|
{
|
|
if (!LaraCheckForLetGo(item, coll))
|
|
{
|
|
int shift = 0;
|
|
Lara.moveAngle = item->pos.yRot - ANGLE(90);
|
|
LaraDoClimbLeftRight(item, coll, LaraTestClimbPos(item, coll->Setup.Radius, -(coll->Setup.Radius + 120), -512, 512, &shift), shift);
|
|
}
|
|
}
|
|
|
|
void lara_as_climbleft(ITEM_INFO* item, COLL_INFO* coll)
|
|
{
|
|
coll->Setup.EnableObjectPush = false;
|
|
coll->Setup.EnableSpaz = false;
|
|
|
|
Camera.targetAngle = -ANGLE(30);
|
|
Camera.targetElevation = -ANGLE(15);
|
|
|
|
if (!(TrInput & (IN_LEFT | IN_LSTEP)))
|
|
item->goalAnimState = LS_LADDER_IDLE;
|
|
}
|
|
|
|
void lara_col_climbstnc(ITEM_INFO* item, COLL_INFO* coll)
|
|
{
|
|
int yShift;
|
|
int resultRight, resultLeft;
|
|
int shiftRight, shiftLeft;
|
|
int ledgeRight, ledgeLeft;
|
|
|
|
if (LaraCheckForLetGo(item, coll) || item->animNumber != LA_LADDER_IDLE)
|
|
return;
|
|
|
|
if (!(TrInput & IN_FORWARD))
|
|
{
|
|
if (!(TrInput & IN_BACK))
|
|
return;
|
|
|
|
if (item->goalAnimState == LS_HANG)
|
|
return;
|
|
|
|
item->goalAnimState = LS_LADDER_IDLE;
|
|
item->pos.yPos += 256;
|
|
|
|
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);
|
|
|
|
item->pos.yPos -= 256;
|
|
|
|
if (!resultRight || !resultLeft || resultLeft == -2 || resultRight == -2)
|
|
return;
|
|
|
|
yShift = ledgeLeft;
|
|
|
|
if (ledgeRight && ledgeLeft)
|
|
{
|
|
if (ledgeLeft < 0 != ledgeRight < 0)
|
|
return;
|
|
if (ledgeRight < 0 == ledgeRight < ledgeLeft)
|
|
yShift = ledgeRight;
|
|
}
|
|
|
|
if (resultRight == 1 && resultLeft == 1)
|
|
{
|
|
item->goalAnimState = LS_LADDER_DOWN;
|
|
item->pos.yPos += yShift;
|
|
}
|
|
else
|
|
{
|
|
item->goalAnimState = LS_HANG;
|
|
}
|
|
}
|
|
else if (item->goalAnimState != LS_GRABBING)
|
|
{
|
|
item->goalAnimState = LS_LADDER_IDLE;
|
|
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)
|
|
{
|
|
yShift = shiftLeft;
|
|
|
|
if (shiftRight)
|
|
{
|
|
if (shiftLeft)
|
|
{
|
|
if (shiftLeft < 0 != shiftRight < 0)
|
|
return;
|
|
if (shiftRight < 0 == shiftRight < shiftLeft)
|
|
yShift = shiftRight;
|
|
}
|
|
else
|
|
{
|
|
yShift = shiftRight;
|
|
}
|
|
}
|
|
|
|
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
|
|
{
|
|
item->goalAnimState = LS_LADDER_TO_CROUCH;
|
|
item->requiredAnimState = LS_CROUCH_IDLE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void lara_as_climbstnc(ITEM_INFO* item, COLL_INFO* coll)
|
|
{
|
|
Lara.isClimbing = true;
|
|
|
|
coll->Setup.EnableSpaz = false;
|
|
coll->Setup.EnableObjectPush = false;
|
|
|
|
Camera.targetElevation = -ANGLE(20);
|
|
|
|
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);
|
|
|
|
if (TrInput & IN_LOOK)
|
|
{
|
|
LookUpDown();
|
|
}
|
|
|
|
if (TrInput & IN_LEFT || TrInput & IN_LSTEP)
|
|
{
|
|
item->goalAnimState = LS_LADDER_LEFT;
|
|
Lara.moveAngle = item->pos.yRot - ANGLE(90);
|
|
}
|
|
else if (TrInput & IN_RIGHT || TrInput & IN_RSTEP)
|
|
{
|
|
item->goalAnimState = LS_LADDER_RIGHT;
|
|
Lara.moveAngle = item->pos.yRot + ANGLE(90);
|
|
}
|
|
else if (TrInput & IN_JUMP)
|
|
{
|
|
if (item->animNumber == LA_LADDER_IDLE)
|
|
{
|
|
item->goalAnimState = LS_JUMP_BACK;
|
|
Lara.gunStatus = LG_NO_ARMS;
|
|
Lara.moveAngle = item->pos.yRot + ANGLE(180);
|
|
}
|
|
}
|
|
}
|
|
|
|
void lara_as_stepoff_left(ITEM_INFO* item, COLL_INFO* coll)
|
|
{
|
|
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)
|
|
{
|
|
coll->Setup.EnableObjectPush = false;
|
|
coll->Setup.EnableSpaz = false;
|
|
|
|
Camera.targetAngle = ANGLE(60.0f);
|
|
Camera.targetElevation = -ANGLE(15.0f);
|
|
|
|
item->pos.yRot += ANGLE(90.0f);
|
|
}
|
|
|
|
int LaraTestClimbPos(ITEM_INFO* item, int front, int right, int origin, int height, int* shift)
|
|
{
|
|
int x;
|
|
int z;
|
|
int xFront = 0;
|
|
int zFront = 0;
|
|
|
|
switch (GetQuadrant(item->pos.yRot))
|
|
{
|
|
case NORTH:
|
|
x = item->pos.xPos + right;
|
|
z = item->pos.zPos + front;
|
|
zFront = 256;
|
|
break;
|
|
|
|
case EAST:
|
|
x = item->pos.xPos + front;
|
|
z = item->pos.zPos - right;
|
|
xFront = 256;
|
|
break;
|
|
|
|
case SOUTH:
|
|
x = item->pos.xPos - right;
|
|
z = item->pos.zPos - front;
|
|
zFront = -256;
|
|
break;
|
|
|
|
case WEST:
|
|
default:
|
|
x = item->pos.xPos - front;
|
|
z = item->pos.zPos + right;
|
|
xFront = -256;
|
|
break;
|
|
}
|
|
|
|
return LaraTestClimb(x, item->pos.yPos + origin, z, xFront, zFront, height, item->roomNumber, shift);
|
|
}
|
|
|
|
void LaraDoClimbLeftRight(ITEM_INFO* item, COLL_INFO* coll, int result, int shift)
|
|
{
|
|
if (result == 1)
|
|
{
|
|
if (TrInput & IN_LEFT)
|
|
{
|
|
item->goalAnimState = LS_LADDER_LEFT;
|
|
}
|
|
else if (TrInput & IN_RIGHT)
|
|
{
|
|
item->goalAnimState = LS_LADDER_RIGHT;
|
|
}
|
|
else
|
|
{
|
|
item->goalAnimState = LS_LADDER_IDLE;
|
|
}
|
|
|
|
item->pos.yPos += shift;
|
|
|
|
return;
|
|
}
|
|
|
|
if (result != 0)
|
|
{
|
|
item->goalAnimState = LS_HANG;
|
|
|
|
do
|
|
{
|
|
AnimateItem(item);
|
|
} while (item->currentAnimState != LS_HANG);
|
|
|
|
item->pos.xPos = coll->Setup.OldPosition.x;
|
|
item->pos.zPos = coll->Setup.OldPosition.z;
|
|
|
|
return;
|
|
}
|
|
|
|
item->pos.xPos = coll->Setup.OldPosition.x;
|
|
item->pos.zPos = coll->Setup.OldPosition.z;
|
|
|
|
item->goalAnimState = LS_LADDER_IDLE;
|
|
item->currentAnimState = LS_LADDER_IDLE;
|
|
|
|
if (coll->Setup.OldAnimState != LS_LADDER_IDLE)
|
|
{
|
|
SetAnimation(item, LA_LADDER_IDLE);
|
|
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;
|
|
}
|
|
}
|
|
|
|
if (TrInput & IN_LEFT)
|
|
{
|
|
int flag = LaraClimbLeftCornerTest(item, coll);
|
|
|
|
if (flag)
|
|
{
|
|
if (flag <= 0)
|
|
SetAnimation(item, LA_LADDER_LEFT_CORNER_INNER_START);
|
|
else
|
|
SetAnimation(item, LA_LADDER_LEFT_CORNER_OUTER_START);
|
|
|
|
return;
|
|
}
|
|
}
|
|
else if (TrInput & IN_RIGHT)
|
|
{
|
|
int flag = LaraClimbRightCornerTest(item, coll);
|
|
|
|
if (flag)
|
|
{
|
|
if (flag <= 0)
|
|
SetAnimation(item, LA_LADDER_RIGHT_CORNER_INNER_START);
|
|
else
|
|
SetAnimation(item, LA_LADDER_RIGHT_CORNER_OUTER_START);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
item->animNumber = coll->Setup.OldAnimNumber;
|
|
item->frameNumber = coll->Setup.OldFrameNumber;
|
|
|
|
AnimateLara(item);
|
|
}
|
|
|
|
int LaraClimbRightCornerTest(ITEM_INFO* item, COLL_INFO* coll)
|
|
{
|
|
int result = 0;
|
|
|
|
if (item->animNumber != LA_LADDER_RIGHT)
|
|
return 0;
|
|
|
|
int oldYrot = item->pos.yRot;
|
|
int oldX = item->pos.xPos;
|
|
int oldY = item->pos.yPos;
|
|
int oldZ = item->pos.zPos;
|
|
|
|
short angle = GetQuadrant(item->pos.yRot);
|
|
int x, z;
|
|
|
|
if (angle && angle != SOUTH)
|
|
{
|
|
x = (item->pos.xPos & 0xFFFFFC00) - (item->pos.zPos % 1024) + 1024;
|
|
z = (item->pos.zPos & 0xFFFFFC00) - (item->pos.xPos % 1024) + 1024;
|
|
}
|
|
else
|
|
{
|
|
x = item->pos.xPos ^ (item->pos.xPos ^ item->pos.zPos) & 0x3FF;
|
|
z = item->pos.zPos ^ (item->pos.xPos ^ item->pos.zPos) & 0x3FF;
|
|
}
|
|
|
|
int shift = 0;
|
|
|
|
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;
|
|
|
|
result = LaraTestClimbPos(item, coll->Setup.Radius, coll->Setup.Radius + 120, -512, 512, &shift);
|
|
}
|
|
|
|
if (!result)
|
|
{
|
|
item->pos.xPos = oldX;
|
|
Lara.moveAngle = oldYrot;
|
|
item->pos.yRot = oldYrot;
|
|
item->pos.zPos = oldZ;
|
|
|
|
int newX, newZ;
|
|
|
|
switch (angle)
|
|
{
|
|
case NORTH:
|
|
newX = ((item->pos.xPos + 1024) & 0xFFFFFC00) - (item->pos.zPos % 1024) + 1024;
|
|
newZ = ((item->pos.zPos + 1024) & 0xFFFFFC00) - (item->pos.xPos % 1024) + 1024;
|
|
break;
|
|
|
|
case SOUTH:
|
|
newX = ((item->pos.xPos - 1024) & 0xFFFFFC00) - (item->pos.zPos % 1024) + 1024;
|
|
newZ = ((item->pos.zPos - 1024) & 0xFFFFFC00) - (item->pos.xPos % 1024) + 1024;
|
|
break;
|
|
|
|
case EAST:
|
|
newX = ((item->pos.zPos ^ item->pos.xPos) % 1024) ^ (item->pos.xPos + 1024);
|
|
newZ = (item->pos.zPos ^ ((item->pos.zPos ^ item->pos.xPos) % 1024)) - 1024;
|
|
break;
|
|
|
|
case WEST:
|
|
default:
|
|
newX = (item->pos.xPos ^ (item->pos.zPos ^ item->pos.xPos) % 1024) - 1024;
|
|
newZ = ((item->pos.zPos ^ item->pos.xPos) % 1024) ^ (item->pos.zPos + 1024);
|
|
break;
|
|
|
|
}
|
|
|
|
if (GetClimbFlags(newX, item->pos.yPos, newZ, item->roomNumber) & (short)LeftIntRightExtTab[angle])
|
|
{
|
|
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;
|
|
result = LaraTestClimbPos(item, coll->Setup.Radius, coll->Setup.Radius + 120, -512, 512, &shift) != 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result = -1;
|
|
}
|
|
|
|
item->pos.xPos = oldX;
|
|
item->pos.yRot = oldYrot;
|
|
item->pos.zPos = oldZ;
|
|
Lara.moveAngle = oldYrot;
|
|
|
|
return result;
|
|
}
|
|
|
|
int LaraClimbLeftCornerTest(ITEM_INFO* item, COLL_INFO* coll)
|
|
{
|
|
int result = 0;
|
|
|
|
if (item->animNumber != LA_LADDER_LEFT)
|
|
return 0;
|
|
|
|
int oldYrot = item->pos.yRot;
|
|
int oldX = item->pos.xPos;
|
|
int oldY = item->pos.yPos;
|
|
int oldZ = item->pos.zPos;
|
|
|
|
short angle = GetQuadrant(item->pos.yRot);
|
|
int x, z;
|
|
|
|
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;
|
|
}
|
|
|
|
int shift = 0;
|
|
|
|
if (GetClimbFlags(x, item->pos.yPos, z, item->roomNumber) & (short)LeftIntRightExtTab[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;
|
|
|
|
result = LaraTestClimbPos(item, coll->Setup.Radius, -coll->Setup.Radius - 120, -512, 512, &shift);
|
|
item->itemFlags[3] = result;
|
|
}
|
|
|
|
if (!result)
|
|
{
|
|
item->pos.xPos = oldX;
|
|
Lara.moveAngle = oldYrot;
|
|
item->pos.yRot = oldYrot;
|
|
item->pos.zPos = oldZ;
|
|
|
|
int newX, newZ;
|
|
|
|
switch (angle)
|
|
{
|
|
case NORTH:
|
|
newX = (item->pos.xPos ^ ((item->pos.zPos ^ item->pos.xPos) & 0x3FF)) - 1024;
|
|
newZ = ((item->pos.zPos ^ item->pos.xPos) & 0x3FF) ^ (item->pos.zPos + 1024);
|
|
break;
|
|
|
|
case SOUTH:
|
|
newX = ((item->pos.zPos ^ item->pos.xPos) & 0x3FF) ^ (item->pos.xPos + 1024);
|
|
newZ = ((item->pos.zPos ^ item->pos.xPos) & 0x3FF) ^ (item->pos.zPos - 1024);
|
|
break;
|
|
|
|
case EAST:
|
|
newX = ((item->pos.xPos + 1024) & 0xFFFFFC00) - (item->pos.zPos & 0x3FF) + 1024;
|
|
newZ = ((item->pos.zPos + 1024) & 0xFFFFFC00) - (item->pos.xPos & 0x3FF) + 1024;
|
|
break;
|
|
|
|
case WEST:
|
|
default:
|
|
newX = (item->pos.xPos & 0xFFFFFC00) - (item->pos.zPos & 0x3FF);
|
|
newZ = (item->pos.zPos & 0xFFFFFC00) - (item->pos.xPos & 0x3FF);
|
|
break;
|
|
|
|
}
|
|
|
|
if (GetClimbFlags(newX, item->pos.yPos, newZ, item->roomNumber) & (short)LeftExtRightIntTab[angle])
|
|
{
|
|
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;
|
|
item->itemFlags[3] = LaraTestClimbPos(item, coll->Setup.Radius, -coll->Setup.Radius - 120, -512, 512, &shift);
|
|
result = item->itemFlags[3] != 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result = -1;
|
|
}
|
|
|
|
item->pos.xPos = oldX;
|
|
item->pos.yRot = oldYrot;
|
|
item->pos.zPos = oldZ;
|
|
Lara.moveAngle = oldYrot;
|
|
|
|
return result;
|
|
}
|
|
|
|
int LaraTestClimb(int x, int y, int z, int xFront, int zFront, int itemHeight, int itemRoom, int* shift)
|
|
{
|
|
*shift = 0;
|
|
int hang = 1;
|
|
if (!Lara.climbStatus)
|
|
return 0;
|
|
|
|
short roomNumber = itemRoom;
|
|
FLOOR_INFO* floor = GetFloor(x, y - 128, z, &roomNumber);
|
|
int height = GetFloorHeight(floor, x, y, z);
|
|
if (height == NO_HEIGHT)
|
|
return 0;
|
|
|
|
height -= (128 + y + itemHeight);
|
|
if (height < -70)
|
|
return 0;
|
|
if (height < 0)
|
|
*shift = height;
|
|
|
|
int ceiling = GetCeiling(floor, x, y, z) - y;
|
|
if (ceiling > 70)
|
|
return 0;
|
|
if (ceiling > 0)
|
|
{
|
|
if (*shift)
|
|
return 0;
|
|
*shift = ceiling;
|
|
}
|
|
|
|
if (itemHeight + height < 900)
|
|
hang = 0;
|
|
|
|
int dz = zFront + z;
|
|
int dx = xFront + x;
|
|
|
|
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;
|
|
}
|
|
|
|
int LaraTestClimbUpPos(ITEM_INFO* item, int front, int right, int* shift, int* ledge)
|
|
{
|
|
int y = item->pos.yPos - 768;
|
|
|
|
int x, z;
|
|
int xFront = 0;
|
|
int zFront = 0;
|
|
|
|
switch (GetQuadrant(item->pos.yRot))
|
|
{
|
|
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;
|
|
|
|
short roomNumber = item->roomNumber;
|
|
FLOOR_INFO* floor = GetFloor(x, y, z, &roomNumber);
|
|
int ceiling = 256 - y + GetCeiling(floor, x, y, z);
|
|
|
|
if (ceiling > 70)
|
|
return 0;
|
|
|
|
if (ceiling > 0)
|
|
*shift = ceiling;
|
|
|
|
floor = GetFloor(x + xFront, y, z + zFront, &roomNumber);
|
|
int height = GetFloorHeight(floor, x + xFront, y, z + zFront);
|
|
|
|
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)
|
|
{
|
|
if (height - ceiling < 512)
|
|
return 0;
|
|
*shift = height;
|
|
return -2;
|
|
}
|
|
else
|
|
{
|
|
*shift = height;
|
|
return -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return -2;
|
|
}
|
|
|
|
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;
|
|
|
|
SetAnimation(item, LA_FALL_START);
|
|
|
|
item->speed = 2;
|
|
item->gravityStatus = true;
|
|
item->fallspeed = 1;
|
|
|
|
Lara.gunStatus = LG_NO_ARMS;
|
|
|
|
return 1;
|
|
}
|