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 #ifndef ADL_ADL_H 24 #define ADL_ADL_H 25 26 #include "common/debug-channels.h" 27 #include "common/array.h" 28 #include "common/rect.h" 29 #include "common/str.h" 30 #include "common/hashmap.h" 31 #include "common/hash-str.h" 32 #include "common/func.h" 33 #include "common/ptr.h" 34 #include "common/scummsys.h" 35 36 #include "engines/engine.h" 37 38 #include "audio/mixer.h" 39 #include "audio/softsynth/pcspk.h" 40 41 #include "adl/console.h" 42 #include "adl/disk.h" 43 #include "adl/sound.h" 44 #include "adl/detection.h" 45 46 namespace Common { 47 class ReadStream; 48 class WriteStream; 49 class SeekableReadStream; 50 class File; 51 struct Event; 52 class RandomSource; 53 } 54 55 namespace Adl { 56 57 Common::String getDiskImageName(const AdlGameDescription &adlDesc, byte volume); 58 GameType getGameType(const AdlGameDescription &desc); 59 GameVersion getGameVersion(const AdlGameDescription &desc); 60 Common::Language getLanguage(const AdlGameDescription &desc); 61 Common::Platform getPlatform(const AdlGameDescription &desc); 62 63 class Console; 64 class Display; 65 class GraphicsMan; 66 class ScriptEnv; 67 68 enum kDebugChannels { 69 kDebugChannelScript = 1 << 0 70 }; 71 72 enum ADLAction { 73 kADLActionNone, 74 kADLActionQuit, 75 76 kADLActionCount 77 }; 78 79 // Save and restore opcodes 80 #define IDO_ACT_SAVE 0x0f 81 #define IDO_ACT_LOAD 0x10 82 83 #define IDI_CUR_ROOM 0xfc 84 #define IDI_VOID_ROOM 0xfd 85 #define IDI_ANY 0xfe 86 87 #define IDI_WORD_SIZE 8 88 89 enum Direction { 90 IDI_DIR_NORTH, 91 IDI_DIR_SOUTH, 92 IDI_DIR_EAST, 93 IDI_DIR_WEST, 94 IDI_DIR_UP, 95 IDI_DIR_DOWN, 96 IDI_DIR_TOTAL 97 }; 98 99 struct Room { RoomRoom100 Room() : 101 description(0), 102 picture(0), 103 curPicture(0), 104 isFirstTime(true) { 105 memset(connections, 0, sizeof(connections)); 106 } 107 108 byte description; 109 byte connections[IDI_DIR_TOTAL]; 110 DataBlockPtr data; 111 byte picture; 112 byte curPicture; 113 bool isFirstTime; 114 }; 115 116 typedef Common::HashMap<byte, DataBlockPtr> PictureMap; 117 118 typedef Common::Array<byte> Script; 119 120 struct Command { 121 byte room; 122 byte verb, noun; 123 byte numCond, numAct; 124 Script script; 125 }; 126 127 class ScriptEnv { 128 public: ScriptEnv(const Command & cmd,byte room,byte verb,byte noun)129 ScriptEnv(const Command &cmd, byte room, byte verb, byte noun) : 130 _cmd(cmd), _room(room), _verb(verb), _noun(noun), _ip(0) { } 131 ~ScriptEnv()132 virtual ~ScriptEnv() { } 133 134 enum kOpType { 135 kOpTypeDone, 136 kOpTypeCond, 137 kOpTypeAct 138 }; 139 op()140 byte op() const { return _cmd.script[_ip]; } 141 virtual kOpType getOpType() const = 0; 142 // We keep this 1-based for easier comparison with the original engine arg(uint i)143 byte arg(uint i) const { return _cmd.script[_ip + i]; } 144 virtual void next(uint numArgs) = 0; 145 isMatch()146 bool isMatch() const { 147 return (_cmd.room == IDI_ANY || _cmd.room == _room) && 148 (_cmd.verb == IDI_ANY || _cmd.verb == _verb) && 149 (_cmd.noun == IDI_ANY || _cmd.noun == _noun); 150 } 151 getNoun()152 byte getNoun() const { return _noun; } getCommand()153 const Command &getCommand() const { return _cmd; } 154 155 protected: 156 byte _ip; 157 158 private: 159 const Command &_cmd; 160 const byte _room, _verb, _noun; 161 }; 162 163 enum { 164 IDI_ITEM_NOT_MOVED, 165 IDI_ITEM_DROPPED, 166 IDI_ITEM_DOESNT_MOVE 167 }; 168 169 struct Item { 170 byte id; 171 byte noun; 172 byte region; 173 byte room; 174 byte picture; 175 bool isShape; 176 Common::Point position; 177 int state; 178 byte description; 179 Common::Array<byte> roomPictures; 180 bool isOnScreen; 181 ItemItem182 Item() : id(0), noun(0), region(0), room(0), picture(0), isShape(false), state(0), description(0), isOnScreen(false) { } 183 }; 184 185 struct Time { 186 byte hours, minutes; 187 TimeTime188 Time() : hours(12), minutes(0) { } 189 }; 190 191 struct RoomState { 192 byte picture; 193 byte isFirstTime; 194 }; 195 196 struct Region { 197 Common::Array<byte> vars; 198 Common::Array<RoomState> rooms; 199 }; 200 201 struct State { 202 Common::Array<Region> regions; 203 Common::Array<Room> rooms; 204 Common::List<Item> items; 205 Common::Array<byte> vars; 206 207 byte region, prevRegion; 208 byte room; 209 byte curPicture; 210 uint16 moves; 211 bool isDark; 212 Time time; 213 StateState214 State() : region(0), prevRegion(0), room(1), curPicture(0), moves(1), isDark(false) { } 215 }; 216 217 typedef Common::List<Command> Commands; 218 typedef Common::HashMap<Common::String, uint> WordMap; 219 220 struct RoomData { 221 Common::String description; 222 PictureMap pictures; 223 Commands commands; 224 }; 225 226 // Opcode debugging macros 227 #define OP_DEBUG_0(F) do { \ 228 if (DebugMan.isDebugChannelEnabled(kDebugChannelScript) && op_debug(F)) \ 229 return 0; \ 230 } while (0) 231 232 #define OP_DEBUG_1(F, P1) do { \ 233 if (DebugMan.isDebugChannelEnabled(kDebugChannelScript) && op_debug(F, P1)) \ 234 return 1; \ 235 } while (0) 236 237 #define OP_DEBUG_2(F, P1, P2) do { \ 238 if (DebugMan.isDebugChannelEnabled(kDebugChannelScript) && op_debug(F, P1, P2)) \ 239 return 2; \ 240 } while (0) 241 242 #define OP_DEBUG_3(F, P1, P2, P3) do { \ 243 if (DebugMan.isDebugChannelEnabled(kDebugChannelScript) && op_debug(F, P1, P2, P3)) \ 244 return 3; \ 245 } while (0) 246 247 #define OP_DEBUG_4(F, P1, P2, P3, P4) do { \ 248 if (DebugMan.isDebugChannelEnabled(kDebugChannelScript) && op_debug(F, P1, P2, P3, P4)) \ 249 return 4; \ 250 } while (0) 251 252 class AdlEngine : public Engine { 253 friend class Console; 254 public: 255 ~AdlEngine() override; 256 257 bool pollEvent(Common::Event &event) const; 258 void bell(uint count = 1) const; 259 260 protected: 261 AdlEngine(OSystem *syst, const AdlGameDescription *gd); 262 263 // Engine 264 Common::Error loadGameState(int slot) override; 265 Common::Error saveGameState(int slot, const Common::String &desc, bool isAutosave = false) override; 266 bool canSaveGameStateCurrently() override; 267 virtual Common::String getSaveStateName(int slot) const override; getAutosaveSlot()268 int getAutosaveSlot() const override { return 15; } 269 getDiskImageName(byte volume)270 Common::String getDiskImageName(byte volume) const { return Adl::getDiskImageName(*_gameDescription, volume); } getGameType()271 GameType getGameType() const { return Adl::getGameType(*_gameDescription); } getGameVersion()272 GameVersion getGameVersion() const { return Adl::getGameVersion(*_gameDescription); } getLanguage()273 Common::Language getLanguage() const { return Adl::getLanguage(*_gameDescription); } 274 virtual void gameLoop(); 275 virtual void loadState(Common::ReadStream &stream); 276 virtual void saveState(Common::WriteStream &stream); 277 Common::String readString(Common::ReadStream &stream, byte until = 0) const; 278 Common::String readStringAt(Common::SeekableReadStream &stream, uint offset, byte until = 0) const; 279 void extractExeStrings(Common::ReadStream &stream, uint16 printAddr, Common::StringArray &strings) const; 280 281 virtual void printString(const Common::String &str) = 0; 282 virtual Common::String loadMessage(uint idx) const = 0; 283 virtual void printMessage(uint idx); 284 virtual Common::String getItemDescription(const Item &item) const; 285 void delay(uint32 ms) const; 286 287 virtual Common::String getLine(); 288 Common::String inputString(byte prompt = 0) const; 289 byte inputKey(bool showCursor = true) const; 290 virtual void getInput(uint &verb, uint &noun); 291 Common::String getWord(const Common::String &line, uint &index) const; 292 293 virtual Common::String formatVerbError(const Common::String &verb) const; 294 virtual Common::String formatNounError(const Common::String &verb, const Common::String &noun) const; 295 void loadWords(Common::ReadStream &stream, WordMap &map, Common::StringArray &pri) const; 296 void readCommands(Common::ReadStream &stream, Commands &commands); 297 void removeCommand(Commands &commands, uint idx); 298 Command &getCommand(Commands &commands, uint idx); 299 void checkInput(byte verb, byte noun); 300 virtual bool isInputValid(byte verb, byte noun, bool &is_any); 301 virtual bool isInputValid(const Commands &commands, byte verb, byte noun, bool &is_any); applyRoomWorkarounds(byte roomNr)302 virtual void applyRoomWorkarounds(byte roomNr) { } applyRegionWorkarounds()303 virtual void applyRegionWorkarounds() { } 304 305 virtual void setupOpcodeTables(); 306 virtual void initState(); 307 virtual void switchRoom(byte roomNr); 308 virtual byte roomArg(byte room) const; advanceClock()309 virtual void advanceClock() { } 310 void loadDroppedItemOffsets(Common::ReadStream &stream, byte count); 311 312 // Opcodes 313 typedef Common::SharedPtr<Common::Functor1<ScriptEnv &, int> > Opcode; 314 315 template <class T> opcode(int (T::* f)(ScriptEnv &))316 Opcode opcode(int (T::*f)(ScriptEnv &)) { 317 return Opcode(new Common::Functor1Mem<ScriptEnv &, int, T>(static_cast<T *>(this), f)); 318 } 319 320 virtual int o_isItemInRoom(ScriptEnv &e); 321 virtual int o_isMovesGT(ScriptEnv &e); 322 virtual int o_isVarEQ(ScriptEnv &e); 323 virtual int o_isCurPicEQ(ScriptEnv &e); 324 virtual int o_isItemPicEQ(ScriptEnv &e); 325 326 virtual int o_varAdd(ScriptEnv &e); 327 virtual int o_varSub(ScriptEnv &e); 328 virtual int o_varSet(ScriptEnv &e); 329 virtual int o_listInv(ScriptEnv &e); 330 virtual int o_moveItem(ScriptEnv &e); 331 virtual int o_setRoom(ScriptEnv &e); 332 virtual int o_setCurPic(ScriptEnv &e); 333 virtual int o_setPic(ScriptEnv &e); 334 virtual int o_printMsg(ScriptEnv &e); 335 virtual int o_setLight(ScriptEnv &e); 336 virtual int o_setDark(ScriptEnv &e); 337 virtual int o_save(ScriptEnv &e); 338 virtual int o_restore(ScriptEnv &e); 339 virtual int o_restart(ScriptEnv &e); 340 virtual int o_quit(ScriptEnv &e); 341 virtual int o_placeItem(ScriptEnv &e); 342 virtual int o_setItemPic(ScriptEnv &e); 343 virtual int o_resetPic(ScriptEnv &e); 344 virtual int o_takeItem(ScriptEnv &e); 345 virtual int o_dropItem(ScriptEnv &e); 346 virtual int o_setRoomPic(ScriptEnv &e); 347 348 virtual int goDirection(ScriptEnv &e, Direction D); o_goNorth(ScriptEnv & e)349 int o_goNorth(ScriptEnv &e) { return goDirection(e, IDI_DIR_NORTH); } o_goSouth(ScriptEnv & e)350 int o_goSouth(ScriptEnv &e) { return goDirection(e, IDI_DIR_SOUTH); } o_goEast(ScriptEnv & e)351 int o_goEast(ScriptEnv &e) { return goDirection(e, IDI_DIR_EAST); } o_goWest(ScriptEnv & e)352 int o_goWest(ScriptEnv &e) { return goDirection(e, IDI_DIR_WEST); } o_goUp(ScriptEnv & e)353 int o_goUp(ScriptEnv &e) { return goDirection(e, IDI_DIR_UP); } o_goDown(ScriptEnv & e)354 int o_goDown(ScriptEnv &e) { return goDirection(e, IDI_DIR_DOWN); } 355 356 // Graphics 357 void drawPic(byte pic, Common::Point pos = Common::Point()) const; 358 359 // Sound 360 bool playTones(const Tones &tones, bool isMusic, bool allowSkip = false) const; 361 362 // Game state functions 363 const Region &getRegion(uint i) const; 364 Region &getRegion(uint i); 365 const Room &getRoom(uint i) const; 366 Room &getRoom(uint i); 367 const Region &getCurRegion() const; 368 Region &getCurRegion(); 369 const Room &getCurRoom() const; 370 Room &getCurRoom(); 371 const Item &getItem(uint i) const; 372 Item &getItem(uint i); 373 byte getVar(uint i) const; 374 void setVar(uint i, byte value); 375 virtual void takeItem(byte noun); 376 virtual void dropItem(byte noun); 377 bool matchCommand(ScriptEnv &env) const; 378 void doActions(ScriptEnv &env); 379 bool doOneCommand(const Commands &commands, byte verb, byte noun); 380 void doAllCommands(const Commands &commands, byte verb, byte noun); 381 virtual ScriptEnv *createScriptEnv(const Command &cmd, byte room, byte verb, byte noun); 382 383 // Debug functions 384 static Common::String toAscii(const Common::String &str); 385 Common::String itemStr(uint i) const; 386 Common::String roomStr(uint i) const; 387 Common::String itemRoomStr(uint i) const; 388 Common::String verbStr(uint i) const; 389 Common::String nounStr(uint i) const; 390 Common::String msgStr(uint i) const; 391 Common::String dirStr(Direction dir) const; 392 bool op_debug(const char *fmt, ...) const; 393 Common::DumpFile *_dumpFile; 394 395 Display *_display; 396 GraphicsMan *_graphics; 397 bool _textMode; 398 399 // Opcodes 400 Common::Array<Opcode> _condOpcodes, _actOpcodes; 401 // Message strings in data file 402 Common::Array<DataBlockPtr> _messages; 403 // Picture data 404 PictureMap _pictures; 405 // Dropped item screen offsets 406 Common::Array<Common::Point> _itemOffsets; 407 // <room, verb, noun, script> lists 408 Commands _roomCommands; 409 Commands _globalCommands; 410 // Data related to the current room 411 RoomData _roomData; 412 413 WordMap _verbs; 414 WordMap _nouns; 415 Common::StringArray _priVerbs; 416 Common::StringArray _priNouns; 417 418 struct { 419 Common::String enterCommand; 420 Common::String verbError; 421 Common::String nounError; 422 Common::String playAgain; 423 Common::String pressReturn; 424 Common::String lineFeeds; 425 } _strings; 426 427 uint32 _verbErrorPos, _nounErrorPos; 428 429 struct { 430 uint cantGoThere; 431 uint dontUnderstand; 432 uint itemDoesntMove; 433 uint itemNotHere; 434 uint thanksForPlaying; 435 } _messageIds; 436 437 // Game state 438 State _state; 439 440 uint _linesPrinted; 441 bool _isRestarting, _isRestoring, _isQuitting; 442 bool _canSaveNow, _canRestoreNow; 443 bool _abortScript; 444 Common::RandomSource *_random; 445 446 const AdlGameDescription *_gameDescription; 447 448 mutable Common::File *_inputScript; 449 mutable uint _scriptDelay; 450 mutable bool _scriptPaused; 451 452 private: runIntro()453 virtual void runIntro() { } 454 virtual void init() = 0; 455 virtual void initGameState() = 0; 456 virtual void drawItems() = 0; 457 virtual void drawItem(Item &item, const Common::Point &pos) = 0; 458 virtual void loadRoom(byte roomNr) = 0; 459 virtual void showRoom() = 0; switchRegion(byte region)460 virtual void switchRegion(byte region) { } 461 void runScript(const char *filename) const; 462 void stopScript() const; setScriptDelay(uint scriptDelay)463 void setScriptDelay(uint scriptDelay) const { _scriptDelay = scriptDelay; } 464 Common::String getScriptLine() const; 465 // Engine 466 Common::Error run() override; 467 bool hasFeature(EngineFeature f) const override; 468 bool canLoadGameStateCurrently() override; 469 470 // Text input 471 byte convertKey(uint16 ascii) const; 472 473 byte _saveVerb, _saveNoun, _restoreVerb, _restoreNoun; 474 }; 475 476 } // End of namespace Adl 477 478 #endif 479