diff options
21 files changed, 3392 insertions, 3205 deletions
diff --git a/engines/parallaction/animation.cpp b/engines/parallaction/animation.cpp deleted file mode 100644 index 47c5454be1..0000000000 --- a/engines/parallaction/animation.cpp +++ /dev/null @@ -1,769 +0,0 @@ -/* 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$ - * - */ - -#include "common/stdafx.h" - -#include "parallaction/parallaction.h" - - -namespace Parallaction { - - -#define INST_ON 1 -#define INST_OFF 2 -#define INST_X 3 -#define INST_Y 4 -#define INST_Z 5 -#define INST_F 6 -#define INST_LOOP 7 -#define INST_ENDLOOP 8 -#define INST_SHOW 9 -#define INST_INC 10 -#define INST_DEC 11 -#define INST_SET 12 -#define INST_PUT 13 -#define INST_CALL 14 -#define INST_WAIT 15 -#define INST_START 16 -#define INST_SOUND 17 -#define INST_MOVE 18 -#define INST_END 19 - - -void wrapLocalVar(LocalVariable *local); - - -#define NUM_LOCALS 10 - -uint16 _numLocals = 0; -char _localNames[NUM_LOCALS][10]; - -Animation *Parallaction::findAnimation(const char *name) { - - for (AnimationList::iterator it = _animations.begin(); it != _animations.end(); it++) - if (!scumm_stricmp((*it)->_label._text, name)) return *it; - - return NULL; -} - -DECLARE_ANIM_PARSER(invalid) { - error("unknown statement '%s' in animation %s", _tokens[0], _locAnimParseCtxt.a->_label._text); -} - - -DECLARE_ANIM_PARSER(script) { - _locAnimParseCtxt.a->_scriptName = strdup(_tokens[1]); -} - - -DECLARE_ANIM_PARSER(commands) { - parseCommands(*_locAnimParseCtxt.script, _locAnimParseCtxt.a->_commands); -} - - -DECLARE_ANIM_PARSER(type) { - if (_tokens[2][0] != '\0') { - _locAnimParseCtxt.a->_type = ((4 + _objectsNames->lookup(_tokens[2])) << 16) & 0xFFFF0000; - } - int16 _si = _zoneTypeNames->lookup(_tokens[1]); - if (_si != Table::notFound) { - _locAnimParseCtxt.a->_type |= 1 << (_si-1); - if (((_locAnimParseCtxt.a->_type & 0xFFFF) != kZoneNone) && ((_locAnimParseCtxt.a->_type & 0xFFFF) != kZoneCommand)) { - parseZoneTypeBlock(*_locAnimParseCtxt.script, _locAnimParseCtxt.a); - } - } - - _locAnimParseCtxt.a->_oldPos.x = -1000; - _locAnimParseCtxt.a->_oldPos.y = -1000; - - _locAnimParseCtxt.a->_flags |= 0x1000000; - - popParserTables(); -} - - -DECLARE_ANIM_PARSER(label) { - renderLabel(&_locAnimParseCtxt.a->_label._cnv, _tokens[1]); -} - - -DECLARE_ANIM_PARSER(flags) { - uint16 _si = 1; - - do { - byte _al = _zoneFlagNames->lookup(_tokens[_si]); - _si++; - _locAnimParseCtxt.a->_flags |= 1 << (_al - 1); - } while (!scumm_stricmp(_tokens[_si++], "|")); -} - - -DECLARE_ANIM_PARSER(file) { - char vC8[200]; - strcpy(vC8, _tokens[1]); - if (_engineFlags & kEngineTransformedDonna) { - if (!scumm_stricmp(_tokens[1], "donnap") || !scumm_stricmp(_tokens[1], "donnapa")) { - strcat(vC8, "tras"); - } - } - _locAnimParseCtxt.a->_cnv = _disk->loadFrames(vC8); -} - - -DECLARE_ANIM_PARSER(position) { - _locAnimParseCtxt.a->_left = atoi(_tokens[1]); - _locAnimParseCtxt.a->_top = atoi(_tokens[2]); - _locAnimParseCtxt.a->_z = atoi(_tokens[3]); -} - - -DECLARE_ANIM_PARSER(moveto) { - _locAnimParseCtxt.a->_moveTo.x = atoi(_tokens[1]); - _locAnimParseCtxt.a->_moveTo.y = atoi(_tokens[2]); -} - - -DECLARE_ANIM_PARSER(endanimation) { - - _locAnimParseCtxt.a->_oldPos.x = -1000; - _locAnimParseCtxt.a->_oldPos.y = -1000; - - _locAnimParseCtxt.a->_flags |= 0x1000000; - - popParserTables(); -} - -Animation *Parallaction::parseAnimation(Script& script, AnimationList &list, char *name) { -// printf("parseAnimation(%s)\n", name); - - Animation *a = new Animation; - - a->_label._text = strdup(name); - - list.push_front(a); - - _locAnimParseCtxt.a = a; - _locAnimParseCtxt.end = false; - _locAnimParseCtxt.script = &script; - - pushParserTables(_locationAnimParsers, _locationAnimStmt); - - return a; -} - - -void Parallaction::freeAnimations() { - _animations.clear(); - return; -} - - - -void jobDisplayAnimations(void *parm, Job *j) { -// printf("jobDisplayAnimations()...\n"); - - Graphics::Surface v14; - - uint16 _si = 0; - - for (AnimationList::iterator it = _vm->_animations.begin(); it != _vm->_animations.end(); it++) { - - Animation *v18 = *it; - - if ((v18->_flags & kFlagsActive) && ((v18->_flags & kFlagsRemove) == 0)) { - v14.w = v18->width(); - v14.h = v18->height(); - - int16 frame = CLIP((int)v18->_frame, 0, v18->getFrameNum()-1); - - v14.pixels = v18->getFrameData(frame); - - if (v18->_flags & kFlagsNoMasked) - _si = 3; - else - _si = _vm->_gfx->queryMask(v18->_top + v18->height()); - - debugC(9, kDebugLocation, "jobDisplayAnimations(%s, x:%i, y:%i, z:%i, w:%i, h:%i, f:%i/%i, %p)", v18->_label._text, v18->_left, v18->_top, _si, v14.w, v14.h, - frame, v18->getFrameNum(), v14.pixels); - _vm->_gfx->blitCnv(&v14, v18->_left, v18->_top, _si, Gfx::kBitBack); - - } - - if (((v18->_flags & kFlagsActive) == 0) && (v18->_flags & kFlagsRemove)) { - v18->_flags &= ~kFlagsRemove; - v18->_oldPos.x = -1000; - } - - if ((v18->_flags & kFlagsActive) && (v18->_flags & kFlagsRemove)) { - v18->_flags &= ~kFlagsActive; - v18->_flags |= kFlagsRemove; - } - - } - -// printf("done\n"); - - return; -} - - -void jobEraseAnimations(void *arg_0, Job *j) { - debugC(3, kDebugJobs, "jobEraseAnimations"); - - for (AnimationList::iterator it = _vm->_animations.begin(); it != _vm->_animations.end(); it++) { - - Animation *a = *it; - - if (((a->_flags & kFlagsActive) == 0) && ((a->_flags & kFlagsRemove) == 0)) continue; - - Common::Rect r(a->width(), a->height()); - r.moveTo(a->_oldPos); - _vm->_gfx->restoreBackground(r); - - if (arg_0) { - a->_oldPos.x = a->_left; - a->_oldPos.y = a->_top; - } - - } - -// printf("done\n"); - - return; -} - - -void Parallaction::loadProgram(Animation *a, char *filename) { -// printf("loadProgram(%s)\n", filename); - - Script *script = _disk->loadScript(filename); - - _numLocals = 0; - - fillBuffers(*script); - - a->_program = new Program; - - Instruction *vCC = new Instruction; - - while (scumm_stricmp(_tokens[0], "endscript")) { - parseScriptLine(vCC, a, a->_program->_locals); - a->_program->_instructions.push_back(vCC); - vCC = new Instruction; - fillBuffers(*script); - } - - // TODO: use List<>::end() to detect the end of the program - vCC->_index = INST_END; - a->_program->_instructions.push_back(vCC); - a->_program->_ip = a->_program->_instructions.begin(); - - delete script; - - return; -} - -int16 findLocal(const char* name, LocalVariable *locals) { - for (uint16 _si = 0; _si < NUM_LOCALS; _si++) { - if (!scumm_stricmp(name, _localNames[_si])) - return _si; - } - - return -1; -} - -int16 addLocal(const char *name, LocalVariable *locals, int16 value = 0, int16 min = -10000, int16 max = 10000) { - assert(_numLocals < NUM_LOCALS); - - strcpy(_localNames[_numLocals], name); - locals[_numLocals]._value = value; - - locals[_numLocals]._min = min; - locals[_numLocals]._max = max; - - return _numLocals++; -} - - -DECLARE_INSTRUCTION_PARSER(animation) { - if (!scumm_stricmp(_tokens[1], _instParseCtxt.a->_label._text)) { - _instParseCtxt.inst->_opBase._a = _instParseCtxt.a; - } else { - _instParseCtxt.inst->_opBase._a = findAnimation(_tokens[1]); - } -} - - -DECLARE_INSTRUCTION_PARSER(loop) { - _instParseCtxt.inst->_opBase._loopCounter = getLValue(_instParseCtxt.inst, _tokens[1], _instParseCtxt.locals, _instParseCtxt.a); -} - - -DECLARE_INSTRUCTION_PARSER(x) { - _instParseCtxt.inst->_opA._pvalue = &_instParseCtxt.a->_left; - _instParseCtxt.inst->_opB = getLValue(_instParseCtxt.inst, _tokens[1], _instParseCtxt.locals, _instParseCtxt.a); -} - - -DECLARE_INSTRUCTION_PARSER(y) { - _instParseCtxt.inst->_opA._pvalue = &_instParseCtxt.a->_top; - _instParseCtxt.inst->_opB = getLValue(_instParseCtxt.inst, _tokens[1], _instParseCtxt.locals, _instParseCtxt.a); -} - - -DECLARE_INSTRUCTION_PARSER(z) { - _instParseCtxt.inst->_opA._pvalue = &_instParseCtxt.a->_z; - _instParseCtxt.inst->_opB = getLValue(_instParseCtxt.inst, _tokens[1], _instParseCtxt.locals, _instParseCtxt.a); -} - - -DECLARE_INSTRUCTION_PARSER(f) { - _instParseCtxt.inst->_opA._pvalue = &_instParseCtxt.a->_frame; - _instParseCtxt.inst->_opB = getLValue(_instParseCtxt.inst, _tokens[1], _instParseCtxt.locals, _instParseCtxt.a); -} - - -DECLARE_INSTRUCTION_PARSER(inc) { - if (!scumm_stricmp(_tokens[1], "X")) { - _instParseCtxt.inst->_opA._pvalue = &_instParseCtxt.a->_left; - } else - if (!scumm_stricmp(_tokens[1], "Y")) { - _instParseCtxt.inst->_opA._pvalue = &_instParseCtxt.a->_top; - } else - if (!scumm_stricmp(_tokens[1], "Z")) { - _instParseCtxt.inst->_opA._pvalue = &_instParseCtxt.a->_z; - } else - if (!scumm_stricmp(_tokens[1], "F")) { - _instParseCtxt.inst->_opA._pvalue = &_instParseCtxt.a->_frame; - } else { - _instParseCtxt.inst->_flags |= kInstUsesLocal; - _instParseCtxt.inst->_opA = getLValue(_instParseCtxt.inst, _tokens[1], _instParseCtxt.locals, _instParseCtxt.a); - } - - _instParseCtxt.inst->_opB = getLValue(_instParseCtxt.inst, _tokens[2], _instParseCtxt.locals, _instParseCtxt.a); - - if (!scumm_stricmp(_tokens[3], "mod")) { - _instParseCtxt.inst->_flags |= kInstMod; - } -} - - -DECLARE_INSTRUCTION_PARSER(set) { - // WORKAROUND: At least one script (balzo.script) in Amiga versions didn't declare - // local variables before using them, thus leading to crashes. The line launching the - // script was commented out on Dos version. This workaround enables the engine - // to dynamically add a local variable when it is encountered the first time in - // the script, so should fix any other occurrence as well. - if (findLocal(_tokens[1], _instParseCtxt.locals) == -1) { - addLocal(_tokens[1], _instParseCtxt.locals); - } - - _instParseCtxt.inst->_opA = getLValue(_instParseCtxt.inst, _tokens[1], _instParseCtxt.locals, _instParseCtxt.a); - _instParseCtxt.inst->_flags |= kInstUsesLocal; - _instParseCtxt.inst->_opB = getLValue(_instParseCtxt.inst, _tokens[2], _instParseCtxt.locals, _instParseCtxt.a); -} - - -DECLARE_INSTRUCTION_PARSER(move) { - _instParseCtxt.inst->_opA = getLValue(_instParseCtxt.inst, _tokens[1], _instParseCtxt.locals, _instParseCtxt.a); - _instParseCtxt.inst->_opB = getLValue(_instParseCtxt.inst, _tokens[2], _instParseCtxt.locals, _instParseCtxt.a); -} - - -DECLARE_INSTRUCTION_PARSER(put) { - if (!scumm_stricmp(_tokens[1], _instParseCtxt.a->_label._text)) { - _instParseCtxt.inst->_opBase._a = _instParseCtxt.a; - } else { - _instParseCtxt.inst->_opBase._a = findAnimation(_tokens[1]); - } - - _instParseCtxt.inst->_opA = getLValue(_instParseCtxt.inst, _tokens[2], _instParseCtxt.locals, _instParseCtxt.a); - _instParseCtxt.inst->_opB = getLValue(_instParseCtxt.inst, _tokens[3], _instParseCtxt.locals, _instParseCtxt.a); - if (!scumm_stricmp(_tokens[4], "masked")) { - _instParseCtxt.inst->_flags |= kInstMaskedPut; - } -} - - -DECLARE_INSTRUCTION_PARSER(call) { - int index = _callableNames->lookup(_tokens[1]); - if (index == Table::notFound) - error("unknown callable '%s'", _tokens[1]); - _instParseCtxt.inst->_opBase._index = index - 1; -} - - -DECLARE_INSTRUCTION_PARSER(sound) { - _instParseCtxt.inst->_opBase._z = findZone(_tokens[1]); -} - - -DECLARE_INSTRUCTION_PARSER(null) { - -} - - -DECLARE_INSTRUCTION_PARSER(defLocal) { - int16 val = atoi(_tokens[2]); - int16 index; - - if (_tokens[3][0] != '\0') { - index = addLocal(_tokens[0], _instParseCtxt.locals, val, atoi(_tokens[3]), atoi(_tokens[4])); - } else { - index = addLocal(_tokens[0], _instParseCtxt.locals, val); - } - - _instParseCtxt.inst->_opA._local = &_instParseCtxt.locals[index]; - _instParseCtxt.inst->_opB._value = _instParseCtxt.locals[index]._value; - - _instParseCtxt.inst->_flags = kInstUsesLiteral | kInstUsesLocal; - _instParseCtxt.inst->_index = INST_SET; -} - - - - -void Parallaction::parseScriptLine(Instruction *inst, Animation *a, LocalVariable *locals) { -// printf("parseScriptLine()\n"); - - if (_tokens[0][1] == '.') { - _tokens[0][1] = '\0'; - a = findAnimation(&_tokens[0][2]); - } - - if (_tokens[1][1] == '.') { - _tokens[1][1] = '\0'; - a = findAnimation(&_tokens[1][2]); - } - - int16 _si = _instructionNames->lookup(_tokens[0]); - inst->_index = _si; - - _instParseCtxt.a = a; - _instParseCtxt.inst = inst; - _instParseCtxt.locals = locals; - - (this->*_instructionParsers[inst->_index])(); - - return; -} - -LValue Parallaction::getLValue(Instruction *inst, char *str, LocalVariable *locals, Animation *a) { - - LValue v; - - v._pvalue = 0; // should stop compiler from complaining - - if (isdigit(str[0]) || str[0] == '-') { - inst->_flags |= kInstUsesLiteral; - v._value = atoi(str); - return v; - } - - int index = findLocal(str, locals); - if (index != -1) { - v._local = &locals[index]; - return v; - } - - if (str[1] == '.') { - a = findAnimation(&str[2]); - } - - if (str[0] == 'X') { - v._pvalue = &a->_left; - } else - if (str[0] == 'Y') { - v._pvalue = &a->_top; - } else - if (str[0] == 'Z') { - v._pvalue = &a->_z; - } else - if (str[0] == 'F') { - v._pvalue = &a->_frame; - } - - return v; -} - - -DECLARE_INSTRUCTION_OPCODE(on) { - (*_instRunCtxt.inst)->_opBase._a->_flags |= kFlagsActive; - (*_instRunCtxt.inst)->_opBase._a->_flags &= ~kFlagsRemove; -} - - -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); - } -} - -DECLARE_INSTRUCTION_OPCODE(null) { - -} - -DECLARE_INSTRUCTION_OPCODE(invalid) { - error("Can't execute invalid opcode %i", (*_instRunCtxt.inst)->_index); -} - -DECLARE_INSTRUCTION_OPCODE(call) { - callFunction((*_instRunCtxt.inst)->_opBase._index, 0); -} - - -DECLARE_INSTRUCTION_OPCODE(wait) { - if (_engineFlags & kEngineWalking) - _instRunCtxt.suspend = true; -} - - -DECLARE_INSTRUCTION_OPCODE(start) { -// v1C = (*_instRunCtxt.inst)->_opBase; - (*_instRunCtxt.inst)->_opBase._a->_flags |= (kFlagsActing | kFlagsActive); -} - - -DECLARE_INSTRUCTION_OPCODE(sound) { - _activeZone = (*_instRunCtxt.inst)->_opBase._z; -} - - -DECLARE_INSTRUCTION_OPCODE(move) { - WalkNodeList *v4 = _char._builder.buildPath(*(*_instRunCtxt.inst)->_opA._pvalue, *(*_instRunCtxt.inst)->_opB._pvalue); - addJob(&jobWalk, v4, kPriority19 ); - _engineFlags |= kEngineWalking; -} - -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(); - - _instRunCtxt.suspend = true; -} - - - -void jobRunScripts(void *parm, Job *j) { - debugC(3, kDebugJobs, "jobRunScripts"); - - static uint16 modCounter = 0; - - for (AnimationList::iterator it = _vm->_animations.begin(); it != _vm->_animations.end(); it++) { - - 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])(); - - inst = _vm->_instRunCtxt.inst; // handles endloop correctly - - if (_vm->_instRunCtxt.suspend) - goto label1; - - inst++; - } - - a->_program->_ip = ++inst; - -label1: - if (a->_flags & kFlagsCharacter) - a->_z = a->_top + a->height(); - } - - _vm->sortAnimations(); - modCounter++; - - return; -} - -void wrapLocalVar(LocalVariable *local) { -// printf("wrapLocalVar(v: %i, min: %i, max: %i)\n", local->_value, local->_min, local->_max); - - if (local->_value >= local->_max) - local->_value = local->_min; - if (local->_value < local->_min) - local->_value = local->_max - 1; - - return; -} - -int compareAnimationZ(const AnimationPointer &a1, const AnimationPointer &a2) { - if (a1->_z == a2->_z) return 0; - return (a1->_z < a2->_z ? -1 : 1); -} - - -void Parallaction::sortAnimations() { - _char._ani._z = _char._ani.height() + _char._ani._top; - _animations.sort(compareAnimationZ); - return; -} - -Animation::Animation() { - _cnv = NULL; - _program = NULL; - _scriptName = 0; - _frame = 0; - _z = 0; -} - -Animation::~Animation() { - if (_program) - delete _program; - - if (_scriptName) - free(_scriptName); - - if (_cnv) - delete _cnv; -} - -uint16 Animation::width() const { - if (!_cnv) return 0; - return _cnv->_width; -} - -uint16 Animation::height() const { - if (!_cnv) return 0; - return _cnv->_height; -} - -uint16 Animation::getFrameNum() const { - if (!_cnv) return 0; - return _cnv->_count; -} - -byte* Animation::getFrameData(uint32 index) const { - if (!_cnv) return NULL; - return _cnv->getFramePtr(index); -} - - -Program::Program() { - _loopCounter = 0; - _locals = new LocalVariable[10]; -} - -Program::~Program() { - delete[] _locals; -} - - -} // namespace Parallaction diff --git a/engines/parallaction/commands.cpp b/engines/parallaction/commands.cpp deleted file mode 100644 index 41deaf49a0..0000000000 --- a/engines/parallaction/commands.cpp +++ /dev/null @@ -1,421 +0,0 @@ -/* 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$ - * - */ - -#include "common/stdafx.h" - -#include "parallaction/parallaction.h" - - -namespace Parallaction { - -#define CMD_SET 1 -#define CMD_CLEAR 2 -#define CMD_START 3 -#define CMD_SPEAK 4 -#define CMD_GET 5 -#define CMD_LOCATION 6 -#define CMD_OPEN 7 -#define CMD_CLOSE 8 -#define CMD_ON 9 -#define CMD_OFF 10 -#define CMD_CALL 11 -#define CMD_TOGGLE 12 -#define CMD_DROP 13 -#define CMD_QUIT 14 -#define CMD_MOVE 15 -#define CMD_STOP 16 - -DECLARE_COMMAND_PARSER(flags) { - createCommand(_lookup); - - if (_globalTable->lookup(_tokens[1]) == Table::notFound) { - 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--; - } - - parseCommandFlags(); - addCommand(); -} - - -DECLARE_COMMAND_PARSER(animation) { - createCommand(_lookup); - - _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++; - } - - parseCommandFlags(); - addCommand(); -} - - -DECLARE_COMMAND_PARSER(zone) { - createCommand(_lookup); - - _cmdParseCtxt.cmd->u._zone = findZone(_tokens[_cmdParseCtxt.nextToken]); - _cmdParseCtxt.nextToken++; - - parseCommandFlags(); - addCommand(); -} - - -DECLARE_COMMAND_PARSER(location) { - createCommand(_lookup); - - _cmdParseCtxt.cmd->u._string = (char*)malloc(strlen(_tokens[_cmdParseCtxt.nextToken])+1); - strcpy(_cmdParseCtxt.cmd->u._string, _tokens[_cmdParseCtxt.nextToken]); - _cmdParseCtxt.nextToken++; - - parseCommandFlags(); - addCommand(); -} - - -DECLARE_COMMAND_PARSER(drop) { - createCommand(_lookup); - - _cmdParseCtxt.cmd->u._object = _objectsNames->lookup(_tokens[_cmdParseCtxt.nextToken]); - _cmdParseCtxt.nextToken++; - - parseCommandFlags(); - addCommand(); -} - - -DECLARE_COMMAND_PARSER(call) { - createCommand(_lookup); - - _cmdParseCtxt.cmd->u._callable = _callableNames->lookup(_tokens[_cmdParseCtxt.nextToken]) - 1; - _cmdParseCtxt.nextToken++; - - parseCommandFlags(); - addCommand(); -} - - -DECLARE_COMMAND_PARSER(null) { -} - - -DECLARE_COMMAND_PARSER(move) { - createCommand(_lookup); - - _cmdParseCtxt.cmd->u._move._x = atoi(_tokens[_cmdParseCtxt.nextToken]); - _cmdParseCtxt.nextToken++; - _cmdParseCtxt.cmd->u._move._y = atoi(_tokens[_cmdParseCtxt.nextToken]); - _cmdParseCtxt.nextToken++; - - parseCommandFlags(); - addCommand(); -} - -DECLARE_COMMAND_PARSER(invalid) { - error("Can't parse unknown command '%s'", _tokens[0]); -} - -DECLARE_COMMAND_PARSER(endcommands) { - popParserTables(); -} - -void Parallaction::parseCommandFlags() { - - int _si = _cmdParseCtxt.nextToken; - Command *cmd = _cmdParseCtxt.cmd; - - if (!scumm_stricmp(_tokens[_si], "flags")) { - _si++; - - do { - if (!scumm_stricmp(_tokens[_si], "exit") || !scumm_stricmp(_tokens[_si], "exittrap")) { - cmd->_flagsOn |= kFlagsExit; - } else - if (!scumm_stricmp(_tokens[_si], "enter") || !scumm_stricmp(_tokens[_si], "entertrap")) { - cmd->_flagsOn |= kFlagsEnter; - } else - if (!scumm_strnicmp(_tokens[_si], "no", 2)) { - byte _al = _localFlagNames->lookup(&_tokens[_si][2]); - cmd->_flagsOff |= 1 << (_al - 1); - } else { - byte _al = _localFlagNames->lookup(_tokens[_si]); - cmd->_flagsOn |= 1 << (_al - 1); - } - - _si++; - - } while (!scumm_stricmp(_tokens[_si++], "|")); - - } - - if (!scumm_stricmp(_tokens[_si], "gflags")) { - _si++; - cmd->_flagsOn |= kFlagsGlobal; - - do { - if (!scumm_stricmp(_tokens[_si], "exit")) { - cmd->_flagsOn |= kFlagsExit; - } else - if (!scumm_stricmp(_tokens[_si], "enter")) { - cmd->_flagsOn |= kFlagsEnter; - } else - if (!scumm_strnicmp(_tokens[_si], "no", 2)) { - byte _al = _globalTable->lookup(&_tokens[_si][2]); - cmd->_flagsOff |= 1 << (_al - 1); - } else { - byte _al = _globalTable->lookup(_tokens[_si]); - cmd->_flagsOn |= 1 << (_al - 1); - } - - _si++; - - } while (!scumm_stricmp(_tokens[_si++], "|")); - - } - - _si = _cmdParseCtxt.nextToken; - -} - -void Parallaction::addCommand() { - - // FIXME: implement a proper parseCommands for BRA - if (getGameType() == GType_BRA) - delete _cmdParseCtxt.cmd; - else - _cmdParseCtxt.list->push_front(_cmdParseCtxt.cmd); // NOTE: command lists are written backwards in scripts - -} - -void Parallaction::createCommand(uint id) { - - _cmdParseCtxt.nextToken = 1; - _cmdParseCtxt.cmd = new Command; - _cmdParseCtxt.cmd->_id = id; - -} - -void Parallaction::parseCommands(Script &script, CommandList& list) { - - _cmdParseCtxt.list = &list; - _cmdParseCtxt.end = false; - - pushParserTables(_commandParsers, _commandsNames); - -} - -DECLARE_COMMAND_OPCODE(invalid) { - error("Can't execute invalid command '%i'", _cmdRunCtxt.cmd->_id); -} - -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; - } -} - - -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; - } -} - - -DECLARE_COMMAND_OPCODE(start) { - _cmdRunCtxt.cmd->u._animation->_flags |= kFlagsActing; -} - - -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 ); - } - } -} - - -DECLARE_COMMAND_OPCODE(off) { - _cmdRunCtxt.cmd->u._zone->_flags |= kFlagsRemove; -} - - -DECLARE_COMMAND_OPCODE(call) { - callFunction(_cmdRunCtxt.cmd->u._callable, _cmdRunCtxt.z); -} - - -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; - } -} - - -DECLARE_COMMAND_OPCODE(drop){ - dropItem( _cmdRunCtxt.cmd->u._object ); -} - - -DECLARE_COMMAND_OPCODE(quit) { - _engineFlags |= kEngineQuit; -} - - -DECLARE_COMMAND_OPCODE(move) { - if ((_char._ani._flags & kFlagsRemove) || (_char._ani._flags & kFlagsActive) == 0) { - return; - } - - WalkNodeList *vC = _char._builder.buildPath(_cmdRunCtxt.cmd->u._move._x, _cmdRunCtxt.cmd->u._move._y); - - addJob(&jobWalk, vC, kPriority19 ); - _engineFlags |= kEngineWalking; -} - - -DECLARE_COMMAND_OPCODE(stop) { - _cmdRunCtxt.cmd->u._animation->_flags &= ~kFlagsActing; -} - - - - -void Parallaction::runCommands(CommandList& list, Zone *z) { - debugC(1, kDebugLocation, "runCommands"); - - 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])(); - } - - debugC(1, kDebugLocation, "runCommands completed"); - - return; - -} - -Command::Command() { - _id = 0; - _flagsOn = 0; - _flagsOff = 0; -} - -Command::~Command() { - -} - -} // namespace Parallaction - - - diff --git a/engines/parallaction/commands.h b/engines/parallaction/commands.h deleted file mode 100644 index 6db194d8c7..0000000000 --- a/engines/parallaction/commands.h +++ /dev/null @@ -1,92 +0,0 @@ -/* 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 PARALLACTION_COMMANDS_H -#define PARALLACTION_COMMANDS_H - - -#include "common/stdafx.h" -#include "common/scummsys.h" - -#include "parallaction/defs.h" - -namespace Parallaction { - -enum CommandFlags { - kFlagsVisited = 1, - kFlagsExit = 0x10000000, - kFlagsEnter = 0x20000000, - kFlagsGlobal = 0x40000000 -}; - -struct Zone; -struct Animation; - - -// TODO: turn this into a struct -struct CommandData { - uint32 _flags; - Animation * _animation; - Zone* _zone; - char* _string; - uint16 _callable; - uint16 _object; - struct { - int16 _x; - int16 _y; - } _move; - - CommandData() { - _flags = 0; - _animation = 0; - _zone = 0; - _string = 0; - _callable = 0; - _object = 0; - _move._x = 0; - _move._y = 0; - } - - ~CommandData() { - if (_string) - free(_string); - } -}; - -struct Command { - uint16 _id; - CommandData u; - uint32 _flagsOn; - uint32 _flagsOff; - - Command(); - ~Command(); -}; - -typedef ManagedList<Command*> CommandList; - -} // namespace Parallaction - -#endif diff --git a/engines/parallaction/dialogue.cpp b/engines/parallaction/dialogue.cpp index 93f2054c9e..33d109842d 100644 --- a/engines/parallaction/dialogue.cpp +++ b/engines/parallaction/dialogue.cpp @@ -56,132 +56,6 @@ int16 _answerBalloonH[10] = { 0 }; -Dialogue *Parallaction::parseDialogue(Script &script) { -// printf("parseDialogue()\n"); - uint16 numQuestions = 0; - - Dialogue *dialogue = new Dialogue; - - Table forwards(20); - - fillBuffers(script, true); - - while (scumm_stricmp(_tokens[0], "enddialogue")) { - if (scumm_stricmp(_tokens[0], "Question")) continue; - - Question *question = new Question; - dialogue->_questions[numQuestions] = question; - - forwards.addData(_tokens[1]); - - question->_text = parseDialogueString(script); - - fillBuffers(script, true); - question->_mood = atoi(_tokens[0]); - - uint16 numAnswers = 0; - - fillBuffers(script, true); - while (scumm_stricmp(_tokens[0], "endquestion")) { // parse answers - - Answer *answer = new Answer; - question->_answers[numAnswers] = answer; - - if (_tokens[1][0]) { - - Table* flagNames; - uint16 token; - - if (!scumm_stricmp(_tokens[1], "global")) { - token = 2; - flagNames = _globalTable; - answer->_yesFlags |= kFlagsGlobal; - } else { - token = 1; - flagNames = _localFlagNames; - } - - do { - - if (!scumm_strnicmp(_tokens[token], "no", 2)) { - byte _al = flagNames->lookup(_tokens[token]+2); - answer->_noFlags |= 1 << (_al - 1); - } else { - byte _al = flagNames->lookup(_tokens[token]); - answer->_yesFlags |= 1 << (_al - 1); - } - - token++; - - } while (!scumm_stricmp(_tokens[token++], "|")); - - } - - answer->_text = parseDialogueString(script); - - fillBuffers(script, true); - answer->_mood = atoi(_tokens[0]); - answer->_following._name = parseDialogueString(script); - - fillBuffers(script, true); - if (!scumm_stricmp(_tokens[0], "commands")) { - parseCommands(script, answer->_commands); - fillBuffers(script, true); - } - - numAnswers++; - } - - fillBuffers(script, true); - numQuestions++; - - } - - // link questions - byte v50[20]; - memset(v50, 0, 20); - - for (uint16 i = 0; i < numQuestions; i++) { - Question *question = dialogue->_questions[i]; - - for (uint16 j = 0; j < NUM_ANSWERS; j++) { - Answer *answer = question->_answers[j]; - if (answer == 0) continue; - - int16 index = forwards.lookup(answer->_following._name); - free(answer->_following._name); - - if (index == Table::notFound) - answer->_following._question = 0; - else - answer->_following._question = dialogue->_questions[index - 1]; - - - } - } - - return dialogue; -} - - -char *Parallaction::parseDialogueString(Script &script) { - - char vC8[200]; - char *vD0 = NULL; - do { - - vD0 = script.readLine(vC8, 200); - if (vD0 == 0) return NULL; - - vD0 = Common::ltrim(vD0); - - } while (strlen(vD0) == 0); - - vD0[strlen(vD0)-1] = '\0'; // deletes the trailing '0xA' - // this is critical for Gfx::displayWrappedString to work properly - return strdup(vD0); -} - class DialogueManager { Parallaction *_vm; @@ -502,34 +376,5 @@ void Parallaction::runDialogue(SpeakData *data) { return; } -Answer::Answer() { - _text = NULL; - _mood = 0; - _following._question = NULL; - _noFlags = 0; - _yesFlags = 0; -} - -Answer::~Answer() { - if (_text) - free(_text); -} - -Question::Question() { - _text = NULL; - _mood = 0; - - for (uint32 i = 0; i < NUM_ANSWERS; i++) - _answers[i] = NULL; - -} - -Question::~Question() { - - for (uint32 i = 0; i < NUM_ANSWERS; i++) - if (_answers[i]) delete _answers[i]; - - free(_text); -} } // namespace Parallaction diff --git a/engines/parallaction/disk_br.cpp b/engines/parallaction/disk_br.cpp index 9e301a66c3..4853a9fb1a 100644 --- a/engines/parallaction/disk_br.cpp +++ b/engines/parallaction/disk_br.cpp @@ -102,7 +102,15 @@ Script* DosDisk_br::loadLocation(const char *name) { Script* DosDisk_br::loadScript(const char* name) { debugC(5, kDebugDisk, "DosDisk_br::loadScript"); - return 0; + + Common::File *stream = new Common::File; + + char path[PATH_LEN]; + sprintf(path, "%s/scripts/%s.scr", _partPath, name); + if (!stream->open(path)) + errorFileNotFound(path); + + return new Script(stream, true); } // there are no Head resources in Big Red Adventure @@ -275,7 +283,7 @@ Table* DosDisk_br::loadTable(const char* name) { stream.close(); - return 0; + return t; } Common::SeekableReadStream* DosDisk_br::loadMusic(const char* name) { diff --git a/engines/parallaction/exec_ns.cpp b/engines/parallaction/exec_ns.cpp new file mode 100644 index 0000000000..b3f90cc09b --- /dev/null +++ b/engines/parallaction/exec_ns.cpp @@ -0,0 +1,857 @@ +/* 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$ + * + */ + +#include "common/stdafx.h" +#include "parallaction/parallaction.h" +#include "parallaction/sound.h" + + +namespace Parallaction { + +#define INST_ON 1 +#define INST_OFF 2 +#define INST_X 3 +#define INST_Y 4 +#define INST_Z 5 +#define INST_F 6 +#define INST_LOOP 7 +#define INST_ENDLOOP 8 +#define INST_SHOW 9 +#define INST_INC 10 +#define INST_DEC 11 +#define INST_SET 12 +#define INST_PUT 13 +#define INST_CALL 14 +#define INST_WAIT 15 +#define INST_START 16 +#define INST_SOUND 17 +#define INST_MOVE 18 +#define INST_END 19 + + +typedef OpcodeImpl<Parallaction_ns> OpcodeV1; +#define COMMAND_OPCODE(op) OpcodeV1(this, &Parallaction_ns::cmdOp_##op) +#define DECLARE_COMMAND_OPCODE(op) void Parallaction_ns::cmdOp_##op() + +#define INSTRUCTION_OPCODE(op) OpcodeV1(this, &Parallaction_ns::instOp_##op) +#define DECLARE_INSTRUCTION_OPCODE(op) void Parallaction_ns::instOp_##op() + + + + +DECLARE_INSTRUCTION_OPCODE(on) { + (*_instRunCtxt.inst)->_opBase._a->_flags |= kFlagsActive; + (*_instRunCtxt.inst)->_opBase._a->_flags &= ~kFlagsRemove; +} + + +DECLARE_INSTRUCTION_OPCODE(off) { + (*_instRunCtxt.inst)->_opBase._a->_flags |= kFlagsRemove; +} + + +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); + } +} + +DECLARE_INSTRUCTION_OPCODE(null) { + +} + +DECLARE_INSTRUCTION_OPCODE(invalid) { + error("Can't execute invalid opcode %i", (*_instRunCtxt.inst)->_index); +} + +DECLARE_INSTRUCTION_OPCODE(call) { + callFunction((*_instRunCtxt.inst)->_opBase._index, 0); +} + + +DECLARE_INSTRUCTION_OPCODE(wait) { + if (_engineFlags & kEngineWalking) + _instRunCtxt.suspend = true; +} + + +DECLARE_INSTRUCTION_OPCODE(start) { + (*_instRunCtxt.inst)->_opBase._a->_flags |= (kFlagsActing | kFlagsActive); +} + + +DECLARE_INSTRUCTION_OPCODE(sound) { + _activeZone = (*_instRunCtxt.inst)->_opBase._z; +} + + +DECLARE_INSTRUCTION_OPCODE(move) { + WalkNodeList *v4 = _char._builder.buildPath(*(*_instRunCtxt.inst)->_opA._pvalue, *(*_instRunCtxt.inst)->_opB._pvalue); + addJob(&jobWalk, v4, kPriority19 ); + _engineFlags |= kEngineWalking; +} + +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(); + + _instRunCtxt.suspend = true; +} + + + +void Parallaction_ns::wrapLocalVar(LocalVariable *local) { + + if (local->_value >= local->_max) + local->_value = local->_min; + if (local->_value < local->_min) + local->_value = local->_max - 1; + + return; +} + + +DECLARE_COMMAND_OPCODE(invalid) { + error("Can't execute invalid command '%i'", _cmdRunCtxt.cmd->_id); +} + +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; + } +} + + +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; + } +} + + +DECLARE_COMMAND_OPCODE(start) { + _cmdRunCtxt.cmd->u._animation->_flags |= kFlagsActing; +} + + +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 ); + } + } +} + + +DECLARE_COMMAND_OPCODE(off) { + _cmdRunCtxt.cmd->u._zone->_flags |= kFlagsRemove; +} + + +DECLARE_COMMAND_OPCODE(call) { + callFunction(_cmdRunCtxt.cmd->u._callable, _cmdRunCtxt.z); +} + + +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; + } +} + + +DECLARE_COMMAND_OPCODE(drop){ + dropItem( _cmdRunCtxt.cmd->u._object ); +} + + +DECLARE_COMMAND_OPCODE(quit) { + _engineFlags |= kEngineQuit; +} + + +DECLARE_COMMAND_OPCODE(move) { + if ((_char._ani._flags & kFlagsRemove) || (_char._ani._flags & kFlagsActive) == 0) { + return; + } + + WalkNodeList *vC = _char._builder.buildPath(_cmdRunCtxt.cmd->u._move.x, _cmdRunCtxt.cmd->u._move.y); + + addJob(&jobWalk, vC, kPriority19 ); + _engineFlags |= kEngineWalking; +} + + +DECLARE_COMMAND_OPCODE(stop) { + _cmdRunCtxt.cmd->u._animation->_flags &= ~kFlagsActing; +} + + +void jobDisplayAnimations(void *parm, Job *j) { + + Graphics::Surface v14; + + uint16 _si = 0; + + for (AnimationList::iterator it = _vm->_animations.begin(); it != _vm->_animations.end(); it++) { + + Animation *v18 = *it; + + if ((v18->_flags & kFlagsActive) && ((v18->_flags & kFlagsRemove) == 0)) { + v14.w = v18->width(); + v14.h = v18->height(); + + int16 frame = CLIP((int)v18->_frame, 0, v18->getFrameNum()-1); + + v14.pixels = v18->getFrameData(frame); + + if (v18->_flags & kFlagsNoMasked) + _si = 3; + else + _si = _vm->_gfx->queryMask(v18->_top + v18->height()); + + debugC(9, kDebugLocation, "jobDisplayAnimations(%s, x:%i, y:%i, z:%i, w:%i, h:%i, f:%i/%i, %p)", v18->_label._text, v18->_left, v18->_top, _si, v14.w, v14.h, + frame, v18->getFrameNum(), v14.pixels); + _vm->_gfx->blitCnv(&v14, v18->_left, v18->_top, _si, Gfx::kBitBack); + + } + + if (((v18->_flags & kFlagsActive) == 0) && (v18->_flags & kFlagsRemove)) { + v18->_flags &= ~kFlagsRemove; + v18->_oldPos.x = -1000; + } + + if ((v18->_flags & kFlagsActive) && (v18->_flags & kFlagsRemove)) { + v18->_flags &= ~kFlagsActive; + v18->_flags |= kFlagsRemove; + } + + } + +// printf("done\n"); + + return; +} + + +void jobEraseAnimations(void *arg_0, Job *j) { + debugC(3, kDebugJobs, "jobEraseAnimations"); + + for (AnimationList::iterator it = _vm->_animations.begin(); it != _vm->_animations.end(); it++) { + + Animation *a = *it; + + if (((a->_flags & kFlagsActive) == 0) && ((a->_flags & kFlagsRemove) == 0)) continue; + + Common::Rect r(a->width(), a->height()); + r.moveTo(a->_oldPos); + _vm->_gfx->restoreBackground(r); + + if (arg_0) { + a->_oldPos.x = a->_left; + a->_oldPos.y = a->_top; + } + + } + + return; +} + + +void jobRunScripts(void *parm, Job *j) { + debugC(3, kDebugJobs, "jobRunScripts"); + + static uint16 modCounter = 0; + + for (AnimationList::iterator it = _vm->_animations.begin(); it != _vm->_animations.end(); it++) { + + 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->_instructionOpcodes[(*inst)->_index])(); + + inst = _vm->_instRunCtxt.inst; // handles endloop correctly + + if (_vm->_instRunCtxt.suspend) + goto label1; + + inst++; + } + + a->_program->_ip = ++inst; + +label1: + if (a->_flags & kFlagsCharacter) + a->_z = a->_top + a->height(); + } + + _vm->sortAnimations(); + modCounter++; + + return; +} + + +void Parallaction::runCommands(CommandList& list, Zone *z) { + debugC(1, kDebugLocation, "runCommands"); + + 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[%i]: %s (on: %x, off: %x)", cmd->_id, _commandsNamesRes[cmd->_id-1], cmd->_flagsOn, cmd->_flagsOff); + + _cmdRunCtxt.z = z; + _cmdRunCtxt.cmd = cmd; + + (*_commandOpcodes[cmd->_id])(); + } + + debugC(1, kDebugLocation, "runCommands completed"); + + return; + +} + + + + +// displays character head commenting an examined object +// +// works on the frontbuffer +// +void Parallaction::displayCharacterComment(ExamineData *data) { + if (data->_description == NULL) return; + + // NOTE: saving visible screen before displaying comment allows + // to restore the exact situation after the comment is deleted. + // This means animations are restored in the exact position as + // they were, thus avoiding clipping effect as signalled in + // BUG item #1762614. + _gfx->copyScreen(Gfx::kBitFront, Gfx::kBitBack); + + _gfx->setFont(_dialogueFont); + _gfx->flatBlitCnv(_char._talk, 0, 190, 80, Gfx::kBitFront); + + int16 v26, v28; + _gfx->getStringExtent(data->_description, 130, &v28, &v26); + Common::Rect r(v28, v26); + r.moveTo(140, 10); + _gfx->drawBalloon(r, 0); + _gfx->displayWrappedString(data->_description, 140, 10, 0, 130); + + waitUntilLeftClick(); + + _gfx->copyScreen(Gfx::kBitBack, Gfx::kBitFront); + _gfx->updateScreen(); + + return; +} + +// +// ZONE TYPE: EXAMINE +// + +// display detail view of an item (and eventually comments) +// +// works on the frontbuffer +// + +void Parallaction::displayItemComment(ExamineData *data) { + + if (data->_description == NULL) return; + + _gfx->setHalfbriteMode(true); + + char v68[PATH_LEN]; + strcpy(v68, data->_filename); + data->_cnv = _disk->loadStatic(v68); + _gfx->flatBlitCnv(data->_cnv, 140, (_screenHeight - data->_cnv->h)/2, Gfx::kBitFront); + delete data->_cnv; + + int16 v6A = 0, v6C = 0; + + _gfx->setFont(_dialogueFont); + _gfx->getStringExtent(data->_description, 130, &v6C, &v6A); + Common::Rect r(v6C, v6A); + r.moveTo(0, 90); + _gfx->drawBalloon(r, 0); + _gfx->flatBlitCnv(_char._head, 100, 152, Gfx::kBitFront); + _gfx->displayWrappedString(data->_description, 0, 90, 0, 130); + + jobEraseAnimations((void*)1, NULL); + _gfx->updateScreen(); + + waitUntilLeftClick(); + + _gfx->setHalfbriteMode(false); + _gfx->copyScreen(Gfx::kBitBack, Gfx::kBitFront); + _gfx->updateScreen(); + + return; +} + + + +uint16 Parallaction::runZone(Zone *z) { + debugC(3, kDebugLocation, "runZone (%s)", z->_label._text); + + uint16 subtype = z->_type & 0xFFFF; + + debugC(3, kDebugLocation, "type = %x, object = %x", subtype, (z->_type & 0xFFFF0000) >> 16); + switch(subtype) { + + case kZoneExamine: + if (z->u.examine->_filename) { + displayItemComment(z->u.examine); + } else { + displayCharacterComment(z->u.examine); + } + break; + + case kZoneGet: + if (z->_flags & kFlagsFixed) break; + if (pickupItem(z) != 0) { + return 1; + } + z->_flags |= kFlagsRemove; + break; + + case kZoneDoor: + if (z->_flags & kFlagsLocked) break; + z->_flags ^= kFlagsClosed; + if (z->u.door->_cnv == NULL) break; + addJob(&jobToggleDoor, z, kPriority18 ); + break; + + case kZoneHear: + _soundMan->playSfx(z->u.hear->_name, z->u.hear->_channel, (z->_flags & kFlagsLooping) == kFlagsLooping, 60); + break; + + case kZoneSpeak: + runDialogue(z->u.speak); + break; + + } + + debugC(3, kDebugLocation, "runZone completed"); + + return 0; +} + +// +// ZONE TYPE: DOOR +// +void jobToggleDoor(void *parm, Job *j) { + + static byte count = 0; + + Zone *z = (Zone*)parm; + + if (z->u.door->_cnv) { + Common::Rect r(z->_left, z->_top, z->_left+z->u.door->_cnv->_width, z->_top+z->u.door->_cnv->_height); + + uint16 _ax = (z->_flags & kFlagsClosed ? 1 : 0); + _vm->_gfx->restoreDoorBackground(r, z->u.door->_cnv->getFramePtr(_ax), z->u.door->_background); + + _ax = (z->_flags & kFlagsClosed ? 0 : 1); + _vm->_gfx->flatBlitCnv(z->u.door->_cnv, _ax, z->_left, z->_top, Gfx::kBitBack); + _vm->_gfx->flatBlitCnv(z->u.door->_cnv, _ax, z->_left, z->_top, Gfx::kBit2); + } + + count++; + if (count == 2) { + j->_finished = 1; + count = 0; + } + + return; +} + + + +// +// ZONE TYPE: GET +// + +int16 Parallaction::pickupItem(Zone *z) { + int r = addInventoryItem(z->u.get->_icon); + if (r == 0) + addJob(&jobRemovePickedItem, z, kPriority17 ); + + return r; +} + +void jobRemovePickedItem(void *parm, Job *j) { + + Zone *z = (Zone*)parm; + + static uint16 count = 0; + + if (z->u.get->_cnv) { + Common::Rect r(z->_left, z->_top, z->_left + z->u.get->_cnv->w, z->_top + z->u.get->_cnv->h); + + _vm->_gfx->restoreGetBackground(r, z->u.get->_backup); + } + + count++; + if (count == 2) { + count = 0; + j->_finished = 1; + } + + return; +} + +void jobDisplayDroppedItem(void *parm, Job *j) { +// printf("jobDisplayDroppedItem..."); + + Zone *z = (Zone*)parm; + + if (z->u.get->_cnv) { + if (j->_count == 0) { + _vm->_gfx->backupGetBackground(z->u.get, z->_left, z->_top); + } + + _vm->_gfx->flatBlitCnv(z->u.get->_cnv, z->_left, z->_top, Gfx::kBitBack); + _vm->_gfx->flatBlitCnv(z->u.get->_cnv, z->_left, z->_top, Gfx::kBit2); + } + + j->_count++; + if (j->_count == 2) { + j->_count = 0; + j->_finished = 1; + } + +// printf("done"); + + return; +} + + + + +Zone *Parallaction::hitZone(uint32 type, uint16 x, uint16 y) { +// printf("hitZone(%i, %i, %i)", type, x, y); + + uint16 _di = y; + uint16 _si = x; + + for (ZoneList::iterator it = _zones.begin(); it != _zones.end(); it++) { +// printf("Zone name: %s", z->_name); + + Zone *z = *it; + + if (z->_flags & kFlagsRemove) continue; + + Common::Rect r; + z->getRect(r); + r.right++; // adjust border because Common::Rect doesn't include bottom-right edge + r.bottom++; + + r.grow(-1); // allows some tolerance for mouse click + + if (!r.contains(_si, _di)) { + + // out of Zone, so look for special values + if ((z->_left == -2) || (z->_left == -3)) { + + // WORKAROUND: this huge condition is needed because we made TypeData a collection of structs + // instead of an union. So, merge->_obj1 and get->_icon were just aliases in the original engine, + // but we need to check it separately here. The same workaround is applied in freeZones. + if ((((z->_type & 0xFFFF) == kZoneMerge) && (((_si == z->u.merge->_obj1) && (_di == z->u.merge->_obj2)) || ((_si == z->u.merge->_obj2) && (_di == z->u.merge->_obj1)))) || + (((z->_type & 0xFFFF) == kZoneGet) && ((_si == z->u.get->_icon) || (_di == z->u.get->_icon)))) { + + // special Zone + if ((type == 0) && ((z->_type & 0xFFFF0000) == 0)) + return z; + if (z->_type == type) + return z; + if ((z->_type & 0xFFFF0000) == type) + return z; + + } + } + + if (z->_left != -1) + continue; + if (_si < _char._ani._left) + continue; + if (_si > (_char._ani._left + _char._ani.width())) + continue; + if (_di < _char._ani._top) + continue; + if (_di > (_char._ani._top + _char._ani.height())) + continue; + + } + + // normal Zone + if ((type == 0) && ((z->_type & 0xFFFF0000) == 0)) + return z; + if (z->_type == type) + return z; + if ((z->_type & 0xFFFF0000) == type) + return z; + + } + + + int16 _a, _b, _c, _d, _e, _f; + for (AnimationList::iterator it = _animations.begin(); it != _animations.end(); it++) { + + Animation *a = *it; + + _a = (a->_flags & kFlagsActive) ? 1 : 0; // _a: active Animation + _e = ((_si >= a->_left + a->width()) || (_si <= a->_left)) ? 0 : 1; // _e: horizontal range + _f = ((_di >= a->_top + a->height()) || (_di <= a->_top)) ? 0 : 1; // _f: vertical range + + _b = ((type != 0) || (a->_type == kZoneYou)) ? 0 : 1; // _b: (no type specified) AND (Animation is not the character) + _c = (a->_type & 0xFFFF0000) ? 0 : 1; // _c: Animation is not an object + _d = ((a->_type & 0xFFFF0000) != type) ? 0 : 1; // _d: Animation is an object of the same type + + if ((_a != 0 && _e != 0 && _f != 0) && ((_b != 0 && _c != 0) || (a->_type == type) || (_d != 0))) { + + return a; + + } + + } + + return NULL; +} + + +void Parallaction_ns::initOpcodes() { + + static const OpcodeV1 op1[] = { + INSTRUCTION_OPCODE(invalid), + 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) + }; + + uint i; + for (i = 0; i < ARRAYSIZE(op1); i++) + _instructionOpcodes.push_back(&op1[i]); + + static const OpcodeV1 op3[] = { + COMMAND_OPCODE(invalid), + 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) + }; + + for (i = 0; i < ARRAYSIZE(op3); i++) + _commandOpcodes.push_back(&op3[i]); + +} + + + +} // namespace Parallaction diff --git a/engines/parallaction/font.cpp b/engines/parallaction/font.cpp index d0973c27e7..afa00f81af 100644 --- a/engines/parallaction/font.cpp +++ b/engines/parallaction/font.cpp @@ -571,7 +571,7 @@ Font *AmigaDisk_ns::createFont(const char *name, Common::SeekableReadStream &str } Font *DosDisk_br::createFont(const char *name, Common::ReadStream &stream) { - printf("DosDisk_br::createFont(%s)\n", name); +// printf("DosDisk_br::createFont(%s)\n", name); return new BraFont(stream); } diff --git a/engines/parallaction/inventory.cpp b/engines/parallaction/inventory.cpp index c9e74b2074..2804578c84 100644 --- a/engines/parallaction/inventory.cpp +++ b/engines/parallaction/inventory.cpp @@ -157,7 +157,7 @@ void Parallaction::dropItem(uint16 v) { bool found = false; for (uint16 slot = 0; slot < INVENTORY_MAX_ITEMS - 1; slot++) { - if (v + INVENTORY_FIRST_ITEM == _inventory[slot]._index) { + if (v == _inventory[slot]._index) { found = true; } diff --git a/engines/parallaction/location.cpp b/engines/parallaction/location.cpp deleted file mode 100644 index 0bac727f88..0000000000 --- a/engines/parallaction/location.cpp +++ /dev/null @@ -1,567 +0,0 @@ -/* 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$ - * - */ - -#include "common/stdafx.h" - -#include "common/system.h" - -#include "parallaction/parallaction.h" -#include "parallaction/sound.h" - -namespace Parallaction { - - -DECLARE_LOCATION_PARSER(invalid) { - error("unknown keyword '%s' in location '%s'", _tokens[0], _locParseCtxt.filename); -} - -DECLARE_LOCATION_PARSER(endlocation) { - _locParseCtxt.end = true; -} - - -DECLARE_LOCATION_PARSER(location) { - // The parameter for location is 'location.mask'. - // If mask is not present, then it is assumed - // that path & mask are encoded in the background - // bitmap, otherwise a separate .msk file exists. - - char *mask = strchr(_tokens[1], '.'); - if (mask) { - mask[0] = '\0'; - mask++; - } - - strcpy(_location._name, _tokens[1]); - switchBackground(_location._name, mask); - - if (_tokens[2][0] != '\0') { - _char._ani._left = atoi(_tokens[2]); - _char._ani._top = atoi(_tokens[3]); - } - - if (_tokens[4][0] != '\0') { - _char._ani._frame = atoi(_tokens[4]); - } -} - - -DECLARE_LOCATION_PARSER(disk) { - _disk->selectArchive(_tokens[1]); -} - - -DECLARE_LOCATION_PARSER(nodes) { - parseWalkNodes(*_locParseCtxt.script, _location._walkNodes); -} - - -DECLARE_LOCATION_PARSER(zone) { - parseZone(*_locParseCtxt.script, _zones, _tokens[1]); -} - - -DECLARE_LOCATION_PARSER(animation) { - parseAnimation(*_locParseCtxt.script, _animations, _tokens[1]); -} - - -DECLARE_LOCATION_PARSER(localflags) { - int _si = 1; // _localFlagNames[0] = 'visited' - while (_tokens[_si][0] != '\0') { - _localFlagNames->addData(_tokens[_si]); - _si++; - } -} - - -DECLARE_LOCATION_PARSER(commands) { - parseCommands(*_locParseCtxt.script, _location._commands); -} - - -DECLARE_LOCATION_PARSER(acommands) { - parseCommands(*_locParseCtxt.script, _location._aCommands); -} - - -DECLARE_LOCATION_PARSER(flags) { - if ((_localFlags[_currentLocationIndex] & kFlagsVisited) == 0) { - // only for 1st visit - _localFlags[_currentLocationIndex] = 0; - int _si = 1; - - do { - byte _al = _localFlagNames->lookup(_tokens[_si]); - _localFlags[_currentLocationIndex] |= 1 << (_al - 1); - - _si++; - if (scumm_stricmp(_tokens[_si], "|")) break; - _si++; - } while (true); - } -} - - -DECLARE_LOCATION_PARSER(comment) { - _location._comment = parseComment(*_locParseCtxt.script); -} - - -DECLARE_LOCATION_PARSER(endcomment) { - _location._endComment = parseComment(*_locParseCtxt.script); -} - - -DECLARE_LOCATION_PARSER(sound) { - if (getPlatform() == Common::kPlatformAmiga) { - strcpy(_locationSound, _tokens[1]); - _hasLocationSound = true; - } -} - - -DECLARE_LOCATION_PARSER(music) { - if (getPlatform() == Common::kPlatformAmiga) - _soundMan->setMusicFile(_tokens[1]); -} - -DECLARE_LOCATION_PARSER(redundant) { - warning("redundant '%s' line found in script '%s'", _tokens[0], _locParseCtxt.filename); -} - - -void Parallaction::parseLocation(const char *filename) { - debugC(1, kDebugLocation, "parseLocation('%s')", filename); - - allocateLocationSlot(filename); - - Script *script = _disk->loadLocation(filename); - - // TODO: the following two lines are specific to Nippon Safes - // and should be moved into something like 'initializeParsing()' - _gfx->setFont(_labelFont); - _hasLocationSound = false; - - _locParseCtxt.end = false; - _locParseCtxt.script = script; - _locParseCtxt.filename = filename; - - pushParserTables(_locationParsers, _locationStmt); - - do { - - fillBuffers(*script, true); - - parseStatement(); - - } while (!_locParseCtxt.end); - - popParserTables(); - - delete script; - - finalizeLocationParsing(); - - return; -} - -void Parallaction::allocateLocationSlot(const char *name) { - // WORKAROUND: the original code erroneously incremented - // _currentLocationIndex, thus producing inconsistent - // savegames. This workaround modified the following loop - // and if-statement, so the code exactly matches the one - // in Big Red Adventure. - _currentLocationIndex = -1; - uint16 _di = 0; - while (_locationNames[_di][0] != '\0') { - if (!scumm_stricmp(_locationNames[_di], name)) { - _currentLocationIndex = _di; - } - _di++; - } - - if (_di == 120) - error("No more location slots available. Please report this immediately to ScummVM team."); - - if (_currentLocationIndex == -1) { - strcpy(_locationNames[_numLocations], name); - _currentLocationIndex = _numLocations; - - _numLocations++; - _locationNames[_numLocations][0] = '\0'; - _localFlags[_numLocations] = 0; - } else { - _localFlags[_currentLocationIndex] |= kFlagsVisited; // 'visited' - } -} - -void Parallaction::finalizeLocationParsing() { - - // this resolves any forward references in the script - for (uint16 _si = 0; _forwardedCommands[_si]; _si++) { - _forwardedCommands[_si]->u._animation = findAnimation(_forwardedAnimationNames[_si]); - _forwardedCommands[_si] = NULL; - } - _numForwards = 0; - - // this loads animation scripts - AnimationList::iterator it = _animations.begin(); - for ( ; it != _animations.end(); it++) { - if ((*it)->_scriptName) - loadProgram(*it, (*it)->_scriptName); - } - - return; -} - - -void Parallaction::freeLocation() { - debugC(7, kDebugLocation, "freeLocation"); - - _soundMan->stopSfx(0); - _soundMan->stopSfx(1); - _soundMan->stopSfx(2); - _soundMan->stopSfx(3); - - if (_localFlagNames) - delete _localFlagNames; - - // HACK: prevents leakage. A routine like this - // should allocate memory at all, though. - if ((_engineFlags & kEngineQuit) == 0) { - _localFlagNames = new Table(120); - _localFlagNames->addData("visited"); - } - - _location._walkNodes.clear(); - - freeZones(); - freeAnimations(); - - if (_location._comment) { - free(_location._comment); - } - _location._comment = NULL; - - _location._commands.clear(); - _location._aCommands.clear(); - - return; -} - - - -void Parallaction::parseWalkNodes(Script& script, WalkNodeList &list) { - - fillBuffers(script, true); - while (scumm_stricmp(_tokens[0], "ENDNODES")) { - - if (!scumm_stricmp(_tokens[0], "COORD")) { - - WalkNode *v4 = new WalkNode( - atoi(_tokens[1]) - _char._ani.width()/2, - atoi(_tokens[2]) - _char._ani.height() - ); - - list.push_front(v4); - } - - fillBuffers(script, true); - } - - return; - -} - -void Parallaction::freeBackground() { - - if (!_backgroundInfo) - return; - - _backgroundInfo->bg.free(); - _backgroundInfo->mask.free(); - _backgroundInfo->path.free(); - - _pathBuffer = 0; - -} - -void Parallaction::setBackground(const char* name, const char* mask, const char* path) { - - _disk->loadScenery(*_backgroundInfo, name, mask, path); - - _gfx->setPalette(_backgroundInfo->palette); - _gfx->_palette.clone(_backgroundInfo->palette); - _gfx->setBackground(&_backgroundInfo->bg); - - if (_backgroundInfo->mask.data) - _gfx->setMask(&_backgroundInfo->mask); - - if (_backgroundInfo->path.data) - _pathBuffer = &_backgroundInfo->path; - - return; -} - -void Parallaction::showLocationComment(const char *text, bool end) { - - _gfx->setFont(_dialogueFont); - - int16 w, h; - _gfx->getStringExtent(const_cast<char*>(text), 130, &w, &h); - - Common::Rect r(w + (end ? 5 : 10), h + 5); - r.moveTo(5, 5); - - _gfx->floodFill(Gfx::kBitFront, r, 0); - r.grow(-2); - _gfx->floodFill(Gfx::kBitFront, r, 1); - _gfx->displayWrappedString(const_cast<char*>(text), 3, 5, 0, 130); - - _gfx->updateScreen(); - - return; -} - -void Parallaction::switchBackground(const char* background, const char* mask) { -// printf("switchBackground(%s)", name); - - Palette pal; - - uint16 v2 = 0; - if (!scumm_stricmp(background, "final")) { - _gfx->clearScreen(Gfx::kBitBack); - for (uint16 _si = 0; _si <= 32; _si++) { - pal.setEntry(_si, v2, v2, v2); - v2 += 4; - } - - g_system->delayMillis(20); - _gfx->setPalette(pal); - _gfx->updateScreen(); - } - - setBackground(background, mask, mask); - - return; -} - -extern Zone *_hoverZone; -extern Job *_jDrawLabel; -extern Job *_jEraseLabel; - -void Parallaction::showSlide(const char *name) { - - BackgroundInfo info; - - _disk->loadSlide(info, name); - - // TODO: avoid using screen buffers for displaying slides. Using a generic buffer - // allows for positioning of graphics as needed by Big Red Adventure. - // The main problem lies with menu, which relies on multiple buffers, mainly because - // it is crappy code. - _gfx->setBackground(&info.bg); - _gfx->setPalette(info.palette); - _gfx->copyScreen(Gfx::kBitBack, Gfx::kBitFront); - - info.bg.free(); - info.mask.free(); - info.path.free(); - - return; -} - -/* - changeLocation handles transitions between locations, and is able to display slides - between one and the other. The input parameter 'location' exists in some flavours: - - 1 - [S].slide.[L]{.[C]} - 2 - [L]{.[C]} - - where: - - [S] is the slide to be shown - [L] is the location to switch to (immediately in case 2, or right after slide [S] in case 1) - [C] is the character to be selected, and is optional - - The routine tells one form from the other by searching for the '.slide.' - - NOTE: there exists one script in which [L] is not used in the case 1, but its use - is commented out, and would definitely crash the current implementation. -*/ -void Parallaction::changeLocation(char *location) { - debugC(1, kDebugLocation, "changeLocation(%s)", location); - - _soundMan->playLocationMusic(location); - - // WORKAROUND: this if-statement has been added to avoid crashes caused by - // execution of label jobs after a location switch. The other workaround in - // Parallaction::runGame should have been rendered useless by this one. - if (_jDrawLabel != NULL) { - removeJob(_jDrawLabel); - removeJob(_jEraseLabel); - _jDrawLabel = NULL; - _jEraseLabel = NULL; - } - - - _hoverZone = NULL; - if (_engineFlags & kEngineBlockInput) { - changeCursor( kCursorArrow ); - } - - _animations.remove(&_char._ani); - - freeLocation(); - char buf[100]; - strcpy(buf, location); - - Common::StringList list; - char *tok = strtok(location, "."); - while (tok) { - list.push_back(tok); - tok = strtok(NULL, "."); - } - - if (list.size() < 1 || list.size() > 4) - error("changeLocation: ill-formed location string '%s'", location); - - if (list.size() > 1) { - if (list[1] == "slide") { - showSlide(list[0].c_str()); - _gfx->setFont(_menuFont); - _gfx->displayCenteredString(14, _slideText[0]); // displays text on screen - _gfx->updateScreen(); - waitUntilLeftClick(); - - list.remove_at(0); // removes slide name - list.remove_at(0); // removes 'slide' - } - - // list is now only [L].{[C]} (see above comment) - if (list.size() == 2) { - changeCharacter(list[1].c_str()); - strcpy(_characterName, list[1].c_str()); - } - } - - _animations.push_front(&_char._ani); - - strcpy(_saveData1, list[0].c_str()); - parseLocation(list[0].c_str()); - - _char._ani._oldPos.x = -1000; - _char._ani._oldPos.y = -1000; - - _char._ani.field_50 = 0; - if (_location._startPosition.x != -1000) { - _char._ani._left = _location._startPosition.x; - _char._ani._top = _location._startPosition.y; - _char._ani._frame = _location._startFrame; - _location._startPosition.y = -1000; - _location._startPosition.x = -1000; - } - - - _gfx->copyScreen(Gfx::kBitBack, Gfx::kBitFront); - _gfx->copyScreen(Gfx::kBitBack, Gfx::kBit2); - _gfx->setBlackPalette(); - _gfx->updateScreen(); - - if (_location._commands.size() > 0) { - runCommands(_location._commands); - runJobs(); - _gfx->swapBuffers(); - runJobs(); - _gfx->swapBuffers(); - } - - if (_location._comment) { - doLocationEnterTransition(); - } - - runJobs(); - _gfx->swapBuffers(); - - _gfx->setPalette(_gfx->_palette); - if (_location._aCommands.size() > 0) { - runCommands(_location._aCommands); - } - - if (_hasLocationSound) - _soundMan->playSfx(_locationSound, 0, true); - - debugC(1, kDebugLocation, "changeLocation() done"); - - return; - -} - -// displays transition before a new location -// -// clears screen (in white??) -// shows location comment (if any) -// waits for mouse click -// fades towards game palette -// -void Parallaction::doLocationEnterTransition() { - debugC(1, kDebugLocation, "doLocationEnterTransition"); - - if (_localFlags[_currentLocationIndex] & kFlagsVisited) { - debugC(3, kDebugLocation, "skipping location transition"); - return; // visited - } - - Palette pal(_gfx->_palette); - pal.makeGrayscale(); - _gfx->setPalette(pal); - - jobRunScripts(NULL, NULL); - jobEraseAnimations(NULL, NULL); - jobDisplayAnimations(NULL, NULL); - - _gfx->swapBuffers(); - _gfx->copyScreen(Gfx::kBitFront, Gfx::kBitBack); - - showLocationComment(_location._comment, false); - waitUntilLeftClick(); - - _gfx->copyScreen(Gfx::kBitBack, Gfx::kBitFront ); - - // fades maximum intensity palette towards approximation of main palette - for (uint16 _si = 0; _si<6; _si++) { - pal.fadeTo(_gfx->_palette, 4); - _gfx->setPalette(pal); - waitTime( 1 ); - _gfx->updateScreen(); - } - - debugC(1, kDebugLocation, "doLocationEnterTransition completed"); - - return; -} - -} // namespace Parallaction diff --git a/engines/parallaction/module.mk b/engines/parallaction/module.mk index b7f60eeb32..61e293ed5b 100644 --- a/engines/parallaction/module.mk +++ b/engines/parallaction/module.mk @@ -1,29 +1,28 @@ MODULE := engines/parallaction MODULE_OBJS := \ - animation.o \ callables_br.o \ callables_ns.o \ - commands.o \ debug.o \ detection.o \ dialogue.o \ disk_br.o \ disk_ns.o \ + exec_ns.o \ font.o \ graphics.o \ inventory.o \ - location.o \ menu.o \ - parser.o \ + objects.o \ parallaction.o \ parallaction_br.o \ parallaction_ns.o \ + parser.o \ + parser_ns.o \ saveload.o \ sound.o \ staticres.o \ - walk.o \ - zone.o + walk.o # This module can be built as a plugin ifdef BUILD_PLUGINS diff --git a/engines/parallaction/objects.cpp b/engines/parallaction/objects.cpp new file mode 100644 index 0000000000..d4eba330bb --- /dev/null +++ b/engines/parallaction/objects.cpp @@ -0,0 +1,215 @@ +/* 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$ + * + */ + +#include "common/stdafx.h" +#include "parallaction/objects.h" + +namespace Parallaction { + + + +Command::Command() { + _id = 0; + _flagsOn = 0; + _flagsOff = 0; +} + +Command::~Command() { + +} + + +Animation::Animation() { + _cnv = NULL; + _program = NULL; + _scriptName = 0; + _frame = 0; + _z = 0; +} + +Animation::~Animation() { + if (_program) + delete _program; + + if (_scriptName) + free(_scriptName); + + if (_cnv) + delete _cnv; +} + +uint16 Animation::width() const { + if (!_cnv) return 0; + return _cnv->_width; +} + +uint16 Animation::height() const { + if (!_cnv) return 0; + return _cnv->_height; +} + +uint16 Animation::getFrameNum() const { + if (!_cnv) return 0; + return _cnv->_count; +} + +byte* Animation::getFrameData(uint32 index) const { + if (!_cnv) return NULL; + return _cnv->getFramePtr(index); +} + + +Program::Program() { + _loopCounter = 0; + _locals = new LocalVariable[10]; +} + +Program::~Program() { + delete[] _locals; +} + + +Zone::Zone() { + _left = _top = _right = _bottom = 0; + + _type = 0; + _flags = 0; +} + +Zone::~Zone() { +// printf("~Zone(%s)\n", _label._text); + + _label._cnv.free(); + + switch (_type & 0xFFFF) { + case kZoneExamine: + free(u.examine->_filename); + free(u.examine->_description); + delete u.examine; + break; + + case kZoneDoor: + free(u.door->_location); + free(u.door->_background); + if (u.door->_cnv) + delete u.door->_cnv; + delete u.door; + break; + + case kZoneSpeak: + delete u.speak->_dialogue; + delete u.speak; + break; + + case kZoneGet: + free(u.get->_backup); + if (u.get->_cnv) { + u.get->_cnv->free(); + delete u.get->_cnv; + } + delete u.get; + break; + + case kZoneHear: + delete u.hear; + break; + + case kZoneMerge: + delete u.merge; + break; + + default: + break; + } +} + +void Zone::getRect(Common::Rect& r) const { + r.left = _left; + r.right = _right; + r.top = _top; + r.bottom = _bottom; +} + +void Zone::translate(int16 x, int16 y) { + _left += x; + _right += x; + _top += y; + _bottom += y; +} + +uint16 Zone::width() const { + return _right - _left; +} + +uint16 Zone::height() const { + return _bottom - _top; +} + +Label::Label() { + _text = NULL; +} + +Label::~Label() { + _cnv.free(); + if (_text) + free(_text); +} + + +Answer::Answer() { + _text = NULL; + _mood = 0; + _following._question = NULL; + _noFlags = 0; + _yesFlags = 0; +} + +Answer::~Answer() { + if (_text) + free(_text); +} + +Question::Question() { + _text = NULL; + _mood = 0; + + for (uint32 i = 0; i < NUM_ANSWERS; i++) + _answers[i] = NULL; + +} + +Question::~Question() { + + for (uint32 i = 0; i < NUM_ANSWERS; i++) + if (_answers[i]) delete _answers[i]; + + free(_text); +} + + + + + +} // namespace Parallaction diff --git a/engines/parallaction/zone.h b/engines/parallaction/objects.h index 38b8730c4b..3f8635eb0d 100644 --- a/engines/parallaction/zone.h +++ b/engines/parallaction/objects.h @@ -30,12 +30,19 @@ #include "parallaction/defs.h" -#include "parallaction/commands.h" #include "parallaction/graphics.h" namespace Parallaction { +struct Zone; +struct Animation; +struct Command; +struct Question; +struct Answer; +struct Instruction; +struct Program; + enum ZoneTypes { kZoneExamine = 1, // zone displays comment if activated kZoneDoor = 2, // zone activated on click (after some walk if needed) @@ -68,12 +75,67 @@ enum ZoneFlags { }; +enum CommandFlags { + kFlagsVisited = 1, + kFlagsExit = 0x10000000, + kFlagsEnter = 0x20000000, + kFlagsGlobal = 0x40000000, + + // BRA specific + kFlagsTestTrue = 2 +}; + +struct CommandData { + uint32 _flags; + Animation * _animation; + Zone* _zone; + char* _string; + uint16 _callable; + uint16 _object; + Common::Point _move; + + // BRA specific + Common::Point _startPos; + Common::Point _startPos2; + uint _lvalue; + int _rvalue; + int _zeta0; + int _zeta1; + int _zeta2; + int _characterId; + char* _string2; + int _musicCommand; + int _musicParm; + + + CommandData() { + memset(this, 0, sizeof(CommandData)); + } + + ~CommandData() { + if (_string) + free(_string); + if (_string2) + free(_string2); + } +}; + +struct Command { + uint16 _id; + CommandData u; + uint32 _flagsOn; + uint32 _flagsOff; + + Command(); + ~Command(); +}; + +typedef ManagedList<Command*> CommandList; + + #define NUM_QUESTIONS 20 #define NUM_ANSWERS 5 -struct Command; -struct Question; - struct Answer { char* _text; uint16 _mood; @@ -192,8 +254,8 @@ struct TypeData { }; struct Label { - char* _text; - Graphics::Surface _cnv; + char* _text; + Graphics::Surface _cnv; Label(); ~Label(); @@ -237,12 +299,12 @@ struct LocalVariable { } }; -union LValue { +union ScriptVar { int16 _value; int16* _pvalue; LocalVariable* _local; - LValue() { + ScriptVar() { _local = NULL; } }; @@ -251,10 +313,18 @@ enum InstructionFlags { kInstUsesLiteral = 1, kInstUsesLocal = 2, kInstMod = 4, - kInstMaskedPut = 8 + kInstMaskedPut = 8, + + kInstUsesField = 0x10, // this value wasn't originally in NS, but it has been added for completeness + + // BRA specific + kInstUnk20 = 0x20, + kInstUsesLLocal = 0x40, + kInstUsesLField = 0x80, + kInstRandom = 0x100 }; -struct Animation; +typedef ManagedList<Instruction*> InstructionList; struct Instruction { uint32 _index; @@ -263,20 +333,30 @@ struct Instruction { Animation *_a; Zone *_z; uint32 _index; - LValue _loopCounter; + ScriptVar _loopCounter; } _opBase; - LValue _opA; - LValue _opB; + ScriptVar _opA; + ScriptVar _opB; + + // BRA specific + byte _colors[3]; + ScriptVar _opC; + char *_text; + char *_text2; + int _y; + InstructionList::iterator _endif; Instruction() { - _index = 0; - _flags = 0; - _opBase._a = NULL; + memset(this, 0, sizeof(Instruction)); } -}; -//typedef Common::List<Instruction*> InstructionList; -typedef ManagedList<Instruction*> InstructionList; + ~Instruction() { + if (_text) + free(_text); + if (_text2) + free(_text2); + } +}; struct Program { LocalVariable *_locals; diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index af0a34e409..dedcddb8c7 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -53,7 +53,6 @@ char _saveData1[30] = { '\0' }; uint16 _language = 0; char _slideText[2][40]; uint32 _engineFlags = 0; -Zone *_activeZone = NULL; uint16 _score = 1; @@ -128,11 +127,9 @@ Parallaction::~Parallaction() { delete _globalTable; delete _callableNames; - delete _commandsNames; - delete _instructionNames; + delete _zoneTypeNames; delete _zoneFlagNames; - delete _locationStmt; _animations.remove(&_char._ani); @@ -168,6 +165,7 @@ int Parallaction::init() { _backgroundInfo = 0; _pathBuffer = 0; + _activeZone = 0; _screenSize = _screenWidth * _screenHeight; @@ -178,8 +176,6 @@ int Parallaction::init() { memset(_locationNames, 0, 120*32); - initOpcodes(); - initInventory(); // needs to be pushed into subclass _animations.push_front(&_char._ani); @@ -840,7 +836,7 @@ void Table::addData(const char* s) { } -int Table::lookup(const char* s) { +uint16 Table::lookup(const char* s) { for (uint16 i = 0; i < _used; i++) { if (!scumm_stricmp(_data[i], s)) return i + 1; @@ -849,14 +845,12 @@ int Table::lookup(const char* s) { return notFound; } -void Parallaction::pushParserTables(const Opcode* opcodes, Table *statements) { - +void Parallaction::pushParserTables(OpcodeSet *opcodes, Table *statements) { _opcodes.push(_currentOpcodes); _statements.push(_currentStatements); _currentOpcodes = opcodes; _currentStatements = statements; - } void Parallaction::popParserTables() { @@ -870,161 +864,427 @@ void Parallaction::parseStatement() { assert(_currentOpcodes != 0); _lookup = _currentStatements->lookup(_tokens[0]); - (this->*(_currentOpcodes[_lookup]))(); + (*(*_currentOpcodes)[_lookup])(); +} + + + + +Animation *Parallaction::findAnimation(const char *name) { + + for (AnimationList::iterator it = _animations.begin(); it != _animations.end(); it++) + if (!scumm_stricmp((*it)->_label._text, name)) return *it; + + return NULL; +} + +void Parallaction::freeAnimations() { + _animations.clear(); + return; +} + +int compareAnimationZ(const AnimationPointer &a1, const AnimationPointer &a2) { + if (a1->_z == a2->_z) return 0; + return (a1->_z < a2->_z ? -1 : 1); +} + +void Parallaction::sortAnimations() { + _char._ani._z = _char._ani.height() + _char._ani._top; + _animations.sort(compareAnimationZ); + return; +} + + +void Parallaction::allocateLocationSlot(const char *name) { + // WORKAROUND: the original code erroneously incremented + // _currentLocationIndex, thus producing inconsistent + // savegames. This workaround modified the following loop + // and if-statement, so the code exactly matches the one + // in Big Red Adventure. + _currentLocationIndex = -1; + uint16 _di = 0; + while (_locationNames[_di][0] != '\0') { + if (!scumm_stricmp(_locationNames[_di], name)) { + _currentLocationIndex = _di; + } + _di++; + } + + if (_di == 120) + error("No more location slots available. Please report this immediately to ScummVM team."); + + if (_currentLocationIndex == -1) { + strcpy(_locationNames[_numLocations], name); + _currentLocationIndex = _numLocations; + + _numLocations++; + _locationNames[_numLocations][0] = '\0'; + _localFlags[_numLocations] = 0; + } else { + _localFlags[_currentLocationIndex] |= kFlagsVisited; // 'visited' + } +} + + + +void Parallaction::freeLocation() { + debugC(7, kDebugLocation, "freeLocation"); + + _soundMan->stopSfx(0); + _soundMan->stopSfx(1); + _soundMan->stopSfx(2); + _soundMan->stopSfx(3); + + if (_localFlagNames) + delete _localFlagNames; + + // HACK: prevents leakage. A routine like this + // should allocate memory at all, though. + if ((_engineFlags & kEngineQuit) == 0) { + _localFlagNames = new Table(120); + _localFlagNames->addData("visited"); + } + + _location._walkNodes.clear(); + + freeZones(); + freeAnimations(); + + if (_location._comment) { + free(_location._comment); + } + _location._comment = NULL; + + _location._commands.clear(); + _location._aCommands.clear(); + + return; +} + + + + +void Parallaction::freeBackground() { + + if (!_backgroundInfo) + return; + + _backgroundInfo->bg.free(); + _backgroundInfo->mask.free(); + _backgroundInfo->path.free(); + + _pathBuffer = 0; + +} + +void Parallaction::setBackground(const char* name, const char* mask, const char* path) { + + _disk->loadScenery(*_backgroundInfo, name, mask, path); + + _gfx->setPalette(_backgroundInfo->palette); + _gfx->_palette.clone(_backgroundInfo->palette); + _gfx->setBackground(&_backgroundInfo->bg); + + if (_backgroundInfo->mask.data) + _gfx->setMask(&_backgroundInfo->mask); + + if (_backgroundInfo->path.data) + _pathBuffer = &_backgroundInfo->path; + + return; +} + +void Parallaction::showLocationComment(const char *text, bool end) { + + _gfx->setFont(_dialogueFont); + + int16 w, h; + _gfx->getStringExtent(const_cast<char*>(text), 130, &w, &h); + + Common::Rect r(w + (end ? 5 : 10), h + 5); + r.moveTo(5, 5); + + _gfx->floodFill(Gfx::kBitFront, r, 0); + r.grow(-2); + _gfx->floodFill(Gfx::kBitFront, r, 1); + _gfx->displayWrappedString(const_cast<char*>(text), 3, 5, 0, 130); + + _gfx->updateScreen(); + + return; +} + +void Parallaction::switchBackground(const char* background, const char* mask) { +// printf("switchBackground(%s)", name); + + Palette pal; + + uint16 v2 = 0; + if (!scumm_stricmp(background, "final")) { + _gfx->clearScreen(Gfx::kBitBack); + for (uint16 _si = 0; _si <= 32; _si++) { + pal.setEntry(_si, v2, v2, v2); + v2 += 4; + } + + g_system->delayMillis(20); + _gfx->setPalette(pal); + _gfx->updateScreen(); + } + + setBackground(background, mask, mask); + + return; +} + +extern Zone *_hoverZone; +extern Job *_jDrawLabel; +extern Job *_jEraseLabel; + +void Parallaction::showSlide(const char *name) { + + BackgroundInfo info; + + _disk->loadSlide(info, name); + + // TODO: avoid using screen buffers for displaying slides. Using a generic buffer + // allows for positioning of graphics as needed by Big Red Adventure. + // The main problem lies with menu, which relies on multiple buffers, mainly because + // it is crappy code. + _gfx->setBackground(&info.bg); + _gfx->setPalette(info.palette); + _gfx->copyScreen(Gfx::kBitBack, Gfx::kBitFront); + + info.bg.free(); + info.mask.free(); + info.path.free(); + + return; +} + +/* + changeLocation handles transitions between locations, and is able to display slides + between one and the other. The input parameter 'location' exists in some flavours: + + 1 - [S].slide.[L]{.[C]} + 2 - [L]{.[C]} + + where: + + [S] is the slide to be shown + [L] is the location to switch to (immediately in case 2, or right after slide [S] in case 1) + [C] is the character to be selected, and is optional + + The routine tells one form from the other by searching for the '.slide.' + + NOTE: there exists one script in which [L] is not used in the case 1, but its use + is commented out, and would definitely crash the current implementation. +*/ +void Parallaction::changeLocation(char *location) { + debugC(1, kDebugLocation, "changeLocation(%s)", location); + + _soundMan->playLocationMusic(location); + + // WORKAROUND: this if-statement has been added to avoid crashes caused by + // execution of label jobs after a location switch. The other workaround in + // Parallaction::runGame should have been rendered useless by this one. + if (_jDrawLabel != NULL) { + removeJob(_jDrawLabel); + removeJob(_jEraseLabel); + _jDrawLabel = NULL; + _jEraseLabel = NULL; + } + + + _hoverZone = NULL; + if (_engineFlags & kEngineBlockInput) { + changeCursor( kCursorArrow ); + } + + _animations.remove(&_char._ani); + + freeLocation(); + char buf[100]; + strcpy(buf, location); + + Common::StringList list; + char *tok = strtok(location, "."); + while (tok) { + list.push_back(tok); + tok = strtok(NULL, "."); + } + + if (list.size() < 1 || list.size() > 4) + error("changeLocation: ill-formed location string '%s'", location); + + if (list.size() > 1) { + if (list[1] == "slide") { + showSlide(list[0].c_str()); + _gfx->setFont(_menuFont); + _gfx->displayCenteredString(14, _slideText[0]); // displays text on screen + _gfx->updateScreen(); + waitUntilLeftClick(); + + list.remove_at(0); // removes slide name + list.remove_at(0); // removes 'slide' + } + + // list is now only [L].{[C]} (see above comment) + if (list.size() == 2) { + changeCharacter(list[1].c_str()); + strcpy(_characterName, list[1].c_str()); + } + } + + _animations.push_front(&_char._ani); + + strcpy(_saveData1, list[0].c_str()); + parseLocation(list[0].c_str()); + + _char._ani._oldPos.x = -1000; + _char._ani._oldPos.y = -1000; + + _char._ani.field_50 = 0; + if (_location._startPosition.x != -1000) { + _char._ani._left = _location._startPosition.x; + _char._ani._top = _location._startPosition.y; + _char._ani._frame = _location._startFrame; + _location._startPosition.y = -1000; + _location._startPosition.x = -1000; + } + + + _gfx->copyScreen(Gfx::kBitBack, Gfx::kBitFront); + _gfx->copyScreen(Gfx::kBitBack, Gfx::kBit2); + _gfx->setBlackPalette(); + _gfx->updateScreen(); + + if (_location._commands.size() > 0) { + runCommands(_location._commands); + runJobs(); + _gfx->swapBuffers(); + runJobs(); + _gfx->swapBuffers(); + } + + if (_location._comment) { + doLocationEnterTransition(); + } + + runJobs(); + _gfx->swapBuffers(); + + _gfx->setPalette(_gfx->_palette); + if (_location._aCommands.size() > 0) { + runCommands(_location._aCommands); + } + + if (_hasLocationSound) + _soundMan->playSfx(_locationSound, 0, true); + + debugC(1, kDebugLocation, "changeLocation() done"); + + return; + } -void Parallaction::initOpcodes() { - - static const Opcode op0[] = { - INSTRUCTION_PARSER(defLocal), // invalid opcode -> local definition - INSTRUCTION_PARSER(animation), // on - INSTRUCTION_PARSER(animation), // off - INSTRUCTION_PARSER(x), - INSTRUCTION_PARSER(y), - INSTRUCTION_PARSER(z), - INSTRUCTION_PARSER(f), - INSTRUCTION_PARSER(loop), - INSTRUCTION_PARSER(null), // endloop - INSTRUCTION_PARSER(null), // show - INSTRUCTION_PARSER(inc), - INSTRUCTION_PARSER(inc), // dec - INSTRUCTION_PARSER(set), - INSTRUCTION_PARSER(put), - INSTRUCTION_PARSER(call), - INSTRUCTION_PARSER(null), // wait - INSTRUCTION_PARSER(animation), // start - INSTRUCTION_PARSER(sound), - INSTRUCTION_PARSER(move) - }; - - _instructionParsers = op0; - - - static const Opcode op1[] = { - INSTRUCTION_OPCODE(invalid), - 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 = op1; - - static const Opcode op2[] = { - COMMAND_PARSER(invalid), - 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 - COMMAND_PARSER(endcommands), // endcommands - COMMAND_PARSER(endcommands) // endzone - }; - - _commandParsers = op2; - - static const Opcode op3[] = { - COMMAND_OPCODE(invalid), - 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 = op3; - - - static const Opcode op4[] = { - LOCATION_PARSER(invalid), - LOCATION_PARSER(endlocation), - LOCATION_PARSER(location), - LOCATION_PARSER(disk), - LOCATION_PARSER(nodes), - LOCATION_PARSER(zone), - LOCATION_PARSER(animation), - LOCATION_PARSER(localflags), - LOCATION_PARSER(commands), - LOCATION_PARSER(acommands), - LOCATION_PARSER(flags), - LOCATION_PARSER(comment), - LOCATION_PARSER(endcomment), - LOCATION_PARSER(sound), - LOCATION_PARSER(music), - LOCATION_PARSER(redundant) // for redundant endanimation - }; - - _locationParsers = op4; - - - static const Opcode op5[] = { - ZONE_PARSER(invalid), - ZONE_PARSER(limits), - ZONE_PARSER(moveto), - ZONE_PARSER(type), - ZONE_PARSER(commands), - ZONE_PARSER(label), - ZONE_PARSER(flags), - ZONE_PARSER(endzone) - }; - - _locationZoneParsers = op5; - - static const Opcode op6[] = { - ANIM_PARSER(invalid), - ANIM_PARSER(script), - ANIM_PARSER(commands), - ANIM_PARSER(type), - ANIM_PARSER(label), - ANIM_PARSER(flags), - ANIM_PARSER(file), - ANIM_PARSER(position), - ANIM_PARSER(moveto), - ANIM_PARSER(endanimation) - }; - - _locationAnimParsers = op6; - - _currentOpcodes = 0; - _currentStatements = 0; +// displays transition before a new location +// +// clears screen (in white??) +// shows location comment (if any) +// waits for mouse click +// fades towards game palette +// +void Parallaction::doLocationEnterTransition() { + debugC(1, kDebugLocation, "doLocationEnterTransition"); + + if (_localFlags[_currentLocationIndex] & kFlagsVisited) { + debugC(3, kDebugLocation, "skipping location transition"); + return; // visited + } + + Palette pal(_gfx->_palette); + pal.makeGrayscale(); + _gfx->setPalette(pal); + + jobRunScripts(NULL, NULL); + jobEraseAnimations(NULL, NULL); + jobDisplayAnimations(NULL, NULL); + + _gfx->swapBuffers(); + _gfx->copyScreen(Gfx::kBitFront, Gfx::kBitBack); + + showLocationComment(_location._comment, false); + waitUntilLeftClick(); + + _gfx->copyScreen(Gfx::kBitBack, Gfx::kBitFront ); + + // fades maximum intensity palette towards approximation of main palette + for (uint16 _si = 0; _si<6; _si++) { + pal.fadeTo(_gfx->_palette, 4); + _gfx->setPalette(pal); + waitTime( 1 ); + _gfx->updateScreen(); + } + debugC(1, kDebugLocation, "doLocationEnterTransition completed"); + + return; +} + + + +Zone *Parallaction::findZone(const char *name) { + + for (ZoneList::iterator it = _zones.begin(); it != _zones.end(); it++) { + if (!scumm_stricmp((*it)->_label._text, name)) return *it; + } + + return findAnimation(name); } + +void Parallaction::freeZones() { + debugC(1, kDebugLocation, "freeZones: kEngineQuit = %i", _engineFlags & kEngineQuit); + + ZoneList::iterator it = _zones.begin(); + + while ( it != _zones.end() ) { + + Zone* z = *it; + + // WORKAROUND: this huge condition is needed because we made TypeData a collection of structs + // instead of an union. So, merge->_obj1 and get->_icon were just aliases in the original engine, + // but we need to check it separately here. The same workaround is applied in hitZone. + if (((z->_top == -1) || + ((z->_left == -2) && ( + (((z->_type & 0xFFFF) == kZoneMerge) && ((isItemInInventory(MAKE_INVENTORY_ID(z->u.merge->_obj1)) != 0) || (isItemInInventory(MAKE_INVENTORY_ID(z->u.merge->_obj2)) != 0))) || + (((z->_type & 0xFFFF) == kZoneGet) && ((isItemInInventory(MAKE_INVENTORY_ID(z->u.get->_icon)) != 0))) + ))) && + ((_engineFlags & kEngineQuit) == 0)) { + + debugC(1, kDebugLocation, "freeZones preserving zone '%s'", z->_label._text); + + it++; + + } else + + it = _zones.erase(it); + + } + + return; +} + + + + + + + + + + + + } // namespace Parallaction diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h index 28551341df..eac10e9b55 100644 --- a/engines/parallaction/parallaction.h +++ b/engines/parallaction/parallaction.h @@ -28,15 +28,16 @@ #include "common/str.h" #include "common/stack.h" +#include "common/array.h" #include "engines/engine.h" #include "parallaction/defs.h" #include "parallaction/inventory.h" #include "parallaction/parser.h" +#include "parallaction/objects.h" #include "parallaction/disk.h" #include "parallaction/walk.h" -#include "parallaction/zone.h" namespace GUI { class ListWidget; @@ -165,7 +166,6 @@ typedef void (*callable)(void*); extern uint16 _mouseButtons; extern uint16 _score; extern uint16 _language; -extern Zone *_activeZone; extern uint32 _engineFlags; extern callable _callables[]; extern uint32 _localFlags[]; @@ -225,7 +225,6 @@ struct Location { Common::Point _startPosition; uint16 _startFrame; - WalkNodeList _walkNodes; char _name[100]; CommandList _aCommands; @@ -233,6 +232,11 @@ struct Location { char *_comment; char *_endComment; + // NS specific + WalkNodeList _walkNodes; + + // BRA specific + CommandList _escapeCommands; }; struct Character { @@ -281,7 +285,7 @@ public: void addData(const char* s); - int lookup(const char* s); + uint16 lookup(const char* s); }; struct BackgroundInfo { @@ -295,34 +299,46 @@ struct BackgroundInfo { Palette palette; }; +class Opcode { -#define DECLARE_ZONE_PARSER(sig) void Parallaction::locZoneParse_##sig() -#define DECLARE_UNQUALIFIED_ZONE_PARSER(sig) void locZoneParse_##sig() -#define ZONE_PARSER(sig) &Parallaction::locZoneParse_##sig +public: + virtual void operator()() const = 0; + virtual ~Opcode() { } +}; -#define DECLARE_ANIM_PARSER(sig) void Parallaction::locAnimParse_##sig() -#define DECLARE_UNQUALIFIED_ANIM_PARSER(sig) void locAnimParse_##sig() -#define ANIM_PARSER(sig) &Parallaction::locAnimParse_##sig +template <class T> +class OpcodeImpl : public Opcode { -#define DECLARE_COMMAND_PARSER(sig) void Parallaction::cmdParse_##sig() -#define DECLARE_UNQUALIFIED_COMMAND_PARSER(sig) void cmdParse_##sig() -#define COMMAND_PARSER(sig) &Parallaction::cmdParse_##sig + typedef void (T::*Fn)(); + + T* _instance; + Fn _fn; + +public: + OpcodeImpl(T* instance, const Fn &fn) : _instance(instance), _fn(fn) { } + + void operator()() const { + (_instance->*_fn)(); + } + +}; + + +typedef Common::Array<const Opcode*> OpcodeSet; -#define DECLARE_COMMAND_OPCODE(op) void Parallaction::cmdOp_##op() -#define DECLARE_UNQUALIFIED_COMMAND_OPCODE(op) void cmdOp_##op() -#define COMMAND_OPCODE(op) &Parallaction::cmdOp_##op -#define DECLARE_INSTRUCTION_PARSER(sig) void Parallaction::instParse_##sig() + +#define DECLARE_UNQUALIFIED_ZONE_PARSER(sig) void locZoneParse_##sig() +#define DECLARE_UNQUALIFIED_ANIM_PARSER(sig) void locAnimParse_##sig() +#define DECLARE_UNQUALIFIED_COMMAND_PARSER(sig) void cmdParse_##sig() +#define DECLARE_UNQUALIFIED_LOCATION_PARSER(sig) void locParse_##sig() #define DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(sig) void instParse_##sig() -#define INSTRUCTION_PARSER(sig) &Parallaction::instParse_##sig -#define DECLARE_INSTRUCTION_OPCODE(op) void Parallaction::instOp_##op() +#define DECLARE_UNQUALIFIED_COMMAND_OPCODE(op) void cmdOp_##op() #define DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(op) void instOp_##op() -#define INSTRUCTION_OPCODE(op) &Parallaction::instOp_##op -#define DECLARE_LOCATION_PARSER(sig) void Parallaction::locParse_##sig() -#define DECLARE_UNQUALIFIED_LOCATION_PARSER(sig) void locParse_##sig() -#define LOCATION_PARSER(sig) &Parallaction::locParse_##sig + + class Parallaction : public Engine { friend class Debugger; @@ -341,90 +357,23 @@ public: void waitTime(uint32 t); - void initOpcodes(); - - typedef void (Parallaction::*Opcode)(); - const Opcode *_commandParsers; - uint _lookup; - - Common::Stack<const Opcode*> _opcodes; - Common::Stack<Table*> _statements; - - const Opcode *_currentOpcodes; - Table *_currentStatements; - - void pushParserTables(const Opcode* opcodes, Table* statements); + Common::Stack<OpcodeSet*> _opcodes; + Common::Stack<Table*> _statements; + OpcodeSet *_currentOpcodes; + Table *_currentStatements; + void pushParserTables(OpcodeSet *opcodes, Table* statements); void popParserTables(); void parseStatement(); - struct { - Command *cmd; - int nextToken; - CommandList *list; - bool end; - } _cmdParseCtxt; - - DECLARE_UNQUALIFIED_COMMAND_PARSER(invalid); - DECLARE_UNQUALIFIED_COMMAND_PARSER(flags); - DECLARE_UNQUALIFIED_COMMAND_PARSER(animation); - DECLARE_UNQUALIFIED_COMMAND_PARSER(zone); - DECLARE_UNQUALIFIED_COMMAND_PARSER(location); - DECLARE_UNQUALIFIED_COMMAND_PARSER(drop); - DECLARE_UNQUALIFIED_COMMAND_PARSER(call); - DECLARE_UNQUALIFIED_COMMAND_PARSER(null); - DECLARE_UNQUALIFIED_COMMAND_PARSER(move); - DECLARE_UNQUALIFIED_COMMAND_PARSER(endcommands); - - const Opcode *_commandOpcodes; + OpcodeSet _commandOpcodes; struct { Command *cmd; Zone *z; } _cmdRunCtxt; - DECLARE_UNQUALIFIED_COMMAND_OPCODE(invalid); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(set); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(clear); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(start); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(speak); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(get); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(location); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(open); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(close); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(on); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(off); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(call); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(toggle); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(drop); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(quit); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(move); - DECLARE_UNQUALIFIED_COMMAND_OPCODE(stop); - - const Opcode *_instructionParsers; - - struct { - Animation *a; - Instruction *inst; - LocalVariable *locals; - } _instParseCtxt; - - DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(defLocal); - DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(animation); - DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(loop); - DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(x); - DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(y); - DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(z); - DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(f); - DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(inc); - DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(set); - DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(move); - DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(put); - DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(call); - DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(sound); - DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(null); - - const Opcode *_instructionOpcodes; + OpcodeSet _instructionOpcodes; struct { Animation *a; @@ -433,93 +382,11 @@ public: bool suspend; } _instRunCtxt; - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(invalid); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(on); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(off); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(loop); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(endloop); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(null); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(inc); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(set); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(put); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(call); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(wait); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(start); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(sound); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(move); - DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(end); - - void parseLocation(const char *filename); - - const Opcode *_locationParsers; - - struct { - const char *filename; - bool end; - Script *script; - Zone *z; - } _locParseCtxt; - - DECLARE_UNQUALIFIED_LOCATION_PARSER(invalid); - DECLARE_UNQUALIFIED_LOCATION_PARSER(endlocation); - DECLARE_UNQUALIFIED_LOCATION_PARSER(location); - DECLARE_UNQUALIFIED_LOCATION_PARSER(disk); - DECLARE_UNQUALIFIED_LOCATION_PARSER(nodes); - DECLARE_UNQUALIFIED_LOCATION_PARSER(zone); - DECLARE_UNQUALIFIED_LOCATION_PARSER(animation); - DECLARE_UNQUALIFIED_LOCATION_PARSER(localflags); - DECLARE_UNQUALIFIED_LOCATION_PARSER(commands); - DECLARE_UNQUALIFIED_LOCATION_PARSER(acommands); - DECLARE_UNQUALIFIED_LOCATION_PARSER(flags); - DECLARE_UNQUALIFIED_LOCATION_PARSER(comment); - DECLARE_UNQUALIFIED_LOCATION_PARSER(endcomment); - DECLARE_UNQUALIFIED_LOCATION_PARSER(sound); - DECLARE_UNQUALIFIED_LOCATION_PARSER(music); - DECLARE_UNQUALIFIED_LOCATION_PARSER(redundant); - - const Opcode *_locationZoneParsers; - - struct { - bool end; - Script *script; - Zone *z; - } _locZoneParseCtxt; - - DECLARE_UNQUALIFIED_ZONE_PARSER(invalid); - DECLARE_UNQUALIFIED_ZONE_PARSER(limits); - DECLARE_UNQUALIFIED_ZONE_PARSER(moveto); - DECLARE_UNQUALIFIED_ZONE_PARSER(type); - DECLARE_UNQUALIFIED_ZONE_PARSER(commands); - DECLARE_UNQUALIFIED_ZONE_PARSER(label); - DECLARE_UNQUALIFIED_ZONE_PARSER(flags); - DECLARE_UNQUALIFIED_ZONE_PARSER(endzone); - - const Opcode *_locationAnimParsers; - - struct { - bool end; - Script *script; - Animation *a; - } _locAnimParseCtxt; - - DECLARE_UNQUALIFIED_ANIM_PARSER(invalid); - DECLARE_UNQUALIFIED_ANIM_PARSER(script); - DECLARE_UNQUALIFIED_ANIM_PARSER(commands); - DECLARE_UNQUALIFIED_ANIM_PARSER(type); - DECLARE_UNQUALIFIED_ANIM_PARSER(label); - DECLARE_UNQUALIFIED_ANIM_PARSER(flags); - DECLARE_UNQUALIFIED_ANIM_PARSER(file); - DECLARE_UNQUALIFIED_ANIM_PARSER(position); - DECLARE_UNQUALIFIED_ANIM_PARSER(moveto); - DECLARE_UNQUALIFIED_ANIM_PARSER(endanimation); void changeCursor(int32 index); void showCursor(bool visible); void changeCharacter(const char *name); - char *parseComment(Script &script); - char *parseDialogueString(Script &script); - Dialogue *parseDialogue(Script &script); Job *addJob(JobFn fn, void *parm, uint16 tag); void removeJob(Job *j); @@ -552,13 +419,8 @@ public: Table *_objectsNames; Table *_zoneTypeNames; Table *_zoneFlagNames; - Table *_commandsNames; Table *_callableNames; - Table *_instructionNames; Table *_localFlagNames; - Table *_locationStmt; - Table *_locationZoneStmt; - Table *_locationAnimStmt; public: @@ -595,6 +457,8 @@ public: Common::Point _mousePos; + Zone *_activeZone; + ZoneList _zones; AnimationList _animations; @@ -664,24 +528,11 @@ protected: // members void freeLocation(); void showLocationComment(const char *text, bool end); - void parseZone(Script &script, ZoneList &list, char *name); - void parseZoneTypeBlock(Script &script, Zone *z); void displayCharacterComment(ExamineData *data); void displayItemComment(ExamineData *data); - void parseWalkNodes(Script& script, WalkNodeList &list); uint16 checkDoor(); - Animation * parseAnimation(Script &script, AnimationList &list, char *name); - void parseScriptLine(Instruction *inst, Animation *a, LocalVariable *locals); - void loadProgram(Animation *a, char *filename); - LValue getLValue(Instruction *inst, char *str, LocalVariable *locals, Animation *a); - - void parseCommands(Script &script, CommandList&); - void parseCommandFlags(); - void createCommand(uint id); - void addCommand(); - void freeCharacter(); int addInventoryItem(uint16 item); @@ -696,6 +547,8 @@ public: virtual void setMousePointer(int16 index) = 0; + virtual void parseLocation(const char* name) = 0; + public: const char **_zoneFlagNamesRes; const char **_zoneTypeNamesRes; @@ -722,15 +575,14 @@ public: void renderLabel(Graphics::Surface *cnv, char *text); void setMousePointer(int16 index); -public: +private: Menu* _menu; -private: void initFonts(); void freeFonts(); private: - void initResources(); + void initResources(); void initCursors(); static byte _mouseArrow[256]; @@ -773,12 +625,184 @@ private: void _c_HBOn(void*); const Callable *_callables; + +protected: + // location parser + OpcodeSet _locationParsers; + OpcodeSet _locationZoneParsers; + OpcodeSet _locationAnimParsers; + OpcodeSet _commandParsers; + Table *_commandsNames; + Table *_locationStmt; + Table *_locationZoneStmt; + Table *_locationAnimStmt; + + struct { + const char *filename; + bool end; + Script *script; + } _locParseCtxt; + struct { + bool end; + Script *script; + Zone *z; + } _locZoneParseCtxt; + struct { + bool end; + Script *script; + Animation *a; + } _locAnimParseCtxt; + struct { + Command *cmd; + int nextToken; + CommandList *list; + bool end; + Script *script; + } _cmdParseCtxt; + + DECLARE_UNQUALIFIED_LOCATION_PARSER(invalid); + DECLARE_UNQUALIFIED_LOCATION_PARSER(endlocation); + DECLARE_UNQUALIFIED_LOCATION_PARSER(location); + DECLARE_UNQUALIFIED_LOCATION_PARSER(disk); + DECLARE_UNQUALIFIED_LOCATION_PARSER(nodes); + DECLARE_UNQUALIFIED_LOCATION_PARSER(zone); + DECLARE_UNQUALIFIED_LOCATION_PARSER(animation); + DECLARE_UNQUALIFIED_LOCATION_PARSER(localflags); + DECLARE_UNQUALIFIED_LOCATION_PARSER(commands); + DECLARE_UNQUALIFIED_LOCATION_PARSER(acommands); + DECLARE_UNQUALIFIED_LOCATION_PARSER(flags); + DECLARE_UNQUALIFIED_LOCATION_PARSER(comment); + DECLARE_UNQUALIFIED_LOCATION_PARSER(endcomment); + DECLARE_UNQUALIFIED_LOCATION_PARSER(sound); + DECLARE_UNQUALIFIED_LOCATION_PARSER(music); + DECLARE_UNQUALIFIED_LOCATION_PARSER(redundant); + DECLARE_UNQUALIFIED_ZONE_PARSER(invalid); + DECLARE_UNQUALIFIED_ZONE_PARSER(limits); + DECLARE_UNQUALIFIED_ZONE_PARSER(moveto); + DECLARE_UNQUALIFIED_ZONE_PARSER(type); + DECLARE_UNQUALIFIED_ZONE_PARSER(commands); + DECLARE_UNQUALIFIED_ZONE_PARSER(label); + DECLARE_UNQUALIFIED_ZONE_PARSER(flags); + DECLARE_UNQUALIFIED_ZONE_PARSER(endzone); + DECLARE_UNQUALIFIED_ANIM_PARSER(invalid); + DECLARE_UNQUALIFIED_ANIM_PARSER(script); + DECLARE_UNQUALIFIED_ANIM_PARSER(commands); + DECLARE_UNQUALIFIED_ANIM_PARSER(type); + DECLARE_UNQUALIFIED_ANIM_PARSER(label); + DECLARE_UNQUALIFIED_ANIM_PARSER(flags); + DECLARE_UNQUALIFIED_ANIM_PARSER(file); + DECLARE_UNQUALIFIED_ANIM_PARSER(position); + DECLARE_UNQUALIFIED_ANIM_PARSER(moveto); + DECLARE_UNQUALIFIED_ANIM_PARSER(endanimation); + DECLARE_UNQUALIFIED_COMMAND_PARSER(invalid); + DECLARE_UNQUALIFIED_COMMAND_PARSER(flags); + DECLARE_UNQUALIFIED_COMMAND_PARSER(animation); + DECLARE_UNQUALIFIED_COMMAND_PARSER(zone); + DECLARE_UNQUALIFIED_COMMAND_PARSER(location); + DECLARE_UNQUALIFIED_COMMAND_PARSER(drop); + DECLARE_UNQUALIFIED_COMMAND_PARSER(call); + DECLARE_UNQUALIFIED_COMMAND_PARSER(simple); + DECLARE_UNQUALIFIED_COMMAND_PARSER(move); + DECLARE_UNQUALIFIED_COMMAND_PARSER(endcommands); + + void parseLocation(const char *filename); + char *parseComment(Script &script); + char *parseDialogueString(Script &script); + Dialogue *parseDialogue(Script &script); + void parseZone(Script &script, ZoneList &list, char *name); + void parseZoneTypeBlock(Script &script, Zone *z); + void parseWalkNodes(Script& script, WalkNodeList &list); + Animation *parseAnimation(Script &script, AnimationList &list, char *name); + void parseCommands(Script &script, CommandList&); + void parseCommandFlags(); + void createCommand(uint id); + void addCommand(); + void initOpcodes(); + void initParsers(); + + + // program parser + OpcodeSet _instructionParsers; + Table *_instructionNames; + + struct { + Animation *a; + Instruction *inst; + LocalVariable *locals; + + // BRA specific + Instruction *openIf; + } _instParseCtxt; + + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(defLocal); + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(animation); + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(loop); + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(x); + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(y); + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(z); + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(f); + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(inc); + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(set); + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(move); + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(put); + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(call); + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(sound); + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(null); + + void parseScriptLine(Instruction *inst, Animation *a, LocalVariable *locals); + void loadProgram(Animation *a, const char *filename); + ScriptVar parseLValue(Instruction *inst, const char *str, LocalVariable *locals, Animation *a); + virtual ScriptVar parseRValue(Instruction *inst, const char *str, LocalVariable *locals, Animation *a); + int16 findLocal(const char* name, LocalVariable *locals); + int16 addLocal(const char *name, LocalVariable *locals, int16 value = 0, int16 min = -10000, int16 max = 10000); + void wrapLocalVar(LocalVariable *local); + + DECLARE_UNQUALIFIED_COMMAND_OPCODE(invalid); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(set); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(clear); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(start); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(speak); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(get); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(location); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(open); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(close); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(on); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(off); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(call); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(toggle); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(drop); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(quit); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(move); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(stop); + + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(invalid); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(on); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(off); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(loop); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(endloop); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(null); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(call); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(inc); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(set); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(put); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(wait); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(start); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(sound); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(move); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(end); + }; -class Parallaction_br : public Parallaction { + + + + +class Parallaction_br : public Parallaction_ns { + + typedef Parallaction_ns Super; public: - Parallaction_br(OSystem* syst) : Parallaction(syst) { } + Parallaction_br(OSystem* syst) : Parallaction_ns(syst) { } ~Parallaction_br(); int init(); @@ -797,10 +821,23 @@ public: int _part; int _progress; + int _zeta0; + int _zeta1; + int _zeta2; + + int16 _lipSyncVal; + + Zone *_activeZone2; + + int32 _counters[32]; + private: void initResources(); void initFonts(); void freeFonts(); + void initOpcodes(); + void initParsers(); + void initPart(); void freePart(); @@ -831,6 +868,113 @@ private: void _c_password(void*); const Callable *_callables; +/* + DECLARE_UNQUALIFIED_LOCATION_PARSER(location); + DECLARE_UNQUALIFIED_LOCATION_PARSER(zone); + DECLARE_UNQUALIFIED_LOCATION_PARSER(animation); + DECLARE_UNQUALIFIED_LOCATION_PARSER(localflags); + DECLARE_UNQUALIFIED_LOCATION_PARSER(flags); + DECLARE_UNQUALIFIED_LOCATION_PARSER(comment); + DECLARE_UNQUALIFIED_LOCATION_PARSER(endcomment); + DECLARE_UNQUALIFIED_LOCATION_PARSER(sound); + DECLARE_UNQUALIFIED_LOCATION_PARSER(music); + DECLARE_UNQUALIFIED_LOCATION_PARSER(redundant); + DECLARE_UNQUALIFIED_LOCATION_PARSER(ifchar); + DECLARE_UNQUALIFIED_LOCATION_PARSER(character); + DECLARE_UNQUALIFIED_LOCATION_PARSER(mask); + DECLARE_UNQUALIFIED_LOCATION_PARSER(path); + DECLARE_UNQUALIFIED_LOCATION_PARSER(escape); + DECLARE_UNQUALIFIED_LOCATION_PARSER(zeta); + DECLARE_UNQUALIFIED_LOCATION_PARSER(null); + DECLARE_UNQUALIFIED_COMMAND_PARSER(ifchar); + DECLARE_UNQUALIFIED_COMMAND_PARSER(endif); + DECLARE_UNQUALIFIED_COMMAND_PARSER(zone); + DECLARE_UNQUALIFIED_COMMAND_PARSER(location); + DECLARE_UNQUALIFIED_COMMAND_PARSER(toggle); + DECLARE_UNQUALIFIED_COMMAND_PARSER(string); + DECLARE_UNQUALIFIED_COMMAND_PARSER(math); + DECLARE_UNQUALIFIED_COMMAND_PARSER(test); + DECLARE_UNQUALIFIED_COMMAND_PARSER(music); + DECLARE_UNQUALIFIED_COMMAND_PARSER(zeta); + DECLARE_UNQUALIFIED_COMMAND_PARSER(swap); + DECLARE_UNQUALIFIED_COMMAND_PARSER(give); + DECLARE_UNQUALIFIED_COMMAND_PARSER(text); + DECLARE_UNQUALIFIED_COMMAND_PARSER(unary); + + void parseLocation(const char* name); + + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(zone); + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(color); + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(mask); + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(print); + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(text); + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(if_op); + DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(endif); + + virtual ScriptVar parseRValue(Instruction *inst, const char *str, LocalVariable *locals, Animation *a); + + + DECLARE_UNQUALIFIED_COMMAND_OPCODE(location); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(open); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(close); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(on); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(off); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(call); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(drop); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(move); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(start); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(stop); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(character); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(followme); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(onmouse); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(offmouse); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(add); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(leave); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(inc); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(dec); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(ifeq); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(iflt); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(ifgt); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(let); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(music); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(fix); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(unfix); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(zeta); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(scroll); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(swap); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(give); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(text); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(part); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(testsfx); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(ret); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(onsave); + DECLARE_UNQUALIFIED_COMMAND_OPCODE(offsave); + + + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(on); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(off); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(loop); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(inc); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(dec); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(set); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(put); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(wait); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(start); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(process); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(move); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(color); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(mask); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(print); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(text); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(mul); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(div); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(ifeq); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(iflt); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(ifgt); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(endif); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(stop); + DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(endscript); +*/ }; // FIXME: remove global diff --git a/engines/parallaction/parallaction_br.cpp b/engines/parallaction/parallaction_br.cpp index 955994a307..3fd56b80aa 100644 --- a/engines/parallaction/parallaction_br.cpp +++ b/engines/parallaction/parallaction_br.cpp @@ -79,10 +79,14 @@ int Parallaction_br::init() { _soundMan = new DummySoundMan(this); + _activeZone2 = 0; + initResources(); initFonts(); initCursors(); - +/* initOpcodes(); + initParsers(); +*/ _part = -1; Parallaction::init(); @@ -316,6 +320,8 @@ void Parallaction_br::setMousePointer(int16 index) { void Parallaction_br::initPart() { + memset(_counters, 0, ARRAYSIZE(_counters)); + _globalTable = _disk->loadTable("global"); _objectsNames = _disk->loadTable("objects"); _countersNames = _disk->loadTable("counters"); @@ -343,83 +349,5 @@ void Parallaction_br::startPart() { } -void skip(Script* script, const char* endToken) { - - while (scumm_stricmp(_tokens[0], endToken)) { - fillBuffers(*script, true); - } - -} -#if 0 -bool Parallaction_br::parseLocationLine(const char *filename, Script *script) { - - bool parsed = true; - bool flip = false; - int nextToken = 0; - - if (!scumm_stricmp(_tokens[0], "LOCATION")) { - - strcpy(_location._name, _tokens[1]); - _disk->loadScenery(*_backgroundInfo, _location._name, NULL, NULL); - _gfx->setBackground(&_backgroundInfo->bg); - _gfx->_palette.clone(_backgroundInfo->palette); - _gfx->setPalette(_backgroundInfo->palette); - - if (!scumm_stricmp("flip", _tokens[2])) { - flip = true; - nextToken = 3; - } else { - nextToken = 2; - } - - if (_tokens[nextToken][0] != '\0') { - _char._ani._left = atoi(_tokens[nextToken]); - nextToken++; - _char._ani._top = atoi(_tokens[nextToken]); - nextToken++; - } - - if (_tokens[nextToken][0] != '\0') { - _char._ani._frame = atoi(_tokens[nextToken]); - } - } else - if (!scumm_stricmp(_tokens[0], "IFCHAR")) { - skip(script, "ENDIF"); - } else - if (!scumm_stricmp(_tokens[0], "CHARACTER")) { - - } else - if (!scumm_stricmp(_tokens[0], "MASK")) { - _disk->loadScenery(*_backgroundInfo, NULL, _tokens[1], NULL); - _gfx->setMask(&_backgroundInfo->mask); - - _gfx->_bgLayers[0] = atoi(_tokens[2]); - _gfx->_bgLayers[1] = atoi(_tokens[3]); - _gfx->_bgLayers[2] = atoi(_tokens[4]); - } else - if (!scumm_stricmp(_tokens[0], "PATH")) { - _disk->loadScenery(*_backgroundInfo, NULL, NULL, _tokens[1]); - _pathBuffer = &_backgroundInfo->path; - } else - if (!scumm_stricmp(_tokens[0], "DISK")) { - // - } else - if (!scumm_stricmp(_tokens[0], "ESCAPE")) { - skip(script, "endcommands"); - } else - if (!scumm_stricmp(_tokens[0], "ZETA")) { - // - } else - if (!scumm_stricmp(_tokens[0], "ZONE")) { - skip(script, "endzone"); - } else - if (!scumm_stricmp(_tokens[0], "ANIMATION")) { - skip(script, "endanimation"); - } else - parsed = false; - - return parsed; -} -#endif } // namespace Parallaction diff --git a/engines/parallaction/parallaction_ns.cpp b/engines/parallaction/parallaction_ns.cpp index e98ef3847c..2a82002f24 100644 --- a/engines/parallaction/parallaction_ns.cpp +++ b/engines/parallaction/parallaction_ns.cpp @@ -74,6 +74,8 @@ int Parallaction_ns::init() { initResources(); initFonts(); initCursors(); + initOpcodes(); + initParsers(); Parallaction::init(); @@ -85,6 +87,12 @@ Parallaction_ns::~Parallaction_ns() { _mouseComposedArrow->free(); delete _mouseComposedArrow; + + + delete _commandsNames; + delete _instructionNames; + delete _locationStmt; + } @@ -200,4 +208,5 @@ int Parallaction_ns::go() { } + } // namespace Parallaction diff --git a/engines/parallaction/parser.cpp b/engines/parallaction/parser.cpp index 34b5e02f8e..dfda083392 100644 --- a/engines/parallaction/parser.cpp +++ b/engines/parallaction/parser.cpp @@ -82,33 +82,6 @@ void Script::seek(int32 offset, int whence) { error("seek not supported on Script streams"); } -// -// a comment can appear both at location and Zone levels -// comments are displayed into rectangles on the screen -// -char *Parallaction::parseComment(Script &script) { - - char _tmp_comment[1000] = "\0"; - char *v194; - - do { - char v190[400]; - v194 = script.readLine(v190, 400); - - v194[strlen(v194)-1] = '\0'; - if (!scumm_stricmp(v194, "endtext")) - break; - - strcat(_tmp_comment, v194); - strcat(_tmp_comment, " "); - } while (true); - - v194 = strdup(_tmp_comment); - _tmp_comment[0] = '\0'; - - return v194; -} - void clearTokens() { for (uint16 i = 0; i < 20; i++) @@ -118,6 +91,14 @@ void clearTokens() { } +void skip(Script* script, const char* endToken) { + + while (scumm_stricmp(_tokens[0], endToken)) { + fillBuffers(*script, true); + } + +} + // // Scans 's' until one of the stop-chars in 'brk' is found, building a token. // If the routine encounters quotes, it will extract the contained text and diff --git a/engines/parallaction/parser.h b/engines/parallaction/parser.h index aa3929a52c..3d1b32ec3a 100644 --- a/engines/parallaction/parser.h +++ b/engines/parallaction/parser.h @@ -57,6 +57,9 @@ public: void seek(int32 offset, int whence = SEEK_SET); }; +void skip(Script* script, const char* endToken); + + } // namespace Parallaction #endif diff --git a/engines/parallaction/parser_ns.cpp b/engines/parallaction/parser_ns.cpp new file mode 100644 index 0000000000..093e95e5f4 --- /dev/null +++ b/engines/parallaction/parser_ns.cpp @@ -0,0 +1,1355 @@ +/* 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$ + * + */ + +#include "common/stdafx.h" + +#include "parallaction/parallaction.h" +#include "parallaction/sound.h" + +namespace Parallaction { + +#define CMD_SET 1 +#define CMD_CLEAR 2 +#define CMD_START 3 +#define CMD_SPEAK 4 +#define CMD_GET 5 +#define CMD_LOCATION 6 +#define CMD_OPEN 7 +#define CMD_CLOSE 8 +#define CMD_ON 9 +#define CMD_OFF 10 +#define CMD_CALL 11 +#define CMD_TOGGLE 12 +#define CMD_DROP 13 +#define CMD_QUIT 14 +#define CMD_MOVE 15 +#define CMD_STOP 16 + +#define INST_ON 1 +#define INST_OFF 2 +#define INST_X 3 +#define INST_Y 4 +#define INST_Z 5 +#define INST_F 6 +#define INST_LOOP 7 +#define INST_ENDLOOP 8 +#define INST_SHOW 9 +#define INST_INC 10 +#define INST_DEC 11 +#define INST_SET 12 +#define INST_PUT 13 +#define INST_CALL 14 +#define INST_WAIT 15 +#define INST_START 16 +#define INST_SOUND 17 +#define INST_MOVE 18 +#define INST_END 19 + + +#define DECLARE_ZONE_PARSER(sig) void Parallaction_ns::locZoneParse_##sig() +#define DECLARE_ANIM_PARSER(sig) void Parallaction_ns::locAnimParse_##sig() +#define DECLARE_COMMAND_PARSER(sig) void Parallaction_ns::cmdParse_##sig() +#define DECLARE_INSTRUCTION_PARSER(sig) void Parallaction_ns::instParse_##sig() +#define DECLARE_LOCATION_PARSER(sig) void Parallaction_ns::locParse_##sig() + + +#define NUM_LOCALS 10 + +uint16 _numLocals = 0; +char _localNames[NUM_LOCALS][10]; + + +DECLARE_ANIM_PARSER(invalid) { + error("unknown statement '%s' in animation %s", _tokens[0], _locAnimParseCtxt.a->_label._text); +} + + +DECLARE_ANIM_PARSER(script) { + _locAnimParseCtxt.a->_scriptName = strdup(_tokens[1]); +} + + +DECLARE_ANIM_PARSER(commands) { + parseCommands(*_locAnimParseCtxt.script, _locAnimParseCtxt.a->_commands); +} + + +DECLARE_ANIM_PARSER(type) { + if (_tokens[2][0] != '\0') { + _locAnimParseCtxt.a->_type = ((4 + _objectsNames->lookup(_tokens[2])) << 16) & 0xFFFF0000; + } + int16 _si = _zoneTypeNames->lookup(_tokens[1]); + if (_si != Table::notFound) { + _locAnimParseCtxt.a->_type |= 1 << (_si-1); + if (((_locAnimParseCtxt.a->_type & 0xFFFF) != kZoneNone) && ((_locAnimParseCtxt.a->_type & 0xFFFF) != kZoneCommand)) { + parseZoneTypeBlock(*_locAnimParseCtxt.script, _locAnimParseCtxt.a); + } + } + + _locAnimParseCtxt.a->_oldPos.x = -1000; + _locAnimParseCtxt.a->_oldPos.y = -1000; + + _locAnimParseCtxt.a->_flags |= 0x1000000; + + popParserTables(); +} + + +DECLARE_ANIM_PARSER(label) { + renderLabel(&_locAnimParseCtxt.a->_label._cnv, _tokens[1]); +} + + +DECLARE_ANIM_PARSER(flags) { + uint16 _si = 1; + + do { + byte _al = _zoneFlagNames->lookup(_tokens[_si]); + _si++; + _locAnimParseCtxt.a->_flags |= 1 << (_al - 1); + } while (!scumm_stricmp(_tokens[_si++], "|")); +} + + +DECLARE_ANIM_PARSER(file) { + char vC8[200]; + strcpy(vC8, _tokens[1]); + if (_engineFlags & kEngineTransformedDonna) { + if (!scumm_stricmp(_tokens[1], "donnap") || !scumm_stricmp(_tokens[1], "donnapa")) { + strcat(vC8, "tras"); + } + } + _locAnimParseCtxt.a->_cnv = _disk->loadFrames(vC8); +} + + +DECLARE_ANIM_PARSER(position) { + _locAnimParseCtxt.a->_left = atoi(_tokens[1]); + _locAnimParseCtxt.a->_top = atoi(_tokens[2]); + _locAnimParseCtxt.a->_z = atoi(_tokens[3]); +} + + +DECLARE_ANIM_PARSER(moveto) { + _locAnimParseCtxt.a->_moveTo.x = atoi(_tokens[1]); + _locAnimParseCtxt.a->_moveTo.y = atoi(_tokens[2]); +} + + +DECLARE_ANIM_PARSER(endanimation) { + + _locAnimParseCtxt.a->_oldPos.x = -1000; + _locAnimParseCtxt.a->_oldPos.y = -1000; + + _locAnimParseCtxt.a->_flags |= 0x1000000; + + popParserTables(); +} + +Animation *Parallaction_ns::parseAnimation(Script& script, AnimationList &list, char *name) { +// printf("parseAnimation(%s)\n", name); + + Animation *a = new Animation; + + a->_label._text = strdup(name); + + list.push_front(a); + + _locAnimParseCtxt.a = a; + _locAnimParseCtxt.end = false; + _locAnimParseCtxt.script = &script; + + pushParserTables(&_locationAnimParsers, _locationAnimStmt); + + return a; +} + +void Parallaction_ns::loadProgram(Animation *a, const char *filename) { +// printf("loadProgram(%s)\n", filename); + + Script *script = _disk->loadScript(filename); + + _numLocals = 0; + + fillBuffers(*script); + + a->_program = new Program; + + Instruction *vCC = new Instruction; + + _instParseCtxt.openIf = NULL; + + while (scumm_stricmp(_tokens[0], "endscript")) { + parseScriptLine(vCC, a, a->_program->_locals); + a->_program->_instructions.push_back(vCC); + vCC = new Instruction; + fillBuffers(*script); + } + + // TODO: use List<>::end() to detect the end of the program + vCC->_index = INST_END; + a->_program->_instructions.push_back(vCC); + a->_program->_ip = a->_program->_instructions.begin(); + + delete script; + + return; +} + +int16 Parallaction_ns::findLocal(const char* name, LocalVariable *locals) { + for (uint16 _si = 0; _si < NUM_LOCALS; _si++) { + if (!scumm_stricmp(name, _localNames[_si])) + return _si; + } + + return -1; +} + +int16 Parallaction_ns::addLocal(const char *name, LocalVariable *locals, int16 value, int16 min, int16 max) { + assert(_numLocals < NUM_LOCALS); + + strcpy(_localNames[_numLocals], name); + locals[_numLocals]._value = value; + + locals[_numLocals]._min = min; + locals[_numLocals]._max = max; + + return _numLocals++; +} + + +DECLARE_INSTRUCTION_PARSER(animation) { + if (!scumm_stricmp(_tokens[1], _instParseCtxt.a->_label._text)) { + _instParseCtxt.inst->_opBase._a = _instParseCtxt.a; + } else { + _instParseCtxt.inst->_opBase._a = findAnimation(_tokens[1]); + } +} + + +DECLARE_INSTRUCTION_PARSER(loop) { + _instParseCtxt.inst->_opBase._loopCounter = parseRValue(_instParseCtxt.inst, _tokens[1], _instParseCtxt.locals, _instParseCtxt.a); +} + + +DECLARE_INSTRUCTION_PARSER(x) { + _instParseCtxt.inst->_opA._pvalue = &_instParseCtxt.a->_left; + _instParseCtxt.inst->_opB = parseRValue(_instParseCtxt.inst, _tokens[1], _instParseCtxt.locals, _instParseCtxt.a); +} + + +DECLARE_INSTRUCTION_PARSER(y) { + _instParseCtxt.inst->_opA._pvalue = &_instParseCtxt.a->_top; + _instParseCtxt.inst->_opB = parseRValue(_instParseCtxt.inst, _tokens[1], _instParseCtxt.locals, _instParseCtxt.a); +} + + +DECLARE_INSTRUCTION_PARSER(z) { + _instParseCtxt.inst->_opA._pvalue = &_instParseCtxt.a->_z; + _instParseCtxt.inst->_opB = parseRValue(_instParseCtxt.inst, _tokens[1], _instParseCtxt.locals, _instParseCtxt.a); +} + + +DECLARE_INSTRUCTION_PARSER(f) { + _instParseCtxt.inst->_opA._pvalue = &_instParseCtxt.a->_frame; + _instParseCtxt.inst->_opB = parseRValue(_instParseCtxt.inst, _tokens[1], _instParseCtxt.locals, _instParseCtxt.a); +} + + +DECLARE_INSTRUCTION_PARSER(inc) { + _instParseCtxt.inst->_opA = parseLValue(_instParseCtxt.inst, _tokens[1], _instParseCtxt.locals, _instParseCtxt.a); + _instParseCtxt.inst->_opB = parseRValue(_instParseCtxt.inst, _tokens[2], _instParseCtxt.locals, _instParseCtxt.a); + + if (!scumm_stricmp(_tokens[3], "mod")) { + _instParseCtxt.inst->_flags |= kInstMod; + } +} + + +DECLARE_INSTRUCTION_PARSER(set) { + // WORKAROUND: At least one script (balzo.script) in Amiga versions didn't declare + // local variables before using them, thus leading to crashes. The line launching the + // script was commented out on Dos version. This workaround enables the engine + // to dynamically add a local variable when it is encountered the first time in + // the script, so should fix any other occurrence as well. + if (findLocal(_tokens[1], _instParseCtxt.locals) == -1) { + addLocal(_tokens[1], _instParseCtxt.locals); + } + + _instParseCtxt.inst->_opA = parseLValue(_instParseCtxt.inst, _tokens[1], _instParseCtxt.locals, _instParseCtxt.a); + _instParseCtxt.inst->_opB = parseRValue(_instParseCtxt.inst, _tokens[2], _instParseCtxt.locals, _instParseCtxt.a); +} + + +DECLARE_INSTRUCTION_PARSER(move) { + _instParseCtxt.inst->_opA = parseRValue(_instParseCtxt.inst, _tokens[1], _instParseCtxt.locals, _instParseCtxt.a); + _instParseCtxt.inst->_opB = parseRValue(_instParseCtxt.inst, _tokens[2], _instParseCtxt.locals, _instParseCtxt.a); +} + + +DECLARE_INSTRUCTION_PARSER(put) { + if (!scumm_stricmp(_tokens[1], _instParseCtxt.a->_label._text)) { + _instParseCtxt.inst->_opBase._a = _instParseCtxt.a; + } else { + _instParseCtxt.inst->_opBase._a = findAnimation(_tokens[1]); + } + + _instParseCtxt.inst->_opA = parseRValue(_instParseCtxt.inst, _tokens[2], _instParseCtxt.locals, _instParseCtxt.a); + _instParseCtxt.inst->_opB = parseRValue(_instParseCtxt.inst, _tokens[3], _instParseCtxt.locals, _instParseCtxt.a); + if (!scumm_stricmp(_tokens[4], "masked")) { + _instParseCtxt.inst->_flags |= kInstMaskedPut; + } +} + + +DECLARE_INSTRUCTION_PARSER(call) { + int index = _callableNames->lookup(_tokens[1]); + if (index == Table::notFound) + error("unknown callable '%s'", _tokens[1]); + _instParseCtxt.inst->_opBase._index = index - 1; +} + + +DECLARE_INSTRUCTION_PARSER(sound) { + _instParseCtxt.inst->_opBase._z = findZone(_tokens[1]); +} + + +DECLARE_INSTRUCTION_PARSER(null) { + +} + + +DECLARE_INSTRUCTION_PARSER(defLocal) { + int16 val = atoi(_tokens[2]); + int16 index; + + if (_tokens[3][0] != '\0') { + index = addLocal(_tokens[0], _instParseCtxt.locals, val, atoi(_tokens[3]), atoi(_tokens[4])); + } else { + index = addLocal(_tokens[0], _instParseCtxt.locals, val); + } + + _instParseCtxt.inst->_opA._local = &_instParseCtxt.locals[index]; + _instParseCtxt.inst->_opB._value = _instParseCtxt.locals[index]._value; + + _instParseCtxt.inst->_flags = kInstUsesLiteral | kInstUsesLocal; + _instParseCtxt.inst->_index = INST_SET; +} + + + + +void Parallaction_ns::parseScriptLine(Instruction *inst, Animation *a, LocalVariable *locals) { +// printf("parseScriptLine()\n"); + + if (_tokens[0][1] == '.') { + _tokens[0][1] = '\0'; + a = findAnimation(&_tokens[0][2]); + } + + if (_tokens[1][1] == '.') { + _tokens[1][1] = '\0'; + a = findAnimation(&_tokens[1][2]); + } + + int16 _si = _instructionNames->lookup(_tokens[0]); + inst->_index = _si; + + _instParseCtxt.a = a; + _instParseCtxt.inst = inst; + _instParseCtxt.locals = locals; + + (*(_instructionParsers[inst->_index]))(); + + return; +} + +ScriptVar Parallaction_ns::parseRValue(Instruction *inst, const char *str, LocalVariable *locals, Animation *a) { + + ScriptVar v; + + v._pvalue = 0; // should stop compiler from complaining + + if (isdigit(str[0]) || str[0] == '-') { + inst->_flags |= kInstUsesLiteral; + v._value = atoi(str); + return v; + } + + int index = findLocal(str, locals); + if (index != -1) { + v._local = &locals[index]; + inst->_flags |= kInstUsesLocal; + return v; + } + + if (str[1] == '.') { + a = findAnimation(&str[2]); + } + + if (str[0] == 'X') { + v._pvalue = &a->_left; + inst->_flags |= kInstUsesField; + } else + if (str[0] == 'Y') { + v._pvalue = &a->_top; + inst->_flags |= kInstUsesField; + } else + if (str[0] == 'Z') { + v._pvalue = &a->_z; + inst->_flags |= kInstUsesField; + } else + if (str[0] == 'F') { + v._pvalue = &a->_frame; + inst->_flags |= kInstUsesField; + } + + return v; +} + +ScriptVar Parallaction_ns::parseLValue(Instruction *inst, const char *str, LocalVariable *locals, Animation *a) { + + ScriptVar v; + + v._pvalue = 0; // should stop compiler from complaining + + int index = findLocal(str, locals); + if (index != -1) { + v._local = &locals[index]; + inst->_flags |= kInstUsesLocal; + return v; + } + + if (str[1] == '.') { + a = findAnimation(&str[2]); + } + + if (str[0] == 'X') { + v._pvalue = &a->_left; + inst->_flags |= kInstUsesField; + } else + if (str[0] == 'Y') { + v._pvalue = &a->_top; + inst->_flags |= kInstUsesField; + } else + if (str[0] == 'Z') { + v._pvalue = &a->_z; + inst->_flags |= kInstUsesField; + } else + if (str[0] == 'F') { + v._pvalue = &a->_frame; + inst->_flags |= kInstUsesField; + } + + return v; +} + + +DECLARE_COMMAND_PARSER(flags) { + createCommand(_lookup); + + if (_globalTable->lookup(_tokens[1]) == Table::notFound) { + 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--; + } + + parseCommandFlags(); + addCommand(); +} + + +DECLARE_COMMAND_PARSER(animation) { + createCommand(_lookup); + + _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++; + } + + parseCommandFlags(); + addCommand(); +} + + +DECLARE_COMMAND_PARSER(zone) { + createCommand(_lookup); + + _cmdParseCtxt.cmd->u._zone = findZone(_tokens[_cmdParseCtxt.nextToken]); + _cmdParseCtxt.nextToken++; + + parseCommandFlags(); + addCommand(); +} + + +DECLARE_COMMAND_PARSER(location) { + createCommand(_lookup); + + _cmdParseCtxt.cmd->u._string = (char*)malloc(strlen(_tokens[_cmdParseCtxt.nextToken])+1); + strcpy(_cmdParseCtxt.cmd->u._string, _tokens[_cmdParseCtxt.nextToken]); + _cmdParseCtxt.nextToken++; + + parseCommandFlags(); + addCommand(); +} + + +DECLARE_COMMAND_PARSER(drop) { + createCommand(_lookup); + + _cmdParseCtxt.cmd->u._object = 4 + _objectsNames->lookup(_tokens[_cmdParseCtxt.nextToken]); + _cmdParseCtxt.nextToken++; + + parseCommandFlags(); + addCommand(); +} + + +DECLARE_COMMAND_PARSER(call) { + createCommand(_lookup); + + _cmdParseCtxt.cmd->u._callable = _callableNames->lookup(_tokens[_cmdParseCtxt.nextToken]) - 1; + _cmdParseCtxt.nextToken++; + + parseCommandFlags(); + addCommand(); +} + + +DECLARE_COMMAND_PARSER(simple) { + createCommand(_lookup); + addCommand(); +} + + +DECLARE_COMMAND_PARSER(move) { + createCommand(_lookup); + + _cmdParseCtxt.cmd->u._move.x = atoi(_tokens[_cmdParseCtxt.nextToken]); + _cmdParseCtxt.nextToken++; + _cmdParseCtxt.cmd->u._move.y = atoi(_tokens[_cmdParseCtxt.nextToken]); + _cmdParseCtxt.nextToken++; + + parseCommandFlags(); + addCommand(); +} + +DECLARE_COMMAND_PARSER(invalid) { + error("Can't parse unknown command '%s'", _tokens[0]); +} + +DECLARE_COMMAND_PARSER(endcommands) { + popParserTables(); + + // temporary trick to handle dialogue commands + _cmdParseCtxt.end = true; +} + +void Parallaction_ns::parseCommandFlags() { + + int _si = _cmdParseCtxt.nextToken; + Command *cmd = _cmdParseCtxt.cmd; + + if (!scumm_stricmp(_tokens[_si], "flags")) { + _si++; + + do { + if (!scumm_stricmp(_tokens[_si], "exit") || !scumm_stricmp(_tokens[_si], "exittrap")) { + cmd->_flagsOn |= kFlagsExit; + } else + if (!scumm_stricmp(_tokens[_si], "enter") || !scumm_stricmp(_tokens[_si], "entertrap")) { + cmd->_flagsOn |= kFlagsEnter; + } else + if (!scumm_strnicmp(_tokens[_si], "no", 2)) { + byte _al = _localFlagNames->lookup(&_tokens[_si][2]); + cmd->_flagsOff |= 1 << (_al - 1); + } else { + byte _al = _localFlagNames->lookup(_tokens[_si]); + cmd->_flagsOn |= 1 << (_al - 1); + } + + _si++; + + } while (!scumm_stricmp(_tokens[_si++], "|")); + + } + + if (!scumm_stricmp(_tokens[_si], "gflags")) { + _si++; + cmd->_flagsOn |= kFlagsGlobal; + + do { + if (!scumm_stricmp(_tokens[_si], "exit")) { + cmd->_flagsOn |= kFlagsExit; + } else + if (!scumm_stricmp(_tokens[_si], "enter")) { + cmd->_flagsOn |= kFlagsEnter; + } else + if (!scumm_strnicmp(_tokens[_si], "no", 2)) { + byte _al = _globalTable->lookup(&_tokens[_si][2]); + cmd->_flagsOff |= 1 << (_al - 1); + } else { + byte _al = _globalTable->lookup(_tokens[_si]); + cmd->_flagsOn |= 1 << (_al - 1); + } + + _si++; + + } while (!scumm_stricmp(_tokens[_si++], "|")); + + } + + _si = _cmdParseCtxt.nextToken; + +} + +void Parallaction_ns::addCommand() { + _cmdParseCtxt.list->push_front(_cmdParseCtxt.cmd); // NOTE: command lists are written backwards in scripts +} + +void Parallaction_ns::createCommand(uint id) { + + _cmdParseCtxt.nextToken = 1; + _cmdParseCtxt.cmd = new Command; + _cmdParseCtxt.cmd->_id = id; + +} + +void Parallaction_ns::parseCommands(Script &script, CommandList& list) { + _cmdParseCtxt.list = &list; + _cmdParseCtxt.end = false; + _cmdParseCtxt.script = &script; + + pushParserTables(&_commandParsers, _commandsNames); + +} + +Dialogue *Parallaction_ns::parseDialogue(Script &script) { +// printf("parseDialogue()\n"); + uint16 numQuestions = 0; + + Dialogue *dialogue = new Dialogue; + + Table forwards(20); + + fillBuffers(script, true); + + while (scumm_stricmp(_tokens[0], "enddialogue")) { + if (scumm_stricmp(_tokens[0], "Question")) continue; + + Question *question = new Question; + dialogue->_questions[numQuestions] = question; + + forwards.addData(_tokens[1]); + + question->_text = parseDialogueString(script); + + fillBuffers(script, true); + question->_mood = atoi(_tokens[0]); + + uint16 numAnswers = 0; + + fillBuffers(script, true); + while (scumm_stricmp(_tokens[0], "endquestion")) { // parse answers + + Answer *answer = new Answer; + question->_answers[numAnswers] = answer; + + if (_tokens[1][0]) { + + Table* flagNames; + uint16 token; + + if (!scumm_stricmp(_tokens[1], "global")) { + token = 2; + flagNames = _globalTable; + answer->_yesFlags |= kFlagsGlobal; + } else { + token = 1; + flagNames = _localFlagNames; + } + + do { + + if (!scumm_strnicmp(_tokens[token], "no", 2)) { + byte _al = flagNames->lookup(_tokens[token]+2); + answer->_noFlags |= 1 << (_al - 1); + } else { + byte _al = flagNames->lookup(_tokens[token]); + answer->_yesFlags |= 1 << (_al - 1); + } + + token++; + + } while (!scumm_stricmp(_tokens[token++], "|")); + + } + + answer->_text = parseDialogueString(script); + + fillBuffers(script, true); + answer->_mood = atoi(_tokens[0]); + answer->_following._name = parseDialogueString(script); + + fillBuffers(script, true); + if (!scumm_stricmp(_tokens[0], "commands")) { + + parseCommands(script, answer->_commands); + _cmdParseCtxt.end = false; + do { + fillBuffers(script, true); + parseStatement(); + } while (!_cmdParseCtxt.end); + + fillBuffers(script, true); + } + + numAnswers++; + } + + fillBuffers(script, true); + numQuestions++; + + } + + // link questions + byte v50[20]; + memset(v50, 0, 20); + + for (uint16 i = 0; i < numQuestions; i++) { + Question *question = dialogue->_questions[i]; + + for (uint16 j = 0; j < NUM_ANSWERS; j++) { + Answer *answer = question->_answers[j]; + if (answer == 0) continue; + + int16 index = forwards.lookup(answer->_following._name); + free(answer->_following._name); + + if (index == Table::notFound) + answer->_following._question = 0; + else + answer->_following._question = dialogue->_questions[index - 1]; + + + } + } + + return dialogue; +} + + +char *Parallaction_ns::parseDialogueString(Script &script) { + + char vC8[200]; + char *vD0 = NULL; + do { + + vD0 = script.readLine(vC8, 200); + if (vD0 == 0) return NULL; + + vD0 = Common::ltrim(vD0); + + } while (strlen(vD0) == 0); + + vD0[strlen(vD0)-1] = '\0'; // deletes the trailing '0xA' + // this is critical for Gfx::displayWrappedString to work properly + return strdup(vD0); +} + + +DECLARE_LOCATION_PARSER(invalid) { + error("unknown keyword '%s' in location '%s'", _tokens[0], _locParseCtxt.filename); +} + +DECLARE_LOCATION_PARSER(endlocation) { + _locParseCtxt.end = true; +} + + +DECLARE_LOCATION_PARSER(location) { + // The parameter for location is 'location.mask'. + // If mask is not present, then it is assumed + // that path & mask are encoded in the background + // bitmap, otherwise a separate .msk file exists. + + char *mask = strchr(_tokens[1], '.'); + if (mask) { + mask[0] = '\0'; + mask++; + } + + strcpy(_location._name, _tokens[1]); + switchBackground(_location._name, mask); + + if (_tokens[2][0] != '\0') { + _char._ani._left = atoi(_tokens[2]); + _char._ani._top = atoi(_tokens[3]); + } + + if (_tokens[4][0] != '\0') { + _char._ani._frame = atoi(_tokens[4]); + } +} + + +DECLARE_LOCATION_PARSER(disk) { + _disk->selectArchive(_tokens[1]); +} + + +DECLARE_LOCATION_PARSER(nodes) { + parseWalkNodes(*_locParseCtxt.script, _location._walkNodes); +} + + +DECLARE_LOCATION_PARSER(zone) { + parseZone(*_locParseCtxt.script, _zones, _tokens[1]); +} + + +DECLARE_LOCATION_PARSER(animation) { + parseAnimation(*_locParseCtxt.script, _animations, _tokens[1]); +} + + +DECLARE_LOCATION_PARSER(localflags) { + int _si = 1; // _localFlagNames[0] = 'visited' + while (_tokens[_si][0] != '\0') { + _localFlagNames->addData(_tokens[_si]); + _si++; + } +} + + +DECLARE_LOCATION_PARSER(commands) { + parseCommands(*_locParseCtxt.script, _location._commands); +} + + +DECLARE_LOCATION_PARSER(acommands) { + parseCommands(*_locParseCtxt.script, _location._aCommands); +} + + +DECLARE_LOCATION_PARSER(flags) { + if ((_localFlags[_currentLocationIndex] & kFlagsVisited) == 0) { + // only for 1st visit + _localFlags[_currentLocationIndex] = 0; + int _si = 1; + + do { + byte _al = _localFlagNames->lookup(_tokens[_si]); + _localFlags[_currentLocationIndex] |= 1 << (_al - 1); + + _si++; + if (scumm_stricmp(_tokens[_si], "|")) break; + _si++; + } while (true); + } +} + + +DECLARE_LOCATION_PARSER(comment) { + _location._comment = parseComment(*_locParseCtxt.script); +} + + +DECLARE_LOCATION_PARSER(endcomment) { + _location._endComment = parseComment(*_locParseCtxt.script); +} + + +DECLARE_LOCATION_PARSER(sound) { + if (getPlatform() == Common::kPlatformAmiga) { + strcpy(_locationSound, _tokens[1]); + _hasLocationSound = true; + } +} + + +DECLARE_LOCATION_PARSER(music) { + if (getPlatform() == Common::kPlatformAmiga) + _soundMan->setMusicFile(_tokens[1]); +} + +DECLARE_LOCATION_PARSER(redundant) { + warning("redundant '%s' line found in script '%s'", _tokens[0], _locParseCtxt.filename); +} + + +void Parallaction_ns::parseLocation(const char *filename) { + debugC(1, kDebugLocation, "parseLocation('%s')", filename); + + allocateLocationSlot(filename); + + Script *script = _disk->loadLocation(filename); + + // TODO: the following two lines are specific to Nippon Safes + // and should be moved into something like 'initializeParsing()' + _gfx->setFont(_labelFont); + _hasLocationSound = false; + + _locParseCtxt.end = false; + _locParseCtxt.script = script; + _locParseCtxt.filename = filename; + + pushParserTables(&_locationParsers, _locationStmt); + + do { + + fillBuffers(*script, true); + + parseStatement(); + + } while (!_locParseCtxt.end); + + popParserTables(); + + delete script; + + // this resolves any forward references in the script + for (uint16 _si = 0; _forwardedCommands[_si]; _si++) { + _forwardedCommands[_si]->u._animation = findAnimation(_forwardedAnimationNames[_si]); + _forwardedCommands[_si] = NULL; + } + _numForwards = 0; + + // this loads animation scripts + AnimationList::iterator it = _animations.begin(); + for ( ; it != _animations.end(); it++) { + if ((*it)->_scriptName) + loadProgram(*it, (*it)->_scriptName); + } + return; +} + + +void Parallaction_ns::parseWalkNodes(Script& script, WalkNodeList &list) { + + fillBuffers(script, true); + while (scumm_stricmp(_tokens[0], "ENDNODES")) { + + if (!scumm_stricmp(_tokens[0], "COORD")) { + + WalkNode *v4 = new WalkNode( + atoi(_tokens[1]) - _char._ani.width()/2, + atoi(_tokens[2]) - _char._ani.height() + ); + + list.push_front(v4); + } + + fillBuffers(script, true); + } + + return; + +} + +typedef OpcodeImpl<Parallaction_ns> OpcodeV1; +#define INSTRUCTION_PARSER(sig) OpcodeV1(this, &Parallaction_ns::instParse_##sig) +#define ZONE_PARSER(sig) OpcodeV1(this, &Parallaction_ns::locZoneParse_##sig) +#define ANIM_PARSER(sig) OpcodeV1(this, &Parallaction_ns::locAnimParse_##sig) +#define LOCATION_PARSER(sig) OpcodeV1(this, &Parallaction_ns::locParse_##sig) +#define COMMAND_PARSER(sig) OpcodeV1(this, &Parallaction_ns::cmdParse_##sig) + +void Parallaction_ns::initParsers() { + + static const OpcodeV1 op0[] = { + INSTRUCTION_PARSER(defLocal), // invalid opcode -> local definition + INSTRUCTION_PARSER(animation), // on + INSTRUCTION_PARSER(animation), // off + INSTRUCTION_PARSER(x), + INSTRUCTION_PARSER(y), + INSTRUCTION_PARSER(z), + INSTRUCTION_PARSER(f), + INSTRUCTION_PARSER(loop), + INSTRUCTION_PARSER(null), // endloop + INSTRUCTION_PARSER(null), // show + INSTRUCTION_PARSER(inc), + INSTRUCTION_PARSER(inc), // dec + INSTRUCTION_PARSER(set), + INSTRUCTION_PARSER(put), + INSTRUCTION_PARSER(call), + INSTRUCTION_PARSER(null), // wait + INSTRUCTION_PARSER(animation), // start + INSTRUCTION_PARSER(sound), + INSTRUCTION_PARSER(move) + }; + + uint i; + for (i = 0; i < ARRAYSIZE(op0); i++) + _instructionParsers.push_back(&op0[i]); + + + static const OpcodeV1 op2[] = { + COMMAND_PARSER(invalid), + 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(simple), // quit + COMMAND_PARSER(move), // move + COMMAND_PARSER(animation), // stop + COMMAND_PARSER(endcommands), // endcommands + COMMAND_PARSER(endcommands) // endzone + }; + + for (i = 0; i < ARRAYSIZE(op2); i++) + _commandParsers.push_back(&op2[i]); + + + static const OpcodeV1 op4[] = { + LOCATION_PARSER(invalid), + LOCATION_PARSER(endlocation), + LOCATION_PARSER(location), + LOCATION_PARSER(disk), + LOCATION_PARSER(nodes), + LOCATION_PARSER(zone), + LOCATION_PARSER(animation), + LOCATION_PARSER(localflags), + LOCATION_PARSER(commands), + LOCATION_PARSER(acommands), + LOCATION_PARSER(flags), + LOCATION_PARSER(comment), + LOCATION_PARSER(endcomment), + LOCATION_PARSER(sound), + LOCATION_PARSER(music), + LOCATION_PARSER(redundant) // for redundant endanimation + }; + + for (i = 0; i < ARRAYSIZE(op4); i++) + _locationParsers.push_back(&op4[i]); + + static const OpcodeV1 op5[] = { + ZONE_PARSER(invalid), + ZONE_PARSER(limits), + ZONE_PARSER(moveto), + ZONE_PARSER(type), + ZONE_PARSER(commands), + ZONE_PARSER(label), + ZONE_PARSER(flags), + ZONE_PARSER(endzone) + }; + + for (i = 0; i < ARRAYSIZE(op5); i++) + _locationZoneParsers.push_back(&op5[i]); + + static const OpcodeV1 op6[] = { + ANIM_PARSER(invalid), + ANIM_PARSER(script), + ANIM_PARSER(commands), + ANIM_PARSER(type), + ANIM_PARSER(label), + ANIM_PARSER(flags), + ANIM_PARSER(file), + ANIM_PARSER(position), + ANIM_PARSER(moveto), + ANIM_PARSER(endanimation) + }; + + for (i = 0; i < ARRAYSIZE(op6); i++) + _locationAnimParsers.push_back(&op6[i]); + + _currentOpcodes = 0; + _currentStatements = 0; + +} + +// +// a comment can appear both at location and Zone levels +// comments are displayed into rectangles on the screen +// +char *Parallaction_ns::parseComment(Script &script) { + + char _tmp_comment[1000] = "\0"; + char *v194; + + do { + char v190[400]; + v194 = script.readLine(v190, 400); + + v194[strlen(v194)-1] = '\0'; + if (!scumm_stricmp(v194, "endtext")) + break; + + strcat(_tmp_comment, v194); + strcat(_tmp_comment, " "); + } while (true); + + v194 = strdup(_tmp_comment); + _tmp_comment[0] = '\0'; + + return v194; +} + + +DECLARE_ZONE_PARSER(invalid) { + error("unknown statement '%s' in zone %s", _tokens[0], _locZoneParseCtxt.z->_label._text); +} + +DECLARE_ZONE_PARSER(endzone) { + popParserTables(); +} + +DECLARE_ZONE_PARSER(limits) { + _locZoneParseCtxt.z->_left = atoi(_tokens[1]); + _locZoneParseCtxt.z->_top = atoi(_tokens[2]); + _locZoneParseCtxt.z->_right = atoi(_tokens[3]); + _locZoneParseCtxt.z->_bottom = atoi(_tokens[4]); +} + + +DECLARE_ZONE_PARSER(moveto) { + _locZoneParseCtxt.z->_moveTo.x = atoi(_tokens[1]); + _locZoneParseCtxt.z->_moveTo.y = atoi(_tokens[2]); +} + + +DECLARE_ZONE_PARSER(type) { + if (_tokens[2][0] != '\0') { + _locZoneParseCtxt.z->_type = (4 + _objectsNames->lookup(_tokens[2])) << 16; + } + int16 _si = _zoneTypeNames->lookup(_tokens[1]); + if (_si != Table::notFound) { + _locZoneParseCtxt.z->_type |= 1 << (_si - 1); + parseZoneTypeBlock(*_locZoneParseCtxt.script, _locZoneParseCtxt.z); + } + + popParserTables(); +} + + +DECLARE_ZONE_PARSER(commands) { + parseCommands(*_locZoneParseCtxt.script, _locZoneParseCtxt.z->_commands); +} + + +DECLARE_ZONE_PARSER(label) { +// printf("label: %s", _tokens[1]); + renderLabel(&_locZoneParseCtxt.z->_label._cnv, _tokens[1]); +} + + +DECLARE_ZONE_PARSER(flags) { + uint16 _si = 1; + + do { + char _al = _zoneFlagNames->lookup(_tokens[_si]); + _si++; + _locZoneParseCtxt.z->_flags |= 1 << (_al - 1); + } while (!scumm_stricmp(_tokens[_si++], "|")); +} + +void Parallaction_ns::parseZone(Script &script, ZoneList &list, char *name) { + + if (findZone(name)) { + while (scumm_stricmp(_tokens[0], "endzone")) { + fillBuffers(script, true); + } + return; + } + + Zone *z = new Zone; + + z->_label._text = strdup(name); + + _locZoneParseCtxt.z = z; + _locZoneParseCtxt.end = false; + _locZoneParseCtxt.script = &script; + + list.push_front(z); + + pushParserTables(&_locationZoneParsers, _locationZoneStmt); + + return; +} + + +void Parallaction_ns::parseZoneTypeBlock(Script &script, Zone *z) { +// printf("parseZoneTypeBlock()"); + + TypeData *u = &z->u; + + switch (z->_type & 0xFFFF) { + case kZoneExamine: // examine Zone alloc + u->examine = new ExamineData; + break; + + case kZoneDoor: // door Zone alloc + u->door = new DoorData; + break; + + case kZoneGet: // get Zone alloc + u->get = new GetData; + break; + + case kZoneMerge: // merge Zone alloc + u->merge = new MergeData; + break; + + case kZoneHear: // hear Zone alloc + u->hear = new HearData; + break; + + case kZoneSpeak: // speak Zone alloc + u->speak = new SpeakData; + break; + + } + + char vC8[PATH_LEN]; + +// printf("type = %x", z->_type); + + do { + + switch (z->_type & 0xFFFF) { + case kZoneExamine: // examine Zone init + if (!scumm_stricmp(_tokens[0], "file")) { + u->examine->_filename = strdup(_tokens[1]); + } + if (!scumm_stricmp(_tokens[0], "desc")) { + u->examine->_description = parseComment(script); + } + break; + + case kZoneDoor: // door Zone init + if (!scumm_stricmp(_tokens[0], "slidetext")) { + strcpy(_slideText[0], _tokens[1]); +// printf("%s\t", _slideText[0]); + strcpy(_slideText[1], _tokens[2]); + } + + if (!scumm_stricmp(_tokens[0], "location")) { + u->door->_location = strdup(_tokens[1]); + } + + if (!scumm_stricmp(_tokens[0], "file")) { +// printf("file: '%s'", _tokens[0]); + + strcpy(vC8, _tokens[1]); + + u->door->_cnv = _disk->loadFrames(vC8); + uint16 _ax = (z->_flags & kFlagsClosed ? 0 : 1); + + u->door->_background = (byte*)malloc(u->door->_cnv->_width * u->door->_cnv->_height); + _gfx->backupDoorBackground(u->door, z->_left, z->_top); + + _gfx->flatBlitCnv(u->door->_cnv, _ax, z->_left, z->_top, Gfx::kBitBack); + } + + if (!scumm_stricmp(_tokens[0], "startpos")) { + u->door->_startPos.x = atoi(_tokens[1]); + u->door->_startPos.y = atoi(_tokens[2]); + u->door->_startFrame = atoi(_tokens[3]); + } + break; + + case kZoneGet: // get Zone init + if (!scumm_stricmp(_tokens[0], "file")) { + strcpy(vC8, _tokens[1]); + u->get->_cnv = _disk->loadStatic(vC8); + u->get->_backup = (byte*)malloc(u->get->_cnv->w*u->get->_cnv->h); + + if ((z->_flags & kFlagsRemove) == 0) { + _gfx->backupGetBackground(u->get, z->_left, z->_top); + _gfx->flatBlitCnv(u->get->_cnv, z->_left, z->_top, Gfx::kBitBack); + } + } + + if (!scumm_stricmp(_tokens[0], "icon")) { + u->get->_icon = 4 + _objectsNames->lookup(_tokens[1]); + } + break; + + case kZoneMerge: // merge Zone init + if (!scumm_stricmp(_tokens[0], "obj1")) { + u->merge->_obj1 = 4 + _objectsNames->lookup(_tokens[1]); + } + if (!scumm_stricmp(_tokens[0], "obj2")) { + u->merge->_obj2 = 4 + _objectsNames->lookup(_tokens[1]); + } + if (!scumm_stricmp(_tokens[0], "newobj")) { + u->merge->_obj3 = 4 + _objectsNames->lookup(_tokens[1]); + } + break; + + case kZoneHear: // hear Zone init + if (!scumm_stricmp(_tokens[0], "sound")) { + strcpy(u->hear->_name, _tokens[1]); + z->u.hear->_channel = atoi(_tokens[2]); + } + if (!scumm_stricmp(_tokens[0], "freq")) { + z->u.hear->_freq = atoi(_tokens[1]); + } + break; + + case kZoneSpeak: // speak Zone init + if (!scumm_stricmp(_tokens[0], "file")) { + strcpy(u->speak->_name, _tokens[1]); +// printf("speak file name: %s", u.speak._name); + } + if (!scumm_stricmp(_tokens[0], "Dialogue")) { + u->speak->_dialogue = parseDialogue(script); + } + break; + } + + fillBuffers(script, true); + } while (scumm_stricmp(_tokens[0], "endzone")); + + return; +} + + + +} // namespace Parallaction diff --git a/engines/parallaction/staticres.cpp b/engines/parallaction/staticres.cpp index d8dbd35816..bd583155db 100644 --- a/engines/parallaction/staticres.cpp +++ b/engines/parallaction/staticres.cpp @@ -434,9 +434,6 @@ const char *_instructionNamesRes_br[] = { "mul", "div", "if", - "ifeq", - "iflt", - "ifgt", "endif", "stop" }; @@ -446,7 +443,7 @@ const char *_commandsNamesRes_br[] = { "clear", "start", "speak", - "get" + "get", "location", "open", "close", @@ -482,7 +479,10 @@ const char *_commandsNamesRes_br[] = { "dummy", "return", "onsave", - "offsave" + "offsave", + "endcommands", + "ifchar", + "endif" }; const char *_callableNamesRes_br[] = { @@ -514,6 +514,52 @@ const char *_audioCommandsNamesRes_br[] = { "loop" }; +const char *_locationStmtRes_br[] = { + "character", + "endlocation", + "ifchar", + "endif", + "location", + "mask", + "path", + "disk", + "localflags", + "commands", + "escape", + "acommands", + "flags", + "comment", + "endcomment", + "zone", + "animation", + "zeta", + "music", + "sound" +}; + +const char *_locationZoneStmtRes_br[] = { + "endzone", + "limits", + "moveto", + "type", + "commands", + "label", + "flags" +}; + +const char *_locationAnimStmtRes_br[] = { + "endanimation", + "endzone", + "script", + "commands", + "type", + "label", + "flags", + "file", + "position", + "moveto" +}; + const char *_dinoName = "dino"; const char *_donnaName = "donna"; const char *_doughName = "dough"; @@ -636,6 +682,9 @@ void Parallaction_br::initResources() { _zoneTypeNames = new Table(ARRAYSIZE(_zoneTypeNamesRes_br), _zoneTypeNamesRes_br); _commandsNames = new Table(ARRAYSIZE(_commandsNamesRes_br), _commandsNamesRes_br); _audioCommandsNames = new Table(ARRAYSIZE(_audioCommandsNamesRes_br), _audioCommandsNamesRes_br); + _locationStmt = new Table(ARRAYSIZE(_locationStmtRes_br), _locationStmtRes_br); + _locationZoneStmt = new Table(ARRAYSIZE(_locationZoneStmtRes_br), _locationZoneStmtRes_br); + _locationAnimStmt = new Table(ARRAYSIZE(_locationAnimStmtRes_br), _locationAnimStmtRes_br); // TODO: make sure there are 120 max locations in Big Red Adventure _localFlagNames = new Table(120); diff --git a/engines/parallaction/zone.cpp b/engines/parallaction/zone.cpp deleted file mode 100644 index 64ef933167..0000000000 --- a/engines/parallaction/zone.cpp +++ /dev/null @@ -1,697 +0,0 @@ -/* 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$ - * - */ - - -#include "common/stdafx.h" - -#include "parallaction/parallaction.h" -#include "parallaction/sound.h" - -namespace Parallaction { - - - - -Zone *Parallaction::findZone(const char *name) { - - for (ZoneList::iterator it = _zones.begin(); it != _zones.end(); it++) { - if (!scumm_stricmp((*it)->_label._text, name)) return *it; - } - - return findAnimation(name); -} - -DECLARE_ZONE_PARSER(invalid) { - error("unknown statement '%s' in zone %s", _tokens[0], _locZoneParseCtxt.z->_label._text); -} - -DECLARE_ZONE_PARSER(endzone) { - popParserTables(); -} - -DECLARE_ZONE_PARSER(limits) { - _locZoneParseCtxt.z->_left = atoi(_tokens[1]); - _locZoneParseCtxt.z->_top = atoi(_tokens[2]); - _locZoneParseCtxt.z->_right = atoi(_tokens[3]); - _locZoneParseCtxt.z->_bottom = atoi(_tokens[4]); -} - - -DECLARE_ZONE_PARSER(moveto) { - _locZoneParseCtxt.z->_moveTo.x = atoi(_tokens[1]); - _locZoneParseCtxt.z->_moveTo.y = atoi(_tokens[2]); -} - - -DECLARE_ZONE_PARSER(type) { - if (_tokens[2][0] != '\0') { - _locZoneParseCtxt.z->_type = (4 + _objectsNames->lookup(_tokens[2])) << 16; - } - int16 _si = _zoneTypeNames->lookup(_tokens[1]); - if (_si != Table::notFound) { - _locZoneParseCtxt.z->_type |= 1 << (_si - 1); - parseZoneTypeBlock(*_locZoneParseCtxt.script, _locZoneParseCtxt.z); - } - - popParserTables(); -} - - -DECLARE_ZONE_PARSER(commands) { - parseCommands(*_locZoneParseCtxt.script, _locZoneParseCtxt.z->_commands); -} - - -DECLARE_ZONE_PARSER(label) { -// printf("label: %s", _tokens[1]); - renderLabel(&_locZoneParseCtxt.z->_label._cnv, _tokens[1]); -} - - -DECLARE_ZONE_PARSER(flags) { - uint16 _si = 1; - - do { - char _al = _zoneFlagNames->lookup(_tokens[_si]); - _si++; - _locZoneParseCtxt.z->_flags |= 1 << (_al - 1); - } while (!scumm_stricmp(_tokens[_si++], "|")); -} - -void Parallaction::parseZone(Script &script, ZoneList &list, char *name) { - printf("parseZone(%s)\n", name); - - if (findZone(name)) { - while (scumm_stricmp(_tokens[0], "endzone")) { - fillBuffers(script, true); - } - return; - } - - Zone *z = new Zone; - - z->_label._text = strdup(name); - - _locZoneParseCtxt.z = z; - _locZoneParseCtxt.end = false; - _locZoneParseCtxt.script = &script; - - list.push_front(z); - - pushParserTables(_locationZoneParsers, _locationZoneStmt); - - return; -} - -void Parallaction::freeZones() { - debugC(1, kDebugLocation, "freeZones: kEngineQuit = %i", _engineFlags & kEngineQuit); - - ZoneList::iterator it = _zones.begin(); - - while ( it != _zones.end() ) { - - Zone* z = *it; - - // WORKAROUND: this huge condition is needed because we made TypeData a collection of structs - // instead of an union. So, merge->_obj1 and get->_icon were just aliases in the original engine, - // but we need to check it separately here. The same workaround is applied in hitZone. - if (((z->_top == -1) || - ((z->_left == -2) && ( - (((z->_type & 0xFFFF) == kZoneMerge) && ((isItemInInventory(MAKE_INVENTORY_ID(z->u.merge->_obj1)) != 0) || (isItemInInventory(MAKE_INVENTORY_ID(z->u.merge->_obj2)) != 0))) || - (((z->_type & 0xFFFF) == kZoneGet) && ((isItemInInventory(MAKE_INVENTORY_ID(z->u.get->_icon)) != 0))) - ))) && - ((_engineFlags & kEngineQuit) == 0)) { - - debugC(1, kDebugLocation, "freeZones preserving zone '%s'", z->_label._text); - - it++; - - } else - - it = _zones.erase(it); - - } - - return; -} - - - - - - - - - -void Parallaction::parseZoneTypeBlock(Script &script, Zone *z) { -// printf("parseZoneTypeBlock()"); - - TypeData *u = &z->u; - - switch (z->_type & 0xFFFF) { - case kZoneExamine: // examine Zone alloc - u->examine = new ExamineData; - break; - - case kZoneDoor: // door Zone alloc - u->door = new DoorData; - break; - - case kZoneGet: // get Zone alloc - u->get = new GetData; - break; - - case kZoneMerge: // merge Zone alloc - u->merge = new MergeData; - break; - - case kZoneHear: // hear Zone alloc - u->hear = new HearData; - break; - - case kZoneSpeak: // speak Zone alloc - u->speak = new SpeakData; - break; - - } - - char vC8[PATH_LEN]; - -// printf("type = %x", z->_type); - - do { - - switch (z->_type & 0xFFFF) { - case kZoneExamine: // examine Zone init - if (!scumm_stricmp(_tokens[0], "file")) { - u->examine->_filename = strdup(_tokens[1]); - } - if (!scumm_stricmp(_tokens[0], "desc")) { - u->examine->_description = parseComment(script); - } - break; - - case kZoneDoor: // door Zone init - if (!scumm_stricmp(_tokens[0], "slidetext")) { - strcpy(_slideText[0], _tokens[1]); -// printf("%s\t", _slideText[0]); - strcpy(_slideText[1], _tokens[2]); - } - - if (!scumm_stricmp(_tokens[0], "location")) { - u->door->_location = strdup(_tokens[1]); - } - - if (!scumm_stricmp(_tokens[0], "file")) { -// printf("file: '%s'", _tokens[0]); - - strcpy(vC8, _tokens[1]); - - u->door->_cnv = _disk->loadFrames(vC8); - uint16 _ax = (z->_flags & kFlagsClosed ? 0 : 1); - - u->door->_background = (byte*)malloc(u->door->_cnv->_width * u->door->_cnv->_height); - _gfx->backupDoorBackground(u->door, z->_left, z->_top); - - _gfx->flatBlitCnv(u->door->_cnv, _ax, z->_left, z->_top, Gfx::kBitBack); - } - - if (!scumm_stricmp(_tokens[0], "startpos")) { - u->door->_startPos.x = atoi(_tokens[1]); - u->door->_startPos.y = atoi(_tokens[2]); - u->door->_startFrame = atoi(_tokens[3]); - } - break; - - case kZoneGet: // get Zone init - if (!scumm_stricmp(_tokens[0], "file")) { - strcpy(vC8, _tokens[1]); - u->get->_cnv = _disk->loadStatic(vC8); - u->get->_backup = (byte*)malloc(u->get->_cnv->w*u->get->_cnv->h); - - if ((z->_flags & kFlagsRemove) == 0) { - _gfx->backupGetBackground(u->get, z->_left, z->_top); - _gfx->flatBlitCnv(u->get->_cnv, z->_left, z->_top, Gfx::kBitBack); - } - } - - if (!scumm_stricmp(_tokens[0], "icon")) { - u->get->_icon = 4 + _objectsNames->lookup(_tokens[1]); - } - break; - - case kZoneMerge: // merge Zone init - if (!scumm_stricmp(_tokens[0], "obj1")) { - u->merge->_obj1 = 4 + _objectsNames->lookup(_tokens[1]); - } - if (!scumm_stricmp(_tokens[0], "obj2")) { - u->merge->_obj2 = 4 + _objectsNames->lookup(_tokens[1]); - } - if (!scumm_stricmp(_tokens[0], "newobj")) { - u->merge->_obj3 = 4 + _objectsNames->lookup(_tokens[1]); - } - break; - - case kZoneHear: // hear Zone init - if (!scumm_stricmp(_tokens[0], "sound")) { - strcpy(u->hear->_name, _tokens[1]); - z->u.hear->_channel = atoi(_tokens[2]); - } - if (!scumm_stricmp(_tokens[0], "freq")) { - z->u.hear->_freq = atoi(_tokens[1]); - } - break; - - case kZoneSpeak: // speak Zone init - if (!scumm_stricmp(_tokens[0], "file")) { - strcpy(u->speak->_name, _tokens[1]); -// printf("speak file name: %s", u.speak._name); - } - if (!scumm_stricmp(_tokens[0], "Dialogue")) { - u->speak->_dialogue = parseDialogue(script); - } - break; - } - - fillBuffers(script, true); - } while (scumm_stricmp(_tokens[0], "endzone")); - - return; -} - -// displays character head commenting an examined object -// -// works on the frontbuffer -// -void Parallaction::displayCharacterComment(ExamineData *data) { - if (data->_description == NULL) return; - - // NOTE: saving visible screen before displaying comment allows - // to restore the exact situation after the comment is deleted. - // This means animations are restored in the exact position as - // they were, thus avoiding clipping effect as signalled in - // BUG item #1762614. - _gfx->copyScreen(Gfx::kBitFront, Gfx::kBitBack); - - _gfx->setFont(_dialogueFont); - _gfx->flatBlitCnv(_char._talk, 0, 190, 80, Gfx::kBitFront); - - int16 v26, v28; - _gfx->getStringExtent(data->_description, 130, &v28, &v26); - Common::Rect r(v28, v26); - r.moveTo(140, 10); - _gfx->drawBalloon(r, 0); - _gfx->displayWrappedString(data->_description, 140, 10, 0, 130); - - waitUntilLeftClick(); - - _gfx->copyScreen(Gfx::kBitBack, Gfx::kBitFront); - _gfx->updateScreen(); - - return; -} - -// -// ZONE TYPE: EXAMINE -// - -// display detail view of an item (and eventually comments) -// -// works on the frontbuffer -// - -void Parallaction::displayItemComment(ExamineData *data) { - - if (data->_description == NULL) return; - - _gfx->setHalfbriteMode(true); - - char v68[PATH_LEN]; - strcpy(v68, data->_filename); - data->_cnv = _disk->loadStatic(v68); - _gfx->flatBlitCnv(data->_cnv, 140, (_screenHeight - data->_cnv->h)/2, Gfx::kBitFront); - delete data->_cnv; - - int16 v6A = 0, v6C = 0; - - _gfx->setFont(_dialogueFont); - _gfx->getStringExtent(data->_description, 130, &v6C, &v6A); - Common::Rect r(v6C, v6A); - r.moveTo(0, 90); - _gfx->drawBalloon(r, 0); - _gfx->flatBlitCnv(_char._head, 100, 152, Gfx::kBitFront); - _gfx->displayWrappedString(data->_description, 0, 90, 0, 130); - - jobEraseAnimations((void*)1, NULL); - _gfx->updateScreen(); - - waitUntilLeftClick(); - - _gfx->setHalfbriteMode(false); - _gfx->copyScreen(Gfx::kBitBack, Gfx::kBitFront); - _gfx->updateScreen(); - - return; -} - - - -uint16 Parallaction::runZone(Zone *z) { - debugC(3, kDebugLocation, "runZone (%s)", z->_label._text); - - uint16 subtype = z->_type & 0xFFFF; - - debugC(3, kDebugLocation, "type = %x, object = %x", subtype, (z->_type & 0xFFFF0000) >> 16); - switch(subtype) { - - case kZoneExamine: - if (z->u.examine->_filename) { - displayItemComment(z->u.examine); - } else { - displayCharacterComment(z->u.examine); - } - break; - - case kZoneGet: - if (z->_flags & kFlagsFixed) break; - if (pickupItem(z) != 0) { - return 1; - } - z->_flags |= kFlagsRemove; - break; - - case kZoneDoor: - if (z->_flags & kFlagsLocked) break; - z->_flags ^= kFlagsClosed; - if (z->u.door->_cnv == NULL) break; - addJob(&jobToggleDoor, z, kPriority18 ); - break; - - case kZoneHear: - _soundMan->playSfx(z->u.hear->_name, z->u.hear->_channel, (z->_flags & kFlagsLooping) == kFlagsLooping, 60); - break; - - case kZoneSpeak: - runDialogue(z->u.speak); - break; - - } - - debugC(3, kDebugLocation, "runZone completed"); - - return 0; -} - -// -// ZONE TYPE: DOOR -// -void jobToggleDoor(void *parm, Job *j) { - - static byte count = 0; - - Zone *z = (Zone*)parm; - - if (z->u.door->_cnv) { - Common::Rect r(z->_left, z->_top, z->_left+z->u.door->_cnv->_width, z->_top+z->u.door->_cnv->_height); - - uint16 _ax = (z->_flags & kFlagsClosed ? 1 : 0); - _vm->_gfx->restoreDoorBackground(r, z->u.door->_cnv->getFramePtr(_ax), z->u.door->_background); - - _ax = (z->_flags & kFlagsClosed ? 0 : 1); - _vm->_gfx->flatBlitCnv(z->u.door->_cnv, _ax, z->_left, z->_top, Gfx::kBitBack); - _vm->_gfx->flatBlitCnv(z->u.door->_cnv, _ax, z->_left, z->_top, Gfx::kBit2); - } - - count++; - if (count == 2) { - j->_finished = 1; - count = 0; - } - - return; -} - - - -// -// ZONE TYPE: GET -// - -int16 Parallaction::pickupItem(Zone *z) { - int r = addInventoryItem(z->u.get->_icon); - if (r == 0) - addJob(&jobRemovePickedItem, z, kPriority17 ); - - return r; -} - -void jobRemovePickedItem(void *parm, Job *j) { - - Zone *z = (Zone*)parm; - - static uint16 count = 0; - - if (z->u.get->_cnv) { - Common::Rect r(z->_left, z->_top, z->_left + z->u.get->_cnv->w, z->_top + z->u.get->_cnv->h); - - _vm->_gfx->restoreGetBackground(r, z->u.get->_backup); - } - - count++; - if (count == 2) { - count = 0; - j->_finished = 1; - } - - return; -} - -void jobDisplayDroppedItem(void *parm, Job *j) { -// printf("jobDisplayDroppedItem..."); - - Zone *z = (Zone*)parm; - - if (z->u.get->_cnv) { - if (j->_count == 0) { - _vm->_gfx->backupGetBackground(z->u.get, z->_left, z->_top); - } - - _vm->_gfx->flatBlitCnv(z->u.get->_cnv, z->_left, z->_top, Gfx::kBitBack); - _vm->_gfx->flatBlitCnv(z->u.get->_cnv, z->_left, z->_top, Gfx::kBit2); - } - - j->_count++; - if (j->_count == 2) { - j->_count = 0; - j->_finished = 1; - } - -// printf("done"); - - return; -} - - - - -Zone *Parallaction::hitZone(uint32 type, uint16 x, uint16 y) { -// printf("hitZone(%i, %i, %i)", type, x, y); - - uint16 _di = y; - uint16 _si = x; - - for (ZoneList::iterator it = _zones.begin(); it != _zones.end(); it++) { -// printf("Zone name: %s", z->_name); - - Zone *z = *it; - - if (z->_flags & kFlagsRemove) continue; - - Common::Rect r; - z->getRect(r); - r.right++; // adjust border because Common::Rect doesn't include bottom-right edge - r.bottom++; - - r.grow(-1); // allows some tolerance for mouse click - - if (!r.contains(_si, _di)) { - - // out of Zone, so look for special values - if ((z->_left == -2) || (z->_left == -3)) { - - // WORKAROUND: this huge condition is needed because we made TypeData a collection of structs - // instead of an union. So, merge->_obj1 and get->_icon were just aliases in the original engine, - // but we need to check it separately here. The same workaround is applied in freeZones. - if ((((z->_type & 0xFFFF) == kZoneMerge) && (((_si == z->u.merge->_obj1) && (_di == z->u.merge->_obj2)) || ((_si == z->u.merge->_obj2) && (_di == z->u.merge->_obj1)))) || - (((z->_type & 0xFFFF) == kZoneGet) && ((_si == z->u.get->_icon) || (_di == z->u.get->_icon)))) { - - // special Zone - if ((type == 0) && ((z->_type & 0xFFFF0000) == 0)) - return z; - if (z->_type == type) - return z; - if ((z->_type & 0xFFFF0000) == type) - return z; - - } - } - - if (z->_left != -1) - continue; - if (_si < _char._ani._left) - continue; - if (_si > (_char._ani._left + _char._ani.width())) - continue; - if (_di < _char._ani._top) - continue; - if (_di > (_char._ani._top + _char._ani.height())) - continue; - - } - - // normal Zone - if ((type == 0) && ((z->_type & 0xFFFF0000) == 0)) - return z; - if (z->_type == type) - return z; - if ((z->_type & 0xFFFF0000) == type) - return z; - - } - - - int16 _a, _b, _c, _d, _e, _f; - for (AnimationList::iterator it = _animations.begin(); it != _animations.end(); it++) { - - Animation *a = *it; - - _a = (a->_flags & kFlagsActive) ? 1 : 0; // _a: active Animation - _e = ((_si >= a->_left + a->width()) || (_si <= a->_left)) ? 0 : 1; // _e: horizontal range - _f = ((_di >= a->_top + a->height()) || (_di <= a->_top)) ? 0 : 1; // _f: vertical range - - _b = ((type != 0) || (a->_type == kZoneYou)) ? 0 : 1; // _b: (no type specified) AND (Animation is not the character) - _c = (a->_type & 0xFFFF0000) ? 0 : 1; // _c: Animation is not an object - _d = ((a->_type & 0xFFFF0000) != type) ? 0 : 1; // _d: Animation is an object of the same type - - if ((_a != 0 && _e != 0 && _f != 0) && ((_b != 0 && _c != 0) || (a->_type == type) || (_d != 0))) { - - return a; - - } - - } - - return NULL; -} - - -Zone::Zone() { - _left = _top = _right = _bottom = 0; - - _type = 0; - _flags = 0; -} - -Zone::~Zone() { -// printf("~Zone(%s)\n", _label._text); - - _label._cnv.free(); - - switch (_type & 0xFFFF) { - case kZoneExamine: - free(u.examine->_filename); - free(u.examine->_description); - delete u.examine; - break; - - case kZoneDoor: - free(u.door->_location); - free(u.door->_background); - if (u.door->_cnv) - delete u.door->_cnv; - delete u.door; - break; - - case kZoneSpeak: - delete u.speak->_dialogue; - delete u.speak; - break; - - case kZoneGet: - free(u.get->_backup); - if (u.get->_cnv) { - u.get->_cnv->free(); - delete u.get->_cnv; - } - delete u.get; - break; - - case kZoneHear: - delete u.hear; - break; - - case kZoneMerge: - delete u.merge; - break; - - default: - break; - } -} - -void Zone::getRect(Common::Rect& r) const { - r.left = _left; - r.right = _right; - r.top = _top; - r.bottom = _bottom; -} - -void Zone::translate(int16 x, int16 y) { - _left += x; - _right += x; - _top += y; - _bottom += y; -} - -uint16 Zone::width() const { - return _right - _left; -} - -uint16 Zone::height() const { - return _bottom - _top; -} - -Label::Label() { - _text = NULL; -} - -Label::~Label() { - _cnv.free(); - if (_text) - free(_text); -} - - -} // namespace Parallaction |