First step in restructuring engine code:
- code has been consolidated in fewer files - new table-driven parsers/execution - some functions has been pushed down the engine hierarchy - Parallaction_br now inherits from Parallaction_ns svn-id: r28711
This commit is contained in:
parent
2bfc4466df
commit
37cdd1c69a
21 changed files with 3380 additions and 3193 deletions
|
@ -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
|
|
@ -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
|
||||
|
||||
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
857
engines/parallaction/exec_ns.cpp
Normal file
857
engines/parallaction/exec_ns.cpp
Normal file
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
215
engines/parallaction/objects.cpp
Normal file
215
engines/parallaction/objects.cpp
Normal file
|
@ -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
|
|
@ -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;
|
||||
|
@ -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,21 +333,31 @@ 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));
|
||||
}
|
||||
|
||||
~Instruction() {
|
||||
if (_text)
|
||||
free(_text);
|
||||
if (_text2)
|
||||
free(_text2);
|
||||
}
|
||||
};
|
||||
|
||||
//typedef Common::List<Instruction*> InstructionList;
|
||||
typedef ManagedList<Instruction*> InstructionList;
|
||||
|
||||
struct Program {
|
||||
LocalVariable *_locals;
|
||||
uint16 _loopCounter;
|
|
@ -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])();
|
||||
}
|
||||
|
||||
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;
|
||||
Animation *Parallaction::findAnimation(const char *name) {
|
||||
|
||||
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
|
||||
};
|
||||
for (AnimationList::iterator it = _animations.begin(); it != _animations.end(); it++)
|
||||
if (!scumm_stricmp((*it)->_label._text, name)) return *it;
|
||||
|
||||
_commandParsers = op2;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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)
|
||||
};
|
||||
void Parallaction::freeAnimations() {
|
||||
_animations.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
_commandOpcodes = op3;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
};
|
||||
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++;
|
||||
}
|
||||
|
||||
_locationParsers = op4;
|
||||
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'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
void Parallaction::freeLocation() {
|
||||
debugC(7, kDebugLocation, "freeLocation");
|
||||
|
||||
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)
|
||||
};
|
||||
_soundMan->stopSfx(0);
|
||||
_soundMan->stopSfx(1);
|
||||
_soundMan->stopSfx(2);
|
||||
_soundMan->stopSfx(3);
|
||||
|
||||
_locationAnimParsers = op6;
|
||||
if (_localFlagNames)
|
||||
delete _localFlagNames;
|
||||
|
||||
_currentOpcodes = 0;
|
||||
_currentStatements = 0;
|
||||
// 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;
|
||||
|
||||
}
|
||||
|
||||
// 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
|
||||
|
|
|
@ -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 {
|
||||
|
||||
public:
|
||||
virtual void operator()() const = 0;
|
||||
virtual ~Opcode() { }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class OpcodeImpl : public Opcode {
|
||||
|
||||
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_ZONE_PARSER(sig) void Parallaction::locZoneParse_##sig()
|
||||
#define DECLARE_UNQUALIFIED_ZONE_PARSER(sig) void locZoneParse_##sig()
|
||||
#define ZONE_PARSER(sig) &Parallaction::locZoneParse_##sig
|
||||
|
||||
#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
|
||||
|
||||
#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
|
||||
|
||||
#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_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_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
|
||||
#define DECLARE_UNQUALIFIED_INSTRUCTION_PARSER(sig) void instParse_##sig()
|
||||
|
||||
#define DECLARE_UNQUALIFIED_COMMAND_OPCODE(op) void cmdOp_##op()
|
||||
#define DECLARE_UNQUALIFIED_INSTRUCTION_OPCODE(op) void instOp_##op()
|
||||
|
||||
|
||||
|
||||
|
||||
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<OpcodeSet*> _opcodes;
|
||||
Common::Stack<Table*> _statements;
|
||||
|
||||
const Opcode *_currentOpcodes;
|
||||
OpcodeSet *_currentOpcodes;
|
||||
Table *_currentStatements;
|
||||
|
||||
void pushParserTables(const Opcode* opcodes, Table* statements);
|
||||
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,10 +575,9 @@ public:
|
|||
void renderLabel(Graphics::Surface *cnv, char *text);
|
||||
void setMousePointer(int16 index);
|
||||
|
||||
public:
|
||||
private:
|
||||
Menu* _menu;
|
||||
|
||||
private:
|
||||
void initFonts();
|
||||
void freeFonts();
|
||||
|
||||
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -57,6 +57,9 @@ public:
|
|||
void seek(int32 offset, int whence = SEEK_SET);
|
||||
};
|
||||
|
||||
void skip(Script* script, const char* endToken);
|
||||
|
||||
|
||||
} // namespace Parallaction
|
||||
|
||||
#endif
|
||||
|
|
1355
engines/parallaction/parser_ns.cpp
Normal file
1355
engines/parallaction/parser_ns.cpp
Normal file
File diff suppressed because it is too large
Load diff
|
@ -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);
|
||||
|
|
|
@ -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
|
Loading…
Add table
Add a link
Reference in a new issue