diff --git a/docs/progress.svg b/docs/progress.svg index f390208..428299f 100644 --- a/docs/progress.svg +++ b/docs/progress.svg @@ -69,10 +69,10 @@ Tomb2.exe progress according to the physical function order: -49.43% (602) · 48.11% (586) · 0% (0) · 2.46% (30) +49.51% (603) · 48.03% (585) · 0% (0) · 2.46% (30) - - + + @@ -635,7 +635,7 @@ void __cdecl undraw_flare_meshes(void); void __cdecl ready_flare(void); void __cdecl FlareControl(int16_t item_num); -void __cdecl Lara_Control(int16_t item_num); +void __cdecl Lara_Control(int16_t item_num); void __cdecl Lara_Animate(ITEM_INFO *item); void __cdecl Lara_UseItem(int16_t object_num); void __cdecl Lara_CheatGetStuff(void); @@ -1298,10 +1298,10 @@ Tomb2.exe progress according to the function sizes: -49.19% · 50.49% · 0% · 0.33% +49.67% · 50.01% · 0% · 0.33% - - + + @@ -1328,7 +1328,7 @@ int32_t __cdecl Inv_AddItem(int32_t item_num); void __cdecl Room_TestTriggers(int16_t *data, int32_t heavy); void __cdecl Collide_GetCollisionInfo(COLL_INFO *coll, int32_t xpos, int32_t ypos, int32_t zpos, int16_t room_num, int32_t obj_height); -void __cdecl Lara_Control(int16_t item_num); +void __cdecl Lara_Control(int16_t item_num); void __cdecl do_passport_option(INVENTORY_ITEM *item); void __cdecl Output_InsertGT3_ZBuffered(const PHD_VBUF *vtx0, const PHD_VBUF *vtx1, const PHD_VBUF *vtx2, const PHD_TEXTURE *texture, const PHD_UV *uv0, const PHD_UV *uv1, const PHD_UV *uv2); void __cdecl Boat_Control(int16_t item_num); diff --git a/docs/progress.txt b/docs/progress.txt index e835801..c8345f3 100644 --- a/docs/progress.txt +++ b/docs/progress.txt @@ -3279,7 +3279,7 @@ typedef enum { 0x00430070 0x026E -R void __cdecl FlareControl(int16_t item_num); # game/laramisc.c -0x004302E0 0x0668 - void __cdecl Lara_Control(int16_t item_num); +0x004302E0 0x0668 + void __cdecl Lara_Control(int16_t item_num); 0x00430970 0x02CD - void __cdecl Lara_Animate(ITEM_INFO *item); 0x00430C70 0x013F - void __cdecl Lara_UseItem(int16_t object_num); 0x00430E30 0x00BA - void __cdecl Lara_CheatGetStuff(void); diff --git a/src/game/game.c b/src/game/game.c index 02a8930..509bc1d 100644 --- a/src/game/game.c +++ b/src/game/game.c @@ -3,6 +3,7 @@ #include "game/camera.h" #include "game/input.h" #include "game/inventory.h" +#include "game/lara/lara_control.h" #include "game/music.h" #include "game/overlay.h" #include "game/room_draw.h" diff --git a/src/game/lara/lara_control.c b/src/game/lara/lara_control.c index 8d815fe..47d4d3f 100644 --- a/src/game/lara/lara_control.c +++ b/src/game/lara/lara_control.c @@ -4,7 +4,9 @@ #include "game/lara/lara_look.h" #include "game/lara/lara_misc.h" #include "game/math.h" +#include "game/music.h" #include "game/room.h" +#include "game/sound.h" #include "global/const.h" #include "global/funcs.h" #include "global/vars.h" @@ -219,3 +221,243 @@ void __cdecl Lara_HandleUnderwater(ITEM_INFO *const item, COLL_INFO *const coll) LaraGun(); Room_TestTriggers(coll->trigger, 0); } + +void __cdecl Lara_Control(const int16_t item_num) +{ + ITEM_INFO *const item = g_LaraItem; + + const bool room_submerged = g_Rooms[item->room_num].flags & RF_UNDERWATER; + const int32_t water_depth = Lara_GetWaterDepth( + item->pos.x, item->pos.y, item->pos.z, item->room_num); + const int32_t water_height = Room_GetWaterHeight( + item->pos.x, item->pos.y, item->pos.z, item->room_num); + const int32_t water_height_diff = + water_height == NO_HEIGHT ? NO_HEIGHT : item->pos.y - water_height; + + g_Lara.water_surface_dist = -water_height_diff; + + if (g_Lara.skidoo == NO_ITEM && !g_Lara.extra_anim) { + switch (g_Lara.water_status) { + case LWS_ABOVE_WATER: + if (water_height_diff == NO_HEIGHT + || water_height_diff < LARA_WADE_DEPTH) { + break; + } + + if (water_depth <= LARA_SWIM_DEPTH - STEP_L) { + if (water_height_diff > LARA_WADE_DEPTH) { + g_Lara.water_status = LWS_WADE; + if (!item->gravity) { + item->goal_anim_state = LS_STOP; + } + } + } else if (room_submerged) { + g_Lara.air = LARA_MAX_AIR; + g_Lara.water_status = LWS_UNDERWATER; + item->gravity = 0; + item->pos.y += 100; + Item_UpdateRoom(item, 0); + Sound_StopEffect(SFX_LARA_FALL); + if (item->current_anim_state == LS_SWAN_DIVE) { + item->rot.x = -45 * PHD_DEGREE; + item->goal_anim_state = LS_DIVE; + Lara_Animate(item); + item->fall_speed *= 2; + } else if (item->current_anim_state == LS_FAST_DIVE) { + item->rot.x = -85 * PHD_DEGREE; + item->goal_anim_state = LS_DIVE; + Lara_Animate(item); + item->fall_speed *= 2; + } else { + item->rot.x = -45 * PHD_DEGREE; + item->anim_num = LA_FREEFALL_TO_UNDERWATER; + item->frame_num = g_Anims[item->anim_num].frame_base; + item->current_anim_state = LS_DIVE; + item->goal_anim_state = LS_SWIM; + item->fall_speed = item->fall_speed * 3 / 2; + } + g_Lara.torso_y_rot = 0; + g_Lara.torso_x_rot = 0; + g_Lara.head_y_rot = 0; + g_Lara.head_x_rot = 0; + Splash(item); + } + break; + + case LWS_UNDERWATER: + if (room_submerged) { + break; + } + + if (water_depth == NO_HEIGHT || ABS(water_height_diff) >= STEP_L) { + g_Lara.water_status = LWS_ABOVE_WATER; + item->anim_num = LA_FALL_START; + item->frame_num = g_Anims[item->anim_num].frame_base; + item->goal_anim_state = LS_FORWARD_JUMP; + item->current_anim_state = LS_FORWARD_JUMP; + item->gravity = 1; + item->speed = item->fall_speed / 4; + item->fall_speed = 0; + item->rot.x = 0; + item->rot.z = 0; + g_Lara.torso_y_rot = 0; + g_Lara.torso_x_rot = 0; + g_Lara.head_y_rot = 0; + g_Lara.head_x_rot = 0; + } else { + g_Lara.water_status = LWS_SURFACE; + item->anim_num = LA_UNDERWATER_TO_ONWATER; + item->frame_num = g_Anims[item->anim_num].frame_base; + item->goal_anim_state = LS_SURF_TREAD; + item->current_anim_state = LS_SURF_TREAD; + item->fall_speed = 0; + item->pos.y += 1 - water_height_diff; + item->rot.z = 0; + item->rot.x = 0; + g_Lara.dive_count = 11; + g_Lara.torso_y_rot = 0; + g_Lara.torso_x_rot = 0; + g_Lara.head_y_rot = 0; + g_Lara.head_x_rot = 0; + Item_UpdateRoom(item, -381); + Sound_Effect(SFX_LARA_BREATH, &item->pos, SPM_ALWAYS); + } + break; + + case LWS_SURFACE: + if (room_submerged) { + break; + } + + if (water_height_diff <= LARA_WADE_DEPTH) { + g_Lara.water_status = LWS_ABOVE_WATER; + item->anim_num = LA_FALL_START; + item->frame_num = g_Anims[item->anim_num].frame_base; + item->goal_anim_state = LS_FORWARD_JUMP; + item->current_anim_state = LS_FORWARD_JUMP; + item->gravity = 1; + item->speed = item->fall_speed / 4; + } else { + g_Lara.water_status = LWS_WADE; + item->anim_num = LA_STAND_IDLE; + item->frame_num = g_Anims[item->anim_num].frame_base; + item->current_anim_state = LS_STOP; + item->goal_anim_state = LS_WADE; + Item_Animate(item); + item->fall_speed = 0; + } + item->rot.x = 0; + item->rot.z = 0; + g_Lara.torso_y_rot = 0; + g_Lara.torso_x_rot = 0; + g_Lara.head_y_rot = 0; + g_Lara.head_x_rot = 0; + break; + + case LWS_WADE: + g_Camera.target_elevation = -22 * PHD_DEGREE; + + if (water_height_diff < LARA_WADE_DEPTH) { + g_Lara.water_status = LWS_ABOVE_WATER; + if (item->current_anim_state == LS_WADE) { + item->goal_anim_state = LS_RUN; + } + } else if (water_height_diff > 730) { + g_Lara.water_status = LWS_SURFACE; + item->pos.y += 1 - water_height_diff; + + switch (item->current_anim_state) { + case LS_BACK: + item->goal_anim_state = LS_SURF_BACK; + item->anim_num = LA_ONWATER_IDLE_TO_SWIM_BACK; + break; + + case LS_STEP_RIGHT: + item->goal_anim_state = LS_SURF_RIGHT; + item->anim_num = LA_ONWATER_SWIM_RIGHT; + break; + + case LS_STEP_LEFT: + item->goal_anim_state = LS_SURF_LEFT; + item->anim_num = LA_ONWATER_SWIM_LEFT; + break; + + default: + item->goal_anim_state = LS_SURF_SWIM; + item->anim_num = LA_ONWATER_SWIM_FORWARD; + break; + } + item->current_anim_state = item->goal_anim_state; + item->frame_num = g_Anims[item->anim_num].frame_base; + + item->rot.z = 0; + item->rot.x = 0; + item->gravity = 0; + item->fall_speed = 0; + g_Lara.dive_count = 0; + g_Lara.torso_y_rot = 0; + g_Lara.torso_x_rot = 0; + g_Lara.head_y_rot = 0; + g_Lara.head_x_rot = 0; + Item_UpdateRoom(item, -LARA_HEIGHT / 2); + } + break; + + default: + break; + } + } + + if (item->hit_points <= 0) { + item->hit_points = -1; + if (!g_Lara.death_count) { + Music_Stop(); + } + g_Lara.death_count++; + if (item->flags & IF_ONE_SHOT) { + g_Lara.death_count++; + return; + } + } else if (g_GF_NoFloor && item->pos.y >= g_GF_NoFloor) { + item->hit_points = -1; + g_Lara.death_count = 9 * FRAMES_PER_SECOND; + } + + COLL_INFO coll; + switch (g_Lara.water_status) { + case LWS_ABOVE_WATER: + case LWS_WADE: + g_Lara.air = LARA_MAX_AIR; + Lara_HandleAboveWater(item, &coll); + break; + + case LWS_UNDERWATER: + if (item->hit_points >= 0) { + g_Lara.air--; + if (g_Lara.air < 0) { + g_Lara.air = -1; + item->hit_points -= 5; + } + } + Lara_HandleUnderwater(item, &coll); + break; + + case LWS_SURFACE: + if (item->hit_points >= 0) { + g_Lara.air += 10; + CLAMPG(g_Lara.air, LARA_MAX_AIR); + } + Lara_HandleSurface(item, &coll); + break; + + default: + break; + } + + g_SaveGame.statistics.distance += Math_Sqrt( + SQUARE(item->pos.z - g_Lara.last_pos.z) + + SQUARE(item->pos.y - g_Lara.last_pos.y) + + SQUARE(item->pos.x - g_Lara.last_pos.x)); + + g_Lara.last_pos = item->pos; +} diff --git a/src/game/lara/lara_control.h b/src/game/lara/lara_control.h index c52091b..d059642 100644 --- a/src/game/lara/lara_control.h +++ b/src/game/lara/lara_control.h @@ -7,3 +7,5 @@ void __cdecl Lara_HandleAboveWater(ITEM_INFO *item, COLL_INFO *coll); void __cdecl Lara_HandleSurface(ITEM_INFO *item, COLL_INFO *coll); void __cdecl Lara_HandleUnderwater(ITEM_INFO *item, COLL_INFO *coll); + +void __cdecl Lara_Control(int16_t item_num); diff --git a/src/global/const.h b/src/global/const.h index 65a00d3..71ff5ca 100644 --- a/src/global/const.h +++ b/src/global/const.h @@ -83,12 +83,14 @@ #define LARA_UW_FRICTION 6 #define LARA_CLIMB_WIDTH_LEFT 80 #define LARA_CLIMB_WIDTH_RIGHT 120 +#define LARA_CLIMB_HEIGHT (WALL_L / 2) // = 512 +#define LARA_WADE_DEPTH 384 +#define LARA_SWIM_DEPTH 730 #define LARA_RADIUS 100 #define LARA_RADIUS_UW 300 #define LARA_HEIGHT 762 #define LARA_HEIGHT_SURF 700 #define LARA_HEIGHT_UW 400 -#define LARA_CLIMB_HEIGHT (WALL_L / 2) // = 512 #define LARA_DEFLECT_ANGLE (5 * PHD_DEGREE) // = 910 #define LARA_HANG_ANGLE (35 * PHD_DEGREE) // = 6370 #define LARA_VAULT_ANGLE (30 * PHD_DEGREE) // = 5460 diff --git a/src/global/funcs.h b/src/global/funcs.h index 28e914c..903b518 100644 --- a/src/global/funcs.h +++ b/src/global/funcs.h @@ -194,7 +194,6 @@ #define undraw_flare_meshes ((void __cdecl (*)(void))0x00430010) #define ready_flare ((void __cdecl (*)(void))0x00430030) #define FlareControl ((void __cdecl (*)(int16_t item_num))0x00430070) -#define Lara_Control ((void __cdecl (*)(int16_t item_num))0x004302E0) #define Lara_Animate ((void __cdecl (*)(ITEM_INFO *item))0x00430970) #define Lara_UseItem ((void __cdecl (*)(int16_t object_num))0x00430C70) #define Lara_CheatGetStuff ((void __cdecl (*)(void))0x00430E30) diff --git a/src/inject_exec.c b/src/inject_exec.c index 8a0bd5d..057c3e9 100644 --- a/src/inject_exec.c +++ b/src/inject_exec.c @@ -524,6 +524,7 @@ static void Inject_Lara_Control(const bool enable) INJECT(enable, 0x00427580, Lara_HandleAboveWater); INJECT(enable, 0x00431670, Lara_HandleSurface); INJECT(enable, 0x00431F50, Lara_HandleUnderwater); + INJECT(enable, 0x004302E0, Lara_Control); } static void Inject_Lara_Draw(const bool enable)