From 9694215490259a5a7c06d606e909165eb724dd66 Mon Sep 17 00:00:00 2001 From: Nicola Mettifogo Date: Mon, 13 Aug 2007 22:59:13 +0000 Subject: Changed Command parsing/execution and Instruction execution from switch statements into arrays of function pointers. svn-id: r28599 --- engines/parallaction/animation.cpp | 285 ++++++++++++++----------- engines/parallaction/commands.cpp | 415 ++++++++++++++++++++---------------- engines/parallaction/parallaction.h | 77 +++++++ 3 files changed, 477 insertions(+), 300 deletions(-) (limited to 'engines/parallaction') 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: -- cgit v1.2.3