From 3ecefbb1f470f00503ea8dd23066629bbfde395c Mon Sep 17 00:00:00 2001 From: rr- Date: Wed, 10 Mar 2021 01:28:00 +0100 Subject: [PATCH] port ExtractSaveGameInfo --- docs/progress.svg | 12 +- docs/progress.txt | 15 +- src/game/moveblock.c | 6 - src/game/savegame.c | 336 ++++++++++++++++++++++++++++++++++++++++++- src/game/savegame.h | 10 +- src/game/types.h | 6 + 6 files changed, 354 insertions(+), 31 deletions(-) diff --git a/docs/progress.svg b/docs/progress.svg index 126c02020..3b922f756 100644 --- a/docs/progress.svg +++ b/docs/progress.svg @@ -572,7 +572,7 @@ ModifyStartInfo CreateStartInfo CreateSaveGameInfo -ExtractSaveGameInfo +ExtractSaveGameInfo S_DrawSprite S_DrawSpriteRel S_DrawUISprite @@ -738,7 +738,7 @@ BaddyObjects sub_40904D DrawLara -ExtractSaveGameInfo +ExtractSaveGameInfo CreateSaveGameInfo CreatureAnimation GetCollisionInfo @@ -1463,10 +1463,10 @@ sub_440EF0 KeyGet S_CDVolume -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 decompiled (count): 69.22% +Functions decompiled (bytesize): 68.84% +Functions not decompiled, but with known names (count): 16.96% +Functions not decompiled, but with known names (bytesize): 15.43% 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 b1deb939a..74d4dc726 100644 --- a/docs/progress.txt +++ b/docs/progress.txt @@ -806,25 +806,22 @@ RatControl 0x00433F50 0x000002A8 + VoleControl 0x00434210 0x000002B5 + # savegame.cpp -ReadSGPos ---------- ---------- - +ReadSGPos ---------- ---------- + WriteSGPos ---------- ---------- + -ReadSGARM ---------- ---------- - -ReadSGLOT ---------- ---------- - -ReadSGLara ---------- ---------- - +ReadSGARM ---------- ---------- + +ReadSGLOT ---------- ---------- + +ReadSGLara ---------- ---------- + WriteSGARM ---------- ---------- + WriteSGLOT ---------- ---------- + WriteSGLara ---------- ---------- + -LoadSaveGameInfo ---------- ---------- - InitialiseStartInfo 0x004344D0 0x00000042 + ModifyStartInfo 0x00434520 0x000000BF + CreateStartInfo 0x004345E0 0x00000139 + CreateSaveGameInfo 0x00434720 0x00000866 + -ExtractSaveGameInfo 0x00434F90 0x00000971 * +ExtractSaveGameInfo 0x00434F90 0x00000971 + ResetSG ---------- ---------- + WriteSG ---------- ---------- + -ReadSG ---------- ---------- - -ConfirmSave ---------- ---------- - -CompleteSave ---------- ---------- - +ReadSG ---------- ---------- + # ??? S_DrawSprite 0x00435910 0x0000025E - diff --git a/src/game/moveblock.c b/src/game/moveblock.c index cdcf82ff1..12777420a 100644 --- a/src/game/moveblock.c +++ b/src/game/moveblock.c @@ -14,12 +14,6 @@ typedef enum { MBS_PULL = 3, } MOVABLE_BLOCK_STATE; -typedef enum { - RBS_START = 0, - RBS_END = 1, - RBS_MOVING = 2, -} ROLLING_BLOCK_STATE; - static int16_t MovingBlockBounds[12] = { -300, +300, diff --git a/src/game/savegame.c b/src/game/savegame.c index 238ff213a..42d0252aa 100644 --- a/src/game/savegame.c +++ b/src/game/savegame.c @@ -1,6 +1,14 @@ +#include "game/control.h" #include "game/inv.h" +#include "game/items.h" +#include "game/lara.h" +#include "game/lot.h" +#include "game/moveblock.h" +#include "game/pickup.h" #include "game/savegame.h" +#include "game/traps.h" #include "game/vars.h" +#include "game/warrior.h" #include "specific/shed.h" #include "util.h" @@ -215,6 +223,236 @@ void CreateSaveGameInfo() WriteSG(&FlipTimer, sizeof(int32_t)); } +void ExtractSaveGameInfo() +{ + int8_t tmp8; + int16_t tmp16; + int32_t tmp32; + + InitialiseLaraInventory(LV_CURRENT); + + for (int i = 0; i < SaveGame[0].num_pickup1; i++) { + Inv_AddItem(O_PICKUP_ITEM1); + } + + for (int i = 0; i < SaveGame[0].num_pickup2; i++) { + Inv_AddItem(O_PICKUP_ITEM2); + } + + for (int i = 0; i < SaveGame[0].num_puzzle1; i++) { + Inv_AddItem(O_PUZZLE_ITEM1); + } + + for (int i = 0; i < SaveGame[0].num_puzzle2; i++) { + Inv_AddItem(O_PUZZLE_ITEM2); + } + + for (int i = 0; i < SaveGame[0].num_puzzle3; i++) { + Inv_AddItem(O_PUZZLE_ITEM3); + } + + for (int i = 0; i < SaveGame[0].num_puzzle4; i++) { + Inv_AddItem(O_PUZZLE_ITEM4); + } + + for (int i = 0; i < SaveGame[0].num_key1; i++) { + Inv_AddItem(O_KEY_ITEM1); + } + + for (int i = 0; i < SaveGame[0].num_key2; i++) { + Inv_AddItem(O_KEY_ITEM2); + } + + for (int i = 0; i < SaveGame[0].num_key3; i++) { + Inv_AddItem(O_KEY_ITEM3); + } + + for (int i = 0; i < SaveGame[0].num_key4; i++) { + Inv_AddItem(O_KEY_ITEM4); + } + + for (int i = 0; i < SaveGame[0].num_leadbar; i++) { + Inv_AddItem(O_LEADBAR_ITEM); + } + + ResetSG(); + + ReadSG(&tmp32, sizeof(int32_t)); + if (tmp32) { + FlipMap(); + } + + for (int i = 0; i < MAX_FLIP_MAPS; i++) { + ReadSG(&tmp8, sizeof(int8_t)); + FlipMapTable[i] = tmp8 << 8; + } + + for (int i = 0; i < NumberCameras; i++) { + ReadSG(&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->control == MovableBlockControl) { + AlterFloorHeight(item, 1024); + } + if (obj->control == RollingBlockControl) { + AlterFloorHeight(item, 2048); + } + + if (obj->save_position) { + ReadSG(&item->pos, sizeof(PHD_3DPOS)); + ReadSG(&tmp16, sizeof(int16_t)); + ReadSG(&item->speed, sizeof(int16_t)); + ReadSG(&item->fall_speed, sizeof(int16_t)); + + if (item->room_number != tmp16) { + ItemNewRoom(i, tmp16); + } + + if (obj->shadow_size) { + FLOOR_INFO *floor = + GetFloor(item->pos.x, item->pos.y, item->pos.z, &tmp16); + item->floor = + GetHeight(floor, item->pos.x, item->pos.y, item->pos.z); + } + } + + if (obj->save_anim) { + ReadSG(&item->current_anim_state, sizeof(int16_t)); + ReadSG(&item->goal_anim_state, sizeof(int16_t)); + ReadSG(&item->required_anim_state, sizeof(int16_t)); + ReadSG(&item->anim_number, sizeof(int16_t)); + ReadSG(&item->frame_number, sizeof(int16_t)); + } + + if (obj->save_hitpoints) { + ReadSG(&item->hit_points, sizeof(int16_t)); + } + + if (obj->save_flags) { + ReadSG(&item->flags, sizeof(int16_t)); + ReadSG(&item->timer, sizeof(int16_t)); + + if (item->flags & IF_KILLED_ITEM) { + KillItem(i); + item->status = IS_DEACTIVATED; + } else { + if ((item->flags & 1) && !item->active) { + AddActiveItem(i); + } + item->status = (item->flags & 6) >> 1; + if (item->flags & 8) { + item->gravity_status = 1; + } + if (!(item->flags & 16)) { + item->collidable = 0; + } + } + + if (item->flags & SAVE_CREATURE) { + EnableBaddieAI(i, 1); + CREATURE_INFO *creature = item->data; + if (creature) { + ReadSG(&creature->head_rotation, sizeof(int16_t)); + ReadSG(&creature->neck_rotation, sizeof(int16_t)); + ReadSG(&creature->maximum_turn, sizeof(int16_t)); + ReadSG(&creature->flags, sizeof(int16_t)); + ReadSG(&creature->mood, sizeof(int32_t)); + } else { + SkipSG(4 * 2 + 4); + } + } else if (obj->intelligent) { + item->data = NULL; + } + + item->flags &= 0xFF00; + + if (obj->collision == PuzzleHoleCollision + && (item->status == IS_DEACTIVATED + || item->status == IS_ACTIVE)) { + item->object_number += O_PUZZLE_DONE1 - O_PUZZLE_HOLE1; + } + + if (obj->control == PodControl && item->status == IS_DEACTIVATED) { + item->mesh_bits = 0x1FF; + item->collidable = 0; + } + + if (obj->collision == PickUpCollision + && item->status == IS_DEACTIVATED) { + RemoveDrawnItem(i); + } + } + + if (obj->control == MovableBlockControl + && item->status == IS_NOT_ACTIVE) { + AlterFloorHeight(item, -1024); + } + + if (obj->control == RollingBlockControl + && item->current_anim_state != RBS_MOVING) { + AlterFloorHeight(item, -2048); + } + + if (item->object_number == O_PIERRE && item->hit_points <= 0 + && (item->flags & IF_ONESHOT)) { + if (Inv_RequestItem(O_SCION_ITEM) == 1) { + SpawnItem(item, O_MAGNUM_ITEM); + SpawnItem(item, O_SCION_ITEM2); + SpawnItem(item, O_KEY_ITEM1); + } + CDFlags[55] |= IF_ONESHOT; + } + + if (item->object_number == O_MERCENARY1 && item->hit_points <= 0) { + if (!Inv_RequestItem(O_UZI_ITEM)) { + SpawnItem(item, O_UZI_ITEM); + } + } + + if (item->object_number == O_MERCENARY2 && item->hit_points <= 0) { + if (!Inv_RequestItem(O_MAGNUM_ITEM)) { + SpawnItem(item, O_MAGNUM_ITEM); + } + CDFlags[52] |= IF_ONESHOT; + } + + if (item->object_number == O_MERCENARY3 && item->hit_points <= 0) { + if (!Inv_RequestItem(O_SHOTGUN_ITEM)) { + SpawnItem(item, O_SHOTGUN_ITEM); + } + CDFlags[51] |= IF_ONESHOT; + } + + if (item->object_number == O_LARSON && item->hit_points <= 0) { + CDFlags[51] |= IF_ONESHOT; + } + } + + BOX_NODE *node = Lara.LOT.node; + ReadSGLara(&Lara); + Lara.LOT.node = node; + Lara.LOT.target_box = NO_BOX; + + ReadSG(&FlipEffect, sizeof(int32_t)); + ReadSG(&FlipTimer, sizeof(int32_t)); +} + +void ResetSG() +{ + SGCount = 0; + SGPoint = SaveGame[0].buffer; +} + +void SkipSG(int size) +{ + SGPoint += size; + SGCount += size; // missing from OG +} + void WriteSG(void *pointer, int size) { SGCount += size; @@ -286,12 +524,6 @@ void WriteSGLara(LARA_INFO *lara) 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; @@ -322,10 +554,102 @@ void WriteSGLOT(LOT_INFO *lot) WriteSG(&lot->target, sizeof(PHD_VECTOR)); } +void ReadSG(void *pointer, int size) +{ + SGCount += size; + char *data = (char *)pointer; + for (int i = 0; i < size; i++) + *data++ = *SGPoint++; +} + +void ReadSGLara(LARA_INFO *lara) +{ + int32_t tmp32 = 0; + + ReadSG(&lara->item_number, sizeof(int16_t)); + ReadSG(&lara->gun_status, sizeof(int16_t)); + ReadSG(&lara->gun_type, sizeof(int16_t)); + ReadSG(&lara->request_gun_type, sizeof(int16_t)); + ReadSG(&lara->calc_fall_speed, sizeof(int16_t)); + ReadSG(&lara->water_status, sizeof(int16_t)); + ReadSG(&lara->pose_count, sizeof(int16_t)); + ReadSG(&lara->hit_frame, sizeof(int16_t)); + ReadSG(&lara->hit_direction, sizeof(int16_t)); + ReadSG(&lara->air, sizeof(int16_t)); + ReadSG(&lara->dive_count, sizeof(int16_t)); + ReadSG(&lara->death_count, sizeof(int16_t)); + ReadSG(&lara->current_active, sizeof(int16_t)); + ReadSG(&lara->spaz_effect_count, sizeof(int16_t)); + + lara->spaz_effect = NULL; + SkipSG(sizeof(FX_INFO *)); + + ReadSG(&lara->mesh_effects, sizeof(int32_t)); + for (int i = 0; i < LM_NUMBER_OF; i++) { + ReadSG(&tmp32, sizeof(int32_t)); + lara->mesh_ptrs[i] = (int16_t *)((size_t)MeshBase + (size_t)tmp32); + } + + lara->target = NULL; + SkipSG(sizeof(ITEM_INFO *)); + + ReadSG(&lara->target_angles[0], sizeof(PHD_ANGLE)); + ReadSG(&lara->target_angles[1], sizeof(PHD_ANGLE)); + ReadSG(&lara->turn_rate, sizeof(int16_t)); + ReadSG(&lara->move_angle, sizeof(int16_t)); + ReadSG(&lara->head_y_rot, sizeof(int16_t)); + ReadSG(&lara->head_x_rot, sizeof(int16_t)); + ReadSG(&lara->head_z_rot, sizeof(int16_t)); + ReadSG(&lara->torso_y_rot, sizeof(int16_t)); + ReadSG(&lara->torso_x_rot, sizeof(int16_t)); + ReadSG(&lara->torso_z_rot, sizeof(int16_t)); + + ReadSGARM(&lara->left_arm); + ReadSGARM(&lara->right_arm); + ReadSG(&lara->pistols, sizeof(AMMO_INFO)); + ReadSG(&lara->magnums, sizeof(AMMO_INFO)); + ReadSG(&lara->uzis, sizeof(AMMO_INFO)); + ReadSG(&lara->shotgun, sizeof(AMMO_INFO)); + ReadSGLOT(&lara->LOT); +} + +void ReadSGARM(LARA_ARM *arm) +{ + int32_t frame_base; + ReadSG(&frame_base, sizeof(int32_t)); + arm->frame_base = (int16_t *)((size_t)AnimFrames + (size_t)frame_base); + + ReadSG(&arm->frame_number, sizeof(int16_t)); + ReadSG(&arm->lock, sizeof(int16_t)); + ReadSG(&arm->y_rot, sizeof(PHD_ANGLE)); + ReadSG(&arm->x_rot, sizeof(PHD_ANGLE)); + ReadSG(&arm->z_rot, sizeof(PHD_ANGLE)); + ReadSG(&arm->flash_gun, sizeof(int16_t)); +} + +void ReadSGLOT(LOT_INFO *lot) +{ + lot->node = NULL; + SkipSG(4); + + ReadSG(&lot->head, sizeof(int16_t)); + ReadSG(&lot->tail, sizeof(int16_t)); + ReadSG(&lot->search_number, sizeof(uint16_t)); + ReadSG(&lot->block_mask, sizeof(uint16_t)); + ReadSG(&lot->step, sizeof(int16_t)); + ReadSG(&lot->drop, sizeof(int16_t)); + ReadSG(&lot->fly, sizeof(int16_t)); + ReadSG(&lot->zone_count, sizeof(int16_t)); + ReadSG(&lot->target_box, sizeof(int16_t)); + ReadSG(&lot->required_box, sizeof(int16_t)); + ReadSG(&lot->target, sizeof(PHD_VECTOR)); +} + void T1MInjectGameSaveGame() { INJECT(0x004344D0, InitialiseStartInfo); INJECT(0x00434520, ModifyStartInfo); INJECT(0x004345E0, CreateStartInfo) INJECT(0x00434720, CreateSaveGameInfo); + INJECT(0x00434F90, ExtractSaveGameInfo); } diff --git a/src/game/savegame.h b/src/game/savegame.h index 04ff670f4..68f58fa1e 100644 --- a/src/game/savegame.h +++ b/src/game/savegame.h @@ -3,17 +3,19 @@ #include -// clang-format off -#define ExtractSaveGameInfo ((void (*)())0x00434F90) -// clang-format on - void InitialiseStartInfo(); void ModifyStartInfo(int32_t level_num); void CreateStartInfo(int level_num); void CreateSaveGameInfo(); +void ExtractSaveGameInfo(); void ResetSG(); +void SkipSG(int size); +void ReadSG(void *pointer, int size); +void ReadSGARM(LARA_ARM *arm); +void ReadSGLara(LARA_INFO *lara); +void ReadSGLOT(LOT_INFO *lot); void WriteSG(void *pointer, int size); void WriteSGARM(LARA_ARM *arm); void WriteSGLara(LARA_INFO *lara); diff --git a/src/game/types.h b/src/game/types.h index b260d82e9..94154d9c0 100644 --- a/src/game/types.h +++ b/src/game/types.h @@ -785,6 +785,12 @@ typedef enum { RIF_FIXED_HEIGHT = 1 << 0, } REQUEST_INFO_FLAGS; +typedef enum { + RBS_START = 0, + RBS_END = 1, + RBS_MOVING = 2, +} ROLLING_BLOCK_STATE; + #pragma pack(push, 1) typedef struct {