Logo Search packages:      
Sourcecode: scummvm version File versions  Download package

agi.h

/* 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.
 *
 * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/tags/release-1-2-0/engines/agi/agi.h $
 * $Id: agi.h 52373 2010-08-25 07:41:14Z sev $
 *
 */

#ifndef AGI_H
#define AGI_H

#include "common/scummsys.h"
#include "common/endian.h"
#include "common/util.h"
#include "common/file.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"


namespace Common { class RandomSource; }

/**
 * This is the namespace of the AGI engine.
 *
 * Status of this engine: ???
 *
 * Supported games:
 * - ???
 */
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     CRYPT_KEY_SIERRA  "Avis Durgan"
#define CRYPT_KEY_AGDS        "Alex Simkin"

#define     MSG_BOX_COLOUR    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_SQ0,                      // Fanmade
      GID_MICKEY,             // PreAGI
      GID_WINNIE,             // PreAGI
      GID_TROLL                     // PreAGI
};

enum AgiGameType {
      GType_PreAGI = 0,
      GType_V2 = 1,
      GType_V3 = 2
};

//
// 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
};

#define report printf

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.
 */
00281 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)
 *
 */
00310 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). */
00389 struct AgiTextColor {
      /** Creates an AGI text color. Uses black text on white background by default. */
00391       AgiTextColor(int fgColor = 0x00, int bgColor = 0x0F) : fg(fgColor), bg(bgColor) {}

      /** Get an AGI text color with swapped foreground and background color. */
00394       AgiTextColor swap() const { return AgiTextColor(bg, fg); }

00396       int fg; ///< Foreground color (Used for text).
00397       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.
 */
00409 struct AgiButtonStyle {
// Public constants etc
public:
      static const int
            // Amiga colors (Indexes into the Amiga-ish palette)
00414             amigaBlack  = 0x00, ///< Accurate,                   is          #000000 (24-bit RGB)
00415             amigaWhite  = 0x0F, ///< Practically accurate,       is close to #FFFFFF (24-bit RGB)
00416             amigaGreen  = 0x02, ///< Quite accurate,             should be   #008A00 (24-bit RGB)
00417             amigaOrange = 0x0C, ///< Inaccurate, too much blue,  should be   #FF7500 (24-bit RGB)
00418             amigaPurple = 0x0D, ///< Inaccurate, too much green, should be   #FF00FF (24-bit RGB)
00419             amigaRed    = 0x04, ///< Quite accurate,             should be   #BD0000 (24-bit RGB)
00420             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:
00495       bool _amigaStyle;     ///< Use Amiga-style buttons if true, otherwise use PC-style buttons.
00496       bool _olderAgi;       ///< Use older AGI style in Amiga-style mode.
00497       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.
 */
00537 struct AgiGame {
00538       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.
00542       int adjMouseX;    /**< last given adj.ego.move.to.x.y-command's 1st parameter */
00543       int adjMouseY;    /**< last given adj.ego.move.to.x.y-command's 2nd parameter */

00545       char name[8];     /**< lead in id (e.g. `GR' for goldrush) */
00546       char id[8];       /**< game id */
00547       uint32 crc;       /**< game CRC */

      // game flags and variables
00550       uint8 flags[MAX_FLAGS]; /**< 256 1-bit flags */
00551       uint8 vars[MAX_VARS];   /**< 256 variables */

      // internal variables
00554       int horizon;                  /**< horizon y coordinate */
00555       int lineStatus;         /**< line number to put status on */
00556       int lineUserInput;      /**< line to put user input on */
00557       int lineMinPrint;       /**< num lines to print on */
00558       int cursorPos;                /**< column where the input cursor is */
00559       uint8 inputBuffer[40]; /**< buffer for user input */
00560       uint8 echoBuffer[40];   /**< buffer for echo.line */
      int keypress;

00563       InputMode inputMode;                /**< keyboard input mode */
00564       bool inputEnabled;            /**< keyboard input enabled */
00565       int lognum;                   /**< current logic number */
      Common::Array<ScriptPos> execStack;

      // internal flags
00569       int playerControl;            /**< player is in control */
00570       int statusLine;         /**< status line on/off */
00571       int clockEnabled;       /**< clock is on/off */
00572       int exitAllLogics;      /**< break cycle after new.room */
00573       int pictureShown;       /**< show.pic has been issued */
00574       int hasPrompt;                /**< input prompt has been printed */
#define ID_AGDS         0x00000001
#define ID_AMIGA  0x00000002
00577       int gameFlags;                /**< agi options flags */

00579       uint8 priTable[_HEIGHT];/**< priority table */

      // windows
00582       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;

00593       uint8 *sbufOrig;        /**< Pointer to the 160x336 AGI screen buffer that contains vertically two 160x168 screens (16 color and 256 color). */
00594       uint8 *sbuf16c;               /**< 160x168 16 color (+control line & priority information) AGI screen buffer. Points at sbufOrig + SBUF16_OFFSET. */
00595       uint8 *sbuf256c;        /**< 160x168 256 color AGI screen buffer (For AGI256 and AGI256-2 support). Points at sbufOrig + SBUF256_OFFSET. */
00596       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;

00604       bool controllerOccured[MAX_DIRS];  /**< keyboard keypress events */
      AgiController controllers[MAX_CONTROLLERS];
      int lastController;

00608       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
00617       AgiPicture pictures[MAX_DIRS];      /**< AGI picture resources */
00618       AgiLogic logics[MAX_DIRS];          /**< AGI logic resources */
00619       AgiView views[MAX_DIRS];            /**< AGI view resources */
00620       AgiSound *sounds[MAX_DIRS];         /**< Pointers to AGI sound resources */

      // view table
      VtEntry viewTable[MAX_VIEWTABLE];

00625       int32 ver;                                /**< detected game version */

00627       int simpleSave;                           /**< select simple savegames */

00629       Common::Rect mouseFence;            /**< rectangle set by fence.mouse command */
};

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_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;
class SearchTree;

// 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 != Common::kNoError)
                  return err;
            return go();
      }
      virtual bool hasFeature(EngineFeature f) const;

      virtual void initialize() = 0;

public:
      GfxMgr *_gfx;

      AgiButtonStyle _defaultButtonStyle;
      AgiButtonStyle _buttonStyle;
      Common::RenderMode _renderMode;
      volatile uint32 _clockCount;
      AgiDebug _debug;
      AgiGame _game;
      Common::RandomSource *_rnd;

      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);

      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;
      virtual     int saveGame(const char *fileName, const char *saveName) = 0;
      virtual int loadGame(const char *fileName, bool checkId = true) = 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);

      bool canLoadGameStateCurrently();
      bool canSaveGameStateCurrently();
};

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 char *desc);

private:

      uint32 _tickTimer;
      uint32 _lastTickTimer;

      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;

      const char *getSavegameFilename(int num);
      void getSavegameDescription(int num, char *buf, bool showEmpty = true);
      int selectSlot();
      int saveGame(const char *fileName, const char *saveName);
      int saveGameDialog();
      int saveGameSimple();
      int loadGame(const char *fileName, bool checkId = true);
      int loadGameDialog();
      int loadGameSimple();

      uint8 *_intobj;
      InputMode _oldMode;
      bool _restartGame;

      Menu* _menu;
      bool _menuSelected;

      char _lastSentence[40];

      SpritesMgr *_sprites;
      SoundMgr *_sound;
      PictureMgr *_picture;
      AgiLoader *_loader;     // loader

      Common::Stack<ImageStackElement> _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();

      static void agiTimerFunctionLow(void *refCon);
      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
      int showObjects();
      int decodeObjects(uint8 *mem, uint32 flen);
      int loadObjects(const char *fname);
      int allocObjects(int);
      void unloadObjects();
      const char *objectName(unsigned int);
      int objectGetLocation(unsigned int);
      void objectSetLocation(unsigned int, int);

      // Logic
      int decodeLogic(int);
      void unloadLogic(int);
      int runLogic(int);
      void debugConsole(int, int, const char *);
      int testIfCode(int);
      void executeAgiCommand(uint8, uint8 *);

private:
      // Some submethods of testIfCode
      uint8 testObjRight(uint8, uint8, uint8, uint8, uint8);
      uint8 testObjCentre(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
      int showWords();
      int loadWords(const char *);
      void unloadWords();
      int findWord(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:
      #define MAXWORDLEN 24

      typedef Common::String String;

      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();
      void clearLines(int, int, int);
      void flushLines(int, int);
      bool predictiveDialog();

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();

      // Predictive dialog
      // TODO: Move this to a separate class
      char *_predictiveDictText;
      char **_predictiveDictLine;
      int32 _predictiveDictLineCount;
      char *_predictiveDictActLine;
      String _currentCode;
      String _currentWord;
      int _wordNumber;
      bool _predictiveDialogRunning;
public:
      char _predictiveResult[40];

private:
      typedef void (AgiEngine::*AgiCommand)(uint8 *);

      AgiCommand _agiCommands[183];
      AgiLogic *_curLogic;
      int _timerHack;               // Workaround for timer loop in MH1 logic 153

      void setupOpcodes();

      void cmd_increment(uint8 *p);
      void cmd_decrement(uint8 *p);
      void cmd_assignn(uint8 *p);
      void cmd_assignv(uint8 *p);
      void cmd_addn(uint8 *p);
      void cmd_addv(uint8 *p);
      void cmd_subn(uint8 *p);
      void cmd_subv(uint8 *p);      // 0x08
      void cmd_lindirectv(uint8 *p);
      void cmd_rindirect(uint8 *p);
      void cmd_lindirectn(uint8 *p);
      void cmd_set(uint8 *p);
      void cmd_reset(uint8 *p);
      void cmd_toggle(uint8 *p);
      void cmd_set_v(uint8 *p);
      void cmd_reset_v(uint8 *p);   // 0x10
      void cmd_toggle_v(uint8 *p);
      void cmd_new_room(uint8 *p);
      void cmd_new_room_f(uint8 *p);
      void cmd_load_logic(uint8 *p);
      void cmd_load_logic_f(uint8 *p);
      void cmd_call(uint8 *p);
      void cmd_call_f(uint8 *p);
      void cmd_load_pic(uint8 *p);  // 0x18
      void cmd_draw_pic(uint8 *p);
      void cmd_show_pic(uint8 *p);
      void cmd_discard_pic(uint8 *p);
      void cmd_overlay_pic(uint8 *p);
      void cmd_show_pri_screen(uint8 *p);
      void cmd_load_view(uint8 *p);
      void cmd_load_view_f(uint8 *p);
      void cmd_discard_view(uint8 *p);    // 0x20
      void cmd_animate_obj(uint8 *p);
      void cmd_unanimate_all(uint8 *p);
      void cmd_draw(uint8 *p);
      void cmd_erase(uint8 *p);
      void cmd_position(uint8 *p);
      void cmd_position_f(uint8 *p);
      void cmd_get_posn(uint8 *p);
      void cmd_reposition(uint8 *p);      // 0x28
      void cmd_set_view(uint8 *p);
      void cmd_set_view_f(uint8 *p);
      void cmd_set_loop(uint8 *p);
      void cmd_set_loop_f(uint8 *p);
      void cmd_fix_loop(uint8 *p);
      void cmd_release_loop(uint8 *p);
      void cmd_set_cel(uint8 *p);
      void cmd_set_cel_f(uint8 *p); // 0x30
      void cmd_last_cel(uint8 *p);
      void cmd_current_cel(uint8 *p);
      void cmd_current_loop(uint8 *p);
      void cmd_current_view(uint8 *p);
      void cmd_number_of_loops(uint8 *p);
      void cmd_set_priority(uint8 *p);
      void cmd_set_priority_f(uint8 *p);
      void cmd_release_priority(uint8 *p);      // 0x38
      void cmd_get_priority(uint8 *p);
      void cmd_stop_update(uint8 *p);
      void cmd_start_update(uint8 *p);
      void cmd_force_update(uint8 *p);
      void cmd_ignore_horizon(uint8 *p);
      void cmd_observe_horizon(uint8 *p);
      void cmd_set_horizon(uint8 *p);
      void cmd_object_on_water(uint8 *p); // 0x40
      void cmd_object_on_land(uint8 *p);
      void cmd_object_on_anything(uint8 *p);
      void cmd_ignore_objs(uint8 *p);
      void cmd_observe_objs(uint8 *p);
      void cmd_distance(uint8 *p);
      void cmd_stop_cycling(uint8 *p);
      void cmd_start_cycling(uint8 *p);
      void cmd_normal_cycle(uint8 *p);    // 0x48
      void cmd_end_of_loop(uint8 *p);
      void cmd_reverse_cycle(uint8 *p);
      void cmd_reverse_loop(uint8 *p);
      void cmd_cycle_time(uint8 *p);
      void cmd_stop_motion(uint8 *p);
      void cmd_start_motion(uint8 *p);
      void cmd_step_size(uint8 *p);
      void cmd_step_time(uint8 *p); // 0x50
      void cmd_move_obj(uint8 *p);
      void cmd_move_obj_f(uint8 *p);
      void cmd_follow_ego(uint8 *p);
      void cmd_wander(uint8 *p);
      void cmd_normal_motion(uint8 *p);
      void cmd_set_dir(uint8 *p);
      void cmd_get_dir(uint8 *p);
      void cmd_ignore_blocks(uint8 *p);   // 0x58
      void cmd_observe_blocks(uint8 *p);
      void cmd_block(uint8 *p);
      void cmd_unblock(uint8 *p);
      void cmd_get(uint8 *p);
      void cmd_get_f(uint8 *p);
      void cmd_drop(uint8 *p);
      void cmd_put(uint8 *p);
      void cmd_put_f(uint8 *p);     // 0x60
      void cmd_get_room_f(uint8 *p);
      void cmd_load_sound(uint8 *p);
      void cmd_sound(uint8 *p);
      void cmd_stop_sound(uint8 *p);
      void cmd_print(uint8 *p);
      void cmd_print_f(uint8 *p);
      void cmd_display(uint8 *p);
      void cmd_display_f(uint8 *p); // 0x68
      void cmd_clear_lines(uint8 *p);
      void cmd_text_screen(uint8 *p);
      void cmd_graphics(uint8 *p);
      void cmd_set_cursor_char(uint8 *p);
      void cmd_set_text_attribute(uint8 *p);
      void cmd_shake_screen(uint8 *p);
      void cmd_configure_screen(uint8 *p);
      void cmd_status_line_on(uint8 *p);  // 0x70
      void cmd_status_line_off(uint8 *p);
      void cmd_set_string(uint8 *p);
      void cmd_get_string(uint8 *p);
      void cmd_word_to_string(uint8 *p);
      void cmd_parse(uint8 *p);
      void cmd_get_num(uint8 *p);
      void cmd_prevent_input(uint8 *p);
      void cmd_accept_input(uint8 *p);    // 0x78
      void cmd_set_key(uint8 *p);
      void cmd_add_to_pic(uint8 *p);
      void cmd_add_to_pic_f(uint8 *p);
      void cmd_status(uint8 *p);
      void cmd_save_game(uint8 *p);
      void cmd_load_game(uint8 *p);
      void cmd_init_disk(uint8 *p);
      void cmd_restart_game(uint8 *p);    // 0x80
      void cmd_show_obj(uint8 *p);
      void cmd_random(uint8 *p);
      void cmd_program_control(uint8 *p);
      void cmd_player_control(uint8 *p);
      void cmd_obj_status_f(uint8 *p);
      void cmd_quit(uint8 *p);
      void cmd_show_mem(uint8 *p);
      void cmd_pause(uint8 *p);     // 0x88
      void cmd_echo_line(uint8 *p);
      void cmd_cancel_line(uint8 *p);
      void cmd_init_joy(uint8 *p);
      void cmd_toggle_monitor(uint8 *p);
      void cmd_version(uint8 *p);
      void cmd_script_size(uint8 *p);
      void cmd_set_game_id(uint8 *p);
      void cmd_log(uint8 *p); // 0x90
      void cmd_set_scan_start(uint8 *p);
      void cmd_reset_scan_start(uint8 *p);
      void cmd_reposition_to(uint8 *p);
      void cmd_reposition_to_f(uint8 *p);
      void cmd_trace_on(uint8 *p);
      void cmd_trace_info(uint8 *p);
      void cmd_print_at(uint8 *p);
      void cmd_print_at_v(uint8 *p);      // 0x98
      //void cmd_discard_view(uint8 *p);  // Opcode repeated from 0x20 ?
      void cmd_clear_text_rect(uint8 *p);
      void cmd_set_upper_left(uint8 *p);
      void cmd_set_menu(uint8 *p);
      void cmd_set_menu_item(uint8 *p);
      void cmd_submit_menu(uint8 *p);
      void cmd_enable_item(uint8 *p);
      void cmd_disable_item(uint8 *p);    // 0xa0
      void cmd_menu_input(uint8 *p);
      void cmd_show_obj_v(uint8 *p);
      void cmd_open_dialogue(uint8 *p);
      void cmd_close_dialogue(uint8 *p);
      void cmd_mul_n(uint8 *p);
      void cmd_mul_v(uint8 *p);
      void cmd_div_n(uint8 *p);
      void cmd_div_v(uint8 *p);     // 0xa8
      void cmd_close_window(uint8 *p);
      void cmd_set_simple(uint8 *p);
      void cmd_push_script(uint8 *p);
      void cmd_pop_script(uint8 *p);
      void cmd_hold_key(uint8 *p);
      void cmd_set_pri_base(uint8 *p);
      void cmd_discard_sound(uint8 *p);
      void cmd_hide_mouse(uint8 *p);      // 0xb0
      void cmd_allow_menu(uint8 *p);
      void cmd_show_mouse(uint8 *p);
      void cmd_fence_mouse(uint8 *p);
      void cmd_mouse_posn(uint8 *p);
      void cmd_release_key(uint8 *p);
      void cmd_adj_ego_move_to_x_y(uint8 *p);
};

} // End of namespace Agi

#endif /* AGI_H */

Generated by  Doxygen 1.6.0   Back to index