From 067d7fbb0993b8ea9297bc9aa0e129605d14809f Mon Sep 17 00:00:00 2001 From: rr- Date: Wed, 10 Mar 2021 00:24:49 +0100 Subject: [PATCH] port CreateSaveGameInfo --- docs/progress.svg | 12 +-- docs/progress.txt | 14 ++-- src/game/laramisc.c | 2 +- src/game/savegame.c | 196 ++++++++++++++++++++++++++++++++++++++++++++ src/game/savegame.h | 9 +- 5 files changed, 218 insertions(+), 15 deletions(-) diff --git a/docs/progress.svg b/docs/progress.svg index 201519f58..126c02020 100644 --- a/docs/progress.svg +++ b/docs/progress.svg @@ -571,7 +571,7 @@ InitialiseStartInfo ModifyStartInfo CreateStartInfo -CreateSaveGameInfo +CreateSaveGameInfo ExtractSaveGameInfo S_DrawSprite S_DrawSpriteRel @@ -739,7 +739,7 @@ sub_40904D DrawLara ExtractSaveGameInfo -CreateSaveGameInfo +CreateSaveGameInfo CreatureAnimation GetCollisionInfo CreatureMood @@ -1463,10 +1463,10 @@ sub_440EF0 KeyGet S_CDVolume -Functions decompiled (count): 68.95% -Functions decompiled (bytesize): 67.02% -Functions not decompiled, but with known names (count): 17.24% -Functions not decompiled, but with known names (bytesize): 17.25% +Functions decompiled (count): 69.08% +Functions decompiled (bytesize): 67.88% +Functions not decompiled, but with known names (count): 17.10% +Functions not decompiled, but with known names (bytesize): 16.39% Functions not decompiled, with unknown names (count): 13.82% Functions not decompiled, with unknown names (bytesize): 15.73% diff --git a/docs/progress.txt b/docs/progress.txt index dfb9b3918..b1deb939a 100644 --- a/docs/progress.txt +++ b/docs/progress.txt @@ -807,21 +807,21 @@ VoleControl 0x00434210 0x000002B5 + # savegame.cpp ReadSGPos ---------- ---------- - -WriteSGPos ---------- ---------- - +WriteSGPos ---------- ---------- + ReadSGARM ---------- ---------- - ReadSGLOT ---------- ---------- - ReadSGLara ---------- ---------- - -WriteSGARM ---------- ---------- - -WriteSGLOT ---------- ---------- - -WriteSGLara ---------- ---------- - +WriteSGARM ---------- ---------- + +WriteSGLOT ---------- ---------- + +WriteSGLara ---------- ---------- + LoadSaveGameInfo ---------- ---------- - InitialiseStartInfo 0x004344D0 0x00000042 + ModifyStartInfo 0x00434520 0x000000BF + CreateStartInfo 0x004345E0 0x00000139 + -CreateSaveGameInfo 0x00434720 0x00000866 * +CreateSaveGameInfo 0x00434720 0x00000866 + ExtractSaveGameInfo 0x00434F90 0x00000971 * -ResetSG ---------- ---------- - -WriteSG ---------- ---------- - +ResetSG ---------- ---------- + +WriteSG ---------- ---------- + ReadSG ---------- ---------- - ConfirmSave ---------- ---------- - CompleteSave ---------- ---------- - diff --git a/src/game/laramisc.c b/src/game/laramisc.c index 9335e4cc0..ae7b14aa0 100644 --- a/src/game/laramisc.c +++ b/src/game/laramisc.c @@ -420,7 +420,7 @@ void InitialiseLara() Lara.hit_direction = 0; Lara.death_count = 0; Lara.target = NULL; - Lara.spaz_effect = 0; + Lara.spaz_effect = NULL; Lara.spaz_effect_count = 0; Lara.turn_rate = 0; Lara.move_angle = 0; diff --git a/src/game/savegame.c b/src/game/savegame.c index 6d3e423f2..238ff213a 100644 --- a/src/game/savegame.c +++ b/src/game/savegame.c @@ -1,8 +1,14 @@ #include "game/inv.h" #include "game/savegame.h" #include "game/vars.h" +#include "specific/shed.h" #include "util.h" +#define SAVE_CREATURE (1 << 7) + +static int SGCount; +static char *SGPoint; + void InitialiseStartInfo() { if (!SaveGame[0].bonus_flag) { @@ -127,9 +133,199 @@ void CreateStartInfo(int level_num) } } +void CreateSaveGameInfo() +{ + SaveGame[0].current_level = CurrentLevel; + + CreateStartInfo(LV_CURRENT); + + SaveGame[0].num_pickup1 = Inv_RequestItem(O_PICKUP_ITEM1); + SaveGame[0].num_pickup2 = Inv_RequestItem(O_PICKUP_ITEM2); + SaveGame[0].num_puzzle1 = Inv_RequestItem(O_PUZZLE_ITEM1); + SaveGame[0].num_puzzle2 = Inv_RequestItem(O_PUZZLE_ITEM2); + SaveGame[0].num_puzzle3 = Inv_RequestItem(O_PUZZLE_ITEM3); + SaveGame[0].num_puzzle4 = Inv_RequestItem(O_PUZZLE_ITEM4); + SaveGame[0].num_key1 = Inv_RequestItem(O_KEY_ITEM1); + SaveGame[0].num_key2 = Inv_RequestItem(O_KEY_ITEM2); + SaveGame[0].num_key3 = Inv_RequestItem(O_KEY_ITEM3); + SaveGame[0].num_key4 = Inv_RequestItem(O_KEY_ITEM4); + SaveGame[0].num_leadbar = Inv_RequestItem(O_LEADBAR_ITEM); + + ResetSG(); + + for (int i = 0; i < MAX_SAVEGAME_BUFFER; i++) { + SGPoint[i] = 0; + } + + WriteSG(&FlipStatus, sizeof(int32_t)); + for (int i = 0; i < MAX_FLIP_MAPS; i++) { + int8_t flag = FlipMapTable[i] >> 8; + WriteSG(&flag, sizeof(int8_t)); + } + + for (int i = 0; i < NumberCameras; i++) { + WriteSG(&Camera.fixed[i].flags, sizeof(int16_t)); + } + + for (int i = 0; i < LevelItemCount; i++) { + ITEM_INFO *item = &Items[i]; + OBJECT_INFO *obj = &Objects[item->object_number]; + + if (obj->save_position) { + WriteSG(&item->pos, sizeof(PHD_3DPOS)); + WriteSG(&item->room_number, sizeof(int16_t)); + WriteSG(&item->speed, sizeof(int16_t)); + WriteSG(&item->fall_speed, sizeof(int16_t)); + } + + if (obj->save_anim) { + WriteSG(&item->current_anim_state, sizeof(int16_t)); + WriteSG(&item->goal_anim_state, sizeof(int16_t)); + WriteSG(&item->required_anim_state, sizeof(int16_t)); + WriteSG(&item->anim_number, sizeof(int16_t)); + WriteSG(&item->frame_number, sizeof(int16_t)); + } + + if (obj->save_hitpoints) { + WriteSG(&item->hit_points, sizeof(int16_t)); + } + + if (obj->save_flags) { + uint16_t flags = item->flags + item->active + (item->status << 1) + + (item->gravity_status << 3) + (item->collidable << 4); + if (obj->intelligent && item->data) { + flags |= SAVE_CREATURE; + } + WriteSG(&flags, sizeof(uint16_t)); + WriteSG(&item->timer, sizeof(int16_t)); + if (flags & SAVE_CREATURE) { + CREATURE_INFO *creature = item->data; + WriteSG(&creature->head_rotation, sizeof(int16_t)); + WriteSG(&creature->neck_rotation, sizeof(int16_t)); + WriteSG(&creature->maximum_turn, sizeof(int16_t)); + WriteSG(&creature->flags, sizeof(int16_t)); + WriteSG(&creature->mood, sizeof(int32_t)); + } + } + } + + WriteSGLara(&Lara); + + WriteSG(&FlipEffect, sizeof(int32_t)); + WriteSG(&FlipTimer, sizeof(int32_t)); +} + +void WriteSG(void *pointer, int size) +{ + SGCount += size; + if (SGCount >= MAX_SAVEGAME_BUFFER) { + S_ExitSystem("FATAL: Savegame is too big to fit in buffer"); + } + + char *data = (char *)pointer; + for (int i = 0; i < size; i++) { + *SGPoint++ = *data++; + } +} + +void WriteSGLara(LARA_INFO *lara) +{ + int32_t tmp32 = 0; + + WriteSG(&lara->item_number, sizeof(int16_t)); + WriteSG(&lara->gun_status, sizeof(int16_t)); + WriteSG(&lara->gun_type, sizeof(int16_t)); + WriteSG(&lara->request_gun_type, sizeof(int16_t)); + WriteSG(&lara->calc_fall_speed, sizeof(int16_t)); + WriteSG(&lara->water_status, sizeof(int16_t)); + WriteSG(&lara->pose_count, sizeof(int16_t)); + WriteSG(&lara->hit_frame, sizeof(int16_t)); + WriteSG(&lara->hit_direction, sizeof(int16_t)); + WriteSG(&lara->air, sizeof(int16_t)); + WriteSG(&lara->dive_count, sizeof(int16_t)); + WriteSG(&lara->death_count, sizeof(int16_t)); + WriteSG(&lara->current_active, sizeof(int16_t)); + WriteSG(&lara->spaz_effect_count, sizeof(int16_t)); + + // NOTE: OG just writes the pointer address (!) + if (lara->spaz_effect) { + tmp32 = (size_t)lara->spaz_effect - (size_t)Effects; + } + WriteSG(&tmp32, sizeof(int32_t)); + + WriteSG(&lara->mesh_effects, sizeof(int32_t)); + + for (int i = 0; i < LM_NUMBER_OF; i++) { + tmp32 = (size_t)lara->mesh_ptrs[i] - (size_t)MeshBase; + WriteSG(&tmp32, sizeof(int32_t)); + } + + // NOTE: og just writes the pointer address (!) assuming it's a + // non-existing mesh 16 (!!) which happens to be Lara's current target. + // Just write NULL. + tmp32 = 0; + WriteSG(&tmp32, sizeof(int32_t)); + + WriteSG(&lara->target_angles[0], sizeof(PHD_ANGLE)); + WriteSG(&lara->target_angles[1], sizeof(PHD_ANGLE)); + WriteSG(&lara->turn_rate, sizeof(int16_t)); + WriteSG(&lara->move_angle, sizeof(int16_t)); + WriteSG(&lara->head_y_rot, sizeof(int16_t)); + WriteSG(&lara->head_x_rot, sizeof(int16_t)); + WriteSG(&lara->head_z_rot, sizeof(int16_t)); + WriteSG(&lara->torso_y_rot, sizeof(int16_t)); + WriteSG(&lara->torso_x_rot, sizeof(int16_t)); + WriteSG(&lara->torso_z_rot, sizeof(int16_t)); + + WriteSGARM(&lara->left_arm); + WriteSGARM(&lara->right_arm); + WriteSG(&lara->pistols, sizeof(AMMO_INFO)); + WriteSG(&lara->magnums, sizeof(AMMO_INFO)); + WriteSG(&lara->uzis, sizeof(AMMO_INFO)); + WriteSG(&lara->shotgun, sizeof(AMMO_INFO)); + WriteSGLOT(&lara->LOT); +} + +void ResetSG() +{ + SGCount = 0; + SGPoint = SaveGame[0].buffer; +} + +void WriteSGARM(LARA_ARM *arm) +{ + int32_t frame_base = (size_t)arm->frame_base - (size_t)AnimFrames; + WriteSG(&frame_base, sizeof(int32_t)); + WriteSG(&arm->frame_number, sizeof(int16_t)); + WriteSG(&arm->lock, sizeof(int16_t)); + WriteSG(&arm->y_rot, sizeof(PHD_ANGLE)); + WriteSG(&arm->x_rot, sizeof(PHD_ANGLE)); + WriteSG(&arm->z_rot, sizeof(PHD_ANGLE)); + WriteSG(&arm->flash_gun, sizeof(int16_t)); +} + +void WriteSGLOT(LOT_INFO *lot) +{ + // it casually saves a pointer again! + WriteSG(&lot->node, sizeof(int32_t)); + + WriteSG(&lot->head, sizeof(int16_t)); + WriteSG(&lot->tail, sizeof(int16_t)); + WriteSG(&lot->search_number, sizeof(uint16_t)); + WriteSG(&lot->block_mask, sizeof(uint16_t)); + WriteSG(&lot->step, sizeof(int16_t)); + WriteSG(&lot->drop, sizeof(int16_t)); + WriteSG(&lot->fly, sizeof(int16_t)); + WriteSG(&lot->zone_count, sizeof(int16_t)); + WriteSG(&lot->target_box, sizeof(int16_t)); + WriteSG(&lot->required_box, sizeof(int16_t)); + WriteSG(&lot->target, sizeof(PHD_VECTOR)); +} + void T1MInjectGameSaveGame() { INJECT(0x004344D0, InitialiseStartInfo); INJECT(0x00434520, ModifyStartInfo); INJECT(0x004345E0, CreateStartInfo) + INJECT(0x00434720, CreateSaveGameInfo); } diff --git a/src/game/savegame.h b/src/game/savegame.h index 34161aa96..04ff670f4 100644 --- a/src/game/savegame.h +++ b/src/game/savegame.h @@ -4,7 +4,6 @@ #include // clang-format off -#define CreateSaveGameInfo ((void (*)())0x00434720) #define ExtractSaveGameInfo ((void (*)())0x00434F90) // clang-format on @@ -12,6 +11,14 @@ void InitialiseStartInfo(); void ModifyStartInfo(int32_t level_num); void CreateStartInfo(int level_num); +void CreateSaveGameInfo(); + +void ResetSG(); +void WriteSG(void *pointer, int size); +void WriteSGARM(LARA_ARM *arm); +void WriteSGLara(LARA_INFO *lara); +void WriteSGLOT(LOT_INFO *lot); + void T1MInjectGameSaveGame(); #endif