scummvm/engines/agi/agi.h
Jussi Pitkanen 3fd26de379 AGI: Detect the bootable floppy version of Donald Duck's Playground
Also create a framework into which more booter games can be added.
2011-08-13 23:26:22 +01:00

1265 lines
32 KiB
C++

/* 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/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: ???
*
* 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 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_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
};
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 {
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<ScriptPos> 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];
int lastController;
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 */
// 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 */
};
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 _dsk0Name;
Common::String _dsk1Name;
public:
AgiLoader_v1(AgiEngine *vm, Common::String dsk0, Common::String dsk1) {
_vm = vm;
_dsk0Name = dsk0;
_dsk1Name = dsk1;
}
virtual int init() { return 0; }
virtual int deinit() { return 0; }
virtual int detectGame() { return 0; }
virtual int loadResource(int, int) { return 0; }
virtual int unloadResource(int, int) { return 0; }
virtual int loadObjects(const char *) { return 0; }
virtual int loadWords(const char *) { return 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;
// 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;
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);
~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;
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 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;
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();
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 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
int showWords();
int loadWords(const char *);
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();
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;
Common::String _currentCode;
Common::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 */