1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 */ 22 23 /* 24 * Based on the Reverse Engineering work of Christophe Fontanel, 25 * maintainer of the Dungeon Master Encyclopaedia (http://dmweb.free.fr/) 26 */ 27 28 #ifndef DM_DM_H 29 #define DM_DM_H 30 31 #include "engines/engine.h" 32 #include "engines/savestate.h" 33 34 #include "common/random.h" 35 #include "common/savefile.h" 36 #include "common/str.h" 37 #include "common/memstream.h" 38 39 #include "advancedDetector.h" 40 41 #include "dm/console.h" 42 43 struct ADGameDescription; 44 45 namespace DM { 46 47 class DisplayMan; 48 class DungeonMan; 49 class EventManager; 50 class MenuMan; 51 class ChampionMan; 52 class ObjectMan; 53 class InventoryMan; 54 class TextMan; 55 class MovesensMan; 56 class GroupMan; 57 class Timeline; 58 class ProjExpl; 59 class DialogMan; 60 class SoundMan; 61 62 enum OriginalSaveFormat { 63 kDMSaveFormatAcceptAny = -1, 64 kDMSaveFormatEndOfList = 0, 65 kDMSaveFormatNone = 0, 66 kDMSaveFormatAtari = 1, 67 kDMSaveFormatAmigaPC98FmTowns = 2, 68 kCSBSaveFormatAtari = 2, 69 kDMSaveFormatAppleIIgs = 3, 70 kDMSaveFormatAmiga36PC = 5, 71 kCSBSaveFormatAmigaPC98FmTowns = 5, 72 kDMSaveFormatTotal 73 }; 74 75 enum OriginalSavePlatform { 76 kDMSavePlatformAcceptAny = -1, 77 kDMSavePlatformEndOfList = 0, 78 kDMSavePlatformNone = 0, 79 kDMSavePlatformAtariSt = 1, // @ C1_PLATFORM_ATARI_ST 80 kDMSavePlatformAppleIIgs = 2, // @ C2_PLATFORM_APPLE_IIGS 81 kDMSavePlatformAmiga = 3, // @ C3_PLATFORM_AMIGA 82 kDMSavePlatformPC98 = 5, // @ C5_PLATFORM_PC98 83 kDMSavePlatformX68000 = 6, // @ C6_PLATFORM_X68000 84 kDMSavePlatformFmTownsEN = 7, // @ C7_PLATFORM_FM_TOWNS_EN 85 kDMSavePlatformFmTownsJP = 8, // @ C8_PLATFORM_FM_TOWNS_JP 86 kDMSavePlatformPC = 9, // @ C9_PLATFORM_PC 87 kDMSavePlatformTotal 88 }; 89 90 enum SaveTarget { 91 kDMSaveTargetAcceptAny = -1, 92 kDMSaveTargetEndOfList = 0, 93 kDMSaveTargetNone = 0, 94 kDMSaveTargetDM21 = 1, 95 kDMSaveTargetTotal 96 }; 97 98 enum Direction { 99 kDMDirNorth = 0, 100 kDMDirEast = 1, 101 kDMDirSouth = 2, 102 kDMDirWest = 3 103 }; 104 105 enum ThingType { 106 kDMThingTypeParty = -1, // @ CM1_THING_TYPE_PARTY 107 kDMThingTypeDoor = 0, // @ C00_THING_TYPE_DOOR 108 kDMThingTypeTeleporter = 1, // @ C01_THING_TYPE_TELEPORTER 109 kDMstringTypeText = 2, // @ C02_THING_TYPE_TEXTSTRING 110 kDMThingTypeSensor = 3, // @ C03_THING_TYPE_SENSOR 111 kDMThingTypeGroup = 4, // @ C04_THING_TYPE_GROUP 112 kDMThingTypeWeapon = 5, // @ C05_THING_TYPE_WEAPON 113 kDMThingTypeArmour = 6, // @ C06_THING_TYPE_ARMOUR 114 kDMThingTypeScroll = 7, // @ C07_THING_TYPE_SCROLL 115 kDMThingTypePotion = 8, // @ C08_THING_TYPE_POTION 116 kDMThingTypeContainer = 9, // @ C09_THING_TYPE_CONTAINER 117 kDMThingTypeJunk = 10, // @ C10_THING_TYPE_JUNK 118 kDMThingTypeProjectile = 14, // @ C14_THING_TYPE_PROJECTILE 119 kDMThingTypeExplosion = 15, // @ C15_THING_TYPE_EXPLOSION 120 kDMThingTypeTotal = 16 // +1 than the last (explosionThingType) 121 }; // @ C[00..15]_THING_TYPE_... 122 123 enum Cell { 124 kDMCellAny = -1, // @ CM1_CELL_ANY 125 kDMCellNorthWest = 0, // @ C00_CELL_NORTHWEST 126 kDMCellNorthEast = 1, // @ C01_CELL_NORTHEAST 127 kDMCellSouthEast = 2, // @ C02_CELL_SOUTHEAST 128 kDMCellSouthWest = 3 // @ C03_CELL_SOUTHWEST 129 }; 130 131 enum GameMode { 132 kDMModeLoadSavedGame = 0, // @ C000_MODE_LOAD_SAVED_GAME 133 kDMModeLoadDungeon = 1, // @ C001_MODE_LOAD_DUNGEON 134 kDMModeWaitingOnEntrance = 99, // @ C099_MODE_WAITING_ON_ENTRANCE 135 kDMModeEntranceDrawCredits = 202 // @ C202_MODE_ENTRANCE_DRAW_CREDITS 136 }; 137 138 enum LoadgameResult { 139 kDMLoadgameFailure = -1, // @ CM1_LOAD_GAME_FAILURE 140 kDMLoadgameSuccess = 1// @ C01_LOAD_GAME_SUCCESS 141 }; 142 143 enum MapIndice { 144 kDMMapIndexNone = -1, // @ CM1_MAP_INDEX_NONE 145 kDMMapIndexEntrance = 255 // @ C255_MAP_INDEX_ENTRANCE 146 }; 147 148 #define kDMMaskDecodeEvenIfInvisible 0x8000 // @ MASK0x8000_DECODE_EVEN_IF_INVISIBLE 149 #define kDMMaskMergeCycles 0x8000 // @ MASK0x8000_MERGE_CYCLES 150 151 #define kDMSlotBoxInventoryFirstSlot 8 // @ C08_SLOT_BOX_INVENTORY_FIRST_SLOT 152 #define kDMSlotBoxInventoryActionHand 9 // @ C09_SLOT_BOX_INVENTORY_ACTION_HAND 153 #define kDMSlotBoxChestFirstSlot 38 // @ C38_SLOT_BOX_CHEST_FIRST_SLOT 154 155 struct DMADGameDescription { 156 ADGameDescription _desc; 157 158 SaveTarget _saveTargetToWrite; 159 OriginalSaveFormat _origSaveFormatToWrite; 160 OriginalSavePlatform _origPlatformToWrite; 161 162 SaveTarget _saveTargetToAccept[kDMSaveTargetTotal + 1]; 163 OriginalSaveFormat _saveFormatToAccept[kDMSaveFormatTotal + 1]; 164 OriginalSavePlatform _origPlatformToAccept[kDMSavePlatformTotal + 1]; 165 }; 166 167 class Thing { 168 public: 169 uint16 _data; 170 Thing()171 Thing() : _data(0) {} Thing(const Thing & other)172 Thing(const Thing &other) { set(other._data); } Thing(uint16 d)173 explicit Thing(uint16 d) { set(d); } 174 set(uint16 d)175 void set(uint16 d) { 176 _data = d; 177 } 178 getCell()179 byte getCell() const { return _data >> 14; } getType()180 ThingType getType() const { return (ThingType)((_data >> 10) & 0xF); } getIndex()181 uint16 getIndex() const { return _data & 0x3FF; } 182 setCell(uint16 cell)183 void setCell(uint16 cell) { _data = (_data & ~(0x3 << 14)) | ((cell & 0x3) << 14); } setType(uint16 type)184 void setType(uint16 type) { _data = (_data & ~(0xF << 10)) | ((type & 0xF) << 10); } setIndex(uint16 index)185 void setIndex(uint16 index) { _data = (_data & ~0x3FF) | (index & 0x3FF); } 186 getTypeAndIndex()187 uint16 getTypeAndIndex() { return _data & 0x3FFF; } toUint16()188 uint16 toUint16() const { return _data; } // I don't like 'em cast operators 189 bool operator==(const Thing &rhs) const { return _data == rhs._data; } 190 bool operator!=(const Thing &rhs) const { return _data != rhs._data; } 191 }; // @ THING 192 193 #define setFlag(val, mask) ((val) |= (mask)) 194 #define getFlag(val, mask) ((val) & (mask)) 195 #define clearFlag(val, mask) ((val) &= (~(mask))) // @ M09_CLEAR 196 197 // Note: F0026_MAIN_GetBoundedValue<T> has been replaced by CLIP<T> 198 199 #define CALL_MEMBER_FN(object, ptrToMember) ((object).*(ptrToMember)) 200 201 struct SaveGameHeader { 202 byte _version; 203 SaveStateDescriptor _descr; 204 }; 205 206 class DMEngine : public Engine { 207 private: 208 void startGame(); // @ F0462_START_StartGame_CPSF 209 void processNewPartyMap(uint16 mapIndex); // @ F0003_MAIN_ProcessNewPartyMap_CPSE 210 void initializeGame(); // @ F0463_START_InitializeGame_CPSADEF 211 void initMemoryManager(); // @ F0448_STARTUP1_InitializeMemoryManager_CPSADEF 212 void gameloop(); // @ F0002_MAIN_GameLoop_CPSDF 213 void initConstants(); 214 Common::String getSavefileName(uint16 slot); 215 void writeSaveGameHeader(Common::OutSaveFile *out, const Common::String &saveName); 216 bool writeCompleteSaveFile(int16 slot, Common::String &desc, int16 saveAndPlayChoice); 217 void drawEntrance(); // @ F0439_STARTEND_DrawEntrance 218 void fuseSequenceUpdate(); // @ F0445_STARTEND_FuseSequenceUpdate 219 void processEntrance(); // @ F0441_STARTEND_ProcessEntrance 220 void openEntranceDoors(); // @ F0438_STARTEND_OpenEntranceDoors 221 void drawTittle(); // @ F0437_STARTEND_DrawTitle 222 223 public: 224 explicit DMEngine(OSystem *syst, const DMADGameDescription *gameDesc); 225 ~DMEngine(); 226 virtual bool hasFeature(EngineFeature f) const; 227 228 virtual Common::Error loadGameState(int slot); 229 virtual bool canLoadGameStateCurrently(); 230 231 bool isDemo() const; 232 getDebugger()233 GUI::Debugger *getDebugger() { return _console; } 234 235 void delay(uint16 verticalBlank); // @ F0022_MAIN_Delay 236 uint16 getScaledProduct(uint16 val, uint16 scale, uint16 vale2); // @ F0030_MAIN_GetScaledProduct getRandomNumber(uint32 max)237 uint16 getRandomNumber(uint32 max) { return _rnd->getRandomNumber(max - 1); } 238 int16 ordinalToIndex(int16 val); // @ M01_ORDINAL_TO_INDEX 239 int16 indexToOrdinal(int16 val); // @ M00_INDEX_TO_ORDINAL 240 virtual Common::Error run(); // @ main 241 void saveGame(); // @ F0433_STARTEND_ProcessCommand140_SaveGame_CPSCDF 242 LoadgameResult loadgame(int16 slot); // @ F0435_STARTEND_LoadGame_CPSF 243 void endGame(bool doNotDrawCreditsOnly); // @ F0444_STARTEND_Endgame 244 245 void entranceDrawCredits(); 246 void fuseSequence(); // @ F0446_STARTEND_FuseSequence 247 Common::Language getGameLanguage(); 248 249 Direction turnDirRight(int16 dir); // @ M17_NEXT 250 Direction turnDirLeft(int16 dir); // @ M19_PREVIOUS 251 Direction returnOppositeDir(int16 dir); // @ M18_OPPOSITE 252 bool isOrientedWestEast(int16 dir); // @ M16_IS_ORIENTED_WEST_EAST 253 uint16 normalizeModulo4(int16 dir); // @ M21_NORMALIZE 254 255 int32 filterTime(int32 mapTime); // @ M30_TIME 256 int32 setMapAndTime(uint32 map, uint32 time); // @ M33_SET_MAP_AND_TIME 257 uint16 getMap(int32 mapTime); // @ M29_MAP 258 Thing thingWithNewCell(Thing thing, int16 cell); // @ M15_THING_WITH_NEW_CELL 259 int16 getDistance(int16 mapx1, int16 mapy1, int16 mapx2, int16 mapy2); // @ M38_DISTANCE 260 int32 setMap(int32 mapTime, uint32 map); // @ M31_setMap 261 262 263 private: 264 uint16 _dungeonId; // @ G0526_ui_DungeonID 265 byte *_entranceDoorAnimSteps[10]; // @ G0562_apuc_Bitmap_EntranceDoorAnimationSteps 266 byte *_interfaceCredits; // @ G0564_puc_Graphic5_InterfaceCredits 267 Common::RandomSource *_rnd; 268 269 byte *_savedScreenForOpenEntranceDoors; // ad-hoc HACK 270 const DMADGameDescription *_gameVersion; 271 bool _canLoadFromGMM; 272 public: 273 Console *_console; 274 DisplayMan *_displayMan; 275 DungeonMan *_dungeonMan; 276 EventManager *_eventMan; 277 MenuMan *_menuMan; 278 ChampionMan *_championMan; 279 ObjectMan *_objectMan; 280 InventoryMan *_inventoryMan; 281 TextMan *_textMan; 282 MovesensMan *_moveSens; 283 GroupMan *_groupMan; 284 Timeline *_timeline; 285 ProjExpl *_projexpl; 286 DialogMan *_dialog; 287 SoundMan *_sound; 288 289 Common::MemoryWriteStreamDynamic *_saveThumbnail; 290 291 bool _engineShouldQuit; 292 int _loadSaveSlotAtRuntime; 293 294 GameMode _gameMode; // @ G0298_B_NewGame 295 bool _restartGameRequest; // @ G0523_B_RestartGameRequested 296 297 bool _stopWaitingForPlayerInput; // @ G0321_B_StopWaitingForPlayerInput 298 bool _gameTimeTicking; // @ G0301_B_GameTimeTicking 299 bool _restartGameAllowed; // @ G0524_B_RestartGameAllowed 300 bool _pressingEye; // @ G0331_B_PressingEye 301 bool _stopPressingEye; // @ G0332_B_StopPressingEye 302 bool _pressingMouth; // @ G0333_B_PressingMouth 303 bool _stopPressingMouth; // @ G0334_B_StopPressingMouth 304 bool _highlightBoxInversionRequested; // @ G0340_B_HighlightBoxInversionRequested 305 int16 _projectileDisableMovementTicks; // @ G0311_i_ProjectileDisabledMovementTicks 306 int16 _lastProjectileDisabledMovementDirection; // @ G0312_i_LastProjectileDisabledMovementDirection 307 bool _gameWon; // @ G0302_B_GameWon 308 int16 _newPartyMapIndex; // @ G0327_i_NewPartyMapIndex 309 bool _setMousePointerToObjectInMainLoop; // @ G0325_B_SetMousePointerToObjectInMainLoop 310 int16 _disabledMovementTicks; // @ G0310_i_DisabledMovementTicks 311 312 int8 _dirIntoStepCountEast[4]; // @ G0233_ai_Graphic559_DirectionToStepEastCount 313 int8 _dirIntoStepCountNorth[4]; // @ G0234_ai_Graphic559_DirectionToStepNorthCount 314 int32 _gameTime; // @ G0313_ul_GameTime 315 char _stringBuildBuffer[128]; // @ G0353_ac_StringBuildBuffer 316 int16 _waitForInputMaxVerticalBlankCount; // @ G0318_i_WaitForInputMaximumVerticalBlankCount 317 318 Thing _thingNone; // @ C0xFFFF_THING_NONE 319 Thing _thingEndOfList; // @ C0xFFFE_THING_ENDOFLIST 320 Thing _thingFirstExplosion; // @ C0xFF80_THING_FIRST_EXPLOSION 321 Thing _thingExplFireBall; // @ C0xFF80_THING_EXPLOSION_FIREBALL 322 Thing _thingExplSlime; // @ C0xFF81_THING_EXPLOSION_SLIME 323 Thing _thingExplLightningBolt; // @ C0xFF82_THING_EXPLOSION_LIGHTNING_BOLT 324 Thing _thingExplHarmNonMaterial; // @ C0xFF83_THING_EXPLOSION_HARM_NON_MATERIAL 325 Thing _thingExplOpenDoor; // @ C0xFF84_THING_EXPLOSION_OPEN_DOOR 326 Thing _thingExplPoisonBolt; // @ C0xFF86_THING_EXPLOSION_POISON_BOLT 327 Thing _thingExplPoisonCloud; // @ C0xFF87_THING_EXPLOSION_POISON_CLOUD 328 Thing _thingExplSmoke; // @ C0xFFA8_THING_EXPLOSION_SMOKE 329 Thing _thingExplFluxcage; // @ C0xFFB2_THING_EXPLOSION_FLUXCAGE 330 Thing _thingExplRebirthStep1; // @ C0xFFE4_THING_EXPLOSION_REBIRTH_STEP1 331 Thing _thingExplRebirthStep2; // @ C0xFFE5_THING_EXPLOSION_REBIRTH_STEP2 332 Thing _thingParty; // @ C0xFFFF_THING_PARTY 333 }; 334 335 WARN_UNUSED_RESULT bool readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader *header, bool skipThumbnail = true); 336 337 } // End of namespace DM 338 339 #endif 340