diff options
author | Bendegúz Nagy | 2016-07-19 18:04:14 +0200 |
---|---|---|
committer | Bendegúz Nagy | 2016-08-26 23:02:22 +0200 |
commit | 11704d0c509c1fc5af73c22bd64be60572ff4b8c (patch) | |
tree | adc925a33b19b7feb6509eb8c882a7a33ffb3aa7 | |
parent | bd9fa3eb87a08dd7ba6387ac7c2d911a040cd9c4 (diff) | |
download | scummvm-rg350-11704d0c509c1fc5af73c22bd64be60572ff4b8c.tar.gz scummvm-rg350-11704d0c509c1fc5af73c22bd64be60572ff4b8c.tar.bz2 scummvm-rg350-11704d0c509c1fc5af73c22bd64be60572ff4b8c.zip |
DM: Add savegame functions
-rw-r--r-- | engines/dm/champion.cpp | 66 | ||||
-rw-r--r-- | engines/dm/champion.h | 1 | ||||
-rw-r--r-- | engines/dm/dm.cpp | 9 | ||||
-rw-r--r-- | engines/dm/dm.h | 17 | ||||
-rw-r--r-- | engines/dm/dungeonman.h | 2 | ||||
-rw-r--r-- | engines/dm/group.cpp | 22 | ||||
-rw-r--r-- | engines/dm/group.h | 3 | ||||
-rw-r--r-- | engines/dm/loadsave.cpp | 148 | ||||
-rw-r--r-- | engines/dm/loadsave.h | 6 | ||||
-rw-r--r-- | engines/dm/timeline.cpp | 19 | ||||
-rw-r--r-- | engines/dm/timeline.h | 2 |
11 files changed, 261 insertions, 34 deletions
diff --git a/engines/dm/champion.cpp b/engines/dm/champion.cpp index 7b2dc00ce6..f22d4dd605 100644 --- a/engines/dm/champion.cpp +++ b/engines/dm/champion.cpp @@ -1295,10 +1295,10 @@ void ChampionMan::f302_processCommands28to65_clickOnSlotBox(uint16 slotBoxIndex) }
if (slotThing != Thing::_none) {
f300_getObjectRemovedFromSlot(champIndex, slotIndex);
- f297_putObjectInLeaderHand(slotThing, false);
+ f297_putObjectInLeaderHand(slotThing, false);
}
if (leaderHandObject != Thing::_none) {
- f301_addObjectInSlot((ChampionIndex)champIndex, leaderHandObject, (ChampionSlot) slotIndex);
+ f301_addObjectInSlot((ChampionIndex)champIndex, leaderHandObject, (ChampionSlot)slotIndex);
}
f292_drawChampionState((ChampionIndex)champIndex);
_vm->_eventMan->f77_hideMouse();
@@ -1702,6 +1702,68 @@ void ChampionMan::f331_applyTimeEffects() { f293_drawAllChampionStates();
}
+void ChampionMan::save2_PartyPart(Common::OutSaveFile* file) {
+ for (uint16 i = 0; i < 4; ++i) {
+ Champion *champ = &_gK71_champions[i];
+ file->writeUint16BE(champ->_attributes);
+ file->writeUint16BE(champ->_wounds);
+ for (uint16 y = 0; y < 7; ++y)
+ for (uint16 x = 0; x < 3; ++x)
+ file->writeByte(champ->_statistics[y][x]);
+ for (uint16 j = 0; j < 30; ++j)
+ file->writeUint16BE(champ->_slots[j].toUint16());
+ for (uint16 j = 0; j < 20; ++j) {
+ file->writeSint16BE(champ->_skills[j]._temporaryExperience);
+ file->writeSint32BE(champ->_skills[j]._experience);
+ }
+ for (uint16 j = 0; j < 8; ++j)
+ file->writeByte(champ->_name[j]);
+ for (uint16 j = 0; j < 20; ++j)
+ file->writeByte(champ->_title[j]);
+ file->writeUint16BE(champ->_dir);
+ file->writeUint16BE(champ->_cell);
+ file->writeUint16BE(champ->_actionIndex);
+ file->writeUint16BE(champ->_symbolStep);
+ for(uint16 j = 0; j < 5; ++j)
+ file->writeByte(champ->_symbols[j]);
+ file->writeUint16BE(champ->_directionMaximumDamageReceived);
+ file->writeUint16BE(champ->_maximumDamageReceived);
+ file->writeUint16BE(champ->_poisonEventCount);
+ file->writeSint16BE(champ->_enableActionEventIndex);
+ file->writeSint16BE(champ->_hideDamageReceivedIndex);
+ file->writeSint16BE(champ->_currHealth);
+ file->writeSint16BE(champ->_maxHealth);
+ file->writeSint16BE(champ->_currStamina);
+ file->writeSint16BE(champ->_maxStamina);
+ file->writeSint16BE(champ->_currMana);
+ file->writeSint16BE(champ->_maxMana);
+ file->writeSint16BE(champ->_actionDefense);
+ file->writeSint16BE(champ->_food);
+ file->writeSint16BE(champ->_water);
+ file->writeUint16BE(champ->_load);
+ file->writeSint16BE(champ->_shieldDefense);
+ for (uint16 j = 0; j < 928; ++j)
+ file->writeByte(champ->_portrait[j]);
+ }
+
+ Party &party = _g407_party;
+ file->writeSint16BE(party._magicalLightAmount);
+ file->writeByte(party._event73Count_ThievesEye);
+ file->writeByte(party._event79Count_Footprints);
+ file->writeSint16BE(party._shieldDefense);
+ file->writeSint16BE(party._fireShieldDefense);
+ file->writeSint16BE(party._spellShieldDefense);
+ file->writeByte(party._scentCount);
+ file->writeByte(party._freezeLifeTicks);
+ file->writeByte(party._firstScentIndex);
+ file->writeByte(party._lastScentIndex);
+ 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);
+}
+
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 d4491d50c8..85afd6f6f9 100644 --- a/engines/dm/champion.h +++ b/engines/dm/champion.h @@ -580,6 +580,7 @@ public: void f318_dropAllObjects(uint16 champIndex); // @ F0318_CHAMPION_DropAllObjects void f323_unpoison(int16 champIndex); // @ F0323_CHAMPION_Unpoison void f331_applyTimeEffects(); // @ F0331_CHAMPION_ApplyTimeEffects_CPSF + void save2_PartyPart(Common::OutSaveFile *file); }; diff --git a/engines/dm/dm.cpp b/engines/dm/dm.cpp index 526b60e5f1..d401c7bbe6 100644 --- a/engines/dm/dm.cpp +++ b/engines/dm/dm.cpp @@ -140,7 +140,6 @@ DMEngine::DMEngine(OSystem *syst) : Engine(syst), _console(nullptr) { _eventMan = nullptr; _menuMan = nullptr; _championMan = nullptr; - _loadsaveMan = nullptr; _objectMan = nullptr; _inventoryMan = nullptr; _textMan = nullptr; @@ -149,6 +148,10 @@ DMEngine::DMEngine(OSystem *syst) : Engine(syst), _console(nullptr) { _timeline = nullptr; _projexpl = nullptr; + _g528_saveFormat = 0; + _g527_platform = 0; + _g526_dungeonId = 0; + _g298_newGame = false; _g523_restartGameRequest = false; _g321_stopWaitingForPlayerInput = true; @@ -187,7 +190,6 @@ DMEngine::~DMEngine() { delete _eventMan; delete _menuMan; delete _championMan; - delete _loadsaveMan; delete _objectMan; delete _inventoryMan; delete _textMan; @@ -220,7 +222,7 @@ void DMEngine::f463_initializeGame() { _objectMan->loadObjectNames(); _eventMan->initMouse(); //F0441_STARTEND_ProcessEntrance(); - while (_loadsaveMan->f435_loadgame() != k1_LoadgameSuccess) { + while (f435_loadgame() != k1_LoadgameSuccess) { warning(false, "TODO: F0441_STARTEND_ProcessEntrance"); } //F0396_MENUS_LoadSpellAreaLinesBitmap() is not needed, every bitmap has been loaded @@ -301,7 +303,6 @@ Common::Error DMEngine::run() { _eventMan = new EventManager(this); _menuMan = new MenuMan(this); _championMan = new ChampionMan(this); - _loadsaveMan = new LoadsaveMan(this); _objectMan = new ObjectMan(this); _inventoryMan = new InventoryMan(this); _textMan = new TextMan(this); diff --git a/engines/dm/dm.h b/engines/dm/dm.h index dce88f17f8..dfc7b4c01c 100644 --- a/engines/dm/dm.h +++ b/engines/dm/dm.h @@ -31,6 +31,8 @@ #include "common/random.h" #include "engines/engine.h" #include "gui/debugger.h" +#include "common/savefile.h" +#include "common/str.h" namespace DM { @@ -41,7 +43,6 @@ class DungeonMan; class EventManager; class MenuMan; class ChampionMan; -class LoadsaveMan; class ObjectMan; class InventoryMan; class TextMan; @@ -50,6 +51,7 @@ class GroupMan; class Timeline; class ProjExpl; + void warning(bool repeat, const char *s, ...); enum direction { @@ -177,6 +179,11 @@ inline T f26_getBoundedValue(T min, T val, T max) { #define k99_modeWaitingOnEntrance 99 // @ C099_MODE_WAITING_ON_ENTRANCE #define k202_modeEntranceDrawCredits 202 // @ C202_MODE_ENTRANCE_DRAW_CREDITS +enum LoadgameResponse { + kM1_LoadgameFailure = -1, // @ CM1_LOAD_GAME_FAILURE + k1_LoadgameSuccess = 1// @ C01_LOAD_GAME_SUCCESS +}; + class DMEngine : public Engine { void f462_startGame(); // @ F0462_START_StartGame_CPSF void f3_processNewPartyMap(uint16 mapIndex); // @ F0003_MAIN_ProcessNewPartyMap_CPSE @@ -184,6 +191,8 @@ class DMEngine : public Engine { void f448_initMemoryManager(); // @ F0448_STARTUP1_InitializeMemoryManager_CPSADEF void f2_gameloop(); // @ F0002_MAIN_GameLoop_CPSDF void initArrays(); + Common::String getSavefileName(uint16 slot); + void writeSaveGameHeader(Common::OutSaveFile *out, const Common::String &saveName); public: explicit DMEngine(OSystem *syst); ~DMEngine(); @@ -195,8 +204,13 @@ public: int16 M0_indexToOrdinal(int16 val); // @ M00_INDEX_TO_ORDINAL 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 private: + int16 _g528_saveFormat; // @ G0528_i_Format + int16 _g527_platform; // @ G0527_i_Platform + uint16 _g526_dungeonId; // @ G0526_ui_DungeonID Console *_console; public: Common::RandomSource *_rnd; @@ -205,7 +219,6 @@ public: EventManager *_eventMan; MenuMan *_menuMan; ChampionMan *_championMan; - LoadsaveMan *_loadsaveMan; ObjectMan *_objectMan; InventoryMan *_inventoryMan; TextMan *_textMan; diff --git a/engines/dm/dungeonman.h b/engines/dm/dungeonman.h index 1a91d5d61e..b3e4194249 100644 --- a/engines/dm/dungeonman.h +++ b/engines/dm/dungeonman.h @@ -604,7 +604,7 @@ public: }; // wrapper for bytes which are used as squares struct DungeonFileHeader { - uint16 _dungeonId; // @ G0526_ui_DungeonID + uint16 _dungeonId; // equal to dungeonId uint16 _ornamentRandomSeed; uint32 _rawMapDataSize; diff --git a/engines/dm/group.cpp b/engines/dm/group.cpp index edb6056aff..5961f7cb92 100644 --- a/engines/dm/group.cpp +++ b/engines/dm/group.cpp @@ -1691,7 +1691,7 @@ void GroupMan::f183_addActiveGroup(Thing thing, int16 mapX, int16 mapY) { L0344_i_ActiveGroupIndex = 0; while (L0341_ps_ActiveGroup->_groupThingIndex >= 0) { if (++L0344_i_ActiveGroupIndex >= _vm->_groupMan->_g376_maxActiveGroupCount) { - return; + return; } L0341_ps_ActiveGroup++; } @@ -2056,4 +2056,24 @@ void GroupMan::f225_fuseAction(uint16 mapX, uint16 mapY) { warning(false, "F0446_STARTEND_FuseSequence()"); } } + +void GroupMan::save1_ActiveGroupPart(Common::OutSaveFile* file) { + for (uint16 i = 0; i < _g376_maxActiveGroupCount; ++i) { + ActiveGroup *group = &_g375_activeGroups[i]; + file->writeUint16BE(group->_groupThingIndex); + file->writeUint16BE(group->_directions); + file->writeByte(group->_cells); + file->writeByte(group->_lastMoveTime); + file->writeByte(group->_delayFleeingFromTarget); + file->writeByte(group->_targetMapX); + file->writeByte(group->_targetMapY); + file->writeByte(group->_priorMapX); + file->writeByte(group->_priorMapY); + file->writeByte(group->_homeMapX); + file->writeByte(group->_homeMapY); + for (uint16 j = 0; j < 4; ++j) + file->writeByte(group->_aspect[j]); + } +} + } diff --git a/engines/dm/group.h b/engines/dm/group.h index 6578a20851..2ad2d8dd1d 100644 --- a/engines/dm/group.h +++ b/engines/dm/group.h @@ -92,7 +92,7 @@ enum CreatureType { class ActiveGroup { public: - int _groupThingIndex; + int16 _groupThingIndex; direction _directions; byte _cells; byte _lastMoveTime; @@ -244,6 +244,7 @@ public: uint16 f222_isLordChaosOnSquare(int16 mapX, int16 mapY); // @ F0222_GROUP_IsLordChaosOnSquare 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); }; diff --git a/engines/dm/loadsave.cpp b/engines/dm/loadsave.cpp index 81a914c040..9d705ef8e5 100644 --- a/engines/dm/loadsave.cpp +++ b/engines/dm/loadsave.cpp @@ -24,39 +24,45 @@ * Based on the Reverse Engineering work of Christophe Fontanel, * maintainer of the Dungeon Master Encyclopaedia (http://dmweb.free.fr/) */ +#include "common/system.h" +#include "common/savefile.h" +#include "graphics/thumbnail.h" -#include "loadsave.h" +#include "dm.h" #include "dungeonman.h" -#include "champion.h" -#include "group.h" #include "timeline.h" - +#include "group.h" +#include "champion.h" +#include "menus.h" +#include "eventman.h" +#include "projexpl.h" namespace DM { - -LoadsaveMan::LoadsaveMan(DMEngine *vm) : _vm(vm) {} - - -LoadgameResponse LoadsaveMan::f435_loadgame() { - bool newGame = _vm->_g298_newGame; - ChampionMan &cm = *_vm->_championMan; - +#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; + _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) { - _vm->_g524_restartGameAllowed = false; + _g524_restartGameAllowed = false; cm._g305_partyChampionCount = 0; cm._g414_leaderHandObject = Thing::_none; - _vm->_g525_gameId = _vm->_rnd->getRandomNumber(65536) * _vm->_rnd->getRandomNumber(65536); + _g525_gameId = _rnd->getRandomNumber(65536) * _rnd->getRandomNumber(65536); } else { assert(false); // MISSING CODE: load game } - _vm->_dungeonMan->f434_loadDungeonFile(); + _dungeonMan->f434_loadDungeonFile(); if (newGame) { - _vm->_timeline->f233_initTimeline(); - _vm->_groupMan->f196_initActiveGroups(); + _timeline->f233_initTimeline(); + _groupMan->f196_initActiveGroups(); } else { assert(false); // MISSING CODE: load game @@ -65,4 +71,110 @@ LoadgameResponse LoadsaveMan::f435_loadgame() { return k1_LoadgameSuccess; } -}
\ No newline at end of file + +void DMEngine::f433_processCommand140_saveGame(uint16 slot, const Common::String desc) { + char *message = nullptr; + + _menuMan->f456_drawDisabledMenu(); + _eventMan->f78_showMouse(); + + // do { + // ask the play what he wants + // while + + // F0427_DIALOG_Draw(0, G0551_pc_SAVINGGAME, 0, 0, 0, 0, false, false, false); + + uint16 champHandObjWeight; + if (!_championMan->_g415_leaderEmptyHanded) { + champHandObjWeight = _dungeonMan->f140_getObjectWeight(_championMan->_g414_leaderHandObject); + _championMan->_gK71_champions[_championMan->_g411_leaderIndex]._load -= champHandObjWeight; + } + + + Common::String savefileName = getSavefileName(slot); + Common::SaveFileManager *saveFileManager = _system->getSavefileManager(); + Common::OutSaveFile *file = saveFileManager->openForSaving(savefileName); + + if (!file) + return; // TODO: silent fail + + writeSaveGameHeader(file, desc); + + // write C0_SAVE_PART_GLOBAL_DATA part + file->writeUint32BE(_g313_gameTime); + //L1348_s_GlobalData.LastRandomNumber = G0349_ul_LastRandomNumber; + file->writeUint16BE(_championMan->_g305_partyChampionCount); + file->writeSint16BE(_dungeonMan->_g306_partyMapX); + file->writeSint16BE(_dungeonMan->_g307_partyMapY); + file->writeUint16BE(_dungeonMan->_g308_partyDir); + file->writeByte(_dungeonMan->_g309_partyMapIndex); + file->writeSint16BE(_championMan->_g411_leaderIndex); + file->writeSint16BE(_championMan->_g514_magicCasterChampionIndex); + file->writeUint16BE(_timeline->_g372_eventCount); + file->writeUint16BE(_timeline->_g373_firstUnusedEventIndex); + file->writeUint16BE(_timeline->_g369_eventMaxCount); + file->writeUint16BE(_groupMan->_g377_currActiveGroupCount); + file->writeSint32BE(_projexpl->_g361_lastCreatureAttackTime); + file->writeSint32BE(_projexpl->_g362_lastPartyMovementTime); + file->writeSint16BE(_g310_disabledMovementTicks); + file->writeSint16BE(_g311_projectileDisableMovementTicks); + file->writeSint16BE(_g312_lastProjectileDisabledMovementDirection); + file->writeUint16BE(_championMan->_g414_leaderHandObject.toUint16()); + file->writeUint16BE(_groupMan->_g376_maxActiveGroupCount); + + // write C1_SAVE_PART_ACTIVE_GROUP part + _groupMan->save1_ActiveGroupPart(file); + // write C2_SAVE_PART_PARTY part + _championMan->save2_PartyPart(file); + // write C3_SAVE_PART_EVENTS part + _timeline->save3_eventsPart(file); + // write C4_SAVE_PART_TIMELINE part + _timeline->save4_timelinePart(file); + + file->writeSint32BE(_g525_gameId); + file->writeSint16BE(_g528_saveFormat); + file->writeSint16BE(_g527_platform); + file->writeUint16BE(_g526_dungeonId); + + warning(false, "MISSING CODE in save game"); + + file->flush(); + file->finalize(); + delete file; +} + +Common::String DMEngine::getSavefileName(uint16 slot) { + return Common::String::format("%s.%03u", _targetName.c_str(), slot); +} + +#define SAVEGAME_ID MKTAG('D', 'M', 'D', 'M') +#define SAVEGAME_VERSION 1 + +void DMEngine::writeSaveGameHeader(Common::OutSaveFile* out, const Common::String& saveName) { + out->writeUint32BE(SAVEGAME_ID); + + // Write version + out->writeByte(SAVEGAME_VERSION); + + // Write savegame name + out->writeString(saveName); + out->writeByte(0); + + // Save the game thumbnail + Graphics::saveThumbnail(*out); + + // Creation date/time + TimeDate curTime; + _system->getTimeAndDate(curTime); + + uint32 saveDate = ((curTime.tm_mday & 0xFF) << 24) | (((curTime.tm_mon + 1) & 0xFF) << 16) | ((curTime.tm_year + 1900) & 0xFFFF); + uint16 saveTime = ((curTime.tm_hour & 0xFF) << 8) | ((curTime.tm_min) & 0xFF); + uint32 playTime = getTotalPlayTime() / 1000; + + out->writeUint32BE(saveDate); + out->writeUint16BE(saveTime); + out->writeUint32BE(playTime); +} + + +} diff --git a/engines/dm/loadsave.h b/engines/dm/loadsave.h index c45b111ac9..85ed8a01da 100644 --- a/engines/dm/loadsave.h +++ b/engines/dm/loadsave.h @@ -32,17 +32,13 @@ namespace DM { -enum LoadgameResponse { - kM1_LoadgameFailure = -1, // @ CM1_LOAD_GAME_FAILURE - k1_LoadgameSuccess = 1// @ C01_LOAD_GAME_SUCCESS -}; +; class LoadsaveMan { DMEngine *_vm; public: explicit LoadsaveMan(DMEngine *vm); - LoadgameResponse f435_loadgame(); // @ F0435_STARTEND_LoadGame_CPSF }; } diff --git a/engines/dm/timeline.cpp b/engines/dm/timeline.cpp index 3858ad512e..afeb577eeb 100644 --- a/engines/dm/timeline.cpp +++ b/engines/dm/timeline.cpp @@ -1087,4 +1087,23 @@ T0255002: _vm->_championMan->f283_viAltarRebirth(event->_priority); } } + +void Timeline::save3_eventsPart(Common::OutSaveFile* file) { + for (uint16 i = 0; i < _g369_eventMaxCount; ++i) { + TimelineEvent *event = &_g370_events[i]; + file->writeSint32BE(event->_mapTime); + file->writeByte(event->_type); + file->writeByte(event->_priority); + file->writeByte(event->_B._location._mapX); // writing bytes of the union I think should preserve the union's identity + file->writeByte(event->_B._location._mapY); + file->writeUint16BE(event->_C.A._cell); // writing bytes of the union I think should preserve the union's identity + file->writeUint16BE(event->_C.A._effect); + } +} + +void Timeline::save4_timelinePart(Common::OutSaveFile* file) { + for (uint16 i = 0; i < _g369_eventMaxCount; ++i) + file->writeUint16BE(_g371_timeline[i]); +} + } diff --git a/engines/dm/timeline.h b/engines/dm/timeline.h index 08c6ce1c5f..8f68c35fe2 100644 --- a/engines/dm/timeline.h +++ b/engines/dm/timeline.h @@ -187,6 +187,8 @@ public: void f257_timelineProcessEvent70_light(TimelineEvent *event); // @ F0257_TIMELINE_ProcessEvent70_Light void f260_timelineRefreshAllChampionStatusBoxes(); // @ F0260_TIMELINE_RefreshAllChampionStatusBoxes void f255_timelineProcessEvent13_ViAltarRebirth(TimelineEvent *event); // @ F0255_TIMELINE_ProcessEvent13_ViAltarRebirth + void save3_eventsPart(Common::OutSaveFile *file); + void save4_timelinePart(Common::OutSaveFile *file); }; |