From ee3973aa153f5fba6485515cf1f51c1659fd31c4 Mon Sep 17 00:00:00 2001 From: Bendegúz Nagy Date: Fri, 22 Jul 2016 21:33:45 +0200 Subject: DM: Add code for loading the save files --- engines/dm/champion.cpp | 66 ++++++++++++++++++++++- engines/dm/champion.h | 1 + engines/dm/dm.cpp | 13 ++--- engines/dm/dm.h | 12 ++++- engines/dm/group.cpp | 18 +++++++ engines/dm/group.h | 1 + engines/dm/loadsave.cpp | 140 ++++++++++++++++++++++++++++++++++++++++++------ engines/dm/timeline.cpp | 18 +++++++ engines/dm/timeline.h | 2 + 9 files changed, 244 insertions(+), 27 deletions(-) (limited to 'engines') diff --git a/engines/dm/champion.cpp b/engines/dm/champion.cpp index f22d4dd605..aac5584777 100644 --- a/engines/dm/champion.cpp +++ b/engines/dm/champion.cpp @@ -1724,7 +1724,7 @@ void ChampionMan::save2_PartyPart(Common::OutSaveFile* file) { file->writeUint16BE(champ->_cell); file->writeUint16BE(champ->_actionIndex); file->writeUint16BE(champ->_symbolStep); - for(uint16 j = 0; j < 5; ++j) + for (uint16 j = 0; j < 5; ++j) file->writeByte(champ->_symbols[j]); file->writeUint16BE(champ->_directionMaximumDamageReceived); file->writeUint16BE(champ->_maximumDamageReceived); @@ -1757,13 +1757,75 @@ void ChampionMan::save2_PartyPart(Common::OutSaveFile* file) { file->writeByte(party._freezeLifeTicks); file->writeByte(party._firstScentIndex); file->writeByte(party._lastScentIndex); - for(uint16 i = 0; i < 24; ++i) + for (uint16 i = 0; i < 24; ++i) file->writeUint16BE(party._scents[i].toUint16()); for (uint16 i = 0; i < 24; ++i) file->writeByte(party._scentStrengths[i]); file->writeByte(party._event71Count_Invisibility); } +void ChampionMan::load2_PartyPart(Common::InSaveFile* file) { + for (uint16 i = 0; i < 4; ++i) { + Champion *champ = &_gK71_champions[i]; + champ->_attributes = file->readUint16BE(); + champ->_wounds = file->readUint16BE(); + for (uint16 y = 0; y < 7; ++y) + for (uint16 x = 0; x < 3; ++x) + champ->_statistics[y][x] = file->readByte(); + for (uint16 j = 0; j < 30; ++j) + champ->_slots[j] = Thing(file->readUint16BE()); + for (uint16 j = 0; j < 20; ++j) { + champ->_skills[j]._temporaryExperience = file->readSint16BE(); + champ->_skills[j]._experience = file->readSint32BE(); + } + for (uint16 j = 0; j < 8; ++j) + champ->_name[j] = file->readByte(); + for (uint16 j = 0; j < 20; ++j) + champ->_title[j] = file->readByte(); + champ->_dir = (direction)file->readUint16BE(); + champ->_cell = (ViewCell)file->readUint16BE(); + champ->_actionIndex = (ChampionAction)file->readUint16BE(); + champ->_symbolStep = file->readUint16BE(); + for (uint16 j = 0; j < 5; ++j) + champ->_symbols[j] = file->readByte(); + champ->_directionMaximumDamageReceived = file->readUint16BE(); + champ->_maximumDamageReceived = file->readUint16BE(); + champ->_poisonEventCount = file->readUint16BE(); + champ->_enableActionEventIndex = file->readSint16BE(); + champ->_hideDamageReceivedIndex = file->readSint16BE(); + champ->_currHealth = file->readSint16BE(); + champ->_maxHealth = file->readSint16BE(); + champ->_currStamina = file->readSint16BE(); + champ->_maxStamina = file->readSint16BE(); + champ->_currMana = file->readSint16BE(); + champ->_maxMana = file->readSint16BE(); + champ->_actionDefense = file->readSint16BE(); + champ->_food = file->readSint16BE(); + champ->_water = file->readSint16BE(); + champ->_load = file->readUint16BE(); + champ->_shieldDefense = file->readSint16BE(); + for (uint16 j = 0; j < 928; ++j) + champ->_portrait[j] = file->readByte(); + } + + Party &party = _g407_party; + party._magicalLightAmount = file->readSint16BE(); + party._event73Count_ThievesEye = file->readByte(); + party._event79Count_Footprints = file->readByte(); + party._shieldDefense = file->readSint16BE(); + party._fireShieldDefense = file->readSint16BE(); + party._spellShieldDefense = file->readSint16BE(); + party._scentCount = file->readByte(); + party._freezeLifeTicks = file->readByte(); + party._firstScentIndex = file->readByte(); + party._lastScentIndex = file->readByte(); + for (uint16 i = 0; i < 24; ++i) + party._scents[i] = Scent(file->readUint16BE()); + for (uint16 i = 0; i < 24; ++i) + party._scentStrengths[i] = file->readByte(); + party._event71Count_Invisibility = file->readByte(); +} + ChampionIndex ChampionMan::f285_getIndexInCell(int16 cell) { for (uint16 i = 0; i < _g305_partyChampionCount; ++i) { if ((_gK71_champions[i]._cell == cell) && _gK71_champions[i]._currHealth) diff --git a/engines/dm/champion.h b/engines/dm/champion.h index 15a07bebe7..17d8831179 100644 --- a/engines/dm/champion.h +++ b/engines/dm/champion.h @@ -586,6 +586,7 @@ public: void f323_unpoison(int16 champIndex); // @ F0323_CHAMPION_Unpoison void f331_applyTimeEffects(); // @ F0331_CHAMPION_ApplyTimeEffects_CPSF void save2_PartyPart(Common::OutSaveFile *file); + void load2_PartyPart(Common::InSaveFile* file); }; diff --git a/engines/dm/dm.cpp b/engines/dm/dm.cpp index 2861cf1243..0aade77684 100644 --- a/engines/dm/dm.cpp +++ b/engines/dm/dm.cpp @@ -177,9 +177,6 @@ DMEngine::DMEngine(OSystem *syst) : Engine(syst), _console(nullptr) { _g564_interfaceCredits = nullptr; debug("DMEngine::DMEngine"); - - warning(false, "DUMMY CODE: setting _g298_newGame to true, should be in processEntrance"); - _g298_newGame = true; } DMEngine::~DMEngine() { @@ -222,7 +219,7 @@ uint16 DMEngine::f30_getScaledProduct(uint16 val, uint16 scale, uint16 vale2) { void DMEngine::f463_initializeGame() { _displayMan->f479_loadGraphics(); _displayMan->f460_initializeGraphicData(); - // DUMMY CODE: next line + warning(false, "Dummy code in f463_initializeGame, setting palette"); _displayMan->loadPalette(g21_PalDungeonView[0]); _displayMan->f94_loadFloorSet(k0_FloorSetStone); _displayMan->f95_loadWallSet(k0_WallSetStone); @@ -231,12 +228,11 @@ void DMEngine::f463_initializeGame() { _objectMan->loadObjectNames(); _eventMan->initMouse(); f441_processEntrance(); - while (f435_loadgame() != k1_LoadgameSuccess) { + while (f435_loadgame(1) != k1_LoadgameSuccess) { f441_processEntrance(); } //F0396_MENUS_LoadSpellAreaLinesBitmap() is not needed, every bitmap has been loaded - // There was some memory wizardy for the Amiga platform, I skipped that part _displayMan->f461_allocateFlippedWallBitmaps(); @@ -321,7 +317,7 @@ Common::Error DMEngine::run() { _projexpl = new ProjExpl(this); _displayMan->setUpScreens(320, 200); - f463_initializeGame(); // @ F0463_START_InitializeGame_CPSADEF + f463_initializeGame(); while (true) { f2_gameloop(); warning(false, "TODO: F0444_STARTEND_Endgame(G0303_B_PartyDead);"); @@ -490,7 +486,6 @@ void DMEngine::f441_processEntrance() { _g562_entranceDoorAnimSteps[i] = nullptr; } - void DMEngine::f439_drawEntrance() { static Box K0079_s_Box_Entrance_DoorsUpperHalf = {0, 231, 0, 80}; static Box K0152_s_Box_Entrance_DoorsLowerHalf = {0, 231, 81, 160}; @@ -508,7 +503,7 @@ void DMEngine::f439_drawEntrance() { _dungeonMan->_g271_currMapData = L1398_apuc_MicroDungeonCurrentMapData; Map map; // uninitialized, won't be used - _dungeonMan->_g269_currMap = ↦ + _dungeonMan->_g269_currMap = ↦ for (uint16 i = 0; i < 25; ++i) L1399_auc_MicroDungeonSquares[i] = Square(k0_ElementTypeWall, 0); for (L1397_ui_ColumnIndex = 0; L1397_ui_ColumnIndex < 5; L1397_ui_ColumnIndex++) { diff --git a/engines/dm/dm.h b/engines/dm/dm.h index cbc0bd35e0..279144bc4d 100644 --- a/engines/dm/dm.h +++ b/engines/dm/dm.h @@ -33,6 +33,8 @@ #include "gui/debugger.h" #include "common/savefile.h" #include "common/str.h" +#include "engines/savestate.h" + namespace DM { @@ -184,6 +186,13 @@ enum LoadgameResponse { k1_LoadgameSuccess = 1// @ C01_LOAD_GAME_SUCCESS }; + +struct SaveGameHeader { + byte _version; + SaveStateDescriptor _descr; +}; + + class DMEngine : public Engine { void f462_startGame(); // @ F0462_START_StartGame_CPSF void f3_processNewPartyMap(uint16 mapIndex); // @ F0003_MAIN_ProcessNewPartyMap_CPSE @@ -193,6 +202,7 @@ class DMEngine : public Engine { void initArrays(); Common::String getSavefileName(uint16 slot); void writeSaveGameHeader(Common::OutSaveFile *out, const Common::String &saveName); + bool readSaveGameHeader(Common::InSaveFile *file, SaveGameHeader *header); void f439_drawEntrance(); // @ F0439_STARTEND_DrawEntrance public: explicit DMEngine(OSystem *syst); @@ -207,7 +217,7 @@ public: void f19_displayErrorAndStop(int16 errorIndex); // @ F0019_MAIN_DisplayErrorAndStop virtual Common::Error run(); // @ main void f433_processCommand140_saveGame(uint16 slot, const Common::String desc); // @ F0433_STARTEND_ProcessCommand140_SaveGame_CPSCDF - LoadgameResponse f435_loadgame(); // @ F0435_STARTEND_LoadGame_CPSF + LoadgameResponse f435_loadgame(int16 slot); // @ F0435_STARTEND_LoadGame_CPSF void f441_processEntrance(); // @ F0441_STARTEND_ProcessEntrance private: diff --git a/engines/dm/group.cpp b/engines/dm/group.cpp index e59a6e7846..6f6991e4b5 100644 --- a/engines/dm/group.cpp +++ b/engines/dm/group.cpp @@ -2077,4 +2077,22 @@ void GroupMan::save1_ActiveGroupPart(Common::OutSaveFile* file) { } } +void GroupMan::load1_ActiveGroupPart(Common::InSaveFile* file) { + for (uint16 i = 0; i < _g376_maxActiveGroupCount; ++i) { + ActiveGroup *group = &_g375_activeGroups[i]; + group->_groupThingIndex = file->readUint16BE(); + group->_directions = (direction)file->readUint16BE(); + group->_cells = file->readByte(); + group->_lastMoveTime = file->readByte(); + group->_delayFleeingFromTarget = file->readByte(); + group->_targetMapX = file->readByte(); + group->_targetMapY = file->readByte(); + group->_priorMapX = file->readByte(); + group->_priorMapY = file->readByte(); + group->_homeMapX = file->readByte(); + group->_homeMapY = file->readByte(); + for (uint16 j = 0; j < 4; ++j) + group->_aspect[j] = file->readByte(); + } +} } diff --git a/engines/dm/group.h b/engines/dm/group.h index 2ad2d8dd1d..699f195aa9 100644 --- a/engines/dm/group.h +++ b/engines/dm/group.h @@ -245,6 +245,7 @@ public: bool f221_isFluxcageOnSquare(int16 mapX, int16 mapY); // @ F0221_GROUP_IsFluxcageOnSquare void f225_fuseAction(uint16 mapX, uint16 mapY); // @ F0225_GROUP_FuseAction void save1_ActiveGroupPart(Common::OutSaveFile *file); + void load1_ActiveGroupPart(Common::InSaveFile* file); }; diff --git a/engines/dm/loadsave.cpp b/engines/dm/loadsave.cpp index 28b57f2651..9b50351376 100644 --- a/engines/dm/loadsave.cpp +++ b/engines/dm/loadsave.cpp @@ -42,32 +42,96 @@ namespace DM { #define C2_FORMAT_DM_AMIGA_2X_PC98_X68000_FM_TOWNS_CSB_ATARI_ST 2 #define C3_PLATFORM_AMIGA 3 #define C10_DUNGEON_DM 10 -LoadgameResponse DMEngine::f435_loadgame() { - bool newGame = _g298_newGame; - ChampionMan &cm = *_championMan; +LoadgameResponse DMEngine::f435_loadgame(int16 slot) { + Common::String fileName; + Common::SaveFileManager *saveFileManager = nullptr; + Common::InSaveFile *file = nullptr; + + if (!_g298_newGame) { + fileName = getSavefileName(slot); + saveFileManager = _system->getSavefileManager(); + file = saveFileManager->openForLoading(fileName); + } + _g528_saveFormat = C2_FORMAT_DM_AMIGA_2X_PC98_X68000_FM_TOWNS_CSB_ATARI_ST; _g527_platform = C3_PLATFORM_AMIGA; _g526_dungeonId = C10_DUNGEON_DM; - if (newGame) { + if (_g298_newGame) { + //L1366_B_FadePalette = !F0428_DIALOG_RequireGameDiskInDrive_NoDialogDrawn(C0_DO_NOT_FORCE_DIALOG_DM_CSB, true); +T0435002: _g524_restartGameAllowed = false; - cm._g305_partyChampionCount = 0; - cm._g414_leaderHandObject = Thing::_none; - _g525_gameId = _rnd->getRandomNumber(65536) * _rnd->getRandomNumber(65536); + _championMan->_g305_partyChampionCount = 0; + _championMan->_g414_leaderHandObject = Thing::_none; + _g525_gameId = ((int32)getRandomNumber(65536)) * getRandomNumber(65536); } else { - assert(false); - // MISSING CODE: load game - } - _dungeonMan->f434_loadDungeonFile(); + warning(false, "MISSING CODE: missing check for matching _g525_gameId in f435_loadgame"); + /*if (_vm->_g523_restartGameRequest && (L1372_s_SaveHeader.GameID != _vm->_g525_gameId)) { + L1367_pc_Message = G0546_pc_THATSNOTTHESAMEGAME; + goto T0435004; + }*/ + + SaveGameHeader header; + readSaveGameHeader(file, &header); + + warning(false, "MISSING CODE: missing check for matching format and platform in save in f435_loadgame"); + + _g313_gameTime = file->readUint32BE(); + // G0349_ul_LastRandomNumber = L1371_s_GlobalData.LastRandomNumber; + _championMan->_g305_partyChampionCount = file->readUint16BE(); + _dungeonMan->_g306_partyMapX = file->readSint16BE(); + _dungeonMan->_g307_partyMapY = file->readSint16BE(); + _dungeonMan->_g308_partyDir = (direction)file->readUint16BE(); + _dungeonMan->_g309_partyMapIndex = file->readByte(); + _championMan->_g411_leaderIndex = (ChampionIndex)file->readSint16BE(); + _championMan->_g514_magicCasterChampionIndex = (ChampionIndex)file->readSint16BE(); + _timeline->_g372_eventCount = file->readUint16BE(); + _timeline->_g373_firstUnusedEventIndex = file->readUint16BE(); + _timeline->_g369_eventMaxCount = file->readUint16BE(); + _groupMan->_g377_currActiveGroupCount = file->readUint16BE(); + _projexpl->_g361_lastCreatureAttackTime = file->readSint32BE(); + _projexpl->_g362_lastPartyMovementTime = file->readSint32BE(); + _g310_disabledMovementTicks = file->readSint16BE(); + _g311_projectileDisableMovementTicks = file->readSint16BE(); + _g312_lastProjectileDisabledMovementDirection = file->readSint16BE(); + _championMan->_g414_leaderHandObject = Thing(file->readUint16BE()); + _groupMan->_g376_maxActiveGroupCount = file->readUint16BE(); + if (!_g523_restartGameRequest) { + _timeline->f233_initTimeline(); + _groupMan->f196_initActiveGroups(); + } - if (newGame) { + _groupMan->load1_ActiveGroupPart(file); + _championMan->load2_PartyPart(file); + _timeline->load3_eventsPart(file); + _timeline->load4_timelinePart(file); + + _g525_gameId = file->readSint32BE(); + } + + _dungeonMan->f434_loadDungeonFile(); + if (_g298_newGame) { _timeline->f233_initTimeline(); _groupMan->f196_initActiveGroups(); + warning(false, "MISSING CODE: missing fadePlette stuff in f435_loadgame on newGame"); + /* + if (L1366_B_FadePalette) { + F0436_STARTEND_FadeToPalette(G0345_aui_BlankBuffer); + D26_WaitForVerticalBlank(); + D18_FillScreenBlack(); + F0436_STARTEND_FadeToPalette(_vm->_displayMan->_g347_paletteTopAndBottomScreen); + }*/ } else { - assert(false); - // MISSING CODE: load game + _g528_saveFormat = file->readSint16BE(); + _g527_platform = file->readSint16BE(); + _g526_dungeonId = file->readUint16BE(); + + _g524_restartGameAllowed = true; + warning(false, "MISSING CDOE: F0427_DIALOG_Draw in f435_loadgame"); } - cm._g303_partyDead = false; + _championMan->_g303_partyDead = false; + + delete file; return k1_LoadgameSuccess; } @@ -176,4 +240,50 @@ void DMEngine::writeSaveGameHeader(Common::OutSaveFile* out, const Common::Strin out->writeUint32BE(playTime); } + +bool DMEngine::readSaveGameHeader(Common::InSaveFile* in, SaveGameHeader* header) { + uint32 id = in->readUint32BE(); + + // Check if it's a valid ScummVM savegame + if (id != SAVEGAME_ID) + return false; + + // Read in the version + header->_version = in->readByte(); + + // Check that the save version isn't newer than this binary + if (header->_version > SAVEGAME_VERSION) + return false; + + // Read in the save name + Common::String saveName; + char ch; + while ((ch = (char)in->readByte()) != '\0') + saveName += ch; + header->_descr.setDescription(saveName); + + // Get the thumbnail + header->_descr.setThumbnail(Graphics::loadThumbnail(*in)); + + uint32 saveDate = in->readUint32BE(); + uint16 saveTime = in->readUint16BE(); + uint32 playTime = in->readUint32BE(); + + int day = (saveDate >> 24) & 0xFF; + int month = (saveDate >> 16) & 0xFF; + int year = saveDate & 0xFFFF; + header->_descr.setSaveDate(year, month, day); + + int hour = (saveTime >> 8) & 0xFF; + int minutes = saveTime & 0xFF; + header->_descr.setSaveTime(hour, minutes); + + header->_descr.setPlayTime(playTime * 1000); + if (g_engine) + g_engine->setTotalPlayTime(playTime * 1000); + + return true; } + +} + diff --git a/engines/dm/timeline.cpp b/engines/dm/timeline.cpp index afeb577eeb..37eb880690 100644 --- a/engines/dm/timeline.cpp +++ b/engines/dm/timeline.cpp @@ -1106,4 +1106,22 @@ void Timeline::save4_timelinePart(Common::OutSaveFile* file) { file->writeUint16BE(_g371_timeline[i]); } +void Timeline::load3_eventsPart(Common::InSaveFile* file) { + for (uint16 i = 0; i < _g369_eventMaxCount; ++i) { + TimelineEvent *event = &_g370_events[i]; + event->_mapTime = file->readSint32BE(); + event->_type = file->readByte(); + event->_priority = file->readByte(); + event->_B._location._mapX = file->readByte(); + event->_B._location._mapY = file->readByte(); + event->_C.A._cell = file->readUint16BE(); + event->_C.A._effect = file->readUint16BE(); + } +} + +void Timeline::load4_timelinePart(Common::InSaveFile* file) { + for (uint16 i = 0; i < _g369_eventMaxCount; ++i) + _g371_timeline[i] = file->readUint16BE(); +} + } diff --git a/engines/dm/timeline.h b/engines/dm/timeline.h index 8f68c35fe2..2d722d5569 100644 --- a/engines/dm/timeline.h +++ b/engines/dm/timeline.h @@ -189,6 +189,8 @@ public: void f255_timelineProcessEvent13_ViAltarRebirth(TimelineEvent *event); // @ F0255_TIMELINE_ProcessEvent13_ViAltarRebirth void save3_eventsPart(Common::OutSaveFile *file); void save4_timelinePart(Common::OutSaveFile *file); + void load3_eventsPart(Common::InSaveFile* file); + void load4_timelinePart(Common::InSaveFile* file); }; -- cgit v1.2.3