aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWalter van Niftrik2016-03-18 00:30:51 +0100
committerWalter van Niftrik2016-06-06 20:35:49 +0200
commit64cf93198fc560d31cc24003d164f656751d2e76 (patch)
treeb7f61e9f4d4531ab58bc31e04e13a5b1ff2b63f9
parentc0b33afc4a41e3c00dfafa6e1262ce17ed68c15c (diff)
downloadscummvm-rg350-64cf93198fc560d31cc24003d164f656751d2e76.tar.gz
scummvm-rg350-64cf93198fc560d31cc24003d164f656751d2e76.tar.bz2
scummvm-rg350-64cf93198fc560d31cc24003d164f656751d2e76.zip
ADL: Use functors to implement opcodes
-rw-r--r--engines/adl/adl.cpp461
-rw-r--r--engines/adl/adl.h55
2 files changed, 342 insertions, 174 deletions
diff --git a/engines/adl/adl.cpp b/engines/adl/adl.cpp
index bd1cc84f42..ad5f559fe0 100644
--- a/engines/adl/adl.cpp
+++ b/engines/adl/adl.cpp
@@ -278,6 +278,71 @@ void AdlEngine::checkInput(byte verb, byte noun) {
printMessage(_messageIds.dontUnderstand);
}
+typedef Common::Functor1Mem<ScriptEnv &, bool, AdlEngine> OpcodeV1;
+#define SetOpcodeTable(x) table = &x;
+#define Opcode(x) table->push_back(new OpcodeV1(this, &AdlEngine::x))
+#define OpcodeUnImpl() table->push_back(new OpcodeV1(this, 0))
+
+void AdlEngine::setupOpcodeTables() {
+ Common::Array<const Opcode *> *table = 0;
+
+ SetOpcodeTable(_condOpcodes);
+ // 0x00
+ OpcodeUnImpl();
+ OpcodeUnImpl();
+ OpcodeUnImpl();
+ Opcode(o1_isItemInRoom);
+ // 0x04
+ OpcodeUnImpl();
+ Opcode(o1_isMovesGrEq);
+ Opcode(o1_isVarEq);
+ OpcodeUnImpl();
+ // 0x08
+ OpcodeUnImpl();
+ Opcode(o1_isCurPicEq);
+ Opcode(o1_isItemPicEq);
+
+ SetOpcodeTable(_actOpcodes);
+ // 0x00
+ OpcodeUnImpl();
+ Opcode(o1_varAdd);
+ Opcode(o1_varSub);
+ Opcode(o1_varSet);
+ // 0x04
+ Opcode(o1_listInv);
+ Opcode(o1_moveItem);
+ Opcode(o1_setRoom);
+ Opcode(o1_setCurPic);
+ // 0x08
+ Opcode(o1_setPic);
+ Opcode(o1_printMsg);
+ Opcode(o1_setLight);
+ Opcode(o1_setDark);
+ // 0x0c
+ OpcodeUnImpl();
+ Opcode(o1_quit);
+ OpcodeUnImpl();
+ Opcode(o1_save);
+ // 0x10
+ Opcode(o1_restore);
+ Opcode(o1_restart);
+ Opcode(o1_placeItem);
+ Opcode(o1_setItemPic);
+ // 0x14
+ Opcode(o1_resetPic);
+ Opcode(o1_goDirection);
+ Opcode(o1_goDirection);
+ Opcode(o1_goDirection);
+ // 0x18
+ Opcode(o1_goDirection);
+ Opcode(o1_goDirection);
+ Opcode(o1_goDirection);
+ Opcode(o1_takeItem);
+ // 0x1c
+ Opcode(o1_dropItem);
+ Opcode(o1_setRoomPic);
+}
+
void AdlEngine::clearScreen() const {
_display->setMode(DISPLAY_MODE_MIXED);
_display->clear(0x00);
@@ -416,6 +481,8 @@ Common::Error AdlEngine::run() {
_speaker = new Speaker();
_display = new Display();
+ setupOpcodeTables();
+
init();
int saveSlot = ConfMan.getInt("save_slot");
@@ -657,8 +724,9 @@ bool AdlEngine::canSaveGameStateCurrently() {
// "SAVE GAME". This prevents saving via the GMM in situations where
// it wouldn't otherwise be possible to do so.
for (cmd = _roomCommands.begin(); cmd != _roomCommands.end(); ++cmd) {
+ ScriptEnv env(*cmd, _saveVerb, _saveNoun);
uint offset;
- if (matchCommand(*cmd, _saveVerb, _saveNoun, &offset))
+ if (matchCommand(env, &offset))
return cmd->script[offset] == IDO_ACT_SAVE;
}
@@ -784,198 +852,249 @@ void AdlEngine::getInput(uint &verb, uint &noun) {
}
}
-#define ARG(N) (command.script[offset + (N)])
+typedef Common::Functor1Mem<ScriptEnv &, bool, AdlEngine> OpcodeV1;
-bool AdlEngine::matchCommand(const Command &command, byte verb, byte noun, uint *actions) const {
- if (command.room != IDI_NONE && command.room != _state.room)
+#define ARG(N) (env.cmd.script[env.ip + (N)])
+
+bool AdlEngine::o1_isItemInRoom(ScriptEnv &env) {
+ if (getItem(ARG(1)).room != ARG(2))
return false;
+ env.ip += 3;
+ return true;
+}
- if (command.verb != IDI_NONE && command.verb != verb)
+bool AdlEngine::o1_isMovesGrEq(ScriptEnv &env) {
+ if (ARG(1) > _state.moves)
return false;
+ env.ip += 2;
+ return true;
+}
- if (command.noun != IDI_NONE && command.noun != noun)
+bool AdlEngine::o1_isVarEq(ScriptEnv &env) {
+ if (getVar(ARG(1)) != ARG(2))
return false;
+ env.ip += 3;
+ return true;
+}
- uint offset = 0;
- for (uint i = 0; i < command.numCond; ++i) {
- switch (ARG(0)) {
- case IDO_CND_ITEM_IN_ROOM:
- if (getItem(ARG(1)).room != ARG(2))
- return false;
- offset += 3;
- break;
- case IDO_CND_MOVES_GE:
- if (ARG(1) > _state.moves)
- return false;
- offset += 2;
- break;
- case IDO_CND_VAR_EQ:
- if (getVar(ARG(1)) != ARG(2))
- return false;
- offset += 3;
- break;
- case IDO_CND_CUR_PIC_EQ:
- if (getCurRoom().curPicture != ARG(1))
- return false;
- offset += 2;
- break;
- case IDO_CND_ITEM_PIC_EQ:
- if (getItem(ARG(1)).picture != ARG(2))
- return false;
- offset += 3;
- break;
- default:
- error("Invalid condition opcode %02x", command.script[offset]);
- }
+bool AdlEngine::o1_isCurPicEq(ScriptEnv &env) {
+ if (getCurRoom().curPicture != ARG(1))
+ return false;
+ env.ip += 2;
+ return true;
+}
+
+bool AdlEngine::o1_isItemPicEq(ScriptEnv &env) {
+ if (getItem(ARG(1)).picture != ARG(2))
+ return false;
+ env.ip += 3;
+ return true;
+}
+
+bool AdlEngine::o1_varAdd(ScriptEnv &env) {
+ setVar(ARG(2), getVar(ARG(2) + ARG(1)));
+ env.ip += 3;
+ return true;
+}
+
+bool AdlEngine::o1_varSub(ScriptEnv &env) {
+ setVar(ARG(2), getVar(ARG(2)) - ARG(1));
+ env.ip += 3;
+ return true;
+}
+
+bool AdlEngine::o1_varSet(ScriptEnv &env) {
+ setVar(ARG(1), ARG(2));
+ env.ip += 3;
+ return true;
+}
+
+bool AdlEngine::o1_listInv(ScriptEnv &env) {
+ Common::Array<Item>::const_iterator item;
+
+ for (item = _state.items.begin(); item != _state.items.end(); ++item)
+ if (item->room == IDI_NONE)
+ printMessage(item->description);
+
+ ++env.ip;
+ return true;
+}
+
+bool AdlEngine::o1_moveItem(ScriptEnv &env) {
+ getItem(ARG(1)).room = ARG(2);
+ env.ip += 3;
+ return true;
+}
+
+bool AdlEngine::o1_setRoom(ScriptEnv &env) {
+ getCurRoom().curPicture = getCurRoom().picture;
+ _state.room = ARG(1);
+ env.ip += 2;
+ return true;
+}
+
+bool AdlEngine::o1_setCurPic(ScriptEnv &env) {
+ getCurRoom().curPicture = ARG(1);
+ env.ip += 2;
+ return true;
+}
+
+bool AdlEngine::o1_setPic(ScriptEnv &env) {
+ getCurRoom().picture = getCurRoom().curPicture = ARG(1);
+ env.ip += 2;
+ return true;
+}
+
+bool AdlEngine::o1_printMsg(ScriptEnv &env) {
+ printMessage(ARG(1));
+ env.ip += 2;
+ return true;
+}
+
+bool AdlEngine::o1_setLight(ScriptEnv &env) {
+ _state.isDark = false;
+ ++env.ip;
+ return true;
+}
+
+bool AdlEngine::o1_setDark(ScriptEnv &env) {
+ _state.isDark = true;
+ ++env.ip;
+ return true;
+}
+
+bool AdlEngine::o1_save(ScriptEnv &env) {
+ saveGameState(0, "");
+ ++env.ip;
+ return true;
+}
+
+bool AdlEngine::o1_restore(ScriptEnv &env) {
+ loadGameState(0);
+ ++env.ip;
+ _isRestoring = false;
+ return true;
+}
+
+bool AdlEngine::o1_restart(ScriptEnv &env) {
+ _display->printString(_strings.playAgain);
+ Common::String input = inputString();
+
+ if (input.size() == 0 || input[0] != APPLECHAR('N')) {
+ _isRestarting = true;
+ _display->clear(0x00);
+ _display->updateHiResScreen();
+ restartGame();
+ return false;
}
- if (actions)
- *actions = offset;
+ return o1_quit(env);
+}
+
+bool AdlEngine::o1_quit(ScriptEnv &env) {
+ printMessage(_messageIds.thanksForPlaying);
+ quitGame();
+ return false;
+}
+bool AdlEngine::o1_placeItem(ScriptEnv &env) {
+ getItem(ARG(1)).room = ARG(2);
+ getItem(ARG(1)).position.x = ARG(3);
+ getItem(ARG(1)).position.y = ARG(4);
+ env.ip += 5;
return true;
}
-void AdlEngine::doActions(const Command &command, byte noun, byte offset) {
- for (uint i = 0; i < command.numAct; ++i) {
- switch (ARG(0)) {
- case IDO_ACT_VAR_ADD:
- setVar(ARG(2), getVar(ARG(2) + ARG(1)));
- offset += 3;
- break;
- case IDO_ACT_VAR_SUB:
- setVar(ARG(2), getVar(ARG(2)) - ARG(1));
- offset += 3;
- break;
- case IDO_ACT_VAR_SET:
- setVar(ARG(1), ARG(2));
- offset += 3;
- break;
- case IDO_ACT_LIST_ITEMS: {
- Common::Array<Item>::const_iterator item;
+bool AdlEngine::o1_setItemPic(ScriptEnv &env) {
+ getItem(ARG(2)).picture = ARG(1);
+ env.ip += 3;
+ return true;
+}
- for (item = _state.items.begin(); item != _state.items.end(); ++item)
- if (item->room == IDI_NONE)
- printMessage(item->description);
+bool AdlEngine::o1_resetPic(ScriptEnv &env) {
+ getCurRoom().curPicture = getCurRoom().picture;
+ ++env.ip;
+ return true;
+}
- ++offset;
- break;
- }
- case IDO_ACT_MOVE_ITEM:
- getItem(ARG(1)).room = ARG(2);
- offset += 3;
- break;
- case IDO_ACT_SET_ROOM:
- getCurRoom().curPicture = getCurRoom().picture;
- _state.room = ARG(1);
- offset += 2;
- break;
- case IDO_ACT_SET_CUR_PIC:
- getCurRoom().curPicture = ARG(1);
- offset += 2;
- break;
- case IDO_ACT_SET_PIC:
- getCurRoom().picture = getCurRoom().curPicture = ARG(1);
- offset += 2;
- break;
- case IDO_ACT_PRINT_MSG:
- printMessage(ARG(1));
- offset += 2;
- break;
- case IDO_ACT_SET_LIGHT:
- _state.isDark = false;
- ++offset;
- break;
- case IDO_ACT_SET_DARK:
- _state.isDark = true;
- ++offset;
- break;
- case IDO_ACT_SAVE:
- saveGameState(0, "");
- ++offset;
- break;
- case IDO_ACT_LOAD:
- loadGameState(0);
- ++offset;
- // Original engine does not jump out of the loop,
- // so we don't either.
- // We reset the restore flag, as the restore game
- // process is complete
- _isRestoring = false;
- break;
- case IDO_ACT_RESTART: {
- _display->printString(_strings.playAgain);
- Common::String input = inputString();
- if (input.size() == 0 || input[0] != APPLECHAR('N')) {
- _isRestarting = true;
- _display->clear(0x00);
- _display->updateHiResScreen();
- restartGame();
- return;
- }
- // Fall-through
- }
- case IDO_ACT_QUIT:
- printMessage(_messageIds.thanksForPlaying);
- quitGame();
- return;
- case IDO_ACT_PLACE_ITEM:
- getItem(ARG(1)).room = ARG(2);
- getItem(ARG(1)).position.x = ARG(3);
- getItem(ARG(1)).position.y = ARG(4);
- offset += 5;
- break;
- case IDO_ACT_SET_ITEM_PIC:
- getItem(ARG(2)).picture = ARG(1);
- offset += 3;
- break;
- case IDO_ACT_RESET_PIC:
- getCurRoom().curPicture = getCurRoom().picture;
- ++offset;
- break;
- case IDO_ACT_GO_NORTH:
- case IDO_ACT_GO_SOUTH:
- case IDO_ACT_GO_EAST:
- case IDO_ACT_GO_WEST:
- case IDO_ACT_GO_UP:
- case IDO_ACT_GO_DOWN: {
- byte room = getCurRoom().connections[ARG(0) - IDO_ACT_GO_NORTH];
-
- if (room == 0) {
- printMessage(_messageIds.cantGoThere);
- return;
- }
+bool AdlEngine::o1_goDirection(ScriptEnv &env) {
+ byte room = getCurRoom().connections[ARG(0) - IDO_ACT_GO_NORTH];
- getCurRoom().curPicture = getCurRoom().picture;
- _state.room = room;
- return;
- }
- case IDO_ACT_TAKE_ITEM:
- takeItem(noun);
- ++offset;
- break;
- case IDO_ACT_DROP_ITEM:
- dropItem(noun);
- ++offset;
- break;
- case IDO_ACT_SET_ROOM_PIC:
- getRoom(ARG(1)).picture = getRoom(ARG(1)).curPicture = ARG(2);
- offset += 3;
- break;
- default:
- error("Invalid action opcode %02x", ARG(0));
- }
+ if (room == 0) {
+ printMessage(_messageIds.cantGoThere);
+ return false;
}
+
+ getCurRoom().curPicture = getCurRoom().picture;
+ _state.room = room;
+ return false;
+}
+
+bool AdlEngine::o1_takeItem(ScriptEnv &env) {
+ takeItem(env.noun);
+ ++env.ip;
+ return true;
+}
+
+bool AdlEngine::o1_dropItem(ScriptEnv &env) {
+ dropItem(env.noun);
+ ++env.ip;
+ return true;
+}
+
+bool AdlEngine::o1_setRoomPic(ScriptEnv &env) {
+ getRoom(ARG(1)).picture = getRoom(ARG(1)).curPicture = ARG(2);
+ env.ip += 3;
+ return true;
}
#undef ARG
+bool AdlEngine::matchCommand(ScriptEnv &env, uint *actions) const {
+ if (env.cmd.room != IDI_NONE && env.cmd.room != _state.room)
+ return false;
+
+ if (env.cmd.verb != IDI_NONE && env.cmd.verb != env.verb)
+ return false;
+
+ if (env.cmd.noun != IDI_NONE && env.cmd.noun != env.noun)
+ return false;
+
+ for (uint i = 0; i < env.cmd.numCond; ++i) {
+ byte op = env.cmd.script[env.ip];
+
+ if (!_condOpcodes[op] || !_condOpcodes[op]->isValid())
+ error("Unimplemented condition opcode %02x", op);
+
+ if (!(*_condOpcodes[op])(env))
+ return false;
+ }
+
+ if (actions)
+ *actions = env.ip;
+
+ return true;
+}
+
+void AdlEngine::doActions(ScriptEnv &env) {
+ for (uint i = 0; i < env.cmd.numAct; ++i) {
+ byte op = env.cmd.script[env.ip];
+
+ if (!_actOpcodes[op] || !_actOpcodes[op]->isValid())
+ error("Unimplemented action opcode %02x", op);
+
+ if (!(*_actOpcodes[op])(env))
+ return;
+ }
+}
+
bool AdlEngine::doOneCommand(const Commands &commands, byte verb, byte noun) {
Commands::const_iterator cmd;
for (cmd = commands.begin(); cmd != commands.end(); ++cmd) {
- uint offset = 0;
- if (matchCommand(*cmd, verb, noun, &offset)) {
- doActions(*cmd, noun, offset);
+ ScriptEnv env(*cmd, verb, noun);
+ if (matchCommand(env)) {
+ doActions(env);
return true;
}
}
@@ -987,9 +1106,9 @@ void AdlEngine::doAllCommands(const Commands &commands, byte verb, byte noun) {
Commands::const_iterator cmd;
for (cmd = commands.begin(); cmd != commands.end(); ++cmd) {
- uint offset = 0;
- if (matchCommand(*cmd, verb, noun, &offset))
- doActions(*cmd, noun, offset);
+ ScriptEnv env(*cmd, verb, noun);
+ if (matchCommand(env))
+ doActions(env);
}
}
diff --git a/engines/adl/adl.h b/engines/adl/adl.h
index 97077f94f7..e007b15545 100644
--- a/engines/adl/adl.h
+++ b/engines/adl/adl.h
@@ -28,6 +28,7 @@
#include "common/str.h"
#include "common/hashmap.h"
#include "common/hash-str.h"
+#include "common/func.h"
#include "engines/engine.h"
@@ -47,6 +48,9 @@ class Display;
class GraphicsMan;
class Speaker;
struct AdlGameDescription;
+struct ScriptEnv;
+
+typedef Common::Functor1<ScriptEnv &, bool> Opcode;
// Conditional opcodes
#define IDO_CND_ITEM_IN_ROOM 0x03
@@ -101,11 +105,22 @@ struct Picture {
uint16 offset;
};
+typedef Common::Array<byte> Script;
+
struct Command {
byte room;
byte verb, noun;
byte numCond, numAct;
- Common::Array<byte> script;
+ Script script;
+};
+
+struct ScriptEnv {
+ ScriptEnv(const Command &cmd_, byte verb_, byte noun_) :
+ cmd(cmd_), verb(verb_), noun(noun_), ip(0) { }
+
+ const Command &cmd;
+ byte verb, noun;
+ byte ip;
};
enum {
@@ -165,6 +180,38 @@ protected:
void readCommands(Common::ReadStream &stream, Commands &commands);
virtual void checkInput(byte verb, byte noun);
+ virtual void setupOpcodeTables();
+
+ // Opcodes
+ bool o1_isItemInRoom(ScriptEnv &env);
+ bool o1_isMovesGrEq(ScriptEnv &env);
+ bool o1_isVarEq(ScriptEnv &env);
+ bool o1_isCurPicEq(ScriptEnv &env);
+ bool o1_isItemPicEq(ScriptEnv &env);
+
+ bool o1_varAdd(ScriptEnv &env);
+ bool o1_varSub(ScriptEnv &env);
+ bool o1_varSet(ScriptEnv &env);
+ bool o1_listInv(ScriptEnv &env);
+ bool o1_moveItem(ScriptEnv &env);
+ bool o1_setRoom(ScriptEnv &env);
+ bool o1_setCurPic(ScriptEnv &env);
+ bool o1_setPic(ScriptEnv &env);
+ bool o1_printMsg(ScriptEnv &env);
+ bool o1_setLight(ScriptEnv &env);
+ bool o1_setDark(ScriptEnv &env);
+ bool o1_save(ScriptEnv &env);
+ bool o1_restore(ScriptEnv &env);
+ bool o1_restart(ScriptEnv &env);
+ bool o1_quit(ScriptEnv &env);
+ bool o1_placeItem(ScriptEnv &env);
+ bool o1_setItemPic(ScriptEnv &env);
+ bool o1_resetPic(ScriptEnv &env);
+ bool o1_goDirection(ScriptEnv &env);
+ bool o1_takeItem(ScriptEnv &env);
+ bool o1_dropItem(ScriptEnv &env);
+ bool o1_setRoomPic(ScriptEnv &env);
+
// Graphics
void clearScreen() const;
void drawItems() const;
@@ -183,8 +230,8 @@ protected:
void setVar(uint i, byte value);
void takeItem(byte noun);
void dropItem(byte noun);
- bool matchCommand(const Command &command, byte verb, byte noun, uint *actions = nullptr) const;
- void doActions(const Command &command, byte noun, byte offset);
+ bool matchCommand(ScriptEnv &env, uint *actions = nullptr) const;
+ void doActions(ScriptEnv &env);
bool doOneCommand(const Commands &commands, byte verb, byte noun);
void doAllCommands(const Commands &commands, byte verb, byte noun);
@@ -192,6 +239,8 @@ protected:
GraphicsMan *_graphics;
Speaker *_speaker;
+ // Opcodes
+ Common::Array<const Opcode *> _condOpcodes, _actOpcodes;
// Message strings in data file
Common::Array<Common::String> _messages;
// Picture data