aboutsummaryrefslogtreecommitdiff
path: root/engines/parallaction
diff options
context:
space:
mode:
authorNicola Mettifogo2007-08-13 22:59:13 +0000
committerNicola Mettifogo2007-08-13 22:59:13 +0000
commit9694215490259a5a7c06d606e909165eb724dd66 (patch)
tree4e76d111002d18dcc582ce01b0eaaa13a37c5f10 /engines/parallaction
parent7460eb55a1ef539af96fdb0c2aac785c348f55fd (diff)
downloadscummvm-rg350-9694215490259a5a7c06d606e909165eb724dd66.tar.gz
scummvm-rg350-9694215490259a5a7c06d606e909165eb724dd66.tar.bz2
scummvm-rg350-9694215490259a5a7c06d606e909165eb724dd66.zip
Changed Command parsing/execution and Instruction execution from switch statements into arrays of function pointers.
svn-id: r28599
Diffstat (limited to 'engines/parallaction')
-rw-r--r--engines/parallaction/animation.cpp285
-rw-r--r--engines/parallaction/commands.cpp415
-rw-r--r--engines/parallaction/parallaction.h77
3 files changed, 477 insertions, 300 deletions
diff --git a/engines/parallaction/animation.cpp b/engines/parallaction/animation.cpp
index 51a21141da..a308b8feba 100644
--- a/engines/parallaction/animation.cpp
+++ b/engines/parallaction/animation.cpp
@@ -49,7 +49,7 @@ namespace Parallaction {
#define INST_START 16
#define INST_SOUND 17
#define INST_MOVE 18
-#define INST_END 1000
+#define INST_END 19
void wrapLocalVar(LocalVariable *local);
@@ -470,152 +470,193 @@ LValue Parallaction::getLValue(Instruction *inst, char *str, LocalVariable *loca
}
+DECLARE_INSTRUCTION_OPCODE(on) {
+ (*_instRunCtxt.inst)->_opBase._a->_flags |= kFlagsActive;
+ (*_instRunCtxt.inst)->_opBase._a->_flags &= ~kFlagsRemove;
+}
-void jobRunScripts(void *parm, Job *j) {
- debugC(3, kDebugJobs, "jobRunScripts");
- static uint16 modCounter = 0;
+DECLARE_INSTRUCTION_OPCODE(off) {
+ (*_instRunCtxt.inst)->_opBase._a->_flags |= kFlagsRemove;
+// v1C = (*_instRunCtxt.inst)->_opBase;
+}
+
+
+DECLARE_INSTRUCTION_OPCODE(loop) {
+ if ((*_instRunCtxt.inst)->_flags & kInstUsesLiteral) {
+ _instRunCtxt.a->_program->_loopCounter = (*_instRunCtxt.inst)->_opBase._loopCounter._value;
+ } else {
+ _instRunCtxt.a->_program->_loopCounter = *(*_instRunCtxt.inst)->_opBase._loopCounter._pvalue;
+ }
+ _instRunCtxt.a->_program->_loopStart = _instRunCtxt.inst;
+}
+
+DECLARE_INSTRUCTION_OPCODE(endloop) {
+ if (--_instRunCtxt.a->_program->_loopCounter > 0) {
+ _instRunCtxt.inst = _instRunCtxt.a->_program->_loopStart;
+ }
+}
+
+DECLARE_INSTRUCTION_OPCODE(inc) {
+ int16 _si = 0;
+ int16 _ax = 0, _bx = 0;
+ if ((*_instRunCtxt.inst)->_flags & kInstUsesLiteral) {
+ _si = (*_instRunCtxt.inst)->_opB._value;
+ } else {
+ _si = *(*_instRunCtxt.inst)->_opB._pvalue;
+ }
+ if ((*_instRunCtxt.inst)->_flags & kInstMod) { // mod
+ _bx = (_si > 0 ? _si : -_si);
+ if (_instRunCtxt.modCounter % _bx != 0) return;
+
+ _si = (_si > 0 ? 1 : -1);
+ }
+ if ((*_instRunCtxt.inst)->_flags & kInstUsesLocal) { // local
+ if ((*_instRunCtxt.inst)->_index == INST_INC) _ax = _si;
+ else _ax = -_si;
+
+ (*_instRunCtxt.inst)->_opA._local->_value += _ax;
+ wrapLocalVar((*_instRunCtxt.inst)->_opA._local);
+ return;
+ }
+
+ // built-in variable (x, y, z, f)
+ if ((*_instRunCtxt.inst)->_index == INST_INC) _ax = _si;
+ else _ax = -_si;
+ *(*_instRunCtxt.inst)->_opA._pvalue += _ax;
+}
+
+
+DECLARE_INSTRUCTION_OPCODE(set) {
+ int16 _si;
+ if ((*_instRunCtxt.inst)->_flags & kInstUsesLiteral) {
+ _si = (*_instRunCtxt.inst)->_opB._value;
+ } else {
+ _si = *(*_instRunCtxt.inst)->_opB._pvalue;
+ }
+
+ if ((*_instRunCtxt.inst)->_flags & kInstUsesLocal) {
+ (*_instRunCtxt.inst)->_opA._local->_value = _si;
+ } else {
+ *(*_instRunCtxt.inst)->_opA._pvalue = _si;
+ }
+}
+
+
+DECLARE_INSTRUCTION_OPCODE(put) {
Graphics::Surface v18;
+ v18.w = (*_instRunCtxt.inst)->_opBase._a->width();
+ v18.h = (*_instRunCtxt.inst)->_opBase._a->height();
+ v18.pixels = (*_instRunCtxt.inst)->_opBase._a->getFrameData((*_instRunCtxt.inst)->_opBase._a->_frame);
+
+ if ((*_instRunCtxt.inst)->_flags & kInstMaskedPut) {
+ uint16 _si = _gfx->queryMask((*_instRunCtxt.inst)->_opB._value);
+ _gfx->blitCnv(&v18, (*_instRunCtxt.inst)->_opA._value, (*_instRunCtxt.inst)->_opB._value, _si, Gfx::kBitBack);
+ _gfx->blitCnv(&v18, (*_instRunCtxt.inst)->_opA._value, (*_instRunCtxt.inst)->_opB._value, _si, Gfx::kBit2);
+ } else {
+ _gfx->flatBlitCnv(&v18, (*_instRunCtxt.inst)->_opA._value, (*_instRunCtxt.inst)->_opB._value, Gfx::kBitBack);
+ _gfx->flatBlitCnv(&v18, (*_instRunCtxt.inst)->_opA._value, (*_instRunCtxt.inst)->_opB._value, Gfx::kBit2);
+ }
+}
- for (AnimationList::iterator it = _vm->_animations.begin(); it != _vm->_animations.end(); it++) {
+DECLARE_INSTRUCTION_OPCODE(null) {
- Animation *a = *it;
+}
- if (a->_flags & kFlagsCharacter) a->_z = a->_top + a->height();
+DECLARE_INSTRUCTION_OPCODE(call) {
+ callFunction((*_instRunCtxt.inst)->_opBase._index, 0);
+}
- if ((a->_flags & kFlagsActing) == 0) continue;
- InstructionList::iterator inst = a->_program->_ip;
-// printf("Animation: %s, flags: %x\n", a->_name, a->_flags);
+DECLARE_INSTRUCTION_OPCODE(wait) {
+ if (_engineFlags & kEngineWalking)
+ _instRunCtxt.suspend = true;
+}
- while (((*inst)->_index != INST_SHOW) && (a->_flags & kFlagsActing)) {
- debugC(9, kDebugJobs, "Animation: %s, instruction: %s", a->_label._text, (*inst)->_index == INST_END ? "end" : _vm->_instructionNamesRes[(*inst)->_index - 1]);
+DECLARE_INSTRUCTION_OPCODE(start) {
+// v1C = (*_instRunCtxt.inst)->_opBase;
+ (*_instRunCtxt.inst)->_opBase._a->_flags |= (kFlagsActing | kFlagsActive);
+}
- switch ((*inst)->_index) {
- case INST_ENDLOOP: // endloop
- if (--a->_program->_loopCounter > 0) {
- inst = a->_program->_loopStart;
- }
- break;
- case INST_OFF: {// off
- (*inst)->_opBase._a->_flags |= kFlagsRemove;
-// v1C = (*inst)->_opBase;
- }
- break;
-
- case INST_ON: // on
- (*inst)->_opBase._a->_flags |= kFlagsActive;
- (*inst)->_opBase._a->_flags &= ~kFlagsRemove;
- break;
-
- case INST_START: // start
-// v1C = (*inst)->_opBase;
- (*inst)->_opBase._a->_flags |= (kFlagsActing | kFlagsActive);
- break;
-
- case INST_LOOP: // loop
- if ((*inst)->_flags & kInstUsesLiteral) {
- a->_program->_loopCounter = (*inst)->_opBase._loopCounter._value;
- } else {
- a->_program->_loopCounter = *(*inst)->_opBase._loopCounter._pvalue;
- }
- a->_program->_loopStart = inst;
- break;
-
- case INST_INC: // inc
- case INST_DEC: { // dec
- int16 _si = 0;
- int16 _ax = 0, _bx = 0;
- if ((*inst)->_flags & kInstUsesLiteral) {
- _si = (*inst)->_opB._value;
- } else {
- _si = *(*inst)->_opB._pvalue;
- }
- if ((*inst)->_flags & kInstMod) { // mod
- _bx = (_si > 0 ? _si : -_si);
- if (modCounter % _bx != 0) break;
+DECLARE_INSTRUCTION_OPCODE(sound) {
+ _activeZone = (*_instRunCtxt.inst)->_opBase._z;
+}
- _si = (_si > 0 ? 1 : -1);
- }
- if ((*inst)->_flags & kInstUsesLocal) { // local
- if ((*inst)->_index == INST_INC) _ax = _si;
- else _ax = -_si;
- (*inst)->_opA._local->_value += _ax;
- wrapLocalVar((*inst)->_opA._local);
- break;
- }
+DECLARE_INSTRUCTION_OPCODE(move) {
+ WalkNodeList *v4 = _char._builder.buildPath(*(*_instRunCtxt.inst)->_opA._pvalue, *(*_instRunCtxt.inst)->_opB._pvalue);
+ addJob(&jobWalk, v4, kPriority19 );
+ _engineFlags |= kEngineWalking;
+}
- // built-in variable (x, y, z, f)
- if ((*inst)->_index == INST_INC) _ax = _si;
- else _ax = -_si;
- *(*inst)->_opA._pvalue += _ax;
- }
- break;
+DECLARE_INSTRUCTION_OPCODE(end) {
+ if ((_instRunCtxt.a->_flags & kFlagsLooping) == 0) {
+ _instRunCtxt.a->_flags &= ~kFlagsActing;
+ runCommands(_instRunCtxt.a->_commands, _instRunCtxt.a);
+ }
+ _instRunCtxt.a->_program->_ip = _instRunCtxt.a->_program->_instructions.begin();
- case INST_MOVE: { // move
- WalkNodeList *v4 = _vm->_char._builder.buildPath(*(*inst)->_opA._pvalue, *(*inst)->_opB._pvalue);
- _vm->addJob(&jobWalk, v4, kPriority19 );
- _engineFlags |= kEngineWalking;
- }
- break;
-
- case INST_PUT: // put
- v18.w = (*inst)->_opBase._a->width();
- v18.h = (*inst)->_opBase._a->height();
- v18.pixels = (*inst)->_opBase._a->getFrameData((*inst)->_opBase._a->_frame);
-
- if ((*inst)->_flags & kInstMaskedPut) {
- uint16 _si = _vm->_gfx->queryMask((*inst)->_opB._value);
- _vm->_gfx->blitCnv(&v18, (*inst)->_opA._value, (*inst)->_opB._value, _si, Gfx::kBitBack);
- _vm->_gfx->blitCnv(&v18, (*inst)->_opA._value, (*inst)->_opB._value, _si, Gfx::kBit2);
- } else {
- _vm->_gfx->flatBlitCnv(&v18, (*inst)->_opA._value, (*inst)->_opB._value, Gfx::kBitBack);
- _vm->_gfx->flatBlitCnv(&v18, (*inst)->_opA._value, (*inst)->_opB._value, Gfx::kBit2);
- }
- break;
+ _instRunCtxt.suspend = true;
+}
- case INST_END: // exit
- if ((a->_flags & kFlagsLooping) == 0) {
- a->_flags &= ~kFlagsActing;
- _vm->runCommands(a->_commands, a);
- }
- a->_program->_ip = a->_program->_instructions.begin();
- goto label1;
- case INST_CALL: // call
- _vm->callFunction((*inst)->_opBase._index, 0);
- break;
+void jobRunScripts(void *parm, Job *j) {
+ debugC(3, kDebugJobs, "jobRunScripts");
- case INST_WAIT: // wait
- if (_engineFlags & kEngineWalking) goto label1;
- break;
+ static uint16 modCounter = 0;
- case INST_SOUND: // sound
- _activeZone = (*inst)->_opBase._z;
- break;
+ static const Parallaction::Opcode opcodes[] = {
+ INSTRUCTION_OPCODE(on),
+ INSTRUCTION_OPCODE(off),
+ INSTRUCTION_OPCODE(set), // x
+ INSTRUCTION_OPCODE(set), // y
+ INSTRUCTION_OPCODE(set), // z
+ INSTRUCTION_OPCODE(set), // f
+ INSTRUCTION_OPCODE(loop),
+ INSTRUCTION_OPCODE(endloop),
+ INSTRUCTION_OPCODE(null),
+ INSTRUCTION_OPCODE(inc),
+ INSTRUCTION_OPCODE(inc), // dec
+ INSTRUCTION_OPCODE(set),
+ INSTRUCTION_OPCODE(put),
+ INSTRUCTION_OPCODE(call),
+ INSTRUCTION_OPCODE(wait),
+ INSTRUCTION_OPCODE(start),
+ INSTRUCTION_OPCODE(sound),
+ INSTRUCTION_OPCODE(move),
+ INSTRUCTION_OPCODE(end)
+ };
+
+ _vm->_instructionOpcodes = opcodes;
- default: { // INST_SET, INST_X, INST_Y, INST_Z, INST_F
- int16 _si;
- if ((*inst)->_flags & kInstUsesLiteral) {
- _si = (*inst)->_opB._value;
- } else {
- _si = *(*inst)->_opB._pvalue;
- }
+ for (AnimationList::iterator it = _vm->_animations.begin(); it != _vm->_animations.end(); it++) {
- if ((*inst)->_flags & kInstUsesLocal) {
- (*inst)->_opA._local->_value = _si;
- } else {
- *(*inst)->_opA._pvalue = _si;
- }
- }
- break;
+ Animation *a = *it;
- }
+ if (a->_flags & kFlagsCharacter) a->_z = a->_top + a->height();
+
+ if ((a->_flags & kFlagsActing) == 0) continue;
+ InstructionList::iterator inst = a->_program->_ip;
+
+ while (((*inst)->_index != INST_SHOW) && (a->_flags & kFlagsActing)) {
+
+ debugC(9, kDebugJobs, "Animation: %s, instruction: %s", a->_label._text, (*inst)->_index == INST_END ? "end" : _vm->_instructionNamesRes[(*inst)->_index - 1]);
+
+ _vm->_instRunCtxt.inst = inst;
+ _vm->_instRunCtxt.a = a;
+ _vm->_instRunCtxt.modCounter = modCounter;
+ _vm->_instRunCtxt.suspend = false;
+
+ (_vm->*(_vm->_instructionOpcodes)[(*inst)->_index - 1])();
+
+ inst = _vm->_instRunCtxt.inst; // handles endloop correctly
+
+ if (_vm->_instRunCtxt.suspend)
+ goto label1;
inst++;
}
diff --git a/engines/parallaction/commands.cpp b/engines/parallaction/commands.cpp
index 915d76d7cc..62cd60b5d4 100644
--- a/engines/parallaction/commands.cpp
+++ b/engines/parallaction/commands.cpp
@@ -47,92 +47,114 @@ namespace Parallaction {
#define CMD_MOVE 15
#define CMD_STOP 16
+DECLARE_COMMAND_PARSER(Flags) {
+ if (_globalTable->lookup(_tokens[1]) == -1) {
+ do {
+ char _al = _localFlagNames->lookup(_tokens[_cmdParseCtxt.nextToken]);
+ _cmdParseCtxt.nextToken++;
+ _cmdParseCtxt.cmd->u._flags |= 1 << (_al - 1);
+ } while (!scumm_stricmp(_tokens[_cmdParseCtxt.nextToken++], "|"));
+ _cmdParseCtxt.nextToken--;
+ } else {
+ _cmdParseCtxt.cmd->u._flags |= kFlagsGlobal;
+ do {
+ char _al = _globalTable->lookup(_tokens[1]);
+ _cmdParseCtxt.nextToken++;
+ _cmdParseCtxt.cmd->u._flags |= 1 << (_al - 1);
+ } while (!scumm_stricmp(_tokens[_cmdParseCtxt.nextToken++], "|"));
+ _cmdParseCtxt.nextToken--;
+ }
+}
-void Parallaction::parseCommands(Script &script, CommandList& list) {
-// printf("parseCommands()");
- fillBuffers(script, true);
+DECLARE_COMMAND_PARSER(Animation) {
+ _cmdParseCtxt.cmd->u._animation = findAnimation(_tokens[_cmdParseCtxt.nextToken]);
+ _cmdParseCtxt.nextToken++;
+ if (_cmdParseCtxt.cmd->u._animation == NULL) {
+ strcpy(_forwardedAnimationNames[_numForwards], _tokens[_cmdParseCtxt.nextToken-1]);
+ _forwardedCommands[_numForwards] = _cmdParseCtxt.cmd;
+ _numForwards++;
+ }
+}
- while (scumm_stricmp(_tokens[0], "ENDCOMMANDS") && scumm_stricmp(_tokens[0], "ENDZONE")) {
-// printf("token[0] = %s", _tokens[0]);
- Command *cmd = new Command;
+DECLARE_COMMAND_PARSER(Zone) {
+ _cmdParseCtxt.cmd->u._zone = findZone(_tokens[_cmdParseCtxt.nextToken]);
+ _cmdParseCtxt.nextToken++;
+}
- cmd->_id = _commandsNames->lookup(_tokens[0]);
- uint16 _si = 1;
-
-// printf("cmd id = %i", cmd->_id);
-
- switch (cmd->_id) {
- case CMD_SET: // set
- case CMD_CLEAR: // clear
- case CMD_TOGGLE: // toggle
- if (_globalTable->lookup(_tokens[1]) == -1) {
- do {
- char _al = _localFlagNames->lookup(_tokens[_si]);
- _si++;
- cmd->u._flags |= 1 << (_al - 1);
- } while (!scumm_stricmp(_tokens[_si++], "|"));
- _si--;
- } else {
- cmd->u._flags |= kFlagsGlobal;
- do {
- char _al = _globalTable->lookup(_tokens[1]);
- _si++;
- cmd->u._flags |= 1 << (_al - 1);
- } while (!scumm_stricmp(_tokens[_si++], "|"));
- _si--;
- }
- break;
- case CMD_START: // start
- case CMD_STOP: // stop
- cmd->u._animation = findAnimation(_tokens[_si]);
- _si++;
- if (cmd->u._animation == NULL) {
- strcpy(_forwardedAnimationNames[_numForwards], _tokens[_si-1]);
- _forwardedCommands[_numForwards] = cmd;
- _numForwards++;
- }
- break;
+DECLARE_COMMAND_PARSER(Location) {
+ _cmdParseCtxt.cmd->u._string = (char*)malloc(strlen(_tokens[_cmdParseCtxt.nextToken])+1);
+ strcpy(_cmdParseCtxt.cmd->u._string, _tokens[_cmdParseCtxt.nextToken]);
+ _cmdParseCtxt.nextToken++;
+}
- case CMD_SPEAK: // speak
- case CMD_GET: // get
- case CMD_OPEN: // open
- case CMD_CLOSE: // close
- case CMD_ON: // on
- case CMD_OFF: // off
- cmd->u._zone = findZone(_tokens[_si]);
- _si++;
- break;
- case CMD_LOCATION: // location
- cmd->u._string = (char*)malloc(strlen(_tokens[_si])+1);
- strcpy(cmd->u._string, _tokens[_si]);
- _si++;
- break;
+DECLARE_COMMAND_PARSER(Drop) {
+ _cmdParseCtxt.cmd->u._object = _objectsNames->lookup(_tokens[_cmdParseCtxt.nextToken]);
+ _cmdParseCtxt.nextToken++;
+}
- case CMD_CALL: // call
- cmd->u._callable = _callableNames->lookup(_tokens[_si]) - 1;
- _si++;
- break;
- case CMD_DROP: // drop
- cmd->u._object = _objectsNames->lookup(_tokens[_si]);
- _si++;
- break;
+DECLARE_COMMAND_PARSER(Call) {
+ _cmdParseCtxt.cmd->u._callable = _callableNames->lookup(_tokens[_cmdParseCtxt.nextToken]) - 1;
+ _cmdParseCtxt.nextToken++;
+}
- case CMD_QUIT: // quit
- break;
- case CMD_MOVE: // move
- cmd->u._move._x = atoi(_tokens[_si]);
- _si++;
- cmd->u._move._y = atoi(_tokens[_si]);
- _si++;
- break;
+DECLARE_COMMAND_PARSER(Null) {
+}
+
+
+DECLARE_COMMAND_PARSER(Move) {
+ _cmdParseCtxt.cmd->u._move._x = atoi(_tokens[_cmdParseCtxt.nextToken]);
+ _cmdParseCtxt.nextToken++;
+ _cmdParseCtxt.cmd->u._move._y = atoi(_tokens[_cmdParseCtxt.nextToken]);
+ _cmdParseCtxt.nextToken++;
+}
+
- }
+
+
+void Parallaction::parseCommands(Script &script, CommandList& list) {
+
+ static const Opcode parsers[] = {
+ COMMAND_PARSER(Flags), // set
+ COMMAND_PARSER(Flags), // clear
+ COMMAND_PARSER(Animation), // start
+ COMMAND_PARSER(Zone), // speak
+ COMMAND_PARSER(Zone), // get
+ COMMAND_PARSER(Location), // location
+ COMMAND_PARSER(Zone), // open
+ COMMAND_PARSER(Zone), // close
+ COMMAND_PARSER(Zone), // on
+ COMMAND_PARSER(Zone), // off
+ COMMAND_PARSER(Call), // call
+ COMMAND_PARSER(Flags), // toggle
+ COMMAND_PARSER(Drop), // drop
+ COMMAND_PARSER(Null), // quit
+ COMMAND_PARSER(Move), // move
+ COMMAND_PARSER(Animation) // stop
+ };
+
+ _commandParsers = parsers;
+
+
+ fillBuffers(script, true);
+
+ while (scumm_stricmp(_tokens[0], "ENDCOMMANDS") && scumm_stricmp(_tokens[0], "ENDZONE")) {
+
+ Command *cmd = new Command;
+
+ cmd->_id = _commandsNames->lookup(_tokens[0]);
+
+ _cmdParseCtxt.nextToken = 1;
+ _cmdParseCtxt.cmd = cmd;
+
+ (this->*_commandParsers[cmd->_id - 1])();
+
+ int _si = _cmdParseCtxt.nextToken;
if (!scumm_stricmp(_tokens[_si], "flags")) {
_si++;
@@ -192,144 +214,181 @@ void Parallaction::parseCommands(Script &script, CommandList& list) {
fillBuffers(script, true);
}
+}
+
+DECLARE_COMMAND_OPCODE(set) {
+ if (_cmdRunCtxt.cmd->u._flags & kFlagsGlobal) {
+ _cmdRunCtxt.cmd->u._flags &= ~kFlagsGlobal;
+ _commandFlags |= _cmdRunCtxt.cmd->u._flags;
+ } else {
+ _localFlags[_currentLocationIndex] |= _cmdRunCtxt.cmd->u._flags;
+ }
}
-void Parallaction::runCommands(CommandList& list, Zone *z) {
- debugC(1, kDebugLocation, "runCommands");
+DECLARE_COMMAND_OPCODE(clear) {
+ if (_cmdRunCtxt.cmd->u._flags & kFlagsGlobal) {
+ _cmdRunCtxt.cmd->u._flags &= ~kFlagsGlobal;
+ _commandFlags &= ~_cmdRunCtxt.cmd->u._flags;
+ } else {
+ _localFlags[_currentLocationIndex] &= ~_cmdRunCtxt.cmd->u._flags;
+ }
+}
- CommandList::iterator it = list.begin();
- for ( ; it != list.end(); it++) {
- Command *cmd = *it;
- CommandData *u = &cmd->u;
- uint32 v8 = _localFlags[_currentLocationIndex];
+DECLARE_COMMAND_OPCODE(start) {
+ _cmdRunCtxt.cmd->u._zone->_flags |= kFlagsActing;
+}
- if (_engineFlags & kEngineQuit)
- break;
- if (cmd->_flagsOn & kFlagsGlobal) {
- v8 = _commandFlags | kFlagsGlobal;
+DECLARE_COMMAND_OPCODE(speak) {
+ _activeZone = _cmdRunCtxt.cmd->u._zone;
+}
+
+
+DECLARE_COMMAND_OPCODE(get) {
+ _cmdRunCtxt.cmd->u._zone->_flags &= ~kFlagsFixed;
+ if (!runZone(_cmdRunCtxt.cmd->u._zone)) {
+ runCommands(_cmdRunCtxt.cmd->u._zone->_commands);
+ }
+}
+
+
+DECLARE_COMMAND_OPCODE(location) {
+ strcpy(_location._name, _cmdRunCtxt.cmd->u._string);
+ _engineFlags |= kEngineChangeLocation;
+}
+
+
+DECLARE_COMMAND_OPCODE(open) {
+ _cmdRunCtxt.cmd->u._zone->_flags &= ~kFlagsClosed;
+ if (_cmdRunCtxt.cmd->u._zone->u.door->_cnv) {
+ addJob(&jobToggleDoor, (void*)_cmdRunCtxt.cmd->u._zone, kPriority18 );
+ }
+}
+
+
+DECLARE_COMMAND_OPCODE(close) {
+ _cmdRunCtxt.cmd->u._zone->_flags |= kFlagsClosed;
+ if (_cmdRunCtxt.cmd->u._zone->u.door->_cnv) {
+ addJob(&jobToggleDoor, (void*)_cmdRunCtxt.cmd->u._zone, kPriority18 );
+ }
+}
+
+
+DECLARE_COMMAND_OPCODE(on) {
+ // WORKAROUND: the original DOS-based engine didn't check u->_zone before dereferencing
+ // the pointer to get structure members, thus leading to crashes in systems with memory
+ // protection.
+ // As a side note, the overwritten address is the 5th entry in the DOS interrupt table
+ // (print screen handler): this suggests that a system would hang when the print screen
+ // key is pressed after playing Nippon Safes, provided that this code path is taken.
+ if (_cmdRunCtxt.cmd->u._zone != NULL) {
+ _cmdRunCtxt.cmd->u._zone->_flags &= ~kFlagsRemove;
+ _cmdRunCtxt.cmd->u._zone->_flags |= kFlagsActive;
+ if ((_cmdRunCtxt.cmd->u._zone->_type & 0xFFFF) == kZoneGet) {
+ addJob(&jobDisplayDroppedItem, _cmdRunCtxt.cmd->u._zone, kPriority17 );
}
+ }
+}
- if ((cmd->_flagsOn & v8) != cmd->_flagsOn) continue;
- if ((cmd->_flagsOff & ~v8) != cmd->_flagsOff) continue;
- debugC(1, kDebugLocation, "runCommands: %s (on: %x, off: %x)", _commandsNamesRes[cmd->_id-1], cmd->_flagsOn, cmd->_flagsOff);
+DECLARE_COMMAND_OPCODE(off) {
+ _cmdRunCtxt.cmd->u._zone->_flags |= kFlagsRemove;
+}
- switch (cmd->_id) {
- case CMD_SET: // set
- if (cmd->u._flags & kFlagsGlobal) {
- cmd->u._flags &= ~kFlagsGlobal;
- _commandFlags |= cmd->u._flags;
- } else {
- _localFlags[_currentLocationIndex] |= cmd->u._flags;
- }
- break;
+DECLARE_COMMAND_OPCODE(call) {
+ callFunction(_cmdRunCtxt.cmd->u._callable, _cmdRunCtxt.z);
+}
- case CMD_CLEAR: // clear
- if (cmd->u._flags & kFlagsGlobal) {
- cmd->u._flags &= ~kFlagsGlobal;
- _commandFlags &= ~cmd->u._flags;
- } else {
- _localFlags[_currentLocationIndex] &= ~cmd->u._flags;
- }
- break;
- case CMD_TOGGLE: // toggle
- if (cmd->u._flags & kFlagsGlobal) {
- cmd->u._flags &= ~kFlagsGlobal;
- _commandFlags ^= cmd->u._flags;
- } else {
- _localFlags[_currentLocationIndex] ^= cmd->u._flags;
- }
- break;
+DECLARE_COMMAND_OPCODE(toggle) {
+ if (_cmdRunCtxt.cmd->u._flags & kFlagsGlobal) {
+ _cmdRunCtxt.cmd->u._flags &= ~kFlagsGlobal;
+ _commandFlags ^= _cmdRunCtxt.cmd->u._flags;
+ } else {
+ _localFlags[_currentLocationIndex] ^= _cmdRunCtxt.cmd->u._flags;
+ }
+}
- case CMD_START: // start
- cmd->u._zone->_flags |= kFlagsActing;
- break;
- case CMD_STOP: // stop
- cmd->u._zone->_flags &= ~kFlagsActing;
- break;
+DECLARE_COMMAND_OPCODE(drop){
+ dropItem( _cmdRunCtxt.cmd->u._object );
+}
- case CMD_SPEAK: // speak
- _activeZone = u->_zone;
- break;
- case CMD_GET: // get
- u->_zone->_flags &= ~kFlagsFixed;
- if (!runZone(u->_zone)) {
- runCommands(u->_zone->_commands);
- }
- break;
+DECLARE_COMMAND_OPCODE(quit) {
+ _engineFlags |= kEngineQuit;
+}
- case CMD_DROP: // drop
- dropItem( u->_object );
- break;
- case CMD_OPEN: // open
- u->_zone->_flags &= ~kFlagsClosed;
- if (u->_zone->u.door->_cnv) {
- addJob(&jobToggleDoor, (void*)u->_zone, kPriority18 );
- }
- break;
+DECLARE_COMMAND_OPCODE(move) {
+ if ((_char._ani._flags & kFlagsRemove) || (_char._ani._flags & kFlagsActive) == 0) {
+ return;
+ }
- case CMD_CLOSE: // close
- u->_zone->_flags |= kFlagsClosed;
- if (u->_zone->u.door->_cnv) {
- addJob(&jobToggleDoor, (void*)u->_zone, kPriority18 );
- }
- break;
+ WalkNodeList *vC = _char._builder.buildPath(_cmdRunCtxt.cmd->u._move._x, _cmdRunCtxt.cmd->u._move._y);
- case CMD_ON: // on
- // WORKAROUND: the original DOS-based engine didn't check u->_zone before dereferencing
- // the pointer to get structure members, thus leading to crashes in systems with memory
- // protection.
- // As a side note, the overwritten address is the 5th entry in the DOS interrupt table
- // (print screen handler): this suggests that a system would hang when the print screen
- // key is pressed after playing Nippon Safes, provided that this code path is taken.
- if (u->_zone != NULL) {
- u->_zone->_flags &= ~kFlagsRemove;
- u->_zone->_flags |= kFlagsActive;
- if ((u->_zone->_type & 0xFFFF) == kZoneGet) {
- addJob(&jobDisplayDroppedItem, u->_zone, kPriority17 );
- }
- }
- break;
+ addJob(&jobWalk, vC, kPriority19 );
+ _engineFlags |= kEngineWalking;
+}
- case CMD_OFF: // off
- u->_zone->_flags |= kFlagsRemove;
- break;
- case CMD_LOCATION: // location
- strcpy(_location._name, u->_string);
- _engineFlags |= kEngineChangeLocation;
- break;
+DECLARE_COMMAND_OPCODE(stop) {
+ _cmdRunCtxt.cmd->u._zone->_flags &= ~kFlagsActing;
+}
+
- case CMD_CALL: // call
- callFunction(u->_callable, z);
- break;
- case CMD_QUIT: // quit
- _engineFlags |= kEngineQuit;
- break;
- case CMD_MOVE: { // move
- if ((_char._ani._flags & kFlagsRemove) || (_char._ani._flags & kFlagsActive) == 0) {
- continue;
- }
+void Parallaction::runCommands(CommandList& list, Zone *z) {
+ debugC(1, kDebugLocation, "runCommands");
- WalkNodeList *vC = _char._builder.buildPath(u->_move._x, u->_move._y);
+ static const Opcode opcodes[] = {
+ COMMAND_OPCODE(set),
+ COMMAND_OPCODE(clear),
+ COMMAND_OPCODE(start),
+ COMMAND_OPCODE(speak),
+ COMMAND_OPCODE(get),
+ COMMAND_OPCODE(location),
+ COMMAND_OPCODE(open),
+ COMMAND_OPCODE(close),
+ COMMAND_OPCODE(on),
+ COMMAND_OPCODE(off),
+ COMMAND_OPCODE(call),
+ COMMAND_OPCODE(toggle),
+ COMMAND_OPCODE(drop),
+ COMMAND_OPCODE(quit),
+ COMMAND_OPCODE(move),
+ COMMAND_OPCODE(stop)
+ };
+
+ _commandOpcodes = opcodes;
- addJob(&jobWalk, vC, kPriority19 );
- _engineFlags |= kEngineWalking;
- }
+ CommandList::iterator it = list.begin();
+ for ( ; it != list.end(); it++) {
+
+ Command *cmd = *it;
+ uint32 v8 = _localFlags[_currentLocationIndex];
+
+ if (_engineFlags & kEngineQuit)
break;
+ if (cmd->_flagsOn & kFlagsGlobal) {
+ v8 = _commandFlags | kFlagsGlobal;
}
+
+ if ((cmd->_flagsOn & v8) != cmd->_flagsOn) continue;
+ if ((cmd->_flagsOff & ~v8) != cmd->_flagsOff) continue;
+
+ debugC(1, kDebugLocation, "runCommands: %s (on: %x, off: %x)", _commandsNamesRes[cmd->_id-1], cmd->_flagsOn, cmd->_flagsOff);
+
+ _cmdRunCtxt.z = z;
+ _cmdRunCtxt.cmd = cmd;
+
+ (this->*_commandOpcodes[cmd->_id - 1])();
}
debugC(1, kDebugLocation, "runCommands completed");
diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h
index 8549cba24f..4fe4e7d77d 100644
--- a/engines/parallaction/parallaction.h
+++ b/engines/parallaction/parallaction.h
@@ -292,6 +292,17 @@ struct BackgroundInfo {
};
+#define DECLARE_COMMAND_PARSER(sig) void Parallaction::cmdParse_##sig()
+#define COMMAND_PARSER(sig) &Parallaction::cmdParse_##sig
+
+#define DECLARE_COMMAND_OPCODE(op) void Parallaction::cmdOp_##op()
+#define COMMAND_OPCODE(op) &Parallaction::cmdOp_##op
+
+
+#define DECLARE_INSTRUCTION_OPCODE(op) void Parallaction::instOp_##op()
+#define INSTRUCTION_OPCODE(op) &Parallaction::instOp_##op
+
+
class Parallaction : public Engine {
friend class Debugger;
@@ -309,6 +320,71 @@ public:
void waitTime(uint32 t);
+ typedef void (Parallaction::*Opcode)();
+ const Opcode *_commandParsers;
+
+ struct {
+ Command *cmd;
+ int nextToken;
+ } _cmdParseCtxt;
+
+ DECLARE_COMMAND_PARSER(Flags);
+ DECLARE_COMMAND_PARSER(Animation);
+ DECLARE_COMMAND_PARSER(Zone);
+ DECLARE_COMMAND_PARSER(Location);
+ DECLARE_COMMAND_PARSER(Drop);
+ DECLARE_COMMAND_PARSER(Call);
+ DECLARE_COMMAND_PARSER(Null);
+ DECLARE_COMMAND_PARSER(Move);
+
+ const Opcode *_commandOpcodes;
+
+ struct {
+ Command *cmd;
+ Zone *z;
+ } _cmdRunCtxt;
+
+ DECLARE_COMMAND_OPCODE(set);
+ DECLARE_COMMAND_OPCODE(clear);
+ DECLARE_COMMAND_OPCODE(start);
+ DECLARE_COMMAND_OPCODE(speak);
+ DECLARE_COMMAND_OPCODE(get);
+ DECLARE_COMMAND_OPCODE(location);
+ DECLARE_COMMAND_OPCODE(open);
+ DECLARE_COMMAND_OPCODE(close);
+ DECLARE_COMMAND_OPCODE(on);
+ DECLARE_COMMAND_OPCODE(off);
+ DECLARE_COMMAND_OPCODE(call);
+ DECLARE_COMMAND_OPCODE(toggle);
+ DECLARE_COMMAND_OPCODE(drop);
+ DECLARE_COMMAND_OPCODE(quit);
+ DECLARE_COMMAND_OPCODE(move);
+ DECLARE_COMMAND_OPCODE(stop);
+
+ const Opcode *_instructionOpcodes;
+
+ struct {
+ Animation *a;
+ InstructionList::iterator inst;
+ uint16 modCounter;
+ bool suspend;
+ } _instRunCtxt;
+
+ DECLARE_INSTRUCTION_OPCODE(on);
+ DECLARE_INSTRUCTION_OPCODE(off);
+ DECLARE_INSTRUCTION_OPCODE(loop);
+ DECLARE_INSTRUCTION_OPCODE(endloop);
+ DECLARE_INSTRUCTION_OPCODE(null);
+ DECLARE_INSTRUCTION_OPCODE(inc);
+ DECLARE_INSTRUCTION_OPCODE(set);
+ DECLARE_INSTRUCTION_OPCODE(put);
+ DECLARE_INSTRUCTION_OPCODE(call);
+ DECLARE_INSTRUCTION_OPCODE(wait);
+ DECLARE_INSTRUCTION_OPCODE(start);
+ DECLARE_INSTRUCTION_OPCODE(sound);
+ DECLARE_INSTRUCTION_OPCODE(move);
+ DECLARE_INSTRUCTION_OPCODE(end);
+
void parseLocation(const char *filename);
virtual bool parseLocationLine(const char *filename, Script *script) = 0;
void changeCursor(int32 index);
@@ -498,6 +574,7 @@ public:
};
+
class Parallaction_ns : public Parallaction {
public: