mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-29 05:03:29 +00:00
2b59700d2a
svn-id: r34989
1000 lines
25 KiB
C++
1000 lines
25 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.
|
|
*
|
|
* $URL$
|
|
* $Id$
|
|
*
|
|
*/
|
|
|
|
#ifndef AGI_H
|
|
#define AGI_H
|
|
|
|
|
|
#include "common/scummsys.h"
|
|
#include "common/endian.h"
|
|
#include "common/util.h"
|
|
#include "common/file.h"
|
|
#include "common/savefile.h"
|
|
#include "common/system.h"
|
|
#include "common/hash-str.h"
|
|
#include "common/stack.h"
|
|
|
|
#include "engines/engine.h"
|
|
|
|
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
|
|
#ifndef MAX_PATH
|
|
#define MAX_PATH 260
|
|
#endif
|
|
|
|
#define _EMPTY 0xfffff
|
|
#define EGO_OWNED 0xff
|
|
|
|
#define CRYPT_KEY_SIERRA "Avis Durgan"
|
|
#define CRYPT_KEY_AGDS "Alex Simkin"
|
|
|
|
#ifndef INLINE
|
|
#define INLINE
|
|
#endif
|
|
|
|
#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
|
|
|
|
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,
|
|
GID_MICKEY, // PreAGI
|
|
GID_WINNIE, // PreAGI
|
|
GID_TROLL // PreAGI
|
|
};
|
|
|
|
} // End of namespace Agi
|
|
|
|
/* AGI resources */
|
|
#include "agi/console.h"
|
|
#include "agi/view.h"
|
|
#include "agi/picture.h"
|
|
#include "agi/logic.h"
|
|
#include "agi/sound.h"
|
|
|
|
namespace Agi {
|
|
|
|
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)
|
|
};
|
|
|
|
struct AGIGameDescription;
|
|
|
|
enum {
|
|
NO_GAMEDIR = 0,
|
|
GAMEDIR
|
|
};
|
|
|
|
enum AGIErrors {
|
|
errOK = 0,
|
|
errDoNothing,
|
|
errBadCLISwitch,
|
|
errInvalidAGIFile,
|
|
errBadFileOpen,
|
|
errNotEnoughMemory,
|
|
errBadResource,
|
|
errUnknownAGIVersion,
|
|
errRestartGame,
|
|
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;
|
|
unsigned int x;
|
|
unsigned 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.
|
|
*/
|
|
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)
|
|
*
|
|
* TODO: Check Amiga versions of Manhunter I & II (I'd guess they use value 5 though).
|
|
*/
|
|
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)
|
|
};
|
|
|
|
/**
|
|
* 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
|
|
};
|
|
|
|
struct AgiEvent {
|
|
uint16 data;
|
|
uint8 occured;
|
|
};
|
|
|
|
struct AgiObject {
|
|
int location;
|
|
char *name;
|
|
};
|
|
|
|
struct AgiWord {
|
|
int id;
|
|
char *word;
|
|
};
|
|
|
|
struct AgiDir {
|
|
uint8 volume;
|
|
uint32 offset;
|
|
uint32 len;
|
|
uint32 clen;
|
|
uint8 flags;
|
|
/* 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
|
|
*/
|
|
};
|
|
|
|
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.
|
|
};
|
|
|
|
#define EGO_VIEW_TABLE 0
|
|
#define HORIZON 36
|
|
#define _WIDTH 160
|
|
#define _HEIGHT 168
|
|
|
|
/**
|
|
* AGI game structure.
|
|
* This structure contains all global data of an AGI game executed
|
|
* by the interpreter.
|
|
*/
|
|
struct AgiGame {
|
|
#define STATE_INIT 0x00
|
|
#define STATE_LOADED 0x01
|
|
#define STATE_RUNNING 0x02
|
|
int 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 */
|
|
uint8 inputBuffer[40]; /**< buffer for user input */
|
|
uint8 echoBuffer[40]; /**< buffer for echo.line */
|
|
int keypress;
|
|
#define INPUT_NORMAL 0x01
|
|
#define INPUT_GETSTRING 0x02
|
|
#define INPUT_MENU 0x03
|
|
#define INPUT_NONE 0x04
|
|
int inputMode; /**< keyboard input mode */
|
|
int inputEnabled; /**< keyboard input enabled */
|
|
int lognum; /**< current logic number */
|
|
|
|
/* 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;
|
|
#define SBUF16_OFFSET 0
|
|
#define SBUF256_OFFSET ((_WIDTH) * (_HEIGHT))
|
|
#define FROM_SBUF16_TO_SBUF256_OFFSET ((SBUF256_OFFSET) - (SBUF16_OFFSET))
|
|
#define FROM_SBUF256_TO_SBUF16_OFFSET ((SBUF16_OFFSET) - (SBUF256_OFFSET))
|
|
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;
|
|
|
|
AgiEvent evKeyp[MAX_DIRS]; /**< keyboard keypress events */
|
|
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 */
|
|
};
|
|
|
|
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;
|
|
virtual int version() = 0;
|
|
virtual void setIntVersion(int) = 0;
|
|
virtual int getIntVersion() = 0;
|
|
};
|
|
|
|
class AgiLoader_v2 : public AgiLoader {
|
|
private:
|
|
int _intVersion;
|
|
AgiEngine *_vm;
|
|
|
|
int loadDir(AgiDir *agid, const char *fname);
|
|
uint8 *loadVolRes(AgiDir *agid);
|
|
|
|
public:
|
|
|
|
AgiLoader_v2(AgiEngine *vm) {
|
|
_vm = vm;
|
|
_intVersion = 0;
|
|
}
|
|
|
|
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 *);
|
|
virtual int version();
|
|
virtual void setIntVersion(int);
|
|
virtual int getIntVersion();
|
|
};
|
|
|
|
class AgiLoader_v3 : public AgiLoader {
|
|
private:
|
|
int _intVersion;
|
|
AgiEngine *_vm;
|
|
|
|
int loadDir(AgiDir *agid, Common::File *fp, uint32 offs, uint32 len);
|
|
uint8 *loadVolRes(AgiDir *agid);
|
|
|
|
public:
|
|
|
|
AgiLoader_v3(AgiEngine *vm) {
|
|
_vm = vm;
|
|
_intVersion = 0;
|
|
}
|
|
|
|
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 *);
|
|
virtual int version();
|
|
virtual void setIntVersion(int);
|
|
virtual int getIntVersion();
|
|
};
|
|
|
|
class GfxMgr;
|
|
class SpritesMgr;
|
|
class Menu;
|
|
class SearchTree;
|
|
|
|
extern struct Mouse g_mouse;
|
|
|
|
/* 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
|
|
virtual Common::Error init();
|
|
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;
|
|
|
|
virtual void agiTimerLow() = 0;
|
|
virtual int agiGetKeypressLow() = 0;
|
|
virtual int agiIsKeypressLow() = 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 getGameID() const;
|
|
uint32 getFeatures() const;
|
|
uint16 getVersion() const;
|
|
uint16 getGameType() const;
|
|
Common::Language getLanguage() const;
|
|
Common::Platform getPlatform() const;
|
|
Common::Error loadGameState(int slot);
|
|
Common::Error saveGameState(int slot, const char *desc);
|
|
bool canLoadGameStateCurrently();
|
|
bool canSaveGameStateCurrently();
|
|
};
|
|
|
|
class AgiEngine : public AgiBase {
|
|
int _gameId;
|
|
|
|
protected:
|
|
// Engine APIs
|
|
virtual Common::Error go();
|
|
virtual void syncSoundSettings();
|
|
|
|
void initialize();
|
|
|
|
uint32 _lastSaveTime;
|
|
|
|
public:
|
|
AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc);
|
|
virtual ~AgiEngine();
|
|
int getGameId() {
|
|
return _gameId;
|
|
}
|
|
|
|
|
|
private:
|
|
|
|
int _keyQueue[KEY_QUEUE_SIZE];
|
|
int _keyQueueStart;
|
|
int _keyQueueEnd;
|
|
|
|
bool _allowSynthetic;
|
|
|
|
int checkPriority(VtEntry *v);
|
|
int checkCollision(VtEntry *v);
|
|
int checkPosition(VtEntry *v);
|
|
|
|
uint32 matchVersion(uint32 crc);
|
|
|
|
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;
|
|
int _oldMode;
|
|
|
|
Menu* _menu;
|
|
|
|
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();
|
|
|
|
Console *_console;
|
|
|
|
int agiInit();
|
|
int agiDeinit();
|
|
int agiVersion();
|
|
int agiGetRelease();
|
|
void agiSetRelease(int);
|
|
int agiDetectGame();
|
|
int agiLoadResource(int, int);
|
|
int agiUnloadResource(int, int);
|
|
void agiUnloadResources();
|
|
|
|
virtual void agiTimerLow();
|
|
virtual int agiGetKeypressLow();
|
|
virtual int agiIsKeypressLow();
|
|
static void agiTimerFunctionLow(void *refCon);
|
|
void initPriTable();
|
|
|
|
void newInputMode(int);
|
|
void oldInputMode();
|
|
|
|
int getvar(int);
|
|
void setvar(int, int);
|
|
void decrypt(uint8 * mem, int len);
|
|
void releaseSprites();
|
|
int mainCycle();
|
|
int viewPictures();
|
|
int parseCli(int, char **);
|
|
int runGame();
|
|
void inventory();
|
|
void listGames();
|
|
uint32 matchCrc(uint32, char *, int);
|
|
int v2IdGame();
|
|
int v3IdGame();
|
|
int v4IdGame(uint32 ver);
|
|
void updateTimer();
|
|
int getAppDir(char *appDir, unsigned int size);
|
|
|
|
int setupV2Game(int ver, uint32 crc);
|
|
int setupV3Game(int ver, uint32 crc);
|
|
|
|
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 *);
|
|
|
|
// 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);
|
|
|
|
// 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);
|
|
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(char *, int *);
|
|
char *agiSprintf(const char *);
|
|
void writeStatus(void);
|
|
void writePrompt(void);
|
|
void clearLines(int, int, int);
|
|
void flushLines(int, int);
|
|
bool predictiveDialog(void);
|
|
|
|
private:
|
|
void printStatus(const char *message, ...);
|
|
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();
|
|
char *safeStrcat(char *s, const char *t);
|
|
void loadDict(void);
|
|
bool matchWord(void);
|
|
|
|
// 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];
|
|
};
|
|
|
|
} // End of namespace Agi
|
|
|
|
#endif /* AGI_H */
|