/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #ifndef AGI_AGI_H #define AGI_AGI_H #include "common/scummsys.h" #include "common/error.h" #include "common/util.h" #include "common/file.h" #include "common/keyboard.h" #include "common/rect.h" #include "common/rendermode.h" #include "common/stack.h" #include "common/str.h" #include "common/system.h" #include "engines/engine.h" #include "gui/debugger.h" // AGI resources #include "agi/console.h" #include "agi/view.h" #include "agi/picture.h" #include "agi/logic.h" #include "agi/sound.h" namespace Common { class RandomSource; } /** * This is the namespace of the AGI engine. * * Status of this engine: ??? * * Games using this engine: * - Early Sierra adventure games * - many fan made games * - Mickey's Space Adventure (Pre-AGI) * - Winnie the Pooh in the Hundred Acre Wood (Pre-AGI) * - Troll's Tale (Pre-AGI) */ namespace Agi { #define TITLE "AGI engine" #define DIR_ "dir" #define LOGDIR "logdir" #define PICDIR "picdir" #define VIEWDIR "viewdir" #define SNDDIR "snddir" #define OBJECTS "object" #define WORDS "words.tok" #define MAX_DIRECTORY_ENTRIES 256 #define MAX_CONTROLLERS 256 #define MAX_VARS 256 #define MAX_FLAGS (256 >> 3) #define SCREENOBJECTS_MAX 255 // KQ3 uses o255! #define SCREENOBJECTS_EGO_ENTRY 0 // first entry is ego #define MAX_WORDS 20 #define MAX_STRINGS 24 // MAX_STRINGS + 1 used for get.num #define MAX_STRINGLEN 40 #define MAX_CONTROLLER_KEYMAPPINGS 39 #define SAVEDGAME_DESCRIPTION_LEN 30 #define _EMPTY 0xfffff #define EGO_OWNED 0xff #define EGO_OWNED_V1 0xf9 #define CRYPT_KEY_SIERRA "Avis Durgan" #define CRYPT_KEY_AGDS "Alex Simkin" #define ADD_PIC 1 #define ADD_VIEW 2 #define CMD_BSIZE 12 enum AgiGameType { GType_PreAGI = 0, GType_V1 = 1, GType_V2 = 2, GType_V3 = 3, GType_A2 = 4, GType_GAL = 5 }; enum AgiGameFeatures { GF_AGIMOUSE = (1 << 0), // marks games created with AGIMOUSE, disables "Click-to-walk mouse interface" GF_AGDS = (1 << 1), // marks games created with AGDS - all using AGI version 2.440 GF_AGI256 = (1 << 2), // marks fanmade AGI-256 games GF_FANMADE = (1 << 3), // marks fanmade games GF_2GSOLDSOUND = (1 << 5), GF_EXTCHAR = (1 << 6) // use WORDS.TOK.EXTENDED }; enum AgiGameID { GID_AGIDEMO, GID_BC, GID_DDP, GID_GOLDRUSH, // V3 GID_KQ1, GID_KQ2, GID_KQ3, GID_KQ4, GID_LSL1, GID_MH1, // V3 GID_MH2, // V3 GID_MIXEDUP, GID_PQ1, GID_SQ1, GID_SQ2, GID_XMASCARD, GID_FANMADE, GID_GETOUTTASQ, // Fanmade GID_MICKEY, // PreAGI GID_WINNIE, // PreAGI GID_TROLL // PreAGI }; enum AGIErrors { errOK = 0, errFilesNotFound, errBadFileOpen, errNotEnoughMemory, errBadResource, errIOError, errUnk = 127 }; enum kDebugLevels { kDebugLevelMain = 1, kDebugLevelResources, kDebugLevelSprites, kDebugLevelPictures, kDebugLevelInventory, kDebugLevelInput, kDebugLevelMenu, kDebugLevelScripts, kDebugLevelSound, kDebugLevelText, kDebugLevelSavegame, }; /** * AGI resources. */ enum { RESOURCETYPE_LOGIC = 1, RESOURCETYPE_SOUND, RESOURCETYPE_VIEW, RESOURCETYPE_PICTURE }; enum { RES_LOADED = 0x01, RES_COMPRESSED = 0x40, RES_PICTURE_V3_NIBBLE_PARM = 0x80 // Flag that gets set for picture resources, // which use a nibble instead of a byte as F0+F2 parameters }; enum { lCOMMAND_MODE = 1, lTEST_MODE }; struct gameIdList { gameIdList *next; uint32 version; uint32 crc; char *gName; char *switches; }; struct Mouse { int button; Common::Point pos; Mouse() : button(0) {} }; // Used by AGI Mouse protocol 1.0 for v27 (i.e. button pressed -variable). enum AgiMouseButton { kAgiMouseButtonUp, // Mouse button is up (not pressed) kAgiMouseButtonLeft, // Left mouse button kAgiMouseButtonRight, // Right mouse button kAgiMouseButtonMiddle // Middle mouse button }; /** * AGI variables. */ enum { VM_VAR_CURRENT_ROOM = 0, // 0 VM_VAR_PREVIOUS_ROOM, // 1 VM_VAR_BORDER_TOUCH_EGO, // 2 VM_VAR_SCORE, // 3 VM_VAR_BORDER_CODE, // 4 VM_VAR_BORDER_TOUCH_OBJECT, // 5 VM_VAR_EGO_DIRECTION, // 6 VM_VAR_MAX_SCORE, // 7 VM_VAR_FREE_PAGES, // 8 VM_VAR_WORD_NOT_FOUND, // 9 VM_VAR_TIME_DELAY, // 10 VM_VAR_SECONDS, // 11 VM_VAR_MINUTES, // 12 VM_VAR_HOURS, // 13 VM_VAR_DAYS, // 14 VM_VAR_JOYSTICK_SENSITIVITY, // 15 VM_VAR_EGO_VIEW_RESOURCE, // 16 VM_VAR_AGI_ERROR_CODE, // 17 VM_VAR_AGI_ERROR_INFO, // 18 VM_VAR_KEY, // 19 VM_VAR_COMPUTER, // 20 VM_VAR_WINDOW_AUTO_CLOSE_TIMER, // 21 VM_VAR_SOUNDGENERATOR, // 22 VM_VAR_VOLUME, // 23 VM_VAR_MAX_INPUT_CHARACTERS, // 24 VM_VAR_SELECTED_INVENTORY_ITEM, // 25 VM_VAR_MONITOR = 26, // 26 VM_VAR_MOUSE_BUTTONSTATE = 27, // 27 VM_VAR_MOUSE_X = 28, // 28 VM_VAR_MOUSE_Y = 29 // 29 }; /** * Different monitor types. * Used with AGI variable 26 i.e. vMonitor. */ enum AgiMonitorType { kAgiMonitorCga = 0, //kAgiMonitorTandy = 1, // Not sure about this kAgiMonitorHercules = 2, kAgiMonitorEga = 3 //kAgiMonitorVga = 4 // Not sure about this }; /** * Different computer types. * Used with AGI variable 20 i.e. vComputer. */ enum AgiComputerType { kAgiComputerPC = 0, kAgiComputerApple2 = 3, kAgiComputerAtariST = 4, kAgiComputerAmiga = 5, kAgiComputerApple2GS = 7 }; enum AgiSoundType { kAgiSoundPC = 1, kAgiSoundTandy = 3, // Tandy (This value is also used by the Amiga AGI and Apple IIGS AGI) kAgiSound2GSOld = 8 // Apple IIGS's Gold Rush! (Version 1.0M 1989-02-28 (CE), AGI 3.003) uses value 8 }; /** * AGI flags */ enum { VM_FLAG_EGO_WATER = 0, // 0 VM_FLAG_EGO_INVISIBLE, VM_FLAG_ENTERED_CLI, VM_FLAG_EGO_TOUCHED_P2, VM_FLAG_SAID_ACCEPTED_INPUT, VM_FLAG_NEW_ROOM_EXEC, // 5 VM_FLAG_RESTART_GAME, VM_FLAG_SCRIPT_BLOCKED, VM_FLAG_JOY_SENSITIVITY, VM_FLAG_SOUND_ON, VM_FLAG_DEBUGGER_ON, // 10 VM_FLAG_LOGIC_ZERO_FIRST_TIME, VM_FLAG_RESTORE_JUST_RAN, VM_FLAG_STATUS_SELECTS_ITEMS, VM_FLAG_MENUS_ACCESSIBLE, VM_FLAG_OUTPUT_MODE, // 15 VM_FLAG_AUTO_RESTART }; struct AgiControllerKeyMapping { uint16 keycode; byte controllerSlot; AgiControllerKeyMapping() : keycode(0), controllerSlot(0) {} }; struct AgiObject { int location; Common::String name; }; struct AgiDir { uint8 volume; uint32 offset; uint32 len; uint32 clen; // 0 = not in mem, can be freed // 1 = in mem, can be released // 2 = not in mem, can't be released // 3 = in mem, can't be released // 0x40 = was compressed uint8 flags; void reset() { volume = 0xff; offset = _EMPTY; len = 0; clen = 0; flags = 0; } AgiDir() { reset(); } }; struct AgiBlock { bool active; int16 x1, y1; int16 x2, y2; AgiBlock() : active(false), x1(0), y1(0), x2(0), y2(0) {} }; struct ScriptPos { int script; int curIP; }; enum CycleInnerLoopType { CYCLE_INNERLOOP_GETSTRING = 0, CYCLE_INNERLOOP_GETNUMBER, CYCLE_INNERLOOP_INVENTORY, CYCLE_INNERLOOP_MENU_VIA_KEYBOARD, CYCLE_INNERLOOP_MENU_VIA_MOUSE, CYCLE_INNERLOOP_SYSTEMUI_SELECTSAVEDGAMESLOT, CYCLE_INNERLOOP_SYSTEMUI_VERIFICATION, CYCLE_INNERLOOP_MESSAGEBOX, CYCLE_INNERLOOP_HAVEKEY }; typedef Common::Array SavedGameSlotIdArray; struct AgiAppleIIgsDelayOverwriteGameEntry; /** * AGI game structure. * This structure contains all global data of an AGI game executed * by the interpreter. */ struct AgiGame { AgiEngine *_vm; // TODO: Check whether adjMouseX and adjMouseY must be saved and loaded when using savegames. // If they must be then loading and saving is partially broken at the moment. int adjMouseX; /**< last given adj.ego.move.to.x.y-command's 1st parameter */ int adjMouseY; /**< last given adj.ego.move.to.x.y-command's 2nd parameter */ char id[8]; /**< game id */ uint32 crc; /**< game CRC */ // game flags and variables uint8 flags[MAX_FLAGS]; /**< 256 1-bit flags combined into a total of 32 bytes */ uint8 vars[MAX_VARS]; /**< 256 variables */ // internal variables int16 horizon; /**< horizon y coordinate */ bool cycleInnerLoopActive; int16 cycleInnerLoopType; int16 curLogicNr; /**< current logic number */ Common::Array execStack; // internal flags bool playerControl; /**< player is in control */ bool exitAllLogics; /**< break cycle after new.room */ bool pictureShown; /**< show.pic has been issued */ // windows AgiBlock block; // graphics & text bool gfxMode; unsigned int numObjects; bool controllerOccurred[MAX_CONTROLLERS]; /**< keyboard keypress events */ AgiControllerKeyMapping controllerKeyMapping[MAX_CONTROLLER_KEYMAPPINGS]; char strings[MAX_STRINGS + 1][MAX_STRINGLEN]; /**< strings */ // directory entries for resources AgiDir dirLogic[MAX_DIRECTORY_ENTRIES]; AgiDir dirPic[MAX_DIRECTORY_ENTRIES]; AgiDir dirView[MAX_DIRECTORY_ENTRIES]; AgiDir dirSound[MAX_DIRECTORY_ENTRIES]; // resources AgiPicture pictures[MAX_DIRECTORY_ENTRIES]; /**< AGI picture resources */ AgiLogic logics[MAX_DIRECTORY_ENTRIES]; /**< AGI logic resources */ AgiView views[MAX_DIRECTORY_ENTRIES]; /**< AGI view resources */ AgiSound *sounds[MAX_DIRECTORY_ENTRIES]; /**< Pointers to AGI sound resources */ AgiLogic *_curLogic; // view table ScreenObjEntry screenObjTable[SCREENOBJECTS_MAX]; ScreenObjEntry addToPicView; bool automaticSave; /**< set by CmdSetSimple() */ char automaticSaveDescription[SAVEDGAME_DESCRIPTION_LEN + 1]; Common::Rect mouseFence; /**< rectangle set by fence.mouse command */ bool mouseEnabled; /**< if mouse is supposed to be active */ bool mouseHidden; /**< if mouse is currently hidden */ bool predictiveDlgOnMouseClick; /**< if predictive dialog is enabled for mouse clicks */ // IF condition handling bool testResult; int max_logics; int logic_list[256]; // used to detect situations, where the game shows some text and changes rooms right afterwards // for example Space Quest 2 intro right at the start // or Space Quest 2, when entering the vent also right at the start // The developers assumed that loading the new room would take a bit. // In ScummVM it's basically done in an instant, which means that // the text would only get shown for a split second. // We delay a bit as soon as such situations get detected. bool nonBlockingTextShown; int16 nonBlockingTextCyclesLeft; bool automaticRestoreGame; byte speedLevel; /**< Current game speed for certain platforms/versions */ uint16 appleIIgsSpeedControllerSlot; const char *getString(int number); void setString(int number, const char *str); /** * Sets the speed level and displays a message box. */ void setSpeedLevel(byte s); AgiGame() { _vm = nullptr; adjMouseX = 0; adjMouseY = 0; memset(id, 0, sizeof(id)); crc = 0; memset(flags, 0, sizeof(flags)); memset(vars, 0, sizeof(vars)); horizon = 0; cycleInnerLoopActive = false; cycleInnerLoopType = 0; curLogicNr = 0; // execStack is defaulted by Common::Array constructor playerControl = false; exitAllLogics = false; pictureShown = false; // block defaulted by AgiBlock constructor gfxMode = false; numObjects = 0; memset(controllerOccurred, 0, sizeof(controllerOccurred)); // controllerKeyMapping defaulted by AgiControllerKeyMapping constructor memset(strings, 0, sizeof(strings)); // dirLogic cleared by AgiDir constructor // dirPic cleared by AgiDir constructor // dirView cleared by AgiDir constructor // dirSound cleared by AgiDir constructor // pictures cleared by AgiPicture constructor // logics cleared by AgiLogic constructor // views cleared by AgiView constructor memset(sounds, 0, sizeof(sounds)); _curLogic = nullptr; // screenObjTable cleared by ScreenObjEntry constructor // addToPicView cleared by ScreenObjEntry constructor automaticSave = false; memset(automaticSaveDescription, 0, sizeof(automaticSaveDescription)); // mouseFence cleared by Common::Rect constructor mouseEnabled = false; mouseHidden = false; predictiveDlgOnMouseClick = false; testResult = false; max_logics = 0; memset(logic_list, 0, sizeof(logic_list)); nonBlockingTextShown = false; nonBlockingTextCyclesLeft = 0; automaticRestoreGame = false; speedLevel = 2; // normal speed appleIIgsSpeedControllerSlot = 0xffff; // we didn't add yet speed menu } }; class AgiLoader; class GfxFont; class GfxMgr; class SpritesMgr; class InventoryMgr; class TextMgr; class GfxMenu; class SystemUI; class Words; struct AGIGameDescription; // Image stack support struct ImageStackElement { uint8 type; uint8 pad; int16 parm1; int16 parm2; int16 parm3; int16 parm4; int16 parm5; int16 parm6; int16 parm7; }; #define TICK_SECONDS 20 #define KEY_QUEUE_SIZE 16 class AgiBase : public ::Engine { protected: // Engine API Common::Error init(); virtual Common::Error go() = 0; Common::Error run() override { Common::Error err; err = init(); if (err.getCode() != Common::kNoError) return err; return go(); } bool hasFeature(EngineFeature f) const override; virtual void initialize() = 0; void initRenderMode(); public: Words *_words; GfxFont *_font; GfxMgr *_gfx; Common::RenderMode _renderMode; AgiDebug _debug; AgiGame _game; Common::RandomSource *_rnd; SoundMgr *_sound; Mouse _mouse; bool _noSaveLoadAllowed; virtual bool promptIsEnabled() { return false; } virtual int getKeypress() = 0; virtual bool isKeypress() = 0; virtual void clearKeyQueue() = 0; AgiBase(OSystem *syst, const AGIGameDescription *gameDesc); ~AgiBase() override; virtual void clearImageStack() = 0; virtual void recordImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3, int16 p4, int16 p5, int16 p6, int16 p7) = 0; virtual void replayImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3, int16 p4, int16 p5, int16 p6, int16 p7) = 0; virtual void releaseImageStack() = 0; int _soundemu; bool getFlag(int16 flagNr); void setFlag(int16 flagNr, bool newState); void flipFlag(int16 flagNr); /** Sets a flag in AGIv2+, sets a variable in AGIv1 */ void setFlagOrVar(int16 flagNr, bool newState); const AGIGameDescription *_gameDescription; uint32 _gameFeatures; uint16 _gameVersion; uint32 getGameID() const; uint32 getFeatures() const; uint16 getVersion() const; uint16 getGameType() const; Common::Language getLanguage() const; bool isLanguageRTL() const; Common::Platform getPlatform() const; const char *getGameMD5() const; void initFeatures(); void initVersion(); const char *getDiskName(uint16 id); bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override; bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override; const byte *getFontData(); void cycleInnerLoopActive(int16 loopType) { _game.cycleInnerLoopActive = true; _game.cycleInnerLoopType = loopType; }; void cycleInnerLoopInactive() { _game.cycleInnerLoopActive = false; }; bool cycleInnerLoopIsActive() { return _game.cycleInnerLoopActive; } }; enum AgiArtificialDelayTriggerType { ARTIFICIALDELAYTYPE_NEWROOM = 0, ARTIFICIALDELAYTYPE_NEWPICTURE = 1, ARTIFICIALDELAYTYPE_END = -1 }; struct AgiArtificialDelayEntry { uint32 gameId; Common::Platform platform; AgiArtificialDelayTriggerType triggerType; int16 orgNr; int16 newNr; uint16 millisecondsDelay; }; typedef void (*AgiOpCodeFunction)(AgiGame *state, AgiEngine *vm, uint8 *p); struct AgiOpCodeEntry { const char *name; const char *parameters; AgiOpCodeFunction functionPtr; uint16 parameterSize; }; struct AgiOpCodeDefinitionEntry { const char *name; const char *parameters; AgiOpCodeFunction functionPtr; }; class AgiEngine : public AgiBase { protected: // Engine APIs Common::Error go() override; void initialize() override; public: AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc); ~AgiEngine() override; bool promptIsEnabled() override; Common::Error loadGameState(int slot) override; Common::Error saveGameState(int slot, const Common::String &description, bool isAutosave = false) override; private: int _keyQueue[KEY_QUEUE_SIZE]; int _keyQueueStart; int _keyQueueEnd; bool _allowSynthetic; bool checkPriority(ScreenObjEntry *v); bool checkCollision(ScreenObjEntry *v); bool checkPosition(ScreenObjEntry *v); int _firstSlot; public: Common::Array _objects; // objects in the game SavedGameSlotIdArray getSavegameSlotIds(); bool getSavegameInformation(int16 slotId, Common::String &saveDescription, uint32 &saveDate, uint32 &saveTime, bool &saveIsValid); int saveGame(const Common::String &fileName, const Common::String &descriptionString); int loadGame(const Common::String &fileName, bool checkId = true); bool saveGameDialog(); bool saveGameAutomatic(); bool loadGameDialog(); bool loadGameAutomatic(); int doSave(int slot, const Common::String &desc); int doLoad(int slot, bool showMessages); int scummVMSaveLoadDialog(bool isSave); uint8 *_intobj; bool _restartGame; SpritesMgr *_sprites; TextMgr *_text; InventoryMgr *_inventory; PictureMgr *_picture; AgiLoader *_loader; GfxMenu *_menu; SystemUI *_systemUI; Common::DumpFile *_logFile; // File used for the log() agi command. Common::Stack _imageStack; void clearImageStack() override; void recordImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3, int16 p4, int16 p5, int16 p6, int16 p7) override; void replayImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3, int16 p4, int16 p5, int16 p6, int16 p7) override; void releaseImageStack() override; void wait(uint32 msec, bool busy = false); int agiInit(); void agiDeinit(); int loadResource(int16 resourceType, int16 resourceNr); void unloadResource(int16 resourceType, int16 resourceNr); /** * Unload all resources except Logic 0 */ void unloadResources(); int getKeypress() override; bool isKeypress() override; void clearKeyQueue() override; byte getVar(int16 varNr); void setVar(int16 varNr, byte newValue); private: void applyVolumeToMixer(); public: void syncSoundSettings() override; public: void decrypt(uint8 *mem, int len); uint16 processAGIEvents(); int runGame(); void newRoom(int16 newRoomNr); void resetControllers(); void interpretCycle(); void playGame(); void allowSynthetic(bool); void processScummVMEvents(); void checkQuickLoad(); const Common::String getTargetName() const { return _targetName; } private: byte getAppleIIgsTimeDelay(const AgiAppleIIgsDelayOverwriteGameEntry *appleIIgsDelayOverwrite, byte &newTimeDelay) const; // Objects public: int loadObjects(const char *fname); int loadObjects(Common::SeekableReadStream &fp, int flen); const char *objectName(uint16 objectNr); int objectGetLocation(uint16 objectNr); void objectSetLocation(uint16 objectNr, int location); private: int decodeObjects(uint8 *mem, uint32 flen); // Logic public: int decodeLogic(int16 logicNr); void unloadLogic(int16 logicNr); int runLogic(int16 logicNr); void debugConsole(int lognum, int mode, const char *str); bool testIfCode(int16 logicNr); void executeAgiCommand(uint8 op, uint8 *p); private: bool _veryFirstInitialCycle; /**< signals, that currently the very first cycle is executed (restarts, etc. do not count!) */ uint32 _instructionCounter; /**< counts every instruction, that got executed, can wrap around */ bool _setVolumeBrokenFangame; void resetGetVarSecondsHeuristic(); void getVarSecondsHeuristicTrigger(); uint32 _getVarSecondsHeuristicLastInstructionCounter; /**< last time VM_VAR_SECONDS were read */ uint16 _getVarSecondsHeuristicCounter; /**< how many times heuristic was triggered */ uint32 _playTimeInSecondsAdjust; /**< milliseconds to adjust for calculating current play time in seconds, see setVarSecondsTrigger() */ void setVarSecondsTrigger(byte newSeconds); public: // Some submethods of testIfCode void skipInstruction(byte op); void skipInstructionsUntil(byte v); bool testObjRight(uint8 n, uint8 x1, uint8 y1, uint8 x2, uint8 y2); bool testObjCenter(uint8 n, uint8 x1, uint8 y1, uint8 x2, uint8 y2); bool testObjInBox(uint8 n, uint8 x1, uint8 y1, uint8 x2, uint8 y2); bool testPosn(uint8 n, uint8 x1, uint8 y1, uint8 x2, uint8 y2); bool testSaid(uint8 nwords, uint8 *cc); bool testController(uint8 cont); bool testCompareStrings(uint8 s1, uint8 s2); // Picture private: void unloadPicture(int16 picNr); // View private: void updateView(ScreenObjEntry *screenObj); public: void setView(ScreenObjEntry *screenObj, int16 viewNr); void setLoop(ScreenObjEntry *screenObj, int16 loopNr); void setCel(ScreenObjEntry *screenObj, int16 celNr); void clipViewCoordinates(ScreenObjEntry *screenObj); void startUpdate(ScreenObjEntry *viewPtr); void stopUpdate(ScreenObjEntry *viewPtr); void updateScreenObjTable(); void unloadView(int16 viewNr); int decodeView(byte *resourceData, uint16 resourceSize, int16 viewNr); private: void unpackViewCelData(AgiViewCel *celData, byte *compressedData, uint16 compressedSize, int16 viewNr); void unpackViewCelDataAGI256(AgiViewCel *celData, byte *compressedData, uint16 compressedSize, int16 viewNr); public: bool isEgoView(const ScreenObjEntry *screenObj); // Motion private: int checkStep(int delta, int step); bool checkBlock(int16 x, int16 y); void changePos(ScreenObjEntry *screenObj); void motionWander(ScreenObjEntry *screenObj); void motionFollowEgo(ScreenObjEntry *screenObj); void motionMoveObj(ScreenObjEntry *screenObj); void motionMoveObjStop(ScreenObjEntry *screenObj); void checkMotion(ScreenObjEntry *screenObj); public: void motionActivated(ScreenObjEntry *screenObj); void cyclerActivated(ScreenObjEntry *screenObj); void checkAllMotions(); void moveObj(ScreenObjEntry *screenObj); void inDestination(ScreenObjEntry *screenObj); void fixPosition(int16 screenObjNr); void fixPosition(ScreenObjEntry *screenObj); void updatePosition(); int getDirection(int16 objX, int16 objY, int16 destX, int16 destY, int16 stepSize); byte egoNearWater(byte limit); int16 nearWater(ScreenObjEntry &screenObj, byte direction, int16 x, int16 y, byte limit); bool _keyHoldMode; Common::KeyCode _keyHoldModeLastKey; // Keyboard int doPollKeyboard(); bool handleMouseClicks(uint16 &key); bool handleController(uint16 key); bool showPredictiveDialog(); int waitKey(); int waitAnyKey(); void waitAnyKeyOrFinishedSound(); void nonBlockingText_IsShown(); void nonBlockingText_Forget(); void artificialDelay_Reset(); void artificialDelay_CycleDone(); uint16 artificialDelay_SearchTable(AgiArtificialDelayTriggerType triggerType, int16 orgNr, int16 newNr); void artificialDelayTrigger_NewRoom(int16 newRoomNr); void artificialDelayTrigger_DrawPicture(int16 newPictureNr); private: int16 _artificialDelayCurrentRoom; int16 _artificialDelayCurrentPicture; public: void redrawScreen(); void inGameTimerReset(uint32 newPlayTime = 0); void inGameTimerResetPassedCycles(); uint32 inGameTimerGet(); uint32 inGameTimerGetPassedCycles(); void inGameTimerUpdate(); private: uint32 _lastUsedPlayTimeInCycles; // 40 per second uint32 _lastUsedPlayTimeInSeconds; // actual seconds uint32 _passedPlayTimeCycles; // increased by 1 every time we passed a cycle private: AgiOpCodeEntry _opCodes[256]; // always keep those at 256, so that there is no way for invalid memory access AgiOpCodeEntry _opCodesCond[256]; void setupOpCodes(uint16 version); public: const AgiOpCodeEntry *getOpCodesTable() { return _opCodes; } private: void goldRushClockTimeWorkaround_OnReadVar(); void goldRushClockTimeWorkaround_OnWriteVar(byte oldValue); }; } // End of namespace Agi #endif /* AGI_AGI_H */