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 AGI_AGI_H 24 #define AGI_AGI_H 25 26 #include "common/scummsys.h" 27 #include "common/error.h" 28 #include "common/util.h" 29 #include "common/file.h" 30 #include "common/keyboard.h" 31 #include "common/rect.h" 32 #include "common/rendermode.h" 33 #include "common/stack.h" 34 #include "common/str.h" 35 #include "common/system.h" 36 37 #include "engines/engine.h" 38 39 #include "gui/debugger.h" 40 41 // AGI resources 42 #include "agi/console.h" 43 #include "agi/view.h" 44 #include "agi/picture.h" 45 #include "agi/logic.h" 46 #include "agi/sound.h" 47 #include "agi/detection.h" 48 49 namespace Common { 50 class RandomSource; 51 } 52 53 /** 54 * This is the namespace of the AGI engine. 55 * 56 * Status of this engine: ??? 57 * 58 * Games using this engine: 59 * - Early Sierra adventure games 60 * - many fan made games 61 * - Mickey's Space Adventure (Pre-AGI) 62 * - Winnie the Pooh in the Hundred Acre Wood (Pre-AGI) 63 * - Troll's Tale (Pre-AGI) 64 */ 65 namespace Agi { 66 67 typedef signed int Err; 68 69 // 70 // Version and other definitions 71 // 72 73 #define TITLE "AGI engine" 74 75 #define DIR_ "dir" 76 #define LOGDIR "logdir" 77 #define PICDIR "picdir" 78 #define VIEWDIR "viewdir" 79 #define SNDDIR "snddir" 80 #define OBJECTS "object" 81 #define WORDS "words.tok" 82 83 #define MAX_DIRECTORY_ENTRIES 256 84 #define MAX_CONTROLLERS 256 85 #define MAX_VARS 256 86 #define MAX_FLAGS (256 >> 3) 87 #define SCREENOBJECTS_MAX 255 // KQ3 uses o255! 88 #define SCREENOBJECTS_EGO_ENTRY 0 // first entry is ego 89 #define MAX_WORDS 20 90 #define MAX_STRINGS 24 // MAX_STRINGS + 1 used for get.num 91 #define MAX_STRINGLEN 40 92 #define MAX_CONTROLLER_KEYMAPPINGS 39 93 94 #define SAVEDGAME_DESCRIPTION_LEN 30 95 96 #define _EMPTY 0xfffff 97 #define EGO_OWNED 0xff 98 #define EGO_OWNED_V1 0xf9 99 100 #define CRYPT_KEY_SIERRA "Avis Durgan" 101 #define CRYPT_KEY_AGDS "Alex Simkin" 102 103 #define ADD_PIC 1 104 #define ADD_VIEW 2 105 106 #define CMD_BSIZE 12 107 108 enum { 109 NO_GAMEDIR = 0, 110 GAMEDIR 111 }; 112 113 enum AGIErrors { 114 errOK = 0, 115 errDoNothing, 116 errBadCLISwitch, 117 errInvalidAGIFile, 118 errBadFileOpen, 119 errNotEnoughMemory, 120 errBadResource, 121 errUnknownAGIVersion, 122 errNoLoopsInView, 123 errViewDataError, 124 errNoGameList, 125 errIOError, 126 127 errUnk = 127 128 }; 129 130 enum kDebugLevels { 131 kDebugLevelMain = 1 << 0, 132 kDebugLevelResources = 1 << 1, 133 kDebugLevelSprites = 1 << 2, 134 kDebugLevelInventory = 1 << 3, 135 kDebugLevelInput = 1 << 4, 136 kDebugLevelMenu = 1 << 5, 137 kDebugLevelScripts = 1 << 6, 138 kDebugLevelSound = 1 << 7, 139 kDebugLevelText = 1 << 8, 140 kDebugLevelSavegame = 1 << 9 141 }; 142 143 /** 144 * AGI resources. 145 */ 146 enum { 147 RESOURCETYPE_LOGIC = 1, 148 RESOURCETYPE_SOUND, 149 RESOURCETYPE_VIEW, 150 RESOURCETYPE_PICTURE 151 }; 152 153 enum { 154 RES_LOADED = 0x01, 155 RES_COMPRESSED = 0x40, 156 RES_PICTURE_V3_NIBBLE_PARM = 0x80 // Flag that gets set for picture resources, 157 // which use a nibble instead of a byte as F0+F2 parameters 158 }; 159 160 enum { 161 lCOMMAND_MODE = 1, 162 lTEST_MODE 163 }; 164 165 struct gameIdList { 166 gameIdList *next; 167 uint32 version; 168 uint32 crc; 169 char *gName; 170 char *switches; 171 }; 172 173 struct Mouse { 174 int button; 175 Common::Point pos; 176 MouseMouse177 Mouse() : button(0) {} 178 }; 179 180 // Used by AGI Mouse protocol 1.0 for v27 (i.e. button pressed -variable). 181 enum AgiMouseButton { 182 kAgiMouseButtonUp, // Mouse button is up (not pressed) 183 kAgiMouseButtonLeft, // Left mouse button 184 kAgiMouseButtonRight, // Right mouse button 185 kAgiMouseButtonMiddle // Middle mouse button 186 }; 187 188 /** 189 * AGI variables. 190 */ 191 enum { 192 VM_VAR_CURRENT_ROOM = 0, // 0 193 VM_VAR_PREVIOUS_ROOM, // 1 194 VM_VAR_BORDER_TOUCH_EGO, // 2 195 VM_VAR_SCORE, // 3 196 VM_VAR_BORDER_CODE, // 4 197 VM_VAR_BORDER_TOUCH_OBJECT, // 5 198 VM_VAR_EGO_DIRECTION, // 6 199 VM_VAR_MAX_SCORE, // 7 200 VM_VAR_FREE_PAGES, // 8 201 VM_VAR_WORD_NOT_FOUND, // 9 202 VM_VAR_TIME_DELAY, // 10 203 VM_VAR_SECONDS, // 11 204 VM_VAR_MINUTES, // 12 205 VM_VAR_HOURS, // 13 206 VM_VAR_DAYS, // 14 207 VM_VAR_JOYSTICK_SENSITIVITY, // 15 208 VM_VAR_EGO_VIEW_RESOURCE, // 16 209 VM_VAR_AGI_ERROR_CODE, // 17 210 VM_VAR_AGI_ERROR_INFO, // 18 211 VM_VAR_KEY, // 19 212 VM_VAR_COMPUTER, // 20 213 VM_VAR_WINDOW_AUTO_CLOSE_TIMER, // 21 214 VM_VAR_SOUNDGENERATOR, // 22 215 VM_VAR_VOLUME, // 23 216 VM_VAR_MAX_INPUT_CHARACTERS, // 24 217 VM_VAR_SELECTED_INVENTORY_ITEM, // 25 218 VM_VAR_MONITOR = 26, // 26 219 VM_VAR_MOUSE_BUTTONSTATE = 27, // 27 220 VM_VAR_MOUSE_X = 28, // 28 221 VM_VAR_MOUSE_Y = 29 // 29 222 }; 223 224 /** 225 * Different monitor types. 226 * Used with AGI variable 26 i.e. vMonitor. 227 */ 228 enum AgiMonitorType { 229 kAgiMonitorCga = 0, 230 //kAgiMonitorTandy = 1, // Not sure about this 231 kAgiMonitorHercules = 2, 232 kAgiMonitorEga = 3 233 //kAgiMonitorVga = 4 // Not sure about this 234 }; 235 236 /** 237 * Different computer types. 238 * Used with AGI variable 20 i.e. vComputer. 239 * 240 * At least these Amiga AGI versions use value 5: 241 * 2.082 (King's Quest I v1.0U 1986) 242 * 2.090 (King's Quest III v1.01 1986-11-08) 243 * x.yyy (Black Cauldron v2.00 1987-06-14) 244 * x.yyy (Larry I v1.05 1987-06-26) 245 * 2.107 (King's Quest II v2.0J. Date is probably 1987-01-29) 246 * 2.202 (Space Quest II v2.0F) 247 * 2.310 (Police Quest I v2.0B 1989-02-22) 248 * 2.316 (Gold Rush! v2.05 1989-03-09) 249 * 2.333 (King's Quest III v2.15 1989-11-15) 250 * 251 * At least these Amiga AGI versions use value 20: 252 * 2.082 (Space Quest I v1.2 1986) 253 * x.yyy (Manhunter NY 1.06 3/18/89) 254 * 2.333 (Manhunter SF 3.06 8/17/89) 255 * 256 */ 257 enum AgiComputerType { 258 kAgiComputerPC = 0, 259 kAgiComputerAtariST = 4, 260 kAgiComputerAmiga = 5, // Newer Amiga AGI interpreters' value (Commonly used) 261 kAgiComputerApple2GS = 7, 262 kAgiComputerAmigaOld = 20 // Older Amiga AGI interpreters' value (Seldom used) 263 }; 264 265 enum AgiSoundType { 266 kAgiSoundPC = 1, 267 kAgiSoundTandy = 3, // Tandy (This value is also used by the Amiga AGI and Apple IIGS AGI) 268 kAgiSound2GSOld = 8 // Apple IIGS's Gold Rush! (Version 1.0M 1989-02-28 (CE), AGI 3.003) uses value 8 269 }; 270 271 /** 272 * AGI flags 273 */ 274 enum { 275 VM_FLAG_EGO_WATER = 0, // 0 276 VM_FLAG_EGO_INVISIBLE, 277 VM_FLAG_ENTERED_CLI, 278 VM_FLAG_EGO_TOUCHED_P2, 279 VM_FLAG_SAID_ACCEPTED_INPUT, 280 VM_FLAG_NEW_ROOM_EXEC, // 5 281 VM_FLAG_RESTART_GAME, 282 VM_FLAG_SCRIPT_BLOCKED, 283 VM_FLAG_JOY_SENSITIVITY, 284 VM_FLAG_SOUND_ON, 285 VM_FLAG_DEBUGGER_ON, // 10 286 VM_FLAG_LOGIC_ZERO_FIRST_TIME, 287 VM_FLAG_RESTORE_JUST_RAN, 288 VM_FLAG_STATUS_SELECTS_ITEMS, 289 VM_FLAG_MENUS_ACCESSIBLE, 290 VM_FLAG_OUTPUT_MODE, // 15 291 VM_FLAG_AUTO_RESTART 292 }; 293 294 struct AgiControllerKeyMapping { 295 uint16 keycode; 296 byte controllerSlot; 297 AgiControllerKeyMappingAgiControllerKeyMapping298 AgiControllerKeyMapping() : keycode(0), controllerSlot(0) {} 299 }; 300 301 struct AgiObject { 302 int location; 303 Common::String name; 304 }; 305 306 struct AgiDir { 307 uint8 volume; 308 uint32 offset; 309 uint32 len; 310 uint32 clen; 311 312 // 0 = not in mem, can be freed 313 // 1 = in mem, can be released 314 // 2 = not in mem, cant be released 315 // 3 = in mem, cant be released 316 // 0x40 = was compressed 317 uint8 flags; 318 resetAgiDir319 void reset() { 320 volume = 0; 321 offset = 0; 322 len = 0; 323 clen = 0; 324 flags = 0; 325 } 326 AgiDirAgiDir327 AgiDir() { reset(); } 328 }; 329 330 struct AgiBlock { 331 bool active; 332 int16 x1, y1; 333 int16 x2, y2; 334 AgiBlockAgiBlock335 AgiBlock() : active(false), x1(0), y1(0), x2(0), y2(0) {} 336 }; 337 338 struct ScriptPos { 339 int script; 340 int curIP; 341 }; 342 343 enum CycleInnerLoopType { 344 CYCLE_INNERLOOP_GETSTRING = 0, 345 CYCLE_INNERLOOP_GETNUMBER, 346 CYCLE_INNERLOOP_INVENTORY, 347 CYCLE_INNERLOOP_MENU_VIA_KEYBOARD, 348 CYCLE_INNERLOOP_MENU_VIA_MOUSE, 349 CYCLE_INNERLOOP_SYSTEMUI_SELECTSAVEDGAMESLOT, 350 CYCLE_INNERLOOP_SYSTEMUI_VERIFICATION, 351 CYCLE_INNERLOOP_MESSAGEBOX, 352 CYCLE_INNERLOOP_HAVEKEY 353 }; 354 355 typedef Common::Array<int16> SavedGameSlotIdArray; 356 357 /** 358 * AGI game structure. 359 * This structure contains all global data of an AGI game executed 360 * by the interpreter. 361 */ 362 struct AgiGame { 363 AgiEngine *_vm; 364 365 // TODO: Check whether adjMouseX and adjMouseY must be saved and loaded when using savegames. 366 // If they must be then loading and saving is partially broken at the moment. 367 int adjMouseX; /**< last given adj.ego.move.to.x.y-command's 1st parameter */ 368 int adjMouseY; /**< last given adj.ego.move.to.x.y-command's 2nd parameter */ 369 370 char name[8]; /**< lead in id (e.g. `GR' for goldrush) */ 371 char id[8]; /**< game id */ 372 uint32 crc; /**< game CRC */ 373 374 // game flags and variables 375 uint8 flags[MAX_FLAGS]; /**< 256 1-bit flags combined into a total of 32 bytes */ 376 uint8 vars[MAX_VARS]; /**< 256 variables */ 377 378 // internal variables 379 int16 horizon; /**< horizon y coordinate */ 380 381 bool cycleInnerLoopActive; 382 int16 cycleInnerLoopType; 383 384 int16 curLogicNr; /**< current logic number */ 385 Common::Array<ScriptPos> execStack; 386 387 // internal flags 388 bool playerControl; /**< player is in control */ 389 bool exitAllLogics; /**< break cycle after new.room */ 390 bool pictureShown; /**< show.pic has been issued */ 391 #define ID_AGDS 0x00000001 392 #define ID_AMIGA 0x00000002 393 int gameFlags; /**< agi options flags */ 394 395 // windows 396 AgiBlock block; 397 398 // graphics & text 399 bool gfxMode; 400 401 unsigned int numObjects; 402 403 bool controllerOccured[MAX_CONTROLLERS]; /**< keyboard keypress events */ 404 AgiControllerKeyMapping controllerKeyMapping[MAX_CONTROLLER_KEYMAPPINGS]; 405 406 char strings[MAX_STRINGS + 1][MAX_STRINGLEN]; /**< strings */ 407 408 // directory entries for resources 409 AgiDir dirLogic[MAX_DIRECTORY_ENTRIES]; 410 AgiDir dirPic[MAX_DIRECTORY_ENTRIES]; 411 AgiDir dirView[MAX_DIRECTORY_ENTRIES]; 412 AgiDir dirSound[MAX_DIRECTORY_ENTRIES]; 413 414 // resources 415 AgiPicture pictures[MAX_DIRECTORY_ENTRIES]; /**< AGI picture resources */ 416 AgiLogic logics[MAX_DIRECTORY_ENTRIES]; /**< AGI logic resources */ 417 AgiView views[MAX_DIRECTORY_ENTRIES]; /**< AGI view resources */ 418 AgiSound *sounds[MAX_DIRECTORY_ENTRIES]; /**< Pointers to AGI sound resources */ 419 420 AgiLogic *_curLogic; 421 422 // view table 423 ScreenObjEntry screenObjTable[SCREENOBJECTS_MAX]; 424 425 ScreenObjEntry addToPicView; 426 427 bool automaticSave; /**< set by CmdSetSimple() */ 428 char automaticSaveDescription[SAVEDGAME_DESCRIPTION_LEN + 1]; 429 430 Common::Rect mouseFence; /**< rectangle set by fence.mouse command */ 431 bool mouseEnabled; /**< if mouse is supposed to be active */ 432 bool mouseHidden; /**< if mouse is currently hidden */ 433 434 // IF condition handling 435 int testResult; 436 437 int max_logics; 438 int logic_list[256]; 439 440 // used to detect situations, where the game shows some text and changes rooms right afterwards 441 // for example Space Quest 2 intro right at the start 442 // or Space Quest 2, when entering the vent also right at the start 443 // The developers assumed that loading the new room would take a bit. 444 // In ScummVM it's basically done in an instant, which means that 445 // the text would only get shown for a split second. 446 // We delay a bit as soon as such situations get detected. 447 bool nonBlockingTextShown; 448 int16 nonBlockingTextCyclesLeft; 449 450 bool automaticRestoreGame; 451 452 uint16 appleIIgsSpeedControllerSlot; 453 int appleIIgsSpeedLevel; 454 455 void setAppleIIgsSpeedLevel(int appleIIgsSpeedLevel); 456 AgiGameAgiGame457 AgiGame() { 458 _vm = nullptr; 459 460 adjMouseX = 0; 461 adjMouseY = 0; 462 463 for (uint16 i = 0; i < ARRAYSIZE(name); i++) { 464 name[i] = 0; 465 } 466 for (uint16 i = 0; i < ARRAYSIZE(id); i++) { 467 id[i] = 0; 468 } 469 crc = 0; 470 471 for (uint16 i = 0; i < ARRAYSIZE(flags); i++) { 472 flags[i] = 0; 473 } 474 for (uint16 i = 0; i < ARRAYSIZE(vars); i++) { 475 vars[i] = 0; 476 } 477 478 horizon = 0; 479 480 cycleInnerLoopActive = false; 481 cycleInnerLoopType = 0; 482 483 curLogicNr = 0; 484 485 // execStack is defaulted by Common::Array constructor 486 487 playerControl = false; 488 exitAllLogics = false; 489 pictureShown = false; 490 gameFlags = 0; 491 492 // block defaulted by AgiBlock constructor 493 494 gfxMode = false; 495 496 numObjects = 0; 497 498 for (uint16 i = 0; i < ARRAYSIZE(controllerOccured); i++) { 499 controllerOccured[i] = false; 500 } 501 502 // controllerKeyMapping defaulted by AgiControllerKeyMapping constructor 503 504 for (uint16 i = 0; i < MAX_STRINGS + 1; i++) { 505 for (uint16 j = 0; j < MAX_STRINGLEN; j++) { 506 strings[i][j] = 0; 507 } 508 } 509 510 // dirLogic cleared by AgiDir constructor 511 // dirPic cleared by AgiDir constructor 512 // dirView cleared by AgiDir constructor 513 // dirSound cleared by AgiDir constructor 514 515 // pictures cleared by AgiPicture constructor 516 // logics cleared by AgiLogic constructor 517 // views cleared by AgiView constructor 518 for (uint16 i = 0; i < ARRAYSIZE(sounds); i++) { 519 sounds[i] = nullptr; 520 } 521 522 _curLogic = nullptr; 523 524 // screenObjTable cleared by ScreenObjEntry constructor 525 526 // addToPicView cleared by ScreenObjEntry constructor 527 528 automaticSave = false; 529 for (uint16 i = 0; i < ARRAYSIZE(automaticSaveDescription); i++) { 530 automaticSaveDescription[i] = 0; 531 } 532 533 // mouseFence cleared by Common::Rect constructor 534 mouseEnabled = false; 535 mouseHidden = false; 536 537 testResult = 0; 538 539 max_logics = 0; 540 for (uint16 i = 0; i < ARRAYSIZE(logic_list); i++) { 541 logic_list[i] = 0; 542 } 543 544 nonBlockingTextShown = false; 545 nonBlockingTextCyclesLeft = 0; 546 547 automaticRestoreGame = false; 548 549 appleIIgsSpeedControllerSlot = 0xffff; // we didn't add yet speed menu 550 appleIIgsSpeedLevel = 2; // normal speed 551 } 552 }; 553 554 class AgiLoader { 555 public: 556 AgiLoader()557 AgiLoader() {} ~AgiLoader()558 virtual ~AgiLoader() {} 559 560 virtual int init() = 0; 561 virtual int deinit() = 0; 562 virtual int detectGame() = 0; 563 virtual int loadResource(int16 resourceType, int16 resourceNr) = 0; 564 virtual int unloadResource(int16 resourceType, int16 resourceNr) = 0; 565 virtual int loadObjects(const char *) = 0; 566 virtual int loadWords(const char *) = 0; 567 }; 568 569 class AgiLoader_v1 : public AgiLoader { 570 private: 571 AgiEngine *_vm; 572 Common::String _filenameDisk0; 573 Common::String _filenameDisk1; 574 575 int loadDir_DDP(AgiDir *agid, int offset, int max); 576 int loadDir_BC(AgiDir *agid, int offset, int max); 577 uint8 *loadVolRes(AgiDir *agid); 578 579 public: 580 AgiLoader_v1(AgiEngine *vm); 581 582 int init() override; 583 int deinit() override; 584 int detectGame() override; 585 int loadResource(int16 resourceType, int16 resourceNr) override; 586 int unloadResource(int16 resourceType, int16 resourceNr) override; 587 int loadObjects(const char *) override; 588 int loadWords(const char *) override; 589 }; 590 591 class AgiLoader_v2 : public AgiLoader { 592 private: 593 AgiEngine *_vm; 594 595 int loadDir(AgiDir *agid, const char *fname); 596 uint8 *loadVolRes(AgiDir *agid); 597 598 public: 599 AgiLoader_v2(AgiEngine * vm)600 AgiLoader_v2(AgiEngine *vm) { 601 _vm = vm; 602 } 603 604 int init() override; 605 int deinit() override; 606 int detectGame() override; 607 int loadResource(int16 resourceType, int16 resourceNr) override; 608 int unloadResource(int16 resourceType, int16 resourceNr) override; 609 int loadObjects(const char *) override; 610 int loadWords(const char *) override; 611 }; 612 613 class AgiLoader_v3 : public AgiLoader { 614 private: 615 AgiEngine *_vm; 616 617 int loadDir(AgiDir *agid, Common::File *fp, uint32 offs, uint32 len); 618 uint8 *loadVolRes(AgiDir *agid); 619 620 public: 621 AgiLoader_v3(AgiEngine * vm)622 AgiLoader_v3(AgiEngine *vm) { 623 _vm = vm; 624 } 625 626 int init() override; 627 int deinit() override; 628 int detectGame() override; 629 int loadResource(int16 resourceType, int16 resourceNr) override; 630 int unloadResource(int16 resourceType, int16 resourceNr) override; 631 int loadObjects(const char *) override; 632 int loadWords(const char *) override; 633 }; 634 635 class GfxFont; 636 class GfxMgr; 637 class SpritesMgr; 638 class InventoryMgr; 639 class TextMgr; 640 class GfxMenu; 641 class SystemUI; 642 class Words; 643 644 // Image stack support 645 struct ImageStackElement { 646 uint8 type; 647 uint8 pad; 648 int16 parm1; 649 int16 parm2; 650 int16 parm3; 651 int16 parm4; 652 int16 parm5; 653 int16 parm6; 654 int16 parm7; 655 }; 656 657 struct StringData { 658 int x; 659 int y; 660 int len; 661 int str; 662 }; 663 664 #define TICK_SECONDS 20 665 666 #define KEY_QUEUE_SIZE 16 667 668 class AgiBase : public ::Engine { 669 protected: 670 // Engine API 671 Common::Error init(); 672 virtual Common::Error go() = 0; run()673 Common::Error run() override { 674 Common::Error err; 675 err = init(); 676 if (err.getCode() != Common::kNoError) 677 return err; 678 return go(); 679 } 680 bool hasFeature(EngineFeature f) const override; 681 682 virtual void initialize() = 0; 683 684 void initRenderMode(); 685 686 public: 687 Words *_words; 688 689 GfxFont *_font; 690 GfxMgr *_gfx; 691 692 Common::RenderMode _renderMode; 693 AgiDebug _debug; 694 AgiGame _game; 695 Common::RandomSource *_rnd; 696 697 SoundMgr *_sound; 698 699 Mouse _mouse; 700 701 bool _noSaveLoadAllowed; 702 promptIsEnabled()703 virtual bool promptIsEnabled() { 704 return false; 705 } 706 707 virtual int getKeypress() = 0; 708 virtual bool isKeypress() = 0; 709 virtual void clearKeyQueue() = 0; 710 711 AgiBase(OSystem *syst, const AGIGameDescription *gameDesc); 712 ~AgiBase() override; 713 714 virtual void clearImageStack() = 0; 715 virtual void recordImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3, 716 int16 p4, int16 p5, int16 p6, int16 p7) = 0; 717 virtual void replayImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3, 718 int16 p4, int16 p5, int16 p6, int16 p7) = 0; 719 virtual void releaseImageStack() = 0; 720 721 int _soundemu; 722 723 bool getFlag(int16 flagNr); 724 void setFlag(int16 flagNr, bool newState); 725 void flipFlag(int16 flagNr); 726 727 const AGIGameDescription *_gameDescription; 728 729 uint32 _gameFeatures; 730 uint16 _gameVersion; 731 732 uint32 getGameID() const; 733 uint32 getFeatures() const; 734 uint16 getVersion() const; 735 uint16 getGameType() const; 736 Common::Language getLanguage() const; 737 bool isLanguageRTL() const; 738 Common::Platform getPlatform() const; 739 const char *getGameMD5() const; 740 void initFeatures(); 741 void setFeature(uint32 feature); 742 void initVersion(); 743 void setVersion(uint16 version); 744 745 const char *getDiskName(uint16 id); 746 747 bool canLoadGameStateCurrently() override; 748 bool canSaveGameStateCurrently() override; 749 750 const byte *getFontData(); 751 cycleInnerLoopActive(int16 loopType)752 void cycleInnerLoopActive(int16 loopType) { 753 _game.cycleInnerLoopActive = true; 754 _game.cycleInnerLoopType = loopType; 755 }; cycleInnerLoopInactive()756 void cycleInnerLoopInactive() { 757 _game.cycleInnerLoopActive = false; 758 }; cycleInnerLoopIsActive()759 bool cycleInnerLoopIsActive() { 760 return _game.cycleInnerLoopActive; 761 } 762 }; 763 764 enum AgiArtificialDelayTriggerType { 765 ARTIFICIALDELAYTYPE_NEWROOM = 0, 766 ARTIFICIALDELAYTYPE_NEWPICTURE = 1, 767 ARTIFICIALDELAYTYPE_END = -1 768 }; 769 770 struct AgiArtificialDelayEntry { 771 uint32 gameId; 772 Common::Platform platform; 773 AgiArtificialDelayTriggerType triggerType; 774 int16 orgNr; 775 int16 newNr; 776 uint16 millisecondsDelay; 777 }; 778 779 typedef void (*AgiOpCodeFunction)(AgiGame *state, AgiEngine *vm, uint8 *p); 780 781 struct AgiOpCodeEntry { 782 const char *name; 783 const char *parameters; 784 AgiOpCodeFunction functionPtr; 785 uint16 parameterSize; 786 }; 787 788 struct AgiOpCodeDefinitionEntry { 789 const char *name; 790 const char *parameters; 791 AgiOpCodeFunction functionPtr; 792 }; 793 794 class AgiEngine : public AgiBase { 795 protected: 796 // Engine APIs 797 Common::Error go() override; 798 799 void initialize() override; 800 801 public: 802 AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc); 803 ~AgiEngine() override; 804 805 bool promptIsEnabled() override; 806 807 Common::Error loadGameState(int slot) override; 808 Common::Error saveGameState(int slot, const Common::String &description, bool isAutosave = false) override; 809 810 private: 811 int _keyQueue[KEY_QUEUE_SIZE]; 812 int _keyQueueStart; 813 int _keyQueueEnd; 814 815 bool _allowSynthetic; 816 817 bool checkPriority(ScreenObjEntry *v); 818 bool checkCollision(ScreenObjEntry *v); 819 bool checkPosition(ScreenObjEntry *v); 820 821 int _firstSlot; 822 823 public: 824 Common::Array<AgiObject> _objects; // objects in the game 825 826 StringData _stringdata; 827 828 SavedGameSlotIdArray getSavegameSlotIds(); 829 bool getSavegameInformation(int16 slotId, Common::String &saveDescription, uint32 &saveDate, uint32 &saveTime, bool &saveIsValid); 830 831 int saveGame(const Common::String &fileName, const Common::String &descriptionString); 832 int loadGame(const Common::String &fileName, bool checkId = true); 833 bool saveGameDialog(); 834 bool saveGameAutomatic(); 835 bool loadGameDialog(); 836 bool loadGameAutomatic(); 837 int doSave(int slot, const Common::String &desc); 838 int doLoad(int slot, bool showMessages); 839 int scummVMSaveLoadDialog(bool isSave); 840 841 uint8 *_intobj; 842 bool _restartGame; 843 844 SpritesMgr *_sprites; 845 TextMgr *_text; 846 InventoryMgr *_inventory; 847 PictureMgr *_picture; 848 AgiLoader *_loader; // loader 849 GfxMenu *_menu; 850 SystemUI *_systemUI; 851 852 Common::Stack<ImageStackElement> _imageStack; 853 854 void clearImageStack() override; 855 void recordImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3, 856 int16 p4, int16 p5, int16 p6, int16 p7) override; 857 void replayImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3, 858 int16 p4, int16 p5, int16 p6, int16 p7) override; 859 void releaseImageStack() override; 860 861 void wait(uint32 msec, bool busy = false); 862 863 int agiInit(); 864 int agiDeinit(); 865 int agiDetectGame(); 866 int agiLoadResource(int16 resourceType, int16 resourceNr); 867 int agiUnloadResource(int16 resourceType, int16 resourceNr); 868 void agiUnloadResources(); 869 870 int getKeypress() override; 871 bool isKeypress() override; 872 void clearKeyQueue() override; 873 874 byte getVar(int16 varNr); 875 void setVar(int16 varNr, byte newValue); 876 877 private: 878 void applyVolumeToMixer(); 879 880 public: 881 void syncSoundSettings() override; 882 883 public: 884 void decrypt(uint8 *mem, int len); 885 void releaseSprites(); 886 uint16 processAGIEvents(); 887 int viewPictures(); 888 int runGame(); 889 int getAppDir(char *appDir, unsigned int size); 890 891 int setupV2Game(int ver); 892 int setupV3Game(int ver); 893 894 void newRoom(int16 newRoomNr); 895 void resetControllers(); 896 void interpretCycle(); 897 int playGame(); 898 899 void allowSynthetic(bool); 900 void processScummVMEvents(); 901 void checkQuickLoad(); 902 903 // Objects 904 public: 905 int showObjects(); 906 int loadObjects(const char *fname); 907 int loadObjects(Common::File &fp); 908 const char *objectName(uint16 objectNr); 909 int objectGetLocation(uint16 objectNr); 910 void objectSetLocation(uint16 objectNr, int); 911 private: 912 int decodeObjects(uint8 *mem, uint32 flen); 913 int readObjects(Common::File &fp, int flen); 914 915 // Logic 916 public: 917 int decodeLogic(int16 logicNr); 918 void unloadLogic(int16 logicNr); 919 int runLogic(int16 logicNr); 920 void debugConsole(int, int, const char *); 921 bool testIfCode(int16 logicNr); 922 void executeAgiCommand(uint8, uint8 *); 923 924 private: 925 bool _veryFirstInitialCycle; /**< signals, that currently the very first cycle is executed (restarts, etc. do not count!) */ 926 uint32 _instructionCounter; /**< counts every instruction, that got executed, can wrap around */ 927 928 bool _setVolumeBrokenFangame; 929 930 void resetGetVarSecondsHeuristic(); 931 void getVarSecondsHeuristicTrigger(); 932 uint32 _getVarSecondsHeuristicLastInstructionCounter; /**< last time VM_VAR_SECONDS were read */ 933 uint16 _getVarSecondsHeuristicCounter; /**< how many times heuristic was triggered */ 934 935 uint32 _playTimeInSecondsAdjust; /**< milliseconds to adjust for calculating current play time in seconds, see setVarSecondsTrigger() */ 936 937 void setVarSecondsTrigger(byte newSeconds); 938 939 public: 940 // Some submethods of testIfCode 941 void skipInstruction(byte op); 942 void skipInstructionsUntil(byte v); 943 uint8 testObjRight(uint8, uint8, uint8, uint8, uint8); 944 uint8 testObjCenter(uint8, uint8, uint8, uint8, uint8); 945 uint8 testObjInBox(uint8, uint8, uint8, uint8, uint8); 946 uint8 testPosn(uint8, uint8, uint8, uint8, uint8); 947 uint8 testSaid(uint8, uint8 *); 948 uint8 testController(uint8); 949 uint8 testCompareStrings(uint8, uint8); 950 951 // View 952 private: 953 954 void lSetLoop(ScreenObjEntry *screenObj, int16 loopNr); 955 void updateView(ScreenObjEntry *screenObj); 956 957 public: 958 void setView(ScreenObjEntry *screenObj, int16 viewNr); 959 void setLoop(ScreenObjEntry *screenObj, int16 loopNr); 960 void setCel(ScreenObjEntry *screenObj, int16 celNr); 961 962 void clipViewCoordinates(ScreenObjEntry *screenObj); 963 964 void startUpdate(ScreenObjEntry *); 965 void stopUpdate(ScreenObjEntry *); 966 void updateScreenObjTable(); 967 void unloadView(int16 viewNr); 968 int decodeView(byte *resourceData, uint16 resourceSize, int16 viewNr); 969 970 private: 971 void unpackViewCelData(AgiViewCel *celData, byte *compressedData, uint16 compressedSize); 972 void unpackViewCelDataAGI256(AgiViewCel *celData, byte *compressedData, uint16 compressedSize); 973 974 public: 975 void addToPic(int, int, int, int, int, int, int); 976 void drawObj(int); 977 bool isEgoView(const ScreenObjEntry *screenObj); 978 979 // Motion 980 private: 981 int checkStep(int delta, int step); 982 bool checkBlock(int16 x, int16 y); 983 void changePos(ScreenObjEntry *screenObj); 984 void motionWander(ScreenObjEntry *screenObj); 985 void motionFollowEgo(ScreenObjEntry *screenObj); 986 void motionMoveObj(ScreenObjEntry *screenObj); 987 void motionMoveObjStop(ScreenObjEntry *screenObj); 988 void checkMotion(ScreenObjEntry *screenObj); 989 990 public: 991 void motionActivated(ScreenObjEntry *screenObj); 992 void cyclerActivated(ScreenObjEntry *screenObj); 993 void checkAllMotions(); 994 void moveObj(ScreenObjEntry *screenObj); 995 void inDestination(ScreenObjEntry *screenObj); 996 void fixPosition(int16 screenObjNr); 997 void fixPosition(ScreenObjEntry *screenObj); 998 void updatePosition(); 999 int getDirection(int16 objX, int16 objY, int16 destX, int16 destY, int16 stepSize); 1000 1001 bool _keyHoldMode; 1002 Common::KeyCode _keyHoldModeLastKey; 1003 1004 // Keyboard 1005 int doPollKeyboard(); 1006 void cleanKeyboard(); 1007 1008 bool handleMouseClicks(uint16 &key); 1009 bool handleController(uint16 key); 1010 1011 bool showPredictiveDialog(); 1012 1013 uint16 agiGetKeypress(); 1014 int waitKey(); 1015 int waitAnyKey(); 1016 1017 void nonBlockingText_IsShown(); 1018 void nonBlockingText_Forget(); 1019 1020 void artificialDelay_Reset(); 1021 void artificialDelay_CycleDone(); 1022 1023 uint16 artificialDelay_SearchTable(AgiArtificialDelayTriggerType triggerType, int16 orgNr, int16 newNr); 1024 1025 void artificialDelayTrigger_NewRoom(int16 newRoomNr); 1026 void artificialDelayTrigger_DrawPicture(int16 newPictureNr); 1027 1028 private: 1029 int16 _artificialDelayCurrentRoom; 1030 int16 _artificialDelayCurrentPicture; 1031 1032 public: 1033 void redrawScreen(); 1034 1035 void inGameTimerReset(uint32 newPlayTime = 0); 1036 void inGameTimerResetPassedCycles(); 1037 uint32 inGameTimerGet(); 1038 uint32 inGameTimerGetPassedCycles(); 1039 1040 void inGameTimerUpdate(); 1041 1042 private: 1043 uint32 _lastUsedPlayTimeInCycles; // 40 per second 1044 uint32 _lastUsedPlayTimeInSeconds; // actual seconds 1045 uint32 _passedPlayTimeCycles; // increased by 1 every time we passed a cycle 1046 1047 private: 1048 AgiOpCodeEntry _opCodes[256]; // always keep those at 256, so that there is no way for invalid memory access 1049 AgiOpCodeEntry _opCodesCond[256]; 1050 1051 void setupOpCodes(uint16 version); 1052 1053 public: getOpCodesTable()1054 const AgiOpCodeEntry *getOpCodesTable() { return _opCodes; } 1055 }; 1056 1057 } // End of namespace Agi 1058 1059 #endif /* AGI_AGI_H */ 1060