TombEngine/TR5Main/Game/Lara/lara.cpp

1086 lines
26 KiB
C++
Raw Normal View History

2020-12-21 13:16:29 -03:00
#include "framework.h"
2021-12-22 16:23:57 +03:00
#include "Game/Lara/lara.h"
2021-12-24 03:32:19 +03:00
2021-12-22 16:23:57 +03:00
#include "Game/Lara/lara_basic.h"
#include "Game/Lara/lara_helpers.h"
#include "Game/Lara/lara_jump.h"
#include "Game/Lara/lara_tests.h"
#include "Game/Lara/lara_monkey.h"
#include "Game/Lara/lara_crawl.h"
#include "Game/Lara/lara_objects.h"
#include "Game/Lara/lara_hang.h"
#include "Game/Lara/lara_slide.h"
#include "Game/Lara/lara_fire.h"
#include "Game/Lara/lara_surface.h"
#include "Game/Lara/lara_swim.h"
#include "Game/Lara/lara_one_gun.h"
#include "Game/Lara/lara_cheat.h"
#include "Game/Lara/lara_climb.h"
#include "Game/Lara/lara_overhang.h"
2021-12-22 16:23:57 +03:00
#include "Game/Lara/lara_initialise.h"
2020-12-21 13:16:29 -03:00
2021-12-22 16:23:57 +03:00
#include "Game/animation.h"
2021-12-24 03:32:19 +03:00
#include "Game/camera.h"
#include "Game/collision/collide_item.h"
2021-12-22 16:23:57 +03:00
#include "Game/control/flipeffect.h"
#include "Game/control/volume.h"
2021-11-22 18:55:29 +03:00
#include "Game/effects/lara_fx.h"
2021-11-23 02:53:52 +03:00
#include "Game/effects/tomb4fx.h"
2021-12-24 03:32:19 +03:00
#include "Game/gui.h"
#include "Game/items.h"
#include "Game/misc.h"
#include "Game/savegame.h"
#include "Scripting/GameFlowScript.h"
#include "Sound/sound.h"
#include "Renderer/Renderer11.h"
2021-11-22 18:55:29 +03:00
using namespace TEN::Effects::Lara;
using namespace TEN::Control::Volumes;
2020-12-21 13:16:29 -03:00
using std::function;
2021-08-30 18:03:21 +03:00
using TEN::Renderer::g_Renderer;
2020-12-21 13:16:29 -03:00
LaraInfo Lara;
ITEM_INFO* LaraItem;
2021-09-16 01:12:19 +03:00
COLL_INFO LaraCollision = {};
2020-12-21 13:16:29 -03:00
byte LaraNodeUnderwater[NUM_LARA_MESHES];
2021-09-15 16:58:53 +03:00
function<LaraRoutineFunction> lara_control_routines[NUM_LARA_STATES + 1] =
{
lara_as_walk_forward,
lara_as_run_forward,
lara_as_idle,
lara_as_jump_forward,//33
lara_as_pose,//4
lara_as_run_back,//5
lara_as_turn_right_slow,//6
lara_as_turn_left_slow,//7
2020-12-21 13:16:29 -03:00
lara_as_death,//8
2021-12-21 23:29:51 +11:00
lara_as_freefall,//9
2020-12-21 13:16:29 -03:00
lara_as_hang,
lara_as_reach,
lara_as_splat,
lara_as_tread,
lara_void_func,
lara_as_jump_prepare,//15
lara_as_walk_back,//16
2020-12-21 13:16:29 -03:00
lara_as_swim,//17
lara_as_glide,//18
lara_as_controlled_no_look,//19
lara_as_turn_right_fast,//20
lara_as_step_right,//21
lara_as_step_left,//22
lara_as_roll_back,
2021-12-18 20:42:15 +11:00
lara_as_slide_forward,//24
2021-12-22 00:39:03 +11:00
lara_as_jump_back,//25
lara_as_jump_right,//26
lara_as_jump_left,//27
lara_as_jump_up,//28
2021-12-20 21:37:38 +11:00
lara_as_fall_back,//29
2020-12-21 13:16:29 -03:00
lara_as_hangleft,//30
lara_as_hangright,//31
2021-12-18 20:42:15 +11:00
lara_as_slide_back,//32
2020-12-21 13:16:29 -03:00
lara_as_surftread,
lara_as_surfswim,
lara_as_dive,
lara_as_pushable_push,//36
lara_as_pushable_pull,//37
lara_as_pushable_grab,//38
2020-12-21 13:16:29 -03:00
lara_as_pickup,//39
lara_as_switch_on,//40
lara_as_switch_off,//41
lara_as_use_key,//42
lara_as_use_puzzle,//43
2020-12-21 13:16:29 -03:00
lara_as_uwdeath,//44
lara_as_roll_forward,//45
2020-12-21 13:16:29 -03:00
lara_as_special,//46
lara_as_surfback,//47
lara_as_surfleft,//48
lara_as_surfright,//49
lara_void_func,//50
lara_void_func,//51
lara_as_swan_dive,//52
lara_as_freefall_dive,//53
2020-12-21 13:16:29 -03:00
lara_as_gymnast,//54
2022-02-05 23:13:31 +11:00
lara_as_waterout,//55
lara_as_climbstnc,//56
lara_as_climbing,//57
lara_as_climbleft,//58
lara_as_climbend,//59
lara_as_climbright,//60
lara_as_climbdown,//61
2022-02-17 15:01:48 +11:00
lara_as_auto_jump,//62
2022-02-05 23:13:31 +11:00
lara_void_func,//63
lara_void_func,//64
lara_as_wade_forward,//65
2020-12-21 13:16:29 -03:00
lara_as_waterroll,//66
lara_as_pickup_flare,//67
2020-12-21 13:16:29 -03:00
lara_void_func,//68
lara_void_func,//69
lara_as_zip_line,//70
lara_as_crouch_idle,//71
2020-12-21 13:16:29 -03:00
lara_as_crouch_roll,//72
2022-02-05 23:13:31 +11:00
lara_as_sprint,//73
lara_as_sprint_dive,//74
lara_as_monkey_idle,//75
2022-01-12 19:33:41 +11:00
lara_as_monkey_forward,//76
2022-01-12 19:58:37 +11:00
lara_as_monkey_shimmy_left,//77
lara_as_monkey_shimmy_right,//78
2022-01-12 19:04:29 +11:00
lara_as_monkey_turn_180,//79
lara_as_crawl_idle,//80
lara_as_crawl_forward,//81
2022-01-12 19:04:29 +11:00
lara_as_monkey_turn_left,//82
lara_as_monkey_turn_right,//83
lara_as_crawl_turn_left,//84
lara_as_crawl_turn_right,//85
lara_as_crawl_back,//86
lara_as_controlled_no_look,
lara_as_controlled_no_look,
2020-12-21 13:16:29 -03:00
lara_as_controlled,
lara_as_rope_turn_clockwise,
lara_as_rope_turn_counter_clockwise,
2020-12-21 13:16:29 -03:00
lara_as_controlled,
lara_as_controlled,
lara_as_controlled,
lara_as_controlled_no_look,
lara_as_controlled_no_look,
2020-12-21 13:16:29 -03:00
lara_as_controlled,
lara_as_pickup,//98
2021-11-21 20:50:17 +11:00
lara_as_pole_idle,//99
lara_as_pole_up,//100
lara_as_pole_down,//101
lara_as_pole_turn_clockwise,//102
lara_as_pole_turn_counter_clockwise,//103
2020-12-21 13:16:29 -03:00
lara_as_pulley,//104
lara_as_crouch_turn_left,//105
lara_as_crouch_turn_right,//106
2021-11-30 03:39:24 +03:00
lara_as_corner,//107
lara_as_corner,//108
lara_as_corner,//109
lara_as_corner,//110
lara_as_rope_idle,//111
lara_as_rope_up,//112
lara_as_rope_down,//113
lara_as_rope_idle,//114
lara_as_rope_idle,//115
2020-12-21 13:16:29 -03:00
lara_void_func,
lara_as_controlled,
lara_as_swimcheat,
lara_as_tightrope_idle,//119
lara_as_controlled_no_look,//120
lara_as_tightrope_walk,//121
lara_as_tightrope_fall,//122
lara_as_tightrope_fall,//123
2020-12-21 13:16:29 -03:00
lara_as_null,//124
#ifdef NEW_TIGHTROPE
lara_as_tightrope_dismount,//125
#else // !NEW_TIGHTROPE
2020-12-21 13:16:29 -03:00
lara_as_null,//125
#endif
lara_as_switch_on,//126
2020-12-21 13:16:29 -03:00
lara_as_null,//127
lara_as_horizontal_bar_swing,//128
lara_as_horizontal_bar_leap,//129
2020-12-21 13:16:29 -03:00
lara_as_null,//130
lara_as_controlled_no_look,//131
lara_as_controlled_no_look,//132
2020-12-21 13:16:29 -03:00
lara_as_null,//133
lara_as_null,//134
lara_as_null,//135
lara_as_null,//136
lara_as_null,//137
lara_as_null,//138
2021-12-01 17:18:31 +03:00
lara_as_null,//139
lara_as_null,//140
lara_as_null,//141
lara_as_null,//142
lara_as_slopeclimb,//143
lara_as_slopeclimbup,//144
lara_as_slopeclimbdown,//145
2022-02-05 23:13:31 +11:00
lara_as_controlled_no_look,//146
lara_as_null,//147
lara_as_null,//148
lara_as_slopefall,//149
2020-12-21 13:16:29 -03:00
lara_as_stepoff_left,
lara_as_stepoff_right,
lara_as_turn_left_fast,
lara_as_controlled,
lara_as_controlled,
lara_as_controlled,//155
lara_as_slopehang,
lara_as_slopeshimmy,
lara_as_sclimbstart,
lara_as_sclimbstop,
lara_as_sclimbend,
lara_as_null,//161
lara_as_null,//162
lara_as_monkey_back,//163
2022-02-17 15:01:48 +11:00
lara_as_vault,//164
lara_as_vault,//165
lara_as_vault,//166
lara_as_vault,//167
lara_as_vault,//168
lara_as_vault,//169
lara_as_idle,//170
2020-12-21 13:16:29 -03:00
};
2021-09-15 16:58:53 +03:00
function<LaraRoutineFunction> lara_collision_routines[NUM_LARA_STATES + 1] =
{
lara_col_walk_forward,
lara_col_run_forward,
lara_col_idle,
lara_col_jump_forward,//3
lara_col_idle,//4
lara_col_run_back,
lara_col_turn_right_slow,
lara_col_turn_left_slow,
2020-12-21 13:16:29 -03:00
lara_col_death,
2021-12-21 23:29:51 +11:00
lara_col_freefall,//9
2020-12-21 13:16:29 -03:00
lara_col_hang,
lara_col_reach,
lara_col_splat,
lara_col_tread,
lara_col_land,
lara_col_jump_prepare,//15
lara_col_walk_back,
2020-12-21 13:16:29 -03:00
lara_col_swim,
lara_col_glide,
2022-02-07 13:06:02 +11:00
lara_default_col,//19
lara_col_turn_right_fast,
lara_col_step_right,
lara_col_step_left,
lara_col_roll_back,
2021-12-18 20:42:15 +11:00
lara_col_slide_forward,//24
2021-12-22 00:39:03 +11:00
lara_col_jump_back,//25
lara_col_jump_right,//26
lara_col_jump_left,//27
lara_col_jump_up,//28
2021-12-20 21:37:38 +11:00
lara_col_fall_back,//29
2020-12-21 13:16:29 -03:00
lara_col_hangleft,
lara_col_hangright,
2021-12-18 20:42:15 +11:00
lara_col_slide_back,//32
2020-12-21 13:16:29 -03:00
lara_col_surftread,
lara_col_surfswim,
lara_col_dive,
lara_default_col,
lara_default_col,
lara_default_col,
lara_default_col,
lara_default_col,
lara_default_col,
lara_default_col,
lara_default_col,
lara_col_uwdeath,
lara_col_roll_forward,
2020-12-21 13:16:29 -03:00
lara_void_func,
lara_col_surfback,
lara_col_surfleft,
lara_col_surfright,
lara_void_func,
lara_void_func,
lara_col_swan_dive,//52
lara_col_freefall_dive,//53
2020-12-21 13:16:29 -03:00
lara_default_col,
lara_default_col,
lara_col_climbstnc,
lara_col_climbing,
lara_col_climbleft,
lara_col_climbend,
lara_col_climbright,
lara_col_climbdown,
2022-02-17 15:01:48 +11:00
lara_void_func,//62
2020-12-21 13:16:29 -03:00
lara_void_func,
lara_void_func,
lara_col_wade_forward,
2020-12-21 13:16:29 -03:00
lara_col_waterroll,
lara_default_col,
lara_void_func,
lara_void_func,
lara_void_func,
lara_col_crouch_idle,
2020-12-21 13:16:29 -03:00
lara_col_crouch_roll,
lara_col_sprint,
lara_col_sprint_dive,
2021-12-01 11:59:24 +03:00
lara_col_monkey_idle,
2022-01-12 19:33:41 +11:00
lara_col_monkey_forward,//76
2022-01-12 19:58:37 +11:00
lara_col_monkey_shimmy_left,//77
lara_col_monkey_shimmy_right,//78
2022-01-12 19:04:29 +11:00
lara_col_monkey_turn_180,//79
lara_col_crawl_idle,
lara_col_crawl_forward,
2022-01-12 19:04:29 +11:00
lara_col_monkey_turn_left,//81
lara_col_monkey_turn_right,//82
lara_col_crawl_turn_left,
lara_col_crawl_turn_right,
lara_col_crawl_back,
2020-12-21 13:16:29 -03:00
lara_void_func,
lara_col_crawl_to_hang,
2020-12-21 13:16:29 -03:00
lara_default_col,
lara_void_func,
lara_void_func,
lara_default_col,
lara_void_func,
lara_void_func,
lara_col_turn_switch,
2020-12-21 13:16:29 -03:00
lara_void_func,
lara_void_func,
lara_default_col,
2021-11-21 20:50:17 +11:00
lara_col_pole_idle,
lara_col_pole_up,
lara_col_pole_down,
lara_col_pole_turn_clockwise,
lara_col_pole_turn_counter_clockwise,
2020-12-21 13:16:29 -03:00
lara_default_col,
lara_col_crouch_turn_left,
lara_col_crouch_turn_right,
2020-12-21 13:16:29 -03:00
lara_default_col,
lara_default_col,
lara_default_col,
lara_default_col,
lara_col_rope_idle,
2020-12-21 13:16:29 -03:00
lara_void_func,
lara_void_func,
lara_col_rope_swing,
lara_col_rope_swing,
2020-12-21 13:16:29 -03:00
lara_void_func,
lara_void_func,
lara_col_swim,
lara_default_col,
lara_default_col,
lara_default_col,
lara_default_col,
lara_default_col,
lara_default_col,
lara_default_col,
lara_default_col,
lara_default_col,
lara_default_col,
lara_default_col,
lara_void_func,
lara_void_func,
lara_void_func,
lara_void_func,
lara_void_func,
lara_void_func,
lara_void_func,
lara_void_func,
lara_void_func,
2021-12-01 17:18:31 +03:00
lara_void_func,
lara_void_func,
lara_void_func,
lara_void_func,
lara_col_slopeclimb,
lara_default_col, // lara_col_slopeclimbup
lara_default_col, // lara_col_slopeclimbdown
2020-12-21 13:16:29 -03:00
lara_void_func,
lara_void_func,
lara_void_func,
lara_default_col, // lara_col_slopefall
2020-12-21 13:16:29 -03:00
lara_default_col,
lara_default_col,
lara_col_turn_left_fast,
lara_default_col,
lara_default_col,
lara_default_col,
lara_col_slopehang, // lara_col_slopehang
lara_col_slopeshimmy, // lara_col_slopeshimmy
lara_default_col, // lara_col_sclimbstart
lara_default_col, // lara_col_sclimbstop
lara_default_col, // lara_col_sclimbend
lara_void_func,//161
lara_void_func,//162
lara_col_monkey_back,//163
2022-02-17 15:01:48 +11:00
lara_void_func,//164
lara_void_func,//165
lara_void_func,//166
lara_void_func,//167
lara_void_func,//168
lara_void_func,//169
lara_col_idle,//170
2020-12-21 13:16:29 -03:00
};
2021-11-09 16:03:56 +11:00
void LaraControl(ITEM_INFO* item, COLL_INFO* coll)
2020-12-21 13:16:29 -03:00
{
2022-02-14 17:05:52 +11:00
auto* info = GetLaraInfo(item);
if (info->Control.WeaponControl.HasFired)
2021-09-16 01:12:19 +03:00
{
2021-11-09 16:03:56 +11:00
AlertNearbyGuards(item);
info->Control.WeaponControl.HasFired = false;
2021-09-16 01:12:19 +03:00
}
if (info->poisoned)
2021-09-16 01:12:19 +03:00
{
if (info->poisoned > 4096)
info->poisoned = 4096;
2021-09-16 01:12:19 +03:00
if (info->poisoned >= 256 && !(Wibble & 0xFF))
item->HitPoints -= info->poisoned >> 8;
2021-09-16 01:12:19 +03:00
}
if (info->Control.IsMoving)
2020-12-21 13:16:29 -03:00
{
if (info->Control.Count.PositionAdjust > 90)
2020-12-21 13:16:29 -03:00
{
info->Control.IsMoving = false;
info->Control.HandStatus = HandStatus::Free;
2020-12-21 13:16:29 -03:00
}
2021-11-09 16:03:56 +11:00
++info->Control.Count.PositionAdjust;
2020-12-21 13:16:29 -03:00
}
if (!info->Control.Locked)
info->locationPad = 128;
2020-12-21 13:16:29 -03:00
int oldX = item->Position.xPos;
int oldY = item->Position.yPos;
int oldZ = item->Position.zPos;
2020-12-21 13:16:29 -03:00
2022-01-26 14:51:50 +11:00
// Set hands free failsafe.
if (info->Control.HandStatus == HandStatus::Busy &&
item->ActiveState == LS_IDLE &&
item->TargetState == LS_IDLE &&
item->AnimNumber == LA_STAND_IDLE &&
!item->Airborne)
2020-12-21 13:16:29 -03:00
{
info->Control.HandStatus = HandStatus::Free;
2020-12-21 13:16:29 -03:00
}
if (item->ActiveState != LS_SPRINT && info->SprintEnergy < LARA_SPRINT_MAX)
info->SprintEnergy++;
2020-12-21 13:16:29 -03:00
info->Control.IsLow = false;
2020-12-21 13:16:29 -03:00
2022-01-25 18:02:22 +11:00
bool isWater = TestEnvironment(ENV_FLAG_WATER, item);
bool isSwamp = TestEnvironment(ENV_FLAG_SWAMP, item);
2020-12-21 13:16:29 -03:00
int waterDepth = GetWaterDepth(item);
int waterHeight = GetWaterHeight(item);
2020-12-21 13:16:29 -03:00
2021-11-09 16:03:56 +11:00
int heightFromWater;
if (waterHeight != NO_HEIGHT)
heightFromWater = item->Position.yPos - waterHeight;
2020-12-21 13:16:29 -03:00
else
2021-11-09 16:03:56 +11:00
heightFromWater = NO_HEIGHT;
info->WaterSurfaceDist = -heightFromWater;
2020-12-21 13:16:29 -03:00
if (info->Vehicle == NO_ITEM)
2021-11-09 16:03:56 +11:00
WadeSplash(item, waterHeight, waterDepth);
2020-12-21 13:16:29 -03:00
if (info->Vehicle == NO_ITEM && info->ExtraAnim == -1)
2020-12-21 13:16:29 -03:00
{
switch (info->Control.WaterStatus)
2020-12-21 13:16:29 -03:00
{
case WaterStatus::Dry:
2021-11-09 16:03:56 +11:00
if (heightFromWater == NO_HEIGHT || heightFromWater < WADE_DEPTH)
2021-11-07 04:54:48 +03:00
break;
2021-11-09 16:03:56 +11:00
Camera.targetElevation = -ANGLE(22.0f);
// Water is deep enough to swim; dispatch dive.
if (waterDepth >= SWIM_DEPTH &&
!isSwamp)
2020-12-21 13:16:29 -03:00
{
2021-11-07 16:07:16 +03:00
if (isWater)
2020-12-21 13:16:29 -03:00
{
info->Air = LARA_AIR_MAX;
info->Control.WaterStatus = WaterStatus::Underwater;
item->Airborne = false;
item->Position.yPos += 100;
2021-11-07 04:54:48 +03:00
2021-11-09 16:03:56 +11:00
UpdateItemRoom(item, 0);
2021-11-07 16:07:16 +03:00
StopSoundEffect(SFX_TR4_LARA_FALL);
2021-11-07 04:54:48 +03:00
if (item->ActiveState == LS_SWAN_DIVE)
2021-11-07 16:07:16 +03:00
{
info->Control.HandStatus = HandStatus::Free;
item->Position.xRot = -ANGLE(45.0f);
item->TargetState = LS_FREEFALL_DIVE;
2021-11-07 16:07:16 +03:00
AnimateLara(item);
item->VerticalVelocity *= 2;
2021-11-07 16:07:16 +03:00
}
else if (item->ActiveState == LS_FREEFALL_DIVE)
2021-11-07 16:07:16 +03:00
{
info->Control.HandStatus = HandStatus::Free;
item->Position.xRot = -ANGLE(85.0f);
item->TargetState = LS_FREEFALL_DIVE;
2021-11-07 16:07:16 +03:00
AnimateLara(item);
item->VerticalVelocity *= 2;
2021-11-07 16:07:16 +03:00
}
else
{
item->Position.xRot = -ANGLE(45.0f);
2021-11-10 02:41:59 +03:00
SetAnimation(item, LA_FREEFALL_DIVE);
item->VerticalVelocity = 3 * item->VerticalVelocity / 2;
2021-11-07 16:07:16 +03:00
}
2020-12-21 13:16:29 -03:00
2021-12-10 12:30:23 +11:00
ResetLaraFlex(item);
2021-11-09 16:03:56 +11:00
Splash(item);
2021-11-07 04:54:48 +03:00
}
}
// Water is at wade depth; update water status and do special handling.
else if (heightFromWater >= WADE_DEPTH)
2021-11-07 04:54:48 +03:00
{
info->Control.WaterStatus = WaterStatus::Wade;
2021-11-09 16:03:56 +11:00
// Make splash ONLY within this particular threshold before swim depth while airborne (WadeSplash() above interferes otherwise).
if (waterDepth > (SWIM_DEPTH - CLICK(1)) &&
!isSwamp &&
item->Airborne)
{
Splash(item);
item->TargetState = LS_IDLE;
}
// Lara is grounded; don't splash again.
else if (!item->Airborne)
item->TargetState = LS_IDLE;
2021-11-07 04:54:48 +03:00
else if (isSwamp)
{
if (item->ActiveState == LS_SWAN_DIVE ||
item->ActiveState == LS_FREEFALL_DIVE)
2021-11-09 20:03:40 +11:00
{
item->Position.yPos = waterHeight + (WALL_SIZE - 24);
2021-11-10 23:27:37 +11:00
}
2021-11-07 04:54:48 +03:00
2021-11-10 02:41:59 +03:00
SetAnimation(item, LA_WADE);
2021-11-07 04:54:48 +03:00
}
}
2021-12-14 14:35:42 +11:00
2020-12-21 13:16:29 -03:00
break;
case WaterStatus::Underwater:
2021-11-09 16:03:56 +11:00
if (isWater ||
waterDepth == DEEP_WATER ||
abs(heightFromWater) >= CLICK(1) ||
item->AnimNumber == LA_UNDERWATER_RESURFACE ||
item->AnimNumber == LA_ONWATER_DIVE)
2020-12-21 13:16:29 -03:00
{
if (!isWater)
{
if (waterDepth == DEEP_WATER || abs(heightFromWater) >= CLICK(1))
2020-12-21 13:16:29 -03:00
{
2021-11-10 02:41:59 +03:00
SetAnimation(item, LA_FALL_START);
item->Velocity = item->VerticalVelocity / 4;
item->VerticalVelocity = 0;
2022-02-14 17:05:52 +11:00
item->Airborne = true;
info->Control.WaterStatus = WaterStatus::Dry;
2022-02-14 17:05:52 +11:00
ResetLaraLean(item);
2021-12-10 12:30:23 +11:00
ResetLaraFlex(item);
2020-12-21 13:16:29 -03:00
}
else
{
2021-11-10 02:41:59 +03:00
SetAnimation(item, LA_UNDERWATER_RESURFACE);
item->Position.yPos = waterHeight;
item->VerticalVelocity = 0;
info->Control.WaterStatus = WaterStatus::TreadWater;
info->Control.Count.Dive = 11;
2022-02-14 17:05:52 +11:00
ResetLaraLean(item);
2021-12-10 12:30:23 +11:00
ResetLaraFlex(item);
2020-12-21 13:16:29 -03:00
2021-11-09 16:03:56 +11:00
UpdateItemRoom(item, -(STEPUP_HEIGHT - 3));
SoundEffect(SFX_TR4_LARA_BREATH, &item->Position, 2);
2020-12-21 13:16:29 -03:00
}
}
}
else
{
2021-11-10 02:41:59 +03:00
SetAnimation(item, LA_UNDERWATER_RESURFACE);
item->Position.yPos = waterHeight + 1;
item->VerticalVelocity = 0;
info->Control.WaterStatus = WaterStatus::TreadWater;
info->Control.Count.Dive = 11;
2022-02-14 17:05:52 +11:00
ResetLaraLean(item);
2021-12-10 12:30:23 +11:00
ResetLaraFlex(item);
2020-12-21 13:16:29 -03:00
UpdateItemRoom(item, 0);
SoundEffect(SFX_TR4_LARA_BREATH, &item->Position, 2);
2020-12-21 13:16:29 -03:00
}
2022-02-14 17:05:52 +11:00
2020-12-21 13:16:29 -03:00
break;
case WaterStatus::TreadWater:
2020-12-21 13:16:29 -03:00
if (!isWater)
{
2021-11-09 16:03:56 +11:00
if (heightFromWater <= WADE_DEPTH)
2020-12-21 13:16:29 -03:00
{
2021-11-10 02:41:59 +03:00
SetAnimation(item, LA_FALL_START);
item->Velocity = item->VerticalVelocity / 4;
item->Airborne = true;
info->Control.WaterStatus = WaterStatus::Dry;
2020-12-21 13:16:29 -03:00
}
else
{
2021-11-10 02:41:59 +03:00
SetAnimation(item, LA_STAND_IDLE);
item->TargetState = LS_WADE_FORWARD; // TODO: Check if really needed? -- Lwmte, 10.11.21
info->Control.WaterStatus = WaterStatus::Wade;
2020-12-21 13:16:29 -03:00
AnimateItem(item);
}
item->VerticalVelocity = 0;
2022-02-14 17:05:52 +11:00
ResetLaraLean(item);
2021-12-10 12:30:23 +11:00
ResetLaraFlex(item);
2020-12-21 13:16:29 -03:00
}
2021-11-09 16:03:56 +11:00
2020-12-21 13:16:29 -03:00
break;
case WaterStatus::Wade:
2021-11-09 16:03:56 +11:00
Camera.targetElevation = -ANGLE(22.0f);
if (heightFromWater >= WADE_DEPTH)
2020-12-21 13:16:29 -03:00
{
2021-11-09 16:03:56 +11:00
if (heightFromWater > SWIM_DEPTH && !isSwamp)
2020-12-21 13:16:29 -03:00
{
2021-11-10 02:41:59 +03:00
SetAnimation(item, LA_ONWATER_IDLE);
item->Position.yPos += 1 - heightFromWater;
item->VerticalVelocity = 0;
2022-02-14 17:05:52 +11:00
item->Airborne = false;
info->Control.WaterStatus = WaterStatus::TreadWater;
info->Control.Count.Dive = 0;
2022-02-14 17:05:52 +11:00
ResetLaraLean(item);
2021-12-10 12:30:23 +11:00
ResetLaraFlex(item);
2020-12-21 13:16:29 -03:00
UpdateItemRoom(item, 0);
2020-12-21 13:16:29 -03:00
}
}
else
{
info->Control.WaterStatus = WaterStatus::Dry;
2021-11-09 16:03:56 +11:00
if (item->ActiveState == LS_WADE_FORWARD)
item->TargetState = LS_RUN_FORWARD;
2020-12-21 13:16:29 -03:00
}
2021-11-09 16:03:56 +11:00
2020-12-21 13:16:29 -03:00
break;
}
}
if (item->HitPoints <= 0)
2020-12-21 13:16:29 -03:00
{
item->HitPoints = -1;
2020-12-21 13:16:29 -03:00
if (info->Control.Count.Death == 0)
2021-09-16 01:12:19 +03:00
StopSoundTracks();
2020-12-21 13:16:29 -03:00
info->Control.Count.Death++;
if ((item->Flags & 0x100))
2020-12-21 13:16:29 -03:00
{
info->Control.Count.Death++;
2020-12-21 13:16:29 -03:00
return;
}
}
switch (info->Control.WaterStatus)
2020-12-21 13:16:29 -03:00
{
case WaterStatus::Dry:
case WaterStatus::Wade:
if (isSwamp && info->WaterSurfaceDist < -(LARA_HEIGHT + 8)) // TODO: Find best height. @Sezz 2021.11.10
2020-12-21 13:16:29 -03:00
{
if (item->HitPoints >= 0)
2020-12-21 13:16:29 -03:00
{
info->Air -= 6;
if (info->Air < 0)
2020-12-21 13:16:29 -03:00
{
info->Air = -1;
item->HitPoints -= 10;
2020-12-21 13:16:29 -03:00
}
}
}
else if (info->Air < LARA_AIR_MAX && item->HitPoints >= 0)
2020-12-21 13:16:29 -03:00
{
if (info->Vehicle == NO_ITEM) // only for the upv !!
2020-12-21 13:16:29 -03:00
{
info->Air += 10;
if (info->Air > LARA_AIR_MAX)
info->Air = LARA_AIR_MAX;
2020-12-21 13:16:29 -03:00
}
}
2021-11-09 16:03:56 +11:00
LaraAboveWater(item, coll);
2020-12-21 13:16:29 -03:00
break;
case WaterStatus::Underwater:
if (item->HitPoints >= 0)
2020-12-21 13:16:29 -03:00
{
2022-02-14 17:05:52 +11:00
auto* level = g_GameFlow->GetLevel(CurrentLevel);
2021-11-11 01:16:27 +03:00
if (level->LaraType != LaraType::Divesuit)
info->Air--;
2021-11-11 01:16:27 +03:00
if (info->Air < 0)
2020-12-21 13:16:29 -03:00
{
// if (LaraDrawType == LARA_TYPE::DIVESUIT && info->anxiety < 251)
// info->anxiety += 4;
info->Air = -1;
item->HitPoints -= 5;
2020-12-21 13:16:29 -03:00
}
}
2021-11-09 16:03:56 +11:00
LaraUnderWater(item, coll);
2020-12-21 13:16:29 -03:00
break;
case WaterStatus::TreadWater:
if (item->HitPoints >= 0)
2020-12-21 13:16:29 -03:00
{
info->Air += 10;
if (info->Air > LARA_AIR_MAX)
info->Air = LARA_AIR_MAX;
2020-12-21 13:16:29 -03:00
}
2021-11-09 16:03:56 +11:00
LaraSurface(item, coll);
2020-12-21 13:16:29 -03:00
break;
case WaterStatus::FlyCheat:
2021-11-09 16:03:56 +11:00
LaraCheat(item, coll);
2020-12-21 13:16:29 -03:00
break;
}
Statistics.Game.Distance += sqrt(
SQUARE(item->Position.xPos - oldX) +
SQUARE(item->Position.yPos - oldY) +
SQUARE(item->Position.zPos - oldZ));
2020-12-21 13:16:29 -03:00
}
void LaraAboveWater(ITEM_INFO* item, COLL_INFO* coll)
2020-12-21 13:16:29 -03:00
{
2022-02-14 17:05:52 +11:00
auto* info = GetLaraInfo(item);
2021-11-19 22:48:47 +11:00
coll->Setup.UpperCeilingBound = NO_UPPER_BOUND;
2022-01-23 18:16:29 +11:00
coll->Setup.OldPosition.x = item->Position.xPos;
coll->Setup.OldPosition.y = item->Position.yPos;
coll->Setup.OldPosition.z = item->Position.zPos;
coll->Setup.OldState = item->ActiveState;
coll->Setup.OldAnimNumber = item->AnimNumber;
coll->Setup.OldFrameNumber = item->FrameNumber;
2021-10-09 19:19:02 +03:00
2021-09-10 00:20:59 +03:00
coll->Setup.EnableObjectPush = true;
coll->Setup.EnableSpasm = true;
coll->Setup.FloorSlopeIsWall = false;
coll->Setup.FloorSlopeIsPit = false;
coll->Setup.CeilingSlopeIsWall = false;
coll->Setup.DeathFlagIsPit = false;
coll->Setup.NoMonkeyFlagIsWall = false;
coll->Setup.Mode = CollProbeMode::Quadrants;
2021-10-09 19:19:02 +03:00
if (TrInput & IN_LOOK && info->Control.CanLook &&
2021-11-19 22:48:47 +11:00
info->ExtraAnim == NO_ITEM)
2021-11-10 16:11:36 +11:00
{
LookLeftRight(item);
2021-11-10 16:11:36 +11:00
}
else if (coll->Setup.Height > LARA_HEIGHT - LARA_HEADROOM) // TEMP HACK: Look feature will need a dedicated refactor; ResetLook() interferes with crawl flexing. @Sezz 2021.12.10
ResetLook(item);
2020-12-21 13:16:29 -03:00
// TODO: Move radius and height default resets above look checks when look feature is refactored.
coll->Setup.Radius = LARA_RAD;
coll->Setup.Height = LARA_HEIGHT;
info->Control.CanLook = true;
2020-12-21 13:16:29 -03:00
UpdateItemRoom(item, -LARA_HEIGHT / 2);
// Process vehicles.
2022-02-20 14:22:26 +11:00
if (HandleLaraVehicle(item, coll))
return;
2020-12-21 13:16:29 -03:00
// Temp. debug stuff
//---
// Kill Lara.
if (KeyMap[DIK_D])
item->HitPoints = 0;
// Say no.
static bool dbNo = false;
if (KeyMap[DIK_N] && !dbNo)
SayNo();
dbNo = KeyMap[DIK_N] ? true : false;
static PHD_3DPOS posO = item->Position;
static short roomNumO = item->RoomNumber;
static CAMERA_INFO camO = Camera;
// Save position.
if (KeyMap[DIK_Q] && TrInput & IN_WALK)
{
posO = item->Position;
roomNumO = item->RoomNumber;
camO = Camera;
}
// Restore position.
if (KeyMap[DIK_E])
{
item->Position = posO;
item->RoomNumber = roomNumO;
Camera = camO;
}
// Forward 1 unit.
if (KeyMap[DIK_I])
{
item->Position.xPos += roundf(phd_sin(item->Position.yRot));
item->Position.zPos += roundf(phd_cos(item->Position.yRot));
}
// Back 1 unit.
else if (KeyMap[DIK_K])
{
item->Position.xPos += roundf(phd_sin(item->Position.yRot + ANGLE(180.0f)));
item->Position.zPos += roundf(phd_cos(item->Position.yRot + ANGLE(180.0f)));
}
// Left 1 unit.
else if (KeyMap[DIK_J])
{
item->Position.xPos += roundf(phd_sin(item->Position.yRot - ANGLE(90.0f)));
item->Position.zPos += roundf(phd_cos(item->Position.yRot - ANGLE(90.0f)));
}
// Right 1 unit.
else if (KeyMap[DIK_L])
{
item->Position.xPos += roundf(phd_sin(item->Position.yRot + ANGLE(90.0f)));
item->Position.zPos += roundf(phd_cos(item->Position.yRot + ANGLE(90.0f)));
}
//---
// Temp. debug stuff.
static bool doRoutines = true;
static bool dbT = false;
if (KeyMap[DIK_T] && !dbT)
doRoutines = !doRoutines;
dbT = KeyMap[DIK_T] ? true : false;
2020-12-21 13:16:29 -03:00
static bool dbU = false;
if (doRoutines || KeyMap[DIK_U] && !dbU)
2020-12-21 13:16:29 -03:00
{
2022-01-18 16:52:52 +11:00
// Handle current Lara status.
lara_control_routines[item->ActiveState](item, coll);
2022-02-14 17:05:52 +11:00
HandleLaraMovementParameters(item, coll);
2022-01-18 16:52:52 +11:00
// Animate Lara.
AnimateLara(item);
if (info->ExtraAnim == -1)
{
// Check for collision with items.
DoObjectCollision(item, coll);
2020-12-21 13:16:29 -03:00
// Handle Lara collision.
if (info->Vehicle == NO_ITEM)
lara_collision_routines[item->ActiveState](item, coll);
}
2020-12-21 13:16:29 -03:00
}
dbU = KeyMap[DIK_U] ? true : false;
2020-12-21 13:16:29 -03:00
2021-11-19 22:48:47 +11:00
//if (info->gunType == WEAPON_CROSSBOW && !LaserSight)
2020-12-21 13:16:29 -03:00
// TrInput &= ~IN_ACTION;
// Handle weapons.
2021-11-20 15:39:05 +11:00
LaraGun(item);
2020-12-21 13:16:29 -03:00
// Handle breath.
2021-11-22 18:55:29 +03:00
LaraBreath(item);
// Test for flags and triggers.
ProcessSectorFlags(item);
2021-09-15 16:58:53 +03:00
TestTriggers(item, false);
TestVolumes(item);
2020-12-21 13:16:29 -03:00
}
2021-02-03 01:50:59 -03:00
void LaraUnderWater(ITEM_INFO* item, COLL_INFO* coll)
2020-12-21 13:16:29 -03:00
{
2022-02-14 17:05:52 +11:00
auto* info = GetLaraInfo(item);
coll->Setup.LowerFloorBound = NO_LOWER_BOUND;
coll->Setup.UpperFloorBound = -(LARA_RAD_UNDERWATER + (LARA_RAD_UNDERWATER / 3));
coll->Setup.LowerCeilingBound = LARA_RAD_UNDERWATER + (LARA_RAD_UNDERWATER / 3);
coll->Setup.UpperCeilingBound = NO_UPPER_BOUND;
2020-12-21 13:16:29 -03:00
coll->Setup.OldPosition.x = item->Position.xPos;
coll->Setup.OldPosition.y = item->Position.yPos;
coll->Setup.OldPosition.z = item->Position.zPos;
2020-12-21 13:16:29 -03:00
coll->Setup.FloorSlopeIsWall = false;
coll->Setup.FloorSlopeIsPit = false;
coll->Setup.CeilingSlopeIsWall = false;
coll->Setup.DeathFlagIsPit = false;
coll->Setup.NoMonkeyFlagIsWall = false;
2021-09-10 00:20:59 +03:00
coll->Setup.EnableObjectPush = true;
coll->Setup.EnableSpasm = false;
coll->Setup.Mode = CollProbeMode::Quadrants;
2020-12-21 13:16:29 -03:00
2021-09-10 01:19:15 +03:00
coll->Setup.Radius = LARA_RAD_UNDERWATER;
coll->Setup.Height = LARA_HEIGHT;
2020-12-21 13:16:29 -03:00
if (TrInput & IN_LOOK && info->Control.CanLook)
LookLeftRight(item);
2020-12-21 13:16:29 -03:00
else
ResetLook(item);
2020-12-21 13:16:29 -03:00
info->Control.CanLook = true;
info->Control.Count.Pose = 0;
2020-12-21 13:16:29 -03:00
lara_control_routines[item->ActiveState](item, coll);
2020-12-21 13:16:29 -03:00
2021-11-11 01:16:27 +03:00
auto level = g_GameFlow->GetLevel(CurrentLevel);
if (level->LaraType == LaraType::Divesuit)
2020-12-21 13:16:29 -03:00
{
if (info->Control.TurnRate < -ANGLE(0.5f))
info->Control.TurnRate += ANGLE(0.5f);
else if (info->Control.TurnRate > ANGLE(0.5f))
info->Control.TurnRate -= ANGLE(0.5f);
2020-12-21 13:16:29 -03:00
else
info->Control.TurnRate = 0;
2020-12-21 13:16:29 -03:00
}
else if (info->Control.TurnRate < -ANGLE(2.0f))
info->Control.TurnRate += ANGLE(2.0f);
else if (info->Control.TurnRate > ANGLE(2.0f))
info->Control.TurnRate -= ANGLE(2.0f);
2020-12-21 13:16:29 -03:00
else
info->Control.TurnRate = 0;
2020-12-21 13:16:29 -03:00
item->Position.yRot += info->Control.TurnRate;
2020-12-21 13:16:29 -03:00
2021-11-11 01:16:27 +03:00
if (level->LaraType == LaraType::Divesuit)
UpdateSubsuitAngles(item);
2020-12-21 13:16:29 -03:00
if (!info->Control.IsMoving && !(TrInput & (IN_LEFT | IN_RIGHT)))
2022-02-14 17:05:52 +11:00
ResetLaraLean(item, 1, true, false);
2021-09-26 12:23:58 +10:00
if (item->Position.xRot < -ANGLE(85.0f))
item->Position.xRot = -ANGLE(85.0f);
else if (item->Position.xRot > ANGLE(85.0f))
item->Position.xRot = ANGLE(85.0f);
2020-12-21 13:16:29 -03:00
2021-11-11 01:16:27 +03:00
if (level->LaraType == LaraType::Divesuit)
2020-12-21 13:16:29 -03:00
{
if (item->Position.zRot > ANGLE(44.0f))
item->Position.zRot = ANGLE(44.0f);
else if (item->Position.zRot < -ANGLE(44.0f))
item->Position.zRot = -ANGLE(44.0f);
2020-12-21 13:16:29 -03:00
}
else
{
if (item->Position.zRot > ANGLE(22.0f))
item->Position.zRot = ANGLE(22.0f);
else if (item->Position.zRot < -ANGLE(22.0f))
item->Position.zRot = -ANGLE(22.0f);
2020-12-21 13:16:29 -03:00
}
if (info->Control.WaterCurrentActive && info->Control.WaterStatus != WaterStatus::FlyCheat)
LaraWaterCurrent(item, coll);
2020-12-21 13:16:29 -03:00
AnimateLara(item);
item->Position.xPos += phd_cos(item->Position.xRot) * item->VerticalVelocity * phd_sin(item->Position.yRot) / 4;
item->Position.yPos -= item->VerticalVelocity * phd_sin(item->Position.xRot) / 4;
item->Position.zPos += phd_cos(item->Position.xRot) * item->VerticalVelocity * phd_cos(item->Position.yRot) / 4;
2020-12-21 13:16:29 -03:00
DoObjectCollision(item, coll);
2020-12-21 13:16:29 -03:00
if (/*info->ExtraAnim == -1 &&*/ info->Vehicle == NO_ITEM)
lara_collision_routines[item->ActiveState](item, coll);
2020-12-21 13:16:29 -03:00
UpdateItemRoom(item, 0);
2020-12-21 13:16:29 -03:00
2021-11-20 15:39:05 +11:00
LaraGun(item);
2020-12-21 13:16:29 -03:00
ProcessSectorFlags(item);
2021-09-15 16:58:53 +03:00
TestTriggers(item, false);
TestVolumes(item);
2020-12-21 13:16:29 -03:00
}
2021-02-03 01:50:59 -03:00
void LaraSurface(ITEM_INFO* item, COLL_INFO* coll)
2020-12-21 13:16:29 -03:00
{
2022-02-14 17:05:52 +11:00
auto* info = GetLaraInfo(item);
2021-11-10 16:11:36 +11:00
Camera.targetElevation = -ANGLE(22.0f);
2020-12-21 13:16:29 -03:00
coll->Setup.LowerFloorBound = NO_LOWER_BOUND;
coll->Setup.UpperFloorBound = -CLICK(0.5f);
coll->Setup.LowerCeilingBound = LARA_RAD;
coll->Setup.UpperCeilingBound = NO_UPPER_BOUND;
2020-12-21 13:16:29 -03:00
coll->Setup.OldPosition.x = item->Position.xPos;
coll->Setup.OldPosition.y = item->Position.yPos;
coll->Setup.OldPosition.z = item->Position.zPos;
2020-12-21 13:16:29 -03:00
coll->Setup.FloorSlopeIsWall = false;
coll->Setup.FloorSlopeIsPit = false;
coll->Setup.CeilingSlopeIsWall = false;
coll->Setup.DeathFlagIsPit = false;
coll->Setup.NoMonkeyFlagIsWall = false;
2021-09-10 00:20:59 +03:00
coll->Setup.EnableObjectPush = false;
coll->Setup.EnableSpasm = false;
coll->Setup.Mode = CollProbeMode::FreeForward;
2020-12-21 13:16:29 -03:00
2021-09-10 01:19:15 +03:00
coll->Setup.Radius = LARA_RAD;
2021-09-19 07:38:15 +03:00
coll->Setup.Height = LARA_HEIGHT_SURFACE;
2020-12-21 13:16:29 -03:00
if (TrInput & IN_LOOK && info->Control.CanLook)
LookLeftRight(item);
2020-12-21 13:16:29 -03:00
else
ResetLook(item);
2020-12-21 13:16:29 -03:00
info->Control.CanLook = true;
info->Control.Count.Pose = 0;
2020-12-21 13:16:29 -03:00
lara_control_routines[item->ActiveState](item, coll);
2020-12-21 13:16:29 -03:00
if (!info->Control.IsMoving && !(TrInput & (IN_LEFT | IN_RIGHT)))
{
if (abs(item->Position.zRot) > 0)
item->Position.zRot += item->Position.zRot / -8;
}
if (info->Control.WaterCurrentActive && info->Control.WaterStatus != WaterStatus::FlyCheat)
LaraWaterCurrent(item, coll);
2020-12-21 13:16:29 -03:00
AnimateLara(item);
item->Position.xPos += item->VerticalVelocity * phd_sin(info->Control.MoveAngle) / 4;
item->Position.zPos += item->VerticalVelocity * phd_cos(info->Control.MoveAngle) / 4;
2020-12-21 13:16:29 -03:00
DoObjectCollision(item, coll);
2020-12-21 13:16:29 -03:00
if (info->Vehicle == NO_ITEM)
lara_collision_routines[item->ActiveState](item, coll);
2020-12-21 13:16:29 -03:00
2022-01-23 18:16:29 +11:00
UpdateItemRoom(item, LARA_RAD);
2020-12-21 13:16:29 -03:00
2021-11-20 15:39:05 +11:00
LaraGun(item);
2020-12-21 13:16:29 -03:00
ProcessSectorFlags(item);
2021-09-15 16:58:53 +03:00
TestTriggers(item, false);
TestVolumes(item);
2020-12-21 13:16:29 -03:00
}
2021-02-03 01:50:59 -03:00
void LaraCheat(ITEM_INFO* item, COLL_INFO* coll)
2020-12-21 13:16:29 -03:00
{
2022-02-14 17:05:52 +11:00
auto* info = GetLaraInfo(item);
item->HitPoints = LARA_HEALTH_MAX;
2020-12-21 13:16:29 -03:00
LaraUnderWater(item, coll);
2021-12-10 12:30:23 +11:00
2020-12-21 13:16:29 -03:00
if (TrInput & IN_WALK && !(TrInput & IN_LOOK))
{
if (TestEnvironment(ENV_FLAG_WATER, item) || (info->WaterSurfaceDist > 0 && info->WaterSurfaceDist != NO_HEIGHT))
2020-12-21 13:16:29 -03:00
{
info->Control.WaterStatus = WaterStatus::Underwater;
2021-11-16 17:25:17 +03:00
SetAnimation(item, LA_UNDERWATER_IDLE);
2021-12-10 12:30:23 +11:00
ResetLaraFlex(item);
2020-12-21 13:16:29 -03:00
}
else
{
info->Control.WaterStatus = WaterStatus::Dry;
2021-11-16 17:25:17 +03:00
SetAnimation(item, LA_STAND_SOLID);
item->Position.zRot = 0;
item->Position.xRot = 0;
2021-12-10 12:30:23 +11:00
ResetLaraFlex(item);
2020-12-21 13:16:29 -03:00
}
2021-12-10 12:30:23 +11:00
info->Control.HandStatus = HandStatus::Free;
LaraInitialiseMeshes(item);
item->HitPoints = LARA_HEALTH_MAX;
2020-12-21 13:16:29 -03:00
}
}