/* 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 2 * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #ifndef AGI_H #define AGI_H #include "common/scummsys.h" #include "common/error.h" #include "common/util.h" #include "common/file.h" #include "common/rect.h" #include "common/rendermode.h" #include "common/stack.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" #include "gui/predictivedialog.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 { typedef signed int Err; // // Version and other definitions // #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_DIRS 256 #define MAX_VARS 256 #define MAX_FLAGS (256 >> 3) #define MAX_VIEWTABLE 255 // KQ3 uses o255! #define MAX_WORDS 20 #define MAX_STRINGS 24 // MAX_STRINGS + 1 used for get.num #define MAX_STRINGLEN 40 #define MAX_CONTROLLERS 39 #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 MSG_BOX_COLOR 0x0f // White #define MSG_BOX_TEXT 0x00 // Black #define MSG_BOX_LINE 0x04 // Red #define BUTTON_BORDER 0x00 // Black #define STATUS_FG 0x00 // Black #define STATUS_BG 0x0f // White #define ADD_PIC 1 #define ADD_VIEW 2 #define CMD_BSIZE 12 enum AgiGameID { GID_AGIDEMO, GID_BC, GID_DDP, GID_GOLDRUSH, GID_KQ1, GID_KQ2, GID_KQ3, GID_KQ4, GID_LSL1, GID_MH1, GID_MH2, 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 AgiGameType { GType_PreAGI = 0, GType_V1 = 1, GType_V2 = 2, GType_V3 = 3 }; enum BooterDisks { BooterDisk1 = 0, BooterDisk2 = 1 }; // // GF_OLDAMIGAV20 means that the interpreter is an old Amiga AGI interpreter that // uses value 20 for the computer type (v20 i.e. vComputer) rather than the usual value 5. // // GF_CLIPCOORDS means that views' coordinates must be clipped at least in commands // position and position.v. // enum AgiGameFeatures { GF_AGIMOUSE = (1 << 0), GF_AGDS = (1 << 1), GF_AGI256 = (1 << 2), GF_AGI256_2 = (1 << 3), GF_AGIPAL = (1 << 4), GF_MACGOLDRUSH = (1 << 5), GF_FANMADE = (1 << 6), GF_MENUS = (1 << 7), GF_ESCPAUSE = (1 << 8), GF_OLDAMIGAV20 = (1 << 9), GF_CLIPCOORDS = (1 << 10), GF_2GSOLDSOUND = (1 << 11) }; struct AGIGameDescription; enum { NO_GAMEDIR = 0, GAMEDIR }; enum AGIErrors { errOK = 0, errDoNothing, errBadCLISwitch, errInvalidAGIFile, errBadFileOpen, errNotEnoughMemory, errBadResource, errUnknownAGIVersion, errNoLoopsInView, errViewDataError, errNoGameList, errIOError, errUnk = 127 }; enum kDebugLevels { kDebugLevelMain = 1 << 0, kDebugLevelResources = 1 << 1, kDebugLevelSprites = 1 << 2, kDebugLevelInventory = 1 << 3, kDebugLevelInput = 1 << 4, kDebugLevelMenu = 1 << 5, kDebugLevelScripts = 1 << 6, kDebugLevelSound = 1 << 7, kDebugLevelText = 1 << 8, kDebugLevelSavegame = 1 << 9 }; /** * AGI resources. */ enum { rLOGIC = 1, rSOUND, rVIEW, rPICTURE }; enum { RES_LOADED = 1, RES_COMPRESSED = 0x40 }; enum { lCOMMAND_MODE = 1, lTEST_MODE }; struct gameIdList { gameIdList *next; uint32 version; uint32 crc; char *gName; char *switches; }; struct Mouse { int button; int x; int y; }; // 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 }; enum GameId { GID_AGI = 1 }; #define WIN_TO_PIC_X(x) ((x) / 2) #define WIN_TO_PIC_Y(y) ((y) < 8 ? 999 : (y) >= (8 + _HEIGHT) ? 999 : (y) - 8) /** * AGI variables. */ enum { vCurRoom = 0, // 0 vPrevRoom, vBorderTouchEgo, vScore, vBorderCode, vBorderTouchObj, // 5 vEgoDir, vMaxScore, vFreePages, vWordNotFound, vTimeDelay, // 10 vSeconds, vMinutes, vHours, vDays, vJoystickSensitivity, // 15 vEgoViewResource, vAgiErrCode, vAgiErrCodeInfo, vKey, vComputer, // 20 vWindowReset, vSoundgen, vVolume, vMaxInputChars, vSelItem, // 25 vMonitor }; /** * 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. * * At least these Amiga AGI versions use value 5: * 2.082 (King's Quest I v1.0U 1986) * 2.090 (King's Quest III v1.01 1986-11-08) * x.yyy (Black Cauldron v2.00 1987-06-14) * x.yyy (Larry I v1.05 1987-06-26) * 2.107 (King's Quest II v2.0J. Date is probably 1987-01-29) * 2.202 (Space Quest II v2.0F) * 2.310 (Police Quest I v2.0B 1989-02-22) * 2.316 (Gold Rush! v2.05 1989-03-09) * 2.333 (King's Quest III v2.15 1989-11-15) * * At least these Amiga AGI versions use value 20: * 2.082 (Space Quest I v1.2 1986) * x.yyy (Manhunter NY 1.06 3/18/89) * 2.333 (Manhunter SF 3.06 8/17/89) * */ enum AgiComputerType { kAgiComputerPC = 0, kAgiComputerAtariST = 4, kAgiComputerAmiga = 5, // Newer Amiga AGI interpreters' value (Commonly used) kAgiComputerApple2GS = 7, kAgiComputerAmigaOld = 20 // Older Amiga AGI interpreters' value (Seldom used) }; 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 { fEgoWater = 0, // 0 fEgoInvisible, fEnteredCli, fEgoTouchedP2, fSaidAcceptedInput, fNewRoomExec, // 5 fRestartGame, fScriptBlocked, fJoySensitivity, fSoundOn, fDebuggerOn, // 10 fLogicZeroFirsttime, fRestoreJustRan, fStatusSelectsItems, fMenusWork, fOutputMode, // 15 fAutoRestart }; enum AgiSlowliness { kPauseRoom = 1500, kPausePicture = 500 }; struct AgiController { uint16 keycode; uint8 controller; }; struct AgiObject { int location; char *name; }; struct AgiWord { int id; char *word; }; 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, cant be released // 3 = in mem, cant be released // 0x40 = was compressed uint8 flags; }; struct AgiBlock { int active; int x1, y1; int x2, y2; uint8 *buffer; // used for window background }; /** AGI text color (Background and foreground color). */ struct AgiTextColor { /** Creates an AGI text color. Uses black text on white background by default. */ AgiTextColor(int fgColor = 0x00, int bgColor = 0x0F) : fg(fgColor), bg(bgColor) {} /** Get an AGI text color with swapped foreground and background color. */ AgiTextColor swap() const { return AgiTextColor(bg, fg); } int fg; ///< Foreground color (Used for text). int bg; ///< Background color (Used for text's background). }; /** * AGI button style (Amiga or PC). * * Supports positive and negative button types (Used with Amiga-style only): * Positive buttons do what the dialog was opened for. * Negative buttons cancel what the dialog was opened for. * Restart-dialog example: Restart-button is positive, Cancel-button negative. * Paused-dialog example: Continue-button is positive. */ struct AgiButtonStyle { // Public constants etc public: static const int // Amiga colors (Indexes into the Amiga-ish palette) amigaBlack = 0x00, ///< Accurate, is #000000 (24-bit RGB) amigaWhite = 0x0F, ///< Practically accurate, is close to #FFFFFF (24-bit RGB) amigaGreen = 0x02, ///< Quite accurate, should be #008A00 (24-bit RGB) amigaOrange = 0x0C, ///< Inaccurate, too much blue, should be #FF7500 (24-bit RGB) amigaPurple = 0x0D, ///< Inaccurate, too much green, should be #FF00FF (24-bit RGB) amigaRed = 0x04, ///< Quite accurate, should be #BD0000 (24-bit RGB) amigaCyan = 0x0B, ///< Inaccurate, too much red, should be #00FFDE (24-bit RGB) // PC colors (Indexes into the EGA-palette) pcBlack = 0x00, pcWhite = 0x0F; // Public methods public: /** * Get the color of the button with the given state and type using current style. * * @param hasFocus True if button has focus, false otherwise. * @param pressed True if button is being pressed, false otherwise. * @param positive True if button is positive, false if button is negative. Only matters for Amiga-style buttons. */ AgiTextColor getColor(bool hasFocus, bool pressed, bool positive = true) const; /** * Get the color of a button with the given base color and state ignoring current style. * Swaps foreground and background color when the button has focus or is being pressed. * * @param hasFocus True if button has focus, false otherwise. * @param pressed True if button is being pressed, false otherwise. * @param baseFgColor Foreground color of the button when it has no focus and is not being pressed. * @param baseBgColor Background color of the button when it has no focus and is not being pressed. */ AgiTextColor getColor(bool hasFocus, bool pressed, int baseFgColor, int baseBgColor) const; /** * Get the color of a button with the given base color and state ignoring current style. * Swaps foreground and background color when the button has focus or is being pressed. * * @param hasFocus True if button has focus, false otherwise. * @param pressed True if button is being pressed, false otherwise. * @param baseColor Color of the button when it has no focus and is not being pressed. */ AgiTextColor getColor(bool hasFocus, bool pressed, const AgiTextColor &baseColor) const; /** * How many pixels to offset the shown text diagonally down and to the right. * Currently only used for pressed PC-style buttons. */ int getTextOffset(bool hasFocus, bool pressed) const; /** * Show border around the button? * Currently border is only used for in focus or pressed Amiga-style buttons * when in inauthentic Amiga-style mode. */ bool getBorder(bool hasFocus, bool pressed) const; /** * Set Amiga-button style. * * @param amigaStyle Set Amiga-button style if true, otherwise set PC-button style. * @param olderAgi If true then use older AGI style in Amiga-mode, otherwise use newer. * @param authenticAmiga If true then don't use a border around buttons in Amiga-mode, otherwise use. */ void setAmigaStyle(bool amigaStyle = true, bool olderAgi = false, bool authenticAmiga = false); /** * Set PC-button style. * @param pcStyle Set PC-button style if true, otherwise set default Amiga-button style. */ void setPcStyle(bool pcStyle = true); // Public constructors public: /** * Create a button style based on the given rendering mode. * @param renderMode If Common::kRenderAmiga then creates default Amiga-button style, otherwise PC-style. */ AgiButtonStyle(Common::RenderMode renderMode = Common::kRenderDefault); // Private member variables private: bool _amigaStyle; ///< Use Amiga-style buttons if true, otherwise use PC-style buttons. bool _olderAgi; ///< Use older AGI style in Amiga-style mode. bool _authenticAmiga; ///< Don't use border around buttons in Amiga-style mode. }; struct ScriptPos { int script; int curIP; }; enum { EGO_VIEW_TABLE = 0, HORIZON = 36, _WIDTH = 160, _HEIGHT = 168 }; enum InputMode { INPUT_NORMAL = 0x01, INPUT_GETSTRING = 0x02, INPUT_MENU = 0x03, INPUT_NONE = 0x04 }; enum State { STATE_INIT = 0x00, STATE_LOADED = 0x01, STATE_RUNNING = 0x02 }; enum { SBUF16_OFFSET = 0, SBUF256_OFFSET = ((_WIDTH) * (_HEIGHT)), FROM_SBUF16_TO_SBUF256_OFFSET = ((SBUF256_OFFSET) - (SBUF16_OFFSET)), FROM_SBUF256_TO_SBUF16_OFFSET = ((SBUF16_OFFSET) - (SBUF256_OFFSET)) }; /** * AGI game structure. * This structure contains all global data of an AGI game executed * by the interpreter. */ struct AgiGame { AgiEngine *_vm; State state; /**< state of the interpreter */ // 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 name[8]; /**< lead in id (e.g. `GR' for goldrush) */ char id[8]; /**< game id */ uint32 crc; /**< game CRC */ // game flags and variables uint8 flags[MAX_FLAGS]; /**< 256 1-bit flags */ uint8 vars[MAX_VARS]; /**< 256 variables */ // internal variables int horizon; /**< horizon y coordinate */ int lineStatus; /**< line number to put status on */ int lineUserInput; /**< line to put user input on */ int lineMinPrint; /**< num lines to print on */ int cursorPos; /**< column where the input cursor is */ byte inputBuffer[40]; /**< buffer for user input */ byte echoBuffer[40]; /**< buffer for echo.line */ int keypress; InputMode inputMode; /**< keyboard input mode */ bool inputEnabled; /**< keyboard input enabled */ int lognum; /**< current logic number */ Common::Array execStack; // internal flags int playerControl; /**< player is in control */ int statusLine; /**< status line on/off */ int clockEnabled; /**< clock is on/off */ int exitAllLogics; /**< break cycle after new.room */ int pictureShown; /**< show.pic has been issued */ int hasPrompt; /**< input prompt has been printed */ #define ID_AGDS 0x00000001 #define ID_AMIGA 0x00000002 int gameFlags; /**< agi options flags */ uint8 priTable[_HEIGHT];/**< priority table */ // windows uint32 msgBoxTicks; /**< timed message box tick counter */ AgiBlock block; AgiBlock window; int hasWindow; // graphics & text int gfxMode; char cursorChar; unsigned int colorFg; unsigned int colorBg; uint8 *sbufOrig; /**< Pointer to the 160x336 AGI screen buffer that contains vertically two 160x168 screens (16 color and 256 color). */ uint8 *sbuf16c; /**< 160x168 16 color (+control line & priority information) AGI screen buffer. Points at sbufOrig + SBUF16_OFFSET. */ uint8 *sbuf256c; /**< 160x168 256 color AGI screen buffer (For AGI256 and AGI256-2 support). Points at sbufOrig + SBUF256_OFFSET. */ uint8 *sbuf; /**< Currently chosen AGI screen buffer (sbuf256c if AGI256 or AGI256-2 is used, otherwise sbuf16c). */ // player command line AgiWord egoWords[MAX_WORDS]; int numEgoWords; unsigned int numObjects; bool controllerOccured[MAX_DIRS]; /**< keyboard keypress events */ AgiController controllers[MAX_CONTROLLERS]; char strings[MAX_STRINGS + 1][MAX_STRINGLEN]; /**< strings */ // directory entries for resources AgiDir dirLogic[MAX_DIRS]; AgiDir dirPic[MAX_DIRS]; AgiDir dirView[MAX_DIRS]; AgiDir dirSound[MAX_DIRS]; // resources AgiPicture pictures[MAX_DIRS]; /**< AGI picture resources */ AgiLogic logics[MAX_DIRS]; /**< AGI logic resources */ AgiView views[MAX_DIRS]; /**< AGI view resources */ AgiSound *sounds[MAX_DIRS]; /**< Pointers to AGI sound resources */ AgiLogic *_curLogic; // words Common::Array words[26]; // view table VtEntry viewTable[MAX_VIEWTABLE]; int32 ver; /**< detected game version */ int simpleSave; /**< select simple savegames */ Common::Rect mouseFence; /**< rectangle set by fence.mouse command */ // IF condition handling int testResult; int max_logics; int logic_list[256]; }; class AgiLoader { public: AgiLoader() {} virtual ~AgiLoader() {} virtual int init() = 0; virtual int deinit() = 0; virtual int detectGame() = 0; virtual int loadResource(int, int) = 0; virtual int unloadResource(int, int) = 0; virtual int loadObjects(const char *) = 0; virtual int loadWords(const char *) = 0; }; class AgiLoader_v1 : public AgiLoader { private: AgiEngine *_vm; Common::String _filenameDisk0; Common::String _filenameDisk1; int loadDir_DDP(AgiDir *agid, int offset, int max); int loadDir_BC(AgiDir *agid, int offset, int max); uint8 *loadVolRes(AgiDir *agid); public: AgiLoader_v1(AgiEngine *vm); virtual int init(); virtual int deinit(); virtual int detectGame(); virtual int loadResource(int, int); virtual int unloadResource(int, int); virtual int loadObjects(const char *); virtual int loadWords(const char *); }; class AgiLoader_v2 : public AgiLoader { private: AgiEngine *_vm; int loadDir(AgiDir *agid, const char *fname); uint8 *loadVolRes(AgiDir *agid); public: AgiLoader_v2(AgiEngine *vm) { _vm = vm; } virtual int init(); virtual int deinit(); virtual int detectGame(); virtual int loadResource(int, int); virtual int unloadResource(int, int); virtual int loadObjects(const char *); virtual int loadWords(const char *); }; class AgiLoader_v3 : public AgiLoader { private: AgiEngine *_vm; int loadDir(AgiDir *agid, Common::File *fp, uint32 offs, uint32 len); uint8 *loadVolRes(AgiDir *agid); public: AgiLoader_v3(AgiEngine *vm) { _vm = vm; } virtual int init(); virtual int deinit(); virtual int detectGame(); virtual int loadResource(int, int); virtual int unloadResource(int, int); virtual int loadObjects(const char *); virtual int loadWords(const char *); }; class GfxMgr; class SpritesMgr; class Menu; // Image stack support struct ImageStackElement { uint8 type; uint8 pad; int16 parm1; int16 parm2; int16 parm3; int16 parm4; int16 parm5; int16 parm6; int16 parm7; }; struct StringData { int x; int y; int len; int str; }; #define TICK_SECONDS 20 #define KEY_QUEUE_SIZE 16 class AgiBase : public ::Engine { protected: // Engine API Common::Error init(); virtual Common::Error go() = 0; virtual Common::Error run() { Common::Error err; err = init(); if (err.getCode() != Common::kNoError) return err; return go(); } virtual bool hasFeature(EngineFeature f) const; virtual void initialize() = 0; void initRenderMode(); public: GfxMgr *_gfx; AgiButtonStyle _defaultButtonStyle; AgiButtonStyle _buttonStyle; Common::RenderMode _renderMode; volatile uint32 _clockCount; AgiDebug _debug; AgiGame _game; Common::RandomSource *_rnd; SoundMgr *_sound; Mouse _mouse; bool _noSaveLoadAllowed; virtual void pollTimer() = 0; virtual int getKeypress() = 0; virtual bool isKeypress() = 0; virtual void clearKeyQueue() = 0; AgiBase(OSystem *syst, const AGIGameDescription *gameDesc); ~AgiBase(); 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; int getflag(int); void setflag(int, int); void flipflag(int); const AGIGameDescription *_gameDescription; uint32 _gameFeatures; uint16 _gameVersion; uint32 getGameID() const; uint32 getFeatures() const; uint16 getVersion() const; uint16 getGameType() const; Common::Language getLanguage() const; Common::Platform getPlatform() const; const char *getGameMD5() const; void initFeatures(); void setFeature(uint32 feature); void initVersion(); void setVersion(uint16 version); const char *getDiskName(uint16 id); bool canLoadGameStateCurrently(); bool canSaveGameStateCurrently(); }; typedef void (*AgiCommand)(AgiGame *state, uint8 *p); class AgiEngine : public AgiBase { protected: // Engine APIs virtual Common::Error go(); void initialize(); uint32 _lastSaveTime; public: AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc); virtual ~AgiEngine(); Common::Error loadGameState(int slot); Common::Error saveGameState(int slot, const Common::String &desc); private: uint32 _lastTick; int _keyQueue[KEY_QUEUE_SIZE]; int _keyQueueStart; int _keyQueueEnd; bool _allowSynthetic; int checkPriority(VtEntry *v); int checkCollision(VtEntry *v); int checkPosition(VtEntry *v); void parseFeatures(); int _firstSlot; public: AgiObject *_objects; // objects in the game StringData _stringdata; Common::String getSavegameFilename(int num) const; void getSavegameDescription(int num, char *buf, bool showEmpty = true); int selectSlot(); int saveGame(const Common::String &fileName, const Common::String &saveName); int loadGame(const Common::String &fileName, bool checkId = true); int saveGameDialog(); int saveGameSimple(); int loadGameDialog(); int loadGameSimple(); uint8 *_intobj; InputMode _oldMode; bool _restartGame; Menu* _menu; bool _menuSelected; char _lastSentence[40]; SpritesMgr *_sprites; PictureMgr *_picture; AgiLoader *_loader; // loader Common::Stack _imageStack; void clearImageStack(); void recordImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3, int16 p4, int16 p5, int16 p6, int16 p7); void replayImageStackCall(uint8 type, int16 p1, int16 p2, int16 p3, int16 p4, int16 p5, int16 p6, int16 p7); void releaseImageStack(); void pause(uint32 msec); Console *_console; GUI::Debugger *getDebugger() { return _console; } int agiInit(); int agiDeinit(); int agiDetectGame(); int agiLoadResource(int, int); int agiUnloadResource(int, int); void agiUnloadResources(); virtual void pollTimer(); virtual int getKeypress(); virtual bool isKeypress(); virtual void clearKeyQueue(); void initPriTable(); void newInputMode(InputMode mode); void oldInputMode(); int getvar(int); void setvar(int, int); void decrypt(uint8 *mem, int len); void releaseSprites(); int mainCycle(); int viewPictures(); int runGame(); void inventory(); void updateTimer(); int getAppDir(char *appDir, unsigned int size); int setupV2Game(int ver); int setupV3Game(int ver); void newRoom(int n); void resetControllers(); void interpretCycle(); int playGame(); void printItem(int n, int fg, int bg); int findItem(); int showItems(); void selectItems(int n); void allowSynthetic(bool); void processEvents(); void checkQuickLoad(); // Objects public: int showObjects(); int loadObjects(const char *fname); int loadObjects(Common::File &fp); void unloadObjects(); const char *objectName(unsigned int); int objectGetLocation(unsigned int); void objectSetLocation(unsigned int, int); private: int decodeObjects(uint8 *mem, uint32 flen); int readObjects(Common::File &fp, int flen); int allocObjects(int); // Logic public: int decodeLogic(int); void unloadLogic(int); int runLogic(int); void debugConsole(int, int, const char *); int testIfCode(int); void executeAgiCommand(uint8, uint8 *); public: // Some submethods of testIfCode void skipInstruction(byte op); void skipInstructionsUntil(byte v); uint8 testObjRight(uint8, uint8, uint8, uint8, uint8); uint8 testObjCenter(uint8, uint8, uint8, uint8, uint8); uint8 testObjInBox(uint8, uint8, uint8, uint8, uint8); uint8 testPosn(uint8, uint8, uint8, uint8, uint8); uint8 testSaid(uint8, uint8 *); uint8 testController(uint8); uint8 testKeypressed(); uint8 testCompareStrings(uint8, uint8); // View private: void lSetCel(VtEntry *v, int n); void lSetLoop(VtEntry *v, int n); void updateView(VtEntry *v); public: void setCel(VtEntry *, int); void clipViewCoordinates(VtEntry *v); void setLoop(VtEntry *, int); void setView(VtEntry *, int); void startUpdate(VtEntry *); void stopUpdate(VtEntry *); void updateViewtable(); void unloadView(int); int decodeView(int); void addToPic(int, int, int, int, int, int, int); void drawObj(int); bool isEgoView(const VtEntry *v); // Words public: int showWords(); int loadWords(const char *); int loadWords_v1(Common::File &f); void unloadWords(); int findWord(const char *word, int *flen); void dictionaryWords(char *); // Motion private: int checkStep(int delta, int step); int checkBlock(int x, int y); void changePos(VtEntry *v); void motionWander(VtEntry *v); void motionFollowEgo(VtEntry *v); void motionMoveObj(VtEntry *v); void checkMotion(VtEntry *v); public: void checkAllMotions(); void moveObj(VtEntry *); void inDestination(VtEntry *); void fixPosition(int); void updatePosition(); int getDirection(int x0, int y0, int x, int y, int s); bool _egoHoldKey; // Keyboard void initWords(); void cleanInput(); int doPollKeyboard(); void cleanKeyboard(); void handleKeys(int); void handleGetstring(int); int handleController(int); void getString(int, int, int, int); uint16 agiGetKeypress(); int waitKey(); int waitAnyKey(); // Text public: int messageBox(const char *); int selectionBox(const char *, const char **); void closeWindow(); void drawWindow(int, int, int, int); void printText(const char *, int, int, int, int, int, int, bool checkerboard = false); void printTextConsole(const char *, int, int, int, int, int); int print(const char *, int, int, int); char *wordWrapString(const char *, int *); char *agiSprintf(const char *); void writeStatus(); void writePrompt(); void clearPrompt(bool useBlackBg = false); void clearLines(int, int, int); void flushLines(int, int); private: void printStatus(const char *message, ...) GCC_PRINTF(2, 3); void printText2(int l, const char *msg, int foff, int xoff, int yoff, int len, int fg, int bg, bool checkerboard = false); void blitTextbox(const char *p, int y, int x, int len); void eraseTextbox(); void loadDict(); bool matchWord(); public: char _predictiveResult[40]; private: AgiCommand _agiCommands[183]; AgiCommand _agiCondCommands[256]; void setupOpcodes(); public: int _timerHack; // Workaround for timer loop in MH1 logic 153 }; } // End of namespace Agi #endif /* AGI_H */