diff --git a/Scripts/Settings.lua b/Scripts/Settings.lua index a9ca7541f..99010cee1 100644 --- a/Scripts/Settings.lua +++ b/Scripts/Settings.lua @@ -16,10 +16,11 @@ settings.errorMode = ErrorMode.WARN; SetSettings(settings); local anims = Animations.new(); -anims.crawlExtra = true; +anims.crawlExtended = true; anims.crouchRoll = true; -anims.monkeyRoll = true; -anims.monkeyVault = true; -anims.oscillateHanging = true; -anims.swandiveRollRun = true; +anims.crawlspaceSwandive = true; +anims.monkeyTurn180 = true; +anims.monkeyAutoJump = false; +anims.oscillateHang = true; +anims.pose = false; SetAnimations(anims); \ No newline at end of file diff --git a/TR5Main/Game/Lara/lara.cpp b/TR5Main/Game/Lara/lara.cpp index 2e0028fa6..2c1171342 100644 --- a/TR5Main/Game/Lara/lara.cpp +++ b/TR5Main/Game/Lara/lara.cpp @@ -1,7 +1,9 @@ #include "framework.h" -#include "Lara.h" +#include "lara.h" #include "lara_basic.h" +#include "lara_helpers.h" +#include "lara_jump.h" #include "lara_tests.h" #include "lara_monkey.h" #include "lara_crawl.h" @@ -54,14 +56,14 @@ byte LaraNodeUnderwater[NUM_LARA_MESHES]; function lara_control_routines[NUM_LARA_STATES + 1] = { - lara_as_walk, - lara_as_run, - lara_as_stop, + lara_as_walk_forward, + lara_as_run_forward, + lara_as_idle, lara_as_forwardjump, - lara_void_func,//4 - lara_as_fastback,//5 - lara_as_turn_r,//6 - lara_as_turn_l,//7 + lara_as_pose,//4 + lara_as_run_back,//5 + lara_as_turn_right_slow,//6 + lara_as_turn_left_slow,//7 lara_as_death,//8 lara_as_fastfall, lara_as_hang, @@ -70,14 +72,14 @@ function lara_control_routines[NUM_LARA_STATES + 1] = lara_as_tread, lara_void_func, lara_as_compress,//15 - lara_as_back,//16 + lara_as_walk_back,//16 lara_as_swim,//17 lara_as_glide,//18 - lara_as_null,//19 - lara_as_fastturn,//20 - lara_as_stepright,//21 - lara_as_stepleft,//22 - lara_void_func, + 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, lara_as_slide,//24 lara_as_backjump,//25 lara_as_rightjump,//26 @@ -99,7 +101,7 @@ function lara_control_routines[NUM_LARA_STATES + 1] = lara_as_usekey,//42 lara_as_usepuzzle,//43 lara_as_uwdeath,//44 - lara_void_func,//45 + lara_as_roll_forward,//45 lara_as_special,//46 lara_as_surfback,//47 lara_as_surfleft,//48 @@ -119,38 +121,38 @@ function lara_control_routines[NUM_LARA_STATES + 1] = lara_void_func, lara_void_func, lara_void_func, - lara_as_wade,//65 + lara_as_wade_forward,//65 lara_as_waterroll,//66 lara_as_pickupflare,//67 lara_void_func,//68 lara_void_func,//69 lara_as_deathslide,//70 - lara_as_duck,//71 + lara_as_crouch_idle,//71 lara_as_crouch_roll,//72 - lara_as_dash, - lara_as_dashdive, + lara_as_sprint, + lara_as_sprint_dive, lara_as_monkey_idle, lara_as_monkeyswing, lara_as_monkeyl, lara_as_monkeyr, lara_as_monkey180, - lara_as_all4s,//80 - lara_as_crawl,//81 + lara_as_crawl_idle,//80 + lara_as_crawl_forward,//81 lara_as_hangturnl, lara_as_hangturnr, - lara_as_all4turnl,//84 - lara_as_all4turnr,//85 - lara_as_crawlb,//86 - lara_as_null, - lara_as_null, + 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, lara_as_controlled, lara_as_ropel, lara_as_roper, lara_as_controlled, lara_as_controlled, lara_as_controlled, - lara_as_controlledl, - lara_as_controlledl, + lara_as_controlled_no_look, + lara_as_controlled_no_look, lara_as_controlled, lara_as_pickup,//98 lara_as_pole_idle,//99 @@ -159,8 +161,8 @@ function lara_control_routines[NUM_LARA_STATES + 1] = lara_as_pole_turn_clockwise,//102 lara_as_pole_turn_counter_clockwise,//103 lara_as_pulley,//104 - lara_as_duckl,//105 - lara_as_duckr,//106 + lara_as_crouch_turn_left,//105 + lara_as_crouch_turn_right,//106 lara_as_corner,//107 lara_as_corner,//108 lara_as_corner,//109 @@ -174,7 +176,7 @@ function lara_control_routines[NUM_LARA_STATES + 1] = lara_as_controlled, lara_as_swimcheat, lara_as_trpose,//119 - lara_as_null,//120 + lara_as_controlled_no_look,//120 lara_as_trwalk,//121 lara_as_trfall,//122 lara_as_trfall,//123 @@ -189,8 +191,8 @@ function lara_control_routines[NUM_LARA_STATES + 1] = lara_as_parallelbars,//128 lara_as_pbleapoff,//129 lara_as_null,//130 - lara_as_null,//131 - lara_as_null,//132 + lara_as_controlled_no_look,//131 + lara_as_controlled_no_look,//132 lara_as_null,//133 lara_as_null,//134 lara_as_null,//135 @@ -204,23 +206,27 @@ function lara_control_routines[NUM_LARA_STATES + 1] = lara_as_null,// 143 - Unused lara_as_null,// 144 - Unused lara_as_null,// 145 - Unused - lara_as_controlledl, + lara_as_controlled_no_look, lara_as_null, lara_as_null, lara_as_null, lara_as_stepoff_left, - lara_as_stepoff_right + lara_as_stepoff_right, + lara_as_turn_left_fast, + lara_as_controlled, + lara_as_controlled, + lara_as_controlled }; function lara_collision_routines[NUM_LARA_STATES + 1] = { - lara_col_walk, - lara_col_run, - lara_col_stop, + lara_col_walk_forward, + lara_col_run_forward, + lara_col_idle, lara_col_forwardjump, - lara_col_pose, - lara_col_fastback, - lara_col_turn_r, - lara_col_turn_l, + lara_col_idle,//4 + lara_col_run_back, + lara_col_turn_right_slow, + lara_col_turn_left_slow, lara_col_death, lara_col_fastfall, lara_col_hang, @@ -229,14 +235,14 @@ function lara_collision_routines[NUM_LARA_STATES + 1] = { lara_col_tread, lara_col_land, lara_col_compress, - lara_col_back, + lara_col_walk_back, lara_col_swim, lara_col_glide, lara_default_col, - lara_col_fastturn, - lara_col_stepright, - lara_col_stepleft, - lara_col_roll2, + lara_col_turn_right_fast, + lara_col_step_right, + lara_col_step_left, + lara_col_roll_back, lara_col_slide, lara_col_backjump, lara_col_rightjump, @@ -258,7 +264,7 @@ function lara_collision_routines[NUM_LARA_STATES + 1] = { lara_default_col, lara_default_col, lara_col_uwdeath, - lara_col_roll, + lara_col_roll_forward, lara_void_func, lara_col_surfback, lara_col_surfleft, @@ -278,30 +284,30 @@ function lara_collision_routines[NUM_LARA_STATES + 1] = { lara_void_func, lara_void_func, lara_void_func, - lara_col_wade, + lara_col_wade_forward, lara_col_waterroll, lara_default_col, lara_void_func, lara_void_func, lara_void_func, - lara_col_duck, + lara_col_crouch_idle, lara_col_crouch_roll, - lara_col_dash, - lara_col_dashdive, + lara_col_sprint, + lara_col_sprint_dive, lara_col_monkey_idle, lara_col_monkeyswing, lara_col_monkeyl, lara_col_monkeyr, lara_col_monkey180, - lara_col_all4s, - lara_col_crawl, + lara_col_crawl_idle, + lara_col_crawl_forward, lara_col_hangturnlr, lara_col_hangturnlr, - lara_col_all4turnlr, - lara_col_all4turnlr, - lara_col_crawlb, + lara_col_crawl_turn_left, + lara_col_crawl_turn_right, + lara_col_crawl_back, lara_void_func, - lara_col_crawl2hang, + lara_col_crawl_to_hang, lara_default_col, lara_void_func, lara_void_func, @@ -318,8 +324,8 @@ function lara_collision_routines[NUM_LARA_STATES + 1] = { lara_col_pole_turn_clockwise, lara_col_pole_turn_counter_clockwise, lara_default_col, - lara_col_ducklr, - lara_col_ducklr, + lara_col_crouch_turn_left, + lara_col_crouch_turn_right, lara_default_col, lara_default_col, lara_default_col, @@ -364,59 +370,63 @@ function lara_collision_routines[NUM_LARA_STATES + 1] = { lara_void_func, lara_void_func, lara_default_col, + lara_default_col, + lara_col_turn_left_fast, + lara_default_col, + lara_default_col, lara_default_col }; void LaraControl(ITEM_INFO* item, COLL_INFO* coll) { - LaraCheatyBits(); + LaraInfo*& info = item->data; - if (Lara.hasFired) + if (info->hasFired) { AlertNearbyGuards(item); - Lara.hasFired = false; + info->hasFired = false; } - if (Lara.poisoned) + if (info->poisoned) { - if (Lara.poisoned > 4096) - Lara.poisoned = 4096; + if (info->poisoned > 4096) + info->poisoned = 4096; - if (Lara.poisoned >= 256 && !(Wibble & 0xFF)) - item->hitPoints -= Lara.poisoned >> 8; + if (info->poisoned >= 256 && !(Wibble & 0xFF)) + item->hitPoints -= info->poisoned >> 8; } - if (Lara.isMoving) + if (info->isMoving) { - if (Lara.moveCount > 90) + if (info->moveCount > 90) { - Lara.isMoving = false; - Lara.gunStatus = LG_NO_ARMS; + info->isMoving = false; + info->gunStatus = LG_HANDS_FREE; } - ++Lara.moveCount; + ++info->moveCount; } - if (!Lara.uncontrollable) - Lara.locationPad = 128; + if (!info->uncontrollable) + info->locationPad = 128; int oldX = item->pos.xPos; int oldY = item->pos.yPos; int oldZ = item->pos.zPos; - if (Lara.gunStatus == LG_HANDS_BUSY && - item->currentAnimState == LS_STOP && - item->goalAnimState == LS_STOP && + if (info->gunStatus == LG_HANDS_BUSY && + item->currentAnimState == LS_IDLE && + item->goalAnimState == LS_IDLE && item->animNumber == LA_STAND_IDLE && !item->gravityStatus) { - Lara.gunStatus = LG_NO_ARMS; + info->gunStatus = LG_HANDS_FREE; } - if (item->currentAnimState != LS_SPRINT && Lara.sprintTimer < LARA_SPRINT_MAX) - Lara.sprintTimer++; + if (item->currentAnimState != LS_SPRINT && info->sprintTimer < LARA_SPRINT_MAX) + info->sprintTimer++; - Lara.isDucked = false; + info->isDucked = false; bool isWater = TestLaraWater(item); bool isSwamp = TestLaraSwamp(item); @@ -429,18 +439,14 @@ void LaraControl(ITEM_INFO* item, COLL_INFO* coll) heightFromWater = item->pos.yPos - waterHeight; else heightFromWater = NO_HEIGHT; - Lara.waterSurfaceDist = -heightFromWater; + info->waterSurfaceDist = -heightFromWater; - if (Lara.Vehicle == NO_ITEM) + if (info->Vehicle == NO_ITEM) WadeSplash(item, waterHeight, waterDepth); - TriggerLaraDrips(item); - - short roomNumber; - - if (Lara.Vehicle == NO_ITEM && Lara.ExtraAnim == -1) + if (info->Vehicle == NO_ITEM && info->ExtraAnim == -1) { - switch (Lara.waterStatus) + switch (info->waterStatus) { case LW_ABOVE_WATER: if (heightFromWater == NO_HEIGHT || heightFromWater < WADE_DEPTH) @@ -448,17 +454,14 @@ void LaraControl(ITEM_INFO* item, COLL_INFO* coll) Camera.targetElevation = -ANGLE(22.0f); - - if (waterDepth > (SWIM_DEPTH - STEP_SIZE) && - !isSwamp && - item->currentAnimState != LS_RUN_FORWARD && // Prevent ridiculous entrances when stepping down into wade-height water. @Sezz 2021.11.17 - item->currentAnimState != LS_WALK_FORWARD && - item->currentAnimState != LS_WALK_BACK) + // Water is deep enough to swim; dispatch dive. + if (waterDepth >= SWIM_DEPTH && + !isSwamp) { if (isWater) { - Lara.air = 1800; - Lara.waterStatus = LW_UNDERWATER; + info->air = LARA_AIR_MAX; + info->waterStatus = LW_UNDERWATER; item->gravityStatus = false; item->pos.yPos += 100; @@ -467,6 +470,7 @@ void LaraControl(ITEM_INFO* item, COLL_INFO* coll) if (item->currentAnimState == LS_SWANDIVE_START) { + info->gunStatus = LG_HANDS_FREE; item->pos.xRot = -ANGLE(45.0f); item->goalAnimState = LS_DIVE; AnimateLara(item); @@ -474,6 +478,7 @@ void LaraControl(ITEM_INFO* item, COLL_INFO* coll) } else if (item->currentAnimState == LS_SWANDIVE_END) { + info->gunStatus = LG_HANDS_FREE; item->pos.xRot = -ANGLE(85.0f); item->goalAnimState = LS_DIVE; AnimateLara(item); @@ -486,34 +491,41 @@ void LaraControl(ITEM_INFO* item, COLL_INFO* coll) item->fallspeed = 3 * item->fallspeed / 2; } - Lara.torsoYrot = 0; - Lara.torsoXrot = 0; - Lara.headYrot = 0; - Lara.headXrot = 0; - + ResetLaraFlex(item); Splash(item); } } - else if (heightFromWater > WADE_DEPTH) + // Water is at wade depth; update water status and do special handling. + else if (heightFromWater >= WADE_DEPTH) { - Lara.waterStatus = LW_WADE; + info->waterStatus = LW_WADE; - if (!item->gravityStatus) - item->goalAnimState = LS_STOP; + // Make splash ONLY within this particular threshold before swim depth while airborne (WadeSplash() above interferes otherwise). + if (waterDepth > (SWIM_DEPTH - STEP_SIZE) && + !isSwamp && + item->gravityStatus) + { + Splash(item); + item->goalAnimState = LS_IDLE; + } + // Lara is grounded; block land-to-run. + else if (!item->gravityStatus) + item->goalAnimState = LS_IDLE; else if (isSwamp) { - if (item->currentAnimState == LS_SWANDIVE_START || item->currentAnimState == LS_SWANDIVE_END) + if (item->currentAnimState == LS_SWANDIVE_START || + item->currentAnimState == LS_SWANDIVE_END) + { item->pos.yPos = waterHeight + (WALL_SIZE - 24); + } SetAnimation(item, LA_WADE); } } + break; case LW_UNDERWATER: - roomNumber = item->roomNumber; - GetFloor(item->pos.xPos, item->pos.yPos - STEP_SIZE, item->pos.zPos, &roomNumber); - if (isWater || waterDepth == DEEP_WATER || abs(heightFromWater) >= STEP_SIZE || @@ -530,11 +542,8 @@ void LaraControl(ITEM_INFO* item, COLL_INFO* coll) item->fallspeed = 0; item->pos.zRot = 0; item->pos.xRot = 0; - Lara.waterStatus = LW_ABOVE_WATER; - Lara.torsoYrot = 0; - Lara.torsoXrot = 0; - Lara.headYrot = 0; - Lara.headXrot = 0; + info->waterStatus = LW_ABOVE_WATER; + ResetLaraFlex(item); } else { @@ -543,12 +552,9 @@ void LaraControl(ITEM_INFO* item, COLL_INFO* coll) item->fallspeed = 0; item->pos.zRot = 0; item->pos.xRot = 0; - Lara.waterStatus = LW_SURFACE; - Lara.diveCount = 11; - Lara.torsoYrot = 0; - Lara.torsoXrot = 0; - Lara.headYrot = 0; - Lara.headXrot = 0; + info->waterStatus = LW_SURFACE; + info->diveCount = 11; + ResetLaraFlex(item); UpdateItemRoom(item, -(STEPUP_HEIGHT - 3)); SoundEffect(SFX_TR4_LARA_BREATH, &item->pos, 2); @@ -562,12 +568,9 @@ void LaraControl(ITEM_INFO* item, COLL_INFO* coll) item->fallspeed = 0; item->pos.zRot = 0; item->pos.xRot = 0; - Lara.waterStatus = LW_SURFACE; - Lara.diveCount = 11; - Lara.torsoYrot = 0; - Lara.torsoXrot = 0; - Lara.headYrot = 0; - Lara.headXrot = 0; + info->waterStatus = LW_SURFACE; + info->diveCount = 11; + ResetLaraFlex(item); UpdateItemRoom(item, 0); SoundEffect(SFX_TR4_LARA_BREATH, &item->pos, 2); @@ -582,13 +585,13 @@ void LaraControl(ITEM_INFO* item, COLL_INFO* coll) SetAnimation(item, LA_FALL_START); item->speed = item->fallspeed / 4; item->gravityStatus = true; - Lara.waterStatus = LW_ABOVE_WATER; + info->waterStatus = LW_ABOVE_WATER; } else { SetAnimation(item, LA_STAND_IDLE); item->goalAnimState = LS_WADE_FORWARD; // TODO: Check if really needed? -- Lwmte, 10.11.21 - Lara.waterStatus = LW_WADE; + info->waterStatus = LW_WADE; AnimateItem(item); } @@ -596,10 +599,7 @@ void LaraControl(ITEM_INFO* item, COLL_INFO* coll) item->fallspeed = 0; item->pos.zRot = 0; item->pos.xRot = 0; - Lara.torsoYrot = 0; - Lara.torsoXrot = 0; - Lara.headYrot = 0; - Lara.headXrot = 0; + ResetLaraFlex(item); } break; @@ -613,24 +613,21 @@ void LaraControl(ITEM_INFO* item, COLL_INFO* coll) { SetAnimation(item, LA_ONWATER_IDLE); - Lara.waterStatus = LW_SURFACE; + info->waterStatus = LW_SURFACE; item->pos.yPos += 1 - heightFromWater; item->gravityStatus = false; item->fallspeed = 0; item->pos.zRot = 0; item->pos.xRot = 0; - Lara.diveCount = 0; - Lara.torsoYrot = 0; - Lara.torsoXrot = 0; - Lara.headYrot = 0; - Lara.headXrot = 0; + info->diveCount = 0; + ResetLaraFlex(item); UpdateItemRoom(item, 0); } } else { - Lara.waterStatus = LW_ABOVE_WATER; + info->waterStatus = LW_ABOVE_WATER; if (item->currentAnimState == LS_WADE_FORWARD) item->goalAnimState = LS_RUN_FORWARD; @@ -644,41 +641,41 @@ void LaraControl(ITEM_INFO* item, COLL_INFO* coll) { item->hitPoints = -1; - if (Lara.deathCount == 0) + if (info->deathCount == 0) StopSoundTracks(); - Lara.deathCount++; + info->deathCount++; if ((item->flags & 0x100)) { - Lara.deathCount++; + info->deathCount++; return; } } - switch (Lara.waterStatus) + switch (info->waterStatus) { case LW_ABOVE_WATER: case LW_WADE: - if (isSwamp && Lara.waterSurfaceDist < -(LARA_HEIGHT + 8)) // TODO: Find best height. @Sezz 2021.11.10 + if (isSwamp && info->waterSurfaceDist < -(LARA_HEIGHT + 8)) // TODO: Find best height. @Sezz 2021.11.10 { if (item->hitPoints >= 0) { - Lara.air -= 6; - if (Lara.air < 0) + info->air -= 6; + if (info->air < 0) { - Lara.air = -1; + info->air = -1; item->hitPoints -= 10; } } } - else if (Lara.air < LARA_AIR_MAX && item->hitPoints >= 0) + else if (info->air < LARA_AIR_MAX && item->hitPoints >= 0) { - if (Lara.Vehicle == NO_ITEM) // only for the upv !! + if (info->Vehicle == NO_ITEM) // only for the upv !! { - Lara.air += 10; - if (Lara.air > LARA_AIR_MAX) - Lara.air = LARA_AIR_MAX; + info->air += 10; + if (info->air > LARA_AIR_MAX) + info->air = LARA_AIR_MAX; } } @@ -691,13 +688,13 @@ void LaraControl(ITEM_INFO* item, COLL_INFO* coll) { auto level = g_GameFlow->GetLevel(CurrentLevel); if (level->LaraType != LaraType::Divesuit) - Lara.air--; + info->air--; - if (Lara.air < 0) + if (info->air < 0) { - // if (LaraDrawType == LARA_TYPE::DIVESUIT && Lara.anxiety < 251) - // Lara.anxiety += 4; - Lara.air = -1; + // if (LaraDrawType == LARA_TYPE::DIVESUIT && info->anxiety < 251) + // info->anxiety += 4; + info->air = -1; item->hitPoints -= 5; } } @@ -709,9 +706,9 @@ void LaraControl(ITEM_INFO* item, COLL_INFO* coll) case LW_SURFACE: if (item->hitPoints >= 0) { - Lara.air += 10; - if (Lara.air > LARA_AIR_MAX) - Lara.air = LARA_AIR_MAX; + info->air += 10; + if (info->air > LARA_AIR_MAX) + info->air = LARA_AIR_MAX; } LaraSurface(item, coll); @@ -732,6 +729,8 @@ void LaraControl(ITEM_INFO* item, COLL_INFO* coll) void LaraAboveWater(ITEM_INFO* item, COLL_INFO* coll) { + LaraInfo*& info = item->data; + coll->Setup.OldPosition.x = item->pos.xPos; coll->Setup.OldPosition.y = item->pos.yPos; coll->Setup.OldPosition.z = item->pos.zPos; @@ -746,25 +745,25 @@ void LaraAboveWater(ITEM_INFO* item, COLL_INFO* coll) coll->Setup.DeathFlagIsPit = false; coll->Setup.Mode = COLL_PROBE_MODE::QUADRANTS; - coll->Setup.Radius = LARA_RAD; - coll->Setup.Height = LARA_HEIGHT; - - if (TrInput & IN_LOOK && Lara.look && - Lara.ExtraAnim == NO_ITEM) + if (TrInput & IN_LOOK && info->look && + info->ExtraAnim == NO_ITEM) { LookLeftRight(); } - else - ResetLook(); + 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); - Lara.look = true; + // TODO: Move radius and height default resets above look checks when + coll->Setup.Radius = LARA_RAD; + coll->Setup.Height = LARA_HEIGHT; + info->look = true; UpdateItemRoom(item, -LARA_HEIGHT / 2); - // Process Vehicles - if (Lara.Vehicle != NO_ITEM) + // Process vehicles. + if (info->Vehicle != NO_ITEM) { - switch (g_Level.Items[Lara.Vehicle].objectNumber) + switch (g_Level.Items[info->Vehicle].objectNumber) { case ID_QUAD: if (QuadBikeControl(item, coll)) @@ -807,53 +806,40 @@ void LaraAboveWater(ITEM_INFO* item, COLL_INFO* coll) break; default: - // Boats are processed like normal items in loop + // Boats are processed like normal items in loop. LaraGun(item); return; } } - // Handle current Lara status + // Handle current Lara status. lara_control_routines[item->currentAnimState](item, coll); - if (item->pos.zRot >= -ANGLE(1.0f) && item->pos.zRot <= ANGLE(1.0f)) - item->pos.zRot = 0; - else if (item->pos.zRot < -ANGLE(1.0f)) - item->pos.zRot += ANGLE(1.0f); - else - item->pos.zRot -= ANGLE(1.0f); + HandleLaraMovementParameters(item, coll); - if (Lara.turnRate >= -ANGLE(2.0f) && Lara.turnRate <= ANGLE(2.0f)) - Lara.turnRate = 0; - else if (Lara.turnRate < -ANGLE(2.0f)) - Lara.turnRate += ANGLE(2.0f); - else - Lara.turnRate -= ANGLE(2.0f); - item->pos.yRot += Lara.turnRate; - - // Animate Lara + // Animate Lara. AnimateLara(item); - if (Lara.ExtraAnim == -1) + if (info->ExtraAnim == -1) { - // Check for collision with items + // Check for collision with items. DoObjectCollision(item, coll); - // Handle Lara collision - if (Lara.Vehicle == NO_ITEM) + // Handle Lara collision. + if (info->Vehicle == NO_ITEM) lara_collision_routines[item->currentAnimState](item, coll); } - //if (Lara.gunType == WEAPON_CROSSBOW && !LaserSight) + //if (info->gunType == WEAPON_CROSSBOW && !LaserSight) // TrInput &= ~IN_ACTION; - // Handle weapons + // Handle weapons. LaraGun(item); - // Handle breath + // Handle breath. LaraBreath(item); - // Test for flags & triggers + // Test for flags and triggers. ProcessSectorFlags(item); TestTriggers(item, false); TestVolumes(item); @@ -861,6 +847,8 @@ void LaraAboveWater(ITEM_INFO* item, COLL_INFO* coll) void LaraUnderWater(ITEM_INFO* item, COLL_INFO* coll) { + LaraInfo*& info = item->data; + coll->Setup.BadHeightDown = 32512; coll->Setup.BadHeightUp = -400; coll->Setup.BadCeilingHeight = 400; @@ -879,12 +867,13 @@ void LaraUnderWater(ITEM_INFO* item, COLL_INFO* coll) coll->Setup.Radius = LARA_RAD_UNDERWATER; coll->Setup.Height = LARA_HEIGHT; - if (TrInput & IN_LOOK && Lara.look) + if (TrInput & IN_LOOK && info->look) LookLeftRight(); else - ResetLook(); + ResetLook(item); - Lara.look = true; + info->look = true; + info->poseCount = 0; lara_control_routines[item->currentAnimState](item, coll); @@ -892,31 +881,30 @@ void LaraUnderWater(ITEM_INFO* item, COLL_INFO* coll) if (level->LaraType == LaraType::Divesuit) { - if (Lara.turnRate < -ANGLE(0.5f)) - Lara.turnRate += ANGLE(0.5f); - else if (Lara.turnRate > ANGLE(0.5f)) - Lara.turnRate -= ANGLE(0.5f); + if (info->turnRate < -ANGLE(0.5f)) + info->turnRate += ANGLE(0.5f); + else if (info->turnRate > ANGLE(0.5f)) + info->turnRate -= ANGLE(0.5f); else - Lara.turnRate = 0; + info->turnRate = 0; } - else if (Lara.turnRate < -ANGLE(2.0f)) - Lara.turnRate += ANGLE(2.0f); - else if (Lara.turnRate > ANGLE(2.0f)) - Lara.turnRate -= ANGLE(2.0f); + else if (info->turnRate < -ANGLE(2.0f)) + info->turnRate += ANGLE(2.0f); + else if (info->turnRate > ANGLE(2.0f)) + info->turnRate -= ANGLE(2.0f); else - Lara.turnRate = 0; + info->turnRate = 0; - item->pos.yRot += Lara.turnRate; + item->pos.yRot += info->turnRate; if (level->LaraType == LaraType::Divesuit) UpdateSubsuitAngles(); - if (item->pos.zRot < -ANGLE(2.0f)) - item->pos.zRot += ANGLE(2.0f); - else if (item->pos.zRot > ANGLE(2.0f)) - item->pos.zRot -= ANGLE(2.0f); - else - item->pos.zRot = 0; + if (!info->isMoving && !(TrInput & (IN_LEFT | IN_RIGHT))) + { + if (abs(item->pos.zRot) > ANGLE(0.0f)) + item->pos.zRot += item->pos.zRot / -8; + } if (item->pos.xRot < -ANGLE(85.0f)) item->pos.xRot = -ANGLE(85.0f); @@ -938,7 +926,7 @@ void LaraUnderWater(ITEM_INFO* item, COLL_INFO* coll) item->pos.zRot = -ANGLE(22.0f); } - if (Lara.currentActive && Lara.waterStatus != LW_FLYCHEAT) + if (info->currentActive && info->waterStatus != LW_FLYCHEAT) LaraWaterCurrent(coll); AnimateLara(item); @@ -949,7 +937,7 @@ void LaraUnderWater(ITEM_INFO* item, COLL_INFO* coll) DoObjectCollision(item, coll); - if (/*Lara.ExtraAnim == -1 &&*/ Lara.Vehicle == NO_ITEM) + if (/*info->ExtraAnim == -1 &&*/ info->Vehicle == NO_ITEM) lara_collision_routines[item->currentAnimState](item, coll); UpdateItemRoom(item, 0); @@ -963,6 +951,8 @@ void LaraUnderWater(ITEM_INFO* item, COLL_INFO* coll) void LaraSurface(ITEM_INFO* item, COLL_INFO* coll) { + LaraInfo*& info = item->data; + Camera.targetElevation = -ANGLE(22.0f); coll->Setup.BadHeightDown = 32512; @@ -983,33 +973,33 @@ void LaraSurface(ITEM_INFO* item, COLL_INFO* coll) coll->Setup.Radius = LARA_RAD; coll->Setup.Height = LARA_HEIGHT_SURFACE; - if (TrInput & IN_LOOK && Lara.look) + if (TrInput & IN_LOOK && info->look) LookLeftRight(); else - ResetLook(); + ResetLook(item); - Lara.look = true; + info->look = true; + info->poseCount = 0; lara_control_routines[item->currentAnimState](item, coll); - if (item->pos.zRot >= -ANGLE(2) && item->pos.zRot <= ANGLE(2.0f)) - item->pos.zRot = 0; - else if (item->pos.zRot < 0) - item->pos.zRot += ANGLE(2.0f); - else - item->pos.zRot -= ANGLE(2.0f); + if (!info->isMoving && !(TrInput & (IN_LEFT | IN_RIGHT))) + { + if (abs(item->pos.zRot) > ANGLE(0.0f)) + item->pos.zRot += item->pos.zRot / -8; + } - if (Lara.currentActive && Lara.waterStatus != LW_FLYCHEAT) + if (info->currentActive && info->waterStatus != LW_FLYCHEAT) LaraWaterCurrent(coll); AnimateLara(item); - item->pos.xPos += item->fallspeed * phd_sin(Lara.moveAngle) / 4; - item->pos.zPos += item->fallspeed * phd_cos(Lara.moveAngle) / 4; + item->pos.xPos += item->fallspeed * phd_sin(info->moveAngle) / 4; + item->pos.zPos += item->fallspeed * phd_cos(info->moveAngle) / 4; DoObjectCollision(item, coll); - if (Lara.Vehicle == NO_ITEM) + if (info->Vehicle == NO_ITEM) lara_collision_routines[item->currentAnimState](item, coll); UpdateItemRoom(item, 100); @@ -1023,38 +1013,38 @@ void LaraSurface(ITEM_INFO* item, COLL_INFO* coll) void LaraCheat(ITEM_INFO* item, COLL_INFO* coll) { - LaraItem->hitPoints = 1000; + LaraInfo*& info = item->data; + + item->hitPoints = LARA_HEALTH_MAX; LaraUnderWater(item, coll); + if (TrInput & IN_WALK && !(TrInput & IN_LOOK)) { - if (TestLaraWater(item) || (Lara.waterSurfaceDist > 0 && Lara.waterSurfaceDist != NO_HEIGHT)) + if (TestLaraWater(item) || (info->waterSurfaceDist > 0 && info->waterSurfaceDist != NO_HEIGHT)) { - Lara.waterStatus = LW_UNDERWATER; + info->waterStatus = LW_UNDERWATER; SetAnimation(item, LA_UNDERWATER_IDLE); - Lara.torsoYrot = 0; - Lara.torsoXrot = 0; - Lara.headYrot = 0; - Lara.headXrot = 0; + ResetLaraFlex(item); } else { - Lara.waterStatus = LW_ABOVE_WATER; + info->waterStatus = LW_ABOVE_WATER; SetAnimation(item, LA_STAND_SOLID); item->pos.zRot = 0; item->pos.xRot = 0; - Lara.torsoYrot = 0; - Lara.torsoXrot = 0; - Lara.headYrot = 0; - Lara.headXrot = 0; + ResetLaraFlex(item); } - Lara.gunStatus = LG_NO_ARMS; + + info->gunStatus = LG_HANDS_FREE; LaraInitialiseMeshes(); - LaraItem->hitPoints = 1000; + item->hitPoints = LARA_HEALTH_MAX; } } void AnimateLara(ITEM_INFO* item) { + LaraInfo*& info = item->data; + item->frameNumber++; ANIM_STRUCT* anim = &g_Level.Anims[item->animNumber]; @@ -1083,16 +1073,16 @@ void AnimateLara(ITEM_INFO* item) item->fallspeed = *(cmd++); item->speed = *(cmd++); item->gravityStatus = true; - if (Lara.calcFallSpeed) + if (info->calcFallSpeed) { - item->fallspeed = Lara.calcFallSpeed; - Lara.calcFallSpeed = 0; + item->fallspeed = info->calcFallSpeed; + info->calcFallSpeed = 0; } break; case COMMAND_ATTACK_READY: - if (Lara.gunStatus != LG_SPECIAL) - Lara.gunStatus = LG_NO_ARMS; + if (info->gunStatus != LG_SPECIAL) + info->gunStatus = LG_HANDS_FREE; break; case COMMAND_SOUND_FX: @@ -1140,8 +1130,8 @@ void AnimateLara(ITEM_INFO* item) flags = cmd[1] & 0xC000; if ( flags == (int)SOUND_PLAYCONDITION::LandAndWater || - (flags == (int)SOUND_PLAYCONDITION::Land && (Lara.waterSurfaceDist >= 0 || Lara.waterSurfaceDist == NO_HEIGHT)) || - (flags == (int)SOUND_PLAYCONDITION::Water && Lara.waterSurfaceDist < 0 && Lara.waterSurfaceDist != NO_HEIGHT && !TestLaraSwamp(item))) + (flags == (int)SOUND_PLAYCONDITION::Land && (info->waterSurfaceDist >= 0 || info->waterSurfaceDist == NO_HEIGHT)) || + (flags == (int)SOUND_PLAYCONDITION::Water && info->waterSurfaceDist < 0 && info->waterSurfaceDist != NO_HEIGHT && !TestLaraSwamp(item))) { SoundEffect(cmd[1] & 0x3FFF, &item->pos, 2); } @@ -1204,7 +1194,7 @@ void AnimateLara(ITEM_INFO* item) { int velocity; - if (Lara.waterStatus == LW_WADE && TestLaraSwamp(item)) + if (info->waterStatus == LW_WADE && TestLaraSwamp(item)) { velocity = (anim->velocity >> 1); if (anim->acceleration) @@ -1220,11 +1210,11 @@ void AnimateLara(ITEM_INFO* item) item->speed = velocity >> 16; } - if (Lara.ropePtr != -1) + if (info->ropePtr != -1) DelAlignLaraToRope(item); - if (!Lara.isMoving) - MoveItem(item, Lara.moveAngle, item->speed, lateral); + if (!info->isMoving) + MoveItem(item, info->moveAngle, item->speed, lateral); // Update matrices g_Renderer.updateLaraAnimations(true); diff --git a/TR5Main/Game/Lara/lara.h b/TR5Main/Game/Lara/lara.h index dacb35255..1cc37f48f 100644 --- a/TR5Main/Game/Lara/lara.h +++ b/TR5Main/Game/Lara/lara.h @@ -4,25 +4,44 @@ struct ITEM_INFO; struct COLL_INFO; -#define FRONT_ARC ANGLE(90.0f) +#define LARA_GRAB_THRESHOLD ANGLE(35.0f) +#define FRONT_ARC ANGLE(90.0f) // TODO: Check use. + +// Lean rates #define LARA_LEAN_RATE ANGLE(1.5f) #define LARA_LEAN_MAX ANGLE(11.0f) -#define LARA_LEAN_DASH_MAX ANGLE(16.0f) -#define LARA_TURN_RATE ANGLE(2.25f) -#define SUB_SUIT_TURN_RATE ANGLE(0.75f) -#define LARA_JUMP_TURN ANGLE(3.0f) -#define LARA_SLOW_TURN ANGLE(4.0f) -#define LARA_MED_TURN ANGLE(6.0f) -#define LARA_FAST_TURN ANGLE(8.0f) -#define LARA_GRAB_THRESHOLD ANGLE(30.0f) -constexpr auto LARA_HEIGHT = CLICK(3) - 1; // The size of Lara (from the floor to the top of the head) -constexpr auto LARA_HEIGHT_CRAWL = 400; // Size of Lara in crawl state -constexpr auto LARA_HEIGHT_MONKEY = 600; // Size of Lara in monkey state -constexpr auto LARA_HEIGHT_SURFSWIM = 700; // Size of Lara in surface swim state -constexpr auto LARA_HEIGHT_STRETCH = 870; // Size of Lara in jump-up or ledge hanging state -constexpr auto LARA_HEIGHT_SURFACE = 800; // Size of Lara when surfacing water -constexpr auto LARA_HEADROOM = 160; // Amount of reasonable space above Lara's head +// Turn rates +#define LARA_TURN_RATE ANGLE(2.25f) +#define LARA_CRAWL_MOVE_TURN_RATE ANGLE(2.15f) +#define LARA_POLE_TURN_RATE ANGLE(2.25f) +#define LARA_SUBSUIT_TURN_RATE ANGLE(0.75f) + +// Turn rate maxes +#define LARA_SLOW_TURN_MAX ANGLE(4.0f) +#define LARA_SLOW_MED_TURN_MAX ANGLE(5.0f) +#define LARA_MED_TURN_MAX ANGLE(6.0f) +#define LARA_MED_FAST_TURN_MAX ANGLE(7.0f) +#define LARA_FAST_TURN_MAX ANGLE(8.0f) +#define LARA_WADE_TURN_MAX ANGLE(5.5f) +#define LARA_SWAMP_TURN_MAX ANGLE(2.0f) +#define LARA_JUMP_TURN_MAX ANGLE(3.0f) +#define LARA_CRAWL_TURN_MAX ANGLE(2.0f) +#define LARA_CRAWL_MOVE_TURN_MAX ANGLE(3.75f) +#define LARA_CROUCH_ROLL_TURN_MAX ANGLE(2.75f) +#define LARA_POLE_TURN_MAX ANGLE(4.5f) + +// Flex rates +#define LARA_CRAWL_FLEX_RATE ANGLE(2.25f) +#define LARA_CRAWL_FLEX_MAX ANGLE(50.0f) / 2 // 2 = hardcoded number of bones to flex (head and torso). + +constexpr auto LARA_HEIGHT = CLICK(3) - 1; // Lara height in standard states. +constexpr auto LARA_HEIGHT_CRAWL = 350; // Lara height in crawl states. +constexpr auto LARA_HEIGHT_MONKEY = 600; // Lara height in monkey swing states. +constexpr auto LARA_HEIGHT_SURFSWIM = 700; // Lara height in water treading states. +constexpr auto LARA_HEIGHT_STRETCH = 870; // Lara height in jump-up and ledge hanging states. +constexpr auto LARA_HEIGHT_SURFACE = 800; // Lara height when surfacing water. +constexpr auto LARA_HEADROOM = 160; // Amount of reasonable space above Lara's head. constexpr auto LARA_RAD = 100; constexpr auto LARA_RAD_CRAWL = 200; constexpr auto LARA_RAD_UNDERWATER = 300; @@ -30,6 +49,9 @@ constexpr auto LARA_RAD_DEATH = 400; constexpr auto LARA_FREEFALL_SPEED = 131; constexpr auto LARA_VELOCITY = 12; +constexpr auto LARA_JUMP_TIME = 22; // Frames to count before running jump is possible. +constexpr auto LARA_POSE_TIME = 30 * 30; // 30 frames * 30 = 30 seconds to AFK pose. + constexpr auto LARA_HEALTH_MAX = 1000.0f; constexpr auto LARA_AIR_MAX = 1800.0f; constexpr auto LARA_SPRINT_MAX = 120.0f; diff --git a/TR5Main/Game/Lara/lara_basic.cpp b/TR5Main/Game/Lara/lara_basic.cpp index f70b330d4..33a3ce7b3 100644 --- a/TR5Main/Game/Lara/lara_basic.cpp +++ b/TR5Main/Game/Lara/lara_basic.cpp @@ -5,6 +5,7 @@ #include "lara_collide.h" #include "lara_slide.h" #include "lara_monkey.h" +#include "lara_helpers.h" #include "input.h" #include "level.h" #include "setup.h" @@ -15,9 +16,17 @@ #include "collide.h" #include "items.h" #include "camera.h" -#include "Scripting/GameFlowScript.h" +#include "GameFlowScript.h" + +// ------------------------------ +// BASIC MOVEMENT & MISCELLANEOUS +// Control & Collision Functions +// ------------------------------ + +// -------------- +// MISCELLANEOUS: +// -------------- -/*generic functions*/ void lara_void_func(ITEM_INFO* item, COLL_INFO* coll) { return; @@ -25,13 +34,15 @@ void lara_void_func(ITEM_INFO* item, COLL_INFO* coll) void lara_default_col(ITEM_INFO* item, COLL_INFO* coll) { - Lara.moveAngle = item->pos.yRot; + LaraInfo*& info = item->data; + + info->moveAngle = item->pos.yRot; coll->Setup.BadHeightDown = STEPUP_HEIGHT; coll->Setup.BadHeightUp = -STEPUP_HEIGHT; coll->Setup.BadCeilingHeight = 0; coll->Setup.SlopesArePits = true; coll->Setup.SlopesAreWalls = true; - coll->Setup.ForwardAngle = Lara.moveAngle; + coll->Setup.ForwardAngle = info->moveAngle; GetCollisionInfo(coll, item); LaraResetGravityStatus(item, coll); } @@ -51,1758 +62,249 @@ void lara_as_null(ITEM_INFO* item, COLL_INFO* coll) void lara_as_controlled(ITEM_INFO* item, COLL_INFO* coll) { - Lara.look = false; + LaraInfo*& info = item->data; + + info->look = false; coll->Setup.EnableObjectPush = false; coll->Setup.EnableSpaz = false; + if (item->frameNumber == g_Level.Anims[item->animNumber].frameEnd - 1) { - Lara.gunStatus = LG_NO_ARMS; + info->gunStatus = LG_HANDS_FREE; + if (UseForcedFixedCamera) UseForcedFixedCamera = 0; } } -void lara_as_controlledl(ITEM_INFO* item, COLL_INFO* coll) +void lara_as_controlled_no_look(ITEM_INFO* item, COLL_INFO* coll) { - Lara.look = false; + LaraInfo*& info = item->data; + + info->look = false; coll->Setup.EnableObjectPush = false; coll->Setup.EnableSpaz = false; } -/*end generic functions*/ -/*-*/ -/*basic movement*/ -void lara_as_walk(ITEM_INFO* item, COLL_INFO* coll) +// --------------- +// BASIC MOVEMENT: +// --------------- + +// State: LS_WALK_FORWARD (0) +// Collision: lara_col_walk_forward() +void lara_as_walk_forward(ITEM_INFO* item, COLL_INFO* coll) { - /*state 0*/ - /*collision: lara_col_walk*/ - if (item->hitPoints <= 0) - { - item->goalAnimState = LS_STOP; - return; - } + LaraInfo*& info = item->data; - if (!Lara.isMoving) - { - 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; - } + info->jumpCount++; + if (info->jumpCount > LARA_JUMP_TIME - 4) + info->jumpCount = LARA_JUMP_TIME - 4; - 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; - } - } - else - { - item->goalAnimState = LS_STOP; - } - } -} - -void lara_col_walk(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 0*/ - /*state code: lara_as_walk*/ - item->gravityStatus = false; - item->fallspeed = 0; - - Lara.moveAngle = item->pos.yRot; - - coll->Setup.BadHeightDown = STEPUP_HEIGHT; - coll->Setup.BadHeightUp = -STEPUP_HEIGHT; - coll->Setup.BadCeilingHeight = 0; - - coll->Setup.SlopesAreWalls = true; - coll->Setup.SlopesArePits = true; - coll->Setup.DeathFlagIsPit = 1; - - coll->Setup.ForwardAngle = Lara.moveAngle; - GetCollisionInfo(coll, item); - - if (!LaraHitCeiling(item, coll) && !TestLaraVault(item, coll)) - { - if (LaraDeflectEdge(item, coll)) - { - item->goalAnimState = LS_SPLAT; - if (GetChange(item, &g_Level.Anims[item->animNumber])) - return; - - LaraCollideStop(item, coll); - } - - if (!LaraFallen(item, coll)) - { - if (coll->Middle.Floor > STEP_SIZE / 2) - { - if (coll->Front.Floor == NO_HEIGHT || coll->Front.Floor <= STEP_SIZE / 2) - { - coll->Middle.Floor = 0; - } - else - { - item->goalAnimState = LS_STEP_DOWN; - GetChange(item, &g_Level.Anims[item->animNumber]); - } - } - if (coll->Middle.Floor >= -STEPUP_HEIGHT && coll->Middle.Floor < -STEP_SIZE / 2) - { - if (coll->Front.Floor == NO_HEIGHT || - coll->Front.Floor < -STEPUP_HEIGHT || - coll->Front.Floor >= -STEP_SIZE / 2) - { - coll->Middle.Floor = 0; - } - else - { - item->goalAnimState = LS_STEP_UP; - GetChange(item, &g_Level.Anims[item->animNumber]); - } - } - - if (!TestLaraSlide(item, coll) && coll->Middle.Floor != NO_HEIGHT && coll->CollisionType != CT_FRONT) - item->pos.yPos += coll->Middle.Floor; - } - } -} - -void lara_as_run(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 1*/ - /*collision: lara_col_run*/ if (item->hitPoints <= 0) { item->goalAnimState = LS_DEATH; return; } - if (TrInput & IN_ROLL) + // TODO: Implement item alignment properly someday. @Sezz 2021.11.01 + if (info->isMoving) + return; + + // TODO: If stopping and holding WALK without FORWARD, Lara can't turn. @Sezz 2021.10.09 + if (TrInput & IN_LEFT) { - SetAnimation(item, LA_ROLL_180_START, 2); + info->turnRate -= LARA_TURN_RATE; + if (info->turnRate < -LARA_MED_TURN_MAX) + info->turnRate = -LARA_MED_TURN_MAX; + + DoLaraLean(item, coll, -LARA_LEAN_MAX / 3, LARA_LEAN_RATE / 6); + } + else if (TrInput & IN_RIGHT) + { + info->turnRate += LARA_TURN_RATE; + if (info->turnRate > LARA_MED_TURN_MAX) + info->turnRate = LARA_MED_TURN_MAX; + + DoLaraLean(item, coll, LARA_LEAN_MAX / 3, LARA_LEAN_RATE / 6); + } + + if (TrInput & IN_FORWARD) + { + if (info->waterStatus == LW_WADE) + item->goalAnimState = LS_WADE_FORWARD; + else if (TrInput & IN_WALK) [[likely]] + item->goalAnimState = LS_WALK_FORWARD; + else + item->goalAnimState = LS_RUN_FORWARD; + return; } - if (TrInput & IN_SPRINT && Lara.sprintTimer) + item->goalAnimState = LS_IDLE; +} + +// State: LA_WALK_FORWARD (0) +// Control: lara_as_walk_forward() +void lara_col_walk_forward(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + info->moveAngle = item->pos.yRot; + item->gravityStatus = false; + item->fallspeed = 0; + coll->Setup.BadHeightDown = STEPUP_HEIGHT; + coll->Setup.BadHeightUp = -STEPUP_HEIGHT; + coll->Setup.BadCeilingHeight = 0; + coll->Setup.SlopesAreWalls = true; + coll->Setup.SlopesArePits = true; + coll->Setup.DeathFlagIsPit = true; + coll->Setup.ForwardAngle = info->moveAngle; + GetCollisionInfo(coll, item); + + if (TestLaraHitCeiling(coll)) + { + SetLaraHitCeiling(item, coll); + return; + } + + if (TestLaraFall(item, coll)) + { + SetLaraFallState(item); + return; + } + + if (TestLaraSlide(item, coll)) + return; + + if (TestLaraVault(item, coll)) + return; + + if (LaraDeflectEdge(item, coll)) + { + item->goalAnimState = LS_SPLAT; + if (GetChange(item, &g_Level.Anims[item->animNumber])) + return; + + LaraCollideStop(item, coll); + } + + if (TestLaraStep(coll) && coll->CollisionType != CT_FRONT) + { + DoLaraStep(item, coll); + return; + } +} + +// State: LS_RUN_FORWARD (1) +// Collision: lara_col_run_forward() +void lara_as_run_forward(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + info->jumpCount++; + if (info->jumpCount > LARA_JUMP_TIME) + info->jumpCount = LARA_JUMP_TIME; + + if (item->hitPoints <= 0) + { + item->goalAnimState = LS_DEATH; + return; + } + + if (TrInput & IN_LEFT) + { + info->turnRate -= LARA_TURN_RATE; + if (info->turnRate < -LARA_FAST_TURN_MAX) + info->turnRate = -LARA_FAST_TURN_MAX; + + DoLaraLean(item, coll, -LARA_LEAN_MAX, LARA_LEAN_RATE); + } + else if (TrInput & IN_RIGHT) + { + info->turnRate += LARA_TURN_RATE; + if (info->turnRate > LARA_FAST_TURN_MAX) + info->turnRate = LARA_FAST_TURN_MAX; + + DoLaraLean(item, coll, LARA_LEAN_MAX, LARA_LEAN_RATE); + } + + if ((TrInput & IN_JUMP || info->jumpQueued) && + info->waterStatus != LW_WADE) + { + if (info->jumpCount >= LARA_JUMP_TIME) + { + item->goalAnimState = LS_JUMP_FORWARD; + return; + } + + info->jumpQueued = item->goalAnimState == LS_RUN_FORWARD; + } + + if (TrInput & IN_SPRINT && info->sprintTimer && + info->waterStatus != LW_WADE) { item->goalAnimState = LS_SPRINT; return; } + if (TrInput & IN_ROLL && !info->jumpQueued && + info->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)) + (info->gunStatus == LG_HANDS_FREE || !IsStandingWeapon(info->gunType)) && + info->waterStatus != LW_WADE) { item->goalAnimState = LS_CROUCH_IDLE; return; } - if (TrInput & IN_LEFT) - { - Lara.turnRate -= LARA_TURN_RATE; - if (Lara.turnRate < -LARA_FAST_TURN) - Lara.turnRate = -LARA_FAST_TURN; - - if (TestLaraLean(item, coll)) - { - item->pos.zRot -= LARA_LEAN_RATE; - if (item->pos.zRot < -LARA_LEAN_MAX) - item->pos.zRot = -LARA_LEAN_MAX; - } - else - { - item->pos.zRot -= LARA_LEAN_RATE; - if (item->pos.zRot < -LARA_LEAN_MAX * 3 / 5)//gives best results - item->pos.zRot = -LARA_LEAN_MAX * 3 / 5; - } - } - else if (TrInput & IN_RIGHT) - { - Lara.turnRate += LARA_TURN_RATE; - if (Lara.turnRate > LARA_FAST_TURN) - Lara.turnRate = LARA_FAST_TURN; - - if (TestLaraLean(item, coll)) - { - item->pos.zRot += LARA_LEAN_RATE; - if (item->pos.zRot > LARA_LEAN_MAX) - item->pos.zRot = LARA_LEAN_MAX; - } - else - { - item->pos.zRot += LARA_LEAN_RATE; - if (item->pos.zRot > LARA_LEAN_MAX * 3 / 5)//gives best results - item->pos.zRot = LARA_LEAN_MAX * 3 / 5; - } - } - - static bool doJump = false; - - if (item->animNumber == LA_STAND_TO_RUN) - { - doJump = false; - } - else if (item->animNumber == LA_RUN) - { - if (item->frameNumber == 4) - doJump = true; - } - else - { - doJump = true; - } - - if (TrInput & IN_JUMP && doJump && !item->gravityStatus) - { - item->goalAnimState = LS_JUMP_FORWARD; - } - else 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; - } - } - else - { - item->goalAnimState = LS_STOP; - } -} - -void lara_col_run(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 1*/ - /*state code: lara_col_run*/ - Lara.moveAngle = item->pos.yRot; - - coll->Setup.BadHeightDown = NO_BAD_POS; - coll->Setup.BadHeightUp = -STEPUP_HEIGHT; - coll->Setup.BadCeilingHeight = 0; - coll->Setup.SlopesAreWalls = true; - coll->Setup.ForwardAngle = Lara.moveAngle; - - GetCollisionInfo(coll, item); - LaraResetGravityStatus(item, coll); - - if (!LaraHitCeiling(item, coll) && !TestLaraVault(item, coll)) - { - if (LaraDeflectEdge(item, coll)) - { - item->pos.zRot = 0; - - if (coll->HitTallObject || TestLaraWall(item, 256, 0, -640) != SPLAT_COLL::NONE) - { - item->goalAnimState = LS_SPLAT; - if (GetChange(item, &g_Level.Anims[item->animNumber])) - { - item->currentAnimState = LS_SPLAT; - return; - } - } - - LaraCollideStop(item, coll); - } - - if (!LaraFallen(item, coll)) - { - if (coll->Middle.Floor >= -STEPUP_HEIGHT && coll->Middle.Floor < -STEP_SIZE / 2) - { - if (coll->Front.Floor == NO_HEIGHT || coll->Front.Floor < -STEPUP_HEIGHT || coll->Front.Floor >= -STEP_SIZE / 2) - { - coll->Middle.Floor = 0; - } - else - { - item->goalAnimState = LS_STEP_UP; - GetChange(item, &g_Level.Anims[item->animNumber]); - } - } - - if (!TestLaraSlide(item, coll) && coll->CollisionType != CT_FRONT) - { - if (coll->Middle.Floor < 50) - { - if (coll->Middle.Floor != NO_HEIGHT) - item->pos.yPos += coll->Middle.Floor; - } - 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->Middle.Floor; // move Lara to middle.Floor - else - item->pos.yPos += 50; // do the default aligment - } - } - } - } -} - -void lara_as_stop(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 2*/ - /*collision: lara_col_stop*/ - COLL_RESULT fheight = {}; fheight.Position.Floor = NO_HEIGHT; - COLL_RESULT rheight = {}; rheight.Position.Floor = NO_HEIGHT; - - if (item->hitPoints <= 0) - { - item->goalAnimState = LS_DEATH; - return; - } - - if (item->animNumber != LA_SPRINT_TO_STAND_RIGHT && item->animNumber != LA_SPRINT_TO_STAND_LEFT) - StopSoundEffect(SFX_TR4_LARA_SLIPPING); - - // Handles waterskin and clockwork beetle - if (UseSpecialItem(item)) - return; - - if (TrInput & IN_ROLL && Lara.waterStatus != LW_WADE) - { - SetAnimation(item, LA_ROLL_180_START, 2); - return; - } - - if (TrInput & IN_DUCK - && Lara.waterStatus != LW_WADE - && item->currentAnimState == LS_STOP - && (Lara.gunStatus == LG_NO_ARMS - || Lara.gunType == WEAPON_NONE - || Lara.gunType == WEAPON_PISTOLS - || (Lara.gunType == WEAPON_REVOLVER && !LaserSight) - || Lara.gunType == WEAPON_UZI - || Lara.gunType == WEAPON_FLARE)) - { - item->goalAnimState = LS_CROUCH_IDLE; - return; - } - - item->goalAnimState = LS_STOP; - - if (TrInput & IN_LOOK) - LookUpDown(); - - if (TrInput & IN_LSTEP) - { - auto collFloorResult = LaraCollisionFront(item, item->pos.yRot - ANGLE(90.0f), LARA_RAD + 48); - auto collCeilingResult = LaraCeilingCollisionFront(item, item->pos.yRot - ANGLE(90.0f), LARA_RAD + 48, LARA_HEIGHT); - - if ((collFloorResult.Position.Floor < 128 && collFloorResult.Position.Floor > -128) && !collFloorResult.Position.Slope && collCeilingResult.Position.Ceiling <= 0) - item->goalAnimState = LS_STEP_LEFT; - } - else if (TrInput & IN_RSTEP) - { - auto collFloorResult = LaraCollisionFront(item, item->pos.yRot + ANGLE(90.0f), LARA_RAD + 48); - auto collCeilingResult = LaraCeilingCollisionFront(item, item->pos.yRot + ANGLE(90.0f), LARA_RAD + 48, LARA_HEIGHT); - - if ((collFloorResult.Position.Floor < 128 && collFloorResult.Position.Floor > -128) && !collFloorResult.Position.Slope && collCeilingResult.Position.Ceiling <= 0) - item->goalAnimState = LS_STEP_RIGHT; - } - else if (TrInput & IN_LEFT) - { - Lara.turnRate -= LARA_TURN_RATE; - if (Lara.turnRate < -LARA_FAST_TURN) - Lara.turnRate = -LARA_FAST_TURN; - - item->goalAnimState = LS_TURN_LEFT_SLOW; - } - else if (TrInput & IN_RIGHT) - { - Lara.turnRate += LARA_TURN_RATE; - if (Lara.turnRate > LARA_FAST_TURN) - Lara.turnRate = LARA_FAST_TURN; - - item->goalAnimState = LS_TURN_RIGHT_SLOW; - } - if (TrInput & IN_FORWARD) - fheight = LaraCollisionFront(item, item->pos.yRot, LARA_RAD + 4); - else if (TrInput & IN_BACK) - rheight = LaraCollisionFront(item, item->pos.yRot - ANGLE(180.0f), LARA_RAD + 4); // TR3: item->pos.yRot + ANGLE(180)? - - if (Lara.waterStatus == LW_WADE) { - if (TrInput & IN_JUMP && !TestLaraSwamp(item)) - item->goalAnimState = LS_JUMP_PREPARE; - - if (TrInput & IN_FORWARD) - { - bool wade = false; - - if (TestLaraSwamp(item)) - { - if (fheight.Position.Floor > -(STEPUP_HEIGHT - 1)) - wade = true; - } - else - { - if ((fheight.Position.Floor < (STEPUP_HEIGHT - 1)) && (fheight.Position.Floor > -(STEPUP_HEIGHT - 1))) - wade = true; - } - - if (!wade) - { - Lara.moveAngle = item->pos.yRot; - coll->Setup.BadHeightDown = NO_BAD_POS; - coll->Setup.BadHeightUp = -STEPUP_HEIGHT; - coll->Setup.BadCeilingHeight = 0; - coll->Setup.SlopesAreWalls = true; - coll->Setup.Radius = LARA_RAD + 2; - coll->Setup.ForwardAngle = Lara.moveAngle; - - GetCollisionInfo(coll, item); - if (TestLaraVault(item, coll)) - return; - - coll->Setup.Radius = LARA_RAD; - } - else - item->goalAnimState = LS_WADE_FORWARD; - } - else if (TrInput & IN_BACK) - { - if (TestLaraSwamp(item) || Lara.waterStatus == LW_WADE || (TrInput & IN_WALK)) - { - if ((rheight.Position.Floor < (STEPUP_HEIGHT - 1)) && (rheight.Position.Floor > -(STEPUP_HEIGHT - 1)) && !rheight.Position.Slope) - item->goalAnimState = LS_WALK_BACK; - } - else if (rheight.Position.Floor > -(STEPUP_HEIGHT - 1)) - { - item->goalAnimState = LS_HOP_BACK; - } - } - } - else - { - if (TrInput & IN_JUMP) - { - if (!TestLaraSwamp(item) && coll->Middle.Ceiling < -LARA_HEADROOM * 0.7f) - item->goalAnimState = LS_JUMP_PREPARE; - } - else if (TrInput & IN_FORWARD) - { - auto cheight = LaraCeilingCollisionFront(item, item->pos.yRot, LARA_RAD + 4, LARA_HEIGHT); - - // Don't try to move if there is slope in front - if (fheight.Position.Slope && (fheight.Position.Floor < 0 || cheight.Position.Ceiling > 0)) - return; // item->goalAnimState = LS_STOP was removed here because it prevented Lara from rotating while still holding forward. -- Lwmte, 17.09.2021 - - if (TestLaraVault(item, coll)) - return; - - if (TrInput & IN_WALK) - { - if (coll->CollisionType == CT_FRONT) // Never try to walk if there's collision in front - return; - item->goalAnimState = LS_WALK_FORWARD; - } - else - { - if (cheight.Position.Ceiling > 0) // Only try to run if there's no overhang ceiling in front - return; - item->goalAnimState = LS_RUN_FORWARD; - } - } - else if (TrInput & IN_BACK) - { - if (TrInput & IN_WALK) - { - if ((rheight.Position.Floor < (STEPUP_HEIGHT - 1)) && (rheight.Position.Floor > -(STEPUP_HEIGHT - 1)) && !rheight.Position.Slope) - item->goalAnimState = LS_WALK_BACK; - } - else if (rheight.Position.Floor > -(STEPUP_HEIGHT - 1)) - { - item->goalAnimState = LS_HOP_BACK; - } - } - } -} - -void lara_col_stop(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 2*/ - /*state code: lara_as_stop*/ - Lara.moveAngle = item->pos.yRot; - coll->Setup.BadHeightDown = STEPUP_HEIGHT; - coll->Setup.BadHeightUp = -STEPUP_HEIGHT; - coll->Setup.BadCeilingHeight = 0; - item->gravityStatus = false; - item->fallspeed = 0; - coll->Setup.SlopesArePits = true; - coll->Setup.SlopesAreWalls = true; - coll->Setup.ForwardAngle = Lara.moveAngle; - GetCollisionInfo(coll, item); - - if (LaraHitCeiling(item, coll)) - return; - - if (LaraFallen(item, coll)) - return; - - if (TestLaraSlide(item, coll)) - return; - - ShiftItem(item, coll); - LaraSnapToHeight(item, coll); -} - -void lara_as_forwardjump(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 3*/ - /*collision: */ - if (item->goalAnimState == LS_SWANDIVE_START || - item->goalAnimState == LS_REACH) - item->goalAnimState = LS_JUMP_FORWARD; - - if (item->goalAnimState != LS_DEATH && - item->goalAnimState != LS_STOP && - item->goalAnimState != LS_RUN_FORWARD) - { - if (Lara.gunStatus == LG_NO_ARMS && TrInput & IN_ACTION) - item->goalAnimState = LS_REACH; - - if (TrInput & IN_BACK || TrInput & IN_ROLL) - item->goalAnimState = LS_JUMP_ROLL_180; - - if (Lara.gunStatus == LG_NO_ARMS && TrInput & IN_WALK) - item->goalAnimState = LS_SWANDIVE_START; - - if (item->fallspeed > LARA_FREEFALL_SPEED) - item->goalAnimState = LS_FREEFALL; - } - - if (TrInput & IN_LEFT) - { - Lara.turnRate -= LARA_TURN_RATE; - - if (Lara.turnRate < -LARA_JUMP_TURN) - Lara.turnRate = -LARA_JUMP_TURN; - } - else if (TrInput & IN_RIGHT) - { - Lara.turnRate += LARA_TURN_RATE; - - if (Lara.turnRate > LARA_JUMP_TURN) - Lara.turnRate = LARA_JUMP_TURN; - } -} - -void lara_col_forwardjump(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 3*/ - /*state code: lara_as_forwardjump*/ - if (item->speed < 0) - Lara.moveAngle = item->pos.yRot + ANGLE(180); - else - Lara.moveAngle = item->pos.yRot; - - coll->Setup.BadHeightDown = NO_BAD_POS; - coll->Setup.BadHeightUp = -STEPUP_HEIGHT; - coll->Setup.BadCeilingHeight = BAD_JUMP_CEILING; - - coll->Setup.ForwardAngle = Lara.moveAngle; - GetCollisionInfo(coll, item); - LaraDeflectEdgeJump(item, coll); - - if (item->speed < 0) - Lara.moveAngle = item->pos.yRot; - - if (item->fallspeed > 0 && (coll->Middle.Floor <= 0 || TestLaraSwamp(item))) - { - 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; - - LaraSnapToHeight(item, coll); - } -} - -void lara_col_pose(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 4*/ - /*state code: lara_void_func*/ - lara_col_stop(item, coll); -} - -void lara_as_fastback(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state: 5*/ - /*collision: lara_col_fastback*/ - item->goalAnimState = LS_STOP; - if (TrInput & IN_LEFT) - { - Lara.turnRate -= LARA_TURN_RATE; - if (Lara.turnRate < -LARA_MED_TURN) - Lara.turnRate = -LARA_MED_TURN; - } - else if (TrInput & IN_RIGHT) - { - Lara.turnRate += LARA_TURN_RATE; - if (Lara.turnRate > LARA_MED_TURN) - Lara.turnRate = LARA_MED_TURN; - } -} - -void lara_col_fastback(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state: 5*/ - /*state code: lara_as_fastback*/ - item->fallspeed = 0; - item->gravityStatus = false; - - Lara.moveAngle = item->pos.yRot + ANGLE(180); - - coll->Setup.SlopesAreWalls = false; - coll->Setup.SlopesArePits = true; - - coll->Setup.BadHeightDown = NO_BAD_POS; - coll->Setup.BadHeightUp = -STEPUP_HEIGHT; - coll->Setup.BadCeilingHeight = 0; - - coll->Setup.ForwardAngle = Lara.moveAngle; - GetCollisionInfo(coll, item); - - if (!LaraHitCeiling(item, coll)) - { - if (coll->Middle.Floor <= 200) - { - if (LaraDeflectEdge(item, coll)) - LaraCollideStop(item, coll); - - if (!TestLaraSlide(item, coll) && coll->Middle.Floor != NO_HEIGHT) - item->pos.yPos += coll->Middle.Floor; - } - else - { - item->fallspeed = 0; - item->gravityStatus = true; - SetAnimation(item, LA_FALL_BACK); - } - } -} - -void lara_as_turn_r(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state: 6*/ - /*collision: */ - if (item->hitPoints <= 0) - { - item->goalAnimState = LS_STOP; - - return; - } - - Lara.turnRate += LARA_TURN_RATE; - - if (Lara.gunStatus != LG_READY || Lara.waterStatus == LW_WADE) - { - if (Lara.turnRate > LARA_SLOW_TURN) - { - if (TrInput & IN_WALK || Lara.waterStatus == LW_WADE) - Lara.turnRate = LARA_SLOW_TURN; - else - item->goalAnimState = LS_TURN_FAST; - } - } - else - { - item->goalAnimState = LS_TURN_FAST; - } - - // Don't try to move forward if button isn't pressed or there's no headroom in front - if (!(TrInput & IN_FORWARD) || coll->CollisionType == CT_FRONT) - { - if (!(TrInput & IN_RIGHT)) - item->goalAnimState = LS_STOP; - - return; - } - - 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; - } -} - -void lara_col_turn_r(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state: 6*/ - /*state code: lara_as_turn_r*/ - item->fallspeed = 0; - item->gravityStatus = false; - Lara.moveAngle = item->pos.yRot; - coll->Setup.BadHeightDown = STEPUP_HEIGHT; - coll->Setup.BadHeightUp = -STEPUP_HEIGHT; - coll->Setup.BadCeilingHeight = 0; - coll->Setup.SlopesAreWalls = true; - coll->Setup.SlopesArePits = true; - coll->Setup.ForwardAngle = Lara.moveAngle; - GetCollisionInfo(coll, item); - - if (coll->Middle.Floor > 100 && !TestLaraSwamp(item)) - { - item->fallspeed = 0; - item->gravityStatus = true; - SetAnimation(item, LA_FALL_START); - return; - } - - if (TestLaraSlide(item, coll)) - return; - - LaraSnapToHeight(item, coll); -} - -void lara_as_turn_l(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 7*/ - /*collision: lara_col_turn_l*/ - if (item->hitPoints <= 0) - { - item->goalAnimState = LS_STOP; - return; - } - - Lara.turnRate -= LARA_TURN_RATE; - - if (Lara.gunStatus != LG_READY || Lara.waterStatus == LW_WADE) - { - if (Lara.turnRate < -LARA_SLOW_TURN) - { - if (TrInput & IN_WALK || Lara.waterStatus == LW_WADE) - Lara.turnRate = -LARA_SLOW_TURN; - else - item->goalAnimState = LS_TURN_FAST; - } - } - else - { - item->goalAnimState = LS_TURN_FAST; - } - - // Don't try to move forward if button isn't pressed or there's no headroom in front - if (!(TrInput & IN_FORWARD) || coll->CollisionType == CT_FRONT) - { - if (!(TrInput & IN_LEFT)) - item->goalAnimState = LS_STOP; - - return; - } - - 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; - } -} - -void lara_col_turn_l(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 7*/ - /*state code: lara_as_turn_l*/ - lara_col_turn_r(item, coll); -} - -void lara_as_death(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 8*/ - /*collision: lara_col_death*/ - Lara.look = false; - coll->Setup.EnableObjectPush = false; - coll->Setup.EnableSpaz = false; - if (BinocularRange) - { - BinocularRange = 0; - LaserSight = false; - AlterFOV(ANGLE(80.0f)); - LaraItem->meshBits = -1; - Lara.busy = false; - } -} - -void lara_col_death(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 8*/ - /*state code: lara_as_death*/ - StopSoundEffect(SFX_TR4_LARA_FALL); - - Lara.moveAngle = item->pos.yRot; - coll->Setup.BadHeightDown = STEPUP_HEIGHT; - coll->Setup.BadHeightUp = -STEPUP_HEIGHT; - coll->Setup.BadCeilingHeight = 0; - coll->Setup.Radius = LARA_RAD_DEATH; - - coll->Setup.ForwardAngle = Lara.moveAngle; - GetCollisionInfo(coll, item); - ShiftItem(item, coll); - - item->hitPoints = -1; - Lara.air = -1; - - if (coll->Middle.Floor != NO_HEIGHT) - item->pos.yPos += coll->Middle.Floor; -} - -void lara_as_fastfall(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 9*/ - /*collision: lara_col_fastfall*/ - item->speed = (item->speed * 95) / 100; - if (item->fallspeed == 154) - SoundEffect(SFX_TR4_LARA_FALL, &item->pos, 0); -} - -void lara_col_fastfall(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 9*/ - /*state code: lara_as_fastfall*/ - item->gravityStatus = true; - - coll->Setup.BadHeightDown = NO_BAD_POS; - coll->Setup.BadHeightUp = -STEPUP_HEIGHT; - coll->Setup.BadCeilingHeight = BAD_JUMP_CEILING; - - coll->Setup.ForwardAngle = Lara.moveAngle; - GetCollisionInfo(coll, item); - LaraSlideEdgeJump(item, coll); - - if (coll->Middle.Floor <= 0 || TestLaraSwamp(item)) - { - if (LaraLandedBad(item, coll)) - item->goalAnimState = LS_DEATH; - else - SetAnimation(item, LA_FREEFALL_LAND); - - StopSoundEffect(SFX_TR4_LARA_FALL); - - item->fallspeed = 0; - item->gravityStatus = false; - - LaraSnapToHeight(item, coll); - } -} - -void lara_as_reach(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 11*/ - /*collision: lara_col_reach*/ - Camera.targetAngle = ANGLE(85.0f); - if (item->fallspeed > LARA_FREEFALL_SPEED) - item->goalAnimState = LS_FREEFALL; -} - -void lara_col_reach(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 11*/ - /*state code: lara_as_reach*/ - if (Lara.ropePtr == -1) - item->gravityStatus = true; - - Lara.moveAngle = item->pos.yRot; - - coll->Setup.Height = LARA_HEIGHT_STRETCH; - coll->Setup.BadHeightDown = NO_BAD_POS; - coll->Setup.BadHeightUp = 0; - coll->Setup.BadCeilingHeight = BAD_JUMP_CEILING; - coll->Setup.ForwardAngle = Lara.moveAngle; - coll->Setup.Radius = coll->Setup.Radius * 1.2f; - coll->Setup.Mode = COLL_PROBE_MODE::FREE_FORWARD; - - GetCollisionInfo(coll, item); - - if (TestLaraHangJump(item, coll)) - return; - - LaraSlideEdgeJump(item, coll); - coll->Setup.ForwardAngle = Lara.moveAngle; - GetCollisionInfo(coll, item); - ShiftItem(item, coll); - - if (item->fallspeed > 0 && coll->Middle.Floor <= 0) - { - if (LaraLandedBad(item, coll)) - { - item->goalAnimState = LS_DEATH; - } - else - { - item->goalAnimState = LS_STOP; - item->fallspeed = 0; - item->gravityStatus = false; - if (coll->Middle.Floor != NO_HEIGHT) - item->pos.yPos += coll->Middle.Floor; - } - } -} - -void lara_as_splat(ITEM_INFO* item, COLL_INFO* coll) -{ - Lara.look = false; -} - -void lara_col_splat(ITEM_INFO* item, COLL_INFO* coll) -{ - Lara.moveAngle = item->pos.yRot; - - coll->Setup.SlopesAreWalls = true; - coll->Setup.SlopesArePits = true; - - coll->Setup.BadHeightDown = STEPUP_HEIGHT; - coll->Setup.BadHeightUp = -STEPUP_HEIGHT; - coll->Setup.BadCeilingHeight = 0; - - coll->Setup.ForwardAngle = Lara.moveAngle; - GetCollisionInfo(coll, item); - ShiftItem(item, coll); - - if (coll->Middle.Floor >= -256 && coll->Middle.Floor <= 256) - item->pos.yPos += coll->Middle.Floor; -} - -void lara_col_land(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 14*/ - /*state code: lara_void_func*/ - lara_col_stop(item, coll); -} - -void lara_as_compress(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 15*/ - /*collision: lara_col_compress*/ - if (Lara.waterStatus != LW_WADE) - { - if (TrInput & IN_FORWARD && !LaraFacingCorner(item, item->pos.yRot, 256) && LaraFloorFront(item, item->pos.yRot, 256) >= -384) - { - item->goalAnimState = LS_JUMP_FORWARD; - Lara.moveAngle = item->pos.yRot; - } - else if (TrInput & IN_LEFT && !LaraFacingCorner(item, item->pos.yRot - ANGLE(90.0f), 256) && LaraFloorFront(item, item->pos.yRot - ANGLE(90.0f), 256) >= -384) - { - item->goalAnimState = LS_JUMP_LEFT; - Lara.moveAngle = item->pos.yRot - ANGLE(90); - } - else if (TrInput & IN_RIGHT && !LaraFacingCorner(item, item->pos.yRot + ANGLE(90.0f), 256) && LaraFloorFront(item, item->pos.yRot + ANGLE(90.0f), 256) >= -384) - { - item->goalAnimState = LS_JUMP_RIGHT; - Lara.moveAngle = item->pos.yRot + ANGLE(90); - } - else if (TrInput & IN_BACK && !LaraFacingCorner(item, item->pos.yRot - ANGLE(180.0f), 256) && LaraFloorFront(item, item->pos.yRot - ANGLE(180.0f), 256) >= -384) - { - item->goalAnimState = LS_JUMP_BACK; - Lara.moveAngle = item->pos.yRot + ANGLE(180); - } - } - - if (item->fallspeed > LARA_FREEFALL_SPEED) - item->goalAnimState = LS_FREEFALL; -} - -void lara_col_compress(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 15*/ - /*state code: lara_as_compress*/ - item->fallspeed = 0; - item->gravityStatus = false; - - coll->Setup.BadHeightDown = NO_BAD_POS; - coll->Setup.BadHeightUp = NO_HEIGHT; - coll->Setup.BadCeilingHeight = 0; - - coll->Setup.ForwardAngle = Lara.moveAngle; - GetCollisionInfo(coll, item); - - if (!LaraFallen(item, coll)) - { - if (coll->Middle.Ceiling > -100) - { - SetAnimation(item, LA_STAND_SOLID); - - item->speed = 0; - item->fallspeed = 0; - item->gravityStatus = false; - - item->pos.xPos = coll->Setup.OldPosition.x; - item->pos.yPos = coll->Setup.OldPosition.y; - item->pos.zPos = coll->Setup.OldPosition.z; - } - - if (coll->Middle.Floor > -256 && coll->Middle.Floor < 256) - item->pos.yPos += coll->Middle.Floor; - } -} - -void lara_as_back(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 16*/ - /*collision: lara_col_back*/ - if (item->hitPoints <= 0) - { - item->goalAnimState = LS_STOP; - return; - } - - if (!Lara.isMoving) - { - if ((TrInput & IN_BACK) && ((TrInput & IN_WALK) || Lara.waterStatus == LW_WADE)) - item->goalAnimState = LS_WALK_BACK; - else - item->goalAnimState = LS_STOP; - - 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; - } - } -} - -void lara_col_back(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 16*/ - /*state code: lara_as_back*/ - item->gravityStatus = false; - item->fallspeed = 0; - Lara.moveAngle = item->pos.yRot + ANGLE(180); - - if (Lara.waterStatus == LW_WADE) - coll->Setup.BadHeightDown = NO_BAD_POS; - else - coll->Setup.BadHeightDown = STEPUP_HEIGHT; - coll->Setup.BadHeightUp = -STEPUP_HEIGHT; - coll->Setup.BadCeilingHeight = 0; - coll->Setup.SlopesArePits = true; - coll->Setup.SlopesAreWalls = true; - coll->Setup.ForwardAngle = Lara.moveAngle; - GetCollisionInfo(coll, item); - - if (LaraHitCeiling(item, coll)) - return; - - if (LaraDeflectEdge(item, coll)) - LaraCollideStop(item, coll); - - if (LaraFallen(item, coll)) - return; - - if (coll->Middle.Floor > STEP_SIZE / 2 && coll->Middle.Floor < STEPUP_HEIGHT) - { - item->goalAnimState = LS_STEP_BACK_DOWN; - GetChange(item, &g_Level.Anims[item->animNumber]); - } - - if (TestLaraSlide(item, coll)) - return; - - LaraSnapToHeight(item, coll); -} - -void lara_as_fastturn(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 20*/ - /*collision: lara_col_fastturn*/ - if (item->hitPoints <= 0) - { - item->goalAnimState = LS_STOP; - return; - } - - if (Lara.turnRate < 0) - { - Lara.turnRate = -LARA_FAST_TURN; - - if (!(TrInput & IN_LEFT)) - item->goalAnimState = LS_STOP; - } - else - { - Lara.turnRate = LARA_FAST_TURN; - - if (!(TrInput & IN_RIGHT)) - item->goalAnimState = LS_STOP; - } -} - -void lara_col_fastturn(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 20*/ - /*state code: lara_as_fastturn*/ - lara_col_stop(item, coll); -} - -void lara_as_stepright(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 21*/ - /*collision: lara_col_stepright*/ - Lara.look = false; - - if (item->hitPoints <= 0) - { - item->goalAnimState = LS_STOP; - return; - } - - if (!Lara.isMoving) - { - if (!(TrInput & IN_RSTEP)) - { - item->goalAnimState = LS_STOP; - } - - 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; - } - } -} - -void lara_col_stepright(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 21*/ - /*state code: lara_as_stepright*/ - if (item->currentAnimState == LS_STEP_RIGHT) - Lara.moveAngle = item->pos.yRot + ANGLE(90); - else - Lara.moveAngle = item->pos.yRot - ANGLE(90); - - item->gravityStatus = false; - item->fallspeed = 0; - - if (Lara.waterStatus == LW_WADE) - coll->Setup.BadHeightDown = NO_BAD_POS; - else - coll->Setup.BadHeightDown = 128; - - coll->Setup.SlopesAreWalls = true; - coll->Setup.SlopesArePits = true; - - coll->Setup.BadHeightUp = -128; - coll->Setup.BadCeilingHeight = 0; - - coll->Setup.ForwardAngle = Lara.moveAngle; - GetCollisionInfo(coll, item); - - if (!LaraHitCeiling(item, coll)) - { - if (LaraDeflectEdge(item, coll)) - LaraCollideStop(item, coll); - - if (!LaraFallen(item, coll) && !TestLaraSlide(item, coll) && coll->Middle.Floor != NO_HEIGHT) - item->pos.yPos += coll->Middle.Floor; - } -} - -void lara_as_stepleft(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 22*/ - /*collision: lara_col_stepleft*/ - Lara.look = false; - - if (item->hitPoints <= 0) - { - item->goalAnimState = LS_STOP; - return; - } - - if (!Lara.isMoving) - { - if (!(TrInput & IN_LSTEP)) - { - item->goalAnimState = LS_STOP; - } - - 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; - } - } -} - -void lara_col_stepleft(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 22*/ - /*state code: lara_as_stepleft*/ - lara_col_stepright(item, coll); -} - -void lara_col_roll2(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 23*/ - /*state code: lara_void_func*/ - Camera.laraNode = 0; - Lara.moveAngle = item->pos.yRot + ANGLE(180); - - coll->Setup.BadHeightDown = NO_BAD_POS; - coll->Setup.BadHeightUp = -STEPUP_HEIGHT; - coll->Setup.BadCeilingHeight = 0; - coll->Setup.SlopesAreWalls = true; - - item->gravityStatus = false; - item->fallspeed = 0; - - coll->Setup.ForwardAngle = Lara.moveAngle; - GetCollisionInfo(coll, item); - - if (LaraHitCeiling(item, coll)) - return; - if (TestLaraSlide(item, coll)) - return; - - if (coll->Middle.Floor > 200) - { - item->fallspeed = 0; - item->gravityStatus = true; - SetAnimation(item, LA_FALL_BACK); - return; - } - - ShiftItem(item, coll); - - if (coll->Middle.Floor != NO_HEIGHT) - item->pos.yPos += coll->Middle.Floor; -} - -void lara_as_backjump(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 25*/ - /*collision: lara_col_backjump*/ - Camera.targetAngle = ANGLE(135.0f); - if (item->fallspeed <= LARA_FREEFALL_SPEED) - { - if (item->goalAnimState == LS_RUN_FORWARD) - { - item->goalAnimState = LS_STOP; - } - else if ((TrInput & IN_FORWARD || TrInput & IN_ROLL) && item->goalAnimState != LS_STOP) - { - item->goalAnimState = LS_JUMP_ROLL_180; - } - } - else - { - item->goalAnimState = LS_FREEFALL; - } -} - -void lara_col_backjump(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 25*/ - /*state code: lara_as_backjump*/ - Lara.moveAngle = item->pos.yRot + ANGLE(180); - lara_col_jumper(item, coll); -} - -void lara_as_rightjump(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 26*/ - /*collision: lara_col_rightjump*/ - Lara.look = false; - if (item->fallspeed > LARA_FREEFALL_SPEED) - item->goalAnimState = LS_FREEFALL; - else if (TrInput & IN_LEFT && item->goalAnimState != LS_STOP) - item->goalAnimState = LS_JUMP_ROLL_180; -} - -void lara_col_rightjump(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 26*/ - /*state code: lara_as_rightjump*/ - Lara.moveAngle = item->pos.yRot + ANGLE(90); - lara_col_jumper(item, coll); -} - -void lara_as_leftjump(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 27*/ - /*collision: lara_col_leftjump*/ - Lara.look = false; - if (item->fallspeed > LARA_FREEFALL_SPEED) - item->goalAnimState = LS_FREEFALL; - else if (TrInput & IN_RIGHT && item->goalAnimState != LS_STOP) - item->goalAnimState = LS_JUMP_ROLL_180; -} - -void lara_col_leftjump(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 27*/ - /*state code: lara_as_leftjump*/ - Lara.moveAngle = item->pos.yRot - ANGLE(90); - lara_col_jumper(item, coll); -} - -void lara_col_jumper(ITEM_INFO* item, COLL_INFO* coll) -{ - /*states 25, 26, 27*/ - /*state code: none, but is called in lara_col_backjump, lara_col_rightjump and lara_col_leftjump*/ - coll->Setup.BadHeightDown = NO_BAD_POS; - coll->Setup.BadHeightUp = -STEPUP_HEIGHT; - coll->Setup.BadCeilingHeight = BAD_JUMP_CEILING; - coll->Setup.ForwardAngle = Lara.moveAngle; - - GetCollisionInfo(coll, item); - LaraDeflectEdgeJump(item, coll); - - if (item->fallspeed > 0 && coll->Middle.Floor <= 0) - { - if (LaraLandedBad(item, coll)) - item->goalAnimState = LS_DEATH; - else - item->goalAnimState = LS_STOP; - - item->fallspeed = 0; - item->gravityStatus = 0; - - if (coll->Middle.Floor != NO_HEIGHT) - item->pos.yPos += coll->Middle.Floor; - } -} - -void lara_as_upjump(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 28*/ - /*collision: lara_col_upjump*/ - if (item->fallspeed > LARA_FREEFALL_SPEED) - { - item->goalAnimState = LS_FREEFALL; - } -} - -void lara_col_upjump(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 28*/ - /*state code: lara_as_upjump*/ - if (item->hitPoints <= 0) - { - item->goalAnimState = LS_STOP; - return; - } - - Lara.moveAngle = item->pos.yRot; - - coll->Setup.Height = LARA_HEIGHT_STRETCH; - coll->Setup.BadHeightDown = NO_BAD_POS; - coll->Setup.BadHeightUp = -STEPUP_HEIGHT; - coll->Setup.BadCeilingHeight = BAD_JUMP_CEILING; - coll->Setup.ForwardAngle = item->speed < 0 ? Lara.moveAngle + ANGLE(180.0f) : Lara.moveAngle; - coll->Setup.Mode = COLL_PROBE_MODE::FREE_FORWARD; - - GetCollisionInfo(coll, item); - - if (TestLaraHangJumpUp(item, coll)) - return; - - if (coll->CollisionType == CT_CLAMP || - coll->CollisionType == CT_TOP || - coll->CollisionType == CT_TOP_FRONT) - item->fallspeed = 1; - - ShiftItem(item, coll); - - if (coll->CollisionType == 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->Middle.Floor <= 0) - { - item->goalAnimState = LaraLandedBad(item, coll) ? LS_DEATH : LS_STOP; - - item->gravityStatus = false; - item->fallspeed = 0; - - if (coll->Middle.Floor != NO_HEIGHT) - item->pos.yPos += coll->Middle.Floor; - } -} - -void lara_as_fallback(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 29*/ - /*collision: lara_col_fallback*/ - if (item->fallspeed > LARA_FREEFALL_SPEED) - item->goalAnimState = LS_FREEFALL; - - if (TrInput & IN_ACTION) - if (Lara.gunStatus == LG_NO_ARMS) - item->goalAnimState = LS_REACH; -} - -void lara_col_fallback(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 29*/ - /*state code: lara_as_fallback*/ - Lara.moveAngle = item->pos.yRot + ANGLE(180); - - coll->Setup.BadHeightDown = NO_BAD_POS; - coll->Setup.BadHeightUp = -STEPUP_HEIGHT; - coll->Setup.BadCeilingHeight = BAD_JUMP_CEILING; - - coll->Setup.ForwardAngle = Lara.moveAngle; - GetCollisionInfo(coll, item); - LaraDeflectEdgeJump(item, coll); - - if (item->fallspeed > 0 && (coll->Middle.Floor <= 0 || TestLaraSwamp(item))) - { - if (LaraLandedBad(item, coll)) - item->goalAnimState = LS_DEATH; - else - item->goalAnimState = LS_STOP; - - LaraResetGravityStatus(item, coll); - LaraSnapToHeight(item, coll); - } -} - -void lara_col_roll(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 45*/ - /*state code: lara_void_func*/ - Lara.moveAngle = item->pos.yRot; - - coll->Setup.BadHeightDown = NO_BAD_POS; - coll->Setup.BadHeightUp = -STEPUP_HEIGHT; - coll->Setup.BadCeilingHeight = 0; - coll->Setup.SlopesArePits = false; - coll->Setup.SlopesAreWalls = true; - - item->gravityStatus = false; - item->fallspeed = 0; - - coll->Setup.ForwardAngle = Lara.moveAngle; - GetCollisionInfo(coll, item); - - if (LaraHitCeiling(item, coll)) - return; - if (TestLaraSlide(item, coll)) - return; - if (LaraFallen(item, coll)) - return; - - if (TrInput & IN_FORWARD && item->animNumber == LA_SWANDIVE_ROLL && g_GameFlow->Animations.SwandiveRollRun) - { - item->goalAnimState = LS_RUN_FORWARD; - } - - ShiftItem(item, coll); - - if (coll->Middle.Floor != NO_HEIGHT) - item->pos.yPos += coll->Middle.Floor; -} - -void lara_as_swandive(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 52*/ - /*collision: lara_col_swandive*/ - coll->Setup.EnableObjectPush = true; - coll->Setup.EnableSpaz = false; - if (item->fallspeed > LARA_FREEFALL_SPEED && item->goalAnimState != LS_DIVE) - item->goalAnimState = LS_SWANDIVE_END; -} - -void lara_col_swandive(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 52*/ - /*state code: lara_as_swandive*/ - Lara.moveAngle = item->pos.yRot; - - coll->Setup.BadHeightDown = NO_BAD_POS; - coll->Setup.BadHeightUp = -STEPUP_HEIGHT; - coll->Setup.BadCeilingHeight = BAD_JUMP_CEILING; - - coll->Setup.ForwardAngle = Lara.moveAngle; - GetCollisionInfo(coll, item); - LaraDeflectEdgeJump(item, coll); - - if (coll->Middle.Floor <= 0 && item->fallspeed > 0) - { - item->goalAnimState = LS_STOP; - item->fallspeed = 0; - item->gravityStatus = 0; - - if (coll->Middle.Floor != NO_HEIGHT) - item->pos.yPos += coll->Middle.Floor; - } -} - -void lara_as_fastdive(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 53*/ - /*collision: lara_col_fastdive*/ - if (TrInput & IN_ROLL && item->goalAnimState == LS_SWANDIVE_END) - item->goalAnimState = LS_JUMP_ROLL_180; - coll->Setup.EnableObjectPush = true; - coll->Setup.EnableSpaz = false; - item->speed = (item->speed * 95) / 100; -} - -void lara_col_fastdive(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 53*/ - /*state code: lara_as_fastdive*/ - Lara.moveAngle = item->pos.yRot; - - coll->Setup.BadHeightDown = NO_BAD_POS; - coll->Setup.BadHeightUp = -STEPUP_HEIGHT; - coll->Setup.BadCeilingHeight = BAD_JUMP_CEILING; - - coll->Setup.ForwardAngle = Lara.moveAngle; - GetCollisionInfo(coll, item); - LaraDeflectEdgeJump(item, coll); - - if (coll->Middle.Floor <= 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->Middle.Floor != NO_HEIGHT) - item->pos.yPos += coll->Middle.Floor; - } -} - -void lara_as_gymnast(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 54*/ - /*collision: lara_default_col*/ - coll->Setup.EnableObjectPush = false; - coll->Setup.EnableSpaz = false; -} - -void lara_as_wade(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 65*/ - /*collision: lara_col_wade*/ - if (item->hitPoints <= 0) - { - item->goalAnimState = LS_STOP; - return; - } - - Camera.targetElevation = -ANGLE(22.0f); - - if (TestLaraSwamp(item)) - { - if (TrInput & IN_LEFT) - { - Lara.turnRate -= LARA_TURN_RATE; - if (Lara.turnRate < -(LARA_FAST_TURN / 2)) - Lara.turnRate = -(LARA_FAST_TURN / 2); - - if (TestLaraLean(item, coll)) - { - item->pos.zRot -= LARA_LEAN_RATE; - if (item->pos.zRot < -(LARA_LEAN_MAX / 2)) - item->pos.zRot = -(LARA_LEAN_MAX / 2); - } - else - { - item->pos.zRot -= LARA_LEAN_RATE; - if (item->pos.zRot < -LARA_LEAN_MAX * 3 / 5) - item->pos.zRot = -LARA_LEAN_MAX * 3 / 5; - } - } - else if (TrInput & IN_RIGHT) - { - Lara.turnRate += LARA_TURN_RATE; - if (Lara.turnRate > (LARA_FAST_TURN / 2)) - Lara.turnRate = (LARA_FAST_TURN / 2); - - if (TestLaraLean(item, coll)) - { - item->pos.zRot += LARA_LEAN_RATE; - if (item->pos.zRot > (LARA_LEAN_MAX / 2)) - item->pos.zRot = (LARA_LEAN_MAX / 2); - } - else - { - item->pos.zRot += LARA_LEAN_RATE; - if (item->pos.zRot > LARA_LEAN_MAX * 3 / 5) - item->pos.zRot = LARA_LEAN_MAX * 3 / 5; - } - } - - if (TrInput & IN_FORWARD) + if (info->waterStatus == LW_WADE) item->goalAnimState = LS_WADE_FORWARD; - else - item->goalAnimState = LS_STOP; + else if (TrInput & IN_WALK) + item->goalAnimState = LS_WALK_FORWARD; + else [[likely]] + item->goalAnimState = LS_RUN_FORWARD; + + return; } - else - { - if (TrInput & IN_LEFT) - { - Lara.turnRate -= LARA_TURN_RATE; - if (Lara.turnRate < -LARA_FAST_TURN) - Lara.turnRate = -LARA_FAST_TURN; - if (TestLaraLean(item, coll)) - { - item->pos.zRot -= LARA_LEAN_RATE; - if (item->pos.zRot < -LARA_LEAN_MAX) - item->pos.zRot = -LARA_LEAN_MAX; - } - else - { - item->pos.zRot -= LARA_LEAN_RATE; - if (item->pos.zRot < -LARA_LEAN_MAX * 3 / 5) - item->pos.zRot = -LARA_LEAN_MAX * 3 / 5; - } - } - else if (TrInput & IN_RIGHT) - { - Lara.turnRate += LARA_TURN_RATE; - if (Lara.turnRate > LARA_FAST_TURN) - Lara.turnRate = LARA_FAST_TURN; - - if (TestLaraLean(item, coll)) - { - item->pos.zRot += LARA_LEAN_RATE; - if (item->pos.zRot > LARA_LEAN_MAX) - item->pos.zRot = LARA_LEAN_MAX; - } - else - { - item->pos.zRot += LARA_LEAN_RATE; - if (item->pos.zRot > LARA_LEAN_MAX * 3 / 5) - item->pos.zRot = LARA_LEAN_MAX * 3 / 5; - } - } - - if (TrInput & IN_FORWARD) - { - if (Lara.waterStatus == LW_ABOVE_WATER) - item->goalAnimState = LS_RUN_FORWARD; - else - item->goalAnimState = LS_WADE_FORWARD; - } - else - { - item->goalAnimState = LS_STOP; - } - } + item->goalAnimState = LS_IDLE; } -void lara_col_wade(ITEM_INFO* item, COLL_INFO* coll) +// State: LS_RUN_FORWARD (1) +// Control: lara_as_run_forward() +void lara_col_run_forward(ITEM_INFO* item, COLL_INFO* coll) { - /*state 65*/ - /*state code: lara_as_wade*/ - Lara.moveAngle = item->pos.yRot; + LaraInfo*& info = item->data; + info->moveAngle = item->pos.yRot; coll->Setup.BadHeightDown = NO_BAD_POS; coll->Setup.BadHeightUp = -STEPUP_HEIGHT; coll->Setup.BadCeilingHeight = 0; - coll->Setup.SlopesAreWalls = true; - - coll->Setup.ForwardAngle = Lara.moveAngle; + coll->Setup.ForwardAngle = info->moveAngle; GetCollisionInfo(coll, item); + LaraResetGravityStatus(item, coll); - if (LaraHitCeiling(item, coll)) + if (TestLaraHitCeiling(coll)) + { + SetLaraHitCeiling(item, coll); + return; + } + + if (TestLaraFall(item, coll)) + { + SetLaraFallState(item); + return; + } + + if (TestLaraSlide(item, coll)) return; if (TestLaraVault(item, coll)) @@ -1812,8 +314,1684 @@ void lara_col_wade(ITEM_INFO* item, COLL_INFO* coll) { item->pos.zRot = 0; + if (coll->HitTallObject || TestLaraWall(item, STEP_SIZE, 0, -(STEP_SIZE * 2 + STEP_SIZE / 2)) != SPLAT_COLL::NONE) + { + item->goalAnimState = LS_SPLAT; + if (GetChange(item, &g_Level.Anims[item->animNumber])) + { + item->currentAnimState = LS_SPLAT; + return; + } + } - if (!coll->Front.Slope && coll->Front.Floor < -((STEP_SIZE * 5) / 2) && !TestLaraSwamp(item)) + LaraCollideStop(item, coll); + } + + if (TestLaraStep(coll) && coll->CollisionType != CT_FRONT) + { + DoLaraStep(item, coll); + return; + } +} + +// State: LS_IDLE (2), LS_POSE (4) +// Collision: lara_col_idle() +void lara_as_idle(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + info->look = ((TestLaraSwamp(item) && info->waterStatus == LW_WADE) || item->animNumber == LA_SWANDIVE_ROLL) ? false : true; + + // TODO: Hardcoding + if (item->animNumber != LA_SPRINT_TO_STAND_RIGHT && + item->animNumber != LA_SPRINT_TO_STAND_LEFT) + { + StopSoundEffect(SFX_TR4_LARA_SLIPPING); + } + + if (item->hitPoints <= 0) + { + item->goalAnimState = LS_DEATH; + return; + } + + // Handles waterskin and clockwork beetle. + // TODO: Hardcoding. + if (UseSpecialItem(item)) + return; + + if (TrInput & IN_LOOK && info->look) + LookUpDown(); + + if (TrInput & IN_LEFT && + !(TrInput & IN_JUMP)) // JUMP locks y rotation. + { + info->turnRate -= LARA_TURN_RATE; + if (info->turnRate < -LARA_SLOW_TURN_MAX) + info->turnRate = -LARA_SLOW_TURN_MAX; + } + else if (TrInput & IN_RIGHT && + !(TrInput & IN_JUMP)) + { + info->turnRate += LARA_TURN_RATE; + if (info->turnRate > LARA_SLOW_TURN_MAX) + info->turnRate = LARA_SLOW_TURN_MAX; + } + + if (info->waterStatus == LW_WADE) + { + if (TestLaraSwamp(item)) + PseudoLaraAsSwampIdle(item, coll); + else [[likely]] + PseudoLaraAsWadeIdle(item, coll); + + return; + } + + if (TrInput & IN_JUMP && + coll->Middle.Ceiling < -(LARA_HEADROOM * 0.7f)) + { + item->goalAnimState = LS_JUMP_PREPARE; + return; + } + + if (TrInput & IN_ROLL) + { + item->goalAnimState = LS_ROLL_FORWARD; + return; + } + + if (TrInput & IN_DUCK && + (info->gunStatus == LG_HANDS_FREE || !IsStandingWeapon(info->gunType))) + { + item->goalAnimState = LS_CROUCH_IDLE; + return; + } + + if (TrInput & IN_FORWARD) + { + if (TrInput & IN_WALK) + { + if (TestLaraWalkForward(item, coll)) + { + item->goalAnimState = LS_WALK_FORWARD; + return; + } + } + else if (TrInput & IN_SPRINT && TestLaraRunForward(item, coll)) + { + item->goalAnimState = LS_SPRINT; + return; + } + else if (TestLaraRunForward(item, coll)) [[likely]] + { + item->goalAnimState = LS_RUN_FORWARD; + return; + } + } + else if (TrInput & IN_BACK) + { + if (TrInput & IN_WALK) + { + if (TestLaraWalkBack(item, coll)) + { + item->goalAnimState = LS_WALK_BACK; + return; + } + } + else if (TestLaraHopBack(item, coll)) [[likely]] + { + item->goalAnimState = LS_RUN_BACK; + return; + } + } + + if (TrInput & IN_LSTEP && TestLaraStepLeft(item, coll)) + { + item->goalAnimState = LS_STEP_LEFT; + return; + } + else if (TrInput & IN_RSTEP && TestLaraStepRight(item, coll)) + { + item->goalAnimState = LS_STEP_RIGHT; + return; + } + + if (TrInput & IN_LEFT) + { + if (TrInput & IN_SPRINT || + info->turnRate <= -LARA_SLOW_TURN_MAX || + (info->gunStatus == LG_READY && info->gunType != WEAPON_TORCH) || + (info->gunStatus == LG_DRAW_GUNS && info->gunType != WEAPON_FLARE)) + { + item->goalAnimState = LS_TURN_LEFT_FAST; + } + else [[likely]] + item->goalAnimState = LS_TURN_LEFT_SLOW; + + return; + } + else if (TrInput & IN_RIGHT) + { + if (TrInput & IN_SPRINT || + info->turnRate >= LARA_SLOW_TURN_MAX || + (info->gunStatus == LG_READY && info->gunType != WEAPON_TORCH) || + (info->gunStatus == LG_DRAW_GUNS && info->gunType != WEAPON_FLARE)) + { + item->goalAnimState = LS_TURN_RIGHT_FAST; + } + else [[likely]] + item->goalAnimState = LS_TURN_RIGHT_SLOW; + + return; + } + + // TODO: Without animation blending, the AFK state's + // movement lock will be rather obnoxious. + // Adding some idle breathing would also be nice. @Sezz 2021.10.31 + if (info->poseCount >= LARA_POSE_TIME && TestLaraPose(item, coll) && + g_GameFlow->Animations.Pose) + { + item->goalAnimState = LS_POSE; + return; + } + + item->goalAnimState = LS_IDLE; +} + +// TODO: Future-proof for rising water. +// TODO: Make these into true states someday? It may take a bit of work. @Sezz 2021.10.13 +// Pseudo-state for idling in wade-height water. +void PseudoLaraAsWadeIdle(ITEM_INFO* item, COLL_INFO* coll) +{ + if (TrInput & IN_JUMP && + coll->Middle.Ceiling < -(LARA_HEADROOM * 0.7f)) + { + item->goalAnimState = LS_JUMP_PREPARE; + return; + } + + if (TrInput & IN_FORWARD && TestLaraRunForward(item, coll)) + { + item->goalAnimState = LS_WADE_FORWARD; + return; + } + + if (TrInput & IN_BACK && TestLaraWalkBack(item, coll)) + { + item->goalAnimState = LS_WALK_BACK; + return; + } + + if (TrInput & IN_LEFT) + { + item->goalAnimState = LS_TURN_LEFT_SLOW; + return; + } + else if (TrInput & IN_RIGHT) + { + item->goalAnimState = LS_TURN_RIGHT_SLOW; + return; + } + + if (TrInput & IN_LSTEP && TestLaraStepLeft(item, coll)) + { + item->goalAnimState = LS_STEP_LEFT; + return; + } + else if (TrInput & IN_RSTEP && TestLaraStepRight(item, coll)) + { + item->goalAnimState = LS_STEP_RIGHT; + return; + } + + item->goalAnimState = LS_IDLE; +} + +// Pseudo-state for idling in swamps. +void PseudoLaraAsSwampIdle(ITEM_INFO* item, COLL_INFO* coll) +{ + if (TrInput & IN_FORWARD && TestLaraRunForward(item, coll)) + { + item->goalAnimState = LS_WADE_FORWARD; + return; + } + + if (TrInput & IN_BACK && TestLaraWalkBackSwamp(item, coll)) + { + item->goalAnimState = LS_WALK_BACK; + return; + } + + if (TrInput & IN_LEFT) + { + item->goalAnimState = LS_TURN_LEFT_SLOW; + return; + } + else if (TrInput & IN_RIGHT) + { + item->goalAnimState = LS_TURN_RIGHT_SLOW; + return; + } + + if (TrInput & IN_LSTEP && TestLaraStepLeftSwamp(item, coll)) + { + item->goalAnimState = LS_STEP_LEFT; + return; + } + else if (TrInput & IN_RSTEP && TestLaraStepRightSwamp(item, coll)) + { + item->goalAnimState = LS_STEP_RIGHT; + return; + } + + item->goalAnimState = LS_IDLE; +} + +// State: LS_IDLE (2) +// Control: lara_as_idle() +void lara_col_idle(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + info->moveAngle = item->pos.yRot; + coll->Setup.BadHeightDown = TestLaraSwamp(item) ? NO_BAD_POS : STEPUP_HEIGHT; + coll->Setup.BadHeightUp = -STEPUP_HEIGHT; + coll->Setup.BadCeilingHeight = 0; + item->gravityStatus = false; + item->fallspeed = 0; + coll->Setup.SlopesArePits = TestLaraSwamp(item) ? false : true; + coll->Setup.SlopesAreWalls = TestLaraSwamp(item) ? false : true; + coll->Setup.ForwardAngle = info->moveAngle; + GetCollisionInfo(coll, item); + + if (TestLaraHitCeiling(coll)) + { + SetLaraHitCeiling(item, coll); + return; + } + + if (TestLaraFall(item, coll)) + { + SetLaraFallState(item); + return; + } + + if (TestLaraSlide(item, coll)) + return; + + ShiftItem(item, coll); + + // TODO: Vaulting from this state. + + if (TestLaraStep(coll)) + { + DoLaraStep(item, coll); + return; + } +} + +// State: LS_POSE (4) +// Collision: lara_col_idle() +void lara_as_pose(ITEM_INFO* item, COLL_INFO* coll) +{ + if (item->hitPoints <= 0) + { + item->goalAnimState = LS_DEATH; + return; + } + + if (TrInput & IN_LOOK) + LookUpDown(); + + if (TestLaraPose(item, coll)) + { + if (TrInput & IN_ROLL) + { + item->goalAnimState = LS_ROLL_FORWARD; + return; + } + + if (TrInput & IN_WAKE) + { + item->goalAnimState = LS_IDLE; + return; + } + + item->goalAnimState = LS_POSE; + return; + } + + item->goalAnimState = LS_IDLE; +} + +// State: LS_RUN_BACK (5) +// Collision: lara_col_run_back() +void lara_as_run_back(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + if (TrInput & IN_LEFT) + { + info->turnRate -= LARA_TURN_RATE; + if (info->turnRate < -LARA_MED_TURN_MAX) + info->turnRate = -LARA_MED_TURN_MAX; + + DoLaraLean(item, coll, -LARA_LEAN_MAX / 3, LARA_LEAN_RATE / 4); + } + else if (TrInput & IN_RIGHT) + { + info->turnRate += LARA_TURN_RATE; + if (info->turnRate > LARA_MED_TURN_MAX) + info->turnRate = LARA_MED_TURN_MAX; + + DoLaraLean(item, coll, LARA_LEAN_MAX / 3, LARA_LEAN_RATE / 4); + } + + if (TrInput & IN_ROLL) + { + item->goalAnimState = LS_ROLL_FORWARD; + return; + } + + item->goalAnimState = LS_IDLE; +} + +// State: LS_RUN_BACK (5) +// Control: lara_as_run_back() +void lara_col_run_back(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + info->moveAngle = item->pos.yRot + ANGLE(180.0f); + item->fallspeed = 0; + item->gravityStatus = false; + coll->Setup.SlopesAreWalls = false; + coll->Setup.SlopesArePits = true; + coll->Setup.BadHeightDown = NO_BAD_POS; + coll->Setup.BadHeightUp = -STEPUP_HEIGHT; + coll->Setup.BadCeilingHeight = 0; + coll->Setup.ForwardAngle = info->moveAngle; + GetCollisionInfo(coll, item); + + if (TestLaraHitCeiling(coll)) + { + SetLaraHitCeiling(item, coll); + return; + } + + if (coll->Middle.Floor > (STEPUP_HEIGHT / 2)) + { + SetLaraFallBackState(item); + return; + } + + if (TestLaraSlide(item, coll)) + return; + + if (LaraDeflectEdge(item, coll)) + LaraCollideStop(item, coll); + + if (TestLaraStep(coll)) + { + DoLaraStep(item, coll); + return; + } +} + +// State: LS_TURN_RIGHT_SLOW (6) +// Collision: lara_col_turn_right_slow() +void lara_as_turn_right_slow(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + info->look = (TestLaraSwamp(item) && info->waterStatus == LW_WADE) ? false : true; + + if (item->hitPoints <= 0) + { + item->goalAnimState = LS_DEATH; + return; + } + + info->turnRate += LARA_TURN_RATE; + if (info->turnRate < 0) + info->turnRate = 0; + else if (info->turnRate > LARA_MED_FAST_TURN_MAX) + info->turnRate = LARA_MED_FAST_TURN_MAX; + + if (info->waterStatus == LW_WADE) + { + if (TestLaraSwamp(item)) + PsuedoLaraAsSwampTurnRightSlow(item, coll); + else [[likely]] + PsuedoLaraAsWadeTurnRightSlow(item, coll); + + return; + } + + if (TrInput & IN_JUMP && + coll->Middle.Ceiling < -(LARA_HEADROOM * 0.7f)) + { + item->goalAnimState = LS_JUMP_PREPARE; + return; + } + + if (TrInput & IN_ROLL) + { + item->goalAnimState = LS_ROLL_FORWARD; + return; + } + + if (TrInput & IN_DUCK && + (info->gunStatus == LG_HANDS_FREE || !IsStandingWeapon(info->gunType))) + { + item->goalAnimState = LS_CROUCH_IDLE; + return; + } + + if (TrInput & IN_FORWARD) + { + if (TrInput & IN_WALK) + { + if (TestLaraWalkForward(item, coll)) + { + item->goalAnimState = LS_WALK_FORWARD; + return; + } + } + else if (TrInput & IN_SPRINT && TestLaraRunForward(item, coll)) + { + item->goalAnimState = LS_SPRINT; + return; + } + else if (TestLaraRunForward(item, coll)) [[likely]] + { + item->goalAnimState = LS_RUN_FORWARD; + return; + } + } + else if (TrInput & IN_BACK) + { + if (TrInput & IN_WALK) + { + if (TestLaraWalkBack(item, coll)) + { + item->goalAnimState = LS_WALK_BACK; + return; + } + } + else if (TestLaraHopBack(item, coll)) [[likely]] + { + item->goalAnimState = LS_RUN_BACK; + return; + } + } + + if (TrInput & IN_LSTEP && TestLaraStepLeft(item, coll)) + { + item->goalAnimState = LS_STEP_LEFT; + return; + } + else if (TrInput & IN_RSTEP && TestLaraStepRight(item, coll)) + { + item->goalAnimState = LS_STEP_RIGHT; + return; + } + + if (TrInput & IN_RIGHT) + { + if (TrInput & IN_WALK) // TODO: This hasn't worked since TR1. + { + item->goalAnimState = LS_TURN_RIGHT_SLOW; + + if (info->turnRate > LARA_SLOW_TURN_MAX) + info->turnRate = LARA_SLOW_TURN_MAX; + } + else if (info->turnRate > LARA_SLOW_MED_TURN_MAX) + item->goalAnimState = LS_TURN_RIGHT_FAST; + else [[likely]] + item->goalAnimState = LS_TURN_RIGHT_SLOW; + + return; + } + + item->goalAnimState = LS_IDLE; +} + +// Pseudo-state for turning right slowly in wade-height water. +void PsuedoLaraAsWadeTurnRightSlow(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + if (info->turnRate > LARA_WADE_TURN_MAX) + info->turnRate = LARA_WADE_TURN_MAX; + + if (TrInput & IN_JUMP && + coll->Middle.Ceiling < -(LARA_HEADROOM * 0.7f)) + { + item->goalAnimState = LS_JUMP_PREPARE; + return; + } + + if (TrInput & IN_FORWARD && TestLaraRunForward(item, coll)) + { + item->goalAnimState = LS_WADE_FORWARD; + return; + } + else if (TrInput & IN_BACK && TestLaraWalkBack(item, coll)) + { + item->goalAnimState = LS_WALK_BACK; + return; + } + + if (TrInput & IN_LSTEP && TestLaraStepLeft(item, coll)) + { + item->goalAnimState = LS_STEP_LEFT; + return; + } + else if (TrInput & IN_RSTEP && TestLaraStepRight(item, coll)) + { + item->goalAnimState = LS_STEP_RIGHT; + return; + } + + if (TrInput & IN_RIGHT) + { + item->goalAnimState = LS_TURN_RIGHT_SLOW; + return; + } + + item->goalAnimState = LS_IDLE; +} + +// Pseudo-state for turning right slowly in swamps. +void PsuedoLaraAsSwampTurnRightSlow(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + if (info->turnRate > LARA_SWAMP_TURN_MAX) + info->turnRate = LARA_SWAMP_TURN_MAX; + + if (TrInput & IN_FORWARD && TestLaraRunForward(item, coll)) + { + item->goalAnimState = LS_WADE_FORWARD; + return; + } + else if (TrInput & IN_BACK && TestLaraWalkBackSwamp(item, coll)) + { + item->goalAnimState = LS_WALK_BACK; + return; + } + + if (TrInput & IN_LSTEP && TestLaraStepLeftSwamp(item, coll)) + { + item->goalAnimState = LS_STEP_LEFT; + return; + } + else if (TrInput & IN_RSTEP && TestLaraStepRightSwamp(item, coll)) + { + item->goalAnimState = LS_STEP_RIGHT; + return; + } + + if (TrInput & IN_RIGHT) + { + item->goalAnimState = LS_TURN_RIGHT_SLOW; + return; + } + + item->goalAnimState = LS_IDLE; +} + +// State: LS_TURN_RIGHT_SLOW (6) +// Control: lara_as_turn_right_slow() +void lara_col_turn_right_slow(ITEM_INFO* item, COLL_INFO* coll) +{ + lara_col_idle(item, coll); +} + +// State: LS_TURN_LEFT_SLOW (7) +// Collision: lara_col_turn_left_slow() +void lara_as_turn_left_slow(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + info->look = (TestLaraSwamp(item) && info->waterStatus == LW_WADE) ? false : true; + + if (item->hitPoints <= 0) + { + item->goalAnimState = LS_DEATH; + return; + } + + info->turnRate -= LARA_TURN_RATE; + if (info->turnRate > 0) + info->turnRate = 0; + else if (info->turnRate < -LARA_MED_FAST_TURN_MAX) + info->turnRate = -LARA_MED_FAST_TURN_MAX; + + if (info->waterStatus == LW_WADE) + { + if (TestLaraSwamp(item)) + PsuedoLaraAsSwampTurnLeftSlow(item, coll); + else [[likely]] + PsuedoLaraAsWadeTurnLeftSlow(item, coll); + + return; + } + + if (TrInput & IN_JUMP && + coll->Middle.Ceiling < -(LARA_HEADROOM * 0.7f)) + { + item->goalAnimState = LS_JUMP_PREPARE; + return; + } + + if (TrInput & IN_ROLL) + { + item->goalAnimState = LS_ROLL_FORWARD; + return; + } + + if (TrInput & IN_DUCK && + (info->gunStatus == LG_HANDS_FREE || !IsStandingWeapon(info->gunType))) + { + item->goalAnimState = LS_CROUCH_IDLE; + return; + } + + if (TrInput & IN_FORWARD) + { + if (TrInput & IN_WALK) + { + if (TestLaraWalkForward(item, coll)) + { + item->goalAnimState = LS_WALK_FORWARD; + return; + } + } + else if (TrInput & IN_SPRINT && TestLaraRunForward(item, coll)) + { + item->goalAnimState = LS_SPRINT; + return; + } + else if (TestLaraRunForward(item, coll)) [[likely]] + { + item->goalAnimState = LS_RUN_FORWARD; + return; + } + } + else if (TrInput & IN_BACK) + { + if (TrInput & IN_WALK) + { + if (TestLaraWalkBack(item, coll)) + { + item->goalAnimState = LS_WALK_BACK; + return; + } + } + else if (TestLaraHopBack(item, coll)) [[likely]] + { + item->goalAnimState = LS_RUN_BACK; + return; + } + } + + if (TrInput & IN_LSTEP && TestLaraStepLeft(item, coll)) + { + item->goalAnimState = LS_STEP_LEFT; + return; + } + else if (TrInput & IN_RSTEP && TestLaraStepRight(item, coll)) + { + item->goalAnimState = LS_STEP_RIGHT; + return; + } + + if (TrInput & IN_LEFT) + { + if (TrInput & IN_WALK) + { + item->goalAnimState = LS_TURN_LEFT_SLOW; + + if (info->turnRate < -LARA_SLOW_TURN_MAX) + info->turnRate = -LARA_SLOW_TURN_MAX; + } + else if (info->turnRate < -LARA_SLOW_MED_TURN_MAX) + item->goalAnimState = LS_TURN_LEFT_FAST; + else [[likely]] + item->goalAnimState = LS_TURN_RIGHT_SLOW; + + return; + } + + item->goalAnimState = LS_IDLE; +} + +// Pseudo-state for turning left slowly in wade-height water. +void PsuedoLaraAsWadeTurnLeftSlow(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + if (info->turnRate < -LARA_WADE_TURN_MAX) + info->turnRate = -LARA_WADE_TURN_MAX; + + if (TrInput & IN_JUMP && + coll->Middle.Ceiling < -(LARA_HEADROOM * 0.7f)) + { + item->goalAnimState = LS_JUMP_PREPARE; + return; + } + + if (TrInput & IN_FORWARD && TestLaraRunForward(item, coll)) + { + item->goalAnimState = LS_WADE_FORWARD; + return; + } + else if (TrInput & IN_BACK && TestLaraWalkBack(item, coll)) + { + item->goalAnimState = LS_WALK_BACK; + return; + } + + if (TrInput & IN_LSTEP && TestLaraStepLeft(item, coll)) + { + item->goalAnimState = LS_STEP_LEFT; + return; + } + else if (TrInput & IN_RSTEP && TestLaraStepRight(item, coll)) + { + item->goalAnimState = LS_STEP_RIGHT; + return; + } + + if (TrInput & IN_LEFT) + { + item->goalAnimState = LS_TURN_LEFT_SLOW; + return; + } + + item->goalAnimState = LS_IDLE; +} + +// Pseudo-state for turning left slowly in swamps. +void PsuedoLaraAsSwampTurnLeftSlow(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + if (info->turnRate < -LARA_SWAMP_TURN_MAX) + info->turnRate = -LARA_SWAMP_TURN_MAX; + + if (TrInput & IN_FORWARD && TestLaraRunForward(item, coll)) + { + item->goalAnimState = LS_WADE_FORWARD; + return; + } + else if (TrInput & IN_BACK && TestLaraWalkBack(item, coll)) + { + item->goalAnimState = LS_WALK_BACK; + return; + } + + if (TrInput & IN_LSTEP && TestLaraStepLeft(item, coll)) + { + item->goalAnimState = LS_STEP_LEFT; + return; + } + else if (TrInput & IN_RSTEP && TestLaraStepRight(item, coll)) + { + item->goalAnimState = LS_STEP_RIGHT; + return; + } + + if (TrInput & IN_LEFT) + { + item->goalAnimState = LS_TURN_LEFT_SLOW; + return; + } + + item->goalAnimState = LS_IDLE; +} + +// State: LS_TURN_LEFT_SLOW (7) +// Control: lara_as_turn_left_slow() +void lara_col_turn_left_slow(ITEM_INFO* item, COLL_INFO* coll) +{ + lara_col_turn_right_slow(item, coll); +} + +// State: LS_DEATH (8) +// Collision: lara_col_death() +void lara_as_death(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + info->look = false; + coll->Setup.EnableObjectPush = false; + coll->Setup.EnableSpaz = false; + + if (BinocularRange) + { + BinocularRange = 0; + LaserSight = false; + AlterFOV(ANGLE(80.0f)); + item->meshBits = -1; + info->busy = false; + } +} + +// State: LS_DEATH (8) +// Control: lara_as_death() +void lara_col_death(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + info->moveAngle = item->pos.yRot; + coll->Setup.BadHeightDown = STEPUP_HEIGHT; + coll->Setup.BadHeightUp = -STEPUP_HEIGHT; + coll->Setup.BadCeilingHeight = 0; + coll->Setup.Radius = LARA_RAD_DEATH; + coll->Setup.ForwardAngle = info->moveAngle; + GetCollisionInfo(coll, item); + + StopSoundEffect(SFX_TR4_LARA_FALL); + item->hitPoints = -1; + info->air = -1; + + ShiftItem(item, coll); + + if (TestLaraStep(coll)) + { + DoLaraStep(item, coll); + return; + } +} + +// State: LS_SPLAT (12) +// Collision: lara_col_splat() +void lara_as_splat(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + info->look = false; +} + +// State: LS_SPLAT (12) +// Control: lara_as_splat() +void lara_col_splat(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + info->moveAngle = item->pos.yRot; + coll->Setup.SlopesAreWalls = true; + coll->Setup.SlopesArePits = true; + coll->Setup.BadHeightDown = STEPUP_HEIGHT; + coll->Setup.BadHeightUp = -STEPUP_HEIGHT; + coll->Setup.BadCeilingHeight = 0; + coll->Setup.ForwardAngle = info->moveAngle; + GetCollisionInfo(coll, item); + + ShiftItem(item, coll); + + if (coll->Middle.Floor >= -STEP_SIZE && coll->Middle.Floor <= STEP_SIZE) + item->pos.yPos += coll->Middle.Floor; +} + +// State: LS_WALK_BACK (16) +// Collision: lara_col_walk_back() +void lara_as_walk_back(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + info->look = (TestLaraSwamp(item) && info->waterStatus == LW_WADE) ? false : true; + + if (item->hitPoints <= 0) + { + item->goalAnimState = LS_DEATH; + return; + } + + if (info->isMoving) + return; + + if (TestLaraSwamp(item) && + info->waterStatus == LW_WADE) + { + PseudoLaraAsSwampWalkBack(item, coll); + return; + } + + if (TrInput & IN_LEFT) + { + info->turnRate -= LARA_TURN_RATE; + if (info->turnRate < -LARA_SLOW_TURN_MAX) + info->turnRate = -LARA_SLOW_TURN_MAX; + + DoLaraLean(item, coll, -LARA_LEAN_MAX / 3, LARA_LEAN_RATE / 4); + + } + else if (TrInput & IN_RIGHT) + { + info->turnRate += LARA_TURN_RATE; + if (info->turnRate > LARA_SLOW_TURN_MAX) + info->turnRate = LARA_SLOW_TURN_MAX; + + DoLaraLean(item, coll, LARA_LEAN_MAX / 3, LARA_LEAN_RATE / 4); + } + + if (TrInput & IN_BACK && + (TrInput & IN_WALK || info->waterStatus == LW_WADE)) + { + item->goalAnimState = LS_WALK_BACK; + return; + } + + item->goalAnimState = LS_IDLE; +} + +// Pseudo-state for walking back in swamps. +void PseudoLaraAsSwampWalkBack(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + if (TrInput & IN_LEFT) + { + info->turnRate -= LARA_TURN_RATE; + if (info->turnRate < -LARA_SLOW_TURN_MAX / 3) + info->turnRate = -LARA_SLOW_TURN_MAX / 3; + + DoLaraLean(item, coll, -LARA_LEAN_MAX / 3, LARA_LEAN_RATE / 3); + + } + else if (TrInput & IN_RIGHT) + { + info->turnRate += LARA_TURN_RATE; + if (info->turnRate > LARA_SLOW_TURN_MAX / 3) + info->turnRate = LARA_SLOW_TURN_MAX / 3; + + DoLaraLean(item, coll, LARA_LEAN_MAX / 3, LARA_LEAN_RATE / 3); + } + + if (TrInput & IN_BACK) + { + item->goalAnimState = LS_WALK_BACK; + return; + } + + item->goalAnimState = LS_IDLE; +} + +// State: LS_WALK_BACK (16) +// Control: lara_as_walk_back() +void lara_col_walk_back(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + info->moveAngle = item->pos.yRot + ANGLE(180.0f); + item->gravityStatus = false; + item->fallspeed = 0; + coll->Setup.BadHeightDown = (info->waterStatus == LW_WADE) ? NO_BAD_POS : STEPUP_HEIGHT; + coll->Setup.BadHeightUp = -STEPUP_HEIGHT; + coll->Setup.BadCeilingHeight = 0; + coll->Setup.SlopesArePits = TestLaraSwamp(item) ? false : true; + coll->Setup.SlopesAreWalls = TestLaraSwamp(item) ? false : true; + coll->Setup.DeathFlagIsPit = true; + coll->Setup.ForwardAngle = info->moveAngle; + GetCollisionInfo(coll, item); + + if (TestLaraHitCeiling(coll)) + { + SetLaraHitCeiling(item, coll); + return; + } + + if (TestLaraFall(item, coll)) + { + SetLaraFallState(item); + return; + } + + if (TestLaraSlide(item, coll)) + return; + + if (LaraDeflectEdge(item, coll)) + LaraCollideStop(item, coll); + + if (TestLaraStep(coll)) + { + DoLaraStep(item, coll); + return; + } +} + +// State: LS_TURN_RIGHT_FAST (20) +// Collision: lara_col_turn_right_fast() +void lara_as_turn_right_fast(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + if (item->hitPoints <= 0) + { + item->goalAnimState = LS_DEATH; + return; + } + + info->turnRate += LARA_TURN_RATE; + if (info->turnRate < LARA_MED_TURN_MAX) + info->turnRate = LARA_MED_TURN_MAX; + else if (info->turnRate > LARA_FAST_TURN_MAX) + info->turnRate = LARA_FAST_TURN_MAX; + + if (TrInput & IN_JUMP && + coll->Middle.Ceiling < -(LARA_HEADROOM * 0.7f)) + { + item->goalAnimState = LS_JUMP_PREPARE; + return; + } + + if (TrInput & IN_ROLL && + info->waterStatus != LW_WADE) + { + item->goalAnimState = LS_ROLL_FORWARD; + return; + } + + if (TrInput & IN_DUCK && + (info->gunStatus == LG_HANDS_FREE || !IsStandingWeapon(info->gunType)) && + info->waterStatus != LW_WADE) + { + item->goalAnimState = LS_CROUCH_IDLE; + return; + } + + if (TrInput & IN_FORWARD) + { + if (info->waterStatus == LW_WADE) // Should not be possible, but here for security. + { + if (TestLaraRunForward(item, coll)) + { + item->goalAnimState = LS_WADE_FORWARD; + return; + } + } + else if (TrInput & IN_WALK) + { + if (TestLaraWalkForward(item, coll)) + { + item->goalAnimState = LS_WALK_FORWARD; + return; + } + } + else if (TrInput & IN_SPRINT && TestLaraRunForward(item, coll)) + { + item->goalAnimState = LS_SPRINT; + return; + } + else if (TestLaraRunForward(item, coll)) [[likely]] + { + item->goalAnimState = LS_RUN_FORWARD; + return; + } + } + else if (TrInput & IN_BACK) + { + if (TrInput & IN_WALK) + { + if (TestLaraWalkBack(item, coll)) + { + item->goalAnimState = LS_WALK_BACK; + return; + } + } + else if (TestLaraHopBack(item, coll)) [[likely]] + { + item->goalAnimState = LS_RUN_BACK; + return; + } + } + + if (TrInput & IN_LSTEP && TestLaraStepLeft(item, coll)) + { + item->goalAnimState = LS_STEP_LEFT; + return; + } + else if (TrInput & IN_RSTEP && TestLaraStepRight(item, coll)) + { + item->goalAnimState = LS_STEP_RIGHT; + return; + } + + // TODO: Hold WALK to slow down again. + if (TrInput & IN_RIGHT) + { + item->goalAnimState = LS_TURN_RIGHT_FAST; + return; + } + + item->goalAnimState = LS_IDLE; +} + +// State: LS_TURN_RIGHT_FAST (20) +// Control: lara_as_turn_right_fast() +void lara_col_turn_right_fast(ITEM_INFO* item, COLL_INFO* coll) +{ + lara_col_idle(item, coll); +} + +// State: LS_TURN_LEFT_FAST (152) +// Collision: lara_col_turn_left_fast() +void lara_as_turn_left_fast(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + if (item->hitPoints <= 0) + { + item->goalAnimState = LS_DEATH; + return; + } + + info->turnRate -= LARA_TURN_RATE; + if (info->turnRate > -LARA_MED_TURN_MAX) + info->turnRate = -LARA_MED_TURN_MAX; + else if (info->turnRate < -LARA_FAST_TURN_MAX) + info->turnRate = -LARA_FAST_TURN_MAX; + + if (TrInput & IN_JUMP && + coll->Middle.Ceiling < -(LARA_HEADROOM * 0.7f)) + { + item->goalAnimState = LS_JUMP_PREPARE; + return; + } + + if (TrInput & IN_ROLL && + info->waterStatus != LW_WADE) + { + item->goalAnimState = LS_ROLL_FORWARD; + return; + } + + if (TrInput & IN_DUCK && + (info->gunStatus == LG_HANDS_FREE || !IsStandingWeapon(info->gunType)) && + info->waterStatus != LW_WADE) + { + item->goalAnimState = LS_CROUCH_IDLE; + return; + } + + if (TrInput & IN_FORWARD) + { + if (info->waterStatus == LW_WADE) // Should not be possible, but here for security. + { + if (TestLaraRunForward(item, coll)) + { + item->goalAnimState = LS_WADE_FORWARD; + return; + } + } + else if (TrInput & IN_WALK) + { + if (TestLaraWalkForward(item, coll)) + { + item->goalAnimState = LS_WALK_FORWARD; + return; + } + } + else if (TrInput & IN_SPRINT && TestLaraRunForward(item, coll)) + { + item->goalAnimState = LS_SPRINT; + return; + } + else if (TestLaraRunForward(item, coll)) [[likely]] + { + item->goalAnimState = LS_RUN_FORWARD; + return; + } + } + else if (TrInput & IN_BACK) + { + if (TrInput & IN_WALK) + { + if (TestLaraWalkBack(item, coll)) + { + item->goalAnimState = LS_WALK_BACK; + return; + } + } + else if (TestLaraHopBack(item, coll)) [[likely]] + { + item->goalAnimState = LS_RUN_BACK; + return; + } + } + + if (TrInput & IN_LSTEP && TestLaraStepLeft(item, coll)) + { + item->goalAnimState = LS_STEP_LEFT; + return; + } + else if (TrInput & IN_RSTEP && TestLaraStepRight(item, coll)) + { + item->goalAnimState = LS_STEP_RIGHT; + return; + } + + if (TrInput & IN_LEFT) + { + item->goalAnimState = LS_TURN_LEFT_FAST; + return; + } + + item->goalAnimState = LS_IDLE; +} + +// State: LS_TURN_LEFT_FAST (152) +// Control: lara_as_turn_left_fast() +void lara_col_turn_left_fast(ITEM_INFO* item, COLL_INFO* coll) +{ + lara_col_idle(item, coll); +} + +// State: LS_STEP_RIGHT (21) +// Collision: lara_col_step_right() +void lara_as_step_right(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + info->look = false; + + if (item->hitPoints <= 0) + { + item->goalAnimState = LS_DEATH; + return; + } + + if (info->isMoving) + return; + + if (TrInput & IN_LEFT) + { + info->turnRate -= LARA_TURN_RATE; + if (info->turnRate < -LARA_SLOW_TURN_MAX) + info->turnRate = -LARA_SLOW_TURN_MAX; + } + else if (TrInput & IN_RIGHT) + { + info->turnRate += LARA_TURN_RATE; + if (info->turnRate > LARA_SLOW_TURN_MAX) + info->turnRate = LARA_SLOW_TURN_MAX; + } + + if (TrInput & IN_RSTEP) + { + item->goalAnimState = LS_STEP_RIGHT; + return; + } + + item->goalAnimState = LS_IDLE; +} + +// State: LS_STEP_RIGHT (21) +// Control: lara_as_step_right() +void lara_col_step_right(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + info->moveAngle = item->pos.yRot + ANGLE(90.0f); + item->gravityStatus = false; + item->fallspeed = 0; + coll->Setup.BadHeightDown = (info->waterStatus == LW_WADE) ? NO_BAD_POS : STEP_SIZE / 2; + coll->Setup.BadHeightUp = -STEP_SIZE / 2; + coll->Setup.BadCeilingHeight = 0; + coll->Setup.SlopesArePits = TestLaraSwamp(item) ? false : true; + coll->Setup.SlopesAreWalls = TestLaraSwamp(item) ? false : true; + coll->Setup.DeathFlagIsPit = true; + coll->Setup.ForwardAngle = info->moveAngle; + GetCollisionInfo(coll, item); + + if (TestLaraHitCeiling(coll)) + { + SetLaraHitCeiling(item, coll); + return; + } + + if (TestLaraFall(item, coll)) + { + SetLaraFallState(item); + return; + } + + if (TestLaraSlide(item, coll)) + return; + + if (LaraDeflectEdge(item, coll)) + LaraCollideStop(item, coll); + + if (TestLaraStep(coll) || TestLaraSwamp(item)) + { + DoLaraStep(item, coll); + return; + } +} + +// State: LS_STEP_LEFT (22) +// Collision: lara_col_step_left() +void lara_as_step_left(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + info->look = false; + + if (item->hitPoints <= 0) + { + item->goalAnimState = LS_DEATH; + return; + } + + if (info->isMoving) + return; + + if (TrInput & IN_LEFT) + { + info->turnRate -= LARA_TURN_RATE; + if (info->turnRate < -LARA_SLOW_TURN_MAX) + info->turnRate = -LARA_SLOW_TURN_MAX; + } + else if (TrInput & IN_RIGHT) + { + info->turnRate += LARA_TURN_RATE; + if (info->turnRate > LARA_SLOW_TURN_MAX) + info->turnRate = LARA_SLOW_TURN_MAX; + } + + if (TrInput & IN_LSTEP) + { + item->goalAnimState = LS_STEP_LEFT; + return; + } + + item->goalAnimState = LS_IDLE; +} + +// State: LS_STEP_LEFT (22) +// Control: lara_as_step_left() +void lara_col_step_left(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + info->moveAngle = item->pos.yRot - ANGLE(90.0f); + item->gravityStatus = false; + item->fallspeed = 0; + coll->Setup.BadHeightDown = (info->waterStatus == LW_WADE) ? NO_BAD_POS : STEP_SIZE / 2; + coll->Setup.BadHeightUp = -STEP_SIZE / 2; + coll->Setup.BadCeilingHeight = 0; + coll->Setup.SlopesArePits = TestLaraSwamp(item) ? false : true; + coll->Setup.SlopesAreWalls = TestLaraSwamp(item) ? false : true; + coll->Setup.DeathFlagIsPit = true; + coll->Setup.ForwardAngle = info->moveAngle; + GetCollisionInfo(coll, item); + + if (TestLaraHitCeiling(coll)) + { + SetLaraHitCeiling(item, coll); + return; + } + + if (TestLaraFall(item, coll)) + { + SetLaraFallState(item); + return; + } + + if (TestLaraSlide(item, coll)) + return; + + if (LaraDeflectEdge(item, coll)) + LaraCollideStop(item, coll); + + if (TestLaraStep(coll) || TestLaraSwamp(item)) + { + DoLaraStep(item, coll); + return; + } +} + +// State: LS_ROLL_BACK (23) +// Collision: lara_col_roll_back() +void lara_as_roll_back(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + info->look = false; + + if (TrInput & IN_ROLL) + { + item->goalAnimState = LS_ROLL_BACK; + return; + } + + item->goalAnimState = LS_IDLE; +} + +// State: LS_ROLL_BACK (23) +// Control: lara_as_roll_back() +void lara_col_roll_back(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + info->moveAngle = item->pos.yRot + ANGLE(180.0f); + item->gravityStatus = false; + item->fallspeed = 0; + coll->Setup.BadHeightDown = NO_BAD_POS; + coll->Setup.BadHeightUp = -STEPUP_HEIGHT; + coll->Setup.BadCeilingHeight = 0; + coll->Setup.SlopesAreWalls = true; + coll->Setup.ForwardAngle = info->moveAngle; + Camera.laraNode = 0; + GetCollisionInfo(coll, item); + + if (TestLaraHitCeiling(coll)) + { + SetLaraHitCeiling(item, coll); + return; + } + + if (TestLaraSlide(item, coll)) + return; + + if (coll->Middle.Floor > (STEPUP_HEIGHT / 2)) // Was 200. + { + SetLaraFallBackState(item); + return; + } + + ShiftItem(item, coll); + + if (TestLaraStep(coll)) + { + DoLaraStep(item, coll); + return; + } +} + +// State: LS_ROLL_FORWARD (45) +// Collision: lara_col_roll_forward() +void lara_as_roll_forward(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + info->look = false; + + // TODO: Change swandive roll anim state to something sensible. + if (TrInput & IN_FORWARD && + item->animNumber == LA_SWANDIVE_ROLL) // Hack. + { + item->goalAnimState = LS_RUN_FORWARD; + return; + } + + if (TrInput & IN_ROLL) + { + item->goalAnimState = LS_ROLL_FORWARD; + return; + } + + item->goalAnimState = LS_IDLE; +} + +// State: LS_ROLL_FORWARD (45) +// Control: lara_as_roll_forward() +void lara_col_roll_forward(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + info->moveAngle = item->pos.yRot; + item->gravityStatus = false; + item->fallspeed = 0; + coll->Setup.BadHeightDown = NO_BAD_POS; + coll->Setup.BadHeightUp = -STEPUP_HEIGHT; + coll->Setup.BadCeilingHeight = 0; + coll->Setup.SlopesArePits = false; + coll->Setup.SlopesAreWalls = true; + coll->Setup.ForwardAngle = info->moveAngle; + GetCollisionInfo(coll, item); + + if (TestLaraHitCeiling(coll)) + { + SetLaraHitCeiling(item, coll); + return; + } + + if (TestLaraFall(item, coll)) + { + SetLaraFallState(item); + return; + } + + if (TestLaraSlide(item, coll)) + return; + + ShiftItem(item, coll); + + if (TestLaraStep(coll)) + { + DoLaraStep(item, coll); + return; + } +} + +// State: LS_WADE_FORWARD (65) +// Collision: lara_col_wade_forward() +void lara_as_wade_forward(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + info->look = (TestLaraSwamp(item) && info->waterStatus == LW_WADE) ? false : true; + Camera.targetElevation = -ANGLE(22.0f); + + if (item->hitPoints <= 0) + { + item->goalAnimState = LS_IDLE; + return; + } + + if (TestLaraSwamp(item)) + { + PseudoLaraAsSwampWadeForward(item, coll); + return; + } + + if (TrInput & IN_LEFT) + { + info->turnRate -= LARA_TURN_RATE; + if (info->turnRate < -LARA_FAST_TURN_MAX) + info->turnRate = -LARA_FAST_TURN_MAX; + + DoLaraLean(item, coll, -LARA_LEAN_MAX, LARA_LEAN_RATE / 2); + } + else if (TrInput & IN_RIGHT) + { + info->turnRate += LARA_TURN_RATE; + if (info->turnRate > LARA_FAST_TURN_MAX) + info->turnRate = LARA_FAST_TURN_MAX; + + DoLaraLean(item, coll, LARA_LEAN_MAX, LARA_LEAN_RATE / 2); + } + + if (TrInput & IN_FORWARD) + { + if (info->waterStatus == LW_ABOVE_WATER) + item->goalAnimState = LS_RUN_FORWARD; + else [[likely]] + item->goalAnimState = LS_WADE_FORWARD; + + return; + } + + item->goalAnimState = LS_IDLE; +} + +// Pseudo-state for wading in swamps. +void PseudoLaraAsSwampWadeForward(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + if (TrInput & IN_LEFT) + { + info->turnRate -= LARA_TURN_RATE; + if (info->turnRate < -LARA_SWAMP_TURN_MAX) + info->turnRate = -LARA_SWAMP_TURN_MAX; + + DoLaraLean(item, coll, -LARA_LEAN_MAX / 5 * 3, LARA_LEAN_RATE / 3); + } + else if (TrInput & IN_RIGHT) + { + info->turnRate += LARA_TURN_RATE; + if (info->turnRate > LARA_SWAMP_TURN_MAX) + info->turnRate = LARA_SWAMP_TURN_MAX; + + DoLaraLean(item, coll, LARA_LEAN_MAX / 5 * 3, LARA_LEAN_RATE / 3); + } + + if (TrInput & IN_FORWARD) + { + item->goalAnimState = LS_WADE_FORWARD; + return; + } + + item->goalAnimState = LS_IDLE; +} + +// State: LS_WADE_FORWARD (65) +// Control: lara_as_wade_forward() +void lara_col_wade_forward(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + info->moveAngle = item->pos.yRot; + coll->Setup.BadHeightDown = NO_BAD_POS; + coll->Setup.BadHeightUp = -STEPUP_HEIGHT; + coll->Setup.BadCeilingHeight = 0; + coll->Setup.SlopesAreWalls = TestLaraSwamp(item) ? false : true; + coll->Setup.ForwardAngle = info->moveAngle; + GetCollisionInfo(coll, item); + + if (TestLaraHitCeiling(coll)) + { + SetLaraHitCeiling(item, coll); + return; + } + + if (TestLaraVault(item, coll)) + return; + + if (LaraDeflectEdge(item, coll)) + { + item->pos.zRot = 0; + + if (coll->Front.Floor < -STEPUP_HEIGHT && + !coll->Front.Slope && + !TestLaraSwamp(item)) { item->goalAnimState = LS_SPLAT; if (GetChange(item, &g_Level.Anims[item->animNumber])) @@ -1823,210 +2001,220 @@ void lara_col_wade(ITEM_INFO* item, COLL_INFO* coll) LaraCollideStop(item, coll); } - - if (coll->Middle.Floor >= -STEPUP_HEIGHT && coll->Middle.Floor < -STEP_SIZE / 2 && !TestLaraSwamp(item)) + if (TestLaraStep(coll) || TestLaraSwamp(item)) { - item->goalAnimState = LS_STEP_UP; - GetChange(item, &g_Level.Anims[item->animNumber]); - } - - if (coll->Middle.Floor >= 50 && !TestLaraSwamp(item)) - { - item->pos.yPos += 50; + DoLaraStep(item, coll); return; } - - LaraSnapToHeight(item, coll); } -void lara_as_dash(ITEM_INFO* item, COLL_INFO* coll) +// State: LS_SPRINT (73) +// Collision: lara_col_sprint() +void lara_as_sprint(ITEM_INFO* item, COLL_INFO* coll) { - /*state 73*/ - /*collision: lara_col_dash*/ - if (item->hitPoints <= 0 || !Lara.sprintTimer || !(TrInput & IN_SPRINT) || Lara.waterStatus == LW_WADE) - { - item->goalAnimState = LS_RUN_FORWARD; - return; - } + LaraInfo*& info = item->data; - Lara.sprintTimer--; + info->sprintTimer--; - 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)) + info->jumpCount++; + if (info->jumpCount > LARA_JUMP_TIME) + info->jumpCount = LARA_JUMP_TIME; + + if (item->hitPoints <= 0) { - item->goalAnimState = LS_CROUCH_IDLE; + item->goalAnimState = LS_DEATH; return; } if (TrInput & IN_LEFT) { - Lara.turnRate -= LARA_TURN_RATE; - if (Lara.turnRate < -LARA_SLOW_TURN) - Lara.turnRate = -LARA_SLOW_TURN; + info->turnRate -= LARA_TURN_RATE; + if (info->turnRate < -LARA_SLOW_TURN_MAX) + info->turnRate = -LARA_SLOW_TURN_MAX; - item->pos.zRot -= LARA_LEAN_RATE; - if (item->pos.zRot < -LARA_LEAN_DASH_MAX) - item->pos.zRot = -LARA_LEAN_DASH_MAX; + DoLaraLean(item, coll, -LARA_LEAN_MAX, LARA_LEAN_RATE); } else if (TrInput & IN_RIGHT) { - Lara.turnRate += LARA_TURN_RATE; - if (Lara.turnRate > LARA_SLOW_TURN) - Lara.turnRate = LARA_SLOW_TURN; + info->turnRate += LARA_TURN_RATE; + if (info->turnRate > LARA_SLOW_TURN_MAX) + info->turnRate = LARA_SLOW_TURN_MAX; - item->pos.zRot += LARA_LEAN_RATE; - if (item->pos.zRot > LARA_LEAN_DASH_MAX) - item->pos.zRot = LARA_LEAN_DASH_MAX; + DoLaraLean(item, coll, LARA_LEAN_MAX, LARA_LEAN_RATE); } - if (!(TrInput & IN_JUMP) || item->gravityStatus) + if (TrInput & IN_JUMP) { - if (TrInput & IN_FORWARD) - { - if (TrInput & IN_WALK) - item->goalAnimState = LS_WALK_FORWARD; - else - item->goalAnimState = LS_SPRINT; - } - else if (!(TrInput & IN_LEFT) && !(TrInput & IN_RIGHT)) - { - item->goalAnimState = LS_STOP; - } + item->goalAnimState = LS_SPRINT_DIVE; + return; } - else + + if (TrInput & IN_DUCK && + (info->gunStatus == LG_HANDS_FREE || !IsStandingWeapon(info->gunType))) { - item->goalAnimState = LS_SPRINT_ROLL; + item->goalAnimState = LS_CROUCH_IDLE; + return; } + + // TODO: Supposedly there is a bug wherein sprinting into the boundary between shallow and deep water + // while meeting some condition allows Lara to run around in the water room. Investigate. @Sezz 2021.09.29 + if (TrInput & IN_FORWARD) + { + if (info->waterStatus == LW_WADE) + item->goalAnimState = LS_RUN_FORWARD; // TODO: Dispatch to wade forward state directly. @Sezz 2021.09.29 + else if (TrInput & IN_WALK) + item->goalAnimState = LS_WALK_FORWARD; + else if (TrInput & IN_SPRINT && info->sprintTimer > 0) [[likely]] + item->goalAnimState = LS_SPRINT; + else + item->goalAnimState = LS_RUN_FORWARD; + + return; + } + + item->goalAnimState = LS_IDLE; } -void lara_col_dash(ITEM_INFO* item, COLL_INFO* coll) +// State: LS_SPRINT (73) +// Control: lara_as_sprint() +void lara_col_sprint(ITEM_INFO* item, COLL_INFO* coll) { - /*state 73*/ - /*state code: lara_as_dash*/ - Lara.moveAngle = item->pos.yRot; + LaraInfo*& info = item->data; + info->moveAngle = item->pos.yRot; coll->Setup.BadHeightDown = NO_BAD_POS; coll->Setup.BadHeightUp = -STEPUP_HEIGHT; coll->Setup.BadCeilingHeight = 0; - coll->Setup.SlopesAreWalls = true; - - coll->Setup.ForwardAngle = Lara.moveAngle; + coll->Setup.ForwardAngle = info->moveAngle; GetCollisionInfo(coll, item); - if (!LaraHitCeiling(item, coll) && !TestLaraVault(item, coll)) + if (TestLaraHitCeiling(coll)) { - if (LaraDeflectEdge(item, coll)) + SetLaraHitCeiling(item, coll); + return; + } + + if (TestLaraFall(item, coll)) + { + SetLaraFallState(item); + return; + } + + if (TestLaraSlide(item, coll)) + return; + + if (LaraDeflectEdge(item, coll)) + { + item->pos.zRot = 0; + + if (coll->HitTallObject || TestLaraWall(item, STEP_SIZE, 0, -(STEP_SIZE * 2 + STEP_SIZE / 2)) != SPLAT_COLL::NONE) { - item->pos.zRot = 0; - - if (coll->HitTallObject || TestLaraWall(item, 256, 0, -640) != SPLAT_COLL::NONE) + item->goalAnimState = LS_SPLAT; + if (GetChange(item, &g_Level.Anims[item->animNumber])) { - item->goalAnimState = LS_SPLAT; - if (GetChange(item, &g_Level.Anims[item->animNumber])) - { - item->currentAnimState = LS_SPLAT; - return; - } + item->currentAnimState = LS_SPLAT; + return; } - - LaraCollideStop(item, coll); } - if (!LaraFallen(item, coll)) - { - if (coll->Middle.Floor >= -STEPUP_HEIGHT && coll->Middle.Floor < -STEP_SIZE / 2) - { - item->goalAnimState = LS_STEP_UP; - GetChange(item, &g_Level.Anims[item->animNumber]); - } + LaraCollideStop(item, coll); + } - if (!TestLaraSlide(item, coll)) - { - if (coll->Middle.Floor < 50) - { - if (coll->Middle.Floor != NO_HEIGHT) - item->pos.yPos += coll->Middle.Floor; - } - else - { - item->goalAnimState = LS_STEP_DOWN; // for theoretical sprint stepdown anims, not in default anims - if (GetChange(item, &g_Level.Anims[item->animNumber])) - item->pos.yPos += coll->Middle.Floor; // move Lara to middle.Floor - else - item->pos.yPos += 50; // do the default aligment - } - } - } + if (TestLaraVault(item, coll)) + return; + + if (TestLaraStep(coll) && coll->CollisionType != CT_FRONT) + { + DoLaraStep(item, coll); + return; } } -void lara_as_dashdive(ITEM_INFO* item, COLL_INFO* coll) +// State: LS_SPRINT_DIVE (74) +// Collision: lara_col_sprint_dive() +void lara_as_sprint_dive(ITEM_INFO* item, COLL_INFO* coll) { - /*state 74*/ - /*collision: lara_col_dashdive*/ + LaraInfo*& info = item->data; + + info->jumpCount++; + if (info->jumpCount > LARA_JUMP_TIME) + info->jumpCount = LARA_JUMP_TIME; + + if (TrInput & IN_LEFT) + { + info->turnRate -= LARA_TURN_RATE; + if (info->turnRate < -LARA_SLOW_TURN_MAX) + info->turnRate = -LARA_SLOW_TURN_MAX; + + DoLaraLean(item, coll, -(LARA_LEAN_MAX * 3) / 5, LARA_LEAN_RATE); + } + else if (TrInput & IN_RIGHT) + { + info->turnRate += LARA_TURN_RATE; + if (info->turnRate > LARA_SLOW_TURN_MAX) + info->turnRate = LARA_SLOW_TURN_MAX; + + DoLaraLean(item, coll, (LARA_LEAN_MAX * 3) / 5, LARA_LEAN_RATE); + } + + // TODO: What? if (item->goalAnimState != LS_DEATH && - item->goalAnimState != LS_STOP && + item->goalAnimState != LS_IDLE && item->goalAnimState != LS_RUN_FORWARD && item->fallspeed > LARA_FREEFALL_SPEED) + { item->goalAnimState = LS_FREEFALL; + } } -void lara_col_dashdive(ITEM_INFO* item, COLL_INFO* coll) +// State: LS_SPRINT_DIVE (74) +// Control: lara_col_sprint_dive() +void lara_col_sprint_dive(ITEM_INFO* item, COLL_INFO* coll) { - /*state 74*/ - /*state code: lara_as_dashdive*/ - if (item->speed < 0) - Lara.moveAngle = item->pos.yRot + ANGLE(180); - else - Lara.moveAngle = item->pos.yRot; + LaraInfo*& info = item->data; + info->moveAngle = (item->speed < 0) ? item->pos.yRot + ANGLE(180.0f) : item->pos.yRot; coll->Setup.BadHeightDown = NO_BAD_POS; coll->Setup.BadHeightUp = -STEPUP_HEIGHT; coll->Setup.BadCeilingHeight = BAD_JUMP_CEILING; - coll->Setup.SlopesAreWalls = true; - - coll->Setup.ForwardAngle = Lara.moveAngle; + coll->Setup.ForwardAngle = info->moveAngle; GetCollisionInfo(coll, item); + LaraDeflectEdgeJump(item, coll); - if (!LaraFallen(item, coll)) + if (TestLaraFall(item, coll)) { - if (item->speed < 0) - Lara.moveAngle = item->pos.yRot; + SetLaraFallState(item); + return; + } - if (coll->Middle.Floor <= 0 && item->fallspeed > 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; - } + if (item->speed < 0) + info->moveAngle = item->pos.yRot; // ??? - item->gravityStatus = false; - item->fallspeed = 0; - item->pos.yPos += coll->Middle.Floor; - item->speed = 0; + if (coll->Middle.Floor <= 0 && item->fallspeed > 0) + { + if (LaraLandedBad(item, coll)) // TODO: It seems Core wanted to make the sprint dive a true jump. + item->goalAnimState = LS_DEATH; + else if (!(TrInput & IN_FORWARD) || TrInput & IN_WALK || info->waterStatus == LW_WADE) + item->goalAnimState = LS_IDLE; + else + item->goalAnimState = LS_RUN_FORWARD; - AnimateLara(item); - } + item->gravityStatus = false; + item->fallspeed = 0; + item->pos.yPos += coll->Middle.Floor; + item->speed = 0; - ShiftItem(item, coll); + AnimateLara(item); + } - if (coll->Middle.Floor != NO_HEIGHT) - item->pos.yPos += coll->Middle.Floor; + ShiftItem(item, coll); + + if (TestLaraStep(coll)) + { + DoLaraStep(item, coll); + return; } } diff --git a/TR5Main/Game/Lara/lara_basic.h b/TR5Main/Game/Lara/lara_basic.h index 3f6b093b8..1814e92ff 100644 --- a/TR5Main/Game/Lara/lara_basic.h +++ b/TR5Main/Game/Lara/lara_basic.h @@ -1,71 +1,71 @@ #pragma once + struct ITEM_INFO; struct COLL_INFO; -/*generic functions*/ +struct COLL_RESULT; + +// ------------------------------ +// BASIC MOVEMENT & MISCELLANEOUS +// Control & Collision Functions +// ------------------------------ + +// -------------- +// MISCELLANEOUS: +// -------------- + void lara_void_func(ITEM_INFO* item, COLL_INFO* coll); void lara_default_col(ITEM_INFO* item, COLL_INFO* coll); void lara_as_special(ITEM_INFO* item, COLL_INFO* coll); void lara_as_null(ITEM_INFO* item, COLL_INFO* coll); void lara_as_controlled(ITEM_INFO* item, COLL_INFO* coll); -void lara_as_controlledl(ITEM_INFO* item, COLL_INFO* coll); -/*end generic functions*/ -/*-*/ -/*basic movement*/ -void lara_as_walk(ITEM_INFO* item, COLL_INFO* coll); -void lara_col_walk(ITEM_INFO* item, COLL_INFO* coll); -void lara_as_run(ITEM_INFO* item, COLL_INFO* coll); -void lara_col_run(ITEM_INFO* item, COLL_INFO* coll); -void lara_as_stop(ITEM_INFO* item, COLL_INFO* coll); -void lara_col_stop(ITEM_INFO* item, COLL_INFO* coll); -void lara_as_forwardjump(ITEM_INFO* item, COLL_INFO* coll); -void lara_col_forwardjump(ITEM_INFO* item, COLL_INFO* coll); -void lara_col_pose(ITEM_INFO* item, COLL_INFO* coll); -void lara_as_fastback(ITEM_INFO* item, COLL_INFO* coll); -void lara_col_fastback(ITEM_INFO* item, COLL_INFO* coll); -void lara_as_turn_r(ITEM_INFO* item, COLL_INFO* coll); -void lara_col_turn_r(ITEM_INFO* item, COLL_INFO* coll); -void lara_as_turn_l(ITEM_INFO* item, COLL_INFO* coll); -void lara_col_turn_l(ITEM_INFO* item, COLL_INFO* coll); +void lara_as_controlled_no_look(ITEM_INFO* item, COLL_INFO* coll); + +// --------------- +// BASIC MOVEMENT: +// --------------- + +void lara_as_walk_forward(ITEM_INFO* item, COLL_INFO* coll); +void lara_col_walk_forward(ITEM_INFO* item, COLL_INFO* coll); +void lara_as_run_forward(ITEM_INFO* item, COLL_INFO* coll); +void lara_col_run_forward(ITEM_INFO* item, COLL_INFO* coll); +void lara_as_idle(ITEM_INFO* item, COLL_INFO* coll); +void PseudoLaraAsWadeIdle(ITEM_INFO* item, COLL_INFO* coll); +void PseudoLaraAsSwampIdle(ITEM_INFO* item, COLL_INFO* coll); +void lara_col_idle(ITEM_INFO* item, COLL_INFO* coll); +void lara_as_pose(ITEM_INFO* item, COLL_INFO* coll); +void lara_as_run_back(ITEM_INFO* item, COLL_INFO* coll); +void lara_col_run_back(ITEM_INFO* item, COLL_INFO* coll); +void lara_as_turn_right_slow(ITEM_INFO* item, COLL_INFO* coll); +void PsuedoLaraAsSwampTurnRightSlow(ITEM_INFO* item, COLL_INFO* coll); +void PsuedoLaraAsWadeTurnRightSlow(ITEM_INFO* item, COLL_INFO* coll); +void lara_col_turn_right_slow(ITEM_INFO* item, COLL_INFO* coll); +void lara_as_turn_left_slow(ITEM_INFO* item, COLL_INFO* coll); +void PsuedoLaraAsWadeTurnLeftSlow(ITEM_INFO* item, COLL_INFO* coll); +void PsuedoLaraAsSwampTurnLeftSlow(ITEM_INFO* item, COLL_INFO* coll); +void lara_col_turn_left_slow(ITEM_INFO* item, COLL_INFO* coll); void lara_as_death(ITEM_INFO* item, COLL_INFO* coll); void lara_col_death(ITEM_INFO* item, COLL_INFO* coll); -void lara_as_fastfall(ITEM_INFO* item, COLL_INFO* coll); -void lara_col_fastfall(ITEM_INFO* item, COLL_INFO* coll); -void lara_as_reach(ITEM_INFO* item, COLL_INFO* coll); -void lara_col_reach(ITEM_INFO* item, COLL_INFO* coll); void lara_as_splat(ITEM_INFO* item, COLL_INFO* coll); void lara_col_splat(ITEM_INFO* item, COLL_INFO* coll); -void lara_col_land(ITEM_INFO* item, COLL_INFO* coll); -void lara_as_compress(ITEM_INFO* item, COLL_INFO* coll); -void lara_col_compress(ITEM_INFO* item, COLL_INFO* coll); -void lara_as_back(ITEM_INFO* item, COLL_INFO* coll); -void lara_col_back(ITEM_INFO* item, COLL_INFO* coll); -void lara_as_fastturn(ITEM_INFO* item, COLL_INFO* coll); -void lara_col_fastturn(ITEM_INFO* item, COLL_INFO* coll); -void lara_as_stepright(ITEM_INFO* item, COLL_INFO* coll); -void lara_col_stepright(ITEM_INFO* item, COLL_INFO* coll); -void lara_as_stepleft(ITEM_INFO* item, COLL_INFO* coll); -void lara_col_stepleft(ITEM_INFO* item, COLL_INFO* coll); -void lara_col_roll2(ITEM_INFO* item, COLL_INFO* coll); -void lara_as_backjump(ITEM_INFO* item, COLL_INFO* coll); -void lara_col_backjump(ITEM_INFO* item, COLL_INFO* coll); -void lara_as_rightjump(ITEM_INFO* item, COLL_INFO* coll); -void lara_col_rightjump(ITEM_INFO* item, COLL_INFO* coll); -void lara_as_leftjump(ITEM_INFO* item, COLL_INFO* coll); -void lara_col_leftjump(ITEM_INFO* item, COLL_INFO* coll); -void lara_col_jumper(ITEM_INFO* item, COLL_INFO* coll); -void lara_as_upjump(ITEM_INFO* item, COLL_INFO* coll); -void lara_col_upjump(ITEM_INFO* item, COLL_INFO* coll); -void lara_as_fallback(ITEM_INFO* item, COLL_INFO* coll); -void lara_col_fallback(ITEM_INFO* item, COLL_INFO* coll); -void lara_col_roll(ITEM_INFO* item, COLL_INFO* coll); -void lara_as_swandive(ITEM_INFO* item, COLL_INFO* coll); -void lara_col_swandive(ITEM_INFO* item, COLL_INFO* coll); -void lara_as_fastdive(ITEM_INFO* item, COLL_INFO* coll); -void lara_col_fastdive(ITEM_INFO* item, COLL_INFO* coll); -void lara_as_gymnast(ITEM_INFO* item, COLL_INFO* coll); -void lara_as_wade(ITEM_INFO* item, COLL_INFO* coll); -void lara_col_wade(ITEM_INFO* item, COLL_INFO* coll); -void lara_as_dash(ITEM_INFO* item, COLL_INFO* coll); -void lara_col_dash(ITEM_INFO* item, COLL_INFO* coll); -void lara_as_dashdive(ITEM_INFO* item, COLL_INFO* coll); -void lara_col_dashdive(ITEM_INFO* item, COLL_INFO* coll); +void lara_as_walk_back(ITEM_INFO* item, COLL_INFO* coll); +void PseudoLaraAsSwampWalkBack(ITEM_INFO* item, COLL_INFO* coll); +void lara_col_walk_back(ITEM_INFO* item, COLL_INFO* coll); +void lara_as_turn_right_fast(ITEM_INFO* item, COLL_INFO* coll); +void lara_col_turn_right_fast(ITEM_INFO* item, COLL_INFO* coll); +void lara_as_turn_left_fast(ITEM_INFO* item, COLL_INFO* coll); +void lara_col_turn_left_fast(ITEM_INFO* item, COLL_INFO* coll); +void lara_as_step_right(ITEM_INFO* item, COLL_INFO* coll); +void lara_col_step_right(ITEM_INFO* item, COLL_INFO* coll); +void lara_as_step_left(ITEM_INFO* item, COLL_INFO* coll); +void lara_col_step_left(ITEM_INFO* item, COLL_INFO* coll); +void lara_as_roll_back(ITEM_INFO* item, COLL_INFO* coll); +void lara_col_roll_back(ITEM_INFO* item, COLL_INFO* coll); +void lara_as_roll_forward(ITEM_INFO* item, COLL_INFO* coll); +void lara_col_roll_forward(ITEM_INFO* item, COLL_INFO* coll); +void lara_as_wade_forward(ITEM_INFO* item, COLL_INFO* coll); +void PseudoLaraAsSwampWadeForward(ITEM_INFO* item, COLL_INFO* coll); +void lara_col_wade_forward(ITEM_INFO* item, COLL_INFO* coll); +void lara_as_sprint(ITEM_INFO* item, COLL_INFO* coll); +void lara_col_sprint(ITEM_INFO* item, COLL_INFO* coll); +void lara_as_sprint_dive(ITEM_INFO* item, COLL_INFO* coll); +void lara_col_sprint_dive(ITEM_INFO* item, COLL_INFO* coll); diff --git a/TR5Main/Game/Lara/lara_climb.cpp b/TR5Main/Game/Lara/lara_climb.cpp index 570067e98..ad0b27449 100644 --- a/TR5Main/Game/Lara/lara_climb.cpp +++ b/TR5Main/Game/Lara/lara_climb.cpp @@ -385,7 +385,7 @@ void lara_as_climbstnc(ITEM_INFO* item, COLL_INFO* coll) if (item->animNumber == LA_LADDER_IDLE) { item->goalAnimState = LS_JUMP_BACK; - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; Lara.moveAngle = item->pos.yRot + ANGLE(180); } } @@ -958,7 +958,7 @@ int LaraCheckForLetGo(ITEM_INFO* item, COLL_INFO* coll) item->gravityStatus = true; item->fallspeed = 1; - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; return 1; } diff --git a/TR5Main/Game/Lara/lara_collide.cpp b/TR5Main/Game/Lara/lara_collide.cpp index 9d8618a8a..dbcc24724 100644 --- a/TR5Main/Game/Lara/lara_collide.cpp +++ b/TR5Main/Game/Lara/lara_collide.cpp @@ -14,7 +14,10 @@ #include "GameFlowScript.h" #include "GameScriptLevel.h" -/*this file has all the generic **collision** test functions called in lara's state code*/ +// ----------------------------- +// COLLISION TEST FUNCTIONS +// For State Control & Collision +// ----------------------------- bool LaraDeflectEdge(ITEM_INFO* item, COLL_INFO* coll) { @@ -22,7 +25,7 @@ bool LaraDeflectEdge(ITEM_INFO* item, COLL_INFO* coll) { ShiftItem(item, coll); - item->goalAnimState = LS_STOP; + item->goalAnimState = LS_IDLE; item->speed = 0; item->gravityStatus = false; @@ -43,46 +46,40 @@ bool LaraDeflectEdge(ITEM_INFO* item, COLL_INFO* coll) return false; } -void LaraDeflectEdgeJump(ITEM_INFO* item, COLL_INFO* coll) +bool LaraDeflectEdgeJump(ITEM_INFO* item, COLL_INFO* coll) { ShiftItem(item, coll); - switch (coll->CollisionType) + if (coll->CollisionType == CT_FRONT || coll->CollisionType == CT_TOP_FRONT) { - case CT_FRONT: - case CT_TOP_FRONT: if (!Lara.climbStatus || item->speed != 2) { - if (coll->Middle.Floor <= 512) - { - if (coll->Middle.Floor <= 128) - SetAnimation(item, LA_JUMP_UP_LAND); - } + if (coll->Middle.Floor <= STEP_SIZE) + SetAnimation(item, LA_LAND); else - { SetAnimation(item, LA_JUMP_WALL_SMASH_START, 1); - } item->speed /= 4; - Lara.moveAngle += ANGLE(180); + Lara.moveAngle += ANGLE(180.0f); if (item->fallspeed <= 0) item->fallspeed = 1; } - break; - case CT_TOP: + return true; + } + + if (coll->CollisionType == CT_TOP) + { if (item->fallspeed <= 0) item->fallspeed = 1; - - break; - case CT_LEFT: + } + else if (coll->CollisionType == CT_LEFT) item->pos.yRot += ANGLE(5.0f); - break; - case CT_RIGHT: + else if (coll->CollisionType == CT_RIGHT) item->pos.yRot -= ANGLE(5.0f); - break; - case CT_CLAMP: + else if (coll->CollisionType == CT_CLAMP) + { item->pos.xPos -= 400 * phd_sin(coll->Setup.ForwardAngle); item->pos.zPos -= 400 * phd_cos(coll->Setup.ForwardAngle); @@ -91,13 +88,14 @@ void LaraDeflectEdgeJump(ITEM_INFO* item, COLL_INFO* coll) if (item->fallspeed <= 0) item->fallspeed = 16; - - break; } + + return false; } bool LaraDeflectEdgeCrawl(ITEM_INFO* item, COLL_INFO* coll) { + // Useless in the best case; Lara does not have to embed in order to perform climbing actions in crawl states. Keeping for security. @Sezz 2021.11.26 if (coll->CollisionType == CT_FRONT || coll->CollisionType == CT_TOP_FRONT) { ShiftItem(item, coll); @@ -111,17 +109,43 @@ bool LaraDeflectEdgeCrawl(ITEM_INFO* item, COLL_INFO* coll) if (coll->CollisionType == CT_LEFT) { ShiftItem(item, coll); - item->pos.yRot += ANGLE(2.0f); + item->pos.yRot += ANGLE(coll->DiagonalStepAtLeft() ? DEFLECT_DIAGONAL_ANGLE_CRAWL : DEFLECT_STRAIGHT_ANGLE_CRAWL); } else if (coll->CollisionType == CT_RIGHT) { ShiftItem(item, coll); - item->pos.yRot -= ANGLE(2.0f); + item->pos.yRot -= ANGLE(coll->DiagonalStepAtRight() ? DEFLECT_DIAGONAL_ANGLE_CRAWL : DEFLECT_STRAIGHT_ANGLE_CRAWL); } return false; } +// TODO: Move the following two functions to lara_tests.cpp and lara_helpers.cpp? +// @Sezz 2021.09.26 +bool TestLaraHitCeiling(COLL_INFO* coll) +{ + if (coll->CollisionType == CT_TOP || + coll->CollisionType == CT_CLAMP) + { + return true; + } + + return false; +} + +void SetLaraHitCeiling(ITEM_INFO* item, COLL_INFO* coll) +{ + item->pos.xPos = coll->Setup.OldPosition.x; + item->pos.yPos = coll->Setup.OldPosition.y; + item->pos.zPos = coll->Setup.OldPosition.z; + + item->speed = 0; + item->fallspeed = 0; + item->gravityStatus = false; +} + +// LEGACY +// TODO: Gradually replace usage with TestLaraHitCeiling() and SetLaraHitCeiling(). @Sezz 2021.09.27 bool LaraHitCeiling(ITEM_INFO* item, COLL_INFO* coll) { if (coll->CollisionType == CT_TOP || coll->CollisionType == CT_CLAMP) @@ -146,33 +170,84 @@ void LaraCollideStop(ITEM_INFO* item, COLL_INFO* coll) { switch (coll->Setup.OldAnimState) { - case LS_STOP: + case LS_IDLE: case LS_TURN_RIGHT_SLOW: case LS_TURN_LEFT_SLOW: - case LS_TURN_FAST: + case LS_TURN_RIGHT_FAST: + case LS_TURN_LEFT_FAST: item->currentAnimState = coll->Setup.OldAnimState; item->animNumber = coll->Setup.OldAnimNumber; item->frameNumber = coll->Setup.OldFrameNumber; + if (TrInput & IN_LEFT) { - item->goalAnimState = LS_TURN_LEFT_SLOW; + // Prevent turn lock against walls. + if (item->currentAnimState == LS_TURN_RIGHT_SLOW || + item->currentAnimState == LS_TURN_RIGHT_FAST) + { + item->goalAnimState = LS_IDLE; + } + else + item->goalAnimState = LS_TURN_LEFT_SLOW; } else if (TrInput & IN_RIGHT) { - item->goalAnimState = LS_TURN_RIGHT_SLOW; + if (item->currentAnimState == LS_TURN_LEFT_SLOW || + item->currentAnimState == LS_TURN_LEFT_FAST) + { + item->goalAnimState = LS_IDLE; + } + else + item->goalAnimState = LS_TURN_RIGHT_SLOW; } else - { - item->goalAnimState = LS_STOP; - } + item->goalAnimState = LS_IDLE; + + AnimateLara(item); + + break; + + default: + item->goalAnimState = LS_IDLE; + + if (item->animNumber != LA_STAND_SOLID) + SetAnimation(item, LA_STAND_SOLID); + + break; + } +} + +void LaraCollideStopCrawl(ITEM_INFO* item, COLL_INFO* coll) +{ + switch (coll->Setup.OldAnimState) + { + case LS_CRAWL_IDLE: + case LS_CRAWL_TURN_LEFT: + case LS_CRAWL_TURN_RIGHT: + item->currentAnimState = coll->Setup.OldAnimState; + item->animNumber = coll->Setup.OldAnimNumber; + item->frameNumber = coll->Setup.OldFrameNumber; + + if (TrInput & IN_LEFT) + item->goalAnimState = LS_CRAWL_TURN_LEFT; + else if (TrInput & IN_RIGHT) + item->goalAnimState = LS_CRAWL_TURN_RIGHT; + else + item->goalAnimState = LS_CRAWL_IDLE; + AnimateLara(item); break; + default: - item->goalAnimState = LS_STOP; - if (item->animNumber != LA_STAND_SOLID) + item->currentAnimState = LS_CRAWL_IDLE; + item->goalAnimState = LS_CRAWL_IDLE; + + if (item->animNumber != LA_CRAWL_IDLE) { - SetAnimation(item, LA_STAND_SOLID); + item->animNumber = LA_CRAWL_IDLE; + item->frameNumber = GetFrameNumber(item, 0); } + break; } } @@ -261,6 +336,35 @@ void GetLaraDeadlyBounds() DeadlyBounds[5] = LaraItem->pos.zPos + tbounds.Z2; } +void LaraJumpCollision(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + /*states 25, 26, 27*/ + /*state code: none, but is called in lara_col_backjump, lara_col_rightjump and lara_col_leftjump*/ + coll->Setup.BadHeightDown = NO_BAD_POS; + coll->Setup.BadHeightUp = -STEPUP_HEIGHT; + coll->Setup.BadCeilingHeight = BAD_JUMP_CEILING; + coll->Setup.ForwardAngle = info->moveAngle; + + GetCollisionInfo(coll, item); + LaraDeflectEdgeJump(item, coll); + + if (item->fallspeed > 0 && coll->Middle.Floor <= 0) + { + if (LaraLandedBad(item, coll)) + item->goalAnimState = LS_DEATH; + else + item->goalAnimState = LS_IDLE; + + item->fallspeed = 0; + item->gravityStatus = 0; + + if (coll->Middle.Floor != NO_HEIGHT) + item->pos.yPos += coll->Middle.Floor; + } +} + void LaraSurfaceCollision(ITEM_INFO* item, COLL_INFO* coll) { coll->Setup.ForwardAngle = Lara.moveAngle; @@ -440,3 +544,18 @@ void LaraSwimCollision(ITEM_INFO* item, COLL_INFO* coll) if (Lara.waterStatus != LW_FLYCHEAT && Lara.ExtraAnim == NO_ITEM) TestLaraWaterDepth(item, coll); } + +bool TestLaraObjectCollision(ITEM_INFO* item, short angle, int dist, int height) +{ + auto oldPos = item->pos; + + item->pos.xPos += dist * phd_sin(item->pos.yRot + angle); + item->pos.yPos += height; + item->pos.zPos += dist * phd_cos(item->pos.yRot + angle); + + auto result = GetCollidedObjects(item, LARA_RAD, 1, CollidedItems, CollidedMeshes, 0); + + item->pos = oldPos; + + return result; +} diff --git a/TR5Main/Game/Lara/lara_collide.h b/TR5Main/Game/Lara/lara_collide.h index ed8777eef..73b8d9d17 100644 --- a/TR5Main/Game/Lara/lara_collide.h +++ b/TR5Main/Game/Lara/lara_collide.h @@ -4,17 +4,27 @@ struct COLL_INFO; constexpr auto DEFLECT_STRAIGHT_ANGLE = 5.0f; constexpr auto DEFLECT_DIAGONAL_ANGLE = 12.0f; +constexpr auto DEFLECT_STRAIGHT_ANGLE_CRAWL = 2.0f; +constexpr auto DEFLECT_DIAGONAL_ANGLE_CRAWL = 5.0f; bool LaraDeflectEdge(ITEM_INFO* item, COLL_INFO* coll); -void LaraDeflectEdgeJump(ITEM_INFO* item, COLL_INFO* coll); +bool LaraDeflectEdgeJump(ITEM_INFO* item, COLL_INFO* coll); bool LaraDeflectEdgeCrawl(ITEM_INFO* item, COLL_INFO* coll); bool LaraHitCeiling(ITEM_INFO* item, COLL_INFO* coll); void LaraCollideStop(ITEM_INFO* item, COLL_INFO* coll); +void LaraCollideStopCrawl(ITEM_INFO* item, COLL_INFO* coll); void LaraSnapToEdgeOfBlock(ITEM_INFO* item, COLL_INFO* coll, short angle); void LaraResetGravityStatus(ITEM_INFO* item, COLL_INFO* coll); void LaraSnapToHeight(ITEM_INFO* item, COLL_INFO* coll); short GetDirOctant(int rot); void GetLaraDeadlyBounds(); +void LaraJumpCollision(ITEM_INFO* item, COLL_INFO* coll); void LaraSurfaceCollision(ITEM_INFO* item, COLL_INFO* coll); void LaraSwimCollision(ITEM_INFO* item, COLL_INFO* coll); + +// TODO: Temporary placement. +bool TestLaraHitCeiling(COLL_INFO* coll); +void SetLaraHitCeiling(ITEM_INFO* item, COLL_INFO* coll); + +bool TestLaraObjectCollision(ITEM_INFO* item, short angle, int dist, int height); diff --git a/TR5Main/Game/Lara/lara_crawl.cpp b/TR5Main/Game/Lara/lara_crawl.cpp index 1f6a6f4f3..6a5b9f8e4 100644 --- a/TR5Main/Game/Lara/lara_crawl.cpp +++ b/TR5Main/Game/Lara/lara_crawl.cpp @@ -6,746 +6,818 @@ #include "lara_collide.h" #include "animation.h" #include "control/los.h" -#include "Lara/lara_flare.h" +#include "lara_flare.h" +#include "lara_helpers.h" #include "collide.h" #include "items.h" #include "camera.h" #include "control/control.h" #include "Scripting/GameFlowScript.h" -/*this file has all the related functions to ducking and crawling*/ +// ----------------------------- +// CRAWL & CROUCH +// Control & Collision Functions +// ----------------------------- -/*crouch/duck start*/ -void lara_as_duck(ITEM_INFO* item, COLL_INFO* coll) +// ------- +// CROUCH: +// ------- + +// State: LS_CROUCH_IDLE (71) +// Collision: lara_col_crouch_idle() +void lara_as_crouch_idle(ITEM_INFO* item, COLL_INFO* coll) { - /*state 71*/ - /*collision: lara_col_duck*/ - short roomNum; + // TODO: Deplete air meter if Lara's head is below the water. Original implementation had a weird buffer zone before + // wade depth where Lara couldn't crouch at all, and if the player forced her into the crouched state by + // crouching into the region from a run as late as possible, she wasn't able to turn or begin crawling. + // Since Lara can now crawl at a considerable depth, a region of peril would make sense. @Sezz 2021.10.21 + + LaraInfo*& info = item->data; coll->Setup.EnableSpaz = false; coll->Setup.EnableObjectPush = true; + Camera.targetElevation = -ANGLE(24.0f); - Lara.isDucked = true; - - if (item->hitPoints <= 0) - { - item->goalAnimState = LS_CRAWL_IDLE; + // TODO: Dispatch pickups from within states. + if (item->goalAnimState == LS_PICKUP) return; - } - roomNum = LaraItem->roomNumber; - - if (TrInput & IN_LOOK) - LookUpDown(); - - GetFloor(LaraItem->pos.xPos, LaraItem->pos.yPos, LaraItem->pos.zPos, &roomNum); - - if ((TrInput & IN_FORWARD || TrInput & IN_BACK) - && (TrInput & IN_DUCK || Lara.keepDucked) - && Lara.gunStatus == LG_NO_ARMS - && Lara.waterStatus != LW_WADE - || Lara.waterSurfaceDist == 256 - && !(Lara.waterSurfaceDist > 256)) - { - - if ((item->animNumber == LA_CROUCH_IDLE - || item->animNumber == LA_STAND_TO_CROUCH_END) - && !(TrInput & IN_FLARE || TrInput & IN_DRAW) - && (Lara.gunType != WEAPON_FLARE || Lara.flareAge < FLARE_AGE && Lara.flareAge != 0)) - { - Lara.torsoYrot = 0; - Lara.torsoXrot = 0; - item->goalAnimState = LS_CRAWL_IDLE; - } - - } - else if ((TrInput & IN_SPRINT) /*crouch roll*/ - && (TrInput & IN_DUCK || Lara.keepDucked) - && Lara.gunStatus == LG_NO_ARMS - && Lara.waterStatus != LW_WADE - || Lara.waterSurfaceDist == 256 - && !(Lara.waterSurfaceDist > 256) - && g_GameFlow->Animations.CrouchRoll) - { - if (LaraFloorFront(item, item->pos.yRot, 1024) >= 384 || // 4 clicks away from holes in the floor - TestLaraWall(item, WALL_SIZE / 2, 0, -256) != SPLAT_COLL::NONE) // 2 clicks away from walls + added a fix in lara_col_crouch_roll, better this way - return; - - if (!(TrInput & IN_FLARE || TrInput & IN_DRAW) //avoids some flare spawning/wep stuff - && (Lara.gunType != WEAPON_FLARE || Lara.flareAge < FLARE_AGE && Lara.flareAge != 0)) - - { - Lara.torsoYrot = 0; - Lara.torsoXrot = 0; - item->goalAnimState = LS_CROUCH_ROLL; - } - } -} - -void lara_col_duck(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 71*/ - /*state code: lara_as_duck*/ - item->gravityStatus = false; - item->fallspeed = 0; - - Lara.moveAngle = item->pos.yRot; - - coll->Setup.Height = LARA_HEIGHT_CRAWL; - coll->Setup.ForwardAngle = item->pos.yRot; - coll->Setup.BadHeightDown = STEPUP_HEIGHT; - coll->Setup.BadHeightUp = -STEPUP_HEIGHT; - coll->Setup.BadCeilingHeight = 0; - coll->Setup.SlopesAreWalls = true; - - GetCollisionInfo(coll, item); - - if (LaraFallen(item, coll)) - { - Lara.gunStatus = LG_NO_ARMS; - } - else if (!TestLaraSlide(item, coll)) - { - Lara.keepDucked = TestLaraStandUp(coll); - ShiftItem(item, coll); - - if (coll->Middle.Floor != NO_HEIGHT) - item->pos.yPos += coll->Middle.Floor; - - if (TrInput & IN_DUCK && Lara.waterStatus != LW_WADE || - Lara.keepDucked || - item->animNumber != LA_CROUCH_IDLE) - { - if (TrInput & IN_LEFT) - { - item->goalAnimState = LS_CROUCH_TURN_LEFT; - } - else if (TrInput & IN_RIGHT) - { - item->goalAnimState = LS_CROUCH_TURN_RIGHT; - } - } - else - { - item->goalAnimState = LS_STOP; - } - } -} - -void lara_as_crouch_roll(ITEM_INFO* item, COLL_INFO* coll)//horrible name. -{ - /*state 72*/ - /*collision: lara_col_crouch_roll*/ - Camera.targetElevation = -ANGLE(20.0f); - item->goalAnimState = LS_CROUCH_IDLE; -} - -void lara_col_crouch_roll(ITEM_INFO* item, COLL_INFO* coll)//horrible name. -{ - /*state 72*/ - /*state code: lara_as_crouch_roll*/ - item->gravityStatus = 0; - item->fallspeed = 0; - - Lara.moveAngle = item->pos.yRot; - - coll->Setup.Height = LARA_HEIGHT_CRAWL; - coll->Setup.BadHeightDown = STEPUP_HEIGHT; - coll->Setup.ForwardAngle = item->pos.yRot; - coll->Setup.BadHeightUp = -STEPUP_HEIGHT; - coll->Setup.BadCeilingHeight = 0; - coll->Setup.SlopesAreWalls = true; - - GetCollisionInfo(coll, item); - - if (LaraFallen(item, coll)) - Lara.gunStatus = LG_NO_ARMS; - else if (!TestLaraSlide(item, coll)) - { - Lara.keepDucked = TestLaraStandUp(coll); - - if (coll->Middle.Floor < coll->Setup.BadHeightUp)//hit a wall, stop - { - item->pos.xPos = coll->Setup.OldPosition.x; - item->pos.yPos = coll->Setup.OldPosition.y; - item->pos.zPos = coll->Setup.OldPosition.z; - return; - } - - ShiftItem(item, coll); - - if (!LaraHitCeiling(item, coll)) - item->pos.yPos += coll->Middle.Floor; - } -} - -/*crouch/duck end*/ -/*-*/ -/*crawl start*/ -void lara_as_all4s(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 80*/ - /*collision: lara_col_all4s*/ if (item->hitPoints <= 0) { item->goalAnimState = LS_DEATH; return; } - if (g_GameFlow->Animations.CrawlExtra) - { - if (TrInput & IN_JUMP) - { - GAME_VECTOR s, d; - - s.x = LaraItem->pos.xPos; - s.y = LaraItem->pos.yPos - 96; - s.z = LaraItem->pos.zPos; - s.roomNumber = LaraItem->roomNumber; - - d.x = s.x + 768 * phd_sin(LaraItem->pos.yRot); - d.y = s.y + LARA_HEADROOM; - d.z = s.z + 768 * phd_cos(LaraItem->pos.yRot); - - if (LOS(&s, &d) && - item->animNumber != LA_CROUCH_TO_CRAWL_START && - item->animNumber != LA_CROUCH_TO_CRAWL_CONTINUE && - LaraCeilingFront(item, item->pos.yRot, CLICK(3), CLICK(2)) != NO_HEIGHT && - LaraCeilingFront(item, item->pos.yRot, CLICK(3), CLICK(2)) <= 0) - { - auto floorFront = LaraFloorFront(item, item->pos.yRot, CLICK(1)); - - if (floorFront >= CLICK(1) / 2 && floorFront <= CLICK(1)) - { - SetAnimation(item, LA_CRAWL_JUMP_DOWN_1CLICK); - } - else if (floorFront <= CLICK(2)) - { - SetAnimation(item, LA_CRAWL_JUMP_DOWN_23CLICK); - } - else if (floorFront <= CLICK(3)) - { - SetAnimation(item, LA_CRAWL_JUMP_DOWN_23CLICK); - } - if (floorFront > CLICK(3)) - { - SetAnimation(item, LA_CRAWL_JUMP_FLIP_DOWN); - } - - Lara.gunStatus = LG_HANDS_BUSY; - } - } - - if ((TrInput & IN_ACTION) && (TrInput & IN_FORWARD) && item->animNumber != LA_CROUCH_TO_CRAWL_START && item->animNumber != LA_CROUCH_TO_CRAWL_CONTINUE) - { - if (LaraFloorFront(item, item->pos.yRot, 256) == -256 && - LaraCeilingFront(item, item->pos.yRot, 256, 256) != NO_HEIGHT && - LaraCeilingFront(item, item->pos.yRot, 256, 256) <= -512) - { - SetAnimation(item, LA_CRAWL_UP_STEP); - Lara.gunStatus = LG_HANDS_BUSY; - } - else if (LaraFloorFront(item, item->pos.yRot, 256) == 256 && - LaraCeilingFront(item, item->pos.yRot, 256, 256) != NO_HEIGHT && - LaraCeilingFront(item, item->pos.yRot, 256, -256) <= -512) - { - SetAnimation(item, LA_CRAWL_DOWN_STEP); - Lara.gunStatus = LG_HANDS_BUSY; - } - } - } - if (TrInput & IN_LOOK) LookUpDown(); - Lara.torsoXrot = 0; - Lara.torsoYrot = 0; + if (TrInput & IN_LEFT) + info->turnRate = -LARA_CRAWL_TURN_MAX; + else if (TrInput & IN_RIGHT) + info->turnRate = LARA_CRAWL_TURN_MAX; - coll->Setup.EnableSpaz = false; - coll->Setup.EnableObjectPush = true; - - if (item->animNumber == LA_CROUCH_TO_CRAWL_START) - Lara.gunStatus = LG_HANDS_BUSY; - - Camera.targetElevation = -ANGLE(23.0f); - - if (TestLaraWater(item)) + if ((TrInput & IN_DUCK || info->keepCrouched) && + info->waterStatus != LW_WADE) { - item->goalAnimState = LS_CROUCH_IDLE; - item->requiredAnimState = LS_STOP; - } -} - -void lara_col_all4s(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 80*/ - /*state code: lara_as_all4s*/ - item->fallspeed = 0; - item->gravityStatus = false; - - if (item->goalAnimState != LS_CRAWL_TO_HANG) - { - Lara.moveAngle = item->pos.yRot; - - coll->Setup.ForwardAngle = Lara.moveAngle; - coll->Setup.Radius = LARA_RAD_CRAWL; - coll->Setup.Height = LARA_HEIGHT_CRAWL; - coll->Setup.BadHeightDown = STEP_SIZE - 1; - coll->Setup.BadHeightUp = -127; - coll->Setup.BadCeilingHeight = LARA_HEIGHT_CRAWL; - coll->Setup.SlopesAreWalls = true; - coll->Setup.SlopesArePits = true; - - GetCollisionInfo(coll, item); - - if (LaraFallen(item, coll)) + if (TrInput & IN_SPRINT && TestLaraCrouchRoll(item, coll) && + info->gunStatus == LG_HANDS_FREE && + g_GameFlow->Animations.CrouchRoll) { - Lara.gunStatus = LG_NO_ARMS; + item->goalAnimState = LS_CROUCH_ROLL; + return; } - else if (!TestLaraSlide(item, coll)) + + if (TrInput & (IN_FORWARD | IN_BACK) && TestLaraCrouchToCrawl(item)) { - int slope = abs(coll->FrontLeft.Floor - coll->FrontRight.Floor); - - Lara.keepDucked = TestLaraStandUp(coll); - ShiftItem(item, coll); - - if (coll->Middle.Floor != NO_HEIGHT && coll->Middle.Floor > -256) - item->pos.yPos += coll->Middle.Floor; - - if (TrInput & IN_DUCK || Lara.keepDucked && - (!(TrInput & IN_FLARE) && !(TrInput & IN_DRAW) || TrInput & IN_FORWARD) && - Lara.waterStatus != LW_WADE) - { - if (item->animNumber == LA_CRAWL_IDLE || - item->animNumber == LA_CROUCH_TO_CRAWL_END || - item->animNumber == LA_CRAWL_TO_IDLE_END_RIGHT_POINTLESS || - item->animNumber == LA_CRAWL_TO_IDLE_END_LEFT_POINTLESS) - { - if (TrInput & IN_FORWARD) - { - auto collResult = LaraCollisionFront(item, item->pos.yRot, 256); - if (abs(collResult.Position.Floor) < 127 && !collResult.Position.Slope) - item->goalAnimState = LS_CRAWL_FORWARD; - } - else if (TrInput & IN_BACK) - { - short height = LaraCeilingFront(item, item->pos.yRot, -300, 128); - short heightl = 0; - short heightr = 0; - - if (height != NO_HEIGHT && height <= -256) - { - if (TrInput & IN_ACTION) - { - int x = item->pos.xPos; - int z = item->pos.zPos; - - item->pos.xPos += 128 * phd_sin(item->pos.yRot - ANGLE(90.0f)); - item->pos.zPos += 128 * phd_cos(item->pos.yRot - ANGLE(90.0f)); - - heightl = LaraFloorFront(item, item->pos.yRot, -300); - - item->pos.xPos += 256 * phd_sin(item->pos.yRot + ANGLE(90.0f)); - item->pos.zPos += 256 * phd_cos(item->pos.yRot + ANGLE(90.0f)); - - heightr = LaraFloorFront(item, item->pos.yRot, -300); - - item->pos.xPos = x; - item->pos.zPos = z; - } - - auto collResult = LaraCollisionFront(item, item->pos.yRot, -300); - height = collResult.Position.Floor; - - if (abs(height) >= STEP_SIZE - 1 || collResult.Position.Slope) - { - if (TrInput & IN_ACTION) - { - if (height > 768 && - heightl > 768 && - heightr > 768 && - slope < 120) - { - int tmp; - int x = item->pos.xPos; - int z = item->pos.zPos; - - item->pos.xPos -= 100 * phd_sin(coll->Setup.ForwardAngle); - item->pos.zPos -= 100 * phd_cos(coll->Setup.ForwardAngle); - - tmp = GetCollidedObjects(item, 100, 1, CollidedItems, CollidedMeshes, 0); - - item->pos.xPos = x; - item->pos.zPos = z; - - if (!tmp) - { - coll->Setup.ForwardAngle += ANGLE(180); - GetCollisionInfo(coll, item); - SnapItemToLedge(item, coll); - MoveItem(item, coll->Setup.ForwardAngle, -(coll->Setup.Radius - STEP_SIZE / 2)); - item->pos.yRot += ANGLE(180); - LaraResetGravityStatus(item, coll); - - item->goalAnimState = LS_CRAWL_TO_HANG; - } - } - } - } - else if (!(abs(height) >= STEP_SIZE)) - { - item->goalAnimState = LS_CRAWL_BACK; - } - } - } - else if (TrInput & IN_LEFT) - SetAnimation(item, LA_CRAWL_TURN_LEFT); - else if (TrInput & IN_RIGHT) - SetAnimation(item, LA_CRAWL_TURN_RIGHT); - } - } - else - { - item->goalAnimState = LS_CROUCH_IDLE; - } + item->goalAnimState = LS_CRAWL_IDLE; + return; } - } -} -void lara_as_crawl(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 81*/ - /*collision: lara_col_crawl*/ - if (item->hitPoints <= 0) - { - item->goalAnimState = LS_CRAWL_IDLE; - return; - } - - if (TrInput & IN_LOOK) - LookUpDown(); - - Lara.torsoXrot = 0; - Lara.torsoYrot = 0; - - coll->Setup.EnableSpaz = false; - coll->Setup.EnableObjectPush = true; - - Camera.targetElevation = -ANGLE(23.0f); - - if (TrInput & IN_FORWARD - && (TrInput & IN_DUCK || Lara.keepDucked) - && Lara.waterStatus != LW_WADE) - { if (TrInput & IN_LEFT) { - Lara.turnRate -= LARA_TURN_RATE; - - if (Lara.turnRate < -ANGLE(3.0f)) - Lara.turnRate = -ANGLE(3.0f); + item->goalAnimState = LS_CROUCH_TURN_LEFT; + return; } else if (TrInput & IN_RIGHT) { - Lara.turnRate += LARA_TURN_RATE; - - if (Lara.turnRate > ANGLE(3.0f)) - Lara.turnRate = ANGLE(3.0f); + item->goalAnimState = LS_CROUCH_TURN_RIGHT; + return; } + + item->goalAnimState = LS_CROUCH_IDLE; + return; } - else - { - item->goalAnimState = LS_CRAWL_IDLE; - } + + item->goalAnimState = LS_IDLE; } -void lara_col_crawl(ITEM_INFO* item, COLL_INFO* coll) +// State: LS_CROUCH_IDLE (71) +// Control: lara_as_crouch_idle() +void lara_col_crouch_idle(ITEM_INFO* item, COLL_INFO* coll) { - /*state 81*/ - /*state code: lara_as_crawl*/ + LaraInfo*& info = item->data; + + info->keepCrouched = TestLaraKeepCrouched(item, coll); + info->isDucked = true; + info->moveAngle = item->pos.yRot; + info->torsoXrot = 0; + info->torsoYrot = 0; item->gravityStatus = false; item->fallspeed = 0; - - Lara.moveAngle = item->pos.yRot; - - coll->Setup.Radius = LARA_RAD_CRAWL; coll->Setup.Height = LARA_HEIGHT_CRAWL; + coll->Setup.ForwardAngle = item->pos.yRot; coll->Setup.BadHeightDown = STEP_SIZE - 1; - coll->Setup.BadHeightUp = -127; - coll->Setup.BadCeilingHeight = LARA_HEIGHT_CRAWL; - coll->Setup.SlopesArePits = true; + coll->Setup.BadHeightUp = -(STEP_SIZE - 1); + coll->Setup.BadCeilingHeight = 0; coll->Setup.SlopesAreWalls = true; - coll->Setup.ForwardAngle = Lara.moveAngle; - - GetCollisionInfo(coll, item, true); - - if (LaraDeflectEdgeCrawl(item, coll)) - { - item->currentAnimState = LS_CRAWL_IDLE; - item->goalAnimState = LS_CRAWL_IDLE; - - if (item->animNumber != LA_CRAWL_IDLE) - { - SetAnimation(item, LA_CRAWL_IDLE); - } - } - else if (LaraFallen(item, coll)) - { - Lara.gunStatus = LG_NO_ARMS; - } - else if (!TestLaraSlide(item, coll)) - { - ShiftItem(item, coll); - - if (coll->Middle.Floor != NO_HEIGHT && coll->Middle.Floor > -256) - item->pos.yPos += coll->Middle.Floor; - } -} - -void lara_as_all4turnl(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 84*/ - /*collision: lara_col_all4turnlr*/ - if (item->hitPoints <= 0) - { - item->goalAnimState = LS_CRAWL_IDLE; - return; - } - - coll->Setup.EnableSpaz = false; - coll->Setup.EnableObjectPush = true; - Lara.torsoYrot = 0; - Lara.torsoXrot = 0; - Camera.targetElevation = -ANGLE(23.0f); - item->pos.yRot -= ANGLE(1.5f); - - if (!(TrInput & IN_LEFT)) - item->goalAnimState = LS_CRAWL_IDLE; -} - -void lara_as_all4turnr(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 85*/ - /*collision: lara_col_all4turnlr*/ - if (item->hitPoints <= 0) - { - item->goalAnimState = LS_CRAWL_IDLE; - return; - } - - coll->Setup.EnableSpaz = false; - coll->Setup.EnableObjectPush = true; - Lara.torsoYrot = 0; - Lara.torsoXrot = 0; - Camera.targetElevation = -ANGLE(23.0f); - item->pos.yRot += ANGLE(1.5f); - - if (!(TrInput & IN_RIGHT)) - item->goalAnimState = LS_CRAWL_IDLE; -} - -void lara_col_all4turnlr(ITEM_INFO* item, COLL_INFO* coll) -{ - /*states 84 and 85*/ - /*state code: lara_as_all4turnl(84) and lara_as_all4turnr(85)*/ - coll->Setup.Height = LARA_HEIGHT_CRAWL; GetCollisionInfo(coll, item); - if (!TestLaraSlide(item, coll)) + if (TestLaraFall(item, coll)) { - if (coll->Middle.Floor != NO_HEIGHT && coll->Middle.Floor > -256) - item->pos.yPos += coll->Middle.Floor; + SetLaraFallState(item); + info->gunStatus = LG_HANDS_FREE; + return; + } + + if (TestLaraSlide(item, coll)) + return; + + ShiftItem(item, coll); + + if (TestLaraStep(coll)) + { + DoLaraStep(item, coll); + return; } } -void lara_as_crawlb(ITEM_INFO* item, COLL_INFO* coll) +// State: LS_CROUCH_ROLL (72) +// Collision: lara_as_crouch_roll() +void lara_as_crouch_roll(ITEM_INFO* item, COLL_INFO* coll) { - /*state 86*/ - /*collision: lara_col_crawlb*/ - if (item->hitPoints <= 0 || Lara.waterStatus == 4) + LaraInfo*& info = item->data; + + info->look = false; + coll->Setup.EnableSpaz = false; + coll->Setup.EnableObjectPush = true; + Camera.targetElevation = -ANGLE(24.0f); + + if (TrInput & IN_LEFT) { - item->goalAnimState = LS_CRAWL_IDLE; + info->turnRate -= LARA_TURN_RATE; + if (info->turnRate < -LARA_CROUCH_ROLL_TURN_MAX) + info->turnRate = -LARA_CROUCH_ROLL_TURN_MAX; + + DoLaraLean(item, coll, -LARA_LEAN_MAX, LARA_LEAN_RATE); + } + else if (TrInput & IN_RIGHT) + { + info->turnRate += LARA_TURN_RATE; + if (info->turnRate > LARA_CROUCH_ROLL_TURN_MAX) + info->turnRate = LARA_CROUCH_ROLL_TURN_MAX; + + DoLaraLean(item, coll, LARA_LEAN_MAX, LARA_LEAN_RATE); + } + + item->goalAnimState = LS_CROUCH_IDLE; +} + +// State: LS_CROUCH_ROLL (72) +// Control: lara_as_crouch_roll() +void lara_col_crouch_roll(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + info->keepCrouched = TestLaraKeepCrouched(item, coll); + info->isDucked = true; + info->moveAngle = item->pos.yRot; + item->gravityStatus = 0; + item->fallspeed = 0; + coll->Setup.Height = LARA_HEIGHT_CRAWL; + coll->Setup.BadHeightDown = STEP_SIZE - 1; + coll->Setup.BadHeightUp = -(STEP_SIZE - 1); + coll->Setup.ForwardAngle = item->pos.yRot; + coll->Setup.BadCeilingHeight = 0; + coll->Setup.SlopesAreWalls = true; + GetCollisionInfo(coll, item); + + // TODO: With sufficient speed, Lara can still roll off ledges. This is particularly a problem in the uncommon scenario where + // she becomes airborne within a crawlspace; collision handling will push her back very rapidly and potentially cause a softlock. @Sezz 2021.11.02 + if (LaraDeflectEdgeCrawl(item, coll)) + { + item->pos.xPos = coll->Setup.OldPosition.x; + item->pos.yPos = coll->Setup.OldPosition.y; + item->pos.zPos = coll->Setup.OldPosition.z; + } + + if (TestLaraFall(item, coll)) + { + SetLaraFallState(item); + info->gunStatus = LG_HANDS_FREE; + item->speed /= 3; // Truncate speed to prevent flying off. + return; + } + + if (TestLaraSlide(item, coll)) + return; + + ShiftItem(item, coll); + + if (TestLaraHitCeiling(coll)) + { + SetLaraHitCeiling(item, coll); + return; + } + + if (TestLaraStep(coll)) + { + DoLaraStep(item, coll); + return; + } +} + +// State: LS_CROUCH_TURN_LEFT (105) +// Collision: lara_col_crouch_turn_left() +void lara_as_crouch_turn_left(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + coll->Setup.EnableSpaz = false; + Camera.targetElevation = -ANGLE(24.0f); + + if (item->hitPoints <= 0) + { + item->goalAnimState = LS_DEATH; return; } if (TrInput & IN_LOOK) LookUpDown(); - coll->Setup.EnableSpaz = false; - coll->Setup.EnableObjectPush = true; + info->turnRate = -LARA_CRAWL_TURN_MAX; - Lara.torsoYrot = 0; - Lara.torsoXrot = 0; - - Camera.targetElevation = -ANGLE(23.0f); - - if (TrInput & IN_BACK) + if ((TrInput & IN_DUCK || info->keepCrouched) && + info->waterStatus != LW_WADE) { - if (TrInput & IN_RIGHT) + if (TrInput & IN_SPRINT && TestLaraCrouchRoll(item, coll) && + g_GameFlow->Animations.CrouchRoll) { - Lara.turnRate -= LARA_TURN_RATE; - if (Lara.turnRate < -ANGLE(3.0f)) - Lara.turnRate = -ANGLE(3.0f); + item->goalAnimState = LS_CROUCH_ROLL; + return; } - else if (TrInput & IN_LEFT) + + if (TrInput & (IN_FORWARD | IN_BACK) && TestLaraCrouchToCrawl(item)) { - Lara.turnRate += LARA_TURN_RATE; - if (Lara.turnRate > ANGLE(3.0f)) - Lara.turnRate = ANGLE(3.0f); + item->goalAnimState = LS_CRAWL_IDLE; + return; } + + if (TrInput & IN_LEFT) + { + item->goalAnimState = LS_CROUCH_TURN_LEFT; + return; + } + + item->goalAnimState = LS_CROUCH_IDLE; + return; } - else - { - item->goalAnimState = LS_CRAWL_IDLE; - } + + item->goalAnimState = LS_IDLE; } -void lara_col_crawlb(ITEM_INFO* item, COLL_INFO* coll) +// State: LS_CRAWL_TURN_LEFT (105) +// Control: lara_as_crouch_turn_left() +void lara_col_crouch_turn_left(ITEM_INFO* item, COLL_INFO* coll) { - /*state 86*/ - /*state code: lara_as_crawlb*/ - item->gravityStatus = false; + lara_col_crouch_idle(item, coll); +} + +// State: LS_CROUCH_TURN_RIGHT (106) +// Collision: lara_col_crouch_turn_right() +void lara_as_crouch_turn_right(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + coll->Setup.EnableSpaz = false; + Camera.targetElevation = -ANGLE(24.0f); + + if (item->hitPoints <= 0) + { + item->goalAnimState = LS_DEATH; + return; + } + + if (TrInput & IN_LOOK) + LookUpDown(); + + info->turnRate = LARA_CRAWL_TURN_MAX; + + if ((TrInput & IN_DUCK || info->keepCrouched) && + info->waterStatus != LW_WADE) + { + if (TrInput & IN_SPRINT && TestLaraCrouchRoll(item, coll) && + g_GameFlow->Animations.CrouchRoll) + { + item->goalAnimState = LS_CROUCH_ROLL; + return; + } + + if (TrInput & (IN_FORWARD | IN_BACK) && TestLaraCrouchToCrawl(item)) + { + item->goalAnimState = LS_CRAWL_IDLE; + return; + } + + if (TrInput & IN_RIGHT) + { + item->goalAnimState = LS_CROUCH_TURN_RIGHT; + return; + } + + item->goalAnimState = LS_CROUCH_IDLE; + return; + } + + item->goalAnimState = LS_IDLE; +} + +// State: LS_CRAWL_TURN_RIGHT (106) +// Control: lara_as_crouch_turn_right() +void lara_col_crouch_turn_right(ITEM_INFO* item, COLL_INFO* coll) +{ + lara_col_crouch_idle(item, coll); +} + +// ------ +// CRAWL: +// ------ + +// State: LS_CRAWL_IDLE (80) +// Collision: lara_col_crawl_idle() +void lara_as_crawl_idle(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + info->gunStatus = LG_HANDS_BUSY; + coll->Setup.EnableSpaz = false; + coll->Setup.EnableObjectPush = true; + Camera.targetElevation = -ANGLE(24.0f); + + // TODO: Dispatch pickups from within states. + if (item->goalAnimState == LS_PICKUP) + return; + + if (item->hitPoints <= 0) + { + item->goalAnimState = LS_DEATH; + return; + } + + if (TrInput & IN_LOOK) + LookUpDown(); + + if (TrInput & IN_LEFT) + info->turnRate = -LARA_CRAWL_TURN_MAX; + else if (TrInput & IN_RIGHT) + info->turnRate = LARA_CRAWL_TURN_MAX; + + if ((TrInput & IN_DUCK || info->keepCrouched) && + info->waterStatus != LW_WADE) + { + // TODO: Flare not working. + if ((TrInput & IN_SPRINT && TestLaraCrouchRoll(item, coll)) || + (TrInput & (IN_DRAW | IN_FLARE) && + !IsStandingWeapon(info->gunType) && + item->animNumber != LA_CROUCH_TO_CRAWL_START)) // Hack. + { + item->goalAnimState = LS_CROUCH_IDLE; + info->gunStatus = LG_HANDS_FREE; + return; + } + + if (TrInput & IN_FORWARD) + { + if (TrInput & (IN_ACTION | IN_JUMP) && TestLaraCrawlVault(item, coll) && + g_GameFlow->Animations.CrawlExtended) + { + DoLaraCrawlVault(item, coll); + return; + } + else if (TestLaraCrawlForward(item, coll)) [[likely]] + { + item->goalAnimState = LS_CRAWL_FORWARD; + return; + } + } + else if (TrInput & IN_BACK) + { + if (TrInput & (IN_ACTION | IN_JUMP) && TestLaraCrawlToHang(item, coll)) + { + item->goalAnimState = LS_CRAWL_TO_HANG; + DoLaraCrawlToHangSnap(item, coll); + return; + } + else if (TestLaraCrawlBack(item, coll)) [[likely]] + { + item->goalAnimState = LS_CRAWL_BACK; + return; + } + } + + if (TrInput & IN_LEFT) + { + item->goalAnimState = LS_CRAWL_TURN_LEFT; + return; + } + else if (TrInput & IN_RIGHT) + { + item->goalAnimState = LS_CRAWL_TURN_RIGHT; + return; + } + + item->goalAnimState = LS_CRAWL_IDLE; + return; + } + + item->goalAnimState = LS_CROUCH_IDLE; + info->gunStatus = LG_HANDS_FREE; +} + +// State: LS_CRAWL_IDLE (80) +// Control: lara_as_crawl_idle() +void lara_col_crawl_idle(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + info->keepCrouched = TestLaraKeepCrouched(item, coll); + info->isDucked = true; + info->moveAngle = item->pos.yRot; + info->torsoXrot = 0; + info->torsoYrot = 0; item->fallspeed = 0; - - Lara.moveAngle = item->pos.yRot + ANGLE(180); - - coll->Setup.Radius = LARA_RAD_CRAWL + 50; // TODO: Check if it still works without 50? + item->gravityStatus = false; + coll->Setup.ForwardAngle = info->moveAngle; + coll->Setup.Radius = LARA_RAD_CRAWL; coll->Setup.Height = LARA_HEIGHT_CRAWL; coll->Setup.BadHeightDown = STEP_SIZE - 1; coll->Setup.BadHeightUp = -(STEP_SIZE - 1); coll->Setup.BadCeilingHeight = LARA_HEIGHT_CRAWL; + coll->Setup.SlopesAreWalls = true; + coll->Setup.SlopesArePits = true; + GetCollisionInfo(coll, item); + + if (TestLaraFall(item, coll)) + { + SetLaraFallState(item); + info->gunStatus = LG_HANDS_FREE; + return; + } + + if (TestLaraSlide(item, coll)) + return; + + ShiftItem(item, coll); + + if (TestLaraStep(coll)) + { + DoLaraStep(item, coll); + return; + } +} + +// State: LS_CRAWL_FORWARD (81) +// Collision: lara_col_crawl_forward() +void lara_as_crawl_forward(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + info->gunStatus = LG_HANDS_BUSY; + coll->Setup.EnableSpaz = false; + coll->Setup.EnableObjectPush = true; + Camera.targetElevation = -ANGLE(24.0f); + + if (item->hitPoints <= 0) + { + item->goalAnimState = LS_DEATH; + return; + } + + if (TrInput & IN_LEFT) + { + info->turnRate -= LARA_CRAWL_MOVE_TURN_RATE; + if (info->turnRate < -LARA_CRAWL_MOVE_TURN_MAX) + info->turnRate = -LARA_CRAWL_MOVE_TURN_MAX; + + DoLaraCrawlFlex(item, coll, -LARA_CRAWL_FLEX_MAX, LARA_CRAWL_FLEX_RATE); + } + else if (TrInput & IN_RIGHT) + { + info->turnRate += LARA_CRAWL_MOVE_TURN_RATE; + if (info->turnRate > LARA_CRAWL_MOVE_TURN_MAX) + info->turnRate = LARA_CRAWL_MOVE_TURN_MAX; + + DoLaraCrawlFlex(item, coll, LARA_CRAWL_FLEX_MAX, LARA_CRAWL_FLEX_RATE); + } + + if ((TrInput & IN_DUCK || info->keepCrouched) && + info->waterStatus != LW_WADE) + { + if (TrInput & IN_SPRINT && TestLaraCrouchRoll(item, coll)) + { + item->goalAnimState = LS_CRAWL_IDLE; + return; + } + + if (TrInput & IN_FORWARD) + { + item->goalAnimState = LS_CRAWL_FORWARD; + return; + } + + item->goalAnimState = LS_CRAWL_IDLE; + return; + } + + item->goalAnimState = LS_CRAWL_IDLE; +} + +// State: LS_CRAWL_FORWARD (81) +// Control: lara_as_crawl_forward() +void lara_col_crawl_forward(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + info->keepCrouched = TestLaraKeepCrouched(item, coll); + info->isDucked = true; + info->moveAngle = item->pos.yRot; + info->torsoXrot = 0; + info->torsoYrot = 0; + item->gravityStatus = false; + item->fallspeed = 0; + coll->Setup.Radius = LARA_RAD_CRAWL; + coll->Setup.Height = LARA_HEIGHT_CRAWL; + coll->Setup.BadHeightDown = STEP_SIZE - 1; // Offset of 1 is required or Lara will crawl up/down steps. + coll->Setup.BadHeightUp = -(STEP_SIZE - 1); // TODO: Stepping approach is different from walk/run because crawl step anims do not submerge Lara. Resolve this someday. @Sezz 2021.10.31 + coll->Setup.BadCeilingHeight = LARA_HEIGHT_CRAWL; coll->Setup.SlopesArePits = true; coll->Setup.SlopesAreWalls = true; - - coll->Setup.ForwardAngle = Lara.moveAngle; - + coll->Setup.DeathFlagIsPit = true; + coll->Setup.ForwardAngle = info->moveAngle; GetCollisionInfo(coll, item, true); if (LaraDeflectEdgeCrawl(item, coll)) + LaraCollideStopCrawl(item, coll); + + if (TestLaraFall(item, coll)) { - item->currentAnimState = LS_CRAWL_IDLE; - item->goalAnimState = LS_CRAWL_IDLE; + SetLaraFallState(item); + info->gunStatus = LG_HANDS_FREE; + return; + } + + if (TestLaraSlide(item, coll)) + return; - if (item->animNumber != LA_CRAWL_IDLE) + ShiftItem(item, coll); + + if (TestLaraStep(coll)) + { + DoLaraStep(item, coll); + return; + } +} + +// State: LS_CRAWL_BACK (86) +// Collision: lara_col_crawl_back() +void lara_as_crawl_back(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + info->look = false; + info->gunStatus = LG_HANDS_BUSY; + coll->Setup.EnableSpaz = false; + coll->Setup.EnableObjectPush = true; + Camera.targetElevation = -ANGLE(24.0f); + + if (item->hitPoints <= 0) + { + item->goalAnimState = LS_DEATH; + return; + } + + if (TrInput & IN_LEFT) + { + info->turnRate -= LARA_CRAWL_MOVE_TURN_RATE; + if (info->turnRate < -LARA_CRAWL_MOVE_TURN_MAX) + info->turnRate = -LARA_CRAWL_MOVE_TURN_MAX; + + DoLaraCrawlFlex(item, coll, LARA_CRAWL_FLEX_MAX, LARA_CRAWL_FLEX_RATE); + } + else if (TrInput & IN_RIGHT) + { + info->turnRate += LARA_CRAWL_MOVE_TURN_RATE; + if (info->turnRate > LARA_CRAWL_MOVE_TURN_MAX) + info->turnRate = LARA_CRAWL_MOVE_TURN_MAX; + + DoLaraCrawlFlex(item, coll, -LARA_CRAWL_FLEX_MAX, LARA_CRAWL_FLEX_RATE); + } + + if ((TrInput & IN_DUCK || info->keepCrouched) && + info->waterStatus != LW_WADE) + { + if (TrInput & IN_BACK) { - SetAnimation(item, LA_CRAWL_IDLE); + item->goalAnimState = LS_CRAWL_BACK; + return; } - } - else if (LaraFallen(item, coll)) - { - Lara.gunStatus = LG_NO_ARMS; - } - else if (!TestLaraSlide(item, coll)) - { - ShiftItem(item, coll); - if (coll->Middle.Floor != NO_HEIGHT && coll->Middle.Floor > -STEP_SIZE) - item->pos.yPos += coll->Middle.Floor; - - Lara.moveAngle = item->pos.yRot; + item->goalAnimState = LS_CRAWL_IDLE; + return; } + + item->goalAnimState = LS_CRAWL_IDLE; } -void lara_as_duckl(ITEM_INFO* item, COLL_INFO* coll) +// State: LS_CRAWL_BACK (86) +// Control: lara_as_crawl_back() +void lara_col_crawl_back(ITEM_INFO* item, COLL_INFO* coll) { - /*state 105*/ - /*collision: lara_col_ducklr*/ - coll->Setup.EnableSpaz = false; - if ((TrInput & (IN_DUCK | IN_LEFT)) != (IN_DUCK | IN_LEFT) || item->hitPoints <= 0) - item->goalAnimState = LS_CROUCH_IDLE; - item->pos.yRot -= ANGLE(1.5f); -} - -void lara_as_duckr(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 106*/ - /*collision: lara_col_ducklr*/ - coll->Setup.EnableSpaz = false; - if ((TrInput & (IN_DUCK | IN_RIGHT)) != (IN_DUCK | IN_RIGHT) || item->hitPoints <= 0) - item->goalAnimState = LS_CROUCH_IDLE; - item->pos.yRot += ANGLE(1.5f); -} - -void lara_col_ducklr(ITEM_INFO* item, COLL_INFO* coll) -{ - /*state 105 and 106*/ - /*state code: lara_as_duckl(105) and lara_col_ducklr(106)*/ - // FIXED - Lara.isDucked = true; - if (TrInput & IN_LOOK) - LookUpDown(); + LaraInfo*& info = item->data; + info->keepCrouched = TestLaraKeepCrouched(item, coll); + info->isDucked = true; + info->moveAngle = item->pos.yRot + ANGLE(180.0f); item->gravityStatus = false; item->fallspeed = 0; - - Lara.moveAngle = item->pos.yRot; - + coll->Setup.Radius = LARA_RAD_CRAWL; coll->Setup.Height = LARA_HEIGHT_CRAWL; - coll->Setup.ForwardAngle = item->pos.yRot; - coll->Setup.BadHeightDown = STEPUP_HEIGHT; - coll->Setup.BadHeightUp = -STEPUP_HEIGHT; - coll->Setup.BadCeilingHeight = 0; + coll->Setup.BadHeightDown = STEP_SIZE - 1; // Offset of 1 is required or Lara will crawl up/down steps. + coll->Setup.BadHeightUp = -(STEP_SIZE - 1); + coll->Setup.BadCeilingHeight = LARA_HEIGHT_CRAWL; + coll->Setup.SlopesArePits = true; coll->Setup.SlopesAreWalls = true; + coll->Setup.DeathFlagIsPit = true; + coll->Setup.ForwardAngle = info->moveAngle; + GetCollisionInfo(coll, item, true); - GetCollisionInfo(coll, item); + if (LaraDeflectEdgeCrawl(item, coll)) + LaraCollideStopCrawl(item, coll); - if (LaraFallen(item, coll)) + if (TestLaraFall(item, coll)) { - Lara.gunStatus = LG_NO_ARMS; + SetLaraFallState(item); + info->gunStatus = LG_HANDS_FREE; + return; } - else if (!TestLaraSlide(item, coll)) - { - Lara.keepDucked = TestLaraStandUp(coll); - ShiftItem(item, coll); - if (coll->Middle.Floor != NO_HEIGHT) - item->pos.yPos += coll->Middle.Floor; + if (TestLaraSlide(item, coll)) + return; + + ShiftItem(item, coll); + + if (TestLaraStep(coll)) + { + DoLaraStep(item, coll); + return; } } -/*crawling end*/ -void lara_col_crawl2hang(ITEM_INFO* item, COLL_INFO* coll) +// State: LS_CRAWL_TURN_LEFT (84) +// Collision: lara_col_crawl_turn_left() +void lara_as_crawl_turn_left(ITEM_INFO* item, COLL_INFO* coll) { - Camera.targetAngle = 0; - Camera.targetElevation = -ANGLE(45.0f); + LaraInfo*& info = item->data; + + info->gunStatus = LG_HANDS_BUSY; + coll->Setup.EnableSpaz = false; + coll->Setup.EnableObjectPush = true; + Camera.targetElevation = -ANGLE(24.0f); + + if (item->hitPoints <= 0) + { + item->goalAnimState = LS_DEATH; + return; + } + + info->turnRate = -LARA_CRAWL_TURN_MAX; + + if ((TrInput & IN_DUCK || info->keepCrouched) && + info->waterStatus != LW_WADE) + { + if (TrInput & IN_SPRINT && TestLaraCrouchRoll(item, coll)) + { + item->goalAnimState = LS_CRAWL_IDLE; + return; + } + + if (TrInput & IN_FORWARD && TestLaraCrawlForward(item, coll)) + { + item->goalAnimState = LS_CRAWL_FORWARD; + return; + } + + if (TrInput & IN_BACK && TestLaraCrawlBack(item, coll)) + { + item->goalAnimState = LS_CRAWL_BACK; + return; + } + + if (TrInput & IN_LEFT) + { + item->goalAnimState = LS_CRAWL_TURN_LEFT; + return; + } + + item->goalAnimState = LS_CRAWL_IDLE; + return; + } + + item->goalAnimState = LS_CRAWL_IDLE; +} + +// State: LS_CRAWL_TURN_LEFT (84) +// Control: lara_as_crawl_turn_left() +void lara_col_crawl_turn_left(ITEM_INFO* item, COLL_INFO* coll) +{ + lara_col_crawl_idle(item, coll); +} + +// State: LS_CRAWL_TURN_RIGHT (85) +// Collision: lara_col_crawl_turn_right() +void lara_as_crawl_turn_right(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + info->gunStatus = LG_HANDS_BUSY; + coll->Setup.EnableSpaz = false; + coll->Setup.EnableObjectPush = true; + Camera.targetElevation = -ANGLE(24.0f); + + if (item->hitPoints <= 0) + { + item->goalAnimState = LS_DEATH; + return; + } + + info->turnRate = LARA_CRAWL_TURN_MAX; + + if ((TrInput & IN_DUCK || info->keepCrouched) && + info->waterStatus != LW_WADE) + { + if (TrInput & IN_SPRINT && TestLaraCrouchRoll(item, coll)) + { + item->goalAnimState = LS_CRAWL_IDLE; + return; + } + + if (TrInput & IN_FORWARD && TestLaraCrawlForward(item, coll)) + { + item->goalAnimState = LS_CRAWL_FORWARD; + return; + } + + if (TrInput & IN_BACK && TestLaraCrawlBack(item, coll)) + { + item->goalAnimState = LS_CRAWL_BACK; + return; + } + + if (TrInput & IN_RIGHT) + { + item->goalAnimState = LS_CRAWL_TURN_RIGHT; + return; + } + + item->goalAnimState = LS_CRAWL_IDLE; + return; + } + + item->goalAnimState = LS_CRAWL_IDLE; +} + +// State: LS_CRAWL_TURN_RIGHT (85) +// Control: lara_as_crawl_turn_right() +void lara_col_crawl_turn_right(ITEM_INFO* item, COLL_INFO* coll) +{ + lara_col_crawl_idle(item, coll); +} + +void lara_col_crawl_to_hang(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; coll->Setup.EnableSpaz = false; coll->Setup.EnableObjectPush = false; + Camera.targetAngle = 0; + Camera.targetElevation = -ANGLE(45.0f); if (item->animNumber == LA_CRAWL_TO_HANG_END) { + info->moveAngle = item->pos.yRot; coll->Setup.Height = LARA_HEIGHT_STRETCH; coll->Setup.BadHeightDown = NO_BAD_POS; coll->Setup.BadHeightUp = -STEPUP_HEIGHT; coll->Setup.BadCeilingHeight = BAD_JUMP_CEILING; - coll->Setup.ForwardAngle = Lara.moveAngle; - - Lara.moveAngle = item->pos.yRot; + coll->Setup.ForwardAngle = info->moveAngle; MoveItem(item, item->pos.yRot, -STEP_SIZE); GetCollisionInfo(coll, item); SnapItemToLedge(item, coll); + // TODO: When refactoring monkey swing, get rid of this. if (TestHangSwingIn(item, item->pos.yRot)) { - - Lara.headYrot = 0; - Lara.headXrot = 0; - Lara.torsoYrot = 0; - Lara.torsoXrot = 0; SetAnimation(item, LA_JUMP_UP_TO_MONKEYSWING); + ResetLaraFlex(item); } else - { SetAnimation(item, LA_REACH_TO_HANG, 12); - } GetCollisionInfo(coll, item); + info->gunStatus = LG_HANDS_BUSY; item->pos.yPos += coll->Front.Floor - GetBoundsAccurate(item)->Y1 - 20; - item->gravityStatus = true; item->speed = 2; item->fallspeed = 1; - - Lara.gunStatus = LG_HANDS_BUSY; } } diff --git a/TR5Main/Game/Lara/lara_crawl.h b/TR5Main/Game/Lara/lara_crawl.h index 9e90f27dd..89352714b 100644 --- a/TR5Main/Game/Lara/lara_crawl.h +++ b/TR5Main/Game/Lara/lara_crawl.h @@ -1,25 +1,36 @@ #pragma once #include "lara_struct.h" -/*crouch/duck start*/ -void lara_as_duck(ITEM_INFO* item, COLL_INFO* coll); -void lara_col_duck(ITEM_INFO* item, COLL_INFO* coll); +// ----------------------------- +// CRAWL & CROUCH +// Control & Collision Functions +// ----------------------------- + +// ------- +// CROUCH: +// ------- + +void lara_as_crouch_idle(ITEM_INFO* item, COLL_INFO* coll); +void lara_col_crouch_idle(ITEM_INFO* item, COLL_INFO* coll); void lara_as_crouch_roll(ITEM_INFO* item, COLL_INFO* coll); void lara_col_crouch_roll(ITEM_INFO* item, COLL_INFO* coll); -/*crouch/duck end*/ -/*-*/ -/*crawl start*/ -void lara_as_all4s(ITEM_INFO* item, COLL_INFO* coll); -void lara_col_all4s(ITEM_INFO* item, COLL_INFO* coll); -void lara_as_crawl(ITEM_INFO* item, COLL_INFO* coll); -void lara_col_crawl(ITEM_INFO* item, COLL_INFO* coll); -void lara_as_all4turnl(ITEM_INFO* item, COLL_INFO* coll); -void lara_as_all4turnr(ITEM_INFO* item, COLL_INFO* coll); -void lara_col_all4turnlr(ITEM_INFO* item, COLL_INFO* coll); -void lara_as_crawlb(ITEM_INFO* item, COLL_INFO* coll); -void lara_col_crawlb(ITEM_INFO* item, COLL_INFO* coll); -void lara_as_duckl(ITEM_INFO* item, COLL_INFO* coll); -void lara_as_duckr(ITEM_INFO* item, COLL_INFO* coll); -void lara_col_ducklr(ITEM_INFO* item, COLL_INFO* coll); -/*crawl end*/ -void lara_col_crawl2hang(ITEM_INFO* item, COLL_INFO* coll); \ No newline at end of file +void lara_as_crouch_turn_left(ITEM_INFO* item, COLL_INFO* coll); +void lara_col_crouch_turn_left(ITEM_INFO* item, COLL_INFO* coll); +void lara_as_crouch_turn_right(ITEM_INFO* item, COLL_INFO* coll); +void lara_col_crouch_turn_right(ITEM_INFO* item, COLL_INFO* coll); + +// ------ +// CRAWL: +// ------ + +void lara_as_crawl_idle(ITEM_INFO* item, COLL_INFO* coll); +void lara_col_crawl_idle(ITEM_INFO* item, COLL_INFO* coll); +void lara_as_crawl_forward(ITEM_INFO* item, COLL_INFO* coll); +void lara_col_crawl_forward(ITEM_INFO* item, COLL_INFO* coll); +void lara_as_crawl_back(ITEM_INFO* item, COLL_INFO* coll); +void lara_col_crawl_back(ITEM_INFO* item, COLL_INFO* coll); +void lara_as_crawl_turn_left(ITEM_INFO* item, COLL_INFO* coll); +void lara_col_crawl_turn_left(ITEM_INFO* item, COLL_INFO* coll); +void lara_as_crawl_turn_right(ITEM_INFO* item, COLL_INFO* coll); +void lara_col_crawl_turn_right(ITEM_INFO* item, COLL_INFO* coll); +void lara_col_crawl_to_hang(ITEM_INFO* item, COLL_INFO* coll); diff --git a/TR5Main/Game/Lara/lara_fire.cpp b/TR5Main/Game/Lara/lara_fire.cpp index 09b64cb0b..68df887ac 100644 --- a/TR5Main/Game/Lara/lara_fire.cpp +++ b/TR5Main/Game/Lara/lara_fire.cpp @@ -235,15 +235,17 @@ WEAPON_INFO Weapons[NUM_WEAPONS] = } }; +// States in which Lara will hold the flare out in front. short HoldStates[] = { LS_WALK_FORWARD, LS_RUN_FORWARD, - LS_STOP, + LS_IDLE, LS_POSE, LS_TURN_RIGHT_SLOW, LS_TURN_LEFT_SLOW, LS_WALK_BACK, - LS_TURN_FAST, + LS_TURN_RIGHT_FAST, + LS_TURN_LEFT_FAST, LS_STEP_RIGHT, LS_STEP_LEFT, LS_PICKUP, @@ -355,8 +357,8 @@ void LaraGun(ITEM_INFO* laraItem) } if (laraItem->hitPoints <= 0) - laraInfo->gunStatus = LG_NO_ARMS; - else if (laraInfo->gunStatus == LG_NO_ARMS) + laraInfo->gunStatus = LG_HANDS_FREE; + else if (laraInfo->gunStatus == LG_HANDS_FREE) { // Draw weapon. if (TrInput & IN_DRAW) @@ -365,12 +367,6 @@ void LaraGun(ITEM_INFO* laraItem) else if (TrInput & IN_FLARE && (g_GameFlow->GetLevel(CurrentLevel)->LaraType != LaraType::Young)) { - if (laraItem->currentAnimState == LS_CROUCH_IDLE && - laraItem->animNumber != LA_CROUCH_IDLE) - { - return; - } - if (laraInfo->gunType == WEAPON_FLARE) { // if (!laraInfo->leftArm.frameNumber) //NO @@ -496,7 +492,7 @@ void LaraGun(ITEM_INFO* laraItem) break; default: - laraInfo->gunStatus = LG_NO_ARMS; + laraInfo->gunStatus = LG_HANDS_FREE; break; } @@ -587,7 +583,7 @@ void LaraGun(ITEM_INFO* laraItem) break; - case LG_NO_ARMS: + case LG_HANDS_FREE: if (laraInfo->gunType == WEAPON_FLARE) { if (laraInfo->Vehicle != NO_ITEM || @@ -661,7 +657,7 @@ void InitialiseNewWeapon(ITEM_INFO* lara) case WEAPON_UZI: laraInfo->rightArm.frameBase = Objects[ID_PISTOLS_ANIM].frameBase; laraInfo->leftArm.frameBase = Objects[ID_PISTOLS_ANIM].frameBase; - if (laraInfo->gunStatus != LG_NO_ARMS) + if (laraInfo->gunStatus != LG_HANDS_FREE) draw_pistol_meshes(laraInfo->gunType); break; @@ -673,14 +669,14 @@ void InitialiseNewWeapon(ITEM_INFO* lara) case WEAPON_ROCKET_LAUNCHER: laraInfo->rightArm.frameBase = Objects[WeaponObject(laraInfo->gunType)].frameBase; laraInfo->leftArm.frameBase = Objects[WeaponObject(laraInfo->gunType)].frameBase; - if (laraInfo->gunStatus != LG_NO_ARMS) + if (laraInfo->gunStatus != LG_HANDS_FREE) draw_shotgun_meshes(laraInfo->gunType); break; case WEAPON_FLARE: laraInfo->rightArm.frameBase = Objects[ID_LARA_FLARE_ANIM].frameBase; laraInfo->leftArm.frameBase = Objects[ID_LARA_FLARE_ANIM].frameBase; - if (laraInfo->gunStatus != LG_NO_ARMS) + if (laraInfo->gunStatus != LG_HANDS_FREE) DrawFlareMeshes(lara); break; @@ -1113,7 +1109,7 @@ void LaraGetNewTarget(ITEM_INFO* lara, WEAPON_INFO* weaponInfo) if (TargetList[slot] == laraInfo->target) break; } - if (laraInfo->gunStatus != LG_NO_ARMS || TrInput & IN_LOOKSWITCH) + if (laraInfo->gunStatus != LG_HANDS_FREE || TrInput & IN_LOOKSWITCH) { if (!laraInfo->target) { diff --git a/TR5Main/Game/Lara/lara_flare.cpp b/TR5Main/Game/Lara/lara_flare.cpp index bc4e6b991..6e06db32a 100644 --- a/TR5Main/Game/Lara/lara_flare.cpp +++ b/TR5Main/Game/Lara/lara_flare.cpp @@ -84,7 +84,7 @@ void ReadyFlare(ITEM_INFO* laraItem) { LaraInfo*& laraInfo = laraItem->data; - laraInfo->gunStatus = LG_NO_ARMS; + laraInfo->gunStatus = LG_HANDS_FREE; laraInfo->leftArm.xRot = 0; laraInfo->leftArm.yRot = 0; laraInfo->leftArm.zRot = 0; @@ -118,7 +118,7 @@ void UndrawFlare(ITEM_INFO* laraItem) laraInfo->flareControlLeft = true; - if (laraItem->goalAnimState == LS_STOP && + if (laraItem->goalAnimState == LS_IDLE && laraInfo->Vehicle == NO_ITEM) { if (laraItem->animNumber == LA_STAND_IDLE) @@ -137,7 +137,7 @@ void UndrawFlare(ITEM_INFO* laraItem) { laraInfo->requestGunType = laraInfo->lastGunType; laraInfo->gunType = laraInfo->lastGunType; - laraInfo->gunStatus = LG_NO_ARMS; + laraInfo->gunStatus = LG_HANDS_FREE; InitialiseNewWeapon(laraItem); @@ -190,7 +190,7 @@ void UndrawFlare(ITEM_INFO* laraItem) armFrame = 0; laraInfo->requestGunType = laraInfo->lastGunType; laraInfo->gunType = laraInfo->lastGunType; - laraInfo->gunStatus = LG_NO_ARMS; + laraInfo->gunStatus = LG_HANDS_FREE; InitialiseNewWeapon(laraItem); @@ -376,7 +376,7 @@ void DoFlareInHand(ITEM_INFO* laraItem, int flareAge) if (ItemInfo->flareAge >= FLARE_AGE) { - if (ItemInfo->gunStatus == LG_NO_ARMS) + if (ItemInfo->gunStatus == LG_HANDS_FREE) ItemInfo->gunStatus = LG_UNDRAW_GUNS; } else if (ItemInfo->flareAge != 0) diff --git a/TR5Main/Game/Lara/lara_hang.cpp b/TR5Main/Game/Lara/lara_hang.cpp index 11aef044e..9d7e6d551 100644 --- a/TR5Main/Game/Lara/lara_hang.cpp +++ b/TR5Main/Game/Lara/lara_hang.cpp @@ -20,7 +20,7 @@ void SetCornerAnim(ITEM_INFO* item, COLL_INFO* coll, bool flip) item->pos.yPos += STEP_SIZE; item->fallspeed = 1; - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; item->pos.yRot += Lara.nextCornerPos.yRot / 2; return; @@ -53,7 +53,7 @@ void lara_as_hang(ITEM_INFO* item, COLL_INFO* coll) if (item->hitPoints <= 0) { - item->goalAnimState = LS_STOP; + item->goalAnimState = LS_IDLE; return; } @@ -278,6 +278,14 @@ void lara_col_hangright(ITEM_INFO* item, COLL_INFO* coll) Lara.moveAngle = item->pos.yRot + ANGLE(90); } +void lara_as_gymnast(ITEM_INFO* item, COLL_INFO* coll) +{ + /*state 54*/ + /*collision: lara_default_col*/ + coll->Setup.EnableObjectPush = false; + coll->Setup.EnableSpaz = false; +} + /*go around corners*/ void lara_as_corner(ITEM_INFO* item, COLL_INFO* coll) diff --git a/TR5Main/Game/Lara/lara_hang.h b/TR5Main/Game/Lara/lara_hang.h index 719731d57..2e06df0b9 100644 --- a/TR5Main/Game/Lara/lara_hang.h +++ b/TR5Main/Game/Lara/lara_hang.h @@ -8,6 +8,7 @@ void lara_as_hangleft(ITEM_INFO* item, COLL_INFO* coll); void lara_col_hangleft(ITEM_INFO* item, COLL_INFO* coll); void lara_as_hangright(ITEM_INFO* item, COLL_INFO* coll); void lara_col_hangright(ITEM_INFO* item, COLL_INFO* coll); +void lara_as_gymnast(ITEM_INFO* item, COLL_INFO* coll); // Go around corners void lara_as_corner(ITEM_INFO* item, COLL_INFO* coll); \ No newline at end of file diff --git a/TR5Main/Game/Lara/lara_helpers.cpp b/TR5Main/Game/Lara/lara_helpers.cpp new file mode 100644 index 000000000..2a48b6125 --- /dev/null +++ b/TR5Main/Game/Lara/lara_helpers.cpp @@ -0,0 +1,253 @@ +#include "framework.h" +#include "collide.h" +#include "control/control.h" +#include "input.h" +#include "items.h" +#include "level.h" +#include "lara.h" +#include "lara_helpers.h" +#include "lara_tests.h" +#include "lara_collide.h" +#include "setup.h" +#include "GameFlowScript.h" + +// ----------------------------- +// HELPER FUNCTIONS +// For State Control & Collision +// ----------------------------- + +// TODO: Some states can't make the most of this function due to missing step up/down animations. +// Try implementing leg IK as a substitute to make step animations obsolete. @Sezz 2021.10.09 +void DoLaraStep(ITEM_INFO* item, COLL_INFO* coll) +{ + if (!TestLaraSwamp(item)) + { + if (TestLaraStepUp(item, coll)) + { + item->goalAnimState = LS_STEP_UP; + if (GetChange(item, &g_Level.Anims[item->animNumber])) + { + item->pos.yPos += coll->Middle.Floor; + return; + } + } + else if (TestLaraStepDown(item, coll)) + { + item->goalAnimState = LS_STEP_DOWN; + if (GetChange(item, &g_Level.Anims[item->animNumber])) + { + item->pos.yPos += coll->Middle.Floor; + return; + } + } + } + + // Height difference is below threshold for step dispatch OR step animation doesn't exist; translate Lara to new floor height. + // TODO: This approach might cause underirable artefacts where an object pushes Lara rapidly up/down a slope or a platform rapidly ascends/descends. + constexpr int rate = 50; + int threshold = std::max(abs(item->speed) / 3 * 2, STEP_SIZE / 16); + int sign = std::copysign(1, coll->Middle.Floor); + + if (TestLaraSwamp(item) && coll->Middle.Floor > 0) + item->pos.yPos += SWAMP_GRAVITY; + else if (abs(coll->Middle.Floor) > (STEPUP_HEIGHT / 2)) // Outer range. + item->pos.yPos += rate * sign; + else if (abs(coll->Middle.Floor) <= (STEPUP_HEIGHT / 2) && // Inner range. + abs(coll->Middle.Floor) >= threshold) + { + item->pos.yPos += std::max((int)abs(coll->Middle.Floor / 2.75), threshold) * sign; + } + else + item->pos.yPos += coll->Middle.Floor; +} + +void DoLaraCrawlVault(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + ResetLaraFlex(item); + + if (TestLaraCrawlExitDownStep(item, coll)) + { + if (TrInput & IN_DUCK && TestLaraCrawlDownStep(item, coll)) + item->goalAnimState = LS_STEP_DOWN; + else [[likely]] + item->goalAnimState = LS_CRAWL_EXIT_DOWN_STEP; + + return; + } + + if (TestLaraCrawlExitJump(item, coll)) + { + if (TrInput & IN_WALK) + item->goalAnimState = LS_CRAWL_EXIT_FLIP; + else [[likely]] + item->goalAnimState = LS_CRAWL_EXIT_JUMP; + + return; + } + + if (TestLaraCrawlUpStep(item, coll)) + { + item->goalAnimState = LS_STEP_UP; + return; + } + + if (TestLaraCrawlDownStep(item, coll)) + { + item->goalAnimState = LS_STEP_DOWN; + return; + } +} + +void DoLaraCrawlToHangSnap(ITEM_INFO* item, COLL_INFO* coll) +{ + coll->Setup.ForwardAngle = item->pos.yRot + ANGLE(180.0f); + GetCollisionInfo(coll, item); + SnapItemToLedge(item, coll); + MoveItem(item, item->pos.yRot, -LARA_RAD_CRAWL); + item->pos.yRot += ANGLE(180.0f); + LaraResetGravityStatus(item, coll); +} + +// TODO: Make lean rate proportional to the turn rate, allowing for nicer aesthetics with future analog stick input. +void DoLaraLean(ITEM_INFO* item, COLL_INFO* coll, int maxAngle, short rate) +{ + if (!item->speed) + return; + + int sign = copysign(1, maxAngle); + + if (coll->CollisionType == CT_LEFT || coll->CollisionType == CT_RIGHT) + item->pos.zRot += std::min(rate, (short)(abs((maxAngle * 3) / 5 - item->pos.zRot) / 3)) * sign; + else + item->pos.zRot += std::min(rate, (short)(abs(maxAngle - item->pos.zRot) / 3)) * sign; +} + +void DoLaraCrawlFlex(ITEM_INFO* item, COLL_INFO* coll, short maxAngle, short rate) +{ + LaraInfo*& info = item->data; + + if (!item->speed) + return; + + int sign = copysign(1, maxAngle); + rate = copysign(rate, maxAngle); + + info->torsoZrot += std::min(abs(rate), abs(maxAngle - info->torsoZrot) / 6) * sign; + + if (!(TrInput & IN_LOOK) && + item->currentAnimState != LS_CRAWL_BACK) + { + info->headZrot = info->torsoZrot / 2; + info->headYrot = info->headZrot; + } +} + +void SetLaraFallState(ITEM_INFO* item) +{ + SetAnimation(item, LA_FALL_START); + item->fallspeed = 0; + item->gravityStatus = true; +} + +void SetLaraFallBackState(ITEM_INFO* item) +{ + SetAnimation(item, LA_FALL_BACK); + item->fallspeed = 0; + item->gravityStatus = true; +} + +void ResetLaraFlex(ITEM_INFO* item, float rate) +{ + LaraInfo*& info = item->data; + + // Reset head. + if (abs(info->headXrot) > ANGLE(0.1f)) + info->headXrot += info->headXrot / -rate; + else + info->headXrot = 0; + + if (abs(info->headYrot) > ANGLE(0.1f)) + info->headYrot += info->headYrot / -rate; + else + info->headYrot = 0; + + if (abs(info->headZrot) > ANGLE(0.1f)) + info->headZrot += info->headZrot / -rate; + else + info->headZrot = 0; + + // Reset torso. + if (abs(info->torsoXrot) > ANGLE(0.1f)) + info->torsoXrot += info->torsoXrot / -rate; + else + info->torsoXrot = 0; + + if (abs(info->torsoYrot) > ANGLE(0.1f)) + info->torsoYrot += info->torsoYrot / -rate; + else + info->torsoYrot = 0; + + if (abs(info->torsoZrot) > ANGLE(0.1f)) + info->torsoZrot += info->torsoZrot / -rate; + else + info->torsoZrot = 0; +} + +void HandleLaraMovementParameters(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + // Reset running jump timer. + if (item->currentAnimState != LS_RUN_FORWARD && + item->currentAnimState != LS_WALK_FORWARD && + item->currentAnimState != LS_JUMP_FORWARD && + item->currentAnimState != LS_SPRINT && + item->currentAnimState != LS_SPRINT_DIVE) + { + info->jumpCount = 0; + } + + // Reset jump action queue. + if (item->currentAnimState != LS_RUN_FORWARD) + info->jumpQueued = false; + + // Increment/reset AFK pose timer. + if (info->poseCount < LARA_POSE_TIME && + TestLaraPose(item, coll) && + !(TrInput & (IN_WAKE | IN_LOOK)) && + g_GameFlow->Animations.Pose) + { + info->poseCount++; + } + else + info->poseCount = 0; + + // Reset lean. + if (!info->isMoving || (info->isMoving && !(TrInput & (IN_LEFT | IN_RIGHT)))) + { + if (abs(item->pos.zRot) > ANGLE(0.1f)) + item->pos.zRot += item->pos.zRot / -6; + else + item->pos.zRot = 0; + } + + // Reset crawl flex. + if (!(TrInput & IN_LOOK) && + coll->Setup.Height > LARA_HEIGHT - LARA_HEADROOM && + (!item->speed || (item->speed && !(TrInput & (IN_LEFT | IN_RIGHT))))) + { + ResetLaraFlex(item, 12); + } + + // Reset turn rate. + int sign = copysign(1, info->turnRate); + if (abs(info->turnRate) > ANGLE(2.0f)) + info->turnRate -= ANGLE(2.0f) * sign; + else if (abs(info->turnRate) > ANGLE(0.5f)) + info->turnRate -= ANGLE(0.5f) * sign; + else + info->turnRate = 0; + item->pos.yRot += info->turnRate; +} diff --git a/TR5Main/Game/Lara/lara_helpers.h b/TR5Main/Game/Lara/lara_helpers.h new file mode 100644 index 000000000..f7ba904d2 --- /dev/null +++ b/TR5Main/Game/Lara/lara_helpers.h @@ -0,0 +1,19 @@ +#pragma once + +struct ITEM_INFO; +struct COLL_INFO; + +// ----------------------------- +// HELPER FUNCTIONS +// For State Control & Collision +// ----------------------------- + +void DoLaraStep(ITEM_INFO* item, COLL_INFO* coll); +void DoLaraCrawlVault(ITEM_INFO* item, COLL_INFO* coll); +void DoLaraCrawlToHangSnap(ITEM_INFO* item, COLL_INFO* coll); +void DoLaraLean(ITEM_INFO* item, COLL_INFO* coll, int maxAngle, short rate); +void DoLaraCrawlFlex(ITEM_INFO* item, COLL_INFO* coll, short maxAngle, short rate); +void SetLaraFallState(ITEM_INFO* item); +void SetLaraFallBackState(ITEM_INFO* item); +void ResetLaraFlex(ITEM_INFO* item, float rate = 1.0f); +void HandleLaraMovementParameters(ITEM_INFO* item, COLL_INFO* coll); diff --git a/TR5Main/Game/Lara/lara_initialise.cpp b/TR5Main/Game/Lara/lara_initialise.cpp index 2c4500410..e01841a59 100644 --- a/TR5Main/Game/Lara/lara_initialise.cpp +++ b/TR5Main/Game/Lara/lara_initialise.cpp @@ -35,6 +35,7 @@ void InitialiseLara(int restore) Lara.look = true; Lara.itemNumber = itemNumber; Lara.hitDirection = -1; + Lara.sprintTimer = LARA_SPRINT_MAX; Lara.air = LARA_AIR_MAX; Lara.weaponItem = NO_ITEM; PoisonFlag = 0; @@ -60,7 +61,7 @@ void InitialiseLara(int restore) Lara.highestLocation = -1; Lara.ropePtr = -1; LaraItem->hitPoints = LARA_HEALTH_MAX; - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; LARA_WEAPON_TYPE gun = WEAPON_NONE; @@ -98,7 +99,6 @@ void InitialiseLara(int restore) InitialiseLaraAnims(LaraItem); Lara.BeetleLife = 3; - Lara.sprintTimer = LARA_SPRINT_MAX; } void LaraInitialiseMeshes() @@ -126,7 +126,7 @@ void LaraInitialiseMeshes() Lara.holsterInfo.backHolster = HOLSTER_SLOT::Empty; } - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; Lara.leftArm.frameNumber = 0; Lara.rightArm.frameNumber = 0; Lara.target = NULL; diff --git a/TR5Main/Game/Lara/lara_jump.cpp b/TR5Main/Game/Lara/lara_jump.cpp new file mode 100644 index 000000000..2857fb496 --- /dev/null +++ b/TR5Main/Game/Lara/lara_jump.cpp @@ -0,0 +1,657 @@ +#include "framework.h" +#include "control.h" +#include "input.h" +#include "level.h" +#include "setup.h" +#include "sound.h" +#include "camera.h" +#include "lara.h" +#include "lara_collide.h" +#include "lara_tests.h" +#include "lara_helpers.h" +#include "lara_jump.h" +#include "lara_basic.h" +#include "lara_slide.h" +#include "Scripting/GameFlowScript.h" + +// ----------------------------- +// JUMP +// Control & Collision Functions +// ----------------------------- + +void lara_as_forwardjump(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + // Update running jump counter in preparation for possible dispatch soon after landing. + info->jumpCount++; + if (info->jumpCount > LARA_JUMP_TIME / 2) + info->jumpCount = LARA_JUMP_TIME / 2; + + /*state 3*/ + /*collision: */ + if (item->goalAnimState == LS_SWANDIVE_START || + item->goalAnimState == LS_REACH) + item->goalAnimState = LS_JUMP_FORWARD; + + if (item->goalAnimState != LS_DEATH && + item->goalAnimState != LS_IDLE && + item->goalAnimState != LS_RUN_FORWARD) + { + if (info->gunStatus == LG_HANDS_FREE && TrInput & IN_ACTION) + item->goalAnimState = LS_REACH; + + if (TrInput & IN_BACK || TrInput & IN_ROLL) + item->goalAnimState = LS_JUMP_ROLL_180; + + if (info->gunStatus == LG_HANDS_FREE && TrInput & IN_WALK) + item->goalAnimState = LS_SWANDIVE_START; + + if (item->fallspeed > LARA_FREEFALL_SPEED) + item->goalAnimState = LS_FREEFALL; + } + + if (TrInput & IN_LEFT) + { + info->turnRate -= LARA_TURN_RATE; + if (info->turnRate < -LARA_JUMP_TURN_MAX) + info->turnRate = -LARA_JUMP_TURN_MAX; + } + else if (TrInput & IN_RIGHT) + { + info->turnRate += LARA_TURN_RATE; + if (info->turnRate > LARA_JUMP_TURN_MAX) + info->turnRate = LARA_JUMP_TURN_MAX; + } +} + +void lara_col_forwardjump(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + /*state 3*/ + /*state code: lara_as_forwardjump*/ + if (item->speed < 0) + info->moveAngle = item->pos.yRot + ANGLE(180); + else + info->moveAngle = item->pos.yRot; + + coll->Setup.BadHeightDown = NO_BAD_POS; + coll->Setup.BadHeightUp = -STEPUP_HEIGHT; + coll->Setup.BadCeilingHeight = BAD_JUMP_CEILING; + + coll->Setup.ForwardAngle = info->moveAngle; + GetCollisionInfo(coll, item); + LaraDeflectEdgeJump(item, coll); + + if (item->speed < 0) + info->moveAngle = item->pos.yRot; + + if (item->fallspeed > 0 && (coll->Middle.Floor <= 0 || TestLaraSwamp(item))) + { + if (LaraLandedBad(item, coll)) + item->goalAnimState = LS_DEATH; + else + { + if (info->waterStatus == LW_WADE) + item->goalAnimState = LS_IDLE; + else + { + if (TrInput & IN_FORWARD && !(TrInput & IN_WALK)) + SetAnimation(item, LA_LAND_TO_RUN); + else + item->goalAnimState = LS_IDLE; + } + } + + item->gravityStatus = false; + item->fallspeed = 0; + item->speed = 0; + + LaraSnapToHeight(item, coll); + } +} + +void lara_as_fastfall(ITEM_INFO* item, COLL_INFO* coll) +{ + /*state 9*/ + /*collision: lara_col_fastfall*/ + item->speed = (item->speed * 95) / 100; + if (item->fallspeed == 154) + SoundEffect(SFX_TR4_LARA_FALL, &item->pos, 0); +} + +void lara_col_fastfall(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + /*state 9*/ + /*state code: lara_as_fastfall*/ + item->gravityStatus = true; + + coll->Setup.BadHeightDown = NO_BAD_POS; + coll->Setup.BadHeightUp = -STEPUP_HEIGHT; + coll->Setup.BadCeilingHeight = BAD_JUMP_CEILING; + + coll->Setup.ForwardAngle = info->moveAngle; + GetCollisionInfo(coll, item); + LaraSlideEdgeJump(item, coll); + + if (coll->Middle.Floor <= 0 || TestLaraSwamp(item)) + { + if (LaraLandedBad(item, coll)) + item->goalAnimState = LS_DEATH; + else + SetAnimation(item, LA_FREEFALL_LAND); + + StopSoundEffect(SFX_TR4_LARA_FALL); + + item->fallspeed = 0; + item->gravityStatus = false; + + LaraSnapToHeight(item, coll); + } +} + +void lara_as_reach(ITEM_INFO* item, COLL_INFO* coll) +{ + /*state 11*/ + /*collision: lara_col_reach*/ + Camera.targetAngle = ANGLE(85.0f); + if (item->fallspeed > LARA_FREEFALL_SPEED) + item->goalAnimState = LS_FREEFALL; +} + +void lara_col_reach(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + /*state 11*/ + /*state code: lara_as_reach*/ + if (info->ropePtr == -1) + item->gravityStatus = true; + + info->moveAngle = item->pos.yRot; + + coll->Setup.Height = LARA_HEIGHT_STRETCH; + coll->Setup.BadHeightDown = NO_BAD_POS; + coll->Setup.BadHeightUp = 0; + coll->Setup.BadCeilingHeight = BAD_JUMP_CEILING; + coll->Setup.ForwardAngle = info->moveAngle; + coll->Setup.Radius = coll->Setup.Radius * 1.2f; + coll->Setup.Mode = COLL_PROBE_MODE::FREE_FORWARD; + + GetCollisionInfo(coll, item); + + if (TestLaraHangJump(item, coll)) + return; + + LaraSlideEdgeJump(item, coll); + coll->Setup.ForwardAngle = info->moveAngle; + GetCollisionInfo(coll, item); + ShiftItem(item, coll); + + if (item->fallspeed > 0 && coll->Middle.Floor <= 0) + { + if (LaraLandedBad(item, coll)) + { + item->goalAnimState = LS_DEATH; + } + else + { + item->goalAnimState = LS_IDLE; + item->fallspeed = 0; + item->gravityStatus = false; + if (coll->Middle.Floor != NO_HEIGHT) + item->pos.yPos += coll->Middle.Floor; + } + } +} + +void lara_col_land(ITEM_INFO* item, COLL_INFO* coll) +{ + /*state 14*/ + /*state code: lara_void_func*/ + lara_col_idle(item, coll); +} + +// State: LS_JUMP_PREPARE (15) +// Collision: lara_col_compress() +void lara_as_compress(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + // TODO: dispatch + /*if (item->hitPoints <= 0) + { + item->goalAnimState = LS_DEATH; + + return; + }*/ + + if (info->waterStatus == LW_WADE) + { + item->goalAnimState = LS_JUMP_UP; + + return; + } + + if (TrInput & IN_LEFT && + TrInput & (IN_FORWARD | IN_BACK)) + { + info->turnRate -= LARA_TURN_RATE; + if (info->turnRate < -LARA_SLOW_TURN_MAX) + info->turnRate = -LARA_SLOW_TURN_MAX; + } + else if (TrInput & IN_RIGHT && + TrInput & (IN_FORWARD | IN_BACK)) + { + info->turnRate += LARA_TURN_RATE; + if (info->turnRate > LARA_SLOW_TURN_MAX) + info->turnRate = LARA_SLOW_TURN_MAX; + } + + if (TrInput & IN_FORWARD && + TestLaraStandingJump(item, coll, item->pos.yRot)) + { + info->moveAngle = item->pos.yRot; + item->goalAnimState = LS_JUMP_FORWARD; + + return; + } + else if (TrInput & IN_BACK && + TestLaraStandingJump(item, coll, item->pos.yRot + ANGLE(180.0f))) + { + info->moveAngle = item->pos.yRot + ANGLE(180.0f); + item->goalAnimState = LS_JUMP_BACK; + + return; + } + + if (TrInput & IN_LEFT && + TestLaraStandingJump(item, coll, item->pos.yRot - ANGLE(90.0f))) + { + info->moveAngle = item->pos.yRot - ANGLE(90.0f); + item->goalAnimState = LS_JUMP_LEFT; + + return; + } + else if (TrInput & IN_RIGHT && + TestLaraStandingJump(item, coll, item->pos.yRot + ANGLE(90.0f))) + { + info->moveAngle = item->pos.yRot + ANGLE(90.0f); + item->goalAnimState = LS_JUMP_RIGHT; + + return; + } + + item->goalAnimState = LS_JUMP_UP; + + // TODO: What is this? @Sezz 2021.11.13 + if (item->fallspeed > LARA_FREEFALL_SPEED) + item->goalAnimState = LS_FREEFALL; +} + +// State: LS_JUMP_PREPARE (15) +// Collision: lara_as_compress() +void lara_col_compress(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + item->fallspeed = 0; + item->gravityStatus = false; + coll->Setup.BadHeightDown = NO_BAD_POS; + coll->Setup.BadHeightUp = NO_HEIGHT; + coll->Setup.BadCeilingHeight = 0; + coll->Setup.ForwardAngle = info->moveAngle; + GetCollisionInfo(coll, item); + + if (TestLaraFall(item, coll)) + { + SetLaraFallState(item); + + return; + } + + if (TestLaraSlide(item, coll)) + return; + + // TODO: Better handling. + if (coll->Middle.Ceiling > -100) + { + SetAnimation(item, LA_STAND_SOLID); + item->speed = 0; + item->fallspeed = 0; + item->gravityStatus = false; + + item->pos.xPos = coll->Setup.OldPosition.x; + item->pos.yPos = coll->Setup.OldPosition.y; + item->pos.zPos = coll->Setup.OldPosition.z; + } + + if (coll->Middle.Floor > -STEP_SIZE && coll->Middle.Floor < STEP_SIZE) + item->pos.yPos += coll->Middle.Floor; +} + +void lara_as_backjump(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + /*state 25*/ + /*collision: lara_col_backjump*/ + info->look = false; + + Camera.targetAngle = ANGLE(135.0f); + if (item->fallspeed <= LARA_FREEFALL_SPEED) + { + if (item->goalAnimState == LS_RUN_FORWARD) + { + item->goalAnimState = LS_IDLE; + } + else if ((TrInput & IN_FORWARD || TrInput & IN_ROLL) && item->goalAnimState != LS_IDLE) + { + item->goalAnimState = LS_JUMP_ROLL_180; + } + } + else + { + item->goalAnimState = LS_FREEFALL; + } +} + +void lara_col_backjump(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + /*state 25*/ + /*state code: lara_as_backjump*/ + info->moveAngle = item->pos.yRot + ANGLE(180); + LaraJumpCollision(item, coll); +} + +void lara_as_rightjump(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + /*state 26*/ + /*collision: lara_col_rightjump*/ + info->look = false; + if (item->fallspeed > LARA_FREEFALL_SPEED) + item->goalAnimState = LS_FREEFALL; + else if (TrInput & IN_LEFT && item->goalAnimState != LS_IDLE) + item->goalAnimState = LS_JUMP_ROLL_180; +} + +void lara_col_rightjump(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + /*state 26*/ + /*state code: lara_as_rightjump*/ + info->moveAngle = item->pos.yRot + ANGLE(90); + LaraJumpCollision(item, coll); +} + +void lara_as_leftjump(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + /*state 27*/ + /*collision: lara_col_leftjump*/ + info->look = false; + if (item->fallspeed > LARA_FREEFALL_SPEED) + item->goalAnimState = LS_FREEFALL; + else if (TrInput & IN_RIGHT && item->goalAnimState != LS_IDLE) + item->goalAnimState = LS_JUMP_ROLL_180; +} + +void lara_col_leftjump(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + /*state 27*/ + /*state code: lara_as_leftjump*/ + info->moveAngle = item->pos.yRot - ANGLE(90); + LaraJumpCollision(item, coll); +} + +void lara_as_upjump(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + info->look = false; + + /*state 28*/ + /*collision: lara_col_upjump*/ + if (item->fallspeed > LARA_FREEFALL_SPEED) + { + item->goalAnimState = LS_FREEFALL; + } +} + +void lara_col_upjump(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + /*state 28*/ + /*state code: lara_as_upjump*/ + if (item->hitPoints <= 0) + { + item->goalAnimState = LS_IDLE; + return; + } + + info->moveAngle = item->pos.yRot; + + coll->Setup.Height = LARA_HEIGHT_STRETCH; + coll->Setup.BadHeightDown = NO_BAD_POS; + coll->Setup.BadHeightUp = -STEPUP_HEIGHT; + coll->Setup.BadCeilingHeight = BAD_JUMP_CEILING; + coll->Setup.ForwardAngle = item->speed < 0 ? info->moveAngle + ANGLE(180.0f) : info->moveAngle; + coll->Setup.Mode = COLL_PROBE_MODE::FREE_FORWARD; + + GetCollisionInfo(coll, item); + + if (TestLaraHangJumpUp(item, coll)) + return; + + if (coll->CollisionType == CT_CLAMP || + coll->CollisionType == CT_TOP || + coll->CollisionType == CT_TOP_FRONT) + item->fallspeed = 1; + + ShiftItem(item, coll); + + if (coll->CollisionType == 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->Middle.Floor <= 0) + { + item->goalAnimState = LaraLandedBad(item, coll) ? LS_DEATH : LS_IDLE; + + item->gravityStatus = false; + item->fallspeed = 0; + + if (coll->Middle.Floor != NO_HEIGHT) + item->pos.yPos += coll->Middle.Floor; + } +} + +void lara_as_fallback(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + /*state 29*/ + /*collision: lara_col_fallback*/ + if (item->fallspeed > LARA_FREEFALL_SPEED) + item->goalAnimState = LS_FREEFALL; + + if (TrInput & IN_ACTION) + if (info->gunStatus == LG_HANDS_FREE) + item->goalAnimState = LS_REACH; +} + +void lara_col_fallback(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + /*state 29*/ + /*state code: lara_as_fallback*/ + info->moveAngle = item->pos.yRot + ANGLE(180); + + coll->Setup.BadHeightDown = NO_BAD_POS; + coll->Setup.BadHeightUp = -STEPUP_HEIGHT; + coll->Setup.BadCeilingHeight = BAD_JUMP_CEILING; + + coll->Setup.ForwardAngle = info->moveAngle; + GetCollisionInfo(coll, item); + LaraDeflectEdgeJump(item, coll); + + if (item->fallspeed > 0 && (coll->Middle.Floor <= 0 || TestLaraSwamp(item))) + { + if (LaraLandedBad(item, coll)) + item->goalAnimState = LS_DEATH; + else + item->goalAnimState = LS_IDLE; + + LaraResetGravityStatus(item, coll); + LaraSnapToHeight(item, coll); + } +} + +// State: LS_SWANDIVE_START (52) +// Control: lara_col_swandive() +void lara_as_swandive(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + info->gunStatus = LG_HANDS_BUSY; + info->look = false; + coll->Setup.EnableObjectPush = true; + coll->Setup.EnableSpaz = false; + + if (TrInput & IN_LEFT) + { + info->turnRate -= LARA_TURN_RATE; + if (info->turnRate < -LARA_JUMP_TURN_MAX) + info->turnRate = -LARA_JUMP_TURN_MAX; + + DoLaraLean(item, coll, -LARA_LEAN_MAX, LARA_LEAN_RATE / 2); + } + else if (TrInput & IN_RIGHT) + { + info->turnRate += LARA_TURN_RATE; + if (info->turnRate > LARA_JUMP_TURN_MAX) + info->turnRate = LARA_JUMP_TURN_MAX; + + DoLaraLean(item, coll, LARA_LEAN_MAX, LARA_LEAN_RATE / 2); + } + + // TODO: Why? + if (item->fallspeed > LARA_FREEFALL_SPEED && item->goalAnimState != LS_DIVE) + item->goalAnimState = LS_SWANDIVE_END; +} + +void lara_col_swandive(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + auto bounds = GetBoundsAccurate(item); + auto realHeight = bounds->Y2 - bounds->Y1; + + /*state 52*/ + /*state code: lara_as_swandive*/ + info->moveAngle = item->pos.yRot; + info->keepCrouched = TestLaraKeepCrouched(item, coll); + coll->Setup.Height = std::max(LARA_HEIGHT_CRAWL, (int)(realHeight * 0.7f)); + coll->Setup.BadHeightDown = NO_BAD_POS; + coll->Setup.BadHeightUp = -STEPUP_HEIGHT; + coll->Setup.BadCeilingHeight = BAD_JUMP_CEILING; + coll->Setup.ForwardAngle = info->moveAngle; + GetCollisionInfo(coll, item); + + if (LaraDeflectEdgeJump(item, coll)) + info->gunStatus = LG_HANDS_FREE; + + if (coll->Middle.Floor <= 0 && item->fallspeed > 0) + { + auto probe = GetCollisionResult(item, coll->Setup.ForwardAngle, coll->Setup.Radius, 0); + + if (TestLaraSlide(item, coll)) + ; + else if (info->keepCrouched || + abs(probe.Position.Ceiling - probe.Position.Floor) < LARA_HEIGHT && + g_GameFlow->Animations.CrawlspaceSwandive) + { + SetAnimation(item, LA_SPRINT_TO_CROUCH_LEFT, 10); + + if (!info->keepCrouched) // HACK: If Lara landed on the edge, shift forward to avoid standing up or falling out. + MoveItem(item, coll->Setup.ForwardAngle, STEP_SIZE / 2); + } + else [[likely]] + SetAnimation(item, LA_SWANDIVE_ROLL, 0); + + item->fallspeed = 0; + item->gravityStatus = false; + info->gunStatus = LG_HANDS_FREE; + + LaraSnapToHeight(item, coll); + } +} + +void lara_as_fastdive(ITEM_INFO* item, COLL_INFO* coll) +{ + /*state 53*/ + /*collision: lara_col_fastdive*/ + if (TrInput & IN_ROLL && item->goalAnimState == LS_SWANDIVE_END) + item->goalAnimState = LS_JUMP_ROLL_180; + coll->Setup.EnableObjectPush = true; + coll->Setup.EnableSpaz = false; + item->speed = (item->speed * 95) / 100; +} + +void lara_col_fastdive(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + /*state 53*/ + /*state code: lara_as_fastdive*/ + info->moveAngle = item->pos.yRot; + + coll->Setup.BadHeightDown = NO_BAD_POS; + coll->Setup.BadHeightUp = -STEPUP_HEIGHT; + coll->Setup.BadCeilingHeight = BAD_JUMP_CEILING; + + coll->Setup.ForwardAngle = info->moveAngle; + GetCollisionInfo(coll, item); + LaraDeflectEdgeJump(item, coll); + + if (coll->Middle.Floor <= 0 && item->fallspeed > 0) + { + if (item->fallspeed <= 133) + item->goalAnimState = LS_IDLE; + else + item->goalAnimState = LS_DEATH; + + item->fallspeed = 0; + item->gravityStatus = 0; + + if (coll->Middle.Floor != NO_HEIGHT) + item->pos.yPos += coll->Middle.Floor; + } +} diff --git a/TR5Main/Game/Lara/lara_jump.h b/TR5Main/Game/Lara/lara_jump.h new file mode 100644 index 000000000..dc33a3d1e --- /dev/null +++ b/TR5Main/Game/Lara/lara_jump.h @@ -0,0 +1,33 @@ +#pragma once + +struct ITEM_INFO; +struct COLL_INFO; + +// ----------------------------- +// JUMP +// Control & Collision Functions +// ----------------------------- + +void lara_as_forwardjump(ITEM_INFO* item, COLL_INFO* coll); +void lara_col_forwardjump(ITEM_INFO* item, COLL_INFO* coll); +void lara_as_fastfall(ITEM_INFO* item, COLL_INFO* coll); +void lara_col_fastfall(ITEM_INFO* item, COLL_INFO* coll); +void lara_as_reach(ITEM_INFO* item, COLL_INFO* coll); +void lara_col_reach(ITEM_INFO* item, COLL_INFO* coll); +void lara_col_land(ITEM_INFO* item, COLL_INFO* coll); +void lara_as_compress(ITEM_INFO* item, COLL_INFO* coll); +void lara_col_compress(ITEM_INFO* item, COLL_INFO* coll); +void lara_as_backjump(ITEM_INFO* item, COLL_INFO* coll); +void lara_col_backjump(ITEM_INFO* item, COLL_INFO* coll); +void lara_as_rightjump(ITEM_INFO* item, COLL_INFO* coll); +void lara_col_rightjump(ITEM_INFO* item, COLL_INFO* coll); +void lara_as_leftjump(ITEM_INFO* item, COLL_INFO* coll); +void lara_col_leftjump(ITEM_INFO* item, COLL_INFO* coll); +void lara_as_upjump(ITEM_INFO* item, COLL_INFO* coll); +void lara_col_upjump(ITEM_INFO* item, COLL_INFO* coll); +void lara_as_fallback(ITEM_INFO* item, COLL_INFO* coll); +void lara_col_fallback(ITEM_INFO* item, COLL_INFO* coll); +void lara_as_swandive(ITEM_INFO* item, COLL_INFO* coll); +void lara_col_swandive(ITEM_INFO* item, COLL_INFO* coll); +void lara_as_fastdive(ITEM_INFO* item, COLL_INFO* coll); +void lara_col_fastdive(ITEM_INFO* item, COLL_INFO* coll); diff --git a/TR5Main/Game/Lara/lara_monkey.cpp b/TR5Main/Game/Lara/lara_monkey.cpp index 8d94311f5..cb534952d 100644 --- a/TR5Main/Game/Lara/lara_monkey.cpp +++ b/TR5Main/Game/Lara/lara_monkey.cpp @@ -23,7 +23,7 @@ void lara_as_monkey_idle(ITEM_INFO* item, COLL_INFO* coll) /*collision: lara_col_hang2*/ if (item->hitPoints <= 0) { - item->goalAnimState = LS_STOP; + item->goalAnimState = LS_IDLE; return; } @@ -90,7 +90,7 @@ void lara_col_monkey_idle(ITEM_INFO* item, COLL_INFO* coll) { item->goalAnimState = LS_MONKEYSWING_TURN_RIGHT; } - else if (TrInput & IN_ROLL && g_GameFlow->Animations.MonkeyRoll) + else if (TrInput & IN_ROLL && g_GameFlow->Animations.MonkeyTurn180) { item->goalAnimState = LS_MONKEYSWING_TURN_180; } @@ -530,6 +530,6 @@ void MonkeySwingFall(ITEM_INFO* item) item->fallspeed = 1; item->pos.yPos += 256; - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; } } diff --git a/TR5Main/Game/Lara/lara_objects.cpp b/TR5Main/Game/Lara/lara_objects.cpp index e97f00b6e..2cc047bd0 100644 --- a/TR5Main/Game/Lara/lara_objects.cpp +++ b/TR5Main/Game/Lara/lara_objects.cpp @@ -1,5 +1,6 @@ #include "framework.h" #include "lara.h" +#include "lara_tests.h" #include "input.h" #include "level.h" #include "Sound/sound.h" @@ -54,7 +55,7 @@ void lara_as_pickupflare(ITEM_INFO* item, COLL_INFO* coll) Camera.targetDistance = WALL_SIZE; if (item->frameNumber == g_Level.Anims[item->animNumber].frameEnd - 1) - info->gunStatus = LG_NO_ARMS; + info->gunStatus = LG_HANDS_FREE; } // ------ @@ -94,7 +95,7 @@ void lara_as_switchoff(ITEM_INFO* item, COLL_INFO* coll) void lara_col_turnswitch(ITEM_INFO* item, COLL_INFO* coll) { /*state 95*/ - /*state code: lara_as_controlledl*/ + /*state code: lara_as_controlled_no_look*/ if (coll->Setup.OldPosition.x != item->pos.xPos || coll->Setup.OldPosition.z != item->pos.zPos) { if (item->animNumber == LA_TURNSWITCH_PUSH_COUNTER_CLOCKWISE_CONTINUE) @@ -200,7 +201,7 @@ void lara_as_ppready(ITEM_INFO* item, COLL_INFO* coll) Camera.targetAngle = ANGLE(75.0f); if (!(TrInput & IN_ACTION)) - item->goalAnimState = LS_STOP; + item->goalAnimState = LS_IDLE; } // ------ @@ -222,7 +223,7 @@ void lara_as_pulley(ITEM_INFO* item, COLL_INFO* coll) if (TrInput & IN_ACTION && pulley->triggerFlags) item->goalAnimState = LS_PULLEY; else - item->goalAnimState = LS_STOP; + item->goalAnimState = LS_IDLE; if (item->animNumber == LA_PULLEY_PULL && item->frameNumber == g_Level.Anims[item->animNumber].frameBase + 44) @@ -257,7 +258,7 @@ void lara_as_pulley(ITEM_INFO* item, COLL_INFO* coll) if (item->animNumber == LA_PULLEY_RELEASE && item->frameNumber == g_Level.Anims[item->animNumber].frameEnd - 1) { - info->gunStatus = LG_NO_ARMS; + info->gunStatus = LG_HANDS_FREE; } } @@ -773,24 +774,6 @@ void lara_as_climbroped(ITEM_INFO* item, COLL_INFO* coll) // VERTICAL POLE // ------------- -// TODO: Move test functions to lara_tests.cpp when lara_state_cleaning_etc branch is merged. -bool TestLaraPoleUp(ITEM_INFO* item, COLL_INFO* coll) -{ - if (!TestLaraPoleCollision(item, coll, true, STEP_SIZE)) - return false; - - // TODO: Accuracy. - return (coll->Middle.Ceiling < -STEP_SIZE); -} - -bool TestLaraPoleDown(ITEM_INFO* item, COLL_INFO* coll) -{ - if (!TestLaraPoleCollision(item, coll, false)) - return false; - - return (coll->Middle.Floor > 0); -} - // State: LS_POLE_IDLE (99) // Collision: lara_col_pole_idle() void lara_as_pole_idle(ITEM_INFO* item, COLL_INFO* coll) @@ -815,15 +798,15 @@ void lara_as_pole_idle(ITEM_INFO* item, COLL_INFO* coll) { if (TrInput & IN_LEFT) { - info->turnRate += LARA_TURN_RATE; - if (info->turnRate > LARA_SLOW_TURN) - info->turnRate = LARA_SLOW_TURN; + info->turnRate += LARA_POLE_TURN_RATE; + if (info->turnRate > LARA_POLE_TURN_MAX) + info->turnRate = LARA_POLE_TURN_MAX; } else if (TrInput & IN_RIGHT) { - info->turnRate -= LARA_TURN_RATE; - if (info->turnRate < -LARA_SLOW_TURN) - info->turnRate = -LARA_SLOW_TURN; + info->turnRate -= LARA_POLE_TURN_RATE; + if (info->turnRate < -LARA_POLE_TURN_MAX) + info->turnRate = -LARA_POLE_TURN_MAX; } } @@ -831,7 +814,6 @@ void lara_as_pole_idle(ITEM_INFO* item, COLL_INFO* coll) if (TrInput & IN_JUMP) { item->goalAnimState = LS_JUMP_BACK; - info->gunStatus = LG_NO_ARMS; return; } @@ -842,8 +824,8 @@ void lara_as_pole_idle(ITEM_INFO* item, COLL_INFO* coll) } else if (TrInput & IN_BACK && TestLaraPoleDown(item, coll)) { - item->itemFlags[2] = 0; // Doesn't seem necessary? item->goalAnimState = LS_POLE_DOWN; + item->itemFlags[2] = 0; // Doesn't seem necessary? return; } @@ -862,18 +844,21 @@ void lara_as_pole_idle(ITEM_INFO* item, COLL_INFO* coll) return; } - info->gunStatus = LG_NO_ARMS; - - if (coll->Middle.Floor <= 0) + GetCollisionInfo(coll, item); // HACK: Lara may step off poles in mid-air upon reload without this. + if (coll->Middle.Floor <= 0 && + item->animNumber != LA_POLE_JUMP_BACK) // Hack. { - item->goalAnimState = LS_STOP; + item->goalAnimState = LS_IDLE; return; } + else if (item->animNumber == LA_POLE_IDLE) + { + item->goalAnimState = LS_FREEFALL; - // TODO: This should not be required. Update anim's root displacement + set position distance. - //item->pos.xPos -= phd_sin(item->pos.yRot) * 64; - //item->pos.zPos -= phd_cos(item->pos.yRot) * 64; - item->goalAnimState = LS_FREEFALL; + // TODO: This shouldn't be required, but the set position command doesn't move Lara correctly. + item->pos.xPos -= phd_sin(item->pos.yRot) * 64; + item->pos.zPos -= phd_cos(item->pos.yRot) * 64; + } } // State: LS_POLE_IDLE (99) @@ -891,6 +876,7 @@ void lara_col_pole_idle(ITEM_INFO* item, COLL_INFO* coll) coll->Setup.SlopesAreWalls = true; GetCollisionInfo(coll, item); + // TODO: There's a visible snap if Lara hits the ground at a high velocity. if (coll->Middle.Floor < 0) item->pos.yPos += coll->Middle.Floor; } @@ -914,15 +900,21 @@ void lara_as_pole_up(ITEM_INFO* item, COLL_INFO* coll) { if (TrInput & IN_LEFT) { - info->turnRate += LARA_TURN_RATE; - if (info->turnRate > LARA_SLOW_TURN) - info->turnRate = LARA_SLOW_TURN; + info->turnRate += LARA_POLE_TURN_RATE; + if (info->turnRate > LARA_POLE_TURN_MAX) + info->turnRate = LARA_POLE_TURN_MAX; } else if (TrInput & IN_RIGHT) { - info->turnRate -= LARA_TURN_RATE; - if (info->turnRate < -LARA_SLOW_TURN) - info->turnRate = -LARA_SLOW_TURN; + info->turnRate -= LARA_POLE_TURN_RATE; + if (info->turnRate < -LARA_POLE_TURN_MAX) + info->turnRate = -LARA_POLE_TURN_MAX; + } + + if (TrInput & IN_JUMP) + { + item->goalAnimState = LS_POLE_IDLE; + return; } if (TrInput & IN_FORWARD && TestLaraPoleUp(item, coll)) @@ -936,7 +928,6 @@ void lara_as_pole_up(ITEM_INFO* item, COLL_INFO* coll) } item->goalAnimState = LS_POLE_IDLE; // TODO: Dispatch to freefall? - } // State: LS_POLE_UP (100) @@ -968,15 +959,21 @@ void lara_as_pole_down(ITEM_INFO* item, COLL_INFO* coll) { if (TrInput & IN_LEFT) { - info->turnRate += LARA_TURN_RATE; - if (info->turnRate > LARA_SLOW_TURN) - info->turnRate = LARA_SLOW_TURN; + info->turnRate += LARA_POLE_TURN_RATE; + if (info->turnRate > LARA_POLE_TURN_MAX) + info->turnRate = LARA_POLE_TURN_MAX; } else if (TrInput & IN_RIGHT) { - info->turnRate -= LARA_TURN_RATE; - if (info->turnRate < -LARA_SLOW_TURN) - info->turnRate = -LARA_SLOW_TURN; + info->turnRate -= LARA_POLE_TURN_RATE; + if (info->turnRate < -LARA_POLE_TURN_MAX) + info->turnRate = -LARA_POLE_TURN_MAX; + } + + if (TrInput & IN_JUMP) + { + item->goalAnimState = LS_POLE_IDLE; + return; } if (TrInput & IN_BACK && TestLaraPoleDown(item, coll)) @@ -985,9 +982,8 @@ void lara_as_pole_down(ITEM_INFO* item, COLL_INFO* coll) return; } - item->itemFlags[2] = 0; // ?? + item->itemFlags[2] = 0; // Vertical velocity. item->goalAnimState = LS_POLE_IDLE; - return; } @@ -1061,9 +1057,9 @@ void lara_as_pole_turn_clockwise(ITEM_INFO* item, COLL_INFO* coll) if (TrInput & IN_LEFT) { - info->turnRate += LARA_TURN_RATE; - if (info->turnRate > LARA_SLOW_TURN + ANGLE(0.5f)) - info->turnRate = LARA_SLOW_TURN + ANGLE(0.5f); + info->turnRate += LARA_POLE_TURN_RATE; + if (info->turnRate > LARA_POLE_TURN_MAX) + info->turnRate = LARA_POLE_TURN_MAX; item->goalAnimState = LS_POLE_TURN_CLOCKWISE; return; @@ -1095,7 +1091,6 @@ void lara_as_pole_turn_counter_clockwise(ITEM_INFO* item, COLL_INFO* coll) if (item->hitPoints <= 0) { item->goalAnimState = LS_POLE_IDLE; // TODO: Death state dispatch. - return; } @@ -1117,9 +1112,9 @@ void lara_as_pole_turn_counter_clockwise(ITEM_INFO* item, COLL_INFO* coll) if (TrInput & IN_RIGHT) { - info->turnRate -= LARA_TURN_RATE; - if (info->turnRate < -(LARA_SLOW_TURN + ANGLE(0.5f))) - info->turnRate = -(LARA_SLOW_TURN + ANGLE(0.5f)); + info->turnRate -= LARA_POLE_TURN_RATE; + if (info->turnRate < -LARA_POLE_TURN_MAX) + info->turnRate = -LARA_POLE_TURN_MAX; item->goalAnimState = LS_POLE_TURN_COUNTER_CLOCKWISE; return; diff --git a/TR5Main/Game/Lara/lara_one_gun.cpp b/TR5Main/Game/Lara/lara_one_gun.cpp index c59693e75..c548433c6 100644 --- a/TR5Main/Game/Lara/lara_one_gun.cpp +++ b/TR5Main/Game/Lara/lara_one_gun.cpp @@ -1817,7 +1817,7 @@ void undraw_shotgun(int weapon) if (item->status == ITEM_DEACTIVATED) { - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; Lara.target = nullptr; Lara.rightArm.lock = false; Lara.leftArm.lock = false; diff --git a/TR5Main/Game/Lara/lara_slide.cpp b/TR5Main/Game/Lara/lara_slide.cpp index c7d33c65e..a7b11f2b8 100644 --- a/TR5Main/Game/Lara/lara_slide.cpp +++ b/TR5Main/Game/Lara/lara_slide.cpp @@ -20,6 +20,14 @@ void lara_slide_slope(ITEM_INFO* item, COLL_INFO* coll) coll->Setup.ForwardAngle = Lara.moveAngle; GetCollisionInfo(coll, item); + // Temporary measure. @Sezz 2021.12.16 + if (TestLaraSwamp(item)) + { + item->goalAnimState = LS_IDLE; + StopSoundEffect(SFX_TR4_LARA_SLIPPING); + return; + } + if (!LaraHitCeiling(item, coll)) { LaraDeflectEdge(item, coll); @@ -37,7 +45,7 @@ void lara_slide_slope(ITEM_INFO* item, COLL_INFO* coll) item->goalAnimState = LS_RUN_FORWARD; } else - item->goalAnimState = LS_STOP; + item->goalAnimState = LS_IDLE; StopSoundEffect(SFX_TR4_LARA_SLIPPING); } diff --git a/TR5Main/Game/Lara/lara_struct.h b/TR5Main/Game/Lara/lara_struct.h index 5d02e9490..d7b20024d 100644 --- a/TR5Main/Game/Lara/lara_struct.h +++ b/TR5Main/Game/Lara/lara_struct.h @@ -19,17 +19,16 @@ namespace TEN::Renderer { struct RendererMesh; } - #pragma region state_and_animation enum LARA_STATE { // TR1 LS_WALK_FORWARD = 0, LS_RUN_FORWARD = 1, - LS_STOP = 2, + LS_IDLE = 2, LS_JUMP_FORWARD = 3, LS_POSE = 4, - LS_HOP_BACK = 5, + LS_RUN_BACK = 5, LS_TURN_RIGHT_SLOW = 6, LS_TURN_LEFT_SLOW = 7, LS_DEATH = 8, @@ -44,7 +43,7 @@ enum LARA_STATE LS_UNDERWATER_FORWARD = 17, LS_UNDERWATER_INERTIA = 18, LS_GRABBING = 19, - LS_TURN_FAST = 20, + LS_TURN_RIGHT_FAST = 20, LS_STEP_RIGHT = 21, LS_STEP_LEFT = 22, LS_ROLL_BACK = 23, @@ -102,7 +101,7 @@ enum LARA_STATE LS_CROUCH_IDLE = 71, LS_CROUCH_ROLL = 72, LS_SPRINT = 73, - LS_SPRINT_ROLL = 74, + LS_SPRINT_DIVE = 74, LS_MONKEYSWING_IDLE = 75, LS_MONKEYSWING_FORWARD = 76, LS_MONKEYSWING_LEFT = 77, @@ -173,9 +172,9 @@ enum LARA_STATE LS_LADDER_TO_CROUCH = 138, // TombEngine - LS_SHIMMY_45_OUTER_LEFT = 139, + LS_SHIMMY_45_OUTER_LEFT = 139, LS_SHIMMY_45_OUTER_RIGHT = 140, - LS_SHIMMY_45_INNER_LEFT = 141, + LS_SHIMMY_45_INNER_LEFT = 141, LS_SHIMMY_45_INNER_RIGHT = 142, LS_UNUSED1 = 143, // Foot hang leftovers - may be safely reused LS_UNUSED2 = 144, // Foot hang leftovers - may be safely reused @@ -183,11 +182,18 @@ enum LARA_STATE LS_COGWHEEL_UNGRAB = 146, LS_STEP_UP = 147, LS_STEP_DOWN = 148, - LS_STEP_BACK_DOWN = 149, + LS_UNUSED4 = 149, // Vestige of step back down; a new state can be added in its place. LS_LADDER_DISMOUNT_LEFT = 150, LS_LADDER_DISMOUNT_RIGHT = 151, - + LS_TURN_LEFT_FAST = 152, + LS_CRAWL_EXIT_DOWN_STEP = 153, + LS_CRAWL_EXIT_JUMP = 154, + LS_CRAWL_EXIT_FLIP = 155, + NUM_LARA_STATES + + // TRASHED STATES (please reuse slots before going any higher and remove entries from this list as you go): + // 143, 144, 145, 149 }; enum LARA_ANIM @@ -205,7 +211,7 @@ enum LARA_ANIM LA_RUN_TO_WALK_LEFT = 9, // Run > walk, right foot first LA_RUN_TO_STAND_RIGHT = 10, // Run > stand, right foot first LA_STAND_SOLID = 11, // Stand solid - // TODO: gradually remove reliance on this anim for erroneous collisions. + // TODO: gradually reduce reliance on this anim for erroneous collisions. LA_TURN_RIGHT_SLOW = 12, // Rotate right slowly LA_TURN_LEFT_SLOW = 13, // Rotate left slowly LA_JUMP_FORWARD_LAND_START_UNUSED = 14, // Forward jump > land (1/2) @@ -243,7 +249,6 @@ enum LARA_ANIM // TODO: implement properly. LA_TURN_RIGHT_FAST = 44, // Rotate right quickly LA_JUMP_FORWARD_TO_FREEFALL_OG = 45, // Jump forward > fall - // TODO: this is the original, but incorrect, linking animation; in WAD should be 49 instead. LA_REACH_TO_FREEFALL_ALTERNATE_UNUSED = 46, // Reach > freefall LA_ROLL_180_START_ALTERNATE_UNUSED = 47, // Standing roll 180 (1/2) LA_ROLL_180_END_ALTERNATE_UNUSED = 48, // Standing roll 180 (2/2) @@ -361,7 +366,7 @@ enum LARA_ANIM LA_SWANDIVE_RIGHT_START = 157, // Run > swan dive, right foot first LA_SWANDIVE = 158, // Swan dive LA_HANG_HANDSTAND = 159, // Hang > stand via handstand - + // TR2 LA_STAND_TO_LADDER = 160, // Stand > ladder idle LA_LADDER_UP = 161, // Ascend ladder (looped) @@ -424,70 +429,66 @@ enum LARA_ANIM LA_ZIPLINE_MOUNT = 214, // Stand > ride sipline LA_ZIPLINE_RIDE = 215, // Ride zipline (looped) LA_ZIPLINE_DISMOUNT = 216, // Ride zipline > jump forward - + // TR3 - LA_STAND_TO_CROUCH_START = 217, // Stand > crouch (1/2) - LA_CROUCH_ROLL_FORWARD_START_ALTERNATE = 218, // Crouch roll forward (1/3) - // TODO: this is the original, but incorrect, linking animation; in WAD it should be 47 instead. - LA_CROUCH_ROLL_FORWARD_CONTINUE = 219, // Crouch roll forward (2/3) - LA_CROUCH_ROLL_FORWARD_END = 220, // Crouch roll forward (3/3) - LA_CROUCH_TO_STAND = 221, // Crouch > stand - LA_CROUCH_IDLE = 222, // Crouch (looped) - LA_SPRINT = 223, // Sprint (looped) - LA_RUN_TO_SPRINT_LEFT = 224, // Run > sprint, left foot first - LA_RUN_TO_SPRINT_RIGHT = 225, // Run > sprint, right foot first - LA_SPRINT_TO_STAND_RIGHT = 226, // Sprint > stand, right foot first - LA_SPRINT_TO_STAND_RIGHT_END_ALTERNATE_UNUSED = 227, // Sprint > stand, right foot first end - LA_SPRINT_TO_STAND_LEFT = 228, // Sprint > stand, left foot first - LA_SPRINT_TO_STAND_LEFT_END_ALTERNATE_UNUSED = 229, // Sprint > stand, left foot first end - LA_SPRINT_ROLL_TO_RUN_LEFT_START = 230, // Sprint roll, left foot first > run (1/2) + LA_STAND_TO_CROUCH_START = 217, // Stand > crouch (1/2) + LA_CROUCH_ROLL_FORWARD_START_ALTERNATE = 218, // Crouch roll forward (1/3) + LA_CROUCH_ROLL_FORWARD_CONTINUE = 219, // Crouch roll forward (2/3) + LA_CROUCH_ROLL_FORWARD_END = 220, // Crouch roll forward (3/3) + LA_CROUCH_TO_STAND = 221, // Crouch > stand + LA_CROUCH_IDLE = 222, // Crouch (looped) + LA_SPRINT = 223, // Sprint (looped) + LA_RUN_TO_SPRINT_LEFT = 224, // Run > sprint, left foot first + LA_RUN_TO_SPRINT_RIGHT = 225, // Run > sprint, right foot first + LA_SPRINT_TO_STAND_RIGHT = 226, // Sprint > stand, right foot first + LA_SPRINT_TO_STAND_RIGHT_END_ALTERNATE_UNUSED = 227, // Sprint > stand, right foot first end + LA_SPRINT_TO_STAND_LEFT = 228, // Sprint > stand, left foot first + LA_SPRINT_TO_STAND_LEFT_END_ALTERNATE_UNUSED = 229, // Sprint > stand, left foot first end + LA_SPRINT_ROLL_TO_RUN_LEFT_START = 230, // Sprint roll, left foot first > run (1/2) LA_SPRINT_ROLL_TO_RUN_RIGHT_CONTINUE_ALTERNATE_UNUSED = 231, // Sprint roll, left foot first > run (2/3) - LA_SPRINT_ROLL_TO_RUN_LEFT_END = 232, // Sprint roll, left foot first > run (2/2) - LA_JUMP_UP_TO_MONKEYSWING = 233, // Jump up > monkey swing - LA_MONKEYSWING_IDLE = 234, // Monkey swing idle (looped) - LA_MONKEYSWING_TO_FREEFALL = 235, // Monkey swing > freefall - LA_MONKEYSWING_FORWARD = 236, // Monkey swing forward (looped) - LA_MONKEYSWING_FORWARD_TO_IDLE_RIGHT = 237, // Monkey-swing forward > monkey swing idle, right hand first - LA_MONKEYSWING_FORWARD_TO_IDLE_LEFT = 238, // Monkey-swing forward > monkey swing idle, left hand first - LA_MONKEYSWING_IDLE_TO_FORWARD_LEFT = 239, // Monkey idle > monkey forward, left hand first - LA_SPRINT_ROLL_TO_RUN_LEFT_START_ALTERNATE_UNUSED = 240, // Sprint roll, left foot first > run (1/3) - LA_SPRINT_ROLL_TO_RUN_LEFT_CONTINUE_ALTERNATE_UNUSED = 241, // Sprint roll, left foot first > run (2/3) - LA_SPRINT_ROLL_TO_RUN_LEFT_END_ALTERNATE_UNUSED = 242, // Sprint roll, left foot first > run (3/3) - LA_SPRINT_TO_RUN_LEFT = 243, // Sprint > run, left foot first - LA_SPRINT_TO_RUN_RIGHT = 244, // Sprint > run, right foot first - LA_STAND_TO_CROUCH_END = 245, // Stand > crouch (2/2) - LA_SLIDE_TO_RUN = 246, // Slide forward > run - LA_CROUCH_ROLL_FORWARD_START = 247, // Crouch roll forward (1/3) - LA_JUMP_FORWARD_TO_REACH_1 = 248, // Jump forward > reach, 1st opportunity - LA_JUMP_FORWARD_TO_REACH_2 = 249, // Jump forward > reach, 2nd opportunity - LA_RUN_JUMP_LEFT_TO_REACH = 251, // Run jump, left foot first > reach - LA_MONKEYSWING_IDLE_TO_FORWARD_RIGHT = 252, // Monkey swing idle > monkey swing forward, right hand first - LA_MONKEYSWING_SHIMMY_LEFT = 253, // Monkey swing shimmy left (looped) - LA_MONKEYSWING_SHIMMY_LEFT_END = 254, // Monkey swing shimmy left > monkey swing idle - LA_MONKEYSWING_SHIMMY_RIGHT = 255, // Monkey swing shimmy right (looped) - LA_MONKEYSWING_SHIMMY_RIGHT_END = 256, // Monkey swing shimmy right > monkey swing idle - // TODO: generic shimmy anims between ledges and ladders? + LA_SPRINT_ROLL_TO_RUN_LEFT_END = 232, // Sprint roll, left foot first > run (2/2) + LA_JUMP_UP_TO_MONKEYSWING = 233, // Jump up > monkey swing + LA_MONKEYSWING_IDLE = 234, // Monkey swing idle (looped) + LA_MONKEYSWING_TO_FREEFALL = 235, // Monkey swing > freefall + LA_MONKEYSWING_FORWARD = 236, // Monkey swing forward (looped) + LA_MONKEYSWING_FORWARD_TO_IDLE_RIGHT = 237, // Monkey-swing forward > monkey swing idle, right hand first + LA_MONKEYSWING_FORWARD_TO_IDLE_LEFT = 238, // Monkey-swing forward > monkey swing idle, left hand first + LA_MONKEYSWING_IDLE_TO_FORWARD_LEFT = 239, // Monkey idle > monkey forward, left hand first + LA_SPRINT_ROLL_TO_RUN_LEFT_START_ALTERNATE_UNUSED = 240, // Sprint roll, left foot first > run (1/3) + LA_SPRINT_ROLL_TO_RUN_LEFT_CONTINUE_ALTERNATE_UNUSED = 241, // Sprint roll, left foot first > run (2/3) + LA_SPRINT_ROLL_TO_RUN_LEFT_END_ALTERNATE_UNUSED = 242, // Sprint roll, left foot first > run (3/3) + LA_SPRINT_TO_RUN_LEFT = 243, // Sprint > run, left foot first + LA_SPRINT_TO_RUN_RIGHT = 244, // Sprint > run, right foot first + LA_STAND_TO_CROUCH_END = 245, // Stand > crouch (2/2) + LA_SLIDE_TO_RUN = 246, // Slide forward > run + LA_CROUCH_ROLL_FORWARD_START = 247, // Crouch roll forward (1/3) + LA_JUMP_FORWARD_TO_REACH_1 = 248, // Jump forward > reach, 1st opportunity + LA_JUMP_FORWARD_TO_REACH_2 = 249, // Jump forward > reach, 2nd opportunity + LA_RUN_JUMP_LEFT_TO_REACH = 251, // Run jump, left foot first > reach + LA_MONKEYSWING_IDLE_TO_FORWARD_RIGHT = 252, // Monkey swing idle > monkey swing forward, right hand first + LA_MONKEYSWING_SHIMMY_LEFT = 253, // Monkey swing shimmy left (looped) + LA_MONKEYSWING_SHIMMY_LEFT_END = 254, // Monkey swing shimmy left > monkey swing idle + LA_MONKEYSWING_SHIMMY_RIGHT = 255, // Monkey swing shimmy right (looped) + LA_MONKEYSWING_SHIMMY_RIGHT_END = 256, // Monkey swing shimmy right > monkey swing idle + // TODO: generic shimmy anims between ledges and ladders? LA_MONKEYSWING_TURN_180 = 257, // Monkey swing turn 180 LA_CROUCH_TO_CRAWL_START = 258, // Crouch > crawl (1/3) LA_CRAWL_TO_CROUCH_START = 259, // Crawl > crouch (1/3) LA_CRAWL = 260, // Crawl forward (looped) LA_CRAWL_IDLE_TO_FORWARD = 261, // Crawl idle > crawl forward LA_CRAWL_TO_IDLE_LEFT = 262, // Crawl forward > crawl idle, left leg first - // TODO: in WAD, link next to 263 LA_CRAWL_IDLE = 263, // Crwal idle LA_CROUCH_TO_CRAWL_END = 264, // Crawl > crouch (2/2) LA_CRAWL_TO_CROUCH_END_UNUSED = 265, // Crouch > crawl (3/3) - LA_CRAWL_TO_IDLE_END_RIGHT_POINTLESS = 266, // TODO: remove.//no dont remove thanks + LA_CRAWL_TO_IDLE_END_RIGHT_POINTLESS = 266, // TODO: remove. LA_CRAWL_TO_IDLE_RIGHT = 267, // Crawl forward > crawl idle, right leg first - // TODO: in WAD, link next to 263 - LA_CRAWL_TO_IDLE_END_LEFT_POINTLESS = 268, // TODO: remove. //no dont remove thanks + LA_CRAWL_TO_IDLE_END_LEFT_POINTLESS = 268, // TODO: remove. LA_CRAWL_TURN_LEFT = 269, // Crawl rotate left (looped) LA_CRAWL_TURN_RIGHT = 270, // Crawl rotate right (looped) LA_MONKEYSWING_TURN_LEFT = 271, // Monkey swing rotate left LA_MONKEYSWING_TURN_RIGHT = 272, // Monkey swing rotate right LA_CROUCH_TO_CRAWL_CONTINUE = 273, // Crouch > crawl (2/3) LA_CRAWL_TO_CROUCH_CONTINUE = 274, // Crouch > crawl (2/3) - // TODO: properly link to 265 (adjustments to next anim necessary?) LA_CRAWL_IDLE_TO_CRAWL_BACK = 275, // Crawl > crawl back LA_CRAWL_BACK = 276, // Crawl back (looped) LA_CRAWL_BACK_TO_IDLE_RIGHT_START = 277, // Crawl back > crawl idle, right foot first (1/2) @@ -518,7 +519,6 @@ enum LARA_ANIM LA_CRAWL_DEATH = 301, // Crawl death LA_CRAWL_TO_HANG_END = 302, // Crawl > hang (3/3) LA_STAND_TO_CROUCH_ABORT = 303, // Stand > crouch abort - // TODO: implement this, OR the ability for any animation to be wound back like pistol aiming. LA_RUN_TO_CROUCH_LEFT_START = 304, // Run > crouch, left foot first (1/2) LA_RUN_TO_CROUCH_RIGHT_START = 305, // Run > crouch, right foot first (1/2) LA_RUN_TO_CROUCH_LEFT_END = 306, // Run > crouch, left foot first (2/2) @@ -711,17 +711,17 @@ enum LARA_ANIM LA_ONWATER_TO_CROUCH_1CLICK = 481, // Pull up 1-click from tread > stand LA_ONWATER_TO_CROUCH_0CLICK = 482, // Pull up 0-click from tread > stand LA_ONWATER_TO_CROUCH_M1CLICK = 483, // Pull up -1-click from tread > stand - LA_UNUSED1 = 484, // Foot hang leftovers - may be safely reused - LA_UNUSED2 = 485, // Foot hang leftovers - may be safely reused - LA_UNUSED3 = 486, // Foot hang leftovers - may be safely reused - LA_UNUSED4 = 487, // Foot hang leftovers - may be safely reused - LA_UNUSED5 = 488, // Foot hang leftovers - may be safely reused - LA_UNUSED6 = 489, // Foot hang leftovers - may be safely reused - LA_UNUSED7 = 490, // Foot hang leftovers - may be safely reused - LA_UNUSED8 = 491, // Foot hang leftovers - may be safely reused - LA_UNUSED9 = 492, // Foot hang leftovers - may be safely reused - LA_UNUSED10 = 493, // Foot hang leftovers - may be safely reused - LA_UNUSED11 = 494, // Foot hang leftovers - may be safely reused + LA_UNUSED1 = 484, // Foot hang leftovers - may be safely reused + LA_UNUSED2 = 485, // Foot hang leftovers - may be safely reused + LA_UNUSED3 = 486, // Foot hang leftovers - may be safely reused + LA_UNUSED4 = 487, // Foot hang leftovers - may be safely reused + LA_UNUSED5 = 488, // Foot hang leftovers - may be safely reused + LA_UNUSED6 = 489, // Foot hang leftovers - may be safely reused + LA_UNUSED7 = 490, // Foot hang leftovers - may be safely reused + LA_UNUSED8 = 491, // Foot hang leftovers - may be safely reused + LA_UNUSED9 = 492, // Foot hang leftovers - may be safely reused + LA_UNUSED10 = 493, // Foot hang leftovers - may be safely reused + LA_UNUSED11 = 494, // Foot hang leftovers - may be safely reused LA_REACH_TO_HANG_OSCILLATE = 495, // Reach > hang, thin ledge LA_SWANDIVE_ROLL_TO_RUN = 496, // Swandive roll > run LA_LADDER_DISMOUNT_LEFT_START = 497, // Ladder dismount left (1/2) @@ -729,8 +729,17 @@ enum LARA_ANIM LA_LADDER_DISMOUNT_RIGHT_START = 499, // Ladder dismount right (1/2) LA_LADDER_DISMOUNT_RIGHT_END = 500, // Ladder dismount right (2/2) LA_ONWATER_TO_LADDER = 501, // Tread water > climb to ladder idle + LA_POSE_START = 502, // Stand > AFK pose + LA_POSE_CONTINUE = 503, // AFK pose (looped) + LA_POSE_END = 504, // AFK pose > stand NUM_LARA_ANIMS + + // TRASHED ANIMS (please reuse slots before going any higher and remove entries from this list as you go): + // 45, + // 245, 265, 266, 268, 273, 274, 278, 280, + // 364, 366, 368, 370, + // 484, 485, 486, 487, 488, 499, 490, 491, 492, 493, 494 }; #pragma endregion @@ -745,7 +754,7 @@ enum LARA_WATER_STATUS enum LARA_GUN_STATUS { - LG_NO_ARMS, + LG_HANDS_FREE, LG_HANDS_BUSY, LG_DRAW_GUNS, LG_UNDRAW_GUNS, @@ -967,26 +976,6 @@ struct LARA_ARM short flash_gun; }; -struct AnimsNew -{ - bool CrouchRoll; // crouch roll - bool Monkey180Roll; // the 180 degrees roll on monkeybars - bool Crawl1clickup; // going 1 click up in crawlspaces - bool Crawl1clickdown; // going 1 click down in crawlspaces - bool CrawlExit1click; // crawlspace exit at 1 click - bool CrawlExit2click; // crawlspace exit at 2 clicks - bool CrawlExit3click; // crawlspace exit at 3 clicks - bool CrawlVault1click; // vault into crawlspace at 1 click - bool CrawlVault2click; // vault into crawlspace at 2 clicks - bool CrawlVault3click; // vault into crawlspace at 3 clicks - bool MonkeyVault; // vault up to monkeybars when pressing up + action underneath them. super annoying :) - bool CrawlExitJump; // TR5 crawlspace exit with jump! - bool SwandiveRollRun; // the transition from swandive roll to run - bool OscillateHanging; // the thin ledge grab animation from TR1 and 2 - bool CrawlFlexWaterPullUp; - bool CrawlFlexSubmerged; -}; - #ifdef NEW_TIGHTROPE struct LaraTightrope { @@ -1008,6 +997,8 @@ struct LaraInfo LARA_WATER_STATUS waterStatus; // LW_enum short climbStatus; short poseCount; + int jumpCount; + bool jumpQueued; short hitFrame; short hitDirection; int sprintTimer; @@ -1029,7 +1020,7 @@ struct LaraInfo bool flareControlLeft; bool look; bool burn; - bool keepDucked; + bool keepCrouched; bool isMoving; bool canMonkeySwing; byte burnBlue; diff --git a/TR5Main/Game/Lara/lara_swim.cpp b/TR5Main/Game/Lara/lara_swim.cpp index 33edad637..ffa54515c 100644 --- a/TR5Main/Game/Lara/lara_swim.cpp +++ b/TR5Main/Game/Lara/lara_swim.cpp @@ -1,4 +1,5 @@ #include "framework.h" +#include "lara_helpers.h" #include "lara_swim.h" #include "control/control.h" #include "camera.h" @@ -107,6 +108,7 @@ void lara_as_tread(ITEM_INFO* item, COLL_INFO* coll) if (TrInput & IN_ROLL && level->LaraType != LaraType::Divesuit) { SetAnimation(item, LA_UNDERWATER_ROLL_180_START); + return; } @@ -116,7 +118,7 @@ void lara_as_tread(ITEM_INFO* item, COLL_INFO* coll) if (level->LaraType == LaraType::Divesuit) SwimTurnSubsuit(item); else - SwimTurn(item); + SwimTurn(item, coll); if (TrInput & IN_JUMP) item->goalAnimState = LS_UNDERWATER_FORWARD; @@ -127,7 +129,7 @@ void lara_as_tread(ITEM_INFO* item, COLL_INFO* coll) item->fallspeed = 0; if (Lara.gunStatus == LG_HANDS_BUSY) - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; } void lara_as_glide(ITEM_INFO* item, COLL_INFO* coll) @@ -143,11 +145,12 @@ void lara_as_glide(ITEM_INFO* item, COLL_INFO* coll) if (TrInput & IN_ROLL && level->LaraType != LaraType::Divesuit) { SetAnimation(item, LA_UNDERWATER_ROLL_180_START); + return; } if (level->LaraType != LaraType::Divesuit) - SwimTurn(item); + SwimTurn(item, coll); else SwimTurnSubsuit(item); @@ -175,11 +178,12 @@ void lara_as_swim(ITEM_INFO* item, COLL_INFO* coll) if (TrInput & IN_ROLL && level->LaraType != LaraType::Divesuit) { SetAnimation(item, LA_UNDERWATER_ROLL_180_START); + return; } if (level->LaraType != LaraType::Divesuit) - SwimTurn(item); + SwimTurn(item, coll); else SwimTurnSubsuit(item); @@ -275,23 +279,23 @@ void SwimTurnSubsuit(ITEM_INFO* item) if (TrInput & IN_LEFT) { - Lara.turnRate -= SUB_SUIT_TURN_RATE; - if (Lara.turnRate < -LARA_MED_TURN) - Lara.turnRate = -LARA_MED_TURN; + Lara.turnRate -= LARA_SUBSUIT_TURN_RATE; + if (Lara.turnRate < -LARA_MED_TURN_MAX) + Lara.turnRate = -LARA_MED_TURN_MAX; - item->pos.zRot -= LARA_LEAN_RATE * 2; + item->pos.zRot -= LARA_LEAN_RATE; } else if (TrInput & IN_RIGHT) { - Lara.turnRate += SUB_SUIT_TURN_RATE; - if (Lara.turnRate > LARA_MED_TURN) - Lara.turnRate = LARA_MED_TURN; + Lara.turnRate += LARA_SUBSUIT_TURN_RATE; + if (Lara.turnRate > LARA_MED_TURN_MAX) + Lara.turnRate = LARA_MED_TURN_MAX; - item->pos.zRot += LARA_LEAN_RATE * 2; + item->pos.zRot += LARA_LEAN_RATE; } } -void SwimTurn(ITEM_INFO* item) +void SwimTurn(ITEM_INFO* item, COLL_INFO* coll) { if (TrInput & IN_FORWARD) item->pos.xRot -= ANGLE(2.0f); @@ -301,18 +305,18 @@ void SwimTurn(ITEM_INFO* item) if (TrInput & IN_LEFT) { Lara.turnRate -= LARA_TURN_RATE; - if (Lara.turnRate < -LARA_MED_TURN) - Lara.turnRate = -LARA_MED_TURN; + if (Lara.turnRate < -LARA_MED_TURN_MAX) + Lara.turnRate = -LARA_MED_TURN_MAX; - item->pos.zRot -= LARA_LEAN_RATE * 2; + item->pos.zRot -= LARA_LEAN_RATE; } else if (TrInput & IN_RIGHT) { Lara.turnRate += LARA_TURN_RATE; - if (Lara.turnRate > LARA_MED_TURN) - Lara.turnRate = LARA_MED_TURN; + if (Lara.turnRate > LARA_MED_TURN_MAX) + Lara.turnRate = LARA_MED_TURN_MAX; - item->pos.zRot += LARA_LEAN_RATE * 2; + item->pos.zRot += LARA_LEAN_RATE; } } diff --git a/TR5Main/Game/Lara/lara_swim.h b/TR5Main/Game/Lara/lara_swim.h index 4f481a055..c6f998491 100644 --- a/TR5Main/Game/Lara/lara_swim.h +++ b/TR5Main/Game/Lara/lara_swim.h @@ -15,6 +15,6 @@ void lara_as_glide(ITEM_INFO* item, COLL_INFO* coll); void lara_as_swim(ITEM_INFO* item, COLL_INFO* coll); void UpdateSubsuitAngles(); void SwimTurnSubsuit(ITEM_INFO* item); -void SwimTurn(ITEM_INFO* item); +void SwimTurn(ITEM_INFO* item, COLL_INFO* coll); void SwimDive(ITEM_INFO* item); -void LaraWaterCurrent(COLL_INFO* coll); \ No newline at end of file +void LaraWaterCurrent(COLL_INFO* coll); diff --git a/TR5Main/Game/Lara/lara_tests.cpp b/TR5Main/Game/Lara/lara_tests.cpp index 525c50ded..696549d94 100644 --- a/TR5Main/Game/Lara/lara_tests.cpp +++ b/TR5Main/Game/Lara/lara_tests.cpp @@ -5,8 +5,10 @@ #include "level.h" #include "animation.h" #include "lara_climb.h" +#include "lara_helpers.h" #include "lara_monkey.h" #include "lara_collide.h" +#include "lara_flare.h" #include "control/control.h" #include "control/los.h" #include "items.h" @@ -16,7 +18,10 @@ using namespace TEN::Renderer; using namespace TEN::Floordata; -/*this file has all the generic test functions called in lara's state code*/ +// ----------------------------- +// TEST FUNCTIONS +// For State Control & Collision +// ----------------------------- // Test if a ledge in front of item is valid to climb. bool TestValidLedge(ITEM_INFO* item, COLL_INFO* coll, bool ignoreHeadroom, bool heightLimit) @@ -55,7 +60,7 @@ bool TestValidLedge(ITEM_INFO* item, COLL_INFO* coll, bool ignoreHeadroom, bool auto right = GetCollisionResult(item->pos.xPos + xf + xr, y, item->pos.zPos + zf + zr, GetRoom(item->location, item->pos.xPos, y, item->pos.zPos).roomNumber).Position.Floor; // If specified, limit vertical search zone only to nearest height - if (heightLimit && (abs(left - y) > (STEP_SIZE / 2) || abs(right - y) > (STEP_SIZE / 2))) + if (heightLimit && (abs(left - y) > CLICK(0.5f) || abs(right - y) > CLICK(0.5f))) return false; // Determine allowed slope difference for a given collision radius @@ -76,7 +81,7 @@ bool TestValidLedge(ITEM_INFO* item, COLL_INFO* coll, bool ignoreHeadroom, bool if (!ignoreHeadroom) { auto headroom = (coll->Front.Floor + coll->Setup.Height) - coll->Middle.Ceiling; - if (headroom < STEP_SIZE) + if (headroom < CLICK(1)) return false; } @@ -85,91 +90,109 @@ bool TestValidLedge(ITEM_INFO* item, COLL_INFO* coll, bool ignoreHeadroom, bool bool TestValidLedgeAngle(ITEM_INFO* item, COLL_INFO* coll) { - return (abs((short) (coll->NearestLedgeAngle - item->pos.yRot)) <= LARA_GRAB_THRESHOLD); + return abs((short) (coll->NearestLedgeAngle - item->pos.yRot)) <= LARA_GRAB_THRESHOLD; } bool TestLaraVault(ITEM_INFO* item, COLL_INFO* coll) { - if (!(TrInput & IN_ACTION) || Lara.gunStatus != LG_NO_ARMS) + LaraInfo*& info = item->data; + + if (!(TrInput & IN_ACTION) || info->gunStatus != LG_HANDS_FREE) return false; - if (TestLaraSwamp(item) && Lara.waterSurfaceDist < -(STOP_SIZE + STEP_SIZE)) + if (TestLaraSwamp(item) && info->waterSurfaceDist < -CLICK(3)) return false; if (TestValidLedge(item, coll)) { bool success = false; - if (coll->Front.Floor < 0 && coll->Front.Floor >= -CLICK(1)) + // Vault to crouch up one step. + if (coll->Front.Floor < 0 && // Lower floor bound. + coll->Front.Floor > -STEPUP_HEIGHT && // Upper floor bound. + g_GameFlow->Animations.CrawlExtended) { - if (g_GameFlow->Animations.CrawlExtra && (abs(coll->Front.Ceiling - coll->Front.Floor) < CLICK(1))) + if (abs((coll->Front.Ceiling - coll->Setup.Height) - coll->Front.Floor) > LARA_HEIGHT_CRAWL) // Front clamp buffer. Presumably, nothing more is necessary, but tend to this in the future. @Sezz 2021.11.06 { item->animNumber = LA_VAULT_TO_CROUCH_1CLICK; item->currentAnimState = LS_GRABBING; - item->frameNumber = g_Level.Anims[item->animNumber].frameBase; + item->frameNumber = GetFrameNumber(item, 0); item->goalAnimState = LS_CROUCH_IDLE; item->pos.yPos += coll->Front.Floor + CLICK(1); - Lara.gunStatus = LG_HANDS_BUSY; + info->gunStatus = LG_HANDS_BUSY; success = true; } } - else if (coll->Front.Floor >= -CLICK(2.5f) && coll->Front.Floor <= -CLICK(1.5f)) + // Vault up two steps. + else if (coll->Front.Floor <= -STEPUP_HEIGHT && // Lower floor bound. + coll->Front.Floor >= -CLICK(2.5f)) // Upper floor bound. { - if (coll->Front.Floor - coll->Front.Ceiling >= 0 && - coll->FrontLeft.Floor - coll->FrontLeft.Ceiling >= 0 && - coll->FrontRight.Floor - coll->FrontRight.Ceiling >= 0) + // Vault to stand up two steps. + if (abs((coll->Front.Ceiling - coll->Setup.Height) - coll->Front.Floor) > LARA_HEIGHT) // Front clamp buffer. BUG: Turned away from the ledge and toward a section with a low ceiling, stand-to-crawl vault will be performed instead. @Sezz 2021.11.06 { item->animNumber = LA_VAULT_TO_STAND_2CLICK_START; item->currentAnimState = LS_GRABBING; - item->frameNumber = g_Level.Anims[item->animNumber].frameBase; - item->goalAnimState = LS_STOP; + item->frameNumber = GetFrameNumber(item, 0); + item->goalAnimState = LS_IDLE; item->pos.yPos += coll->Front.Floor + CLICK(2); - Lara.gunStatus = LG_HANDS_BUSY; + info->gunStatus = LG_HANDS_BUSY; success = true; } - else if (g_GameFlow->Animations.CrawlExtra && (abs(coll->Front.Ceiling - coll->Front.Floor) < CLICK(1))) + // Vault to crouch up two steps. + else if (abs((coll->Front.Ceiling - coll->Setup.Height) - coll->Front.Floor) > LARA_HEIGHT_CRAWL && // Front clamp buffer. + abs((coll->FrontLeft.Ceiling - coll->Setup.Height) - coll->FrontLeft.Floor) > LARA_HEIGHT_CRAWL && // Left clamp buffer. + abs((coll->FrontRight.Ceiling - coll->Setup.Height) - coll->FrontRight.Floor) > LARA_HEIGHT_CRAWL && // Right clamp buffer. + g_GameFlow->Animations.CrawlExtended) { item->animNumber = LA_VAULT_TO_CROUCH_2CLICK; - item->frameNumber = g_Level.Anims[item->animNumber].frameBase; + item->frameNumber = GetFrameNumber(item, 0); item->currentAnimState = LS_GRABBING; item->goalAnimState = LS_CROUCH_IDLE; item->pos.yPos += coll->Front.Floor + CLICK(2); - Lara.gunStatus = LG_HANDS_BUSY; + info->gunStatus = LG_HANDS_BUSY; success = true; } } - else if (coll->Front.Floor >= -CLICK(3.5f) && coll->Front.Floor <= -CLICK(2.5f)) + // Vault up three steps. + else if (coll->Front.Floor <= -CLICK(2.5f) && // Lower floor bound. + coll->Front.Floor >= -CLICK(3.5f)) // Upper floor bound. { - if (coll->Front.Floor - coll->Front.Ceiling >= 0 && - coll->FrontLeft.Floor - coll->FrontLeft.Ceiling >= 0 && - coll->FrontRight.Floor - coll->FrontRight.Ceiling >= 0) + // Vault to stand up three steps. + if (abs((coll->Front.Ceiling - coll->Setup.Height) - coll->Front.Floor) > LARA_HEIGHT) // Front clamp buffer. BUG: Turned away from the ledge and toward a section with a low ceiling, stand-to-crawl vault will be performed instead. @Sezz 2021.11.06 { item->animNumber = LA_VAULT_TO_STAND_3CLICK; item->currentAnimState = LS_GRABBING; - item->frameNumber = g_Level.Anims[item->animNumber].frameBase; - item->goalAnimState = LS_STOP; + item->frameNumber = GetFrameNumber(item, 0); + item->goalAnimState = LS_IDLE; item->pos.yPos += coll->Front.Floor + CLICK(3); - Lara.gunStatus = LG_HANDS_BUSY; + info->gunStatus = LG_HANDS_BUSY; success = true; } - else if (g_GameFlow->Animations.CrawlExtra && (abs(coll->Front.Ceiling - coll->Front.Floor) < CLICK(1))) + // Vault to crouch up three steps. + else if (abs((coll->Front.Ceiling - coll->Setup.Height) - coll->Front.Floor) > LARA_HEIGHT_CRAWL && // Front clamp buffer. + abs((coll->FrontLeft.Ceiling - coll->Setup.Height) - coll->FrontLeft.Floor) > LARA_HEIGHT_CRAWL && // Left clamp buffer. + abs((coll->FrontRight.Ceiling - coll->Setup.Height) - coll->FrontRight.Floor) > LARA_HEIGHT_CRAWL && // Right clamp buffer. + g_GameFlow->Animations.CrawlExtended) { item->animNumber = LA_VAULT_TO_CROUCH_3CLICK; - item->frameNumber = g_Level.Anims[item->animNumber].frameBase; + item->frameNumber = GetFrameNumber(item, 0); item->currentAnimState = LS_GRABBING; item->goalAnimState = LS_CROUCH_IDLE; item->pos.yPos += coll->Front.Floor + CLICK(3); - Lara.gunStatus = LG_HANDS_BUSY; + info->gunStatus = LG_HANDS_BUSY; success = true; } } - else if (coll->Front.Floor >= -CLICK(7.5f) && coll->Front.Floor <= -CLICK(3.5f)) + // Auto jump. + else if (coll->Front.Floor >= -CLICK(7.5f) && // Upper floor bound. + coll->Front.Floor <= -CLICK(3.5f) && // Lower floor bound. + !TestLaraSwamp(item)) { item->animNumber = LA_STAND_SOLID; - item->frameNumber = g_Level.Anims[item->animNumber].frameBase; + item->frameNumber = GetFrameNumber(item, 0); item->goalAnimState = LS_JUMP_UP; - item->currentAnimState = LS_STOP; - Lara.calcFallSpeed = -3 - sqrt(-9600 - 12 * coll->Front.Floor); + item->currentAnimState = LS_IDLE; + info->calcFallSpeed = -3 - sqrt(-9600 - 12 * coll->Front.Floor); AnimateLara(item); success = true; } @@ -181,20 +204,26 @@ bool TestLaraVault(ITEM_INFO* item, COLL_INFO* coll) } } - if (TestValidLedgeAngle(item, coll) && Lara.climbStatus) + // Begin ladder climb. + if (info->climbStatus && TestValidLedgeAngle(item, coll)) { - if (coll->Front.Floor > -CLICK(7.5f) || Lara.waterStatus == LW_WADE || coll->FrontLeft.Floor > -CLICK(7.5f) || coll->FrontRight.Floor > -CLICK(8) || coll->Middle.Ceiling > -1158) + if (coll->Front.Floor > -CLICK(7.5f) || // Upper front floor bound. + coll->FrontLeft.Floor > -CLICK(7.5f) || // Upper left floor bound. + coll->FrontRight.Floor > -CLICK(2) || // Upper right floor bound. + coll->Middle.Ceiling > -CLICK(4.5f) + 6 || // Upper ceiling bound. + info->waterStatus == LW_WADE) { - if ((coll->Front.Floor < -CLICK(4) || coll->Front.Ceiling >= 506) && coll->Middle.Ceiling <= -518) + if ((coll->Front.Floor < -WALL_SIZE || coll->Front.Ceiling >= (CLICK(2) - 6)) && + coll->Middle.Ceiling <= -(CLICK(2) + 6)) { if (TestLaraClimbStance(item, coll)) { item->animNumber = LA_STAND_SOLID; - item->frameNumber = g_Level.Anims[item->animNumber].frameBase; + item->frameNumber = GetFrameNumber(item, 0); item->goalAnimState = LS_LADDER_IDLE; - item->currentAnimState = LS_STOP; - Lara.gunStatus = LG_HANDS_BUSY; - Lara.turnRate = 0; + item->currentAnimState = LS_IDLE; + info->gunStatus = LG_HANDS_BUSY; + info->turnRate = 0; ShiftItem(item, coll); SnapItemToGrid(item, coll); // HACK: until fragile ladder code is refactored, we must exactly snap to grid. @@ -203,15 +232,17 @@ bool TestLaraVault(ITEM_INFO* item, COLL_INFO* coll) return true; } } + return false; } + // Auto jump to ladder. TODO: Check swamps. item->animNumber = LA_STAND_SOLID; - item->frameNumber = g_Level.Anims[item->animNumber].frameBase; + item->frameNumber = GetFrameNumber(item, 0); item->goalAnimState = LS_JUMP_UP; - item->currentAnimState = LS_STOP; - Lara.calcFallSpeed = -116; - Lara.turnRate = 0; + item->currentAnimState = LS_IDLE; + info->calcFallSpeed = -116; + info->turnRate = 0; ShiftItem(item, coll); SnapItemToGrid(item, coll); // HACK: until fragile ladder code is refactored, we must exactly snap to grid. @@ -220,17 +251,24 @@ bool TestLaraVault(ITEM_INFO* item, COLL_INFO* coll) return true; } - if (Lara.canMonkeySwing && g_GameFlow->Animations.MonkeyVault) + // Auto jump to monkey swing. + if (info->canMonkeySwing && + !TestLaraSwamp(item) && + g_GameFlow->Animations.MonkeyAutoJump) { short roomNum = item->roomNumber; int ceiling = (GetCeiling(GetFloor(item->pos.xPos, item->pos.yPos, item->pos.zPos, &roomNum), item->pos.xPos, item->pos.yPos, item->pos.zPos))-(item->pos.yPos); - if (ceiling > 1792 || ceiling < -1792 || abs(ceiling) == 768) + if (ceiling > CLICK(7) || + ceiling < -CLICK(7) || + abs(ceiling) == CLICK(3)) + { return false; + } item->animNumber = LA_STAND_IDLE; - item->frameNumber = g_Level.Anims[LA_STAND_IDLE].frameBase; + item->frameNumber = GetFrameNumber(item, 0); item->goalAnimState = LS_JUMP_UP; item->currentAnimState = LS_MONKEY_VAULT; @@ -240,13 +278,39 @@ bool TestLaraVault(ITEM_INFO* item, COLL_INFO* coll) return false; } -bool TestLaraStandUp(COLL_INFO* coll) +bool TestLaraKeepCrouched(ITEM_INFO* item, COLL_INFO* coll) { - return (coll->Middle.Ceiling >= -362); + // TODO: Temporary. coll->Setup.Radius is currently only set to + // LARA_RAD_CRAWL in the collision function, then reset by LaraAboveWater(). + // For tests called in control functions, then, it will store the wrong radius. @Sezz 2021.11.05 + auto radius = (item->currentAnimState == LS_CROUCH_IDLE || + item->currentAnimState == LS_CROUCH_TURN_LEFT || + item->currentAnimState == LS_CROUCH_TURN_RIGHT) + ? LARA_RAD : LARA_RAD_CRAWL; + + auto y = item->pos.yPos; + auto probeBack = GetCollisionResult(item, item->pos.yRot + ANGLE(180.0f), radius, 0); + + // TODO: Cannot use as a failsafe in standing states; bugged with slanted ceilings reaching the ground. + // In common setups, Lara may embed on such ceilings, resulting in inappropriate crouch state dispatches. + // A buffer might help, but improved collision handling would presumably eliminate this issue entirely. @Sezz 2021.10.15 + if ((coll->Middle.Ceiling - LARA_HEIGHT_CRAWL) >= -LARA_HEIGHT || // Middle is not a clamp. + (coll->Front.Ceiling - LARA_HEIGHT_CRAWL) >= -LARA_HEIGHT || // Front is not a clamp. + (probeBack.Position.Ceiling - y) >= -LARA_HEIGHT) // Back is not a clamp. + { + return true; + } + + return false; } bool TestLaraSlide(ITEM_INFO* item, COLL_INFO* coll) { + LaraInfo*& info = item->data; + + if (TestLaraSwamp(item)) + return false; + static short oldAngle = 1; if (abs(coll->TiltX) <= 2 && abs(coll->TiltZ) <= 2) @@ -284,12 +348,22 @@ bool TestLaraSlide(ITEM_INFO* item, COLL_INFO* coll) item->pos.yRot = angle; } - Lara.moveAngle = angle; + info->moveAngle = angle; oldAngle = angle; return true; } +bool TestLaraSwamp(ITEM_INFO* item) +{ + return (g_Level.Rooms[item->roomNumber].flags & ENV_FLAG_SWAMP); +} + +bool TestLaraWater(ITEM_INFO* item) +{ + return (g_Level.Rooms[item->roomNumber].flags & ENV_FLAG_WATER); +} + SPLAT_COLL TestLaraWall(ITEM_INFO* item, int front, int right, int down) { int x = item->pos.xPos; @@ -299,9 +373,6 @@ SPLAT_COLL TestLaraWall(ITEM_INFO* item, int front, int right, int down) short angle = GetQuadrant(item->pos.yRot); short roomNum = item->roomNumber; - FLOOR_INFO* floor; - int h, c; - switch (angle) { case NORTH: @@ -340,14 +411,14 @@ SPLAT_COLL TestLaraWall(ITEM_INFO* item, int front, int right, int down) break; } - floor = GetFloor(x, y, z, &roomNum); - h = GetFloorHeight(floor, x, y, z); - c = GetCeiling(floor, x, y, z); + auto floor = GetFloor(x, y, z, &roomNum); + auto floorHeight = GetFloorHeight(floor, x, y, z); + auto ceilHeight = GetCeiling(floor, x, y, z); - if (h == NO_HEIGHT) + if (floorHeight == NO_HEIGHT) return SPLAT_COLL::WALL; - if (y >= h || y <= c) + if (y >= floorHeight || y <= ceilHeight) return SPLAT_COLL::STEP; return SPLAT_COLL::NONE; @@ -355,17 +426,19 @@ SPLAT_COLL TestLaraWall(ITEM_INFO* item, int front, int right, int down) bool TestLaraHangJumpUp(ITEM_INFO* item, COLL_INFO* coll) { - if (!(TrInput & IN_ACTION) || (Lara.gunStatus != LG_NO_ARMS) || (coll->HitStatic)) + LaraInfo*& info = item->data; + + if (!(TrInput & IN_ACTION) || (info->gunStatus != LG_HANDS_FREE) || (coll->HitStatic)) return false; - if (Lara.canMonkeySwing && coll->CollisionType == CT_TOP) + if (info->canMonkeySwing && coll->CollisionType == CT_TOP) { SetAnimation(item, LA_JUMP_UP_TO_MONKEYSWING); item->gravityStatus = false; item->speed = 0; item->fallspeed = 0; - Lara.gunStatus = LG_HANDS_BUSY; + info->gunStatus = LG_HANDS_BUSY; MonkeySwingSnap(item, coll); @@ -413,25 +486,24 @@ bool TestLaraHangJumpUp(ITEM_INFO* item, COLL_INFO* coll) item->speed = 0; item->fallspeed = 0; - Lara.gunStatus = LG_HANDS_BUSY; - Lara.torsoYrot = 0; - Lara.torsoXrot = 0; + info->gunStatus = LG_HANDS_BUSY; + info->torsoYrot = 0; + info->torsoXrot = 0; return true; } bool TestLaraHangJump(ITEM_INFO* item, COLL_INFO* coll) { - if (!(TrInput & IN_ACTION) || (Lara.gunStatus != LG_NO_ARMS) || (coll->HitStatic)) + LaraInfo*& info = item->data; + + if (!(TrInput & IN_ACTION) || (info->gunStatus != LG_HANDS_FREE) || (coll->HitStatic)) return false; - if (Lara.canMonkeySwing && coll->CollisionType == CT_TOP) + if (info->canMonkeySwing && coll->CollisionType == CT_TOP) { - Lara.headYrot = 0; - Lara.headXrot = 0; - Lara.torsoYrot = 0; - Lara.torsoXrot = 0; - Lara.gunStatus = LG_HANDS_BUSY; + ResetLaraFlex(item); + info->gunStatus = LG_HANDS_BUSY; SetAnimation(item, LA_REACH_TO_MONKEYSWING); item->gravityStatus = false; @@ -461,27 +533,19 @@ bool TestLaraHangJump(ITEM_INFO* item, COLL_INFO* coll) if (TestHangSwingIn(item, angle)) { - if (g_GameFlow->Animations.OscillateHanging) + if (g_GameFlow->Animations.OscillateHang) { - Lara.headYrot = 0; - Lara.headXrot = 0; - Lara.torsoYrot = 0; - Lara.torsoXrot = 0; + ResetLaraFlex(item); SetAnimation(item, LA_REACH_TO_HANG_OSCILLATE); } else { - Lara.headYrot = 0; - Lara.headXrot = 0; - Lara.torsoYrot = 0; - Lara.torsoXrot = 0; + ResetLaraFlex(item); SetAnimation(item, LA_REACH_TO_MONKEYSWING); } } else - { SetAnimation(item, LA_REACH_TO_HANG); - } auto bounds = GetBoundsAccurate(item); @@ -502,19 +566,21 @@ bool TestLaraHangJump(ITEM_INFO* item, COLL_INFO* coll) item->speed = 2; item->fallspeed = 1; - Lara.gunStatus = LG_HANDS_BUSY; + info->gunStatus = LG_HANDS_BUSY; return true; } bool TestLaraHang(ITEM_INFO* item, COLL_INFO* coll) { - auto angle = Lara.moveAngle; + LaraInfo*& info = item->data; + + auto angle = info->moveAngle; auto climbShift = 0; - if (Lara.moveAngle == (short)(item->pos.yRot - ANGLE(90.0f))) + if (info->moveAngle == (short)(item->pos.yRot - ANGLE(90.0f))) climbShift = -coll->Setup.Radius; - else if (Lara.moveAngle == (short)(item->pos.yRot + ANGLE(90.0f))) + else if (info->moveAngle == (short)(item->pos.yRot + ANGLE(90.0f))) climbShift = coll->Setup.Radius; // Temporarily move item a bit closer to the wall to get more precise coll results @@ -523,24 +589,24 @@ bool TestLaraHang(ITEM_INFO* item, COLL_INFO* coll) item->pos.zPos += phd_cos(item->pos.yRot) * coll->Setup.Radius * 0.5f; // Get height difference with side spaces (left or right, depending on movement direction) - auto hdif = LaraFloorFront(item, Lara.moveAngle, coll->Setup.Radius * 1.4f); + auto hdif = LaraFloorFront(item, info->moveAngle, coll->Setup.Radius * 1.4f); // Set stopped flag, if floor height is above footspace which is step size - auto stopped = hdif < STEP_SIZE / 2; + auto stopped = hdif < CLICK(0.5f); // Set stopped flag, if ceiling height is below headspace which is step size - if (LaraCeilingFront(item, Lara.moveAngle, coll->Setup.Radius * 1.5f, 0) > -950) + if (LaraCeilingFront(item, info->moveAngle, coll->Setup.Radius * 1.5f, 0) > -950) stopped = true; // Backup item pos to restore it after coll tests item->pos = oldPos; // Setup coll info - Lara.moveAngle = item->pos.yRot; + info->moveAngle = item->pos.yRot; coll->Setup.BadHeightDown = NO_BAD_POS; coll->Setup.BadHeightUp = -STEPUP_HEIGHT; coll->Setup.BadCeilingHeight = 0; - coll->Setup.ForwardAngle = Lara.moveAngle; + coll->Setup.ForwardAngle = info->moveAngle; // When Lara is about to move, use larger embed offset for stabilizing diagonal shimmying) auto embedOffset = 4; @@ -554,11 +620,11 @@ bool TestLaraHang(ITEM_INFO* item, COLL_INFO* coll) bool result = false; - if (Lara.climbStatus) // Ladder case + if (info->climbStatus) // Ladder case { if (TrInput & IN_ACTION && item->hitPoints > 0) { - Lara.moveAngle = angle; + info->moveAngle = angle; if (!TestLaraHangOnClimbWall(item, coll)) { @@ -588,7 +654,7 @@ bool TestLaraHang(ITEM_INFO* item, COLL_INFO* coll) item->gravityStatus = true; item->speed = 2; item->fallspeed = 1; - Lara.gunStatus = LG_NO_ARMS; + info->gunStatus = LG_HANDS_FREE; } } else // Normal case @@ -602,12 +668,12 @@ bool TestLaraHang(ITEM_INFO* item, COLL_INFO* coll) auto x = item->pos.xPos; auto z = item->pos.zPos; - Lara.moveAngle = angle; + info->moveAngle = angle; if (climbShift != 0) { - auto s = phd_sin(Lara.moveAngle); - auto c = phd_cos(Lara.moveAngle); + auto s = phd_sin(info->moveAngle); + auto c = phd_cos(info->moveAngle); auto testShift = Vector2(s * climbShift, c * climbShift); x += testShift.x; @@ -654,12 +720,12 @@ bool TestLaraHang(ITEM_INFO* item, COLL_INFO* coll) { SetAnimation(item, LA_JUMP_UP, 9); item->pos.xPos += coll->Shift.x; - item->pos.yPos += GetBoundsAccurate(item)->Y2; + item->pos.yPos += GetBoundsAccurate(item)->Y2 * 2.4f; item->pos.zPos += coll->Shift.z; item->gravityStatus = true; item->speed = 2; item->fallspeed = 1; - Lara.gunStatus = LG_NO_ARMS; + info->gunStatus = LG_HANDS_FREE; } } @@ -668,6 +734,8 @@ bool TestLaraHang(ITEM_INFO* item, COLL_INFO* coll) CORNER_RESULT TestLaraHangCorner(ITEM_INFO* item, COLL_INFO* coll, float testAngle) { + LaraInfo*& info = item->data; + // Lara isn't in stop state yet, bypass test if (item->animNumber != LA_REACH_TO_HANG) return CORNER_RESULT::NONE; @@ -689,22 +757,22 @@ CORNER_RESULT TestLaraHangCorner(ITEM_INFO* item, COLL_INFO* coll, float testAng auto bounds = GetBoundsAccurate(item); // Store next position - Lara.nextCornerPos.xPos = item->pos.xPos; - Lara.nextCornerPos.yPos = LaraCollisionAboveFront(item, item->pos.yRot, coll->Setup.Radius * 2, abs(bounds->Y1) + LARA_HEADROOM).Position.Floor + abs(bounds->Y1); - Lara.nextCornerPos.zPos = item->pos.zPos; - Lara.nextCornerPos.yRot = item->pos.yRot; - Lara.moveAngle = item->pos.yRot; + info->nextCornerPos.xPos = item->pos.xPos; + info->nextCornerPos.yPos = LaraCollisionAboveFront(item, item->pos.yRot, coll->Setup.Radius * 2, abs(bounds->Y1) + LARA_HEADROOM).Position.Floor + abs(bounds->Y1); + info->nextCornerPos.zPos = item->pos.zPos; + info->nextCornerPos.yRot = item->pos.yRot; + info->moveAngle = item->pos.yRot; auto result = TestLaraValidHangPos(item, coll); // Restore original item positions item->pos = oldPos; - Lara.moveAngle = oldMoveAngle; + info->moveAngle = oldMoveAngle; if (result) return CORNER_RESULT::INNER; - if (Lara.climbStatus) + if (info->climbStatus) { auto& angleSet = testAngle > 0 ? LeftExtRightIntTab : LeftIntRightExtTab; if (GetClimbFlags(Lara.nextCornerPos.xPos, item->pos.yPos, Lara.nextCornerPos.zPos, item->roomNumber) & (short)angleSet[GetQuadrant(item->pos.yRot)]) @@ -717,17 +785,17 @@ CORNER_RESULT TestLaraHangCorner(ITEM_INFO* item, COLL_INFO* coll, float testAng // Restore original item positions item->pos = oldPos; - Lara.moveAngle = oldMoveAngle; + info->moveAngle = oldMoveAngle; // OUTER CORNER TESTS // Test if there's a material obstacles blocking outer corner pathway - if ((LaraFloorFront(item, item->pos.yRot + ANGLE(testAngle), coll->Setup.Radius + STEP_SIZE) < 0) || - (LaraCeilingFront(item, item->pos.yRot + ANGLE(testAngle), coll->Setup.Radius + STEP_SIZE, coll->Setup.Height) > 0)) + if ((LaraFloorFront(item, item->pos.yRot + ANGLE(testAngle), coll->Setup.Radius + CLICK(1)) < 0) || + (LaraCeilingFront(item, item->pos.yRot + ANGLE(testAngle), coll->Setup.Radius + CLICK(1), coll->Setup.Height) > 0)) return CORNER_RESULT::NONE; // Last chance for possible diagonal vs. non-diagonal cases: ray test - if (!LaraPositionOnLOS(item, item->pos.yRot + ANGLE(testAngle), coll->Setup.Radius + STEP_SIZE)) + if (!LaraPositionOnLOS(item, item->pos.yRot + ANGLE(testAngle), coll->Setup.Radius + CLICK(1))) return CORNER_RESULT::NONE; bool snappable = SnapAndTestItemAtNextCornerPosition(item, coll, testAngle, true); @@ -744,22 +812,22 @@ CORNER_RESULT TestLaraHangCorner(ITEM_INFO* item, COLL_INFO* coll, float testAng auto bounds = GetBoundsAccurate(item); // Store next position - Lara.nextCornerPos.xPos = item->pos.xPos; - Lara.nextCornerPos.yPos = LaraCollisionAboveFront(item, item->pos.yRot, coll->Setup.Radius * 2, abs(bounds->Y1) + LARA_HEADROOM).Position.Floor + abs(bounds->Y1); - Lara.nextCornerPos.zPos = item->pos.zPos; - Lara.nextCornerPos.yRot = item->pos.yRot; - Lara.moveAngle = item->pos.yRot; + info->nextCornerPos.xPos = item->pos.xPos; + info->nextCornerPos.yPos = LaraCollisionAboveFront(item, item->pos.yRot, coll->Setup.Radius * 2, abs(bounds->Y1) + LARA_HEADROOM).Position.Floor + abs(bounds->Y1); + info->nextCornerPos.zPos = item->pos.zPos; + info->nextCornerPos.yRot = item->pos.yRot; + info->moveAngle = item->pos.yRot; auto result = TestLaraValidHangPos(item, coll); // Restore original item positions item->pos = oldPos; - Lara.moveAngle = oldMoveAngle; + info->moveAngle = oldMoveAngle; if (result) return CORNER_RESULT::OUTER; - if (Lara.climbStatus) + if (info->climbStatus) { auto& angleSet = testAngle > 0 ? LeftIntRightExtTab : LeftExtRightIntTab; if (GetClimbFlags(Lara.nextCornerPos.xPos, item->pos.yPos, Lara.nextCornerPos.zPos, item->roomNumber) & (short)angleSet[GetQuadrant(item->pos.yRot)]) @@ -772,21 +840,23 @@ CORNER_RESULT TestLaraHangCorner(ITEM_INFO* item, COLL_INFO* coll, float testAng // Restore original item positions item->pos = oldPos; - Lara.moveAngle = oldMoveAngle; + info->moveAngle = oldMoveAngle; return CORNER_RESULT::NONE; } bool TestLaraValidHangPos(ITEM_INFO* item, COLL_INFO* coll) { + LaraInfo*& info = item->data; + // Get incoming ledge height and own Lara's upper bound. // First one will be negative while first one is positive. // Difference between two indicates difference in height between ledges. - auto frontFloor = LaraCollisionAboveFront(item, Lara.moveAngle, coll->Setup.Radius + STEP_SIZE / 2, LARA_HEIGHT).Position.Floor; + auto frontFloor = LaraCollisionAboveFront(item, info->moveAngle, coll->Setup.Radius + CLICK(0.5f), LARA_HEIGHT).Position.Floor; auto laraUpperBound = item->pos.yPos - coll->Setup.Height; // If difference is above 1/2 click, return false (ledge is out of reach). - if (abs(frontFloor - laraUpperBound) > STEP_SIZE / 2) + if (abs(frontFloor - laraUpperBound) > CLICK(0.5f)) return false; // Embed Lara into wall to make collision test succeed @@ -794,12 +864,12 @@ bool TestLaraValidHangPos(ITEM_INFO* item, COLL_INFO* coll) item->pos.zPos += phd_cos(item->pos.yRot) * 8; // Setup new GCI call - Lara.moveAngle = item->pos.yRot; + info->moveAngle = item->pos.yRot; coll->Setup.BadHeightDown = NO_BAD_POS; coll->Setup.BadHeightUp = -CLICK(2); coll->Setup.BadCeilingHeight = 0; coll->Setup.Mode = COLL_PROBE_MODE::FREE_FLAT; - coll->Setup.ForwardAngle = Lara.moveAngle; + coll->Setup.ForwardAngle = info->moveAngle; GetCollisionInfo(coll, item); @@ -815,10 +885,10 @@ bool TestLaraClimbStance(ITEM_INFO* item, COLL_INFO* coll) { int shift_r, shift_l; - if (LaraTestClimbPos(item, coll->Setup.Radius, coll->Setup.Radius + CLICK(0.5f), -700, STOP_SIZE, &shift_r) != 1) + if (LaraTestClimbPos(item, coll->Setup.Radius, coll->Setup.Radius + CLICK(0.5f), -700, CLICK(2), &shift_r) != 1) return false; - if (LaraTestClimbPos(item, coll->Setup.Radius, -(coll->Setup.Radius + CLICK(0.5f)), -700, STOP_SIZE, &shift_l) != 1) + if (LaraTestClimbPos(item, coll->Setup.Radius, -(coll->Setup.Radius + CLICK(0.5f)), -700, CLICK(2), &shift_l) != 1) return false; if (shift_r) @@ -848,9 +918,10 @@ bool TestLaraClimbStance(ITEM_INFO* item, COLL_INFO* coll) bool TestLaraHangOnClimbWall(ITEM_INFO* item, COLL_INFO* coll) { + LaraInfo*& info = item->data; int shift, result; - if (Lara.climbStatus == 0) + if (info->climbStatus == 0) return false; if (item->fallspeed < 0) @@ -881,10 +952,10 @@ bool TestLaraHangOnClimbWall(ITEM_INFO* item, COLL_INFO* coll) auto bounds = GetBoundsAccurate(item); - if (Lara.moveAngle != item->pos.yRot) + if (info->moveAngle != item->pos.yRot) { short l = LaraCeilingFront(item, item->pos.yRot, 0, 0); - short r = LaraCeilingFront(item, Lara.moveAngle, STEP_SIZE / 2, 0); + short r = LaraCeilingFront(item, info->moveAngle, CLICK(0.5f), 0); if (abs(l - r) > SLOPE_DIFFERENCE) return false; @@ -936,6 +1007,7 @@ int TestLaraEdgeCatch(ITEM_INFO* item, COLL_INFO* coll, int* edge) bool TestHangSwingIn(ITEM_INFO* item, short angle) { + LaraInfo*& info = item->data; int x = item->pos.xPos; int y = item->pos.yPos; int z = item->pos.zPos; @@ -943,8 +1015,8 @@ bool TestHangSwingIn(ITEM_INFO* item, short angle) FLOOR_INFO* floor; int floorHeight, ceilingHeight; - z += phd_cos(angle) * (STEP_SIZE / 2); - x += phd_sin(angle) * (STEP_SIZE / 2); + z += phd_cos(angle) * CLICK(0.5f); + x += phd_sin(angle) * CLICK(0.5f); floor = GetFloor(x, y, z, &roomNum); floorHeight = GetFloorHeight(floor, x, y, z); @@ -952,7 +1024,7 @@ bool TestHangSwingIn(ITEM_INFO* item, short angle) if (floorHeight != NO_HEIGHT) { - if (g_GameFlow->Animations.OscillateHanging) + if (g_GameFlow->Animations.OscillateHang) { if (floorHeight - y > 0 && ceilingHeight - y < -400) return true; @@ -969,13 +1041,14 @@ bool TestHangSwingIn(ITEM_INFO* item, short angle) bool TestLaraHangSideways(ITEM_INFO* item, COLL_INFO* coll, short angle) { + LaraInfo*& info = item->data; auto oldPos = item->pos; Lara.moveAngle = item->pos.yRot + angle; static constexpr auto sidewayTestDistance = 16; - item->pos.xPos += phd_sin(Lara.moveAngle) * sidewayTestDistance; - item->pos.zPos += phd_cos(Lara.moveAngle) * sidewayTestDistance; + item->pos.xPos += phd_sin(info->moveAngle) * sidewayTestDistance; + item->pos.zPos += phd_cos(info->moveAngle) * sidewayTestDistance; coll->Setup.OldPosition.y = item->pos.yPos; @@ -986,23 +1059,39 @@ bool TestLaraHangSideways(ITEM_INFO* item, COLL_INFO* coll, short angle) return !res; } -bool LaraFacingCorner(ITEM_INFO* item, short ang, int dist) +bool TestLaraStandingJump(ITEM_INFO* item, COLL_INFO* coll, short angle) { - auto angle1 = ang + ANGLE(15); - auto angle2 = ang - ANGLE(15); + auto y = item->pos.yPos; + auto probe = GetCollisionResult(item, angle, CLICK(1), coll->Setup.Height); + + // TODO: Ceiling test interfered with bridges. For now, behaves as original. + if (!TestLaraFacingCorner(item, angle, CLICK(1)) && + probe.Position.Floor + probe.Position.Bridge - y >= -STEPUP_HEIGHT && // Highest floor bound. + probe.Position.Floor != NO_HEIGHT) + { + return true; + } + + return false; +} + +bool TestLaraFacingCorner(ITEM_INFO* item, short angle, int dist) +{ + auto angle1 = angle + ANGLE(15.0f); + auto angle2 = angle - ANGLE(15.0f); auto vec1 = GAME_VECTOR(item->pos.xPos + dist * phd_sin(angle1), - item->pos.yPos - (LARA_HEIGHT / 2), - item->pos.zPos + dist * phd_cos(angle1), + item->pos.yPos - STEPUP_HEIGHT, + item->pos.zPos + dist * phd_cos(angle1), item->roomNumber); auto vec2 = GAME_VECTOR(item->pos.xPos + dist * phd_sin(angle2), - item->pos.yPos - (LARA_HEIGHT / 2), + item->pos.yPos - STEPUP_HEIGHT, item->pos.zPos + dist * phd_cos(angle2), item->roomNumber); - auto pos = GAME_VECTOR(item->pos.xPos, - item->pos.yPos - (LARA_HEIGHT / 2), + auto pos = GAME_VECTOR(item->pos.xPos, + item->pos.yPos - STEPUP_HEIGHT, item->pos.zPos, item->roomNumber); @@ -1047,12 +1136,12 @@ int LaraFloorFront(ITEM_INFO* item, short ang, int dist) COLL_RESULT LaraCollisionFront(ITEM_INFO* item, short ang, int dist) { - auto collResult = GetCollisionResult(item, ang, dist, -LARA_HEIGHT); + auto probe = GetCollisionResult(item, ang, dist, -LARA_HEIGHT); - if (collResult.Position.Floor != NO_HEIGHT) - collResult.Position.Floor -= item->pos.yPos; + if (probe.Position.Floor != NO_HEIGHT) + probe.Position.Floor -= item->pos.yPos; - return collResult; + return probe; } COLL_RESULT LaraCollisionAboveFront(ITEM_INFO* item, short ang, int dist, int h) @@ -1071,27 +1160,39 @@ int LaraCeilingFront(ITEM_INFO* item, short ang, int dist, int h) COLL_RESULT LaraCeilingCollisionFront(ITEM_INFO* item, short ang, int dist, int h) { - auto collResult = GetCollisionResult(item, ang, dist, -h); + auto probe = GetCollisionResult(item, ang, dist, -h); - if (collResult.Position.Ceiling != NO_HEIGHT) - collResult.Position.Ceiling += h - item->pos.yPos; + if (probe.Position.Ceiling != NO_HEIGHT) + probe.Position.Ceiling += h - item->pos.yPos; - return collResult; + return probe; } -bool LaraFallen(ITEM_INFO* item, COLL_INFO* coll) +bool TestLaraFall(ITEM_INFO* item, COLL_INFO* coll) { - if (Lara.waterStatus == LW_WADE || coll->Middle.Floor <= STEPUP_HEIGHT) + LaraInfo*& info = item->data; + + if (coll->Middle.Floor <= STEPUP_HEIGHT || + info->waterStatus == LW_WADE) // TODO: This causes a legacy floor snap bug when lara wades off a ledge into a dry room. @Sezz 2021.09.26 { return false; } - item->animNumber = LA_FALL_START; - item->currentAnimState = LS_JUMP_FORWARD; - item->goalAnimState = LS_JUMP_FORWARD; - item->frameNumber = g_Level.Anims[item->animNumber].frameBase; + return true; +} + +// TODO: Gradually replace calls. +bool LaraFallen(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + if (info->waterStatus == LW_WADE || coll->Middle.Floor <= STEPUP_HEIGHT) + return false; + + SetAnimation(item, LA_FALL_START); item->fallspeed = 0; item->gravityStatus = true; + return true; } @@ -1104,11 +1205,13 @@ bool LaraLandedBad(ITEM_INFO* item, COLL_INFO* coll) if (landspeed <= 14) { item->hitPoints -= 1000 * SQUARE(landspeed) / 196; + return item->hitPoints <= 0; } else { item->hitPoints = -1; + return true; } } @@ -1118,6 +1221,8 @@ bool LaraLandedBad(ITEM_INFO* item, COLL_INFO* coll) bool TestLaraWaterStepOut(ITEM_INFO* item, COLL_INFO* coll) { + LaraInfo*& info = item->data; + if (coll->CollisionType == CT_FRONT || coll->Middle.Slope || coll->Middle.Floor >= 0) @@ -1125,17 +1230,17 @@ bool TestLaraWaterStepOut(ITEM_INFO* item, COLL_INFO* coll) return false; } - if (coll->Middle.Floor >= -(STEP_SIZE / 2)) + if (coll->Middle.Floor >= -CLICK(0.5f)) { SetAnimation(item, LA_STAND_IDLE); } else { SetAnimation(item, LA_ONWATER_TO_WADE_1CLICK); - item->goalAnimState = LS_STOP; + item->goalAnimState = LS_IDLE; } - item->pos.yPos += coll->Middle.Floor + (STOP_SIZE + STEP_SIZE / 2 + STEP_SIZE / 4 - 9); + item->pos.yPos += coll->Middle.Floor + CLICK(2.75f) - 9; UpdateItemRoom(item, -(STEPUP_HEIGHT - 3)); @@ -1144,19 +1249,20 @@ bool TestLaraWaterStepOut(ITEM_INFO* item, COLL_INFO* coll) item->gravityStatus = false; item->speed = 0; item->fallspeed = 0; - Lara.waterStatus = LW_WADE; + info->waterStatus = LW_WADE; return true; } - bool TestLaraWaterClimbOut(ITEM_INFO* item, COLL_INFO* coll) { + LaraInfo*& info = item->data; + if (coll->CollisionType != CT_FRONT || !(TrInput & IN_ACTION)) return false; - if (Lara.gunStatus && - (Lara.gunStatus != LG_READY || Lara.gunType != WEAPON_FLARE)) + if (info->gunStatus && + (info->gunStatus != LG_READY || info->gunType != WEAPON_FLARE)) { return false; } @@ -1165,8 +1271,8 @@ bool TestLaraWaterClimbOut(ITEM_INFO* item, COLL_INFO* coll) return false; int frontFloor = coll->Front.Floor + LARA_HEIGHT_SURFSWIM; - if (frontFloor <= -STOP_SIZE || - frontFloor > (STEP_SIZE + STEP_SIZE / 4 - 4)) + if (frontFloor <= -CLICK(2) || + frontFloor > CLICK(1.25f) - 4) { return false; } @@ -1174,14 +1280,14 @@ bool TestLaraWaterClimbOut(ITEM_INFO* item, COLL_INFO* coll) if (!TestValidLedge(item, coll)) return false; - auto surface = LaraCollisionAboveFront(item, coll->Setup.ForwardAngle, (STEP_SIZE * 2), STEP_SIZE); + auto surface = LaraCollisionAboveFront(item, coll->Setup.ForwardAngle, CLICK(2), CLICK(1)); auto headroom = surface.Position.Floor - surface.Position.Ceiling; - if (frontFloor <= -STEP_SIZE) + if (frontFloor <= -CLICK(1)) { if (headroom < LARA_HEIGHT) { - if (g_GameFlow->Animations.CrawlExtra) + if (g_GameFlow->Animations.CrawlExtended) SetAnimation(item, LA_ONWATER_TO_CROUCH_1CLICK); else return false; @@ -1189,11 +1295,11 @@ bool TestLaraWaterClimbOut(ITEM_INFO* item, COLL_INFO* coll) else SetAnimation(item, LA_ONWATER_TO_STAND_1CLICK); } - else if (frontFloor > (STEP_SIZE / 2)) + else if (frontFloor > CLICK(0.5f)) { if (headroom < LARA_HEIGHT) { - if (g_GameFlow->Animations.CrawlExtra) + if (g_GameFlow->Animations.CrawlExtended) SetAnimation(item, LA_ONWATER_TO_CROUCH_M1CLICK); else return false; @@ -1206,7 +1312,7 @@ bool TestLaraWaterClimbOut(ITEM_INFO* item, COLL_INFO* coll) { if (headroom < LARA_HEIGHT) { - if (g_GameFlow->Animations.CrawlExtra) + if (g_GameFlow->Animations.CrawlExtended) SetAnimation(item, LA_ONWATER_TO_CROUCH_0CLICK); else return false; @@ -1223,23 +1329,25 @@ bool TestLaraWaterClimbOut(ITEM_INFO* item, COLL_INFO* coll) item->gravityStatus = false; item->speed = 0; item->fallspeed = 0; - Lara.gunStatus = LG_HANDS_BUSY; - Lara.waterStatus = LW_ABOVE_WATER; + info->gunStatus = LG_HANDS_BUSY; + info->waterStatus = LW_ABOVE_WATER; return true; } bool TestLaraLadderClimbOut(ITEM_INFO* item, COLL_INFO* coll) // NEW function for water to ladder move { + LaraInfo*& info = item->data; + if (!(TrInput & IN_ACTION) || - !Lara.climbStatus || + !info->climbStatus || coll->CollisionType != CT_FRONT) { return false; } - if (Lara.gunStatus && - (Lara.gunStatus != LG_READY || Lara.gunType != WEAPON_FLARE)) + if (info->gunStatus && + (info->gunStatus != LG_READY || info->gunType != WEAPON_FLARE)) { return false; } @@ -1291,12 +1399,392 @@ bool TestLaraLadderClimbOut(ITEM_INFO* item, COLL_INFO* coll) // NEW function fo item->gravityStatus = false; item->speed = 0; item->fallspeed = 0; - Lara.gunStatus = LG_HANDS_BUSY; - Lara.waterStatus = LW_ABOVE_WATER; + info->gunStatus = LG_HANDS_BUSY; + info->waterStatus = LW_ABOVE_WATER; return true; } +void TestLaraWaterDepth(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + short roomNumber = item->roomNumber; + FLOOR_INFO* floor = GetFloor(item->pos.xPos, item->pos.yPos, item->pos.zPos, &roomNumber); + int waterDepth = GetWaterDepth(item->pos.xPos, item->pos.yPos, item->pos.zPos, roomNumber); + + if (waterDepth == NO_HEIGHT) + { + item->fallspeed = 0; + item->pos.xPos = coll->Setup.OldPosition.x; + item->pos.yPos = coll->Setup.OldPosition.y; + item->pos.zPos = coll->Setup.OldPosition.z; + } + // Height check was at CLICK(2) before but changed to this + // because now Lara surfaces on a head level, not mid-body level. + else if (waterDepth <= LARA_HEIGHT - LARA_HEADROOM / 2) + { + SetAnimation(item, LA_UNDERWATER_TO_STAND); + item->goalAnimState = LS_IDLE; + item->pos.zRot = 0; + item->pos.xRot = 0; + item->speed = 0; + item->fallspeed = 0; + item->gravityStatus = false; + info->waterStatus = LW_WADE; + item->pos.yPos = GetFloorHeight(floor, item->pos.xPos, item->pos.yPos, item->pos.zPos); + } +} + +#ifndef NEW_TIGHTROPE +void GetTighRopeFallOff(int regularity) { + if (LaraItem->hitPoints <= 0 || LaraItem->hitStatus) + SetAnimation(LaraItem, LA_TIGHTROPE_FALL_LEFT); + + if (!info->tightRopeFall && !(GetRandomControl() & regularity)) + info->tightRopeFall = 2 - ((GetRandomControl() & 0xF) != 0); +} +#endif + +bool IsStandingWeapon(LARA_WEAPON_TYPE gunType) +{ + if (gunType == LARA_WEAPON_TYPE::WEAPON_SHOTGUN || + gunType == LARA_WEAPON_TYPE::WEAPON_HK || + gunType == LARA_WEAPON_TYPE::WEAPON_CROSSBOW || + gunType == LARA_WEAPON_TYPE::WEAPON_TORCH || + gunType == LARA_WEAPON_TYPE::WEAPON_GRENADE_LAUNCHER || + gunType == LARA_WEAPON_TYPE::WEAPON_HARPOON_GUN || + gunType == LARA_WEAPON_TYPE::WEAPON_ROCKET_LAUNCHER || + gunType == LARA_WEAPON_TYPE::WEAPON_SNOWMOBILE) + { + return true; + } + + return false; +} + +bool TestLaraPose(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + if (!TestLaraSwamp(item) && + info->gunStatus == LG_HANDS_FREE && // Hands are free. + !(TrInput & (IN_FLARE | IN_DRAW)) && // Avoid unsightly concurrent actions. + (info->gunType != WEAPON_FLARE || info->flareAge > 0) && // Flare is not being handled. TODO: Will she pose with weapons drawn? + info->Vehicle == NO_ITEM) // Not in a vehicle. + { + return true; + } + + return false; +} + +bool TestLaraStep(COLL_INFO* coll) +{ + if (abs(coll->Middle.Floor) > 0 && + //coll->Middle.Floor <= STEPUP_HEIGHT && // Lower floor bound. BUG: Wading in water over a pit, Lara will not descend. + coll->Middle.Floor >= -STEPUP_HEIGHT && // Upper floor bound. + coll->Middle.Floor != NO_HEIGHT) + { + return true; + } + + return false; +} + +bool TestLaraStepUp(ITEM_INFO* item, COLL_INFO* coll) +{ + if (coll->Middle.Floor < -CLICK(0.5f) && // Lower floor bound. + coll->Middle.Floor >= -STEPUP_HEIGHT && // Upper floor bound. + item->currentAnimState != LS_CRAWL_IDLE && // Crawl step up handled differently. + item->currentAnimState != LS_CRAWL_FORWARD) + { + return true; + } + + return false; +} + +bool TestLaraStepDown(ITEM_INFO* item, COLL_INFO* coll) +{ + if (coll->Middle.Floor > CLICK(0.5f) && // Upper floor bound. + coll->Middle.Floor <= STEPUP_HEIGHT && // Lower floor bound. + item->currentAnimState != LS_CRAWL_IDLE && // Crawl step down handled differently. + item->currentAnimState != LS_CRAWL_FORWARD) + { + return true; + } + + return false; +} + +// TODO: This function and its clone below should become obsolete with more accurate and accessible collision detection in the future. +// For now, it supercedes old probes and is used alongside COLL_INFO. @Sezz 2021.10.24 +bool TestLaraMove(ITEM_INFO* item, COLL_INFO* coll, short angle, int lowerBound, int upperBound, bool checkSlope, bool checkDeath) +{ + auto y = item->pos.yPos; + auto probe = GetCollisionResult(item, angle, coll->Setup.Radius * sqrt(2) + 4, 0); // Offset required to account for gap between Lara and the wall. Results in slight overshoot, but avoids oscillation. + auto isSlope = checkSlope ? probe.Position.Slope : false; + auto isDeath = checkDeath ? probe.Block->Flags.Death : false; + + if ((probe.Position.Floor - y) <= lowerBound && // Lower floor bound. + (probe.Position.Floor - y) >= upperBound && // Upper floor bound. + (probe.Position.Ceiling - y) < -coll->Setup.Height && // Lowest ceiling bound. + abs(probe.Position.Ceiling - probe.Position.Floor) > coll->Setup.Height && // Space is not a clamp. + !isSlope && !isDeath && // No slope or death sector (if applicable). + probe.Position.Floor != NO_HEIGHT) + { + return true; + } + + return false; +} + +// HACK: coll->Setup.Radius and coll->Setup.Height are only set +// in COLLISION functions, then reset by LaraAboveWater() to defaults. +// This means they will store the wrong values for tests called in crawl CONTROL functions. +// When states become objects, collision setup should occur at the beginning of each state, eliminating the need +// for this clone function. @Sezz 2021.12.05 +bool TestLaraMoveCrawl(ITEM_INFO* item, COLL_INFO* coll, short angle, int lowerBound, int upperBound, bool checkSlope, bool checkDeath) +{ + auto y = item->pos.yPos; + auto probe = GetCollisionResult(item, angle, LARA_RAD_CRAWL * sqrt(2) + 4, 0); // Offset required to account for gap between Lara and the wall. Results in slight overshoot, but avoids oscillation. + auto isSlope = checkSlope ? probe.Position.Slope : false; + auto isDeath = checkDeath ? probe.Block->Flags.Death : false; + + if ((probe.Position.Floor - y) <= lowerBound && // Lower floor bound. + (probe.Position.Floor - y) >= upperBound && // Upper floor bound. + (probe.Position.Ceiling - y) < -LARA_HEIGHT_CRAWL && // Lowest ceiling bound. + abs(probe.Position.Ceiling - probe.Position.Floor) > LARA_HEIGHT_CRAWL && // Space is not a clamp. + !isSlope && !isDeath && // No slope or death sector (if applicable). + probe.Position.Floor != NO_HEIGHT) + { + return true; + } + + return false; +} + +bool TestLaraRunForward(ITEM_INFO* item, COLL_INFO* coll) +{ + auto y = item->pos.yPos - coll->Setup.Height; + auto probe = GetCollisionResult(item, item->pos.yRot, coll->Setup.Radius * sqrt(2) + 4, 0); + + // Hack to ensure Lara can run off diagonal ledges and stops on slanted ceilings. coll->Front.Floor often holds the wrong height because of quadrant-dependent wall pushing. @Sezz 2021.11.06 + // BUG: This interferes with the one-step stand-to-crouch vault where the ceiling is lower than Lara's height. + if ((probe.Position.Ceiling - y) < 0) + return true; + + return false; + + // TODO: TestLaraMove() call not useful yet; it can block Lara from climbing. @Sezz 2021.10.28 + //return TestLaraMove(item, coll, item->pos.yRot, STEPUP_HEIGHT, -STEPUP_HEIGHT, false); // Using BadHeightUp/Down defined in walk and run state collision functions. +} + +bool TestLaraWalkForward(ITEM_INFO* item, COLL_INFO* coll) +{ + if (coll->CollisionType != CT_FRONT && + coll->CollisionType != CT_TOP_FRONT) + { + return true; + } + + return false; + + // TODO: Same issues as in TestLaraRunForward(). + //return TestLaraMove(item, coll, item->pos.yRot, STEPUP_HEIGHT, -STEPUP_HEIGHT, true, true); // Using BadHeightUp/Down defined in walk and run state collision functions. +} + +bool TestLaraWalkBack(ITEM_INFO* item, COLL_INFO* coll) +{ + return TestLaraMove(item, coll, item->pos.yRot + ANGLE(180.0f), STEPUP_HEIGHT, -STEPUP_HEIGHT); // Using BadHeightUp/Down defined in walk back state collision function. +} + +bool TestLaraHopBack(ITEM_INFO* item, COLL_INFO* coll) +{ + return TestLaraMove(item, coll, item->pos.yRot + ANGLE(180.0f), NO_BAD_POS, -STEPUP_HEIGHT, false, false); // Using BadHeightUp/Down defined in hop back state collision function. +} + +bool TestLaraStepLeft(ITEM_INFO* item, COLL_INFO* coll) +{ + return TestLaraMove(item, coll, item->pos.yRot - ANGLE(90.0f), CLICK(0.5f), -CLICK(0.5f)); // Using BadHeightUp/Down defined in step left state collision function. +} + +bool TestLaraStepRight(ITEM_INFO* item, COLL_INFO* coll) +{ + return TestLaraMove(item, coll, item->pos.yRot + ANGLE(90.0f), CLICK(0.5f), -CLICK(0.5f)); // Using BadHeightUp/Down defined in step right state collision function. +} + +bool TestLaraWalkBackSwamp(ITEM_INFO* item, COLL_INFO* coll) +{ + return TestLaraMove(item, coll, item->pos.yRot + ANGLE(180.0f), NO_BAD_POS, -STEPUP_HEIGHT, false); // Using BadHeightUp defined in walk back state collision function. +} + +bool TestLaraStepLeftSwamp(ITEM_INFO* item, COLL_INFO* coll) +{ + return TestLaraMove(item, coll, item->pos.yRot - ANGLE(90.0f), NO_BAD_POS, -CLICK(0.5f), false); // Using BadHeightUp defined in step left state collision function. +} + +bool TestLaraStepRightSwamp(ITEM_INFO* item, COLL_INFO* coll) +{ + return TestLaraMove(item, coll, item->pos.yRot + ANGLE(90.0f), NO_BAD_POS, -CLICK(0.5f), false); // Using BadHeightUp defined in step right state collision function. +} + +bool TestLaraCrawlForward(ITEM_INFO* item, COLL_INFO* coll) +{ + return TestLaraMoveCrawl(item, coll, item->pos.yRot, CLICK(1) - 1, -(CLICK(1) - 1)); // Using BadHeightUp/Down defined in crawl state collision functions. +} + +bool TestLaraCrawlBack(ITEM_INFO* item, COLL_INFO* coll) +{ + return TestLaraMoveCrawl(item, coll, item->pos.yRot + ANGLE(180.0f), CLICK(1) - 1, -(CLICK(1) - 1)); // Using BadHeightUp/Down defined in crawl state collision functions. +} + +bool TestLaraCrouchToCrawl(ITEM_INFO* item) +{ + LaraInfo*& info = item->data; + + if (info->gunStatus == LG_HANDS_FREE && // Hands are free. + !(TrInput & (IN_FLARE | IN_DRAW)) && // Avoid unsightly concurrent actions. + (info->gunType != WEAPON_FLARE || info->flareAge > 0)) // Not handling flare. + { + return true; + } + + return false; +} + +bool TestLaraCrouchRoll(ITEM_INFO* item, COLL_INFO* coll) +{ + LaraInfo*& info = item->data; + + auto y = item->pos.yPos; + auto probe = GetCollisionResult(item, item->pos.yRot, WALL_SIZE / 2, 0); + + if ((probe.Position.Floor - y) <= (CLICK(1) - 1) && // Lower floor bound. + (probe.Position.Floor - y) >= -(CLICK(1) - 1) && // Upper floor bound. + (probe.Position.Ceiling - y) < -LARA_HEIGHT_CRAWL && // Lowest ceiling bound. + !probe.Position.Slope && // Not a slope. + info->waterSurfaceDist >= -CLICK(1) && // Water depth is optically feasible for action. + !(TrInput & (IN_FLARE | IN_DRAW)) && // Avoid unsightly concurrent actions. + (info->gunType != WEAPON_FLARE || info->flareAge > 0)) // Not handling flare. + { + return true; + } + + return false; +} + +bool TestLaraCrawlUpStep(ITEM_INFO* item, COLL_INFO* coll) +{ + auto y = item->pos.yPos; + auto probeA = GetCollisionResult(item, item->pos.yRot, CLICK(1), 0); // Crossing. + auto probeB = GetCollisionResult(item, item->pos.yRot, CLICK(2), 0); // Approximate destination. + + if ((probeA.Position.Floor - y) <= -CLICK(1) && // Lower floor bound. Synced with crawl states' BadHeightUp. + (probeA.Position.Floor - y) >= -STEPUP_HEIGHT && // Upper floor bound. + abs(probeA.Position.Floor - probeB.Position.Floor) <= (CLICK(1) - 1) && // Destination height is within idle threshold. + ((coll->Front.Ceiling - LARA_HEIGHT_CRAWL) - (probeA.Position.Floor - y)) <= -(CLICK(0.5f) + CLICK(1) / 8) && // Gap is optically feasible for action. + abs(probeA.Position.Ceiling - probeA.Position.Floor) > LARA_HEIGHT_CRAWL && // Crossing is not a clamp. + abs(probeB.Position.Ceiling - probeB.Position.Floor) > LARA_HEIGHT_CRAWL && // Destination is not a clamp. + !probeA.Position.Slope && !probeB.Position.Slope && // No slopes. + probeA.Position.Floor != NO_HEIGHT && probeB.Position.Floor != NO_HEIGHT) + { + return true; + } + + return false; +} + +bool TestLaraCrawlDownStep(ITEM_INFO* item, COLL_INFO* coll) +{ + auto y = item->pos.yPos; + auto probeA = GetCollisionResult(item, item->pos.yRot, CLICK(1), 0); // Crossing. + auto probeB = GetCollisionResult(item, item->pos.yRot, CLICK(2), 0); // Approximate destination. + + if ((probeA.Position.Floor - y) <= STEPUP_HEIGHT && // Lower floor bound. Synced with crawl exit jump's highest floor bound. + (probeA.Position.Floor - y) >= CLICK(1) && // Upper floor bound. Synced with crawl states' BadHeightDown. + abs(probeA.Position.Floor - probeB.Position.Floor) <= (CLICK(1) - 1) && // Destination height is within idle threshold. + (probeA.Position.Ceiling - y) <= -CLICK(0.75f) && // Gap is optically feasible for action. + abs(probeA.Position.Ceiling - probeA.Position.Floor) > LARA_HEIGHT_CRAWL && // Crossing is not a clamp. + abs(probeB.Position.Ceiling - probeB.Position.Floor) > LARA_HEIGHT_CRAWL && // Destination is not a clamp. + !probeA.Position.Slope && !probeB.Position.Slope && // No slopes. + probeA.Position.Floor != NO_HEIGHT && probeB.Position.Floor != NO_HEIGHT) + { + return true; + } + + return false; +} + +bool TestLaraCrawlExitDownStep(ITEM_INFO* item, COLL_INFO* coll) +{ + auto y = item->pos.yPos; + auto probeA = GetCollisionResult(item, item->pos.yRot, CLICK(1), 0); // Crossing. + auto probeB = GetCollisionResult(item, item->pos.yRot, CLICK(1.5f), 0); // Approximate destination. + + if ((((probeA.Position.Floor - y) <= STEPUP_HEIGHT && // Lower floor bound. Synced with crawl exit jump's highest floor bound. + (probeA.Position.Floor - y) >= CLICK(1)) || // Upper floor bound. Synced with crawl states' BadHeightDown. OR + (probeA.Position.Slope && probeB.Position.Slope)) && // Slopes ahead. + (probeA.Position.Ceiling - y) <= -CLICK(1.25f) && // Gap is optically feasible for action. + abs(probeA.Position.Ceiling - probeA.Position.Floor) > LARA_HEIGHT && // Crossing is not a clamp. + abs(probeB.Position.Ceiling - probeB.Position.Floor) > LARA_HEIGHT && // Destination is not a clamp. + probeA.Position.Floor != NO_HEIGHT && probeB.Position.Floor != NO_HEIGHT) + { + return true; + } + + return false; +} + +bool TestLaraCrawlExitJump(ITEM_INFO* item, COLL_INFO* coll) +{ + auto y = item->pos.yPos; + auto probeA = GetCollisionResult(item, item->pos.yRot, CLICK(1), 0); // Crossing. + auto probeB = GetCollisionResult(item, item->pos.yRot, CLICK(1.5f), 0); // Approximate destination. + + if ((probeA.Position.Floor - y) > STEPUP_HEIGHT && // Highest floor bound. Synced with crawl down step and crawl exit down step's lower floor bounds. + (probeA.Position.Ceiling - y) <= -CLICK(1.25f) && // Gap is optically feasible for action. + abs(probeA.Position.Ceiling - probeA.Position.Floor) > LARA_HEIGHT && // Crossing is not a clamp. + abs(probeB.Position.Ceiling - probeB.Position.Floor) > LARA_HEIGHT && // Destination is not a clamp. + probeA.Position.Floor != NO_HEIGHT && probeB.Position.Floor != NO_HEIGHT) + { + return true; + } + + return false; +} + +bool TestLaraCrawlVault(ITEM_INFO* item, COLL_INFO* coll) +{ + if (TestLaraCrawlExitJump(item, coll) || + TestLaraCrawlExitDownStep(item, coll) || + TestLaraCrawlUpStep(item, coll) || + TestLaraCrawlDownStep(item, coll)) + { + return true; + } + + return false; +} + +bool TestLaraCrawlToHang(ITEM_INFO* item, COLL_INFO* coll) +{ + auto y = item->pos.yPos; + auto probe = GetCollisionResult(item, item->pos.yRot + ANGLE(180.0f), CLICK(1), 0); + auto objectCollided = TestLaraObjectCollision(item, item->pos.yRot + ANGLE(180.0f), CLICK(1), 0); + + if (!objectCollided && // No obstruction. + (probe.Position.Floor - y) >= LARA_HEIGHT_STRETCH && // Highest floor bound. + (probe.Position.Ceiling - y) <= -CLICK(0.75f) && // Gap is optically feasible for action. + probe.Position.Floor != NO_HEIGHT) + { + return true; + } + + return false; +} + bool TestLaraPoleCollision(ITEM_INFO* item, COLL_INFO* coll, bool up, float offset) { static constexpr auto poleProbeCollRadius = 16.0f; @@ -1310,7 +1798,7 @@ bool TestLaraPoleCollision(ITEM_INFO* item, COLL_INFO* coll, bool up, float offs // HACK: because Core implemented upward pole movement as SetPosition command, we can't precisely // check her position. So we add a fixed height offset. - auto sphere = BoundingSphere(laraBox.Center + Vector3(0, (laraBox.Extents.y + poleProbeCollRadius + offset) * (up ? -1 : 1) , 0), poleProbeCollRadius); + auto sphere = BoundingSphere(laraBox.Center + Vector3(0, (laraBox.Extents.y + poleProbeCollRadius + offset) * (up ? -1 : 1), 0), poleProbeCollRadius); //g_Renderer.addDebugSphere(sphere.Center, 16.0f, Vector4(1, 0, 0, 1), RENDERER_DEBUG_PAGE::LOGIC_STATS); @@ -1339,75 +1827,19 @@ bool TestLaraPoleCollision(ITEM_INFO* item, COLL_INFO* coll, bool up, float offs return atLeastOnePoleCollided; } -void TestLaraWaterDepth(ITEM_INFO* item, COLL_INFO* coll) +bool TestLaraPoleUp(ITEM_INFO* item, COLL_INFO* coll) { - short roomNumber = item->roomNumber; - FLOOR_INFO* floor = GetFloor(item->pos.xPos, item->pos.yPos, item->pos.zPos, &roomNumber); - int waterDepth = GetWaterDepth(item->pos.xPos, item->pos.yPos, item->pos.zPos, roomNumber); - - if (waterDepth == NO_HEIGHT) - { - item->fallspeed = 0; - item->pos.xPos = coll->Setup.OldPosition.x; - item->pos.yPos = coll->Setup.OldPosition.y; - item->pos.zPos = coll->Setup.OldPosition.z; - } - // Height check was at STEP_SIZE * 2 before but changed to this - // because now Lara surfaces on a head level, not mid-body level. - else if (waterDepth <= LARA_HEIGHT - LARA_HEADROOM / 2) - { - SetAnimation(item, LA_UNDERWATER_TO_STAND); - item->goalAnimState = LS_STOP; - item->pos.zRot = 0; - item->pos.xRot = 0; - item->speed = 0; - item->fallspeed = 0; - item->gravityStatus = false; - Lara.waterStatus = LW_WADE; - item->pos.yPos = GetFloorHeight(floor, item->pos.xPos, item->pos.yPos, item->pos.zPos); - } -} - -#ifndef NEW_TIGHTROPE -void GetTighRopeFallOff(int regularity) { - if(LaraItem->hitPoints <= 0 || LaraItem->hitStatus) - { - SetAnimation(LaraItem, LA_TIGHTROPE_FALL_LEFT); - } - - if(!Lara.tightRopeFall && !(GetRandomControl() & regularity)) - Lara.tightRopeFall = 2 - ((GetRandomControl() & 0xF) != 0); -} -#endif // !NEW_TIGHTROPE - -bool TestLaraLean(ITEM_INFO* item, COLL_INFO* coll) -{ -#if 0 - // TODO: make it more fine-tuned when new collision is done. - switch (coll->CollisionType) - { - case CT_RIGHT: - if (TrInput & IN_RIGHT) - return false; - case CT_LEFT: - if (TrInput & IN_LEFT) - return false; - } - return true; -#else - if (coll->CollisionType == CT_RIGHT || coll->CollisionType == CT_LEFT) + if (!TestLaraPoleCollision(item, coll, true, CLICK(1))) return false; - return true; -#endif + // TODO: Accuracy. + return (coll->Middle.Ceiling < -CLICK(1)); } -bool TestLaraSwamp(ITEM_INFO* item) +bool TestLaraPoleDown(ITEM_INFO* item, COLL_INFO* coll) { - return (g_Level.Rooms[item->roomNumber].flags & ENV_FLAG_SWAMP) != 0; -} + if (!TestLaraPoleCollision(item, coll, false)) + return false; -bool TestLaraWater(ITEM_INFO* item) -{ - return (g_Level.Rooms[item->roomNumber].flags & ENV_FLAG_WATER) != 0; + return (coll->Middle.Floor > 0); } diff --git a/TR5Main/Game/Lara/lara_tests.h b/TR5Main/Game/Lara/lara_tests.h index 015d7b982..298bb44cd 100644 --- a/TR5Main/Game/Lara/lara_tests.h +++ b/TR5Main/Game/Lara/lara_tests.h @@ -1,18 +1,23 @@ #pragma once #include "collide.h" +#include "lara_struct.h" struct ITEM_INFO; struct COLL_INFO; +// ----------------------------- +// TEST FUNCTIONS +// For State Control & Collision +// ----------------------------- + SPLAT_COLL TestLaraWall(ITEM_INFO* item, int front, int right, int down); bool TestValidLedge(ITEM_INFO* item, COLL_INFO* coll, bool ignoreHeadroom = false, bool heightLimit = false); bool TestValidLedgeAngle(ITEM_INFO* item, COLL_INFO* coll); bool TestLaraVault(ITEM_INFO* item, COLL_INFO* coll); -bool TestLaraStandUp(COLL_INFO* coll); +bool TestLaraKeepCrouched(ITEM_INFO* item, COLL_INFO* coll); bool TestLaraSlide(ITEM_INFO* item, COLL_INFO* coll); bool TestLaraSwamp(ITEM_INFO* item); bool TestLaraWater(ITEM_INFO* item); -bool TestLaraLean(ITEM_INFO* item, COLL_INFO* coll); bool TestLaraHang(ITEM_INFO* item, COLL_INFO* coll); bool TestLaraHangJump(ITEM_INFO* item, COLL_INFO* coll); bool TestLaraHangJumpUp(ITEM_INFO* item, COLL_INFO* coll); @@ -23,8 +28,9 @@ bool TestLaraValidHangPos(ITEM_INFO* item, COLL_INFO* coll); CORNER_RESULT TestLaraHangCorner(ITEM_INFO* item, COLL_INFO* coll, float testAngle); bool TestHangSwingIn(ITEM_INFO* item, short angle); bool TestLaraHangSideways(ITEM_INFO* item, COLL_INFO* coll, short angle); -bool LaraFacingCorner(ITEM_INFO* item, short ang, int dist); bool LaraPositionOnLOS(ITEM_INFO* item, short ang, int dist); +bool TestLaraFacingCorner(ITEM_INFO* item, short angle, int dist); +bool TestLaraStandingJump(ITEM_INFO* item, COLL_INFO* coll, short angle); int LaraFloorFront(ITEM_INFO* item, short ang, int dist); int LaraCeilingFront(ITEM_INFO* item, short ang, int dist, int h); @@ -32,6 +38,7 @@ COLL_RESULT LaraCollisionFront(ITEM_INFO* item, short ang, int dist); COLL_RESULT LaraCeilingCollisionFront(ITEM_INFO* item, short ang, int dist, int h); COLL_RESULT LaraCollisionAboveFront(ITEM_INFO* item, short ang, int dist, int h); +bool TestLaraFall(ITEM_INFO* item, COLL_INFO* coll); bool LaraFallen(ITEM_INFO* item, COLL_INFO* coll); bool LaraLandedBad(ITEM_INFO* item, COLL_INFO* coll); @@ -39,8 +46,41 @@ bool TestLaraWaterStepOut(ITEM_INFO* item, COLL_INFO* coll); bool TestLaraWaterClimbOut(ITEM_INFO* item, COLL_INFO* coll); bool TestLaraLadderClimbOut(ITEM_INFO* item, COLL_INFO* coll); void TestLaraWaterDepth(ITEM_INFO* item, COLL_INFO* coll); -bool TestLaraPoleCollision(ITEM_INFO* item, COLL_INFO* coll, bool up, float offset = 0.0f); #ifndef NEW_TIGHTROPE void GetTighRopeFallOff(int Regularity); -#endif // !NEW_TIGHTROPE +#endif + +bool IsStandingWeapon(LARA_WEAPON_TYPE gunType); + +bool TestLaraPose(ITEM_INFO* item, COLL_INFO* coll); +bool TestLaraStep(COLL_INFO* coll); +bool TestLaraStepUp(ITEM_INFO* item, COLL_INFO* coll); +bool TestLaraStepDown(ITEM_INFO* item, COLL_INFO* coll); + +bool TestLaraMove(ITEM_INFO* item, COLL_INFO* coll, short angle, int lowerBound, int upperBound, bool checkSlope = true, bool checkDeath = true); +bool TestLaraMoveCrawl(ITEM_INFO* item, COLL_INFO* coll, short angle, int lowerBound, int upperBound, bool checkSlope = true, bool checkDeath = true); +bool TestLaraRunForward(ITEM_INFO* item, COLL_INFO* coll); +bool TestLaraWalkForward(ITEM_INFO* item, COLL_INFO* coll); +bool TestLaraWalkBack(ITEM_INFO* item, COLL_INFO* coll); +bool TestLaraHopBack(ITEM_INFO* item, COLL_INFO* coll); +bool TestLaraStepLeft(ITEM_INFO* item, COLL_INFO* coll); +bool TestLaraStepRight(ITEM_INFO* item, COLL_INFO* coll); +bool TestLaraWalkBackSwamp(ITEM_INFO* item, COLL_INFO* coll); +bool TestLaraStepLeftSwamp(ITEM_INFO* item, COLL_INFO* coll); +bool TestLaraStepRightSwamp(ITEM_INFO* item, COLL_INFO* coll); +bool TestLaraCrawlForward(ITEM_INFO* item, COLL_INFO* coll); +bool TestLaraCrawlBack(ITEM_INFO* item, COLL_INFO* coll); + +bool TestLaraCrouchToCrawl(ITEM_INFO* item); +bool TestLaraCrouchRoll(ITEM_INFO* item, COLL_INFO* coll); +bool TestLaraCrawlUpStep(ITEM_INFO* item, COLL_INFO* coll); +bool TestLaraCrawlDownStep(ITEM_INFO* item, COLL_INFO* coll); +bool TestLaraCrawlExitDownStep(ITEM_INFO* item, COLL_INFO* coll); +bool TestLaraCrawlExitJump(ITEM_INFO* item, COLL_INFO* coll); +bool TestLaraCrawlVault(ITEM_INFO* item, COLL_INFO* coll); +bool TestLaraCrawlToHang(ITEM_INFO* item, COLL_INFO* coll); + +bool TestLaraPoleCollision(ITEM_INFO* item, COLL_INFO* coll, bool up, float offset = 0.0f); +bool TestLaraPoleUp(ITEM_INFO* item, COLL_INFO* coll); +bool TestLaraPoleDown(ITEM_INFO* item, COLL_INFO* coll); diff --git a/TR5Main/Game/Lara/lara_two_guns.cpp b/TR5Main/Game/Lara/lara_two_guns.cpp index 487831a7a..ef82343e8 100644 --- a/TR5Main/Game/Lara/lara_two_guns.cpp +++ b/TR5Main/Game/Lara/lara_two_guns.cpp @@ -472,7 +472,7 @@ void undraw_pistols(LARA_WEAPON_TYPE weaponType) if (frameLeft == p->draw1Anim && frameRight == p->draw1Anim) { - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; Lara.leftArm.frameNumber = 0; Lara.rightArm.frameNumber = 0; Lara.target = NULL; diff --git a/TR5Main/Game/animation.cpp b/TR5Main/Game/animation.cpp index 76f22228a..e837c7fe8 100644 --- a/TR5Main/Game/animation.cpp +++ b/TR5Main/Game/animation.cpp @@ -198,13 +198,13 @@ void TranslateItem(ITEM_INFO* item, int x, int y, int z) item->pos.zPos += -s * x + c * z; } -int GetChange(ITEM_INFO* item, ANIM_STRUCT* anim) +bool GetChange(ITEM_INFO* item, ANIM_STRUCT* anim) { if (item->currentAnimState == item->goalAnimState) - return 0; + return false; if (anim->numberChanges <= 0) - return 0; + return false; for (int i = 0; i < anim->numberChanges; i++) { @@ -219,13 +219,13 @@ int GetChange(ITEM_INFO* item, ANIM_STRUCT* anim) item->animNumber = range->linkAnimNum; item->frameNumber = range->linkFrameNum; - return 1; + return true; } } } } - return 0; + return false; } BOUNDING_BOX* GetBoundsAccurate(ITEM_INFO* item) diff --git a/TR5Main/Game/animation.h b/TR5Main/Game/animation.h index 3f4629e15..108c7ff03 100644 --- a/TR5Main/Game/animation.h +++ b/TR5Main/Game/animation.h @@ -61,7 +61,7 @@ short GetFrameNumber(short objectID, short animNumber, short frameToStart); int GetFrameCount(short animNumber); int GetNextAnimState(ITEM_INFO* item); int GetNextAnimState(short objectID, short animNumber); -int GetChange(ITEM_INFO* item, ANIM_STRUCT* anim); +bool GetChange(ITEM_INFO* item, ANIM_STRUCT* anim); int GetFrame(ITEM_INFO* item, ANIM_FRAME* framePtr[], int* rate); ANIM_FRAME* GetBestFrame(ITEM_INFO* item); BOUNDING_BOX* GetBoundsAccurate(ITEM_INFO* item); diff --git a/TR5Main/Game/camera.cpp b/TR5Main/Game/camera.cpp index 157dcc421..f30cae63f 100644 --- a/TR5Main/Game/camera.cpp +++ b/TR5Main/Game/camera.cpp @@ -1758,34 +1758,44 @@ void LookUpDown() } } -void ResetLook() +void ResetLook(ITEM_INFO* item) { + LaraInfo*& info = item->data; + if (Camera.type != CAMERA_TYPE::LOOK_CAMERA) { - if (Lara.headXrot <= -ANGLE(2.0f) || Lara.headXrot >= ANGLE(2.0f)) - Lara.headXrot = Lara.headXrot / -8 + Lara.headXrot; + if (abs(info->headXrot) > ANGLE(0.1f)) + info->headXrot += info->headXrot / -8; else - Lara.headXrot = 0; + info->headXrot = 0; - if (Lara.headYrot <= -ANGLE(2.0f) || Lara.headYrot >= ANGLE(2.0f)) - Lara.headYrot = Lara.headYrot / -8 + Lara.headYrot; + if (abs(info->headYrot) > ANGLE(0.1f)) + info->headYrot += info->headYrot / -8; else - Lara.headYrot = 0; + info->headYrot = 0; - if (Lara.gunStatus != LG_HANDS_BUSY && - !Lara.leftArm.lock && - !Lara.rightArm.lock && - Lara.Vehicle == NO_ITEM) + if (abs(info->headZrot) > ANGLE(0.1f)) + info->headZrot += info->headZrot / -8; + else + info->headZrot = 0; + + if (info->gunStatus != LG_HANDS_BUSY && + !info->leftArm.lock && + !info->rightArm.lock && + info->Vehicle == NO_ITEM) { - Lara.torsoYrot = Lara.headYrot; - Lara.torsoXrot = Lara.headXrot; + info->torsoXrot = info->headXrot; + info->torsoYrot = info->headYrot; + info->torsoZrot = info->headZrot; } else { - if (!Lara.headXrot) - Lara.torsoXrot = 0; - if (!Lara.headYrot) - Lara.torsoYrot = 0; + if (!info->headXrot) + info->torsoXrot = 0; + if (!info->headYrot) + info->torsoYrot = 0; + if (!info->headZrot) + info->torsoZrot = 0; } } } diff --git a/TR5Main/Game/camera.h b/TR5Main/Game/camera.h index 92ff85b07..a08f7117c 100644 --- a/TR5Main/Game/camera.h +++ b/TR5Main/Game/camera.h @@ -79,7 +79,7 @@ void ConfirmCameraTargetPos(); void CalculateCamera(); void LookLeftRight(); void LookUpDown(); -void ResetLook(); +void ResetLook(ITEM_INFO* item); void RumbleScreen(); bool TestBoundsCollideCamera(BOUNDING_BOX* bounds, PHD_3DPOS* pos, short radius); void ItemPushCamera(BOUNDING_BOX* bounds, PHD_3DPOS* pos, short radius); diff --git a/TR5Main/Game/collide.cpp b/TR5Main/Game/collide.cpp index b951c758c..b5ad7d5dc 100644 --- a/TR5Main/Game/collide.cpp +++ b/TR5Main/Game/collide.cpp @@ -610,9 +610,9 @@ void ShiftItem(ITEM_INFO* item, COLL_INFO* coll) item->pos.xPos += coll->Shift.x; item->pos.yPos += coll->Shift.y; item->pos.zPos += coll->Shift.z; - coll->Shift.z = 0; - coll->Shift.y = 0; coll->Shift.x = 0; + coll->Shift.y = 0; + coll->Shift.z = 0; } void MoveItem(ITEM_INFO* item, short angle, int x, int y) @@ -845,7 +845,7 @@ bool ItemPushStatic(ITEM_INFO* item, MESH_INFO* mesh, COLL_INFO* coll) // previo if (item == LaraItem && Lara.isMoving && Lara.moveCount > 15) { Lara.isMoving = false; - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; } return true; @@ -965,7 +965,7 @@ bool ItemPushItem(ITEM_INFO* item, ITEM_INFO* item2, COLL_INFO* coll, bool spazo if (lara != nullptr && lara->moveCount > 15) { Lara.isMoving = false; - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; } return true; @@ -1190,7 +1190,7 @@ bool MoveLaraPosition(PHD_VECTOR* vec, ITEM_INFO* item, ITEM_INFO* l) if (Lara.isMoving) { Lara.isMoving = false; - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; } return false; @@ -1543,7 +1543,7 @@ void GetCollisionInfo(COLL_INFO* coll, ITEM_INFO* item, PHD_VECTOR offset, bool coll->Front.Floor = STOP_SIZE; } else if (coll->Setup.DeathFlagIsPit && - coll->Front.Floor > 0 && + coll->MiddleLeft.Floor >= STEP_SIZE / 2 && collResult.BottomBlock->Flags.Death) { coll->Front.Floor = STOP_SIZE; @@ -1591,7 +1591,7 @@ void GetCollisionInfo(COLL_INFO* coll, ITEM_INFO* item, PHD_VECTOR offset, bool coll->MiddleLeft.Floor = STOP_SIZE; } else if (coll->Setup.DeathFlagIsPit && - coll->MiddleLeft.Floor > 0 && + coll->MiddleLeft.Floor >= STEP_SIZE / 2 && collResult.BottomBlock->Flags.Death) { coll->MiddleLeft.Floor = STOP_SIZE; @@ -1634,7 +1634,7 @@ void GetCollisionInfo(COLL_INFO* coll, ITEM_INFO* item, PHD_VECTOR offset, bool coll->FrontLeft.Floor = STOP_SIZE; } else if (coll->Setup.DeathFlagIsPit && - coll->FrontLeft.Floor > 0 && + coll->MiddleLeft.Floor >= STEP_SIZE / 2 && collResult.BottomBlock->Flags.Death) { coll->FrontLeft.Floor = STOP_SIZE; @@ -1682,7 +1682,7 @@ void GetCollisionInfo(COLL_INFO* coll, ITEM_INFO* item, PHD_VECTOR offset, bool coll->MiddleRight.Floor = STOP_SIZE; } else if (coll->Setup.DeathFlagIsPit && - coll->MiddleRight.Floor > 0 && + coll->MiddleLeft.Floor >= STEP_SIZE / 2 && collResult.BottomBlock->Flags.Death) { coll->MiddleRight.Floor = STOP_SIZE; @@ -1725,7 +1725,7 @@ void GetCollisionInfo(COLL_INFO* coll, ITEM_INFO* item, PHD_VECTOR offset, bool coll->FrontRight.Floor = STOP_SIZE; } else if (coll->Setup.DeathFlagIsPit && - coll->FrontRight.Floor > 0 && + coll->MiddleLeft.Floor >= STEP_SIZE / 2 && collResult.BottomBlock->Flags.Death) { coll->FrontRight.Floor = STOP_SIZE; @@ -1762,9 +1762,10 @@ void GetCollisionInfo(COLL_INFO* coll, ITEM_INFO* item, PHD_VECTOR offset, bool coll->CollisionType = CT_TOP; } - if (coll->Front.Floor > coll->Setup.BadHeightDown || + if (coll->Front.Floor > coll->Setup.BadHeightDown || coll->Front.Floor < coll->Setup.BadHeightUp || - coll->Front.Ceiling > coll->Setup.BadCeilingHeight) + coll->Front.Ceiling > coll->Setup.BadCeilingHeight || + coll->Front.Floor - coll->Front.Ceiling <= 0) { if (coll->Front.HasDiagonalSplit()) { @@ -1804,7 +1805,8 @@ void GetCollisionInfo(COLL_INFO* coll, ITEM_INFO* item, PHD_VECTOR offset, bool if (coll->MiddleLeft.Floor > coll->Setup.BadHeightDown || coll->MiddleLeft.Floor < coll->Setup.BadHeightUp || - coll->MiddleLeft.Ceiling > coll->Setup.BadCeilingHeight) + coll->MiddleLeft.Ceiling > coll->Setup.BadCeilingHeight || + coll->MiddleLeft.Floor - coll->MiddleLeft.Ceiling <= 0) { if (coll->TriangleAtLeft() && !coll->MiddleLeft.Slope) { @@ -1854,7 +1856,8 @@ void GetCollisionInfo(COLL_INFO* coll, ITEM_INFO* item, PHD_VECTOR offset, bool if (coll->MiddleRight.Floor > coll->Setup.BadHeightDown || coll->MiddleRight.Floor < coll->Setup.BadHeightUp || - coll->MiddleRight.Ceiling > coll->Setup.BadCeilingHeight) + coll->MiddleRight.Ceiling > coll->Setup.BadCeilingHeight || + coll->MiddleRight.Floor - coll->MiddleRight.Ceiling <= 0) { if (coll->TriangleAtRight() && !coll->MiddleRight.Slope) { diff --git a/TR5Main/Game/control/control.cpp b/TR5Main/Game/control/control.cpp index e311511a7..b0ffe0f77 100644 --- a/TR5Main/Game/control/control.cpp +++ b/TR5Main/Game/control/control.cpp @@ -6,7 +6,6 @@ #include "pickup.h" #include "camera.h" #include "Lara.h" -#include "effects/hair.h" #include "items.h" #include "flipeffect.h" #include "gui.h" @@ -22,15 +21,17 @@ #include "input.h" #include "setup.h" #include "room.h" -#include "effects/effects.h" -#include "effects/tomb4fx.h" -#include "effects/debris.h" -#include "effects/footprint.h" -#include "effects/smoke.h" -#include "effects/spark.h" -#include "effects/explosion.h" -#include "effects/drip.h" -#include "effects/weather.h" +#include "Game/effects/hair.h" +#include "Game/effects/effects.h" +#include "Game/effects/tomb4fx.h" +#include "Game/effects/debris.h" +#include "Game/effects/footprint.h" +#include "Game/effects/smoke.h" +#include "Game/effects/spark.h" +#include "Game/effects/explosion.h" +#include "Game/effects/drip.h" +#include "Game/effects/weather.h" +#include "Game/effects/lightning.h" #include "tr5_rats_emitter.h" #include "tr5_bats_emitter.h" #include "tr5_spider_emitter.h" @@ -40,9 +41,10 @@ #include "Specific/prng.h" #include "Specific/clock.h" #include "Lara/lara_one_gun.h" +#include "Lara/lara_cheat.h" +#include "Lara/lara_helpers.h" #include "generic_switch.h" #include "Scripting/GameFlowScript.h" -#include "Game/effects/lightning.h" using std::vector; using std::unordered_map; @@ -110,8 +112,8 @@ GAME_STATUS ControlPhase(int numFrames, int demoMode) g_GameScript->ProcessDisplayStrings(DELTA_TIME); - static int FramesCount = 0; - for (FramesCount += numFrames; FramesCount > 0; FramesCount -= 2) + static int framesCount = 0; + for (framesCount += numFrames; framesCount > 0; framesCount -= 2) { GlobalCounter++; @@ -210,7 +212,7 @@ GAME_STATUS ControlPhase(int numFrames, int demoMode) if (CurrentLevel != 0) { if (!(TrInput & IN_LOOK) || UseSpotCam || TrackCameraInit || - ((LaraItem->currentAnimState != LS_STOP || LaraItem->animNumber != LA_STAND_IDLE) && (!Lara.isDucked || TrInput & IN_DUCK || LaraItem->animNumber != LA_CROUCH_IDLE || LaraItem->goalAnimState != LS_CROUCH_IDLE))) + ((LaraItem->currentAnimState != LS_IDLE || LaraItem->animNumber != LA_STAND_IDLE) && (!Lara.isDucked || TrInput & IN_DUCK || LaraItem->animNumber != LA_CROUCH_IDLE || LaraItem->goalAnimState != LS_CROUCH_IDLE))) { if (BinocularRange == 0) { @@ -232,11 +234,7 @@ GAME_STATUS ControlPhase(int numFrames, int demoMode) Lara.busy = false; Camera.type = BinocularOldCamera; - Lara.headYrot = 0; - Lara.headXrot = 0; - - Lara.torsoYrot = 0; - Lara.torsoXrot = 0; + ResetLaraFlex(LaraItem); Camera.bounce = 0; BinocularOn = -8; @@ -325,7 +323,6 @@ GAME_STATUS ControlPhase(int numFrames, int demoMode) if (CurrentLevel != 0) { - // Control Lara InItemControlLoop = true; LaraControl(LaraItem, &LaraCollision); @@ -340,10 +337,11 @@ GAME_STATUS ControlPhase(int numFrames, int demoMode) g_Gui.SetInventoryItemChosen(NO_ITEM); } + LaraCheatyBits(); + TriggerLaraDrips(LaraItem); + // Update Lara's ponytails - HairControl(0, 0, 0); - if (level->LaraType == LaraType::Young) - HairControl(0, 1, 0); + HairControl(LaraItem, level->LaraType == LaraType::Young); } if (UseSpotCam) diff --git a/TR5Main/Game/effects/effects.cpp b/TR5Main/Game/effects/effects.cpp index 04feef7c2..152a9e5de 100644 --- a/TR5Main/Game/effects/effects.cpp +++ b/TR5Main/Game/effects/effects.cpp @@ -1238,16 +1238,12 @@ void WadeSplash(ITEM_INFO* item, int wh, int wd) { if (!(Wibble & 0xF)) { - if (!(GetRandomControl() & 0xF) || item->currentAnimState != LS_STOP) + if (!(GetRandomControl() & 0xF) || item->currentAnimState != LS_IDLE) { - if (item->currentAnimState == LS_STOP) - { + if (item->currentAnimState == LS_IDLE) SetupRipple(item->pos.xPos, wh - 1, item->pos.zPos, (GetRandomControl() & 0xF) + 112, RIPPLE_FLAG_RAND_ROT | RIPPLE_FLAG_RAND_POS, Objects[ID_DEFAULT_SPRITES].meshIndex + SPR_RIPPLES); - } else - { SetupRipple(item->pos.xPos, wh - 1, item->pos.zPos, (GetRandomControl() & 0xF) + 112, RIPPLE_FLAG_RAND_ROT | RIPPLE_FLAG_RAND_POS, Objects[ID_DEFAULT_SPRITES].meshIndex + SPR_RIPPLES); - } } } } diff --git a/TR5Main/Game/effects/hair.cpp b/TR5Main/Game/effects/hair.cpp index f4797bd50..99f01604f 100644 --- a/TR5Main/Game/effects/hair.cpp +++ b/TR5Main/Game/effects/hair.cpp @@ -41,7 +41,14 @@ void InitialiseHair() } } -void HairControl(int cutscene, int ponytail, ANIM_FRAME* framePtr) +void HairControl(ITEM_INFO* item, bool young) +{ + HairControl(item, 0, 0); + if (young) + HairControl(item, 1, 0); +} + +void HairControl(ITEM_INFO* item, int ponytail, ANIM_FRAME* framePtr) { SPHERE sphere[HAIR_SPHERE]; OBJECT_INFO* object = &Objects[ID_LARA]; @@ -49,45 +56,47 @@ void HairControl(int cutscene, int ponytail, ANIM_FRAME* framePtr) int spaz; bool youngLara = g_GameFlow->GetLevel(CurrentLevel)->LaraType == LaraType::Young; + LaraInfo*& lara = item->data; + if (framePtr == NULL) { - if (Lara.hitDirection >= 0) + if (lara->hitDirection >= 0) { - switch (Lara.hitDirection) + switch (lara->hitDirection) { case NORTH: - if (Lara.isDucked) + if (lara->isDucked) spaz = 294; else spaz = 125; break; case SOUTH: - if (Lara.isDucked) + if (lara->isDucked) spaz = 293; else spaz = 126; break; case EAST: - if (Lara.isDucked) + if (lara->isDucked) spaz = 295; else spaz = 127; break; default: - if (Lara.isDucked) + if (lara->isDucked) spaz = 296; else spaz = 128; break; } - frame = &g_Level.Frames[g_Level.Anims[spaz].framePtr + Lara.hitFrame]; + frame = &g_Level.Frames[g_Level.Anims[spaz].framePtr + lara->hitFrame]; } else - frame = GetBestFrame(LaraItem); + frame = GetBestFrame(item); } else { @@ -95,7 +104,7 @@ void HairControl(int cutscene, int ponytail, ANIM_FRAME* framePtr) } // Get Lara's spheres in absolute coords, for head, torso, hips and upper arms - MESH* mesh = &g_Level.Meshes[Lara.meshPtrs[LM_HIPS]]; + MESH* mesh = &g_Level.Meshes[lara->meshPtrs[LM_HIPS]]; PHD_VECTOR pos = { (int)mesh->sphere.Center.x, (int)mesh->sphere.Center.y, (int)mesh->sphere.Center.z }; GetLaraJointPosition(&pos, LM_HIPS); sphere[0].x = pos.x; @@ -103,7 +112,7 @@ void HairControl(int cutscene, int ponytail, ANIM_FRAME* framePtr) sphere[0].z = pos.z; sphere[0].r = (int)mesh->sphere.Radius; - mesh = &g_Level.Meshes[Lara.meshPtrs[LM_TORSO]]; + mesh = &g_Level.Meshes[lara->meshPtrs[LM_TORSO]]; pos = { (int)mesh->sphere.Center.x - 10, (int)mesh->sphere.Center.y, (int)mesh->sphere.Center.z + 25 }; // Repositioning sphere - from tomb5 GetLaraJointPosition(&pos, LM_TORSO); sphere[1].x = pos.x; @@ -113,7 +122,7 @@ void HairControl(int cutscene, int ponytail, ANIM_FRAME* framePtr) if (youngLara) sphere[1].r = sphere[1].r - ((sphere[1].r >> 2) + (sphere[1].r >> 3)); - mesh = &g_Level.Meshes[Lara.meshPtrs[LM_HEAD]]; + mesh = &g_Level.Meshes[lara->meshPtrs[LM_HEAD]]; pos = { (int)mesh->sphere.Center.x - 2, (int)mesh->sphere.Center.y, (int)mesh->sphere.Center.z }; // Repositioning sphere - from tomb5 GetLaraJointPosition(&pos, LM_HEAD); sphere[2].x = pos.x; @@ -121,7 +130,7 @@ void HairControl(int cutscene, int ponytail, ANIM_FRAME* framePtr) sphere[2].z = pos.z; sphere[2].r = (int)mesh->sphere.Radius; - mesh = &g_Level.Meshes[Lara.meshPtrs[LM_RINARM]]; + mesh = &g_Level.Meshes[lara->meshPtrs[LM_RINARM]]; pos = { (int)mesh->sphere.Center.x, (int)mesh->sphere.Center.y, (int)mesh->sphere.Center.z }; GetLaraJointPosition(&pos, LM_RINARM); sphere[3].x = pos.x; @@ -129,7 +138,7 @@ void HairControl(int cutscene, int ponytail, ANIM_FRAME* framePtr) sphere[3].z = pos.z; sphere[3].r = (int)(4.0f * mesh->sphere.Radius / 3.0f); // Resizing sphere - from tomb5 - mesh = &g_Level.Meshes[Lara.meshPtrs[LM_LINARM]]; + mesh = &g_Level.Meshes[lara->meshPtrs[LM_LINARM]]; pos = { (int)mesh->sphere.Center.x, (int)mesh->sphere.Center.y, (int)mesh->sphere.Center.z }; GetLaraJointPosition(&pos, LM_LINARM); sphere[4].x = pos.x; @@ -151,7 +160,7 @@ void HairControl(int cutscene, int ponytail, ANIM_FRAME* framePtr) sphere[5].r = youngLara ? 0 : (int)(3.0f * (float)sphere[2].r / 4.0f); Matrix world; - g_Renderer.getBoneMatrix(Lara.itemNumber, LM_HEAD, &world); + g_Renderer.getBoneMatrix(lara->itemNumber, LM_HEAD, &world); if (ponytail) { @@ -197,20 +206,11 @@ void HairControl(int cutscene, int ponytail, ANIM_FRAME* framePtr) Hairs[ponytail][0].pos.yPos = pos.y; Hairs[ponytail][0].pos.zPos = pos.z; - short roomNumber = LaraItem->roomNumber; - int wh; - - if (cutscene) - { - wh = NO_HEIGHT; - } - else - { - int x = LaraItem->pos.xPos + (frame->boundingBox.X1 + frame->boundingBox.X2) / 2; - int y = LaraItem->pos.yPos + (frame->boundingBox.Y1 + frame->boundingBox.Y2) / 2; - int z = LaraItem->pos.zPos + (frame->boundingBox.Z1 + frame->boundingBox.Z2) / 2; - wh = GetWaterHeight(x, y, z, roomNumber); - } + short roomNumber = item->roomNumber; + int x = item->pos.xPos + (frame->boundingBox.X1 + frame->boundingBox.X2) / 2; + int y = item->pos.yPos + (frame->boundingBox.Y1 + frame->boundingBox.Y2) / 2; + int z = item->pos.zPos + (frame->boundingBox.Z1 + frame->boundingBox.Z2) / 2; + int wh = GetWaterHeight(x, y, z, roomNumber); for (int i = 1; i < HAIR_SEGMENTS + 1; i++, bone += 4) { @@ -218,17 +218,8 @@ void HairControl(int cutscene, int ponytail, ANIM_FRAME* framePtr) Hairs[ponytail][0].hvel.y = Hairs[ponytail][i].pos.yPos; Hairs[ponytail][0].hvel.z = Hairs[ponytail][i].pos.zPos; - int height; - - if (!cutscene) - { - FLOOR_INFO* floor = GetFloor(Hairs[ponytail][i].pos.xPos, Hairs[ponytail][i].pos.yPos, Hairs[ponytail][i].pos.zPos, &roomNumber); - height = GetFloorHeight(floor, Hairs[ponytail][i].pos.xPos, Hairs[ponytail][i].pos.yPos, Hairs[ponytail][i].pos.zPos); - } - else - { - height = 32767; - } + auto floor = GetFloor(Hairs[ponytail][i].pos.xPos, Hairs[ponytail][i].pos.yPos, Hairs[ponytail][i].pos.zPos, &roomNumber); + int height = GetFloorHeight(floor, Hairs[ponytail][i].pos.xPos, Hairs[ponytail][i].pos.yPos, Hairs[ponytail][i].pos.zPos); Hairs[ponytail][i].pos.xPos += Hairs[ponytail][i].hvel.x * 3 / 4; Hairs[ponytail][i].pos.yPos += Hairs[ponytail][i].hvel.y * 3 / 4; @@ -236,7 +227,7 @@ void HairControl(int cutscene, int ponytail, ANIM_FRAME* framePtr) // TR3 UPV uses a hack which forces Lara water status to dry. // Therefore, we can't directly use water status value to determine hair mode. - bool dryMode = (Lara.waterStatus == LW_ABOVE_WATER) && (Lara.Vehicle == -1 || g_Level.Items[Lara.Vehicle].objectNumber != ID_UPV); + bool dryMode = (lara->waterStatus == LW_ABOVE_WATER) && (lara->Vehicle == -1 || g_Level.Items[lara->Vehicle].objectNumber != ID_UPV); if (dryMode) { diff --git a/TR5Main/Game/effects/hair.h b/TR5Main/Game/effects/hair.h index f34789dbb..530fc4399 100644 --- a/TR5Main/Game/effects/hair.h +++ b/TR5Main/Game/effects/hair.h @@ -7,6 +7,7 @@ constexpr auto HAIR_SEGMENTS = 6; // classic = 7, young = 14 constexpr auto HAIR_SPHERE = 6; // current hair max collision struct ANIM_FRAME; +struct ITEM_INFO; struct HAIR_STRUCT { @@ -19,4 +20,5 @@ struct HAIR_STRUCT extern HAIR_STRUCT Hairs[HAIR_MAX][HAIR_SEGMENTS + 1]; void InitialiseHair(); -void HairControl(int cutscene, int ponytail, ANIM_FRAME* framePtr); +void HairControl(ITEM_INFO* item, bool young); +void HairControl(ITEM_INFO* item, int ponytail, ANIM_FRAME* framePtr); diff --git a/TR5Main/Game/effects/tomb4fx.cpp b/TR5Main/Game/effects/tomb4fx.cpp index c69408e1e..07cf6ac6d 100644 --- a/TR5Main/Game/effects/tomb4fx.cpp +++ b/TR5Main/Game/effects/tomb4fx.cpp @@ -1157,12 +1157,12 @@ void UpdateDrips() void TriggerLaraDrips(ITEM_INFO* item) { - auto pos = PHD_VECTOR(); - if (!(Wibble & 0xF)) { for (int i = 0; i < NUM_LARA_MESHES; i++) { + auto pos = PHD_VECTOR(); + GetLaraJointPosition(&pos, (LARA_MESHES)i); auto room = GetRoom(item->location, pos.x, pos.y, pos.z).roomNumber; diff --git a/TR5Main/Game/flipeffect.cpp b/TR5Main/Game/flipeffect.cpp index 0b0075e5e..874691570 100644 --- a/TR5Main/Game/flipeffect.cpp +++ b/TR5Main/Game/flipeffect.cpp @@ -172,7 +172,7 @@ void ShootRightGun(ITEM_INFO* item) void LaraHandsFree(ITEM_INFO* item) { - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; } void KillActiveBaddies(ITEM_INFO* item) diff --git a/TR5Main/Game/gui.cpp b/TR5Main/Game/gui.cpp index 0248771e0..4a1d6717a 100644 --- a/TR5Main/Game/gui.cpp +++ b/TR5Main/Game/gui.cpp @@ -2008,7 +2008,7 @@ void GuiController::UseCurrentItem() { Lara.requestGunType = WEAPON_PISTOLS; - if (Lara.gunStatus != LG_NO_ARMS) + if (Lara.gunStatus != LG_HANDS_FREE) return; if (Lara.gunType == WEAPON_PISTOLS) @@ -2021,7 +2021,7 @@ void GuiController::UseCurrentItem() { Lara.requestGunType = WEAPON_UZI; - if (Lara.gunStatus != LG_NO_ARMS) + if (Lara.gunStatus != LG_HANDS_FREE) return; if (Lara.gunType == WEAPON_UZI) @@ -2036,7 +2036,7 @@ void GuiController::UseCurrentItem() { if (gmeobject == ID_FLARE_INV_ITEM) { - if (Lara.gunStatus == LG_NO_ARMS) + if (Lara.gunStatus == LG_HANDS_FREE) { if (LaraItem->currentAnimState != LS_CRAWL_IDLE && LaraItem->currentAnimState != LS_CRAWL_FORWARD && @@ -2064,7 +2064,7 @@ void GuiController::UseCurrentItem() { case INV_OBJECT_BINOCULARS: - if (((LaraItem->currentAnimState == LS_STOP && LaraItem->animNumber == LA_STAND_IDLE) + if (((LaraItem->currentAnimState == LS_IDLE && LaraItem->animNumber == LA_STAND_IDLE) || (Lara.isDucked && !(TrInput & IN_DUCK))) && !UseSpotCam && !TrackCameraInit) @@ -2072,7 +2072,7 @@ void GuiController::UseCurrentItem() Lara.oldBusy = true; BinocularRange = 128; - if (Lara.gunStatus != LG_NO_ARMS) + if (Lara.gunStatus != LG_HANDS_FREE) Lara.gunStatus = LG_UNDRAW_GUNS; } @@ -2166,7 +2166,7 @@ void GuiController::UseCurrentItem() { Lara.requestGunType = WEAPON_SHOTGUN; - if (Lara.gunStatus != LG_NO_ARMS) + if (Lara.gunStatus != LG_HANDS_FREE) return; if (Lara.gunType == WEAPON_SHOTGUN) @@ -2179,7 +2179,7 @@ void GuiController::UseCurrentItem() { Lara.requestGunType = WEAPON_REVOLVER; - if (Lara.gunStatus != LG_NO_ARMS) + if (Lara.gunStatus != LG_HANDS_FREE) return; if (Lara.gunType == WEAPON_REVOLVER) @@ -2191,7 +2191,7 @@ void GuiController::UseCurrentItem() { Lara.requestGunType = WEAPON_HK; - if (Lara.gunStatus != LG_NO_ARMS) + if (Lara.gunStatus != LG_HANDS_FREE) return; if (Lara.gunType == WEAPON_HK) @@ -2203,7 +2203,7 @@ void GuiController::UseCurrentItem() { Lara.requestGunType = WEAPON_CROSSBOW; - if (Lara.gunStatus != LG_NO_ARMS) + if (Lara.gunStatus != LG_HANDS_FREE) return; if (Lara.gunType == WEAPON_CROSSBOW) @@ -2215,7 +2215,7 @@ void GuiController::UseCurrentItem() { Lara.requestGunType = WEAPON_GRENADE_LAUNCHER; - if (Lara.gunStatus != LG_NO_ARMS) + if (Lara.gunStatus != LG_HANDS_FREE) return; if (Lara.gunType == WEAPON_GRENADE_LAUNCHER) @@ -2227,7 +2227,7 @@ void GuiController::UseCurrentItem() { Lara.requestGunType = WEAPON_HARPOON_GUN; - if (Lara.gunStatus != LG_NO_ARMS) + if (Lara.gunStatus != LG_HANDS_FREE) return; if (Lara.gunType == WEAPON_HARPOON_GUN) @@ -2239,7 +2239,7 @@ void GuiController::UseCurrentItem() { Lara.requestGunType = WEAPON_ROCKET_LAUNCHER; - if (Lara.gunStatus != LG_NO_ARMS) + if (Lara.gunStatus != LG_HANDS_FREE) return; if (Lara.gunType == WEAPON_ROCKET_LAUNCHER) diff --git a/TR5Main/Game/objects.cpp b/TR5Main/Game/objects.cpp index 85492b1f7..3777b6a2a 100644 --- a/TR5Main/Game/objects.cpp +++ b/TR5Main/Game/objects.cpp @@ -106,7 +106,7 @@ void TightRopeCollision(short itemNum, ITEM_INFO* l, COLL_INFO* coll) ITEM_INFO* item = &g_Level.Items[itemNum]; if (((TrInput & IN_ACTION) == 0 - || l->currentAnimState != LS_STOP + || l->currentAnimState != LS_IDLE || l->animNumber != LA_STAND_IDLE || l->status == ITEM_INVISIBLE || Lara.gunStatus) diff --git a/TR5Main/Game/pickup/pickup.cpp b/TR5Main/Game/pickup/pickup.cpp index ce26c70ec..9c2ff0ead 100644 --- a/TR5Main/Game/pickup/pickup.cpp +++ b/TR5Main/Game/pickup/pickup.cpp @@ -10,6 +10,7 @@ #include "items.h" #include "lara_fire.h" #include "lara_flare.h" +#include "lara_helpers.h" #include "lara_one_gun.h" #include "lara_two_guns.h" #include "setup.h" @@ -30,7 +31,7 @@ using namespace TEN::Entities::Generic; static PHD_VECTOR PickUpPosition(0, 0, -100); OBJECT_COLLISION_BOUNDS PickUpBounds = -{ -256, 256, -200, 200, -256, 256, ANGLE(-10), ANGLE(10), 0, 0, 0, 0 }; +{ -256, 256, -200, 200, -256, 256, -ANGLE(10.0f), ANGLE(10.0f), 0, 0, -ANGLE(2.0f), ANGLE(2.0f) }; // TODO: Adjust these bounds when crawl surface alignment is implemented. @Sezz 2021.11.04 static PHD_VECTOR HiddenPickUpPosition(0, 0, -690); OBJECT_COLLISION_BOUNDS HiddenPickUpBounds = @@ -323,8 +324,8 @@ void PickupCollision(short itemNum, ITEM_INFO* l, COLL_INFO* coll) if (lara->interactedItem == itemNum) { getThisItemPlease = itemNum; - lara->isMoving = false; - lara->gunStatus = LG_NO_ARMS; + Lara.isMoving = false; + Lara.gunStatus = LG_HANDS_FREE; } } } @@ -345,7 +346,7 @@ void PickupCollision(short itemNum, ITEM_INFO* l, COLL_INFO* coll) if (!(TrInput & IN_ACTION) && (g_Gui.GetInventoryItemChosen() == NO_ITEM || triggerFlags != 2) || BinocularRange || - (l->currentAnimState != LS_STOP || l->animNumber != LA_STAND_IDLE || lara->gunStatus) && + (l->currentAnimState != LS_IDLE || l->animNumber != LA_STAND_IDLE || lara->gunStatus) && (l->currentAnimState != LS_CROUCH_IDLE || l->animNumber != LA_CROUCH_IDLE || lara->gunStatus) && (l->currentAnimState != LS_CRAWL_IDLE || l->animNumber != LA_CRAWL_IDLE)) { @@ -393,8 +394,8 @@ void PickupCollision(short itemNum, ITEM_INFO* l, COLL_INFO* coll) { if (lara->interactedItem == itemNum) { - lara->isMoving = false; - lara->gunStatus = LG_NO_ARMS; + Lara.isMoving = false; + Lara.gunStatus = LG_HANDS_FREE; } } @@ -427,8 +428,8 @@ void PickupCollision(short itemNum, ITEM_INFO* l, COLL_INFO* coll) if (lara->interactedItem == itemNum) { - lara->isMoving = false; - lara->gunStatus = LG_NO_ARMS; + Lara.isMoving = false; + Lara.gunStatus = LG_HANDS_FREE; } item->pos.xRot = oldXrot; @@ -528,8 +529,8 @@ void PickupCollision(short itemNum, ITEM_INFO* l, COLL_INFO* coll) if (lara->interactedItem == itemNum) { - lara->isMoving = false; - lara->gunStatus = LG_NO_ARMS; + Lara.isMoving = false; + Lara.gunStatus = LG_HANDS_FREE; } item->pos.xRot = oldXrot; @@ -571,8 +572,8 @@ void PickupCollision(short itemNum, ITEM_INFO* l, COLL_INFO* coll) if (lara->interactedItem == itemNum) { - lara->isMoving = false; - lara->gunStatus = LG_NO_ARMS; + Lara.isMoving = false; + Lara.gunStatus = LG_HANDS_FREE; } item->pos.xRot = oldXrot; @@ -653,10 +654,7 @@ void PickupCollision(short itemNum, ITEM_INFO* l, COLL_INFO* coll) if (flag) { - lara->headYrot = 0; - lara->headXrot = 0; - lara->torsoYrot = 0; - lara->torsoXrot = 0; + ResetLaraFlex(l); l->frameNumber = g_Level.Anims[l->animNumber].frameBase; lara->isMoving = false; lara->gunStatus = LG_HANDS_BUSY; @@ -895,9 +893,9 @@ void SearchObjectCollision(short itemNumber, ITEM_INFO* laraitem, COLL_INFO* lar objNumber = (item->objectNumber - ID_SEARCH_OBJECT1) / 2; if (TrInput & IN_ACTION - && laraitem->currentAnimState == LS_STOP + && laraitem->currentAnimState == LS_IDLE && laraitem->animNumber == LA_STAND_IDLE - && Lara.gunStatus == LG_NO_ARMS + && Lara.gunStatus == LG_HANDS_FREE && (item->status == ITEM_NOT_ACTIVE && item->objectNumber != ID_SEARCH_OBJECT4 || !item->itemFlags[0]) || Lara.isMoving && Lara.interactedItem == itemNumber) @@ -925,10 +923,7 @@ void SearchObjectCollision(short itemNumber, ITEM_INFO* laraitem, COLL_INFO* lar laraitem->animNumber = SearchAnims[objNumber]; laraitem->frameNumber = g_Level.Anims[laraitem->animNumber].frameBase; Lara.isMoving = false; - Lara.headYrot = 0; - Lara.headXrot = 0; - Lara.torsoYrot = 0; - Lara.torsoXrot = 0; + ResetLaraFlex(laraitem); Lara.gunStatus = LG_HANDS_BUSY; if (item->objectNumber == ID_SEARCH_OBJECT4) @@ -953,7 +948,7 @@ void SearchObjectCollision(short itemNumber, ITEM_INFO* laraitem, COLL_INFO* lar else if (Lara.isMoving && Lara.interactedItem == itemNumber) { Lara.isMoving = false; - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; } } else if (laraitem->currentAnimState != LS_MISC_CONTROL) @@ -1064,7 +1059,7 @@ int UseSpecialItem(ITEM_INFO* item) int flag = 0; int use = g_Gui.GetInventoryItemChosen(); - if (item->animNumber == LA_STAND_IDLE && Lara.gunStatus == LG_NO_ARMS && use != NO_ITEM) + if (item->animNumber == LA_STAND_IDLE && Lara.gunStatus == LG_HANDS_FREE && use != NO_ITEM) { if ((use >= ID_WATERSKIN1_EMPTY) && (use <= ID_WATERSKIN2_5)) { diff --git a/TR5Main/Game/puzzles_keys.cpp b/TR5Main/Game/puzzles_keys.cpp index ca29b47ce..6198863a9 100644 --- a/TR5Main/Game/puzzles_keys.cpp +++ b/TR5Main/Game/puzzles_keys.cpp @@ -54,7 +54,7 @@ void PuzzleHoleCollision(short itemNum, ITEM_INFO* l, COLL_INFO* coll) if (((TrInput & IN_ACTION || g_Gui.GetInventoryItemChosen() != NO_ITEM) && !BinocularRange && !Lara.gunStatus - && l->currentAnimState == LS_STOP + && l->currentAnimState == LS_IDLE && l->animNumber == LA_STAND_IDLE && GetKeyTrigger(&g_Level.Items[itemNum])) || (Lara.isMoving @@ -141,7 +141,7 @@ void PuzzleHoleCollision(short itemNum, ITEM_INFO* l, COLL_INFO* coll) if (Lara.interactedItem == itemNum) { Lara.isMoving = false; - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; } } @@ -248,7 +248,7 @@ void KeyHoleCollision(short itemNum, ITEM_INFO* l, COLL_INFO* coll) if (!((TrInput & IN_ACTION || g_Gui.GetInventoryItemChosen() != NO_ITEM) && !BinocularRange && !Lara.gunStatus - && l->currentAnimState == LS_STOP + && l->currentAnimState == LS_IDLE && l->animNumber == LA_STAND_IDLE) && (!Lara.isMoving || Lara.interactedItem != itemNum)) { @@ -315,7 +315,7 @@ void KeyHoleCollision(short itemNum, ITEM_INFO* l, COLL_INFO* coll) if (Lara.isMoving && Lara.interactedItem == itemNum) { Lara.isMoving = false; - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; } } diff --git a/TR5Main/Game/savegame.cpp b/TR5Main/Game/savegame.cpp index 32143a87b..f404ecf25 100644 --- a/TR5Main/Game/savegame.cpp +++ b/TR5Main/Game/savegame.cpp @@ -283,7 +283,9 @@ bool SaveGame::Save(int slot) lara.add_is_ducked(Lara.isDucked); lara.add_is_moving(Lara.isMoving); lara.add_item_number(Lara.itemNumber); - lara.add_keep_ducked(Lara.keepDucked); + lara.add_jump_count(Lara.jumpCount); + lara.add_jump_queued(Lara.jumpQueued); + lara.add_keep_crouched(Lara.keepCrouched); lara.add_keys(keysOffset); lara.add_keys_combo(keysComboOffset); lara.add_lasersight(Lara.Lasersight); @@ -331,6 +333,7 @@ bool SaveGame::Save(int slot) lara.add_silencer(Lara.Silencer); lara.add_small_waterskin(Lara.small_waterskin); lara.add_spaz_effect_count(Lara.spazEffectCount); + lara.add_sprint_timer(Lara.sprintTimer); lara.add_target_angles(laraTargetAnglesOffset); lara.add_target_item_number(Lara.target - g_Level.Items.data()); lara.add_torch(Lara.Torch); @@ -1197,7 +1200,9 @@ bool SaveGame::Load(int slot) Lara.isDucked = s->lara()->is_ducked(); Lara.isMoving = s->lara()->is_moving(); Lara.itemNumber = s->lara()->item_number(); - Lara.keepDucked = s->lara()->keep_ducked(); + Lara.jumpCount = s->lara()->jump_count(); + Lara.jumpQueued = s->lara()->jump_queued(); + Lara.keepCrouched = s->lara()->keep_crouched(); Lara.Lasersight = s->lara()->lasersight(); Lara.lastGunType = (LARA_WEAPON_TYPE)s->lara()->last_gun_type(); Lara.lastPos = PHD_VECTOR( @@ -1255,6 +1260,7 @@ bool SaveGame::Load(int slot) Lara.Silencer = s->lara()->silencer(); Lara.small_waterskin = s->lara()->small_waterskin(); Lara.spazEffectCount = s->lara()->spaz_effect_count(); + Lara.sprintTimer = s->lara()->sprint_timer(); Lara.target = (s->lara()->target_item_number() >= 0 ? &g_Level.Items[s->lara()->target_item_number()] : nullptr); Lara.targetAngles[0] = s->lara()->target_angles()->Get(0); Lara.targetAngles[1] = s->lara()->target_angles()->Get(1); diff --git a/TR5Main/Objects/Effects/flame_emitters.cpp b/TR5Main/Objects/Effects/flame_emitters.cpp index f9111ac4d..0ae4ff492 100644 --- a/TR5Main/Objects/Effects/flame_emitters.cpp +++ b/TR5Main/Objects/Effects/flame_emitters.cpp @@ -645,7 +645,7 @@ namespace TEN::Entities::Effects || Lara.litTorch == (item->status & 1) || item->timer == -1 || !(TrInput & IN_ACTION) - || l->currentAnimState != LS_STOP + || l->currentAnimState != LS_IDLE || l->animNumber != LA_STAND_IDLE || l->gravityStatus) { diff --git a/TR5Main/Objects/Effects/tr4_locusts.cpp b/TR5Main/Objects/Effects/tr4_locusts.cpp index fc5671fb2..64ceaecb7 100644 --- a/TR5Main/Objects/Effects/tr4_locusts.cpp +++ b/TR5Main/Objects/Effects/tr4_locusts.cpp @@ -139,7 +139,7 @@ namespace TEN::Entities::TR4 //if (LaraItem == nullptr) // LaraItem = LaraItem; - if ((Lara.keepDucked || LaraItem->hitPoints <= 0) + if ((Lara.keepCrouched || LaraItem->hitPoints <= 0) && locust->counter >= 90 && !(GetRandomControl() & 7)) locust->counter = 90; diff --git a/TR5Main/Objects/Generic/Doors/double_doors.cpp b/TR5Main/Objects/Generic/Doors/double_doors.cpp index 5dfee2333..f7a5803b9 100644 --- a/TR5Main/Objects/Generic/Doors/double_doors.cpp +++ b/TR5Main/Objects/Generic/Doors/double_doors.cpp @@ -37,7 +37,7 @@ namespace TEN::Entities::Doors ITEM_INFO* item = &g_Level.Items[itemNum]; if (TrInput & IN_ACTION - && l->currentAnimState == LS_STOP + && l->currentAnimState == LS_IDLE && l->animNumber == LA_STAND_IDLE && !(item->status && item->gravityStatus) && !(l->hitStatus) @@ -72,7 +72,7 @@ namespace TEN::Entities::Doors if (Lara.isMoving && Lara.interactedItem == itemNum) { Lara.isMoving = false; - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; } item->pos.yRot ^= ANGLE(180); } diff --git a/TR5Main/Objects/Generic/Doors/generic_doors.cpp b/TR5Main/Objects/Generic/Doors/generic_doors.cpp index 095103846..db02e9ae5 100644 --- a/TR5Main/Objects/Generic/Doors/generic_doors.cpp +++ b/TR5Main/Objects/Generic/Doors/generic_doors.cpp @@ -167,10 +167,10 @@ namespace TEN::Entities::Doors if (item->triggerFlags == 2 && item->status == ITEM_NOT_ACTIVE && !item->gravityStatus // CHECK && ((TrInput & IN_ACTION || g_Gui.GetInventoryItemChosen() == ID_CROWBAR_ITEM) - && l->currentAnimState == LS_STOP + && l->currentAnimState == LS_IDLE && l->animNumber == LA_STAND_IDLE && !l->hitStatus - && Lara.gunStatus == LG_NO_ARMS + && Lara.gunStatus == LG_HANDS_FREE || Lara.isMoving && Lara.interactedItem == itemNum)) { item->pos.yRot ^= ANGLE(180); @@ -229,7 +229,7 @@ namespace TEN::Entities::Doors else if (Lara.isMoving && Lara.interactedItem == itemNum) { Lara.isMoving = 0; - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; } item->pos.yRot ^= ANGLE(180); diff --git a/TR5Main/Objects/Generic/Doors/pushpull_kick_door.cpp b/TR5Main/Objects/Generic/Doors/pushpull_kick_door.cpp index 576d9cf9a..a1fb86b1d 100644 --- a/TR5Main/Objects/Generic/Doors/pushpull_kick_door.cpp +++ b/TR5Main/Objects/Generic/Doors/pushpull_kick_door.cpp @@ -47,7 +47,7 @@ namespace TEN::Entities::Doors ITEM_INFO* item = &g_Level.Items[itemNum]; if (TrInput & IN_ACTION - && l->currentAnimState == LS_STOP + && l->currentAnimState == LS_IDLE && l->animNumber == LA_STAND_IDLE && item->status != ITEM_ACTIVE && !(l->hitStatus) @@ -115,7 +115,7 @@ namespace TEN::Entities::Doors item->status = ITEM_ACTIVE; l->currentAnimState = LS_MISC_CONTROL; - l->goalAnimState = LS_STOP; + l->goalAnimState = LS_IDLE; Lara.isMoving = false; Lara.gunStatus = LG_HANDS_BUSY; } @@ -123,7 +123,7 @@ namespace TEN::Entities::Doors else if (Lara.isMoving && Lara.interactedItem == itemNum) { Lara.isMoving = false; - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; } if (pull) diff --git a/TR5Main/Objects/Generic/Doors/underwater_door.cpp b/TR5Main/Objects/Generic/Doors/underwater_door.cpp index 72de8e67a..b076ba8a9 100644 --- a/TR5Main/Objects/Generic/Doors/underwater_door.cpp +++ b/TR5Main/Objects/Generic/Doors/underwater_door.cpp @@ -73,7 +73,7 @@ namespace TEN::Entities::Doors if (Lara.isMoving && Lara.interactedItem == itemNum) { Lara.isMoving = false; - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; } l->pos.yRot ^= ANGLE(180); } diff --git a/TR5Main/Objects/Generic/Object/burning_torch.cpp b/TR5Main/Objects/Generic/Object/burning_torch.cpp index f6b52071d..dc4584361 100644 --- a/TR5Main/Objects/Generic/Object/burning_torch.cpp +++ b/TR5Main/Objects/Generic/Object/burning_torch.cpp @@ -111,7 +111,7 @@ namespace TEN::Entities::Generic Lara.leftArm.lock = false; Lara.gunType = Lara.lastGunType; Lara.requestGunType = WEAPON_NONE; - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; } else if (Lara.leftArm.frameNumber == 12) { @@ -131,7 +131,7 @@ namespace TEN::Entities::Generic Lara.leftArm.lock = false; Lara.lastGunType = WEAPON_NONE; Lara.gunType = WEAPON_NONE; - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; } else if (Lara.leftArm.frameNumber == 36) { @@ -293,7 +293,7 @@ namespace TEN::Entities::Generic || Lara.litTorch == (item->status == ITEM_ACTIVE) || item->timer == -1 || !(TrInput & IN_ACTION) - || l->currentAnimState != LS_STOP + || l->currentAnimState != LS_IDLE || l->animNumber != LA_STAND_IDLE || l->gravityStatus) { diff --git a/TR5Main/Objects/Generic/Object/generic_trapdoor.cpp b/TR5Main/Objects/Generic/Object/generic_trapdoor.cpp index 1ac3c9980..29132010b 100644 --- a/TR5Main/Objects/Generic/Object/generic_trapdoor.cpp +++ b/TR5Main/Objects/Generic/Object/generic_trapdoor.cpp @@ -45,7 +45,7 @@ void CeilingTrapDoorCollision(short itemNumber, ITEM_INFO* l, COLL_INFO* coll) bool result2 = TestLaraPosition(&CeilingTrapDoorBounds, item, l); l->pos.yRot += ANGLE(180); - if (TrInput & IN_ACTION && item->status != ITEM_ACTIVE && l->currentAnimState == LS_JUMP_UP && l->gravityStatus && Lara.gunStatus == LG_NO_ARMS && itemIsAbove && (result || result2)) + if (TrInput & IN_ACTION && item->status != ITEM_ACTIVE && l->currentAnimState == LS_JUMP_UP && l->gravityStatus && Lara.gunStatus == LG_HANDS_FREE && itemIsAbove && (result || result2)) { AlignLaraPosition(&CeilingTrapDoorPos, item, l); if (result2) @@ -85,7 +85,7 @@ void FloorTrapDoorCollision(short itemNumber, ITEM_INFO* l, COLL_INFO* coll) ITEM_INFO* item; item = &g_Level.Items[itemNumber]; - if (TrInput & IN_ACTION && item->status != ITEM_ACTIVE && l->currentAnimState == LS_STOP && l->animNumber == LA_STAND_IDLE && Lara.gunStatus == LG_NO_ARMS + if (TrInput & IN_ACTION && item->status != ITEM_ACTIVE && l->currentAnimState == LS_IDLE && l->animNumber == LA_STAND_IDLE && Lara.gunStatus == LG_HANDS_FREE || Lara.isMoving && Lara.interactedItem == itemNumber) { if (TestLaraPosition(&FloorTrapDoorBounds, item, l)) diff --git a/TR5Main/Objects/Generic/Object/polerope.cpp b/TR5Main/Objects/Generic/Object/polerope.cpp index 1d13c071b..69bab8552 100644 --- a/TR5Main/Objects/Generic/Object/polerope.cpp +++ b/TR5Main/Objects/Generic/Object/polerope.cpp @@ -33,9 +33,9 @@ namespace TEN::Entities::Generic auto isLara = (!item->data.is()); if (isLara && - (TrInput & IN_ACTION) && + TrInput & IN_ACTION && !Lara.gunStatus && - l->currentAnimState == LS_STOP && + l->currentAnimState == LS_IDLE && l->animNumber == LA_STAND_IDLE || Lara.isMoving && Lara.interactedItem == itemNumber) { @@ -63,7 +63,7 @@ namespace TEN::Entities::Generic if (Lara.isMoving && Lara.interactedItem == itemNumber) { Lara.isMoving = false; - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; } item->pos.yRot = rot; } diff --git a/TR5Main/Objects/Generic/Object/rope.cpp b/TR5Main/Objects/Generic/Object/rope.cpp index dd2f3d22b..3130efc3d 100644 --- a/TR5Main/Objects/Generic/Object/rope.cpp +++ b/TR5Main/Objects/Generic/Object/rope.cpp @@ -187,7 +187,7 @@ namespace TEN::Entities::Generic rope = &Ropes[item->triggerFlags]; if (TrInput & IN_ACTION - && Lara.gunStatus == LG_NO_ARMS + && Lara.gunStatus == LG_HANDS_FREE && (l->currentAnimState == LS_REACH || l->currentAnimState == LS_JUMP_UP) && l->gravityStatus @@ -643,7 +643,7 @@ namespace TEN::Entities::Generic item->pos.xRot = 0; item->gravityStatus = true; - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; if (item->frameNumber - g_Level.Anims[LA_ROPE_SWING].frameBase > 42) { @@ -680,7 +680,7 @@ namespace TEN::Entities::Generic item->fallspeed = 0; item->gravityStatus = true; - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; Lara.ropePtr = -1; } diff --git a/TR5Main/Objects/Generic/Switches/cog_switch.cpp b/TR5Main/Objects/Generic/Switches/cog_switch.cpp index 457511cc0..9f485c1e7 100644 --- a/TR5Main/Objects/Generic/Switches/cog_switch.cpp +++ b/TR5Main/Objects/Generic/Switches/cog_switch.cpp @@ -68,7 +68,7 @@ namespace TEN::Entities::Switches && (TrInput & IN_ACTION && !Lara.gunStatus && !item->gravityStatus - && l->currentAnimState == LS_STOP + && l->currentAnimState == LS_IDLE && l->animNumber == LA_STAND_IDLE || Lara.isMoving && Lara.interactedItem == itemNum)) @@ -111,7 +111,7 @@ namespace TEN::Entities::Switches else if (Lara.isMoving && Lara.interactedItem == itemNum) { Lara.isMoving = false; - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; } } @@ -129,7 +129,7 @@ namespace TEN::Entities::Switches { if (item->goalAnimState == SWITCH_ON && !(TrInput & IN_ACTION)) { - LaraItem->goalAnimState = LS_STOP; + LaraItem->goalAnimState = LS_IDLE; item->goalAnimState = SWITCH_OFF; } @@ -153,9 +153,9 @@ namespace TEN::Entities::Switches LaraItem->animNumber = LA_STAND_SOLID; LaraItem->frameNumber = g_Level.Anims[LaraItem->animNumber].frameBase; - LaraItem->goalAnimState = LS_STOP; - LaraItem->currentAnimState = LS_STOP; - Lara.gunStatus = LG_NO_ARMS; + LaraItem->goalAnimState = LS_IDLE; + LaraItem->currentAnimState = LS_IDLE; + Lara.gunStatus = LG_HANDS_FREE; } } } diff --git a/TR5Main/Objects/Generic/Switches/crowbar_switch.cpp b/TR5Main/Objects/Generic/Switches/crowbar_switch.cpp index ffd4533b8..30886ba8a 100644 --- a/TR5Main/Objects/Generic/Switches/crowbar_switch.cpp +++ b/TR5Main/Objects/Generic/Switches/crowbar_switch.cpp @@ -43,9 +43,9 @@ namespace TEN::Entities::Switches ITEM_INFO* item = &g_Level.Items[itemNum]; if ((((TrInput & IN_ACTION) || g_Gui.GetInventoryItemChosen() == ID_CROWBAR_ITEM) - && l->currentAnimState == LS_STOP + && l->currentAnimState == LS_IDLE && l->animNumber == LA_STAND_IDLE - && Lara.gunStatus == LG_NO_ARMS + && Lara.gunStatus == LG_HANDS_FREE && item->itemFlags[0] == 0) || (Lara.isMoving && Lara.interactedItem == itemNum)) { @@ -79,7 +79,7 @@ namespace TEN::Entities::Switches else if (Lara.isMoving && Lara.interactedItem == itemNum) { Lara.isMoving = false; - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; } l->pos.yRot ^= (short)ANGLE(180); } @@ -111,7 +111,7 @@ namespace TEN::Entities::Switches else if (Lara.isMoving && Lara.interactedItem == itemNum) { Lara.isMoving = false; - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; } } } diff --git a/TR5Main/Objects/Generic/Switches/fullblock_switch.cpp b/TR5Main/Objects/Generic/Switches/fullblock_switch.cpp index 2a83d0310..3248bcb71 100644 --- a/TR5Main/Objects/Generic/Switches/fullblock_switch.cpp +++ b/TR5Main/Objects/Generic/Switches/fullblock_switch.cpp @@ -37,7 +37,7 @@ namespace TEN::Entities::Switches || item->flags & 0x100 || CurrentSequence >= 3 || Lara.gunStatus - || l->currentAnimState != LS_STOP + || l->currentAnimState != LS_IDLE || l->animNumber != LA_STAND_IDLE) && (!Lara.isMoving || Lara.interactedItem !=itemNum)) { @@ -55,7 +55,7 @@ namespace TEN::Entities::Switches l->animNumber = LA_BUTTON_GIANT_PUSH; item->goalAnimState = 0; } - l->goalAnimState = LS_STOP; + l->goalAnimState = LS_IDLE; l->frameNumber = g_Level.Anims[l->animNumber].frameBase; item->status = ITEM_ACTIVE; @@ -77,7 +77,7 @@ namespace TEN::Entities::Switches else if (Lara.isMoving && Lara.interactedItem == itemNum) { Lara.isMoving = false; - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; } } diff --git a/TR5Main/Objects/Generic/Switches/generic_switch.cpp b/TR5Main/Objects/Generic/Switches/generic_switch.cpp index 8f5e2f4de..9520e104c 100644 --- a/TR5Main/Objects/Generic/Switches/generic_switch.cpp +++ b/TR5Main/Objects/Generic/Switches/generic_switch.cpp @@ -50,7 +50,7 @@ namespace TEN::Entities::Switches { ITEM_INFO* item = &g_Level.Items[itemNum]; if (TrInput & IN_ACTION - && l->currentAnimState == LS_STOP + && l->currentAnimState == LS_IDLE && l->animNumber == LA_STAND_IDLE && !Lara.gunStatus && item->status == ITEM_NOT_ACTIVE @@ -151,7 +151,7 @@ namespace TEN::Entities::Switches else if (Lara.isMoving && Lara.interactedItem == itemNum) { Lara.isMoving = false; - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; } return; diff --git a/TR5Main/Objects/Generic/Switches/pulley_switch.cpp b/TR5Main/Objects/Generic/Switches/pulley_switch.cpp index e85fc35ac..9b02ae388 100644 --- a/TR5Main/Objects/Generic/Switches/pulley_switch.cpp +++ b/TR5Main/Objects/Generic/Switches/pulley_switch.cpp @@ -43,8 +43,8 @@ namespace TEN::Entities::Switches ITEM_INFO* item = &g_Level.Items[itemNum]; if ((TrInput & IN_ACTION) - && Lara.gunStatus == LG_NO_ARMS - && l->currentAnimState == LS_STOP + && Lara.gunStatus == LG_HANDS_FREE + && l->currentAnimState == LS_IDLE && l->animNumber == LA_STAND_IDLE && l->gravityStatus == false || Lara.isMoving && Lara.interactedItem == itemNum) @@ -93,7 +93,7 @@ namespace TEN::Entities::Switches if (Lara.isMoving && Lara.interactedItem == itemNum) { Lara.isMoving = false; - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; } item->pos.yRot = oldYrot; } diff --git a/TR5Main/Objects/Generic/Switches/rail_switch.cpp b/TR5Main/Objects/Generic/Switches/rail_switch.cpp index e3a964637..f78ded4e0 100644 --- a/TR5Main/Objects/Generic/Switches/rail_switch.cpp +++ b/TR5Main/Objects/Generic/Switches/rail_switch.cpp @@ -40,7 +40,7 @@ namespace TEN::Entities::Switches ITEM_INFO* item = &g_Level.Items[itemNum]; if ((!(TrInput & IN_ACTION) - || l->currentAnimState != LS_STOP + || l->currentAnimState != LS_IDLE || l->animNumber != LA_STAND_IDLE || Lara.gunStatus) && (!Lara.isMoving @@ -69,7 +69,7 @@ namespace TEN::Entities::Switches else if (Lara.isMoving && Lara.interactedItem == itemNum) { Lara.isMoving = false; - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; } l->pos.yRot ^= (short)ANGLE(180); @@ -129,7 +129,7 @@ namespace TEN::Entities::Switches if (Lara.interactedItem == itemNum) { Lara.isMoving = false; - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; } } diff --git a/TR5Main/Objects/Generic/Switches/turn_switch.cpp b/TR5Main/Objects/Generic/Switches/turn_switch.cpp index 092bab5e6..092e7bb9b 100644 --- a/TR5Main/Objects/Generic/Switches/turn_switch.cpp +++ b/TR5Main/Objects/Generic/Switches/turn_switch.cpp @@ -52,10 +52,10 @@ namespace TEN::Entities::Switches if (item->currentAnimState == TURN_SWITCH_STOP && TrInput & IN_ACTION - && l->currentAnimState == LS_STOP + && l->currentAnimState == LS_IDLE && l->animNumber == LA_STAND_IDLE && l->gravityStatus == false - && Lara.gunStatus == LG_NO_ARMS + && Lara.gunStatus == LG_HANDS_FREE || Lara.isMoving && Lara.interactedItem == itemNum) { if (TestLaraPosition(&TurnSwitchBoundsA, item, l)) @@ -99,7 +99,7 @@ namespace TEN::Entities::Switches else if (Lara.isMoving && Lara.interactedItem == itemNum) { Lara.isMoving = false; - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; } l->pos.yRot ^= (short)ANGLE(180); } @@ -225,7 +225,7 @@ namespace TEN::Entities::Switches if (item->itemFlags[1] == 1) { l->animNumber = LA_STAND_IDLE; - l->currentAnimState = LS_STOP; + l->currentAnimState = LS_IDLE; l->frameNumber = g_Level.Anims[l->animNumber].frameBase; item->animNumber = Objects[item->objectNumber].animIndex; item->frameNumber = g_Level.Anims[item->animNumber].frameBase; @@ -233,7 +233,7 @@ namespace TEN::Entities::Switches RemoveActiveItem(itemNum); - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; UseForcedFixedCamera = 0; item->itemFlags[1] = 2; } diff --git a/TR5Main/Objects/TR2/Trap/tr2_springboard.cpp b/TR5Main/Objects/TR2/Trap/tr2_springboard.cpp index 58963d42c..f830e3b3a 100644 --- a/TR5Main/Objects/TR2/Trap/tr2_springboard.cpp +++ b/TR5Main/Objects/TR2/Trap/tr2_springboard.cpp @@ -16,7 +16,7 @@ void SpringBoardControl(short itemNumber) if (LaraItem->hitPoints <= 0) return; - if (LaraItem->currentAnimState == LS_WALK_BACK || LaraItem->currentAnimState == LS_HOP_BACK) + if (LaraItem->currentAnimState == LS_WALK_BACK || LaraItem->currentAnimState == LS_RUN_BACK) LaraItem->speed = -LaraItem->speed; LaraItem->fallspeed = -240; diff --git a/TR5Main/Objects/TR2/Vehicles/boat.cpp b/TR5Main/Objects/TR2/Vehicles/boat.cpp index 40c7e89fa..18850df9c 100644 --- a/TR5Main/Objects/TR2/Vehicles/boat.cpp +++ b/TR5Main/Objects/TR2/Vehicles/boat.cpp @@ -180,7 +180,7 @@ BoatMountType GetSpeedBoatMountType(ITEM_INFO* laraItem, ITEM_INFO* sBoatItem, C BoatMountType mountType = BoatMountType::None; - if (laraInfo->gunStatus != LG_NO_ARMS) + if (laraInfo->gunStatus != LG_HANDS_FREE) return mountType; if (!TestBoundsCollide(sBoatItem, laraItem, coll->Setup.Radius)) diff --git a/TR5Main/Objects/TR2/Vehicles/snowmobile.cpp b/TR5Main/Objects/TR2/Vehicles/snowmobile.cpp index b731655d7..989412f57 100644 --- a/TR5Main/Objects/TR2/Vehicles/snowmobile.cpp +++ b/TR5Main/Objects/TR2/Vehicles/snowmobile.cpp @@ -302,7 +302,7 @@ bool SkidooCheckGetOff(ITEM_INFO* lara, ITEM_INFO* skidoo) lara->pos.xRot = 0; lara->pos.zRot = 0; laraInfo->Vehicle = NO_ITEM; - laraInfo->gunStatus = LG_NO_ARMS; + laraInfo->gunStatus = LG_HANDS_FREE; } else if (lara->currentAnimState == SKIDOO_STATE_JUMP_OFF && (skidoo->pos.yPos == skidoo->floor || TestLastFrame(lara))) @@ -328,7 +328,7 @@ bool SkidooCheckGetOff(ITEM_INFO* lara, ITEM_INFO* skidoo) lara->pos.xRot = 0; lara->pos.zRot = 0; lara->gravityStatus = true; - laraInfo->gunStatus = LG_NO_ARMS; + laraInfo->gunStatus = LG_HANDS_FREE; laraInfo->moveAngle = skidoo->pos.yRot; skidoo->flags |= ONESHOT; skidoo->collidable = false; @@ -618,7 +618,7 @@ int SkidooCheckGetOn(ITEM_INFO* lara, ITEM_INFO* skidoo, COLL_INFO* coll) int mountType = 0; if (!(TrInput & IN_ACTION) || - laraInfo->gunStatus != LG_NO_ARMS || + laraInfo->gunStatus != LG_HANDS_FREE || lara->gravityStatus) { return mountType = 0; @@ -668,7 +668,7 @@ void SkidooCollision(short itemNum, ITEM_INFO* lara, COLL_INFO* coll) UndrawFlareMeshes(lara); laraInfo->flareControlLeft = 0; laraInfo->requestGunType = WEAPON_NONE; - laraInfo->gunStatus = LG_NO_ARMS; + laraInfo->gunStatus = LG_HANDS_FREE; } if (mountType == 1) diff --git a/TR5Main/Objects/TR3/Vehicles/biggun.cpp b/TR5Main/Objects/TR3/Vehicles/biggun.cpp index d79578684..b0a0a7448 100644 --- a/TR5Main/Objects/TR3/Vehicles/biggun.cpp +++ b/TR5Main/Objects/TR3/Vehicles/biggun.cpp @@ -96,7 +96,7 @@ static bool CanUseGun(ITEM_INFO* lara, ITEM_INFO* bigGun) //LaraInfo*& laraInfo = lara->data; // This function is presumably called before Lara is initialised, so global must be used. @Sezz 2021.11.16 if (!(TrInput & IN_ACTION) || - Lara.gunStatus != LG_NO_ARMS || + Lara.gunStatus != LG_HANDS_FREE || lara->gravityStatus) // BUG: Lara can still mount when jumping up. @Sezz 2021.11.16 { return false; @@ -255,7 +255,7 @@ bool BigGunControl(ITEM_INFO* lara, COLL_INFO* coll) { SetAnimation(lara, LA_STAND_IDLE); laraInfo->Vehicle = NO_ITEM; - laraInfo->gunStatus = LG_NO_ARMS; + laraInfo->gunStatus = LG_HANDS_FREE; bigGun->hitPoints = 0; } diff --git a/TR5Main/Objects/TR3/Vehicles/kayak.cpp b/TR5Main/Objects/TR3/Vehicles/kayak.cpp index 5373bb848..e31539187 100644 --- a/TR5Main/Objects/TR3/Vehicles/kayak.cpp +++ b/TR5Main/Objects/TR3/Vehicles/kayak.cpp @@ -213,7 +213,7 @@ int KayakGetIn(short itemNumber, COLL_INFO* coll) ITEM_INFO* l = LaraItem; if ((!(TrInput & IN_ACTION)) - || (Lara.gunStatus != LG_NO_ARMS) + || (Lara.gunStatus != LG_HANDS_FREE) || (l->gravityStatus)) return 0; @@ -1028,7 +1028,7 @@ void KayakUserInput(ITEM_INFO* v, ITEM_INFO* l, KAYAK_INFO* Kayak) l->fallspeed = 0; l->gravityStatus = true; - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; Lara.Vehicle = NO_ITEM; } break; @@ -1055,7 +1055,7 @@ void KayakUserInput(ITEM_INFO* v, ITEM_INFO* l, KAYAK_INFO* Kayak) l->fallspeed = 0; l->gravityStatus = true; - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; Lara.Vehicle = NO_ITEM; } } diff --git a/TR5Main/Objects/TR3/Vehicles/minecart.cpp b/TR5Main/Objects/TR3/Vehicles/minecart.cpp index 441f3016b..d2b6cffb6 100644 --- a/TR5Main/Objects/TR3/Vehicles/minecart.cpp +++ b/TR5Main/Objects/TR3/Vehicles/minecart.cpp @@ -116,7 +116,7 @@ static bool GetInMineCart(ITEM_INFO* v, ITEM_INFO* l, COLL_INFO* coll) FLOOR_INFO* floor; short roomNumber; - if (!(TrInput & IN_ACTION) || Lara.gunStatus != LG_NO_ARMS || l->gravityStatus) + if (!(TrInput & IN_ACTION) || Lara.gunStatus != LG_HANDS_FREE || l->gravityStatus) return 0; if (!TestBoundsCollide(v, l, coll->Setup.Radius)) @@ -617,7 +617,7 @@ static void DoUserInput(ITEM_INFO* v, ITEM_INFO* l, CART_INFO* cart) SetAnimation(l, LA_STAND_SOLID); Lara.Vehicle = NO_ITEM; - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; } break; @@ -636,7 +636,7 @@ static void DoUserInput(ITEM_INFO* v, ITEM_INFO* l, CART_INFO* cart) SetAnimation(l, LA_STAND_SOLID); Lara.Vehicle = NO_ITEM; - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; } break; diff --git a/TR5Main/Objects/TR3/Vehicles/quad.cpp b/TR5Main/Objects/TR3/Vehicles/quad.cpp index cdedbcd7c..27d2ccb5c 100644 --- a/TR5Main/Objects/TR3/Vehicles/quad.cpp +++ b/TR5Main/Objects/TR3/Vehicles/quad.cpp @@ -251,7 +251,7 @@ static bool QuadCheckGetOff(ITEM_INFO* lara, ITEM_INFO* quad) lara->pos.xRot = 0; lara->pos.zRot = 0; laraInfo->Vehicle = NO_ITEM; - laraInfo->gunStatus = LG_NO_ARMS; + laraInfo->gunStatus = LG_HANDS_FREE; if (lara->currentAnimState == QUAD_STATE_FALL_OFF) { @@ -268,7 +268,7 @@ static bool QuadCheckGetOff(ITEM_INFO* lara, ITEM_INFO* quad) lara->pos.xRot = 0; lara->pos.zRot = 0; lara->hitPoints = 0; - laraInfo->gunStatus = LG_NO_ARMS; + laraInfo->gunStatus = LG_HANDS_FREE; quad->flags |= ONESHOT; return false; @@ -295,7 +295,7 @@ static int GetOnQuadBike(ITEM_INFO* lara, ITEM_INFO* quad, COLL_INFO* coll) if (!(TrInput & IN_ACTION) || lara->gravityStatus || - laraInfo->gunStatus != LG_NO_ARMS || + laraInfo->gunStatus != LG_HANDS_FREE || quad->flags & ONESHOT || abs(quad->pos.yPos - lara->pos.yPos) > STEP_SIZE) { diff --git a/TR5Main/Objects/TR3/Vehicles/rubberboat.cpp b/TR5Main/Objects/TR3/Vehicles/rubberboat.cpp index 7be8c6969..970933cf0 100644 --- a/TR5Main/Objects/TR3/Vehicles/rubberboat.cpp +++ b/TR5Main/Objects/TR3/Vehicles/rubberboat.cpp @@ -125,7 +125,7 @@ RubberBoatMountType RubberBoatCheckGeton(short itemNum, ITEM_INFO* lara, COLL_IN RubberBoatMountType getOn = RBOAT_MOUNT_NONE; if (!(TrInput & IN_ACTION) || - Lara.gunStatus != LG_NO_ARMS || + Lara.gunStatus != LG_HANDS_FREE || lara->gravityStatus || rBoat->speed) { diff --git a/TR5Main/Objects/TR3/Vehicles/upv.cpp b/TR5Main/Objects/TR3/Vehicles/upv.cpp index f4f5096df..34cae1d5b 100644 --- a/TR5Main/Objects/TR3/Vehicles/upv.cpp +++ b/TR5Main/Objects/TR3/Vehicles/upv.cpp @@ -329,7 +329,7 @@ static bool TestUPVMount(ITEM_INFO* laraItem, ITEM_INFO* UPVItem) LaraInfo*& laraInfo = laraItem->data; if (!(TrInput & IN_ACTION) || - laraInfo->gunStatus != LG_NO_ARMS || + laraInfo->gunStatus != LG_HANDS_FREE || laraItem->gravityStatus) { return false; @@ -694,7 +694,7 @@ static void UserInput(ITEM_INFO* laraItem, ITEM_INFO* UPVItem) UpdateItemRoom(laraItem, 0); laraInfo->waterStatus = LW_UNDERWATER; - laraInfo->gunStatus = LG_NO_ARMS; + laraInfo->gunStatus = LG_HANDS_FREE; laraInfo->Vehicle = NO_ITEM; UPVItem->hitPoints = 0; @@ -738,7 +738,7 @@ static void UserInput(ITEM_INFO* laraItem, ITEM_INFO* UPVItem) laraInfo->torsoYrot = 0; laraInfo->headXrot = 0; laraInfo->headYrot = 0; - laraInfo->gunStatus = LG_NO_ARMS; + laraInfo->gunStatus = LG_HANDS_FREE; laraInfo->Vehicle = NO_ITEM; UPVItem->hitPoints = 0; diff --git a/TR5Main/Objects/TR4/Entity/tr4_baddy.cpp b/TR5Main/Objects/TR4/Entity/tr4_baddy.cpp index a8b5f8438..3727457ab 100644 --- a/TR5Main/Objects/TR4/Entity/tr4_baddy.cpp +++ b/TR5Main/Objects/TR4/Entity/tr4_baddy.cpp @@ -1049,7 +1049,7 @@ namespace TEN::Entities::TR4 LaraItem->speed = 2; LaraItem->fallspeed = 1; LaraItem->pos.yPos += (STEP_SIZE * 0.75f); - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; currentCreature->flags = 1; } } diff --git a/TR5Main/Objects/TR4/Entity/tr4_demigod.cpp b/TR5Main/Objects/TR4/Entity/tr4_demigod.cpp index f83755761..7782890d1 100644 --- a/TR5Main/Objects/TR4/Entity/tr4_demigod.cpp +++ b/TR5Main/Objects/TR4/Entity/tr4_demigod.cpp @@ -748,7 +748,7 @@ namespace TEN::Entities::TR4 LaraItem->hitStatus = true; LaraItem->speed = 2; LaraItem->fallspeed = 1; - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; } } diff --git a/TR5Main/Objects/TR4/Entity/tr4_sas.cpp b/TR5Main/Objects/TR4/Entity/tr4_sas.cpp index c6a5d970b..d0e7543b7 100644 --- a/TR5Main/Objects/TR4/Entity/tr4_sas.cpp +++ b/TR5Main/Objects/TR4/Entity/tr4_sas.cpp @@ -690,7 +690,7 @@ namespace TEN::Entities::TR4 ITEM_INFO* item = &g_Level.Items[itemNumber]; if ((!(TrInput & IN_ACTION) - || l->currentAnimState != LS_STOP + || l->currentAnimState != LS_IDLE || l->animNumber != LA_STAND_IDLE || Lara.gunStatus || l->gravityStatus diff --git a/TR5Main/Objects/TR4/Object/tr4_clockwork_beetle.cpp b/TR5Main/Objects/TR4/Object/tr4_clockwork_beetle.cpp index 4fb0953f4..bf2b7edaa 100644 --- a/TR5Main/Objects/TR4/Object/tr4_clockwork_beetle.cpp +++ b/TR5Main/Objects/TR4/Object/tr4_clockwork_beetle.cpp @@ -307,10 +307,10 @@ void UseClockworkBeetle(short flag) short itemNum; if (flag - || LaraItem->currentAnimState == LS_STOP + || LaraItem->currentAnimState == LS_IDLE && LaraItem->animNumber == LA_STAND_IDLE && !LaraItem->hitStatus - && Lara.gunStatus == LG_NO_ARMS) + && Lara.gunStatus == LG_HANDS_FREE) { itemNum = CreateItem(); diff --git a/TR5Main/Objects/TR4/Object/tr4_element_puzzle.cpp b/TR5Main/Objects/TR4/Object/tr4_element_puzzle.cpp index 175d59b64..8cac7a432 100644 --- a/TR5Main/Objects/TR4/Object/tr4_element_puzzle.cpp +++ b/TR5Main/Objects/TR4/Object/tr4_element_puzzle.cpp @@ -244,7 +244,7 @@ namespace TEN::Entities::TR4 || !(TrInput & IN_ACTION) || item->triggerFlags != 1 || item->itemFlags[0] != 1 - || l->currentAnimState != LS_STOP + || l->currentAnimState != LS_IDLE || l->animNumber != LA_STAND_IDLE || !Lara.litTorch || l->gravityStatus) diff --git a/TR5Main/Objects/TR4/Object/tr4_sarcophagus.cpp b/TR5Main/Objects/TR4/Object/tr4_sarcophagus.cpp index 3684dda31..2318ef366 100644 --- a/TR5Main/Objects/TR4/Object/tr4_sarcophagus.cpp +++ b/TR5Main/Objects/TR4/Object/tr4_sarcophagus.cpp @@ -23,9 +23,9 @@ void SarcophagusCollision(short itemNum, ITEM_INFO* l, COLL_INFO* coll) if (TrInput & IN_ACTION && item->status != ITEM_ACTIVE && - l->currentAnimState == LS_STOP && + l->currentAnimState == LS_IDLE && l->animNumber == LA_STAND_IDLE && - Lara.gunStatus == LG_NO_ARMS || + Lara.gunStatus == LG_HANDS_FREE || Lara.isMoving && Lara.interactedItem == itemNum) { if (TestLaraPosition(&SarcophagusBounds, item, l)) @@ -57,7 +57,7 @@ void SarcophagusCollision(short itemNum, ITEM_INFO* l, COLL_INFO* coll) if (Lara.interactedItem == itemNum) { Lara.isMoving = false; - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; } } } diff --git a/TR5Main/Objects/TR4/Object/tr4_senet.cpp b/TR5Main/Objects/TR4/Object/tr4_senet.cpp index 3b7b98550..3feea79a5 100644 --- a/TR5Main/Objects/TR4/Object/tr4_senet.cpp +++ b/TR5Main/Objects/TR4/Object/tr4_senet.cpp @@ -413,7 +413,7 @@ void GameStixCollision(short item_num, ITEM_INFO* laraitem, COLL_INFO* coll) { ITEM_INFO* item = &g_Level.Items[item_num]; - if (TrInput & IN_ACTION && laraitem->currentAnimState == LS_STOP && laraitem->animNumber == LA_STAND_IDLE && Lara.gunStatus == LG_NO_ARMS && + if (TrInput & IN_ACTION && laraitem->currentAnimState == LS_IDLE && laraitem->animNumber == LA_STAND_IDLE && Lara.gunStatus == LG_HANDS_FREE && !item->active || Lara.isMoving && Lara.interactedItem == item_num) { laraitem->pos.yRot ^= 0x8000; diff --git a/TR5Main/Objects/TR4/Vehicles/jeep.cpp b/TR5Main/Objects/TR4/Vehicles/jeep.cpp index 9b5191150..445d8e23b 100644 --- a/TR5Main/Objects/TR4/Vehicles/jeep.cpp +++ b/TR5Main/Objects/TR4/Vehicles/jeep.cpp @@ -401,14 +401,14 @@ static int JeepCheckGetOff() LaraItem->pos.yRot += ANGLE(90); LaraItem->animNumber = LA_STAND_SOLID; LaraItem->frameNumber = g_Level.Anims[LaraItem->animNumber].frameBase; - LaraItem->goalAnimState = LS_STOP; - LaraItem->currentAnimState = LS_STOP; + LaraItem->goalAnimState = LS_IDLE; + LaraItem->currentAnimState = LS_IDLE; LaraItem->pos.xPos -= JEEP_GETOFF_DISTANCE * phd_sin(LaraItem->pos.yRot); LaraItem->pos.zPos -= JEEP_GETOFF_DISTANCE * phd_cos(LaraItem->pos.yRot); LaraItem->pos.xRot = 0; LaraItem->pos.zRot = 0; Lara.Vehicle = NO_ITEM; - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; return false; } } @@ -429,7 +429,7 @@ static int GetOnJeep(int itemNumber) if (Lara.gunStatus) return 0; - if (LaraItem->currentAnimState != LS_STOP) + if (LaraItem->currentAnimState != LS_IDLE) return 0; if (LaraItem->animNumber != LA_STAND_IDLE) diff --git a/TR5Main/Objects/TR4/Vehicles/motorbike.cpp b/TR5Main/Objects/TR4/Vehicles/motorbike.cpp index bef25ea3c..a3569a7d1 100644 --- a/TR5Main/Objects/TR4/Vehicles/motorbike.cpp +++ b/TR5Main/Objects/TR4/Vehicles/motorbike.cpp @@ -298,7 +298,7 @@ static BOOL GetOnMotorBike(short itemNumber) short room_number; item = &g_Level.Items[itemNumber]; - if (item->flags & ONESHOT || Lara.gunStatus != LG_NO_ARMS || LaraItem->gravityStatus) + if (item->flags & ONESHOT || Lara.gunStatus != LG_HANDS_FREE || LaraItem->gravityStatus) return false; if ((abs(item->pos.yPos - LaraItem->pos.yPos) >= STEP_SIZE || !(TrInput & IN_ACTION)) && g_Gui.GetInventoryItemChosen() != ID_PUZZLE_ITEM1) @@ -364,7 +364,7 @@ void MotorbikeCollision(short itemNumber, ITEM_INFO* laraitem, COLL_INFO* coll) Lara.flareAge = 0; } - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; short angle = phd_atan(item->pos.zPos - laraitem->pos.zPos, item->pos.xPos - laraitem->pos.xPos) - item->pos.yRot; if (angle <= -ANGLE(45.0f) || angle >= ANGLE(135.0f)) @@ -547,14 +547,14 @@ static int MotorBikeCheckGetOff(void) LaraItem->pos.yRot -= 0x4000; LaraItem->animNumber = LA_STAND_SOLID; LaraItem->frameNumber = g_Level.Anims[LaraItem->animNumber].frameBase; - LaraItem->goalAnimState = LS_STOP; - LaraItem->currentAnimState = LS_STOP; + LaraItem->goalAnimState = LS_IDLE; + LaraItem->currentAnimState = LS_IDLE; LaraItem->pos.xPos -= 2 * phd_sin(item->pos.yRot); LaraItem->pos.zPos -= 2 * phd_cos(item->pos.yRot); LaraItem->pos.xRot = 0; LaraItem->pos.zRot = 0; Lara.Vehicle = NO_ITEM; - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; Lara.sprintTimer = 120; return true; } diff --git a/TR5Main/Objects/TR5/Object/tr5_pushableblock.cpp b/TR5Main/Objects/TR5/Object/tr5_pushableblock.cpp index b851966ff..7b8073fbe 100644 --- a/TR5Main/Objects/TR5/Object/tr5_pushableblock.cpp +++ b/TR5Main/Objects/TR5/Object/tr5_pushableblock.cpp @@ -243,7 +243,7 @@ void PushableBlockControl(short itemNumber) MoveStackXZ(itemNumber); //SoundEffect(pushable->stopSound, &item->pos, 2); DoPushPull = 0; - LaraItem->goalAnimState = LS_STOP; + LaraItem->goalAnimState = LS_IDLE; item->gravityStatus = true; // do fall return; @@ -255,7 +255,7 @@ void PushableBlockControl(short itemNumber) { if (!TestBlockPush(item, blockHeight, quadrant)) { - LaraItem->goalAnimState = LS_STOP; + LaraItem->goalAnimState = LS_IDLE; } else { @@ -266,7 +266,7 @@ void PushableBlockControl(short itemNumber) } else { - LaraItem->goalAnimState = LS_STOP; + LaraItem->goalAnimState = LS_IDLE; } } break; @@ -317,7 +317,7 @@ void PushableBlockControl(short itemNumber) { if (!TestBlockPull(item, blockHeight, quadrant)) { - LaraItem->goalAnimState = LS_STOP; + LaraItem->goalAnimState = LS_IDLE; } else { @@ -328,7 +328,7 @@ void PushableBlockControl(short itemNumber) } else { - LaraItem->goalAnimState = LS_STOP; + LaraItem->goalAnimState = LS_IDLE; } } break; @@ -375,7 +375,7 @@ void PushableBlockCollision(short itemNum, ITEM_INFO* l, COLL_INFO* coll) int blockHeight = GetStackHeight(item); if ((!(TrInput & IN_ACTION) - || l->currentAnimState != LS_STOP + || l->currentAnimState != LS_IDLE || l->animNumber != LA_STAND_IDLE || l->gravityStatus || Lara.gunStatus @@ -515,7 +515,7 @@ void PushableBlockCollision(short itemNum, ITEM_INFO* l, COLL_INFO* coll) if (Lara.isMoving && Lara.interactedItem == itemNum) { Lara.isMoving = false; - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; } item->pos.yRot = rot; } diff --git a/TR5Main/Objects/TR5/Switch/tr5_crowdove_switch.cpp b/TR5Main/Objects/TR5/Switch/tr5_crowdove_switch.cpp index 1c0ad913e..e6d939124 100644 --- a/TR5Main/Objects/TR5/Switch/tr5_crowdove_switch.cpp +++ b/TR5Main/Objects/TR5/Switch/tr5_crowdove_switch.cpp @@ -38,7 +38,7 @@ namespace TEN::Entities::TR5 || !(item->meshBits & 4) || (!(TrInput & IN_ACTION) || Lara.gunStatus - || l->currentAnimState != LS_STOP + || l->currentAnimState != LS_IDLE || l->animNumber != LA_STAND_IDLE || l->gravityStatus) && (!Lara.isMoving || Lara.interactedItem != itemNum)) @@ -85,7 +85,7 @@ namespace TEN::Entities::TR5 if (Lara.isMoving && Lara.interactedItem == itemNum) { Lara.isMoving = false; - Lara.gunStatus = LG_NO_ARMS; + Lara.gunStatus = LG_HANDS_FREE; } item->pos.yRot = oldYrot; } diff --git a/TR5Main/Objects/TR5/Trap/tr5_deathslide.cpp b/TR5Main/Objects/TR5/Trap/tr5_deathslide.cpp index 81136f19c..4c8aedd46 100644 --- a/TR5Main/Objects/TR5/Trap/tr5_deathslide.cpp +++ b/TR5Main/Objects/TR5/Trap/tr5_deathslide.cpp @@ -25,7 +25,7 @@ void InitialiseDeathSlide(short itemNumber) void DeathSlideCollision(short itemNumber, ITEM_INFO* l, COLL_INFO* coll) { - if (!(TrInput & IN_ACTION) || l->gravityStatus || Lara.gunStatus != LG_NO_ARMS || l->currentAnimState != LS_STOP) + if (!(TrInput & IN_ACTION) || l->gravityStatus || Lara.gunStatus != LG_HANDS_FREE || l->currentAnimState != LS_IDLE) return; ITEM_INFO* item = &g_Level.Items[itemNumber]; diff --git a/TR5Main/Renderer/Renderer11Lara.cpp b/TR5Main/Renderer/Renderer11Lara.cpp index d373e03c4..0b9911488 100644 --- a/TR5Main/Renderer/Renderer11Lara.cpp +++ b/TR5Main/Renderer/Renderer11Lara.cpp @@ -26,7 +26,7 @@ bool shouldAnimateUpperBody(const LARA_WEAPON_TYPE& weapon) { case WEAPON_GRENADE_LAUNCHER: case WEAPON_CROSSBOW: case WEAPON_SHOTGUN: - return (LaraItem->currentAnimState == LS_STOP || LaraItem->currentAnimState == LS_TURN_FAST || LaraItem->currentAnimState == LS_TURN_LEFT_SLOW || LaraItem->currentAnimState == LS_TURN_RIGHT_SLOW); + return (LaraItem->currentAnimState == LS_IDLE || LaraItem->currentAnimState == LS_TURN_LEFT_FAST || LaraItem->currentAnimState == LS_TURN_RIGHT_FAST || LaraItem->currentAnimState == LS_TURN_LEFT_SLOW || LaraItem->currentAnimState == LS_TURN_RIGHT_SLOW); break; case WEAPON_HK: { @@ -35,7 +35,7 @@ bool shouldAnimateUpperBody(const LARA_WEAPON_TYPE& weapon) { if(laraInfo.rightArm.animNumber - baseAnim == 0 || laraInfo.rightArm.animNumber - baseAnim == 2 || laraInfo.rightArm.animNumber - baseAnim == 4){ return true; } else - return (LaraItem->currentAnimState == LS_STOP || LaraItem->currentAnimState == LS_TURN_FAST || LaraItem->currentAnimState == LS_TURN_LEFT_SLOW || LaraItem->currentAnimState == LS_TURN_RIGHT_SLOW); + return (LaraItem->currentAnimState == LS_IDLE || LaraItem->currentAnimState == LS_TURN_LEFT_FAST || LaraItem->currentAnimState == LS_TURN_RIGHT_FAST || LaraItem->currentAnimState == LS_TURN_LEFT_SLOW || LaraItem->currentAnimState == LS_TURN_RIGHT_SLOW); } break; default: @@ -86,7 +86,7 @@ void Renderer11::updateLaraAnimations(bool force) updateAnimation(item, laraObj, framePtr, frac, rate, mask); // Then the arms, based on current weapon status - if (Lara.gunType != WEAPON_FLARE && (Lara.gunStatus == LG_NO_ARMS || Lara.gunStatus == LG_HANDS_BUSY) || Lara.gunType == WEAPON_FLARE && !Lara.flareControlLeft) + if (Lara.gunType != WEAPON_FLARE && (Lara.gunStatus == LG_HANDS_FREE || Lara.gunStatus == LG_HANDS_BUSY) || Lara.gunType == WEAPON_FLARE && !Lara.flareControlLeft) { // Both arms mask = MESH_BITS(LM_LINARM) | MESH_BITS(LM_LOUTARM) | MESH_BITS(LM_LHAND) | MESH_BITS(LM_RINARM) | MESH_BITS(LM_ROUTARM) | MESH_BITS(LM_RHAND); diff --git a/TR5Main/Scripting/GameScriptAnimations.cpp b/TR5Main/Scripting/GameScriptAnimations.cpp index 12353abb1..579671e22 100644 --- a/TR5Main/Scripting/GameScriptAnimations.cpp +++ b/TR5Main/Scripting/GameScriptAnimations.cpp @@ -10,11 +10,12 @@ New custom animations which Lara can perform. void GameScriptAnimations::Register(sol::state* lua) { lua->new_usertype("Animations", - "crawlExtra", &GameScriptAnimations::CrawlExtra, + "crawlExtended", &GameScriptAnimations::CrawlExtended, "crouchRoll", &GameScriptAnimations::CrouchRoll, - "monkeyRoll", &GameScriptAnimations::MonkeyRoll, - "monkeyVault", &GameScriptAnimations::MonkeyVault, - "oscillateHanging", &GameScriptAnimations::OscillateHanging, - "swandiveRollRun", &GameScriptAnimations::SwandiveRollRun + "crawlspaceSwandive", &GameScriptAnimations::CrawlspaceSwandive, + "monkeyTurn180", &GameScriptAnimations::MonkeyTurn180, + "monkeyAutoJump", &GameScriptAnimations::MonkeyAutoJump, + "oscillateHang", &GameScriptAnimations::OscillateHang, + "pose", &GameScriptAnimations::Pose ); } \ No newline at end of file diff --git a/TR5Main/Scripting/GameScriptAnimations.h b/TR5Main/Scripting/GameScriptAnimations.h index b3c180089..893185288 100644 --- a/TR5Main/Scripting/GameScriptAnimations.h +++ b/TR5Main/Scripting/GameScriptAnimations.h @@ -9,12 +9,13 @@ namespace sol { struct GameScriptAnimations { + bool CrawlExtended; // Extended crawl moveset bool CrouchRoll; // Crouch roll - bool MonkeyRoll; // The 180 degrees roll on monkeybars - bool CrawlExtra; // All extra crawl moves - bool MonkeyVault; // Vault up to monkeybars when pressing up + action underneath them - bool SwandiveRollRun; // The transition from swandive roll to run - bool OscillateHanging; // The thin ledge grab animation from TR1 and 2 + bool CrawlspaceSwandive; // Swandive into crawlspaces + bool MonkeyTurn180; // 180 degree turn on monkey swing + bool MonkeyAutoJump; // Auto jump to monkey swing when pressing UP + ACTION beneath + bool OscillateHang; // Grab thin ledge animation from TR1 and 2 + bool Pose; // Crossed arms AFK posing static void Register(sol::state* lua); }; \ No newline at end of file diff --git a/TR5Main/Specific/input.cpp b/TR5Main/Specific/input.cpp index 53423d1d0..521dd3956 100644 --- a/TR5Main/Specific/input.cpp +++ b/TR5Main/Specific/input.cpp @@ -250,9 +250,9 @@ int S_UpdateInput() if (Key(KEY_OPTION)) linput |= IN_OPTION; if (Key(KEY_STEPL)) - linput |= IN_WALK | IN_LEFT; + linput |= IN_LSTEP; if (Key(KEY_STEPR)) - linput |= IN_WALK | IN_RIGHT; + linput |= IN_RSTEP; if (Key(KEY_PAUSE)) linput |= IN_PAUSE; if (Key(KEY_SELECT)) diff --git a/TR5Main/Specific/input.h b/TR5Main/Specific/input.h index 0746570fd..2edca70b2 100644 --- a/TR5Main/Specific/input.h +++ b/TR5Main/Specific/input.h @@ -187,6 +187,7 @@ enum INPUT_BUTTONS }; #define IN_OPTIC_CONTROLS (IN_FORWARD | IN_BACK | IN_LEFT | IN_RIGHT | IN_ACTION | IN_SELECT | IN_DUCK | IN_SPRINT) +#define IN_WAKE (IN_FORWARD | IN_BACK | IN_LEFT | IN_RIGHT | IN_LSTEP | IN_RSTEP | IN_WALK | IN_JUMP | IN_SPRINT | IN_ROLL | IN_DUCK | IN_DRAW | IN_FLARE | IN_ACTION) enum IKEYS { diff --git a/TR5Main/Specific/savegame/flatbuffers/ten_savegame_generated.h b/TR5Main/Specific/savegame/flatbuffers/ten_savegame_generated.h index f13f712aa..e7c8d605f 100644 --- a/TR5Main/Specific/savegame/flatbuffers/ten_savegame_generated.h +++ b/TR5Main/Specific/savegame/flatbuffers/ten_savegame_generated.h @@ -1389,8 +1389,11 @@ struct LaraT : public flatbuffers::NativeTable { int32_t water_status = 0; int32_t climb_status = 0; int32_t pose_count = 0; + int32_t jump_count = 0; + bool jump_queued = false; int32_t hit_frame = 0; int32_t hit_direction = 0; + int32_t sprint_timer = 0; int32_t air = 0; int32_t dive_count = 0; int32_t death_count = 0; @@ -1409,7 +1412,7 @@ struct LaraT : public flatbuffers::NativeTable { int32_t flare_control_left = 0; bool look = false; bool burn = false; - bool keep_ducked = false; + bool keep_crouched = false; bool is_moving = false; bool can_monkey_swing = false; int32_t burn_blue = 0; @@ -1506,104 +1509,107 @@ struct Lara FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { VT_WATER_STATUS = 22, VT_CLIMB_STATUS = 24, VT_POSE_COUNT = 26, - VT_HIT_FRAME = 28, - VT_HIT_DIRECTION = 30, - VT_AIR = 32, - VT_DIVE_COUNT = 34, - VT_DEATH_COUNT = 36, - VT_CURRENT_ACTIVE = 38, - VT_CURRENT_X_VEL = 40, - VT_CURRENT_Y_VEL = 42, - VT_CURRENT_Z_VEL = 44, - VT_SPAZ_EFFECT_COUNT = 46, - VT_FLARE_AGE = 48, - VT_BURN_COUNT = 50, - VT_WEAPON_ITEM = 52, - VT_HOLSTER_INFO = 54, - VT_FLARE_FRAME = 56, - VT_POISONED = 58, - VT_WET = 60, - VT_FLARE_CONTROL_LEFT = 62, - VT_LOOK = 64, - VT_BURN = 66, - VT_KEEP_DUCKED = 68, - VT_IS_MOVING = 70, - VT_CAN_MONKEY_SWING = 72, - VT_BURN_BLUE = 74, - VT_BURN_SMOKE = 76, - VT_IS_DUCKED = 78, - VT_HAS_FIRED = 80, - VT_BUSY = 82, - VT_OLD_BUSY = 84, - VT_UNCONTROLLABLE = 86, - VT_LIT_TORCH = 88, - VT_IS_CLIMBING = 90, - VT_FIRED = 92, - VT_WATER_SURFACE_DIST = 94, - VT_LAST_POSITION = 96, - VT_NEXT_CORNER_POSITION = 98, - VT_NEXT_CORNER_ROTATION = 100, - VT_MESH_PTRS = 102, - VT_TARGET_ANGLES = 104, - VT_TURN_RATE = 106, - VT_MOVE_ANGLE = 108, - VT_HEAD_X_ROT = 110, - VT_HEAD_Y_ROT = 112, - VT_HEAD_Z_ROT = 114, - VT_TORSO_X_ROT = 116, - VT_TORSO_Y_ROT = 118, - VT_TORSO_Z_ROT = 120, - VT_LEFT_ARM = 122, - VT_RIGHT_ARM = 124, - VT_ROPE_SEGMENT = 126, - VT_ROPE_DIRECTION = 128, - VT_ROPE_ARC_FRONT = 130, - VT_ROPE_ARC_BACK = 132, - VT_ROPE_LAST_X = 134, - VT_ROPE_MAX_X_FORWARD = 136, - VT_ROPE_MAX_X_BACKWARD = 138, - VT_ROPE_DFRAME = 140, - VT_ROPE_FRAME = 142, - VT_ROPE_FRAMERATE = 144, - VT_ROPE_Y = 146, - VT_ROPE_PTR = 148, - VT_INTERACTED_ITEM = 150, - VT_ROPE_OFFSET = 152, - VT_ROPE_DOWN_VEL = 154, - VT_ROPE_FLAG = 156, - VT_ROPE_COUNT = 158, - VT_MOVE_COUNT = 160, - VT_LOCATION = 162, - VT_HIGHEST_LOCATION = 164, - VT_LOCATION_PAD = 166, - VT_TIGHTROPE = 168, - VT_BEETLE_LIFE = 170, - VT_HAS_BEETLE_THINGS = 172, - VT_SMALL_WATERSKIN = 174, - VT_BIG_WATERSKIN = 176, - VT_VEHICLE = 178, - VT_EXTRA_ANIM = 180, - VT_MINE_L = 182, - VT_MINE_R = 184, - VT_WEAPONS = 186, - VT_PUZZLES = 188, - VT_KEYS = 190, - VT_PICKUPS = 192, - VT_EXAMINES = 194, - VT_PUZZLES_COMBO = 196, - VT_KEYS_COMBO = 198, - VT_PICKUPS_COMBO = 200, - VT_EXAMINES_COMBO = 202, - VT_SECRETS = 204, - VT_LASERSIGHT = 206, - VT_CROWBAR = 208, - VT_TORCH = 210, - VT_SILENCER = 212, - VT_BINOCULARS = 214, - VT_NUM_LARGE_MEDIPACKS = 216, - VT_NUM_SMALL_MEDIPACKS = 218, - VT_NUM_FLARES = 220, - VT_TARGET_ITEM_NUMBER = 222 + VT_JUMP_COUNT = 28, + VT_JUMP_QUEUED = 30, + VT_HIT_FRAME = 32, + VT_HIT_DIRECTION = 34, + VT_SPRINT_TIMER = 36, + VT_AIR = 38, + VT_DIVE_COUNT = 40, + VT_DEATH_COUNT = 42, + VT_CURRENT_ACTIVE = 44, + VT_CURRENT_X_VEL = 46, + VT_CURRENT_Y_VEL = 48, + VT_CURRENT_Z_VEL = 50, + VT_SPAZ_EFFECT_COUNT = 52, + VT_FLARE_AGE = 54, + VT_BURN_COUNT = 56, + VT_WEAPON_ITEM = 58, + VT_HOLSTER_INFO = 60, + VT_FLARE_FRAME = 62, + VT_POISONED = 64, + VT_WET = 66, + VT_FLARE_CONTROL_LEFT = 68, + VT_LOOK = 70, + VT_BURN = 72, + VT_KEEP_CROUCHED = 74, + VT_IS_MOVING = 76, + VT_CAN_MONKEY_SWING = 78, + VT_BURN_BLUE = 80, + VT_BURN_SMOKE = 82, + VT_IS_DUCKED = 84, + VT_HAS_FIRED = 86, + VT_BUSY = 88, + VT_OLD_BUSY = 90, + VT_UNCONTROLLABLE = 92, + VT_LIT_TORCH = 94, + VT_IS_CLIMBING = 96, + VT_FIRED = 98, + VT_WATER_SURFACE_DIST = 100, + VT_LAST_POSITION = 102, + VT_NEXT_CORNER_POSITION = 104, + VT_NEXT_CORNER_ROTATION = 106, + VT_MESH_PTRS = 108, + VT_TARGET_ANGLES = 110, + VT_TURN_RATE = 112, + VT_MOVE_ANGLE = 114, + VT_HEAD_X_ROT = 116, + VT_HEAD_Y_ROT = 118, + VT_HEAD_Z_ROT = 120, + VT_TORSO_X_ROT = 122, + VT_TORSO_Y_ROT = 124, + VT_TORSO_Z_ROT = 126, + VT_LEFT_ARM = 128, + VT_RIGHT_ARM = 130, + VT_ROPE_SEGMENT = 132, + VT_ROPE_DIRECTION = 134, + VT_ROPE_ARC_FRONT = 136, + VT_ROPE_ARC_BACK = 138, + VT_ROPE_LAST_X = 140, + VT_ROPE_MAX_X_FORWARD = 142, + VT_ROPE_MAX_X_BACKWARD = 144, + VT_ROPE_DFRAME = 146, + VT_ROPE_FRAME = 148, + VT_ROPE_FRAMERATE = 150, + VT_ROPE_Y = 152, + VT_ROPE_PTR = 154, + VT_INTERACTED_ITEM = 156, + VT_ROPE_OFFSET = 158, + VT_ROPE_DOWN_VEL = 160, + VT_ROPE_FLAG = 162, + VT_ROPE_COUNT = 164, + VT_MOVE_COUNT = 166, + VT_LOCATION = 168, + VT_HIGHEST_LOCATION = 170, + VT_LOCATION_PAD = 172, + VT_TIGHTROPE = 174, + VT_BEETLE_LIFE = 176, + VT_HAS_BEETLE_THINGS = 178, + VT_SMALL_WATERSKIN = 180, + VT_BIG_WATERSKIN = 182, + VT_VEHICLE = 184, + VT_EXTRA_ANIM = 186, + VT_MINE_L = 188, + VT_MINE_R = 190, + VT_WEAPONS = 192, + VT_PUZZLES = 194, + VT_KEYS = 196, + VT_PICKUPS = 198, + VT_EXAMINES = 200, + VT_PUZZLES_COMBO = 202, + VT_KEYS_COMBO = 204, + VT_PICKUPS_COMBO = 206, + VT_EXAMINES_COMBO = 208, + VT_SECRETS = 210, + VT_LASERSIGHT = 212, + VT_CROWBAR = 214, + VT_TORCH = 216, + VT_SILENCER = 218, + VT_BINOCULARS = 220, + VT_NUM_LARGE_MEDIPACKS = 222, + VT_NUM_SMALL_MEDIPACKS = 224, + VT_NUM_FLARES = 226, + VT_TARGET_ITEM_NUMBER = 228 }; int32_t item_number() const { return GetField(VT_ITEM_NUMBER, 0); @@ -1641,12 +1647,21 @@ struct Lara FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { int32_t pose_count() const { return GetField(VT_POSE_COUNT, 0); } + int32_t jump_count() const { + return GetField(VT_JUMP_COUNT, 0); + } + bool jump_queued() const { + return GetField(VT_JUMP_QUEUED, 0) != 0; + } int32_t hit_frame() const { return GetField(VT_HIT_FRAME, 0); } int32_t hit_direction() const { return GetField(VT_HIT_DIRECTION, 0); } + int32_t sprint_timer() const { + return GetField(VT_SPRINT_TIMER, 0); + } int32_t air() const { return GetField(VT_AIR, 0); } @@ -1701,8 +1716,8 @@ struct Lara FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { bool burn() const { return GetField(VT_BURN, 0) != 0; } - bool keep_ducked() const { - return GetField(VT_KEEP_DUCKED, 0) != 0; + bool keep_crouched() const { + return GetField(VT_KEEP_CROUCHED, 0) != 0; } bool is_moving() const { return GetField(VT_IS_MOVING, 0) != 0; @@ -1949,8 +1964,11 @@ struct Lara FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { VerifyField(verifier, VT_WATER_STATUS) && VerifyField(verifier, VT_CLIMB_STATUS) && VerifyField(verifier, VT_POSE_COUNT) && + VerifyField(verifier, VT_JUMP_COUNT) && + VerifyField(verifier, VT_JUMP_QUEUED) && VerifyField(verifier, VT_HIT_FRAME) && VerifyField(verifier, VT_HIT_DIRECTION) && + VerifyField(verifier, VT_SPRINT_TIMER) && VerifyField(verifier, VT_AIR) && VerifyField(verifier, VT_DIVE_COUNT) && VerifyField(verifier, VT_DEATH_COUNT) && @@ -1971,7 +1989,7 @@ struct Lara FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { VerifyField(verifier, VT_FLARE_CONTROL_LEFT) && VerifyField(verifier, VT_LOOK) && VerifyField(verifier, VT_BURN) && - VerifyField(verifier, VT_KEEP_DUCKED) && + VerifyField(verifier, VT_KEEP_CROUCHED) && VerifyField(verifier, VT_IS_MOVING) && VerifyField(verifier, VT_CAN_MONKEY_SWING) && VerifyField(verifier, VT_BURN_BLUE) && @@ -2111,12 +2129,21 @@ struct LaraBuilder { void add_pose_count(int32_t pose_count) { fbb_.AddElement(Lara::VT_POSE_COUNT, pose_count, 0); } + void add_jump_count(int32_t jump_count) { + fbb_.AddElement(Lara::VT_JUMP_COUNT, jump_count, 0); + } + void add_jump_queued(bool jump_queued) { + fbb_.AddElement(Lara::VT_JUMP_QUEUED, static_cast(jump_queued), 0); + } void add_hit_frame(int32_t hit_frame) { fbb_.AddElement(Lara::VT_HIT_FRAME, hit_frame, 0); } void add_hit_direction(int32_t hit_direction) { fbb_.AddElement(Lara::VT_HIT_DIRECTION, hit_direction, 0); } + void add_sprint_timer(int32_t sprint_timer) { + fbb_.AddElement(Lara::VT_SPRINT_TIMER, sprint_timer, 0); + } void add_air(int32_t air) { fbb_.AddElement(Lara::VT_AIR, air, 0); } @@ -2171,8 +2198,8 @@ struct LaraBuilder { void add_burn(bool burn) { fbb_.AddElement(Lara::VT_BURN, static_cast(burn), 0); } - void add_keep_ducked(bool keep_ducked) { - fbb_.AddElement(Lara::VT_KEEP_DUCKED, static_cast(keep_ducked), 0); + void add_keep_crouched(bool keep_crouched) { + fbb_.AddElement(Lara::VT_KEEP_CROUCHED, static_cast(keep_crouched), 0); } void add_is_moving(bool is_moving) { fbb_.AddElement(Lara::VT_IS_MOVING, static_cast(is_moving), 0); @@ -2430,8 +2457,11 @@ inline flatbuffers::Offset CreateLara( int32_t water_status = 0, int32_t climb_status = 0, int32_t pose_count = 0, + int32_t jump_count = 0, + bool jump_queued = false, int32_t hit_frame = 0, int32_t hit_direction = 0, + int32_t sprint_timer = 0, int32_t air = 0, int32_t dive_count = 0, int32_t death_count = 0, @@ -2450,7 +2480,7 @@ inline flatbuffers::Offset CreateLara( int32_t flare_control_left = 0, bool look = false, bool burn = false, - bool keep_ducked = false, + bool keep_crouched = false, bool is_moving = false, bool can_monkey_swing = false, int32_t burn_blue = 0, @@ -2604,8 +2634,10 @@ inline flatbuffers::Offset CreateLara( builder_.add_death_count(death_count); builder_.add_dive_count(dive_count); builder_.add_air(air); + builder_.add_sprint_timer(sprint_timer); builder_.add_hit_direction(hit_direction); builder_.add_hit_frame(hit_frame); + builder_.add_jump_count(jump_count); builder_.add_pose_count(pose_count); builder_.add_climb_status(climb_status); builder_.add_water_status(water_status); @@ -2636,9 +2668,10 @@ inline flatbuffers::Offset CreateLara( builder_.add_burn_smoke(burn_smoke); builder_.add_can_monkey_swing(can_monkey_swing); builder_.add_is_moving(is_moving); - builder_.add_keep_ducked(keep_ducked); + builder_.add_keep_crouched(keep_crouched); builder_.add_burn(burn); builder_.add_look(look); + builder_.add_jump_queued(jump_queued); return builder_.Finish(); } @@ -2661,8 +2694,11 @@ inline flatbuffers::Offset CreateLaraDirect( int32_t water_status = 0, int32_t climb_status = 0, int32_t pose_count = 0, + int32_t jump_count = 0, + bool jump_queued = false, int32_t hit_frame = 0, int32_t hit_direction = 0, + int32_t sprint_timer = 0, int32_t air = 0, int32_t dive_count = 0, int32_t death_count = 0, @@ -2681,7 +2717,7 @@ inline flatbuffers::Offset CreateLaraDirect( int32_t flare_control_left = 0, bool look = false, bool burn = false, - bool keep_ducked = false, + bool keep_crouched = false, bool is_moving = false, bool can_monkey_swing = false, int32_t burn_blue = 0, @@ -2785,8 +2821,11 @@ inline flatbuffers::Offset CreateLaraDirect( water_status, climb_status, pose_count, + jump_count, + jump_queued, hit_frame, hit_direction, + sprint_timer, air, dive_count, death_count, @@ -2805,7 +2844,7 @@ inline flatbuffers::Offset CreateLaraDirect( flare_control_left, look, burn, - keep_ducked, + keep_crouched, is_moving, can_monkey_swing, burn_blue, @@ -5071,8 +5110,11 @@ inline void Lara::UnPackTo(LaraT *_o, const flatbuffers::resolver_function_t *_r { auto _e = water_status(); _o->water_status = _e; } { auto _e = climb_status(); _o->climb_status = _e; } { auto _e = pose_count(); _o->pose_count = _e; } + { auto _e = jump_count(); _o->jump_count = _e; } + { auto _e = jump_queued(); _o->jump_queued = _e; } { auto _e = hit_frame(); _o->hit_frame = _e; } { auto _e = hit_direction(); _o->hit_direction = _e; } + { auto _e = sprint_timer(); _o->sprint_timer = _e; } { auto _e = air(); _o->air = _e; } { auto _e = dive_count(); _o->dive_count = _e; } { auto _e = death_count(); _o->death_count = _e; } @@ -5091,7 +5133,7 @@ inline void Lara::UnPackTo(LaraT *_o, const flatbuffers::resolver_function_t *_r { auto _e = flare_control_left(); _o->flare_control_left = _e; } { auto _e = look(); _o->look = _e; } { auto _e = burn(); _o->burn = _e; } - { auto _e = keep_ducked(); _o->keep_ducked = _e; } + { auto _e = keep_crouched(); _o->keep_crouched = _e; } { auto _e = is_moving(); _o->is_moving = _e; } { auto _e = can_monkey_swing(); _o->can_monkey_swing = _e; } { auto _e = burn_blue(); _o->burn_blue = _e; } @@ -5191,8 +5233,11 @@ inline flatbuffers::Offset CreateLara(flatbuffers::FlatBufferBuilder &_fbb auto _water_status = _o->water_status; auto _climb_status = _o->climb_status; auto _pose_count = _o->pose_count; + auto _jump_count = _o->jump_count; + auto _jump_queued = _o->jump_queued; auto _hit_frame = _o->hit_frame; auto _hit_direction = _o->hit_direction; + auto _sprint_timer = _o->sprint_timer; auto _air = _o->air; auto _dive_count = _o->dive_count; auto _death_count = _o->death_count; @@ -5211,7 +5256,7 @@ inline flatbuffers::Offset CreateLara(flatbuffers::FlatBufferBuilder &_fbb auto _flare_control_left = _o->flare_control_left; auto _look = _o->look; auto _burn = _o->burn; - auto _keep_ducked = _o->keep_ducked; + auto _keep_crouched = _o->keep_crouched; auto _is_moving = _o->is_moving; auto _can_monkey_swing = _o->can_monkey_swing; auto _burn_blue = _o->burn_blue; @@ -5303,8 +5348,11 @@ inline flatbuffers::Offset CreateLara(flatbuffers::FlatBufferBuilder &_fbb _water_status, _climb_status, _pose_count, + _jump_count, + _jump_queued, _hit_frame, _hit_direction, + _sprint_timer, _air, _dive_count, _death_count, @@ -5323,7 +5371,7 @@ inline flatbuffers::Offset CreateLara(flatbuffers::FlatBufferBuilder &_fbb _flare_control_left, _look, _burn, - _keep_ducked, + _keep_crouched, _is_moving, _can_monkey_swing, _burn_blue, diff --git a/TR5Main/Specific/savegame/schema/ten_savegame.fbs b/TR5Main/Specific/savegame/schema/ten_savegame.fbs index af2732ff4..bfceb58bf 100644 --- a/TR5Main/Specific/savegame/schema/ten_savegame.fbs +++ b/TR5Main/Specific/savegame/schema/ten_savegame.fbs @@ -99,8 +99,11 @@ table Lara { water_status: int32; climb_status: int32; pose_count: int32; + jump_count: int32; + jump_queued: bool; hit_frame: int32; hit_direction: int32; + sprint_timer: int32; air: int32; dive_count: int32; death_count: int32; @@ -119,7 +122,7 @@ table Lara { flare_control_left: int32; look: bool; burn: bool; - keep_ducked: bool; + keep_crouched: bool; is_moving: bool; can_monkey_swing: bool; burn_blue: int32; diff --git a/TR5Main/TombEngine.vcxproj b/TR5Main/TombEngine.vcxproj index decc4c26b..2bad96a34 100644 --- a/TR5Main/TombEngine.vcxproj +++ b/TR5Main/TombEngine.vcxproj @@ -161,6 +161,8 @@ CALL gen.bat + + @@ -560,7 +562,9 @@ CALL gen.bat + + diff --git a/TR5Main/TombEngine.vcxproj.filters b/TR5Main/TombEngine.vcxproj.filters index efb33987e..63d07c564 100644 --- a/TR5Main/TombEngine.vcxproj.filters +++ b/TR5Main/TombEngine.vcxproj.filters @@ -316,6 +316,8 @@ + + @@ -709,6 +711,8 @@ + +