mirror of
https://github.com/TombEngine/TombEngine.git
synced 2025-05-10 20:46:47 +03:00
3273 lines
64 KiB
C++
3273 lines
64 KiB
C++
#include "framework.h"
|
|
#include "lara.h"
|
|
#include "lara_basic.h"
|
|
#include "lara_tests.h"
|
|
#include "lara_collide.h"
|
|
#include "lara_slide.h"
|
|
#include "lara_monkey.h"
|
|
#include "input.h"
|
|
#include "health.h"
|
|
#include "sound.h"
|
|
#include "draw.h"
|
|
#include "pickup.h"
|
|
|
|
bool EnableBackKeyTurn = false;
|
|
|
|
bool EnableJump = false;
|
|
|
|
// BASIC MOVEMENT
|
|
|
|
// ------------------------------
|
|
// Auxiliary Functions
|
|
// ------------------------------
|
|
|
|
bool TestLaraStepDown(COLL_INFO* coll)
|
|
{
|
|
if (coll->midFloor <= STEPUP_HEIGHT &&
|
|
coll->midFloor > STEP_SIZE / 2)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool TestLaraStepUp(COLL_INFO* coll)
|
|
{
|
|
if (coll->frontFloor >= -STEPUP_HEIGHT &&
|
|
coll->frontFloor < -STEP_SIZE / 2)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// TODO: Some states can't use this function yet due to missing step up/down anims.
|
|
void DoLaraStep(ITEM_INFO* item, COLL_INFO* coll)
|
|
{
|
|
if (TestLaraStepDown(coll))
|
|
{
|
|
item->pos.yPos += coll->midFloor;
|
|
|
|
item->goalAnimState = LS_STEP_DOWN;
|
|
GetChange(item, &g_Level.Anims[item->animNumber]);
|
|
}
|
|
else if (TestLaraStepUp(coll))
|
|
{
|
|
item->pos.yPos += coll->midFloor;
|
|
|
|
item->goalAnimState = LS_STEP_UP;
|
|
GetChange(item, &g_Level.Anims[item->animNumber]);
|
|
}
|
|
else if (abs(coll->midFloor) >= 50)
|
|
{
|
|
item->pos.yPos += 50 * GetSign(coll->midFloor);
|
|
}
|
|
else
|
|
{
|
|
item->pos.yPos += coll->midFloor;
|
|
}
|
|
}
|
|
|
|
// ------------------------------
|
|
// GENERAL
|
|
// Control & Collision Functions
|
|
// ------------------------------
|
|
|
|
void lara_void_func(ITEM_INFO* item, COLL_INFO* coll)//19928(<), 19A5C(<) (F)
|
|
{
|
|
return;
|
|
}
|
|
|
|
void lara_default_col(ITEM_INFO* item, COLL_INFO* coll)//1C80C(<), 1C940(<) (F)
|
|
{
|
|
Lara.moveAngle = 0;
|
|
|
|
coll->badPos = 384;
|
|
coll->badNeg = -STEPUP_HEIGHT;
|
|
coll->badCeiling = 0;
|
|
coll->slopesArePits = true;
|
|
coll->slopesAreWalls = true;
|
|
coll->facing = Lara.moveAngle;
|
|
|
|
GetCollisionInfo(coll, item->pos.xPos, item->pos.yPos, item->pos.zPos, item->roomNumber, LARA_HITE);
|
|
}
|
|
|
|
void lara_as_special(ITEM_INFO* item, COLL_INFO* coll)//1ADDC(<), 1AF10(<) (F)
|
|
{
|
|
Camera.flags = CF_FOLLOW_CENTER;
|
|
Camera.targetAngle = ANGLE(170.0f);
|
|
Camera.targetElevation = ANGLE(-25.0f);
|
|
}
|
|
|
|
void lara_as_null(ITEM_INFO* item, COLL_INFO* coll)//1A5DC(<), 1A710(<) (F)
|
|
{
|
|
coll->enableBaddiePush = false;
|
|
coll->enableSpaz = false;
|
|
}
|
|
|
|
void lara_as_controlled(ITEM_INFO* item, COLL_INFO* coll)//1B0FC(<), 1B230(<) (F)
|
|
{
|
|
Lara.look = false;
|
|
|
|
coll->enableBaddiePush = false;
|
|
coll->enableSpaz = false;
|
|
|
|
if (item->frameNumber == g_Level.Anims[item->animNumber].frameEnd - 1)
|
|
{
|
|
Lara.gunStatus = LG_NO_ARMS;
|
|
|
|
if (UseForcedFixedCamera)
|
|
{
|
|
UseForcedFixedCamera = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
void lara_as_controlledl(ITEM_INFO* item, COLL_INFO* coll)//1B180(<), 1B2B4(<) (F)
|
|
{
|
|
Lara.look = false;
|
|
|
|
coll->enableBaddiePush = false;
|
|
coll->enableSpaz = false;
|
|
}
|
|
|
|
// ------------------------------
|
|
// BASIC MOVEMENT
|
|
// Control & Collision Functions
|
|
// ------------------------------
|
|
|
|
// State: 0
|
|
// Collision: lara_col_walk_forward()
|
|
void lara_as_walk_forward(ITEM_INFO* item, COLL_INFO* coll)//191B8(<), 192EC(<) (F)
|
|
{
|
|
// TODO: Looking while walking.
|
|
// BUG: When looking while running Lara transitions into a walk, look mode locks.
|
|
|
|
if (item->hitPoints <= 0)
|
|
{
|
|
item->goalAnimState = LS_STOP;
|
|
return;
|
|
}
|
|
|
|
if (Lara.isMoving)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// TODO: Lara refuses to turn when performing walk-to-stand anims.
|
|
if (TrInput & IN_LEFT)
|
|
{
|
|
Lara.turnRate -= LARA_TURN_RATE;
|
|
if (Lara.turnRate < ANGLE(-4.0f))
|
|
{
|
|
Lara.turnRate = ANGLE(-4.0f);
|
|
}
|
|
}
|
|
else if (TrInput & IN_RIGHT)
|
|
{
|
|
Lara.turnRate += LARA_TURN_RATE;
|
|
if (Lara.turnRate > ANGLE(4.0f))
|
|
{
|
|
Lara.turnRate = ANGLE(4.0f);
|
|
}
|
|
}
|
|
|
|
if (TrInput & IN_FORWARD)
|
|
{
|
|
if (Lara.waterStatus == LW_WADE)
|
|
{
|
|
item->goalAnimState = LS_WADE_FORWARD;
|
|
}
|
|
else if (TrInput & IN_WALK)
|
|
{
|
|
item->goalAnimState = LS_WALK_FORWARD;
|
|
}
|
|
else
|
|
{
|
|
item->goalAnimState = LS_RUN_FORWARD;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
item->goalAnimState = LS_STOP;
|
|
}
|
|
|
|
// State: 0
|
|
// State code: lara_as_walk_forward()
|
|
void lara_col_walk_forward(ITEM_INFO* item, COLL_INFO* coll)//1B3E8, 1B51C (F)
|
|
{
|
|
Lara.moveAngle = 0;
|
|
|
|
item->gravityStatus = false;
|
|
item->fallspeed = 0;
|
|
|
|
coll->badPos = 384;
|
|
coll->badNeg = -STEPUP_HEIGHT;
|
|
coll->badCeiling = 0;
|
|
coll->slopesAreWalls = true;
|
|
coll->slopesArePits = true;
|
|
coll->lavaIsPit = 1;
|
|
coll->facing = Lara.moveAngle;
|
|
|
|
GetCollisionInfo(coll, item->pos.xPos, item->pos.yPos, item->pos.zPos, item->roomNumber, LARA_HITE);
|
|
|
|
if (TrInput & IN_LEFT)
|
|
{
|
|
if (TestLaraLean(coll) && item->pos.zRot <= 0)
|
|
{
|
|
item->pos.zRot -= LARA_LEAN_RATE;
|
|
if (item->pos.zRot < -LARA_LEAN_MAX / 2)
|
|
{
|
|
item->pos.zRot = -LARA_LEAN_MAX / 2;
|
|
}
|
|
}
|
|
}
|
|
else if (TrInput & IN_RIGHT)
|
|
{
|
|
if (TestLaraLean(coll) && item->pos.zRot >= 0)
|
|
{
|
|
item->pos.zRot += LARA_LEAN_RATE;
|
|
if (item->pos.zRot > LARA_LEAN_MAX / 2)
|
|
{
|
|
item->pos.zRot = LARA_LEAN_MAX / 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (TestLaraVault(item, coll))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (TestLaraHitCeiling(coll))
|
|
{
|
|
SetLaraHitCeiling(item, coll);
|
|
return;
|
|
}
|
|
|
|
if (TestLaraWallDeflect(coll))
|
|
{
|
|
SetLaraWallDeflect(item, coll);
|
|
|
|
item->goalAnimState = LS_SPLAT;
|
|
if (GetChange(item, &g_Level.Anims[item->animNumber]))
|
|
{
|
|
return;
|
|
}
|
|
|
|
LaraCollideStop(item, coll);
|
|
}
|
|
|
|
if (abs(coll->midFloor) > 0 && abs(coll->midFloor <= STEPUP_HEIGHT))
|
|
{
|
|
DoLaraStep(item, coll);
|
|
}
|
|
|
|
if (TestLaraFall(coll))
|
|
{
|
|
item->goalAnimState = LS_FALL;
|
|
item->fallspeed = 0;
|
|
item->gravityStatus = true;
|
|
|
|
return;
|
|
}
|
|
|
|
if (TestLaraSlide(coll))
|
|
{
|
|
SetLaraSlide(item, coll);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// State: 1
|
|
// Collision: lara_col_run()
|
|
void lara_as_run(ITEM_INFO* item, COLL_INFO* coll)//192EC, 19420 (F)
|
|
{
|
|
if (item->hitPoints <= 0)
|
|
{
|
|
item->goalAnimState = LS_DEATH;
|
|
return;
|
|
}
|
|
|
|
if (TrInput & IN_LEFT)
|
|
{
|
|
Lara.turnRate -= LARA_TURN_RATE;
|
|
if (Lara.turnRate < -LARA_FAST_TURN)
|
|
{
|
|
Lara.turnRate = -LARA_FAST_TURN;
|
|
}
|
|
}
|
|
else if (TrInput & IN_RIGHT)
|
|
{
|
|
Lara.turnRate += LARA_TURN_RATE;
|
|
if (Lara.turnRate > LARA_FAST_TURN)
|
|
{
|
|
Lara.turnRate = LARA_FAST_TURN;
|
|
}
|
|
}
|
|
|
|
if (item->animNumber == LA_STAND_TO_RUN)
|
|
{
|
|
EnableJump = false;
|
|
}
|
|
else if (item->animNumber == LA_RUN && item->frameNumber == 4)
|
|
{
|
|
EnableJump = true;
|
|
}
|
|
else
|
|
{
|
|
EnableJump = true;
|
|
}
|
|
|
|
if (TrInput & IN_JUMP && EnableJump && !item->gravityStatus)
|
|
{
|
|
item->goalAnimState = LS_JUMP_FORWARD;
|
|
return;
|
|
}
|
|
|
|
if (TrInput & IN_SPRINT && DashTimer)
|
|
{
|
|
item->goalAnimState = LS_SPRINT;
|
|
|
|
return;
|
|
}
|
|
|
|
if (TrInput & IN_DUCK &&
|
|
Lara.waterStatus != LW_WADE &&
|
|
(Lara.gunStatus == LG_NO_ARMS ||
|
|
Lara.gunType == WEAPON_NONE ||
|
|
Lara.gunType == WEAPON_PISTOLS ||
|
|
Lara.gunType == WEAPON_REVOLVER ||
|
|
Lara.gunType == WEAPON_UZI ||
|
|
Lara.gunType == WEAPON_FLARE))
|
|
{
|
|
item->goalAnimState = LS_CROUCH_IDLE;
|
|
return;
|
|
}
|
|
|
|
if ((TrInput & IN_ROLL ||
|
|
(TrInput & IN_BACK && EnableBackKeyTurn))
|
|
&& !(TrInput & IN_JUMP)) // A slightly hacky fix to prevent unintentional rolling when JUMP and ROLL are pressed and EnableJump isn't true yet.
|
|
{
|
|
item->goalAnimState = LS_ROLL_FORWARD;
|
|
return;
|
|
}
|
|
|
|
if (TrInput & IN_FORWARD)
|
|
{
|
|
if (Lara.waterStatus == LW_WADE)
|
|
{
|
|
item->goalAnimState = LS_WADE_FORWARD;
|
|
}
|
|
else if (TrInput & IN_WALK)
|
|
{
|
|
item->goalAnimState = LS_WALK_FORWARD;
|
|
}
|
|
else
|
|
{
|
|
item->goalAnimState = LS_RUN_FORWARD;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
item->goalAnimState = LS_STOP;
|
|
}
|
|
|
|
// State: 1
|
|
// State code: lara_col_run()
|
|
void lara_col_run(ITEM_INFO* item, COLL_INFO* coll)//1B64C, 1B780 (F)
|
|
{
|
|
Lara.moveAngle = 0;
|
|
|
|
coll->badPos = NO_BAD_POS;
|
|
coll->badNeg = -STEPUP_HEIGHT;
|
|
coll->badCeiling = 0;
|
|
coll->slopesAreWalls = true;
|
|
coll->facing = Lara.moveAngle;
|
|
|
|
GetCollisionInfo(coll, item->pos.xPos, item->pos.yPos, item->pos.zPos, item->roomNumber, LARA_HITE);
|
|
|
|
if (TrInput & IN_LEFT)
|
|
{
|
|
if (TestLaraLean(coll))
|
|
{
|
|
item->pos.zRot -= LARA_LEAN_RATE;
|
|
if (item->pos.zRot < -LARA_LEAN_MAX)
|
|
{
|
|
item->pos.zRot = -LARA_LEAN_MAX;
|
|
}
|
|
}
|
|
}
|
|
else if (TrInput & IN_RIGHT)
|
|
{
|
|
if (TestLaraLean(coll))
|
|
{
|
|
item->pos.zRot += LARA_LEAN_RATE;
|
|
if (item->pos.zRot > LARA_LEAN_MAX)
|
|
{
|
|
item->pos.zRot = LARA_LEAN_MAX;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (TestLaraVault(item, coll))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (TestLaraHitCeiling(coll))
|
|
{
|
|
SetLaraHitCeiling(item, coll);
|
|
return;
|
|
}
|
|
|
|
if (LaraDeflectEdge(item, coll))
|
|
{
|
|
item->pos.zRot = 0;
|
|
|
|
if (TestWall(item, 256, 0, -640))
|
|
{
|
|
item->goalAnimState = LS_SPLAT;
|
|
if (GetChange(item, &g_Level.Anims[item->animNumber]))
|
|
{
|
|
item->currentAnimState = LS_SPLAT;
|
|
return;
|
|
}
|
|
}
|
|
|
|
LaraCollideStop(item, coll);
|
|
}
|
|
|
|
if (abs(coll->midFloor) > 0 && abs(coll->midFloor <= STEPUP_HEIGHT))
|
|
{
|
|
//DoLaraStep(item, coll); // Uncomment this line and remove everything below when a step down anim is created.
|
|
|
|
/*if (TestLaraStepDown(coll))
|
|
{
|
|
item->pos.yPos += coll->midFloor;
|
|
|
|
item->goalAnimState = LS_STEP_DOWN;
|
|
GetChange(item, &g_Level.Anims[item->animNumber]);
|
|
}
|
|
else */if (TestLaraStepUp(coll))
|
|
{
|
|
item->pos.yPos += coll->midFloor;
|
|
|
|
item->goalAnimState = LS_STEP_UP;
|
|
GetChange(item, &g_Level.Anims[item->animNumber]);
|
|
}
|
|
else if (abs(coll->midFloor) >= 50)
|
|
{
|
|
item->pos.yPos += 50 * GetSign(coll->midFloor);
|
|
}
|
|
else
|
|
{
|
|
item->pos.yPos += coll->midFloor;
|
|
}
|
|
}
|
|
|
|
if (TestLaraFall(coll))
|
|
{
|
|
//if (TrInput & IN_ACTION &&
|
|
// EnableSafetyDrop &&
|
|
// coll->midFloor >= 1024 &&
|
|
// Lara.gunStatus == LG_NO_ARMS) // TODO: Also test for floor behind and static below.
|
|
//{
|
|
// item->goalAnimState = LS_SAFE_DROP;
|
|
//}
|
|
//else
|
|
//{
|
|
item->goalAnimState = LS_FALL;
|
|
item->fallspeed = 0;
|
|
item->gravityStatus = true;
|
|
//}
|
|
|
|
return;
|
|
}
|
|
|
|
// LEGACY step code. Has NO_HEIGHT checks unaccounted for above; not sure what they do exactly. -Sezz
|
|
//if (coll->midFloor >= -STEPUP_HEIGHT && coll->midFloor < -STEP_SIZE / 2)
|
|
//{
|
|
// if (coll->frontFloor == NO_HEIGHT || coll->frontFloor < -STEPUP_HEIGHT || coll->frontFloor >= -STEP_SIZE / 2)
|
|
// {
|
|
// coll->midFloor = 0;
|
|
// }
|
|
// else
|
|
// {
|
|
// item->goalAnimState = LS_STEP_UP;
|
|
// GetChange(item, &g_Level.Anims[item->animNumber]);
|
|
// }
|
|
//}
|
|
//else
|
|
//{
|
|
// if (coll->midFloor < 50)
|
|
// {
|
|
// if (coll->midFloor != NO_HEIGHT)
|
|
// {
|
|
// item->pos.yPos += coll->midFloor / 2;
|
|
// }
|
|
// else
|
|
// {
|
|
// item->goalAnimState = LS_STEP_DOWN; // for theoretical running stepdown anims, not in default anims
|
|
|
|
// if (GetChange(item, &g_Level.Anims[item->animNumber]))
|
|
// {
|
|
// item->pos.yPos += coll->midFloor; // move Lara to midFloor
|
|
// }
|
|
// else
|
|
// {
|
|
// item->pos.yPos += 50; // do the default aligment
|
|
// }
|
|
// }
|
|
// }
|
|
//}
|
|
|
|
if (TestLaraSlide(coll))
|
|
{
|
|
SetLaraSlide(item, coll);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// State: 2
|
|
// Collision: lara_col_stop()
|
|
void lara_as_stop(ITEM_INFO* item, COLL_INFO* coll)
|
|
{
|
|
int fHeight = NO_HEIGHT;
|
|
int rHeight = NO_HEIGHT;
|
|
|
|
if (item->animNumber != LA_SPRINT_TO_STAND_RIGHT && item->animNumber != LA_SPRINT_TO_STAND_LEFT)
|
|
{
|
|
StopSoundEffect(SFX_LARA_SLIPPING);
|
|
}
|
|
|
|
if (item->hitPoints <= 0)
|
|
{
|
|
item->goalAnimState = LS_DEATH;
|
|
return;
|
|
}
|
|
|
|
// Handles waterskin and clockwork beetle.
|
|
if (UseSpecialItem(item))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// TODO: This prevents locks and looping actions, but those should be caught by each state.
|
|
item->goalAnimState = LS_STOP;
|
|
|
|
if (TrInput & IN_LOOK)
|
|
{
|
|
LookUpDown();
|
|
}
|
|
|
|
if (TrInput & IN_FORWARD)
|
|
{
|
|
fHeight = LaraFloorFront(item, item->pos.yRot, LARA_RAD + 4);
|
|
}
|
|
else if (TrInput & IN_BACK)
|
|
{
|
|
rHeight = LaraFloorFront(item, item->pos.yRot - ANGLE(180.0f), LARA_RAD + 4); // TR3: item->pos.yRot + ANGLE(180) ?
|
|
}
|
|
|
|
int height, ceiling;
|
|
|
|
if (TrInput & IN_LEFT)
|
|
{
|
|
item->goalAnimState = LS_TURN_LEFT_SLOW;
|
|
}
|
|
else if (TrInput & IN_RIGHT)
|
|
{
|
|
item->goalAnimState = LS_TURN_RIGHT_SLOW;
|
|
}
|
|
else if (TrInput & IN_LSTEP)
|
|
{
|
|
height = LaraFloorFront(item, item->pos.yRot - ANGLE(90.0f), LARA_RAD + 48);
|
|
ceiling = LaraCeilingFront(item, item->pos.yRot - ANGLE(90.0f), LARA_RAD + 48, LARA_HITE);
|
|
|
|
if ((height < 128 && height > -128) && HeightType != BIG_SLOPE && ceiling <= 0)
|
|
{
|
|
item->goalAnimState = LS_STEP_LEFT;
|
|
}
|
|
}
|
|
else if (TrInput & IN_RSTEP)
|
|
{
|
|
height = LaraFloorFront(item, item->pos.yRot + ANGLE(90.0f), LARA_RAD + 48);
|
|
ceiling = LaraCeilingFront(item, item->pos.yRot + ANGLE(90.0f), LARA_RAD + 48, LARA_HITE);
|
|
|
|
if ((height < 128 && height > -128) && HeightType != BIG_SLOPE && ceiling <= 0)
|
|
{
|
|
item->goalAnimState = LS_STEP_RIGHT;
|
|
}
|
|
}
|
|
|
|
if (Lara.waterStatus == LW_WADE)
|
|
{
|
|
if (TrInput & IN_JUMP && !(g_Level.Rooms[item->roomNumber].flags & ENV_FLAG_SWAMP))
|
|
{
|
|
item->goalAnimState = LS_JUMP_PREPARE;
|
|
}
|
|
|
|
if (TrInput & IN_FORWARD)
|
|
{
|
|
if ((g_Level.Rooms[item->roomNumber].flags & ENV_FLAG_SWAMP &&
|
|
fHeight > -(STEPUP_HEIGHT - 1)) ||
|
|
(fHeight < (STEPUP_HEIGHT - 1) &&
|
|
fHeight > -(STEPUP_HEIGHT - 1)))
|
|
{
|
|
item->goalAnimState = LS_WADE_FORWARD;
|
|
return;
|
|
}
|
|
|
|
Lara.moveAngle = 0;
|
|
|
|
coll->badPos = NO_BAD_POS;
|
|
coll->badNeg = -STEPUP_HEIGHT;
|
|
coll->badCeiling = 0;
|
|
coll->slopesAreWalls = true;
|
|
coll->radius = LARA_RAD + 2;
|
|
coll->facing = Lara.moveAngle;
|
|
|
|
GetCollisionInfo(coll, item->pos.xPos, item->pos.yPos, item->pos.zPos, item->roomNumber, LARA_HITE);
|
|
|
|
if (TestLaraVault(item, coll))
|
|
{
|
|
return;
|
|
}
|
|
|
|
coll->radius = LARA_RAD;
|
|
|
|
return;
|
|
}
|
|
|
|
if (TrInput & IN_BACK)
|
|
{
|
|
if ((rHeight < (STEPUP_HEIGHT - 1)) && (rHeight > -(STEPUP_HEIGHT - 1)))
|
|
{
|
|
item->goalAnimState = LS_WALK_BACK;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// TODO: Add failsafe which automatically crouches Lara if she unexpectedly embeds into a crawlspace.
|
|
if (TrInput & IN_DUCK &&
|
|
Lara.waterStatus != LW_WADE &&
|
|
(Lara.gunStatus == LG_NO_ARMS ||
|
|
Lara.gunType == WEAPON_NONE ||
|
|
Lara.gunType == WEAPON_PISTOLS ||
|
|
Lara.gunType == WEAPON_REVOLVER ||
|
|
Lara.gunType == WEAPON_UZI ||
|
|
Lara.gunType == WEAPON_FLARE))
|
|
{
|
|
item->goalAnimState = LS_CROUCH_IDLE;
|
|
return;
|
|
}
|
|
|
|
if (TrInput & IN_ROLL && Lara.waterStatus != LW_WADE)
|
|
{
|
|
item->goalAnimState = LS_ROLL_FORWARD;
|
|
return;
|
|
}
|
|
}
|
|
else [[likely]]
|
|
{
|
|
if (TrInput & IN_JUMP)
|
|
{
|
|
item->goalAnimState = LS_JUMP_PREPARE;
|
|
return;
|
|
}
|
|
|
|
if (TrInput & IN_FORWARD)
|
|
{
|
|
int height = LaraFloorFront(item, item->pos.yRot, LARA_RAD + 4);
|
|
int ceiling = LaraCeilingFront(item, item->pos.yRot, LARA_RAD + 4, LARA_HITE);
|
|
|
|
if ((HeightType == BIG_SLOPE || HeightType == DIAGONAL) && (height < 0 || ceiling > 0))
|
|
{
|
|
item->goalAnimState = LS_STOP;
|
|
return;
|
|
}
|
|
|
|
/*if (TrInput & IN_ACTION &&
|
|
EnableSafetyDrop &&
|
|
LaraFloorFront(item, -item->pos.yRot, 100) <= 1024)
|
|
{
|
|
item->goalAnimState = LS_SAFE_DROP;
|
|
}
|
|
else */if (TrInput & IN_WALK)
|
|
{
|
|
item->goalAnimState = LS_WALK_FORWARD;
|
|
}
|
|
else
|
|
{
|
|
item->goalAnimState = LS_RUN_FORWARD;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if (TrInput & IN_BACK)
|
|
{
|
|
/*if (TrInput & IN_ACTION && LaraFloorFront(item, -item->pos.yRot, 100) < 1024 && EnableSafetyDrop)
|
|
{
|
|
item->goalAnimState = LS_SAFE_DROP;
|
|
}
|
|
else */if (TrInput & IN_WALK)
|
|
{
|
|
if ((rHeight < (STEPUP_HEIGHT - 1)) && (rHeight > -(STEPUP_HEIGHT - 1)) && HeightType != BIG_SLOPE)
|
|
{
|
|
item->goalAnimState = LS_WALK_BACK;
|
|
}
|
|
}
|
|
else if (rHeight > -(STEPUP_HEIGHT - 1))
|
|
{
|
|
item->goalAnimState = LS_HOP_BACK;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//if (TrInput & IN_SPRINT)
|
|
//{
|
|
// item->goalAnimState = LS_SPRINT;
|
|
// return;
|
|
//}
|
|
|
|
if (TrInput & IN_DUCK &&
|
|
Lara.waterStatus != LW_WADE &&
|
|
(Lara.gunStatus == LG_NO_ARMS ||
|
|
Lara.gunType == WEAPON_NONE ||
|
|
Lara.gunType == WEAPON_PISTOLS ||
|
|
Lara.gunType == WEAPON_REVOLVER ||
|
|
Lara.gunType == WEAPON_UZI ||
|
|
Lara.gunType == WEAPON_FLARE))
|
|
{
|
|
item->goalAnimState = LS_CROUCH_IDLE;
|
|
return;
|
|
}
|
|
|
|
if (TrInput & IN_ROLL && Lara.waterStatus != LW_WADE)
|
|
{
|
|
item->goalAnimState = LS_ROLL_FORWARD;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// State: 2
|
|
// State code: lara_as_stop()
|
|
void lara_col_stop(ITEM_INFO* item, COLL_INFO* coll) // (F) (D)
|
|
{
|
|
Lara.moveAngle = 0;
|
|
|
|
item->gravityStatus = false;
|
|
item->fallspeed = 0;
|
|
|
|
coll->badPos = STEPUP_HEIGHT;
|
|
coll->badNeg = -STEPUP_HEIGHT;
|
|
coll->badCeiling = 0;
|
|
coll->slopesArePits = true;
|
|
coll->slopesAreWalls = true;
|
|
coll->facing = Lara.moveAngle;
|
|
|
|
GetCollisionInfo(coll, item->pos.xPos, item->pos.yPos, item->pos.zPos, item->roomNumber, LARA_HITE);
|
|
|
|
if (TestLaraVault(item, coll))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (TestLaraHitCeiling(coll))
|
|
{
|
|
SetLaraHitCeiling(item, coll);
|
|
return;
|
|
}
|
|
|
|
if (TestLaraFall(coll))
|
|
{
|
|
item->goalAnimState = LS_FALL;
|
|
item->fallspeed = 0;
|
|
item->gravityStatus = true;
|
|
|
|
return;
|
|
}
|
|
|
|
if (TestLaraSlide(coll))
|
|
{
|
|
SetLaraSlide(item, coll);
|
|
return;
|
|
}
|
|
|
|
ShiftItem(item, coll);
|
|
|
|
#if 1
|
|
if (coll->midFloor != NO_HEIGHT)
|
|
{
|
|
item->pos.yPos += coll->midFloor;
|
|
}
|
|
#else
|
|
if (!(g_Level.Rooms[item->roomNumber].flags & ENV_FLAG_SWAMP) || coll->midFloor < 0)
|
|
{
|
|
item->pos.yPos += coll->midFloor;
|
|
}
|
|
else if (g_Level.Rooms[item->roomNumber].flags & ENV_FLAG_SWAMP && coll->midFloor)
|
|
{
|
|
item->pos.yPos += SWAMP_GRAVITY;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// State: 3
|
|
// Collision: lara_col_forward_jump()
|
|
void lara_as_jump_forward(ITEM_INFO* item, COLL_INFO* coll)//18A34, 18B68 (F)
|
|
{
|
|
//if (item->hitPoints <= 0)
|
|
//{
|
|
// item->goalAnimState = LS_DEATH;
|
|
// return;
|
|
//}
|
|
|
|
if (item->fallspeed > LARA_FREEFALL_SPEED)
|
|
{
|
|
item->goalAnimState = LS_FREEFALL;
|
|
return;
|
|
}
|
|
|
|
// Petition to ban banana jumps.
|
|
if (TrInput & IN_LEFT)
|
|
{
|
|
Lara.turnRate -= LARA_TURN_RATE;
|
|
if (Lara.turnRate < ANGLE(-3.0f))
|
|
{
|
|
Lara.turnRate = ANGLE(-3.0f);
|
|
}
|
|
}
|
|
else if (TrInput & IN_RIGHT)
|
|
{
|
|
Lara.turnRate += LARA_TURN_RATE;
|
|
if (Lara.turnRate > ANGLE(3.0f))
|
|
{
|
|
Lara.turnRate = ANGLE(3.0f);
|
|
}
|
|
}
|
|
|
|
if (TrInput & IN_ACTION &&
|
|
Lara.gunStatus == LG_NO_ARMS)
|
|
{
|
|
item->goalAnimState = LS_REACH;
|
|
return;
|
|
}
|
|
|
|
if (TrInput & IN_WALK &&
|
|
Lara.gunStatus == LG_NO_ARMS)
|
|
{
|
|
item->goalAnimState = LS_SWANDIVE_START;
|
|
return;
|
|
}
|
|
|
|
if (TrInput & IN_ROLL ||
|
|
(TrInput & IN_BACK && EnableBackKeyTurn))
|
|
{
|
|
item->goalAnimState = LS_JUMP_ROLL_180;
|
|
return;
|
|
}
|
|
|
|
//item->goalAnimState = LS_JUMP_FORWARD;
|
|
}
|
|
|
|
// State: 3
|
|
// State code: lara_as_forward_jump()
|
|
void lara_col_jump_forward(ITEM_INFO* item, COLL_INFO* coll)//18B88, 18CBC (F)
|
|
{
|
|
if (item->speed < 0)
|
|
{
|
|
Lara.moveAngle = ANGLE(180.0f);
|
|
}
|
|
else
|
|
{
|
|
Lara.moveAngle = 0;
|
|
}
|
|
|
|
coll->badPos = NO_BAD_POS;
|
|
coll->badNeg = -STEPUP_HEIGHT;
|
|
coll->badCeiling = BAD_JUMP_CEILING;
|
|
coll->facing = Lara.moveAngle;
|
|
|
|
GetCollisionInfo(coll, item->pos.xPos, item->pos.yPos, item->pos.zPos, item->roomNumber, LARA_HITE);
|
|
|
|
LaraDeflectEdgeJump(item, coll);
|
|
|
|
if (item->speed < 0) // ??
|
|
{
|
|
Lara.moveAngle = 0;
|
|
}
|
|
|
|
if (coll->midFloor <= 0 && item->fallspeed > 0)
|
|
{
|
|
if (LaraLandedBad(item, coll)) // ?
|
|
{
|
|
item->goalAnimState = LS_DEATH;
|
|
}
|
|
else
|
|
{
|
|
if (Lara.waterStatus == LW_WADE)
|
|
{
|
|
item->goalAnimState = LS_STOP;
|
|
}
|
|
else
|
|
{
|
|
if (TrInput & IN_FORWARD && !(TrInput & IN_STEPSHIFT)) // ???
|
|
{
|
|
item->goalAnimState = LS_RUN_FORWARD;
|
|
}
|
|
else
|
|
{
|
|
item->goalAnimState = LS_STOP;
|
|
}
|
|
}
|
|
}
|
|
|
|
item->gravityStatus = false;
|
|
item->fallspeed = 0;
|
|
item->speed = 0;
|
|
|
|
if (coll->midFloor != NO_HEIGHT)
|
|
{
|
|
item->pos.yPos += coll->midFloor;
|
|
}
|
|
|
|
AnimateLara(item);
|
|
}
|
|
}
|
|
|
|
// State: 4
|
|
// Collision: lara_void_func()
|
|
void lara_col_pose(ITEM_INFO* item, COLL_INFO* coll)//1B87C(<), 1B9B0(<) (F)
|
|
{
|
|
lara_col_stop(item, coll);
|
|
}
|
|
|
|
// State: 5
|
|
// Collision: lara_col_hop_back()
|
|
void lara_as_hop_back(ITEM_INFO* item, COLL_INFO* coll)//1959C(<), 196D0(<) (F)
|
|
{
|
|
if (TrInput & IN_LEFT)
|
|
{
|
|
Lara.turnRate -= LARA_TURN_RATE;
|
|
if (Lara.turnRate < ANGLE(-6.0f))
|
|
{
|
|
Lara.turnRate = ANGLE(-6.0f);
|
|
}
|
|
}
|
|
else if (TrInput & IN_RIGHT)
|
|
{
|
|
Lara.turnRate += LARA_TURN_RATE;
|
|
if (Lara.turnRate > ANGLE(6.0f))
|
|
{
|
|
Lara.turnRate = ANGLE(6.0f);
|
|
}
|
|
}
|
|
|
|
item->goalAnimState = LS_STOP;
|
|
}
|
|
|
|
// State: 5
|
|
// State code: lara_as_hop_back()
|
|
void lara_col_hop_back(ITEM_INFO* item, COLL_INFO* coll)//1B89C, 1B9D0 (F)
|
|
{
|
|
Lara.moveAngle = ANGLE(180.0f);
|
|
|
|
item->fallspeed = 0;
|
|
item->gravityStatus = false;
|
|
|
|
coll->slopesAreWalls = 0;
|
|
coll->slopesArePits = true;
|
|
coll->badPos = NO_BAD_POS;
|
|
coll->badNeg = -STEPUP_HEIGHT;
|
|
coll->badCeiling = 0;
|
|
coll->facing = Lara.moveAngle;
|
|
|
|
GetCollisionInfo(coll, item->pos.xPos, item->pos.yPos, item->pos.zPos, item->roomNumber, LARA_HITE);
|
|
|
|
if (TestLaraHitCeiling(coll))
|
|
{
|
|
SetLaraHitCeiling(item, coll);
|
|
return;
|
|
}
|
|
|
|
if (TestLaraWallDeflect(coll))
|
|
{
|
|
SetLaraWallDeflect(item, coll);
|
|
LaraCollideStop(item, coll);
|
|
}
|
|
|
|
// TODO: Hop back step height check is unique among the land traversal states. Appropriate to make test functions have extra parameters to account for this one case?
|
|
if (abs(coll->midFloor) > 0 && abs(coll->midFloor <= 200))
|
|
{
|
|
if (abs(coll->midFloor) >= 50)
|
|
{
|
|
item->pos.yPos += 50 * GetSign(coll->midFloor);
|
|
}
|
|
else
|
|
{
|
|
item->pos.yPos += coll->midFloor;
|
|
}
|
|
}
|
|
|
|
if (coll->midFloor >= 200)
|
|
{
|
|
item->goalAnimState = LS_FALL_BACK;
|
|
item->fallspeed = 0;
|
|
item->gravityStatus = true;
|
|
|
|
return;
|
|
}
|
|
|
|
if (TestLaraSlide(coll))
|
|
{
|
|
SetLaraSlide(item, coll);
|
|
return;
|
|
}
|
|
|
|
item->goalAnimState = LS_STOP;
|
|
}
|
|
|
|
// State: 6
|
|
// Collision: lara_col_turn_right()
|
|
void lara_as_turn_right(ITEM_INFO* item, COLL_INFO* coll)//19628(<), 1975C(<) (F)
|
|
{
|
|
if (item->hitPoints <= 0)
|
|
{
|
|
item->goalAnimState = LS_STOP;
|
|
return;
|
|
}
|
|
|
|
Lara.turnRate += LARA_TURN_RATE;
|
|
if (Lara.waterStatus == LW_WADE ||
|
|
Lara.gunStatus != LG_READY)
|
|
{
|
|
if (Lara.turnRate > ANGLE(4.0f))
|
|
{
|
|
item->goalAnimState = LS_TURN_RIGHT_FAST; // TODO: Investigate why a 1 frame WALK input causes an early dispatch to FAST_TURN instead of SIDESTEP.
|
|
}
|
|
}
|
|
else
|
|
{
|
|
item->goalAnimState = LS_TURN_RIGHT_FAST;
|
|
}
|
|
|
|
if (TrInput & IN_JUMP)
|
|
{
|
|
item->goalAnimState = LS_JUMP_PREPARE;
|
|
return;
|
|
}
|
|
|
|
//if (TrInput & IN_SPRINT)
|
|
//{
|
|
// item->goalAnimState = LS_SPRINT;
|
|
// return;
|
|
//}
|
|
|
|
if (TrInput & IN_DUCK &&
|
|
Lara.waterStatus != LW_WADE &&
|
|
(Lara.gunStatus == LG_NO_ARMS ||
|
|
Lara.gunType == WEAPON_NONE ||
|
|
Lara.gunType == WEAPON_PISTOLS ||
|
|
Lara.gunType == WEAPON_REVOLVER ||
|
|
Lara.gunType == WEAPON_UZI ||
|
|
Lara.gunType == WEAPON_FLARE))
|
|
{
|
|
item->goalAnimState = LS_CROUCH_IDLE;
|
|
return;
|
|
}
|
|
|
|
if (TrInput & IN_ROLL && Lara.waterStatus != LW_WADE)
|
|
{
|
|
item->goalAnimState = LS_ROLL_FORWARD;
|
|
return;
|
|
}
|
|
|
|
if (TrInput & IN_FORWARD)
|
|
{
|
|
if (Lara.waterStatus == LW_WADE)
|
|
{
|
|
item->goalAnimState = LS_WADE_FORWARD;
|
|
}
|
|
else if (TrInput & IN_WALK)
|
|
{
|
|
item->goalAnimState = LS_WALK_FORWARD;
|
|
}
|
|
else
|
|
{
|
|
item->goalAnimState = LS_RUN_FORWARD;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if (!(TrInput & IN_RIGHT))
|
|
{
|
|
item->goalAnimState = LS_STOP;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// State: 6
|
|
// State code: lara_as_turn_r()
|
|
void lara_col_turn_right(ITEM_INFO* item, COLL_INFO* coll) // (F) (D)
|
|
{
|
|
Lara.moveAngle = 0;
|
|
|
|
item->fallspeed = 0;
|
|
item->gravityStatus = false;
|
|
|
|
coll->badPos = STEPUP_HEIGHT;
|
|
coll->badNeg = -STEPUP_HEIGHT;
|
|
coll->badCeiling = 0;
|
|
coll->slopesAreWalls = 1;
|
|
coll->slopesArePits = true;
|
|
coll->facing = Lara.moveAngle;
|
|
|
|
GetCollisionInfo(coll, item->pos.xPos, item->pos.yPos, item->pos.zPos, item->roomNumber, LARA_HITE);
|
|
|
|
#if 1
|
|
if (coll->midFloor > 100)
|
|
#else
|
|
if (coll->midFloor > 100 && !(g_Level.Rooms[item->roomNumber].flags & ENV_FLAG_SWAMP))
|
|
#endif
|
|
{
|
|
item->goalAnimState = LS_FALL;
|
|
item->fallspeed = 0;
|
|
item->gravityStatus = true;
|
|
|
|
return;
|
|
}
|
|
|
|
if (TestLaraSlide(coll))
|
|
{
|
|
SetLaraSlide(item, coll);
|
|
return;
|
|
}
|
|
|
|
//return; ??
|
|
|
|
#if 1
|
|
if (coll->midFloor != NO_HEIGHT)
|
|
{
|
|
item->pos.yPos += coll->midFloor;
|
|
}
|
|
#else
|
|
if (!(g_Level.Rooms[item->roomNumber].flags & ENV_FLAG_SWAMP) || coll->midFloor < 0)
|
|
{
|
|
item->pos.yPos += coll->midFloor;
|
|
}
|
|
else if (g_Level.Rooms[item->roomNumber].flags & ENV_FLAG_SWAMP && coll->midFloor)
|
|
{
|
|
item->pos.yPos += SWAMP_GRAVITY;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// TODO: TURN_RIGHT_FAST is dispatched instead?!
|
|
// State: 7
|
|
// Collision: lara_col_turn()
|
|
void lara_as_turn_left(ITEM_INFO* item, COLL_INFO* coll)//1972C(<), 19860(<) (F)
|
|
{
|
|
if (item->hitPoints <= 0)
|
|
{
|
|
item->goalAnimState = LS_STOP;
|
|
return;
|
|
}
|
|
|
|
Lara.turnRate -= LARA_TURN_RATE;
|
|
if (Lara.waterStatus == LW_WADE ||
|
|
Lara.gunStatus != LG_READY)
|
|
{
|
|
if (Lara.turnRate < ANGLE(-4.0f))
|
|
{
|
|
item->goalAnimState = LS_TURN_LEFT_FAST;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
item->goalAnimState = LS_TURN_LEFT_FAST;
|
|
}
|
|
|
|
if (TrInput & IN_JUMP)
|
|
{
|
|
item->goalAnimState = LS_JUMP_PREPARE;
|
|
return;
|
|
}
|
|
|
|
//if (TrInput & IN_SPRINT)
|
|
//{
|
|
// item->goalAnimState = LS_SPRINT;
|
|
// return;
|
|
//}
|
|
|
|
if (TrInput & IN_DUCK &&
|
|
Lara.waterStatus != LW_WADE &&
|
|
(Lara.gunStatus == LG_NO_ARMS ||
|
|
Lara.gunType == WEAPON_NONE ||
|
|
Lara.gunType == WEAPON_PISTOLS ||
|
|
Lara.gunType == WEAPON_REVOLVER ||
|
|
Lara.gunType == WEAPON_UZI ||
|
|
Lara.gunType == WEAPON_FLARE))
|
|
{
|
|
item->goalAnimState = LS_CROUCH_IDLE;
|
|
return;
|
|
}
|
|
|
|
if (TrInput & IN_ROLL && Lara.waterStatus != LW_WADE)
|
|
{
|
|
item->goalAnimState = LS_ROLL_FORWARD;
|
|
return;
|
|
}
|
|
|
|
if (TrInput & IN_FORWARD)
|
|
{
|
|
if (Lara.waterStatus == LW_WADE)
|
|
{
|
|
item->goalAnimState = LS_WADE_FORWARD;
|
|
}
|
|
else if (TrInput & IN_WALK)
|
|
{
|
|
item->goalAnimState = LS_WALK_FORWARD;
|
|
}
|
|
else
|
|
{
|
|
item->goalAnimState = LS_RUN_FORWARD;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if (!(TrInput & IN_LEFT))
|
|
{
|
|
item->goalAnimState = LS_STOP;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// State: 6
|
|
// State code: lara_as_turn_left()
|
|
void lara_col_turn_left(ITEM_INFO* item, COLL_INFO* coll) // (F) (D)
|
|
{
|
|
lara_col_turn_right(item, coll);
|
|
}
|
|
|
|
// State: 8
|
|
// Collision: lara_col_death()
|
|
void lara_as_death(ITEM_INFO* item, COLL_INFO* coll)//19830(<), 19964(<) (F)
|
|
{
|
|
Lara.look = false;
|
|
|
|
coll->enableBaddiePush = false;
|
|
coll->enableSpaz = false;
|
|
|
|
if (BinocularRange)
|
|
{
|
|
BinocularRange = 0;
|
|
LaserSight = 0;
|
|
LaraItem->meshBits = -1;
|
|
Lara.busy = false;
|
|
|
|
AlterFOV(ANGLE(80.0f));
|
|
}
|
|
}
|
|
|
|
// State: 8
|
|
// State code: lara_as_death()
|
|
void lara_col_death(ITEM_INFO* item, COLL_INFO* coll)//1BADC(<), 1BC10(<) (F)
|
|
{
|
|
Lara.moveAngle = 0;
|
|
|
|
coll->badPos = 384;
|
|
coll->badNeg = -STEPUP_HEIGHT;
|
|
coll->badCeiling = 0;
|
|
coll->radius = 400;
|
|
coll->facing = Lara.moveAngle;
|
|
|
|
StopSoundEffect(SFX_LARA_FALL);
|
|
|
|
GetCollisionInfo(coll, item->pos.xPos, item->pos.yPos, item->pos.zPos, item->roomNumber, LARA_HITE);
|
|
ShiftItem(item, coll);
|
|
|
|
item->hitPoints = -1;
|
|
Lara.air = -1;
|
|
|
|
if (coll->midFloor != NO_HEIGHT)
|
|
{
|
|
item->pos.yPos += coll->midFloor;
|
|
}
|
|
}
|
|
|
|
// State: 9
|
|
// Collision: lara_col_freefall()
|
|
void lara_as_freefall(ITEM_INFO* item, COLL_INFO* coll)//198BC(<), 199F0(<) (F)
|
|
{
|
|
item->speed = (item->speed * 95) / 100;
|
|
if (item->fallspeed == 154)
|
|
{
|
|
SoundEffect(SFX_LARA_FALL, &item->pos, 0);
|
|
}
|
|
}
|
|
|
|
// State: 9
|
|
// State code: lara_as_freefall()
|
|
void lara_col_freefall(ITEM_INFO* item, COLL_INFO* coll)//1BB88, 1BCBC (F)
|
|
{
|
|
item->gravityStatus = true;
|
|
|
|
coll->badPos = NO_BAD_POS;
|
|
coll->badNeg = -STEPUP_HEIGHT;
|
|
coll->badCeiling = BAD_JUMP_CEILING;
|
|
coll->facing = Lara.moveAngle;
|
|
|
|
StopSoundEffect(SFX_LARA_FALL);
|
|
|
|
GetCollisionInfo(coll, item->pos.xPos, item->pos.yPos, item->pos.zPos, item->roomNumber, LARA_HITE);
|
|
PerformLaraSlideEdgeJump(item, coll);
|
|
|
|
if (coll->midFloor <= 0)
|
|
{
|
|
if (LaraLandedBad(item, coll))
|
|
{
|
|
item->goalAnimState = LS_DEATH;
|
|
}
|
|
else
|
|
{
|
|
item->goalAnimState = LS_STOP;
|
|
}
|
|
|
|
item->fallspeed = 0;
|
|
item->gravityStatus = false;
|
|
|
|
if (coll->midFloor != NO_HEIGHT)
|
|
{
|
|
item->pos.yPos += coll->midFloor;
|
|
}
|
|
}
|
|
}
|
|
|
|
// State: 11
|
|
// Collision: lara_col_reach()
|
|
void lara_as_reach(ITEM_INFO* item, COLL_INFO* coll)//18CE0(<), 18E14(<) (F)
|
|
{
|
|
Camera.targetAngle = ANGLE(85.0f);
|
|
|
|
if (item->fallspeed > LARA_FREEFALL_SPEED)
|
|
{
|
|
item->goalAnimState = LS_FREEFALL;
|
|
}
|
|
}
|
|
|
|
// State: 11
|
|
// State code: lara_as_reach()
|
|
void lara_col_reach(ITEM_INFO* item, COLL_INFO* coll)//18D0C, 18E40 (F)
|
|
{
|
|
if (Lara.ropePtr == -1)
|
|
{
|
|
item->gravityStatus = true;
|
|
}
|
|
|
|
Lara.moveAngle = 0;
|
|
|
|
coll->badPos = NO_BAD_POS;
|
|
coll->badNeg = 0;
|
|
coll->badCeiling = BAD_JUMP_CEILING;
|
|
coll->facing = Lara.moveAngle;
|
|
|
|
GetCollisionInfo(coll, item->pos.xPos, item->pos.yPos, item->pos.zPos, item->roomNumber, LARA_HITE);
|
|
|
|
short angle;
|
|
bool result = false;
|
|
int edge = 0;
|
|
int edgeCatch = 0;
|
|
|
|
if (TrInput & IN_ACTION &&
|
|
Lara.gunStatus == LG_NO_ARMS &&
|
|
!coll->hitStatic)
|
|
{
|
|
if (coll->collType == CT_TOP && Lara.canMonkeySwing)
|
|
{
|
|
Lara.headYrot = 0;
|
|
Lara.headXrot = 0;
|
|
Lara.torsoYrot = 0;
|
|
Lara.torsoXrot = 0;
|
|
Lara.gunStatus = LG_HANDS_BUSY;
|
|
|
|
// TODO: State dispatch. Doing it the obvious way results in a delay before the catch.
|
|
item->animNumber = LA_REACH_TO_MONKEYSWING;
|
|
item->frameNumber = g_Level.Anims[item->animNumber].frameBase;
|
|
item->goalAnimState = LS_MONKEYSWING_IDLE;
|
|
item->currentAnimState = LS_MONKEYSWING_IDLE;
|
|
item->gravityStatus = false;
|
|
item->speed = 0;
|
|
item->fallspeed = 0;
|
|
|
|
return;
|
|
}
|
|
|
|
if (coll->midCeiling <= -384 &&
|
|
coll->midFloor >= 200 &&
|
|
coll->collType == CT_FRONT)
|
|
{
|
|
edgeCatch = LaraTestEdgeCatch(item, coll, &edge);
|
|
|
|
if (!(!edgeCatch || edgeCatch < 0 && !LaraTestHangOnClimbWall(item, coll)))
|
|
{
|
|
angle = item->pos.yRot;
|
|
if (coll->midSplitFloor && coll->frontSplitFloor == coll->midSplitFloor)
|
|
{
|
|
result = SnapToDiagonal(angle, 35);
|
|
}
|
|
else
|
|
{
|
|
result = SnapToQuadrant(angle, 35);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!result)
|
|
{
|
|
PerformLaraSlideEdgeJump(item, coll);
|
|
coll->facing = Lara.moveAngle;
|
|
GetCollisionInfo(coll, item->pos.xPos, item->pos.yPos, item->pos.zPos, item->roomNumber, LARA_HITE);
|
|
ShiftItem(item, coll);
|
|
|
|
if (item->fallspeed > 0 && coll->midFloor <= 0)
|
|
{
|
|
if (LaraLandedBad(item, coll))
|
|
{
|
|
item->goalAnimState = LS_DEATH;
|
|
}
|
|
else
|
|
{
|
|
item->goalAnimState = LS_STOP;
|
|
item->fallspeed = 0;
|
|
item->gravityStatus = false;
|
|
|
|
if (coll->midFloor != NO_HEIGHT)
|
|
{
|
|
item->pos.yPos += coll->midFloor;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (TestHangSwingIn(item, angle))
|
|
{
|
|
Lara.headYrot = 0;
|
|
Lara.headXrot = 0;
|
|
Lara.torsoYrot = 0;
|
|
Lara.torsoXrot = 0;
|
|
item->animNumber = LA_REACH_TO_HANG_OSCILLATE;
|
|
item->frameNumber = g_Level.Anims[item->animNumber].frameBase;
|
|
item->currentAnimState = LS_HANG;
|
|
item->goalAnimState = LS_HANG;
|
|
item->gravityStatus = false;
|
|
item->speed = 0;
|
|
item->fallspeed = 0;
|
|
}
|
|
else
|
|
{
|
|
if (TestHangFeet(item, angle))
|
|
{
|
|
item->animNumber = LA_REACH_TO_HANG;
|
|
item->frameNumber = g_Level.Anims[item->animNumber].frameBase;
|
|
item->currentAnimState = LS_HANG;
|
|
item->goalAnimState = LS_HANG_FEET;
|
|
}
|
|
else
|
|
{
|
|
item->animNumber = LA_REACH_TO_HANG;
|
|
item->frameNumber = g_Level.Anims[item->animNumber].frameBase;
|
|
item->currentAnimState = LS_HANG;
|
|
item->goalAnimState = LS_HANG;
|
|
}
|
|
}
|
|
|
|
BOUNDING_BOX* bounds = GetBoundsAccurate(item);
|
|
|
|
if (edgeCatch <= 0)
|
|
{
|
|
item->pos.yPos = edge - bounds->Y1 - 22;
|
|
}
|
|
else
|
|
{
|
|
item->pos.yPos += coll->frontFloor - bounds->Y1;
|
|
|
|
if (coll->midSplitFloor)
|
|
{
|
|
Vector2 v = GetDiagonalIntersect(item->pos.xPos, item->pos.zPos, coll->midSplitFloor, LARA_RAD, angle);
|
|
item->pos.xPos = v.x;
|
|
item->pos.zPos = v.y;
|
|
}
|
|
else
|
|
{
|
|
Vector2 v = GetOrthogonalIntersect(item->pos.xPos, item->pos.zPos, LARA_RAD, angle);
|
|
item->pos.xPos = v.x;
|
|
item->pos.zPos = v.y;
|
|
}
|
|
}
|
|
|
|
item->pos.yRot = angle;
|
|
item->gravityStatus = true;
|
|
item->speed = 2;
|
|
item->fallspeed = 1;
|
|
|
|
Lara.gunStatus = LG_HANDS_BUSY;
|
|
}
|
|
}
|
|
|
|
void lara_as_splat(ITEM_INFO* item, COLL_INFO* coll)//1A340(<), 1A474(<) (F)
|
|
{
|
|
Lara.look = false;
|
|
}
|
|
|
|
void lara_col_splat(ITEM_INFO* item, COLL_INFO* coll)//1BC74(<), 1BDA8(<) (F)
|
|
{
|
|
Lara.moveAngle = 0;
|
|
|
|
coll->slopesAreWalls = true;
|
|
coll->slopesArePits = true;
|
|
coll->badPos = 384;
|
|
coll->badNeg = -STEPUP_HEIGHT;
|
|
coll->badCeiling = 0;
|
|
coll->facing = Lara.moveAngle;
|
|
|
|
GetCollisionInfo(coll, item->pos.xPos, item->pos.yPos, item->pos.zPos, item->roomNumber, LARA_HITE);
|
|
|
|
ShiftItem(item, coll);
|
|
|
|
if (coll->midFloor >= -256 && coll->midFloor <= 256)
|
|
{
|
|
item->pos.yPos += coll->midFloor;
|
|
}
|
|
}
|
|
|
|
// State: 15
|
|
// Collision: lara_col_jump_prepare()
|
|
void lara_as_jump_prepare(ITEM_INFO* item, COLL_INFO* coll)
|
|
{
|
|
if (Lara.waterStatus != LW_WADE)
|
|
{
|
|
// TODO: Check ceilings as well.
|
|
if (TrInput & IN_FORWARD && LaraFloorFront(item, item->pos.yRot, 256) >= -384)
|
|
{
|
|
item->goalAnimState = LS_JUMP_FORWARD;
|
|
Lara.moveAngle = 0;
|
|
}
|
|
else if (TrInput & IN_BACK && LaraFloorFront(item, item->pos.yRot - ANGLE(180.0f), 256) >= -384)
|
|
{
|
|
item->goalAnimState = LS_JUMP_BACK;
|
|
Lara.moveAngle = ANGLE(180.0f);
|
|
}
|
|
else if (TrInput & IN_LEFT && LaraFloorFront(item, item->pos.yRot - ANGLE(90.0f), 256) >= -384)
|
|
{
|
|
item->goalAnimState = LS_JUMP_LEFT;
|
|
Lara.moveAngle = ANGLE(-90.0f);
|
|
}
|
|
else if (TrInput & IN_RIGHT && LaraFloorFront(item, item->pos.yRot + ANGLE(90.0f), 256) >= -384)
|
|
{
|
|
item->goalAnimState = LS_JUMP_RIGHT;
|
|
Lara.moveAngle = ANGLE(90.0f);
|
|
}
|
|
else if (TrInput & IN_ROLL)
|
|
{
|
|
item->goalAnimState = LS_JUMP_ROLL_180;
|
|
}
|
|
//else
|
|
//{
|
|
// // Cancel jump preparation if the ceiling in a chosen direction is too low.
|
|
//}
|
|
}
|
|
|
|
if (item->fallspeed > LARA_FREEFALL_SPEED)
|
|
{
|
|
item->goalAnimState = LS_FREEFALL;
|
|
}
|
|
}
|
|
|
|
// State: 15
|
|
// State code: lara_as_jump_prepare()
|
|
void lara_col_jump_prepare(ITEM_INFO* item, COLL_INFO* coll)//1BD30, 1BE64 (F)
|
|
{
|
|
item->fallspeed = 0;
|
|
item->gravityStatus = false;
|
|
|
|
coll->badPos = NO_BAD_POS;
|
|
coll->badNeg = NO_HEIGHT;
|
|
coll->badCeiling = 0;
|
|
coll->facing = Lara.moveAngle;
|
|
|
|
GetCollisionInfo(coll, item->pos.xPos, item->pos.yPos, item->pos.zPos, item->roomNumber, LARA_HITE);
|
|
|
|
if (TestLaraFall(coll))
|
|
{
|
|
item->goalAnimState = LS_FALL;
|
|
item->fallspeed = 0;
|
|
item->gravityStatus = true;
|
|
|
|
return;
|
|
}
|
|
|
|
// G A R B A G E.
|
|
// TODO: Dispatch crouch if ceiling lowers.
|
|
if (coll->midCeiling > -100)
|
|
{
|
|
item->animNumber = LA_STAND_SOLID; // <- This anim needs to go!!
|
|
item->frameNumber = g_Level.Anims[item->animNumber].frameBase;
|
|
item->goalAnimState = LS_STOP;
|
|
item->currentAnimState = LS_STOP;
|
|
|
|
item->speed = 0;
|
|
item->fallspeed = 0;
|
|
item->gravityStatus = false;
|
|
|
|
item->pos.xPos = coll->old.x;
|
|
item->pos.yPos = coll->old.y;
|
|
item->pos.zPos = coll->old.z;
|
|
}
|
|
|
|
if (coll->midFloor > -256 && coll->midFloor < 256)
|
|
{
|
|
item->pos.yPos += coll->midFloor;
|
|
}
|
|
}
|
|
|
|
// State: 16
|
|
// Collision: lara_col_walk_back()
|
|
void lara_as_walk_back(ITEM_INFO* item, COLL_INFO* coll)//1A4F0(<), 1A624(<) (F)
|
|
{
|
|
if (item->hitPoints <= 0)
|
|
{
|
|
item->goalAnimState = LS_STOP;
|
|
return;
|
|
}
|
|
|
|
if (Lara.isMoving)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (TrInput & IN_LEFT)
|
|
{
|
|
Lara.turnRate -= LARA_TURN_RATE;
|
|
if (Lara.turnRate < ANGLE(-4.0f))
|
|
{
|
|
Lara.turnRate = ANGLE(-4.0f);
|
|
}
|
|
}
|
|
else if (TrInput & IN_RIGHT)
|
|
{
|
|
Lara.turnRate += LARA_TURN_RATE;
|
|
if (Lara.turnRate > ANGLE(4.0f))
|
|
{
|
|
Lara.turnRate = ANGLE(4.0f);
|
|
}
|
|
}
|
|
|
|
if (TrInput & IN_JUMP)
|
|
{
|
|
item->goalAnimState = LS_JUMP_PREPARE; // TODO
|
|
return;
|
|
}
|
|
|
|
if (TrInput & IN_BACK &&
|
|
(TrInput & IN_WALK || Lara.waterStatus == LW_WADE))
|
|
{
|
|
item->goalAnimState = LS_WALK_BACK;
|
|
return;
|
|
}
|
|
|
|
item->goalAnimState = LS_STOP;
|
|
}
|
|
|
|
// State: 16
|
|
// State code: lara_as_walk_back()
|
|
void lara_col_walk_back(ITEM_INFO* item, COLL_INFO* coll) // (F) (D)
|
|
{
|
|
item->gravityStatus = false;
|
|
item->fallspeed = 0;
|
|
Lara.moveAngle = ANGLE(180.0f);
|
|
|
|
if (Lara.waterStatus == LW_WADE)
|
|
{
|
|
coll->badPos = NO_BAD_POS;
|
|
}
|
|
else
|
|
{
|
|
coll->badPos = STEPUP_HEIGHT;
|
|
}
|
|
|
|
coll->badNeg = -STEPUP_HEIGHT;
|
|
coll->badCeiling = 0;
|
|
coll->slopesArePits = true;
|
|
coll->slopesAreWalls = 1;
|
|
coll->facing = Lara.moveAngle;
|
|
|
|
GetCollisionInfo(coll, item->pos.xPos, item->pos.yPos, item->pos.zPos, item->roomNumber, LARA_HITE);
|
|
|
|
if (LaraHitCeiling(item, coll))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (LaraDeflectEdge(item, coll))
|
|
{
|
|
LaraCollideStop(item, coll);
|
|
}
|
|
|
|
if (TestLaraFall(coll))
|
|
{
|
|
item->goalAnimState = LS_FALL;
|
|
item->fallspeed = 0;
|
|
item->gravityStatus = true;
|
|
|
|
return;
|
|
}
|
|
|
|
if (abs(coll->midFloor) > 0 && abs(coll->midFloor <= STEPUP_HEIGHT))
|
|
{
|
|
// Like the hop back, step back is also unique. TODO: Make step test/set functions take extra parameters.
|
|
if (TestLaraStepDown(coll))
|
|
{
|
|
item->pos.yPos += coll->midFloor;
|
|
|
|
item->goalAnimState = LS_STEP_BACK_DOWN;
|
|
GetChange(item, &g_Level.Anims[item->animNumber]);
|
|
}
|
|
/*else if (TestLaraStepUp(coll))
|
|
{
|
|
item->pos.yPos += coll->midFloor;
|
|
|
|
item->goalAnimState = LS_STEP_BACK_UP;
|
|
GetChange(item, &g_Level.Anims[item->animNumber]);
|
|
}*/
|
|
else if (abs(coll->midFloor) >= 50)
|
|
{
|
|
item->pos.yPos += 50 * GetSign(coll->midFloor);
|
|
}
|
|
else
|
|
{
|
|
item->pos.yPos += coll->midFloor;
|
|
}
|
|
}
|
|
|
|
if (TestLaraSlide(coll))
|
|
{
|
|
SetLaraSlide(item, coll);
|
|
return;
|
|
}
|
|
|
|
#if 0
|
|
if (!(g_Level.Rooms[item->roomNumber].flags & ENV_FLAG_SWAMP) || coll->midFloor < 0)
|
|
{
|
|
item->pos.yPos += coll->midFloor;
|
|
}
|
|
else if (g_Level.Rooms[item->roomNumber].flags & ENV_FLAG_SWAMP && coll->midFloor)
|
|
{
|
|
item->pos.yPos += SWAMP_GRAVITY;
|
|
}
|
|
#else
|
|
//if (coll->midFloor != NO_HEIGHT)
|
|
//{
|
|
// item->pos.yPos += coll->midFloor;
|
|
//}
|
|
#endif
|
|
}
|
|
|
|
// State: 20
|
|
// Collision: lara_col_fast_turn_right()
|
|
void lara_as_turn_right_fast(ITEM_INFO* item, COLL_INFO* coll)
|
|
{
|
|
if (item->hitPoints <= 0)
|
|
{
|
|
item->goalAnimState = LS_STOP;
|
|
return;
|
|
}
|
|
|
|
Lara.turnRate = LARA_FAST_TURN;
|
|
|
|
if (TrInput & IN_JUMP)
|
|
{
|
|
item->goalAnimState = LS_JUMP_PREPARE;
|
|
return;
|
|
}
|
|
|
|
if (TrInput & IN_ROLL && Lara.waterStatus != LW_WADE)
|
|
{
|
|
item->goalAnimState = LS_ROLL_FORWARD;
|
|
return;
|
|
}
|
|
|
|
if (TrInput & IN_DUCK &&
|
|
Lara.waterStatus != LW_WADE &&
|
|
(Lara.gunStatus == LG_NO_ARMS ||
|
|
Lara.gunType == WEAPON_NONE ||
|
|
Lara.gunType == WEAPON_PISTOLS ||
|
|
Lara.gunType == WEAPON_REVOLVER ||
|
|
Lara.gunType == WEAPON_UZI ||
|
|
Lara.gunType == WEAPON_FLARE))
|
|
{
|
|
item->goalAnimState = LS_CROUCH_IDLE;
|
|
return;
|
|
}
|
|
|
|
if (TrInput & IN_FORWARD)
|
|
{
|
|
if (Lara.waterStatus == LW_WADE) // Failsafe.
|
|
{
|
|
item->goalAnimState = LS_WADE_FORWARD;
|
|
}
|
|
else if (TrInput & IN_WALK)
|
|
{
|
|
item->goalAnimState = LS_WALK_FORWARD;
|
|
}
|
|
else
|
|
{
|
|
item->goalAnimState = LS_RUN_FORWARD;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if (!(TrInput & IN_RIGHT))
|
|
{
|
|
item->goalAnimState = LS_STOP;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// State: 20
|
|
// State code: lara_as_turn_right_fast()
|
|
void lara_col_turn_right_fast(ITEM_INFO* item, COLL_INFO* coll)
|
|
{
|
|
lara_col_stop(item, coll); // TODO: Investigate why collision is different to regular turn.
|
|
}
|
|
|
|
// State: 157
|
|
// State code: lara_as_turn_left_fast()
|
|
void lara_as_turn_left_fast(ITEM_INFO* item, COLL_INFO* coll)
|
|
{
|
|
if (item->hitPoints <= 0)
|
|
{
|
|
item->goalAnimState = LS_STOP;
|
|
return;
|
|
}
|
|
|
|
Lara.turnRate = -LARA_FAST_TURN;
|
|
|
|
if (TrInput & IN_JUMP)
|
|
{
|
|
item->goalAnimState = LS_JUMP_PREPARE;
|
|
return;
|
|
}
|
|
|
|
if (TrInput & IN_ROLL && Lara.waterStatus != LW_WADE)
|
|
{
|
|
item->goalAnimState = LS_ROLL_FORWARD;
|
|
return;
|
|
}
|
|
|
|
if (TrInput & IN_DUCK &&
|
|
Lara.waterStatus != LW_WADE &&
|
|
(Lara.gunStatus == LG_NO_ARMS ||
|
|
Lara.gunType == WEAPON_NONE ||
|
|
Lara.gunType == WEAPON_PISTOLS ||
|
|
Lara.gunType == WEAPON_REVOLVER ||
|
|
Lara.gunType == WEAPON_UZI ||
|
|
Lara.gunType == WEAPON_FLARE))
|
|
{
|
|
item->goalAnimState = LS_CROUCH_IDLE;
|
|
return;
|
|
}
|
|
|
|
if (TrInput & IN_FORWARD)
|
|
{
|
|
if (Lara.waterStatus == LW_WADE) // Failsafe.
|
|
{
|
|
item->goalAnimState = LS_WADE_FORWARD;
|
|
}
|
|
else if (TrInput & IN_WALK)
|
|
{
|
|
item->goalAnimState = LS_WALK_FORWARD;
|
|
}
|
|
else
|
|
{
|
|
item->goalAnimState = LS_RUN_FORWARD;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if (!(TrInput & IN_LEFT))
|
|
{
|
|
item->goalAnimState = LS_STOP;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// State: 157
|
|
// State code: lara_as_turn_left_fast()
|
|
void lara_col_turn_left_fast(ITEM_INFO* item, COLL_INFO* coll)
|
|
{
|
|
lara_col_turn_right_fast(item, coll);
|
|
}
|
|
|
|
// State: 21
|
|
// Collision: lara_col_sidestep()
|
|
void lara_as_step_right(ITEM_INFO* item, COLL_INFO* coll)//1A67C(<), 1A7B0(<) (F)
|
|
{
|
|
Lara.look = false;
|
|
|
|
if (item->hitPoints <= 0)
|
|
{
|
|
item->goalAnimState = LS_STOP;
|
|
return;
|
|
}
|
|
|
|
if (Lara.isMoving)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (TrInput & IN_LEFT)
|
|
{
|
|
Lara.turnRate -= LARA_TURN_RATE;
|
|
if (Lara.turnRate < ANGLE(-4.0f))
|
|
{
|
|
Lara.turnRate = ANGLE(-4.0f);
|
|
}
|
|
}
|
|
else if (TrInput & IN_RIGHT)
|
|
{
|
|
Lara.turnRate += LARA_TURN_RATE;
|
|
if (Lara.turnRate > ANGLE(4.0f))
|
|
{
|
|
Lara.turnRate = ANGLE(4.0f);
|
|
}
|
|
}
|
|
|
|
if (TrInput & IN_RSTEP)
|
|
{
|
|
item->goalAnimState = LS_STEP_RIGHT;
|
|
return;
|
|
}
|
|
|
|
item->goalAnimState = LS_STOP;
|
|
}
|
|
|
|
// State: 21
|
|
// State code: lara_as_step_right()
|
|
void lara_col_step_right(ITEM_INFO* item, COLL_INFO* coll)//1BFB0, 1C0E4 (F)
|
|
{
|
|
Lara.moveAngle = ANGLE(90.0f);
|
|
|
|
item->gravityStatus = false;
|
|
item->fallspeed = 0;
|
|
|
|
if (Lara.waterStatus == LW_WADE)
|
|
{
|
|
coll->badPos = NO_BAD_POS;
|
|
}
|
|
else
|
|
{
|
|
coll->badPos = 128;
|
|
}
|
|
|
|
coll->slopesAreWalls = true;
|
|
coll->slopesArePits = true;
|
|
coll->badNeg = -128;
|
|
coll->badCeiling = 0;
|
|
coll->facing = Lara.moveAngle;
|
|
|
|
GetCollisionInfo(coll, item->pos.xPos, item->pos.yPos, item->pos.zPos, item->roomNumber, LARA_HITE);
|
|
|
|
if (TestLaraHitCeiling(coll))
|
|
{
|
|
SetLaraHitCeiling(item, coll);
|
|
return;
|
|
}
|
|
|
|
if (TestLaraWallDeflect(coll))
|
|
{
|
|
SetLaraWallDeflect(item, coll);
|
|
LaraCollideStop(item, coll);
|
|
}
|
|
|
|
if (TestLaraFall(coll))
|
|
{
|
|
item->goalAnimState = LS_FALL;
|
|
item->fallspeed = 0;
|
|
item->gravityStatus = true;
|
|
|
|
return;
|
|
}
|
|
|
|
if (abs(coll->midFloor) > 0 && coll->midFloor != NO_HEIGHT)
|
|
{
|
|
if (abs(coll->midFloor) >= 50)
|
|
{
|
|
item->pos.yPos += 50 * GetSign(coll->midFloor);
|
|
}
|
|
else
|
|
{
|
|
item->pos.yPos += coll->midFloor;
|
|
}
|
|
}
|
|
|
|
if (TestLaraSlide(coll))
|
|
{
|
|
SetLaraSlide(item, coll);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// State: 22
|
|
// Collision: lara_col_sidestep()
|
|
void lara_as_step_left(ITEM_INFO* item, COLL_INFO* coll)//1A750(<), 1A884(<) (F)
|
|
{
|
|
Lara.look = false;
|
|
|
|
if (item->hitPoints <= 0)
|
|
{
|
|
item->goalAnimState = LS_STOP;
|
|
return;
|
|
}
|
|
|
|
if (Lara.isMoving)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (TrInput & IN_LEFT)
|
|
{
|
|
Lara.turnRate -= LARA_TURN_RATE;
|
|
if (Lara.turnRate < -LARA_SLOW_TURN)
|
|
{
|
|
Lara.turnRate = -LARA_SLOW_TURN;
|
|
}
|
|
}
|
|
else if (TrInput & IN_RIGHT)
|
|
{
|
|
Lara.turnRate += LARA_TURN_RATE;
|
|
if (Lara.turnRate > LARA_SLOW_TURN)
|
|
{
|
|
Lara.turnRate = LARA_SLOW_TURN;
|
|
}
|
|
}
|
|
|
|
if (TrInput & IN_LSTEP)
|
|
{
|
|
item->goalAnimState = LS_STEP_LEFT;
|
|
return;
|
|
}
|
|
|
|
item->goalAnimState = LS_STOP;
|
|
}
|
|
|
|
// State: 22
|
|
// State code: lara_as_step_left()
|
|
void lara_col_step_left(ITEM_INFO* item, COLL_INFO* coll)//1BFB0, 1C0E4 (F)
|
|
{
|
|
Lara.moveAngle = ANGLE(-90.0f);
|
|
|
|
item->gravityStatus = false;
|
|
item->fallspeed = 0;
|
|
|
|
if (Lara.waterStatus == LW_WADE)
|
|
{
|
|
coll->badPos = NO_BAD_POS;
|
|
}
|
|
else
|
|
{
|
|
coll->badPos = 128;
|
|
}
|
|
|
|
coll->slopesAreWalls = true;
|
|
coll->slopesArePits = true;
|
|
coll->badNeg = -128;
|
|
coll->badCeiling = 0;
|
|
coll->facing = Lara.moveAngle;
|
|
|
|
GetCollisionInfo(coll, item->pos.xPos, item->pos.yPos, item->pos.zPos, item->roomNumber, LARA_HITE);
|
|
|
|
if (TestLaraHitCeiling(coll))
|
|
{
|
|
SetLaraHitCeiling(item, coll);
|
|
return;
|
|
}
|
|
|
|
if (TestLaraWallDeflect(coll))
|
|
{
|
|
SetLaraWallDeflect(item, coll);
|
|
LaraCollideStop(item, coll);
|
|
}
|
|
|
|
if (TestLaraFall(coll))
|
|
{
|
|
item->goalAnimState = LS_FALL;
|
|
item->fallspeed = 0;
|
|
item->gravityStatus = true;
|
|
|
|
return;
|
|
}
|
|
|
|
if (abs(coll->midFloor) > 0 && coll->midFloor != NO_HEIGHT)
|
|
{
|
|
if (abs(coll->midFloor) >= 50)
|
|
{
|
|
item->pos.yPos += 50 * GetSign(coll->midFloor);
|
|
}
|
|
else
|
|
{
|
|
item->pos.yPos += coll->midFloor;
|
|
}
|
|
}
|
|
|
|
if (TestLaraSlide(coll))
|
|
{
|
|
SetLaraSlide(item, coll);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// State: 23
|
|
// State code: lara_void_func()
|
|
void lara_col_roll2(ITEM_INFO* item, COLL_INFO* coll)//1C384, 1C4B8 (F)
|
|
{
|
|
Camera.laraNode = 0;
|
|
|
|
Lara.moveAngle = ANGLE(180.0f);
|
|
|
|
item->gravityStatus = false;
|
|
item->fallspeed = 0;
|
|
|
|
coll->badPos = NO_BAD_POS;
|
|
coll->badNeg = -STEPUP_HEIGHT;
|
|
coll->badCeiling = 0;
|
|
coll->slopesAreWalls = true;
|
|
coll->facing = Lara.moveAngle;
|
|
|
|
GetCollisionInfo(coll, item->pos.xPos, item->pos.yPos, item->pos.zPos, item->roomNumber, LARA_HITE);
|
|
|
|
if (LaraHitCeiling(item, coll))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (TestLaraSlide(coll))
|
|
{
|
|
SetLaraSlide(item, coll);
|
|
return;
|
|
}
|
|
|
|
if (coll->midFloor > 200)
|
|
{
|
|
// TODO: not working?
|
|
item->goalAnimState = LS_FALL_BACK;
|
|
item->fallspeed = 0;
|
|
item->gravityStatus = true;
|
|
|
|
return;
|
|
}
|
|
|
|
ShiftItem(item, coll);
|
|
|
|
if (coll->midFloor != NO_HEIGHT)
|
|
item->pos.yPos += coll->midFloor;
|
|
}
|
|
|
|
// State: 25
|
|
// Cllision: lara_col_jump_back()
|
|
void lara_as_jump_back(ITEM_INFO* item, COLL_INFO* coll)//1A854(<), 1A988(<) (F)
|
|
{
|
|
Camera.targetAngle = ANGLE(135.0f);
|
|
Lara.look = false;
|
|
|
|
//if (item->hitPoints <= 0)
|
|
//{
|
|
// item->goalAnimState = LS_DEATH;
|
|
// return;
|
|
//}
|
|
|
|
if (item->fallspeed > LARA_FREEFALL_SPEED)
|
|
{
|
|
item->goalAnimState = LS_FREEFALL;
|
|
return;
|
|
}
|
|
|
|
if ((TrInput & IN_ROLL ||
|
|
TrInput & IN_FORWARD && EnableBackKeyTurn) &&
|
|
item->goalAnimState != LS_STOP)
|
|
{
|
|
item->goalAnimState = LS_JUMP_ROLL_180;
|
|
return;
|
|
}
|
|
|
|
//item->goalAnimState = LS_JUMP_BACK;
|
|
}
|
|
|
|
// State: 25
|
|
// State code: lara_as_jump_back()
|
|
void lara_col_jump_back(ITEM_INFO* item, COLL_INFO* coll)//1C130(<), 1C264(<) (F)
|
|
{
|
|
Lara.moveAngle = ANGLE(180.0f);
|
|
lara_col_jump(item, coll);
|
|
}
|
|
|
|
// State: 26
|
|
// Collision: lara_col_jump_right()
|
|
//
|
|
void lara_as_jump_right(ITEM_INFO* item, COLL_INFO* coll)//1A8C4(<), 1A9F8(<) (F)
|
|
{
|
|
Lara.look = false;
|
|
|
|
//if (item->hitPoints <= 0)
|
|
//{
|
|
// item->goalAnimState = LS_DEATH;
|
|
// return;
|
|
//}
|
|
|
|
if (item->fallspeed > LARA_FREEFALL_SPEED)
|
|
{
|
|
item->goalAnimState = LS_FREEFALL;
|
|
return;
|
|
}
|
|
|
|
//if (TrInput & IN_ACTION)
|
|
//{
|
|
// item->goalAnimState = LS_REACH;
|
|
// return;
|
|
//}
|
|
|
|
if ((TrInput & IN_ROLL ||
|
|
TrInput & IN_LEFT && EnableBackKeyTurn) &&
|
|
item->goalAnimState != LS_STOP)
|
|
{
|
|
item->goalAnimState = LS_JUMP_ROLL_180;
|
|
return;
|
|
}
|
|
|
|
//item->goalAnimState = LS_JUMP_RIGHT;
|
|
}
|
|
|
|
// State: 26
|
|
// State code: lara_as_jump_right()
|
|
void lara_col_jump_right(ITEM_INFO* item, COLL_INFO* coll)//1C15C(<), 1C290(<) (F)
|
|
{
|
|
Lara.moveAngle = ANGLE(90.0f);
|
|
lara_col_jump(item, coll);
|
|
}
|
|
|
|
// State: 27
|
|
// Collision: lara_col_jump_left()
|
|
void lara_as_jump_left(ITEM_INFO* item, COLL_INFO* coll)//1A92C(<), 1AA60(<) (F)
|
|
{
|
|
Lara.look = false;
|
|
|
|
//if (item->hitPoints <= 0)
|
|
//{
|
|
// item->goalAnimState = LS_DEATH;
|
|
// return;
|
|
//}
|
|
|
|
if (item->fallspeed > LARA_FREEFALL_SPEED)
|
|
{
|
|
item->goalAnimState = LS_FREEFALL;
|
|
return;
|
|
}
|
|
|
|
//if (TrInput & IN_ACTION)
|
|
//{
|
|
// item->goalAnimState = LS_REACH;
|
|
// return;
|
|
//}
|
|
|
|
if ((TrInput & IN_ROLL ||
|
|
TrInput & IN_RIGHT && EnableBackKeyTurn) &&
|
|
item->goalAnimState != LS_STOP)
|
|
{
|
|
item->goalAnimState = LS_JUMP_ROLL_180;
|
|
return;
|
|
}
|
|
|
|
//item->goalAnimState = LS_JUMP_LEFT;
|
|
}
|
|
|
|
// State: 27
|
|
// State code: lara_as_jump_left()
|
|
void lara_col_jump_left(ITEM_INFO* item, COLL_INFO* coll)//1C188(<), 1C2BC(<) (F)
|
|
{
|
|
Lara.moveAngle = ANGLE(-90.0f);
|
|
lara_col_jump(item, coll);
|
|
}
|
|
|
|
|
|
// States: 25, 26, 27
|
|
// State code: none; called in lara_col_jump_back(), lara_col_jump_right(), lara_col_jump_left()
|
|
void lara_col_jump(ITEM_INFO* item, COLL_INFO* coll)
|
|
{
|
|
coll->badPos = NO_BAD_POS;
|
|
coll->badNeg = -STEPUP_HEIGHT;
|
|
coll->badCeiling = BAD_JUMP_CEILING;
|
|
coll->facing = Lara.moveAngle;
|
|
|
|
GetCollisionInfo(coll, item->pos.xPos, item->pos.yPos, item->pos.zPos, item->roomNumber, LARA_HITE);
|
|
LaraDeflectEdgeJump(item, coll);
|
|
|
|
if (item->fallspeed > 0 && coll->midFloor <= 0)
|
|
{
|
|
if (LaraLandedBad(item, coll))
|
|
{
|
|
item->goalAnimState = LS_DEATH;
|
|
}
|
|
else
|
|
{
|
|
item->goalAnimState = LS_STOP;
|
|
}
|
|
|
|
item->fallspeed = 0;
|
|
item->gravityStatus = 0;
|
|
|
|
if (coll->midFloor != NO_HEIGHT)
|
|
{
|
|
item->pos.yPos += coll->midFloor;
|
|
}
|
|
}
|
|
}
|
|
|
|
// State: 28
|
|
// Collision: lara_col_jump_up()
|
|
void lara_as_jump_up(ITEM_INFO* item, COLL_INFO* coll)
|
|
{
|
|
if (item->hitPoints <= 0)
|
|
{
|
|
item->goalAnimState = LS_STOP;
|
|
return;
|
|
}
|
|
|
|
if (item->fallspeed > LARA_FREEFALL_SPEED)
|
|
{
|
|
item->goalAnimState = LS_FREEFALL;
|
|
return;
|
|
}
|
|
|
|
item->goalAnimState = LS_JUMP_UP;
|
|
}
|
|
|
|
// State: 28
|
|
// State code: lara_as_jump_up()
|
|
void lara_col_jump_up(ITEM_INFO* item, COLL_INFO* coll)
|
|
{
|
|
Lara.moveAngle = 0;
|
|
|
|
coll->badPos = NO_BAD_POS;
|
|
coll->badNeg = -STEPUP_HEIGHT;
|
|
coll->badCeiling = BAD_JUMP_CEILING;
|
|
coll->hitCeiling = false;
|
|
coll->facing = item->speed < 0 ? Lara.moveAngle + ANGLE(180.0f) : Lara.moveAngle;
|
|
|
|
GetCollisionInfo(coll, item->pos.xPos, item->pos.yPos, item->pos.zPos, item->roomNumber, 870);
|
|
|
|
if (TrInput & IN_ACTION &&
|
|
Lara.gunStatus == LG_NO_ARMS &&
|
|
!coll->hitStatic)
|
|
{
|
|
if (Lara.canMonkeySwing && coll->collType == CT_TOP)
|
|
{
|
|
Lara.gunStatus = LG_HANDS_BUSY;
|
|
|
|
item->goalAnimState = LS_MONKEYSWING_IDLE;
|
|
item->gravityStatus = false;
|
|
item->speed = 0;
|
|
item->fallspeed = 0;
|
|
|
|
MonkeySwingSnap(item, coll);
|
|
|
|
return;
|
|
}
|
|
|
|
if (coll->collType == CT_FRONT &&
|
|
coll->midCeiling <= -STEPUP_HEIGHT)
|
|
{
|
|
int edge;
|
|
int edgeCatch = LaraTestEdgeCatch(item, coll, &edge);
|
|
|
|
if (edgeCatch)
|
|
{
|
|
if (edgeCatch >= 0 || LaraTestHangOnClimbWall(item, coll))
|
|
{
|
|
short angle = item->pos.yRot;
|
|
bool result;
|
|
|
|
if (coll->midSplitFloor && coll->frontSplitFloor == coll->midSplitFloor)
|
|
{
|
|
result = SnapToDiagonal(angle, 35);
|
|
}
|
|
else
|
|
{
|
|
result = SnapToQuadrant(angle, 35);
|
|
}
|
|
|
|
if (result)
|
|
{
|
|
BOUNDING_BOX* bounds;
|
|
|
|
if (TestHangSwingIn(item, angle))
|
|
{
|
|
item->animNumber = LA_JUMP_UP_TO_MONKEYSWING;
|
|
item->frameNumber = g_Level.Anims[item->animNumber].frameBase;
|
|
item->goalAnimState = LS_MONKEYSWING_IDLE;
|
|
item->currentAnimState = LS_MONKEYSWING_IDLE;
|
|
}
|
|
else
|
|
{
|
|
if (TestHangFeet(item, angle))
|
|
{
|
|
item->animNumber = LA_REACH_TO_HANG;
|
|
item->frameNumber = g_Level.Anims[item->animNumber].frameBase + 12;
|
|
item->currentAnimState = LS_HANG;
|
|
item->goalAnimState = LS_HANG_FEET;
|
|
}
|
|
else
|
|
{
|
|
item->goalAnimState = LS_HANG;
|
|
}
|
|
}
|
|
|
|
bounds = GetBoundsAccurate(item);
|
|
|
|
if (edgeCatch <= 0)
|
|
{
|
|
item->pos.yPos = edge - bounds->Y1 + 4;
|
|
}
|
|
else
|
|
{
|
|
item->pos.yPos += coll->frontFloor - bounds->Y1;
|
|
}
|
|
|
|
if (coll->midSplitFloor)
|
|
{
|
|
Vector2 v = GetDiagonalIntersect(item->pos.xPos, item->pos.zPos, coll->midSplitFloor, LARA_RAD, item->pos.yRot);
|
|
item->pos.xPos = v.x;
|
|
item->pos.zPos = v.y;
|
|
}
|
|
else
|
|
{
|
|
Vector2 v = GetOrthogonalIntersect(item->pos.xPos, item->pos.zPos, LARA_RAD, item->pos.yRot);
|
|
item->pos.xPos = v.x;
|
|
item->pos.zPos = v.y;
|
|
}
|
|
item->pos.yRot = angle;
|
|
|
|
item->gravityStatus = false;
|
|
item->speed = 0;
|
|
item->fallspeed = 0;
|
|
|
|
Lara.gunStatus = LG_HANDS_BUSY;
|
|
Lara.torsoYrot = 0;
|
|
Lara.torsoXrot = 0;
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ShiftItem(item, coll);
|
|
|
|
if (coll->collType == CT_CLAMP ||
|
|
coll->collType == CT_TOP ||
|
|
coll->collType == CT_TOP_FRONT ||
|
|
coll->hitCeiling)
|
|
{
|
|
item->fallspeed = 1;
|
|
}
|
|
|
|
if (coll->collType == CT_NONE)
|
|
{
|
|
if (item->fallspeed < -70)
|
|
{
|
|
if (TrInput & IN_FORWARD && item->speed < 5)
|
|
{
|
|
item->speed++;
|
|
}
|
|
else if (TrInput & IN_BACK && item->speed > -5)
|
|
{
|
|
item->speed -= 2;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
item->speed = item->speed <= 0 ? -2 : 2;
|
|
}
|
|
|
|
if (item->fallspeed > 0 && coll->midFloor <= 0)
|
|
{
|
|
item->goalAnimState = LaraLandedBad(item, coll) ? LS_DEATH : LS_STOP;
|
|
|
|
item->gravityStatus = false;
|
|
item->fallspeed = 0;
|
|
|
|
if (coll->midFloor != NO_HEIGHT)
|
|
{
|
|
item->pos.yPos += coll->midFloor;
|
|
}
|
|
}
|
|
}
|
|
|
|
// State: 29
|
|
// Collision: lara_col_fall_back()
|
|
void lara_as_fall_back(ITEM_INFO* item, COLL_INFO* coll)//1959C(<), 196D0(<) (F)
|
|
{
|
|
if (item->fallspeed > LARA_FREEFALL_SPEED)
|
|
{
|
|
item->goalAnimState = LS_FREEFALL;
|
|
return;
|
|
}
|
|
|
|
if (TrInput & IN_ACTION &&
|
|
Lara.gunStatus == LG_NO_ARMS)
|
|
{
|
|
item->goalAnimState = LS_REACH;
|
|
return;
|
|
}
|
|
|
|
item->goalAnimState = LS_FALL_BACK;
|
|
}
|
|
|
|
// State: 29
|
|
// State code: lara_as_fall_back()
|
|
void lara_col_fall_back(ITEM_INFO* item, COLL_INFO* coll)//1C1B4(<), 1C2E8(<) (F)
|
|
{
|
|
Lara.moveAngle = ANGLE(180.0f);
|
|
|
|
coll->badPos = NO_BAD_POS;
|
|
coll->badNeg = -STEPUP_HEIGHT;
|
|
coll->badCeiling = BAD_JUMP_CEILING;
|
|
coll->facing = Lara.moveAngle;
|
|
|
|
GetCollisionInfo(coll, item->pos.xPos, item->pos.yPos, item->pos.zPos, item->roomNumber, LARA_HITE);
|
|
LaraDeflectEdgeJump(item, coll);
|
|
|
|
if (item->fallspeed > 0 && coll->midFloor <= 0)
|
|
{
|
|
if (LaraLandedBad(item, coll))
|
|
{
|
|
item->goalAnimState = LS_DEATH;
|
|
}
|
|
else
|
|
{
|
|
item->goalAnimState = LS_STOP;
|
|
}
|
|
|
|
item->fallspeed = 0;
|
|
item->gravityStatus = 0;
|
|
|
|
if (coll->midFloor != NO_HEIGHT)
|
|
{
|
|
item->pos.yPos += coll->midFloor;
|
|
}
|
|
}
|
|
}
|
|
|
|
// State: 45
|
|
// State code: lara_void_func()
|
|
void lara_col_roll(ITEM_INFO* item, COLL_INFO* coll)//1C2B0, 1C3E4 (F)
|
|
{
|
|
Lara.moveAngle = 0;
|
|
|
|
item->gravityStatus = false;
|
|
item->fallspeed = 0;
|
|
|
|
coll->badPos = NO_BAD_POS;
|
|
coll->badNeg = -STEPUP_HEIGHT;
|
|
coll->badCeiling = 0;
|
|
coll->slopesArePits = false;
|
|
coll->slopesAreWalls = true;
|
|
coll->facing = Lara.moveAngle;
|
|
|
|
GetCollisionInfo(coll, item->pos.xPos, item->pos.yPos, item->pos.zPos, item->roomNumber, LARA_HITE);
|
|
|
|
if (LaraHitCeiling(item, coll))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (TestLaraSlide(coll))
|
|
{
|
|
SetLaraSlide(item, coll);
|
|
return;
|
|
}
|
|
|
|
if (TestLaraFall(coll))
|
|
{
|
|
item->goalAnimState = LS_FALL;
|
|
item->fallspeed = 0;
|
|
item->gravityStatus = true;
|
|
|
|
return;
|
|
}
|
|
|
|
if (TrInput & IN_FORWARD &&
|
|
item->animNumber == LA_SWANDIVE_ROLL)
|
|
{
|
|
item->goalAnimState = LS_RUN_FORWARD;
|
|
}
|
|
|
|
ShiftItem(item, coll);
|
|
|
|
if (coll->midFloor != NO_HEIGHT)
|
|
{
|
|
item->pos.yPos += coll->midFloor;
|
|
}
|
|
}
|
|
|
|
// State: 52
|
|
// Collision: lara_col_swandive_start()
|
|
void lara_as_swandive_start(ITEM_INFO* item, COLL_INFO* coll)//1AE08(<), 1AF3C(<) (F)
|
|
{
|
|
coll->enableBaddiePush = true;
|
|
coll->enableSpaz = false;
|
|
|
|
if (item->fallspeed > LARA_FREEFALL_SPEED
|
|
&& item->goalAnimState != LS_DIVE)
|
|
{
|
|
item->goalAnimState = LS_SWANDIVE_END;
|
|
return;
|
|
}
|
|
|
|
item->goalAnimState = LS_SWANDIVE_START;
|
|
}
|
|
|
|
// State: 52
|
|
// State code: lara_as_swandive_start()
|
|
void lara_col_swandive_start(ITEM_INFO* item, COLL_INFO* coll)//1C4A0(<), 1C5D4(<) (F)
|
|
{
|
|
Lara.moveAngle = 0;
|
|
|
|
coll->badPos = NO_BAD_POS;
|
|
coll->badNeg = -STEPUP_HEIGHT;
|
|
coll->badCeiling = BAD_JUMP_CEILING;
|
|
coll->facing = Lara.moveAngle;
|
|
|
|
GetCollisionInfo(coll, item->pos.xPos, item->pos.yPos, item->pos.zPos, item->roomNumber, LARA_HITE);
|
|
LaraDeflectEdgeJump(item, coll);
|
|
|
|
if (coll->midFloor <= 0 && item->fallspeed > 0)
|
|
{
|
|
item->goalAnimState = LS_STOP;
|
|
item->fallspeed = 0;
|
|
item->gravityStatus = 0;
|
|
|
|
if (coll->midFloor != NO_HEIGHT)
|
|
{
|
|
item->pos.yPos += coll->midFloor;
|
|
}
|
|
}
|
|
}
|
|
|
|
// State: 53
|
|
// Collision: lara_col_swandive_freefall()
|
|
void lara_as_swandive_freefall(ITEM_INFO* item, COLL_INFO* coll)//1AE4C(<), 1AF80(<) (F)
|
|
{
|
|
item->speed = (item->speed * 95) / 100;
|
|
|
|
coll->enableBaddiePush = true;
|
|
coll->enableSpaz = false;
|
|
|
|
if (TrInput & IN_ROLL ||
|
|
(TrInput & IN_BACK && EnableBackKeyTurn))
|
|
{
|
|
item->goalAnimState = LS_JUMP_ROLL_180;
|
|
return;
|
|
}
|
|
|
|
item->goalAnimState = LS_SWANDIVE_END;
|
|
}
|
|
|
|
// State: 53
|
|
// State code: lara_as_swandive_freefall()
|
|
void lara_col_swandive_freefall(ITEM_INFO* item, COLL_INFO* coll)//1C558(<), 1C68C(<) (F)
|
|
{
|
|
Lara.moveAngle = 0;
|
|
|
|
coll->badPos = NO_BAD_POS;
|
|
coll->badNeg = -STEPUP_HEIGHT;
|
|
coll->badCeiling = BAD_JUMP_CEILING;
|
|
coll->facing = Lara.moveAngle;
|
|
|
|
GetCollisionInfo(coll, item->pos.xPos, item->pos.yPos, item->pos.zPos, item->roomNumber, LARA_HITE);
|
|
LaraDeflectEdgeJump(item, coll);
|
|
|
|
if (coll->midFloor <= 0 && item->fallspeed > 0)
|
|
{
|
|
if (item->fallspeed <= 133)
|
|
{
|
|
item->goalAnimState = LS_STOP;
|
|
}
|
|
else
|
|
{
|
|
item->goalAnimState = LS_DEATH;
|
|
}
|
|
|
|
item->fallspeed = 0;
|
|
item->gravityStatus = 0;
|
|
|
|
if (coll->midFloor != NO_HEIGHT)
|
|
{
|
|
item->pos.yPos += coll->midFloor;
|
|
}
|
|
}
|
|
}
|
|
|
|
// State: 54
|
|
// Collision: lara_default_col()
|
|
void lara_as_gymnast(ITEM_INFO* item, COLL_INFO* coll)//1AEC8(<), 1AFFC(<) (F)
|
|
{
|
|
coll->enableBaddiePush = false;
|
|
coll->enableSpaz = false;
|
|
}
|
|
|
|
// State: 65
|
|
// Collision: lara_col_wade()
|
|
void lara_as_wade(ITEM_INFO* item, COLL_INFO* coll)//1AF10, 1B044 (F)
|
|
{
|
|
Camera.targetElevation = ANGLE(-22.0f);
|
|
|
|
if (item->hitPoints <= 0)
|
|
{
|
|
item->goalAnimState = LS_STOP;
|
|
return;
|
|
}
|
|
|
|
if (g_Level.Rooms[item->roomNumber].flags & ENV_FLAG_SWAMP)
|
|
{
|
|
if (TrInput & IN_LEFT)
|
|
{
|
|
Lara.turnRate -= LARA_TURN_RATE;
|
|
if (Lara.turnRate < -(LARA_FAST_TURN / 2))
|
|
{
|
|
Lara.turnRate = -(LARA_FAST_TURN / 2);
|
|
}
|
|
}
|
|
else if (TrInput & IN_RIGHT)
|
|
{
|
|
Lara.turnRate += LARA_TURN_RATE;
|
|
if (Lara.turnRate > (LARA_FAST_TURN / 2))
|
|
{
|
|
Lara.turnRate = (LARA_FAST_TURN / 2);
|
|
}
|
|
}
|
|
|
|
if (TrInput & IN_FORWARD)
|
|
{
|
|
item->goalAnimState = LS_WADE_FORWARD;
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (TrInput & IN_LEFT)
|
|
{
|
|
Lara.turnRate -= LARA_TURN_RATE;
|
|
if (Lara.turnRate < -LARA_FAST_TURN)
|
|
{
|
|
Lara.turnRate = -LARA_FAST_TURN;
|
|
}
|
|
}
|
|
else if (TrInput & IN_RIGHT)
|
|
{
|
|
Lara.turnRate += LARA_TURN_RATE;
|
|
if (Lara.turnRate > LARA_FAST_TURN)
|
|
{
|
|
Lara.turnRate = LARA_FAST_TURN;
|
|
}
|
|
}
|
|
|
|
if (TrInput & IN_FORWARD)
|
|
{
|
|
if (Lara.waterStatus == LW_ABOVE_WATER)
|
|
{
|
|
item->goalAnimState = LS_RUN_FORWARD;
|
|
}
|
|
else
|
|
{
|
|
item->goalAnimState = LS_WADE_FORWARD;
|
|
}
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
item->goalAnimState = LS_STOP;
|
|
}
|
|
|
|
// State: 65
|
|
// State code: lara_as_wade()
|
|
void lara_col_wade(ITEM_INFO* item, COLL_INFO* coll)
|
|
{
|
|
Lara.moveAngle = 0;
|
|
|
|
coll->badPos = NO_BAD_POS;
|
|
coll->badNeg = -STEPUP_HEIGHT;
|
|
coll->badCeiling = 0;
|
|
coll->slopesAreWalls = true;
|
|
coll->facing = Lara.moveAngle;
|
|
|
|
GetCollisionInfo(coll, item->pos.xPos, item->pos.yPos, item->pos.zPos, item->roomNumber, LARA_HITE);
|
|
|
|
if (g_Level.Rooms[item->roomNumber].flags & ENV_FLAG_SWAMP)
|
|
{
|
|
if (TrInput & IN_LEFT)
|
|
{
|
|
if (TestLaraLean(coll))
|
|
{
|
|
item->pos.zRot -= LARA_LEAN_RATE;
|
|
if (item->pos.zRot < -(LARA_LEAN_MAX / 2))
|
|
{
|
|
item->pos.zRot = -(LARA_LEAN_MAX / 2);
|
|
}
|
|
}
|
|
}
|
|
else if (TrInput & IN_RIGHT)
|
|
{
|
|
if (TestLaraLean(coll))
|
|
{
|
|
item->pos.zRot += LARA_LEAN_RATE;
|
|
if (item->pos.zRot > (LARA_LEAN_MAX / 2))
|
|
{
|
|
item->pos.zRot = (LARA_LEAN_MAX / 2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (TrInput & IN_LEFT)
|
|
{
|
|
if (TestLaraLean(coll))
|
|
{
|
|
item->pos.zRot -= LARA_LEAN_RATE;
|
|
if (item->pos.zRot < -LARA_LEAN_MAX)
|
|
{
|
|
item->pos.zRot = -LARA_LEAN_MAX;
|
|
}
|
|
}
|
|
}
|
|
else if (TrInput & IN_RIGHT)
|
|
{
|
|
if (TestLaraLean(coll))
|
|
{
|
|
item->pos.zRot += LARA_LEAN_RATE;
|
|
if (item->pos.zRot > LARA_LEAN_MAX)
|
|
{
|
|
item->pos.zRot = LARA_LEAN_MAX;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (TestLaraVault(item, coll))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (LaraHitCeiling(item, coll))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (LaraDeflectEdge(item, coll))
|
|
{
|
|
item->pos.zRot = 0;
|
|
|
|
|
|
if ((coll->frontType == WALL || coll->frontType == SPLIT_TRI) &&
|
|
coll->frontFloor < -((STEP_SIZE * 5) / 2) &&
|
|
!(g_Level.Rooms[item->roomNumber].flags & ENV_FLAG_SWAMP))
|
|
{
|
|
item->goalAnimState = LS_SPLAT;
|
|
if (GetChange(item, &g_Level.Anims[item->animNumber]))
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
LaraCollideStop(item, coll);
|
|
}
|
|
|
|
if (abs(coll->midFloor) > 0 && abs(coll->midFloor <= STEPUP_HEIGHT) &&
|
|
!(g_Level.Rooms[item->roomNumber].flags & ENV_FLAG_SWAMP))
|
|
{
|
|
//DoLaraStep(item, coll); // Uncomment this line and remove everything below when a step down anim is created.
|
|
|
|
/*if (TestLaraStepDown(coll))
|
|
{
|
|
item->pos.yPos += coll->midFloor;
|
|
|
|
item->goalAnimState = LS_STEP_DOWN;
|
|
GetChange(item, &g_Level.Anims[item->animNumber]);
|
|
}
|
|
else */if (TestLaraStepUp(coll))
|
|
{
|
|
item->pos.yPos += coll->midFloor;
|
|
|
|
item->goalAnimState = LS_STEP_UP;
|
|
GetChange(item, &g_Level.Anims[item->animNumber]);
|
|
}
|
|
else if (abs(coll->midFloor) >= 50)
|
|
{
|
|
item->pos.yPos += 50 * GetSign(coll->midFloor);
|
|
}
|
|
else
|
|
{
|
|
item->pos.yPos += coll->midFloor;
|
|
}
|
|
}
|
|
|
|
/*if (!(g_Level.Rooms[item->roomNumber].flags & ENV_FLAG_SWAMP) || coll->midFloor < 0)
|
|
{
|
|
item->pos.yPos += coll->midFloor; // Enforce to floor height.. if not a swamp room.
|
|
}
|
|
else */if (g_Level.Rooms[item->roomNumber].flags & ENV_FLAG_SWAMP && coll->midFloor)
|
|
{
|
|
item->pos.yPos += SWAMP_GRAVITY;
|
|
}
|
|
}
|
|
|
|
// State: 73
|
|
// Collision: lara_col_sprint()
|
|
void lara_as_sprint(ITEM_INFO* item, COLL_INFO* coll)//15A28, 15B5C (F)
|
|
{
|
|
if (item->hitPoints <= 0)
|
|
{
|
|
item->goalAnimState = LS_RUN_FORWARD; // item->goalAnimState = LS_DEATH;
|
|
return;
|
|
}
|
|
|
|
if (TrInput & IN_LEFT)
|
|
{
|
|
Lara.turnRate -= LARA_TURN_RATE;
|
|
if (Lara.turnRate < ANGLE(-4.0f))
|
|
{
|
|
Lara.turnRate = ANGLE(-4.0f);
|
|
}
|
|
}
|
|
else if (TrInput & IN_RIGHT)
|
|
{
|
|
Lara.turnRate += LARA_TURN_RATE;
|
|
if (Lara.turnRate > ANGLE(4.0f))
|
|
{
|
|
Lara.turnRate = ANGLE(4.0f);
|
|
}
|
|
}
|
|
|
|
if (TrInput & IN_JUMP || item->gravityStatus)
|
|
{
|
|
if (LaraFloorFront(item, item->pos.yRot, 1600) >= 384) // Something fun. However, the range should be probed rather than the final location.
|
|
{
|
|
item->goalAnimState = LS_SWANDIVE_START;
|
|
}
|
|
else
|
|
{
|
|
item->goalAnimState = LS_SPRINT_ROLL;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if (TrInput & IN_DUCK &&
|
|
(Lara.gunStatus == LG_NO_ARMS ||
|
|
Lara.gunType == WEAPON_NONE ||
|
|
Lara.gunType == WEAPON_PISTOLS ||
|
|
Lara.gunType == WEAPON_REVOLVER ||
|
|
Lara.gunType == WEAPON_UZI ||
|
|
Lara.gunType == WEAPON_FLARE))
|
|
{
|
|
item->goalAnimState = LS_CROUCH_IDLE;
|
|
return;
|
|
}
|
|
|
|
if (!(TrInput & IN_SPRINT) || !DashTimer ||
|
|
Lara.waterStatus == LW_WADE)
|
|
{
|
|
item->goalAnimState = LS_RUN_FORWARD;
|
|
return;
|
|
}
|
|
|
|
DashTimer--;
|
|
|
|
if (TrInput & IN_FORWARD)
|
|
{
|
|
if (TrInput & IN_WALK)
|
|
{
|
|
item->goalAnimState = LS_WALK_FORWARD;
|
|
}
|
|
else
|
|
{
|
|
item->goalAnimState = LS_SPRINT;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// Legacy doesn't require FORWARD to be held when sprinting. Keep original behaviour?
|
|
//if (TrInput & IN_LEFT || TrInput & IN_RIGHT)
|
|
//{
|
|
// item->goalAnimState = LS_SPRINT;
|
|
// return;
|
|
//}
|
|
|
|
item->goalAnimState = LS_STOP;
|
|
}
|
|
|
|
// State: 73
|
|
// State code: lara_as_sprint()
|
|
void lara_col_sprint(ITEM_INFO* item, COLL_INFO* coll)//15C50, 15D84 (F)
|
|
{
|
|
Lara.moveAngle = 0;
|
|
|
|
coll->badPos = NO_BAD_POS;
|
|
coll->badNeg = -STEPUP_HEIGHT;
|
|
coll->badCeiling = 0;
|
|
coll->slopesAreWalls = true;
|
|
coll->facing = Lara.moveAngle;
|
|
|
|
if (TrInput & IN_LEFT)
|
|
{
|
|
if (TestLaraLean(coll))
|
|
{
|
|
item->pos.zRot -= ANGLE(1.5f);
|
|
if (item->pos.zRot < ANGLE(-16.0f))
|
|
{
|
|
item->pos.zRot = ANGLE(-16.0f);
|
|
}
|
|
}
|
|
}
|
|
else if (TrInput & IN_RIGHT)
|
|
{
|
|
item->pos.zRot += ANGLE(1.5f);
|
|
if (item->pos.zRot > ANGLE(16.0f))
|
|
{
|
|
item->pos.zRot = ANGLE(16.0f);
|
|
}
|
|
}
|
|
|
|
GetCollisionInfo(coll, item->pos.xPos, item->pos.yPos, item->pos.zPos, item->roomNumber, LARA_HITE);
|
|
|
|
if (TestLaraVault(item, coll))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (TestLaraHitCeiling(coll))
|
|
{
|
|
SetLaraHitCeiling(item, coll);
|
|
return;
|
|
}
|
|
|
|
if (LaraDeflectEdge(item, coll))
|
|
{
|
|
item->pos.zRot = 0;
|
|
|
|
if (TestWall(item, 256, 0, -640))
|
|
{
|
|
item->goalAnimState = LS_SPLAT;
|
|
if (GetChange(item, &g_Level.Anims[item->animNumber]))
|
|
{
|
|
item->currentAnimState = LS_SPLAT;
|
|
return;
|
|
}
|
|
}
|
|
|
|
LaraCollideStop(item, coll);
|
|
}
|
|
|
|
if (TestLaraFall(coll))
|
|
{
|
|
item->goalAnimState = LS_FALL;
|
|
item->fallspeed = 0;
|
|
item->gravityStatus = true;
|
|
|
|
return;
|
|
}
|
|
|
|
// TODO: Step dispatches are the normal run step up anims. This is why Lara sprints up stairs like a dolt.
|
|
if (abs(coll->midFloor) > 0 && abs(coll->midFloor <= STEPUP_HEIGHT))
|
|
{
|
|
/*if (TestLaraStepDown(coll))
|
|
{
|
|
item->pos.yPos += coll->midFloor;
|
|
|
|
item->goalAnimState = LS_STEP_DOWN;
|
|
GetChange(item, &g_Level.Anims[item->animNumber]);
|
|
}
|
|
else */if (TestLaraStepUp(coll))
|
|
{
|
|
item->pos.yPos += coll->midFloor;
|
|
|
|
item->goalAnimState = LS_STEP_UP;
|
|
GetChange(item, &g_Level.Anims[item->animNumber]);
|
|
}
|
|
else if (abs(coll->midFloor) >= 50)
|
|
{
|
|
item->pos.yPos += 50 * GetSign(coll->midFloor);
|
|
}
|
|
else
|
|
{
|
|
item->pos.yPos += coll->midFloor;
|
|
}
|
|
}
|
|
|
|
if (TestLaraSlide(coll))
|
|
{
|
|
SetLaraSlide(item, coll);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// State: 74
|
|
// Collision: lara_col_sprint_roll()
|
|
void lara_as_sprint_roll(ITEM_INFO* item, COLL_INFO* coll)//15E1C(<), 15F50(<) (F)
|
|
{
|
|
//if (item->hitPoints <= 0)
|
|
//{
|
|
// item->goalAnimState = LS_DEATH;
|
|
// return;
|
|
//}
|
|
|
|
if (TrInput & IN_LEFT)
|
|
{
|
|
Lara.turnRate -= LARA_TURN_RATE;
|
|
if (Lara.turnRate < ANGLE(-4.0f))
|
|
{
|
|
Lara.turnRate = ANGLE(-4.0f);
|
|
}
|
|
}
|
|
else if (TrInput & IN_RIGHT)
|
|
{
|
|
Lara.turnRate += LARA_TURN_RATE;
|
|
if (Lara.turnRate > ANGLE(4.0f))
|
|
{
|
|
Lara.turnRate = ANGLE(4.0f);
|
|
}
|
|
}
|
|
|
|
if (TrInput & IN_FORWARD) // Not necessary...
|
|
{
|
|
item->goalAnimState = LS_RUN_FORWARD;
|
|
return;
|
|
}
|
|
|
|
item->goalAnimState = LS_STOP;
|
|
|
|
//LEGACY.
|
|
//if (item->goalAnimState != LS_DEATH &&
|
|
// item->goalAnimState != LS_STOP &&
|
|
// item->goalAnimState != LS_RUN_FORWARD &&
|
|
// item->fallspeed > LARA_FREEFALL_SPEED)
|
|
//{
|
|
// item->goalAnimState = LS_FREEFALL; // Hmm? It's not possible to go into a freefall from this state.
|
|
//}
|
|
}
|
|
|
|
// State: 74
|
|
// State code: lara_as_sprint_dive()
|
|
void lara_col_sprint_roll(ITEM_INFO* item, COLL_INFO* coll)//15E5C, 15F90 (F)
|
|
{
|
|
if (item->speed < 0) // Is this necessary??
|
|
{
|
|
Lara.moveAngle = ANGLE(180.0f);
|
|
}
|
|
else
|
|
{
|
|
Lara.moveAngle = 0;
|
|
}
|
|
|
|
coll->badPos = NO_BAD_POS;
|
|
coll->badNeg = -256;
|
|
coll->badCeiling = BAD_JUMP_CEILING;
|
|
coll->slopesAreWalls = true;
|
|
coll->facing = Lara.moveAngle;
|
|
|
|
GetCollisionInfo(coll, item->pos.xPos, item->pos.yPos, item->pos.zPos, item->roomNumber, LARA_HITE);
|
|
LaraDeflectEdgeJump(item, coll);
|
|
|
|
if (TrInput & IN_LEFT)
|
|
{
|
|
if (TestLaraLean(coll))
|
|
{
|
|
item->pos.zRot -= ANGLE(1.5f);
|
|
if (item->pos.zRot < ANGLE(-16.0f))
|
|
{
|
|
item->pos.zRot = ANGLE(-16.0f);
|
|
}
|
|
}
|
|
}
|
|
else if (TrInput & IN_RIGHT)
|
|
{
|
|
item->pos.zRot += ANGLE(1.5f);
|
|
if (item->pos.zRot > ANGLE(16.0f))
|
|
{
|
|
item->pos.zRot = ANGLE(16.0f);
|
|
}
|
|
}
|
|
|
|
if (TestLaraFall(coll))
|
|
{
|
|
item->goalAnimState = LS_FALL;
|
|
item->fallspeed = 0;
|
|
item->gravityStatus = true;
|
|
|
|
return;
|
|
|
|
if (item->speed < 0)
|
|
{
|
|
Lara.moveAngle = 0;
|
|
}
|
|
|
|
if (coll->midFloor <= 0 && item->fallspeed > 0)
|
|
{
|
|
item->gravityStatus = false;
|
|
item->fallspeed = 0;
|
|
item->pos.yPos += coll->midFloor;
|
|
item->speed = 0;
|
|
|
|
if (LaraLandedBad(item, coll))
|
|
{
|
|
item->goalAnimState = LS_DEATH;
|
|
}
|
|
else if (Lara.waterStatus == LW_WADE || !(TrInput & IN_FORWARD) || TrInput & IN_WALK)
|
|
{
|
|
item->goalAnimState = LS_STOP;
|
|
}
|
|
else
|
|
{
|
|
item->goalAnimState = LS_RUN_FORWARD;
|
|
}
|
|
|
|
AnimateLara(item);
|
|
}
|
|
|
|
ShiftItem(item, coll);
|
|
|
|
if (coll->midFloor != NO_HEIGHT)
|
|
{
|
|
item->pos.yPos += coll->midFloor;
|
|
}
|
|
}
|
|
}
|