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:
Nicola Mettifogo 2007-08-24 20:14:51 +00:00
parent 2bfc4466df
commit 37cdd1c69a
21 changed files with 3380 additions and 3193 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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) {

View 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

View file

@ -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);
}

View file

@ -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;
}

View file

@ -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

View file

@ -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

View 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

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -57,6 +57,9 @@ public:
void seek(int32 offset, int whence = SEEK_SET);
};
void skip(Script* script, const char* endToken);
} // namespace Parallaction
#endif

File diff suppressed because it is too large Load diff

View file

@ -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);

View file

@ -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