aboutsummaryrefslogtreecommitdiff
path: root/engines/parallaction
diff options
context:
space:
mode:
authorEugene Sandulenko2007-01-14 21:29:12 +0000
committerEugene Sandulenko2007-01-14 21:29:12 +0000
commite5c7ce83b8c7bb5f7d64c53fa8dcc378f667e902 (patch)
treeb9fa4e43e98a703bb60ef9a375c39d3579f610fd /engines/parallaction
parent549f818e3195136ee3fbd7cd7e474f5932deb529 (diff)
downloadscummvm-rg350-e5c7ce83b8c7bb5f7d64c53fa8dcc378f667e902.tar.gz
scummvm-rg350-e5c7ce83b8c7bb5f7d64c53fa8dcc378f667e902.tar.bz2
scummvm-rg350-e5c7ce83b8c7bb5f7d64c53fa8dcc378f667e902.zip
Initial import of Parallaction engine
svn-id: r25083
Diffstat (limited to 'engines/parallaction')
-rw-r--r--engines/parallaction/animation.cpp728
-rw-r--r--engines/parallaction/archive.cpp176
-rw-r--r--engines/parallaction/callables.cpp375
-rw-r--r--engines/parallaction/commands.cpp345
-rw-r--r--engines/parallaction/commands.h61
-rw-r--r--engines/parallaction/debug.cpp80
-rw-r--r--engines/parallaction/defs.h108
-rw-r--r--engines/parallaction/detection.cpp97
-rw-r--r--engines/parallaction/dialogue.cpp644
-rw-r--r--engines/parallaction/disk.h61
-rw-r--r--engines/parallaction/graphics.cpp1361
-rw-r--r--engines/parallaction/graphics.h185
-rw-r--r--engines/parallaction/intro.cpp334
-rw-r--r--engines/parallaction/inventory.cpp401
-rw-r--r--engines/parallaction/inventory.h56
-rw-r--r--engines/parallaction/loadsave.cpp531
-rw-r--r--engines/parallaction/location.cpp483
-rw-r--r--engines/parallaction/menu.cpp427
-rw-r--r--engines/parallaction/menu.h57
-rw-r--r--engines/parallaction/module.mk31
-rw-r--r--engines/parallaction/music.cpp125
-rw-r--r--engines/parallaction/music.h34
-rw-r--r--engines/parallaction/parallaction.cpp939
-rw-r--r--engines/parallaction/parallaction.h311
-rw-r--r--engines/parallaction/parser.cpp151
-rw-r--r--engines/parallaction/parser.h43
-rw-r--r--engines/parallaction/staticres.cpp244
-rw-r--r--engines/parallaction/table.cpp134
-rw-r--r--engines/parallaction/walk.cpp471
-rw-r--r--engines/parallaction/zone.cpp673
-rw-r--r--engines/parallaction/zone.h225
31 files changed, 9891 insertions, 0 deletions
diff --git a/engines/parallaction/animation.cpp b/engines/parallaction/animation.cpp
new file mode 100644
index 0000000000..33ca821b70
--- /dev/null
+++ b/engines/parallaction/animation.cpp
@@ -0,0 +1,728 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * 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 "parallaction/disk.h"
+#include "parallaction/parallaction.h"
+#include "parallaction/graphics.h"
+#include "parallaction/music.h"
+#include "parallaction/parser.h"
+#include "parallaction/zone.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 1000
+
+
+void wrapLocalVar(LocalVariable *local);
+void sortAnimations();
+
+LValue getLValue(Instruction *inst, char *str, LocalVariable *locals, Animation *a);
+
+int16 scriptFillBuffers(ArchivedFile *file);
+
+uint16 _numLocals = 0;
+char _localNames[10][10];
+
+Animation *findAnimation(const char *name) {
+
+ Animation *v4 = (Animation*)_animations._next;
+
+ while (v4) {
+ if (!scumm_stricmp(name, v4->_zone._name)) return v4;
+ v4 = (Animation*)v4->_zone._node._next;
+ }
+
+ return NULL;
+}
+
+
+Animation *Parallaction::parseAnimation(ArchivedFile *file, Node *list, char *name) {
+// printf("parseAnimation(%s)\n", name);
+
+ Animation *vD0 = (Animation*)memAlloc(sizeof(Animation));
+ memset(vD0, 0, sizeof(Animation));
+
+ vD0->_zone._name = (char*)memAlloc(strlen(name)+1);
+ strcpy(vD0->_zone._name, name);
+
+ addNode(list, &vD0->_zone._node);
+
+ parseFillBuffers();
+ while (scumm_stricmp(_tokens[0], "endanimation")) {
+// printf("token[0] = %s\n", _tokens[0]);
+
+ if (!scumm_stricmp(_tokens[0], "script")) {
+ loadProgram(vD0, _tokens[1]);
+ }
+ if (!scumm_stricmp(_tokens[0], "commands")) {
+ vD0->_zone._commands = parseCommands(file);
+ }
+ if (!scumm_stricmp(_tokens[0], "type")) {
+ if (_tokens[2][0] != '\0') {
+ vD0->_zone._type = ((4 + searchTable(_tokens[2], _objectsNames)) << 16) & 0xFFFF0000;
+ }
+ int16 _si = searchTable(_tokens[1], _zoneTypeNames);
+ if (_si != -1) {
+ vD0->_zone._type |= 1 << (_si-1);
+ if (((vD0->_zone._type & 0xFFFF) != kZoneNone) && ((vD0->_zone._type & 0xFFFF) != kZoneCommand)) {
+ parseZoneTypeBlock(file, &vD0->_zone);
+ }
+ }
+ }
+ if (!scumm_stricmp(_tokens[0], "label")) {
+ _vm->_graphics->makeCnvFromString(&vD0->_zone._label, _tokens[1]);
+ }
+ if (!scumm_stricmp(_tokens[0], "flags")) {
+ uint16 _si = 1;
+
+ do {
+ byte _al = searchTable(_tokens[_si], _zoneFlagNames);
+ _si++;
+ vD0->_zone._flags |= 1 << (_al - 1);
+ } while (!scumm_stricmp(_tokens[_si++], "|"));
+ }
+ if (!scumm_stricmp(_tokens[0], "file")) {
+ char vC8[200];
+ strcpy(vC8, _tokens[1]);
+ if (_engineFlags & kEngineMiniDonna) {
+ if (!scumm_stricmp(_tokens[1], "donnap") || !scumm_stricmp(_tokens[1], "donnapa")) {
+ strcat(vC8, "tras");
+ }
+ }
+
+ _vm->_graphics->loadCnv(vC8, &vD0->_cnv);
+// int16 _ax = _vm->_graphics->loadCnv(vC8, &vD0->_cnv);
+// if (_ax == -1) exit(-1);
+ }
+ if (!scumm_stricmp(_tokens[0], "position")) {
+ vD0->_zone.pos._position._x = atoi(_tokens[1]);
+ vD0->_zone.pos._position._y = atoi(_tokens[2]);
+ vD0->_z = atoi(_tokens[3]);
+ }
+ if (!scumm_stricmp(_tokens[0], "moveto")) {
+ vD0->_zone._moveTo._x = atoi(_tokens[1]);
+ vD0->_zone._moveTo._y = atoi(_tokens[2]);
+ }
+
+ parseFillBuffers();
+ }
+
+ vD0->_zone.pos._oldposition._x = -1000;
+ vD0->_zone.pos._oldposition._y = -1000;
+
+ vD0->_zone._flags |= 0x1000000;
+
+ return vD0;
+}
+
+
+
+void freeScript(Program *program) {
+
+ if (!program) return;
+
+ memFree(program->_locals);
+ freeNodeList(&program->_node);
+
+ return;
+}
+
+
+
+void freeAnimations() {
+ Animation *v4 = (Animation*)_animations._next;
+ while (v4) {
+ freeScript(v4->_program);
+ _vm->_graphics->freeCnv(&v4->_cnv);
+ v4 = (Animation*)v4->_zone._node._next;
+ }
+
+ return;
+}
+
+
+
+void jobDisplayAnimations(void *parm, Job *j) {
+// printf("jobDisplayAnimations()...\n");
+
+ Animation *v18 = (Animation*)_animations._next;
+ StaticCnv v14;
+
+ uint16 _si = 0;
+
+ for ( ; v18; v18 = (Animation*)v18->_zone._node._next) {
+
+ if ((v18->_zone._flags & kFlagsActive) && ((v18->_zone._flags & kFlagsRemove) == 0)) {
+ v14._width = v18->_cnv._width;
+ v14._height = v18->_cnv._height;
+ v14._data0 = v18->_cnv._array[v18->_frame];
+// v14._data1 = v18->_cnv.field_8[v18->_frame];
+
+ if (v18->_zone._flags & kFlagsNoMasked)
+ _si = 3;
+ else
+ _si = _vm->_graphics->queryMask(v18->_zone.pos._position._y + v18->_cnv._height);
+
+// printf("jobDisplayAnimations %s, x: %i, y: %i, w: %i, h: %i\n", v18->_zone._name, v18->_zone.pos._position._x, v18->_zone.pos._position._y, v14._width, v14._height);
+ _vm->_graphics->blitCnv(&v14, v18->_zone.pos._position._x, v18->_zone.pos._position._y, _si, Graphics::kBitBack, Graphics::kMask0);
+
+ }
+
+ if (((v18->_zone._flags & kFlagsActive) == 0) && (v18->_zone._flags & kFlagsRemove)) {
+ v18->_zone._flags &= ~kFlagsRemove;
+ v18->_zone.pos._oldposition._x = -1000;
+ }
+
+ if ((v18->_zone._flags & kFlagsActive) && (v18->_zone._flags & kFlagsRemove)) {
+ v18->_zone._flags &= ~kFlagsActive;
+ v18->_zone._flags |= kFlagsRemove;
+ }
+
+ }
+
+// printf("done\n");
+
+ return;
+}
+
+
+void jobEraseAnimations(void *arg_0, Job *j) {
+// printf("jobEraseAnimations()...\n");
+
+ Animation *a = (Animation*)_animations._next;
+
+ for (; a; a=(Animation*)a->_zone._node._next) {
+
+ if (((a->_zone._flags & kFlagsActive) == 0) && ((a->_zone._flags & kFlagsRemove) == 0)) continue;
+
+ // printf("jobEraseAnimations %s, x: %i, y: %i, w: %i, h: %i\n", a->_zone._name, a->_zone.pos._oldposition._x, a->_zone.pos._oldposition._y, a->_cnv._width, a->_cnv._height);
+ _vm->_graphics->restoreBackground(a->_zone.pos._oldposition._x, a->_zone.pos._oldposition._y, a->_cnv._width, a->_cnv._height);
+ if (arg_0) {
+ a->_zone.pos._oldposition._x = a->_zone.pos._position._x;
+ a->_zone.pos._oldposition._y = a->_zone.pos._position._y;
+ }
+
+ }
+
+// printf("done\n");
+
+ return;
+}
+
+
+void Parallaction::loadProgram(Animation *a, char *filename) {
+// printf("loadProgram(%s)\n", filename);
+
+
+ char vC8[PATH_LEN];
+
+ sprintf(vC8, "%s.script", filename);
+
+ ArchivedFile *file = openArchivedFile(vC8);
+ if (!file) errorFileNotFound(vC8);
+
+ _numLocals = 0;
+ scriptFillBuffers(file);
+
+ a->_program = (Program*)memAlloc(sizeof(Program));
+ memset(a->_program, 0, sizeof(Program));
+ a->_program->_locals = (LocalVariable*)memAlloc(sizeof(LocalVariable)*10);
+ Node *vD0 = &a->_program->_node;
+
+ Instruction *vCC = (Instruction*)memAlloc(sizeof(Instruction));
+ memset(vCC, 0, sizeof(Instruction));
+
+ while (scumm_stricmp(_tokens[0], "endscript")) {
+
+ parseScriptLine(vCC, a, a->_program->_locals);
+ addNode(vD0, &vCC->_node);
+ vD0 = &vCC->_node;
+
+ vCC = (Instruction*)memAlloc(sizeof(Instruction));
+ memset(vCC, 0, sizeof(Instruction));
+ scriptFillBuffers(file);
+ }
+
+ vCC->_index = INST_END;
+ addNode(vD0, &vCC->_node);
+
+ a->_program->_ip = (Instruction*)a->_program->_node._next;
+
+ closeArchivedFile(file);
+
+ return;
+}
+
+
+
+// FIXME
+// this function does the same Job as parseFillBuffers, except that
+// it gets input from an ArchivedFile instead of a memory buffer
+//
+int16 scriptFillBuffers(ArchivedFile *file) {
+// printf("scriptFillBuffers()\n");
+ char v2[] = "\"\0";
+
+ for (uint16 _si = 0; _si < 15; _si++)
+ _tokens[_si][0] = '\0';
+
+ int16 _si = 0;
+
+ char vCA[200];
+ char *vCE = NULL;
+ do {
+ vCE = readArchivedFileText(vCA, 200, file);
+ if (vCE == 0) return 0;
+
+ skip_whitespace(vCE);
+ } while (strlen(vCE) == 0 || vCE[0] == '#');
+
+ while (strlen(vCE) > 0 && _si < 20) {
+ vCE = parseNextToken(vCE, _tokens[_si], 40, " \t\n");
+ if (_tokens[_si][0] == '"' && _tokens[_si][strlen(_tokens[_si])-1] != '"') {
+
+ vCE = parseNextToken(vCE, _tokens[_si], 40, v2);
+ strcat(_tokens[_si], _tokens[_si+1]);
+ _tokens[_si][0] = ' ';
+ vCE++;
+
+ }
+
+ vCE = skip_whitespace(vCE);
+ _si++;
+ }
+
+ return _si;
+}
+
+
+
+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 = searchTable(_tokens[0], _instructionNames);
+ inst->_index = _si;
+
+// printf("token[0] = %s (%i)\n", _tokens[0], inst->_index);
+
+ switch (inst->_index) {
+ case INST_ON: // on
+ case INST_OFF: // off
+ case INST_START: // start
+ if (!scumm_stricmp(_tokens[1], a->_zone._name)) {
+ inst->_opBase._a = a;
+ } else {
+ inst->_opBase._a = findAnimation(_tokens[1]);
+ }
+ break;
+
+ case INST_LOOP: // loop
+ inst->_opBase._loopCounter = getLValue(inst, _tokens[1], locals, a);
+ break;
+
+ case INST_X: // x
+ inst->_opA._pvalue = &a->_zone.pos._position._x;
+ inst->_opB = getLValue(inst, _tokens[1], locals, a);
+ break;
+
+ case INST_Y: // y
+ inst->_opA._pvalue = &a->_zone.pos._position._y;
+ inst->_opB = getLValue(inst, _tokens[1], locals, a);
+ break;
+
+ case INST_Z: // z
+ inst->_opA._pvalue = &a->_z;
+ inst->_opB = getLValue(inst, _tokens[1], locals, a);
+ break;
+
+ case INST_F: // f
+ inst->_opA._pvalue = &a->_frame;
+ inst->_opB = getLValue(inst, _tokens[1], locals, a);
+ break;
+
+ case INST_INC: // inc
+ case INST_DEC: // dec
+ if (!scumm_stricmp(_tokens[1], "X")) {
+ inst->_opA._pvalue = &a->_zone.pos._position._x;
+ } else
+ if (!scumm_stricmp(_tokens[1], "Y")) {
+ inst->_opA._pvalue = &a->_zone.pos._position._y;
+ } else
+ if (!scumm_stricmp(_tokens[1], "Z")) {
+ inst->_opA._pvalue = &a->_z;
+ } else
+ if (!scumm_stricmp(_tokens[1], "F")) {
+ inst->_opA._pvalue = &a->_frame;
+ } else {
+ inst->_flags |= kInstUsesLocal;
+ inst->_opA = getLValue(inst, _tokens[1], locals, a);
+ }
+
+ inst->_opB = getLValue(inst, _tokens[2], locals, a);
+
+ if (!scumm_stricmp(_tokens[3], "mod")) {
+ inst->_flags |= kInstMod;
+ }
+ break;
+
+ case INST_SET: // set
+ inst->_opA = getLValue(inst, _tokens[1], locals, a);
+ inst->_flags |= kInstUsesLocal;
+ inst->_opB = getLValue(inst, _tokens[2], locals, a);
+ break;
+
+ case INST_MOVE: // move
+ inst->_opA = getLValue(inst, _tokens[1], locals, a);
+ inst->_opB = getLValue(inst, _tokens[2], locals, a);
+ break;
+
+ case INST_PUT: // put
+ if (!scumm_stricmp(_tokens[1], a->_zone._name)) {
+ inst->_opBase._a = a;
+ } else {
+ inst->_opBase._a = findAnimation(_tokens[1]);
+ }
+
+ inst->_opA = getLValue(inst, _tokens[2], locals, a);
+ inst->_opB = getLValue(inst, _tokens[3], locals, a);
+ if (!scumm_stricmp(_tokens[4], "masked")) {
+ inst->_flags |= kInstMaskedPut;
+ }
+ break;
+
+ case INST_CALL: { // call
+ int16 _ax = searchTable(_tokens[1], _callableNames);
+ inst->_opBase._index = _ax - 1;
+ if (_ax - 1 < 0) exit(0);
+ }
+ break;
+
+ case INST_SOUND: // sound
+ inst->_opBase._z = findZone(_tokens[1]);
+ break;
+
+ case INST_ENDLOOP: // endloop
+ case INST_SHOW: // show
+ case INST_WAIT: // wait
+ break;
+
+ default: // local definition
+ strcpy(_localNames[_numLocals], _tokens[0]);
+ locals[_numLocals]._value = atoi(_tokens[2]);
+
+ if (_tokens[3][0] != '\0') {
+ locals[_numLocals]._min = atoi(_tokens[3]);
+ locals[_numLocals]._max = atoi(_tokens[4]);
+ } else {
+ locals[_numLocals]._min = -10000;
+ locals[_numLocals]._max = 10000;
+ }
+
+ inst->_opA._local = &locals[_numLocals];
+ inst->_opB._value = locals[_numLocals]._value;
+
+ inst->_flags = kInstUsesLiteral | kInstUsesLocal;
+ inst->_index = INST_SET;
+ _numLocals++;
+ break;
+
+ }
+
+
+ return;
+}
+
+LValue getLValue(Instruction *inst, char *str, LocalVariable *locals, Animation *a) {
+
+ LValue v;
+
+ if (isdigit(str[0]) || str[0] == '-') {
+ inst->_flags |= kInstUsesLiteral;
+ v._value = atoi(str);
+ return v;
+ }
+
+ for (uint16 _si = 0; _si < 10; _si++) {
+ if (!scumm_stricmp(str, _localNames[_si])) {
+ v._local = &locals[_si];
+ return v;
+ }
+ }
+
+ if (str[1] == '.') {
+ a = findAnimation(&str[2]);
+ }
+
+ if (str[0] == 'X') {
+ v._pvalue = &a->_zone.pos._position._x;
+ } else
+ if (str[0] == 'Y') {
+ v._pvalue = &a->_zone.pos._position._y;
+ } else
+ if (str[0] == 'Z') {
+ v._pvalue = &a->_z;
+ } else
+ if (str[0] == 'F') {
+ v._pvalue = &a->_frame;
+ }
+
+ return v;
+}
+
+
+
+void jobRunScripts(void *parm, Job *j) {
+// printf("jobRunScripts()\n");
+
+ static uint16 modCounter = 0;
+
+ Animation *a = (Animation*)_animations._next;
+
+ StaticCnv v18;
+ WalkNode *v4 = NULL;
+
+ if (a->_zone._flags & kFlagsCharacter) a->_z = a->_zone.pos._position._y + a->_cnv._height;
+ for ( ; a; a = (Animation*)a->_zone._node._next) {
+
+ if ((a->_zone._flags & kFlagsActing) == 0) continue;
+ Instruction *inst = a->_program->_ip;
+
+// printf("Animation: %s, flags: %x\n", a->_zone._name, a->_zone._flags);
+
+ while ((inst->_index != INST_SHOW) && (a->_zone._flags & kFlagsActing)) {
+
+// printf("Animation: %s, instruction: %s\n", a->_zone._name, inst->_index == INST_END ? "end" : _instructionNames[inst->_index - 1]);
+
+ switch (inst->_index) {
+ case INST_ENDLOOP: // endloop
+ if (--a->_program->_loopCounter > 0) {
+ inst = a->_program->_loopStart;
+ }
+ break;
+
+ case INST_OFF: {// off
+ inst->_opBase._a->_zone._flags |= kFlagsRemove;
+// v1C = inst->_opBase;
+ }
+ break;
+
+ case INST_ON: // on
+ inst->_opBase._a->_zone._flags |= kFlagsActive;
+ inst->_opBase._a->_zone._flags &= ~kFlagsRemove;
+ break;
+
+ case INST_START: // start
+// v1C = inst->_opBase;
+ inst->_opBase._a->_zone._flags |= (kFlagsActing | kFlagsActive);
+ break;
+
+ case INST_LOOP: // loop
+ if (inst->_flags & kInstUsesLiteral) {
+ a->_program->_loopCounter = inst->_opBase._loopCounter._value;
+ } else {
+ a->_program->_loopCounter = *inst->_opBase._loopCounter._pvalue;
+ }
+ a->_program->_loopStart = inst;
+ break;
+
+ case INST_INC: // inc
+ case INST_DEC: { // dec
+ int16 _si = 0;
+ int16 _ax = 0, _bx = 0;
+ if (inst->_flags & kInstUsesLiteral) {
+ _si = inst->_opB._value;
+ } else {
+ _si = *inst->_opB._pvalue;
+ }
+ if (inst->_flags & kInstMod) { // mod
+ _bx = (_si > 0 ? _si : -_si);
+ if (modCounter % _bx != 0) break;
+
+ _si = (_si > 0 ? 1 : -1);
+ }
+ if (inst->_flags & kInstUsesLocal) { // local
+ if (inst->_index == INST_INC) _ax = _si;
+ else _ax = -_si;
+
+ inst->_opA._local->_value += _ax;
+ wrapLocalVar(inst->_opA._local);
+ break;
+ }
+
+ // built-in variable (x, y, z, f)
+ if (inst->_index == INST_INC) _ax = _si;
+ else _ax = -_si;
+ *inst->_opA._pvalue += _ax;
+ }
+ break;
+
+ case INST_MOVE: // move
+ v4 = buildWalkPath(*inst->_opA._pvalue, *inst->_opB._pvalue);
+ addJob(jobWalk, v4, JOBPRIORITY_WALK );
+ _engineFlags |= kEngineWalking;
+ break;
+
+ case INST_PUT: // put
+ v18._width = inst->_opBase._a->_cnv._width;
+ v18._height = inst->_opBase._a->_cnv._height;
+ v18._data0 = inst->_opBase._a->_cnv._array[inst->_opBase._a->_frame];
+// v18._data1 = inst->_opBase._a->_cnv.field_8[inst->_opBase._a->_frame];
+
+ if (inst->_flags & kInstMaskedPut) {
+ uint16 _si = _vm->_graphics->queryMask(inst->_opB._value);
+ _vm->_graphics->blitCnv(&v18, inst->_opA._value, inst->_opB._value, _si, Graphics::kBitBack, Graphics::kMask0 );
+ _vm->_graphics->blitCnv(&v18, inst->_opA._value, inst->_opB._value, _si, Graphics::kBit2, Graphics::kMask0 );
+ } else {
+ _vm->_graphics->flatBlitCnv(&v18, inst->_opA._value, inst->_opB._value, Graphics::kBitBack, v18._data1);
+ _vm->_graphics->flatBlitCnv(&v18, inst->_opA._value, inst->_opB._value, Graphics::kBit2, v18._data1);
+ }
+ break;
+
+ case INST_END: // exit
+ if ((a->_zone._flags & kFlagsLooping) == 0) {
+ a->_zone._flags &= ~kFlagsActing;
+ runCommands(a->_zone._commands, (Zone*)&a->_zone);
+ }
+ a->_program->_ip = (Instruction*)a->_program->_node._next;
+ goto label1;
+
+
+ case INST_CALL: // call
+ _callables[inst->_opBase._index](0);
+ break;
+
+ case INST_WAIT: // wait
+ if (_engineFlags & kEngineWalking) goto label1;
+ break;
+
+ case INST_SOUND: // sound
+ _activeZone = inst->_opBase._z;
+ break;
+
+ default: { // INST_SET, INST_X, INST_Y, INST_Z, INST_F
+ int16 _si;
+ if (inst->_flags & kInstUsesLiteral) {
+ _si = inst->_opB._value;
+ } else {
+ _si = *inst->_opB._pvalue;
+ }
+
+ if (inst->_flags & kInstUsesLocal) {
+ inst->_opA._local->_value = _si;
+ } else {
+ *inst->_opA._pvalue = _si;
+ }
+ }
+ break;
+
+ }
+
+ inst = (Instruction*)inst->_node._next;
+ }
+
+ a->_program->_ip = (Instruction*)inst->_node._next;
+
+label1:
+ if (a->_zone._flags & kFlagsCharacter) a->_z = a->_zone.pos._position._y + a->_cnv._height;
+ }
+
+ 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;
+}
+
+
+
+void sortAnimations() {
+ Node v14;
+ memset(&v14, 0, sizeof(Node));
+
+ _yourself._z = _yourself._cnv._height + _yourself._zone._limits._top;
+
+ Animation *vC = (Animation*)_animations._next;
+ Node *v8;
+ Animation *v4;
+
+ while (vC) {
+
+ v8 = &v14;
+
+ while ((v8->_next != NULL) && (vC->_z >= ((Animation*)(v8->_next))->_z)) {
+ v8 = v8->_next;
+ }
+
+ v4 = (Animation*)vC->_zone._node._next;
+
+ addNode(v8, &vC->_zone._node);
+
+ vC = v4;
+ }
+
+ memcpy(&_animations, &v14, sizeof(Node));
+
+ _animations._next->_prev = &_animations;
+
+ return;
+}
+
+
+} // namespace Parallaction
diff --git a/engines/parallaction/archive.cpp b/engines/parallaction/archive.cpp
new file mode 100644
index 0000000000..7f6e52da17
--- /dev/null
+++ b/engines/parallaction/archive.cpp
@@ -0,0 +1,176 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * 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/file.h"
+
+#include "parallaction/disk.h"
+
+
+namespace Parallaction {
+
+#define MAX_ARCHIVE_ENTRIES 384
+
+#define DIRECTORY_OFFSET_IN_FILE 0x4000
+
+static Common::File _archive;
+static char _archiveDir[MAX_ARCHIVE_ENTRIES][32];
+static uint32 _archiveLenghts[MAX_ARCHIVE_ENTRIES];
+static uint32 _archiveOffsets[MAX_ARCHIVE_ENTRIES];
+
+static uint32 _handle = MAX_ARCHIVE_ENTRIES;
+
+
+void openArchive(const char *file) {
+// printf("openArchive(%s)\n", file);
+
+ uint32 offset = DIRECTORY_OFFSET_IN_FILE;
+ char path[PATH_LEN];
+
+ strcpy(path, file);
+ if (!_archive.open(path))
+ errorFileNotFound(path);
+
+ _archive.skip(22);
+ _archive.read(_archiveDir, MAX_ARCHIVE_ENTRIES*32);
+
+ uint16 i;
+ for (i = 0; i < MAX_ARCHIVE_ENTRIES; i++) {
+ _archiveOffsets[i] = offset;
+
+ uint32 len = _archive.readUint32BE();
+// if (len>0) printf("%i) %s - [%i bytes]\n", i, _archiveDir[i], len);
+
+ _archiveLenghts[i] = len;
+ offset += len;
+ }
+
+// printf("%i entries found\n", i);
+// printf("%i bytes of data\n", offset);
+
+ return;
+}
+
+
+
+void closeArchive() {
+// printf("closeArchive()\n");
+
+ if (!_archive.isOpen()) return;
+
+ _archive.close();
+}
+
+
+ArchivedFile *openArchivedFile(const char *name) {
+// printf("openArchivedFile(%s)\n", name);
+
+ uint16 i = 0;
+ for ( ; i < MAX_ARCHIVE_ENTRIES; i++) {
+ if (!scumm_stricmp(_archiveDir[i], name)) break;
+ }
+ if (i == MAX_ARCHIVE_ENTRIES) return NULL;
+
+ printf("found file %s in slot %i\n", name, i);
+
+ ArchivedFile *file = (ArchivedFile*)memAlloc(sizeof(ArchivedFile));
+
+ if (!file)
+ printf("can't allocate archive file\n");
+
+ file->_index = i;
+ file->_offset = _archiveOffsets[i];
+ file->_cursor = _archiveOffsets[i];
+ file->_endOffset = _archiveOffsets[i] + _archiveLenghts[i];
+
+ _handle = file->_index;
+ _archive.seek(file->_offset);
+
+ return file;
+}
+
+
+
+void closeArchivedFile(ArchivedFile *file) {
+ if (file) memFree(file);
+ _handle = MAX_ARCHIVE_ENTRIES;
+ return;
+}
+
+
+
+
+uint16 getArchivedFileLength(const char *name) {
+// printf("getArchivedFileLength(%s)\n", name);
+
+ for (uint16 i = 0; i < MAX_ARCHIVE_ENTRIES; i++) {
+ if (!scumm_stricmp(_archiveDir[i], name))
+ return _archiveLenghts[i];
+ }
+
+ return 0;
+}
+
+
+
+int16 readArchivedFile(ArchivedFile *file, void *buffer, uint16 size) {
+// printf("readArchivedFile(%i, %i)\n", file->_cursor, file->_endOffset);
+
+ if (file->_cursor == file->_endOffset) return -1;
+
+ if (file->_endOffset - file->_cursor < size)
+ size = file->_endOffset - file->_cursor;
+
+ _archive.seek(file->_cursor);
+ int16 read = _archive.read(buffer, size);
+ file->_cursor += read;
+
+ return read;
+}
+
+#if 0
+int16 readArchivedFile(ArchivedFile *file, void *buffer, uint16 size) {
+ printf("readArchivedFile(%i, %i)\n", file->_cursor, file->_endOffset);
+
+ if (file->_cursor == file->_endOffset) return -1;
+
+ _archive.seek(file->_cursor);
+ int16 read = _archive.read(buffer, size);
+ file->_cursor += read;
+
+ return read;
+}
+#endif
+
+
+char *readArchivedFileText(char *buf, uint16 size, void*) {
+
+ char *t = _archive.readLine(buf, size);
+
+ if (_archive.eof() || t == NULL) return NULL;
+
+ return t;
+}
+
+
+
+
+} // namespace Parallaction
diff --git a/engines/parallaction/callables.cpp b/engines/parallaction/callables.cpp
new file mode 100644
index 0000000000..d3af0cdae1
--- /dev/null
+++ b/engines/parallaction/callables.cpp
@@ -0,0 +1,375 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * 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 "parallaction/disk.h"
+#include "parallaction/parallaction.h"
+#include "parallaction/graphics.h"
+#include "parallaction/inventory.h"
+#include "parallaction/menu.h"
+#include "parallaction/music.h"
+#include "parallaction/zone.h"
+
+#include "common/file.h"
+
+namespace Parallaction {
+
+
+
+
+static Zone *_moveSarcZones[5];
+static Zone *_moveSarcExaZones[5];
+
+void _c_null(void *parm) {
+
+ return;
+}
+
+void _c_play_boogie(void *parm) {
+
+ static uint16 flag = 1;
+
+ if (flag == 0) return;
+ flag = 0;
+
+ stopMusic();
+ loadMusic("boogie2");
+ playMusic();
+
+ return;
+}
+
+
+void _c_score(void *parm) {
+ _score += 5;
+ return;
+}
+
+void _c_fade(void *parm) {
+ byte palette[PALETTE_SIZE];
+ _vm->_graphics->getBlackPalette(palette);
+ _vm->_graphics->setPalette(palette);
+
+ _vm->_graphics->swapBuffers();
+
+ for (uint16 _di = 0; _di < 64; _di++) {
+ _vm->_graphics->fadePalette(palette);
+ _vm->_graphics->setPalette(palette);
+ }
+
+ _vm->waitTime( 1 );
+
+ return;
+}
+
+Zone *_moveSarcZone0 = NULL;
+int16 _introSarcData1 = 0;
+Zone *_moveSarcZone1 = NULL;
+
+void _c_moveSarc(void *parm) {
+
+ Animation *a;
+
+ if (_introSarcData2 != 0) {
+
+ _introSarcData2 = 0;
+ if (_moveSarcZones[0] == NULL) {
+
+ _moveSarcZones[0] = findZone("sarc1");
+ _moveSarcZones[1] = findZone("sarc2");
+ _moveSarcZones[2] = findZone("sarc3");
+ _moveSarcZones[3] = findZone("sarc4");
+ _moveSarcZones[4] = findZone("sarc5");
+
+ _moveSarcExaZones[0] = findZone("sarc1exa");
+ _moveSarcExaZones[1] = findZone("sarc2exa");
+ _moveSarcExaZones[2] = findZone("sarc3exa");
+ _moveSarcExaZones[3] = findZone("sarc4exa");
+ _moveSarcExaZones[4] = findZone("sarc5exa");
+
+ }
+
+ a = findAnimation("sposta");
+
+ _moveSarcZone1 = (Zone*)parm;
+
+ for (uint16 _si = 0; _si < 5; _si++) {
+ if (_moveSarcZones[_si] == _moveSarcZone1) {
+ _moveSarcZone0 = _moveSarcExaZones[_si];
+ }
+ }
+
+ _introSarcData1 = _introSarcData3 - _moveSarcZone1->_limits._left;
+ a->_z = _introSarcData3;
+ a->_frame = _moveSarcZone1->_limits._top - (_introSarcData1 / 20);
+ _introSarcData3 = _moveSarcZone1->_limits._left;
+
+ if (_introSarcData1 > 0) {
+ a->_zone.pos._position._x = _introSarcData1 / 2;
+ } else {
+ a->_zone.pos._position._x = -_introSarcData1 / 2;
+ }
+
+ if (_introSarcData1 > 0) {
+ a->_zone.pos._position._y = 2;
+ } else {
+ a->_zone.pos._position._y = -2;
+ }
+
+ return;
+
+ }
+
+ _introSarcData2 = 1;
+
+ _moveSarcZone1->_limits._right += _introSarcData1;
+ _moveSarcZone1->_limits._left += _introSarcData1;
+
+ _moveSarcZone1->_limits._top -= (_introSarcData1 / 20);
+ _moveSarcZone1->_limits._bottom -= (_introSarcData1 / 20);
+
+ _moveSarcZone0->_limits._right += _introSarcData1;
+ _moveSarcZone0->_limits._left += _introSarcData1;
+
+ _moveSarcZone0->_limits._top -= (_introSarcData1 / 20);
+ _moveSarcZone0->_limits._bottom -= (_introSarcData1 / 20);
+
+ if (_moveSarcZones[0]->_limits._left == 35 &&
+ _moveSarcZones[1]->_limits._left == 68 &&
+ _moveSarcZones[2]->_limits._left == 101 &&
+ _moveSarcZones[3]->_limits._left == 134 &&
+ _moveSarcZones[4]->_limits._left == 167) {
+
+ a = findAnimation("finito");
+
+ a->_zone._flags |= (kFlagsActive | kFlagsActing);
+ _localFlags[_vm->_currentLocationIndex] |= kFlagsFixed;
+ }
+
+ return;
+
+}
+
+
+static uint16 num_foglie = 0;
+
+void _c_contaFoglie(void *parm) {
+
+ num_foglie++;
+ if (num_foglie != 6) return;
+
+ _commandFlags |= 0x1000;
+
+ return;
+}
+
+void _c_zeroFoglie(void *parm) {
+ num_foglie = 0;
+ return;
+}
+
+void _c_trasformata(void *parm) {
+ _engineFlags ^= kEngineMiniDonna;
+ return;
+}
+
+void _c_offMouse(void *parm) {
+ _mouseHidden = 1;
+ _engineFlags |= kEngineMouse;
+ return;
+}
+
+void _c_onMouse(void *parm) {
+ _engineFlags &= ~kEngineMouse;
+ _mouseHidden = 0;
+ return;
+}
+
+
+
+void _c_setMask(void *parm) {
+
+ _vm->_graphics->intGrottaHackMask();
+
+ return;
+}
+
+void _c_endComment(void *parm) {
+
+}
+
+void _c_frankenstein(void *parm) {
+ byte pal0[PALETTE_SIZE], pal1[PALETTE_SIZE];
+
+ for (uint16 i = 0; i <= PALETTE_COLORS; i++) {
+ pal0[i] = _palette[i];
+ pal0[i*3+1] = 0;
+ pal0[i*3+2] = 0;
+ }
+
+ _vm->_graphics->getBlackPalette(pal1);
+
+ for (uint16 _di = 0; _di < 30; _di++) {
+ g_system->delayMillis(20);
+ _vm->_graphics->setPalette(pal0);
+ g_system->delayMillis(20);
+ _vm->_graphics->setPalette(pal1);
+ }
+
+ _vm->_graphics->setPalette(_palette);
+
+ return;
+}
+// part completion messages
+const char *endMsg0[] = {"COMPLIMENTI!", "BRAVO!", "CONGRATULATIONS!", "PRIMA!"};
+const char *endMsg1[] = {"HAI FINITO QUESTA PARTE", "TU AS COMPLETE' CETTE AVENTURE", "YOU HAVE COMPLETED THIS PART", "DU HAST EIN ABENTEUER ERFOLGREICH"};
+const char *endMsg2[] = {"ORA COMPLETA IL RESTO ", "AVEC SUCCES.", "NOW GO ON WITH THE REST OF", "ZU ENDE GEFUHRT"};
+const char *endMsg3[] = {"DELL' AVVENTURA", "CONTINUE AVEC LES AUTRES", "THIS ADVENTURE", "MACH' MIT DEN ANDEREN WEITER"};
+// game completion messages
+const char *endMsg4[] = {"COMPLIMENTI!", "BRAVO!", "CONGRATULATIONS!", "PRIMA!"};
+const char *endMsg5[] = {"HAI FINITO LE TRE PARTI", "TU AS COMPLETE' LES TROIS PARTIES", "YOU HAVE COMPLETED THE THREE PARTS", "DU HAST DREI ABENTEURE ERFOLGREICH"};
+const char *endMsg6[] = {"DELL' AVVENTURA", "DE L'AVENTURE", "OF THIS ADVENTURE", "ZU ENDE GEFUHRT"};
+const char *endMsg7[] = {"ED ORA IL GRAN FINALE ", "ET MAINTENANT LE GRAND FINAL", "NOW THE GREAT FINAL", "UND YETZT DER GROSSE SCHLUSS!"};
+
+
+void _c_finito(void *parm) {
+
+ const char **v8C = endMsg0;
+ const char **v7C = endMsg1;
+ const char **v6C = endMsg2;
+ const char **v5C = endMsg3;
+ const char **v4C = endMsg4;
+ const char **v3C = endMsg5;
+ const char **v2C = endMsg6;
+ const char **v1C = endMsg7;
+
+ Common::File stream;
+
+ stream.open(_vm->_characterName, Common::File::kFileWriteMode);
+ if (stream.isOpen()) stream.close();
+
+ Common::File streamDino, streamDough, streamDonna;
+
+ streamDino.open("dino");
+ streamDough.open("dough");
+ streamDonna.open("donna");
+
+ bool gameCompleted = streamDino.isOpen() && streamDough.isOpen() && streamDonna.isOpen();
+
+ streamDino.close();
+ streamDough.close();
+ streamDonna.close();
+
+ cleanInventory();
+ refreshInventory(_vm->_characterName);
+
+ _vm->_graphics->palUnk0(_palette);
+
+ if (gameCompleted) {
+ _vm->_graphics->loadExternalCnv("slidecnv", &Graphics::_font);
+ _vm->_graphics->_proportionalFont = false;
+ uint16 _ax = _vm->_graphics->getStringWidth(v4C[_language]);
+ _vm->_graphics->displayString((SCREEN_WIDTH - _ax)/2, 70, v4C[_language]);
+ _ax = _vm->_graphics->getStringWidth(v3C[_language]);
+ _vm->_graphics->displayString((SCREEN_WIDTH - _ax)/2, 100, v3C[_language]);
+ _ax = _vm->_graphics->getStringWidth(v2C[_language]);
+ _vm->_graphics->displayString((SCREEN_WIDTH - _ax)/2, 130, v2C[_language]);
+ _ax = _vm->_graphics->getStringWidth(v1C[_language]);
+ _vm->_graphics->displayString((SCREEN_WIDTH - _ax)/2, 160, v1C[_language]);
+
+ _vm->_graphics->copyScreen(Graphics::kBitFront, Graphics::kBitBack);
+ _vm->_graphics->copyScreen(Graphics::kBitFront, Graphics::kBit2);
+ waitUntilLeftClick();
+
+ strcpy(_location, "estgrotta.drki");
+
+ _engineFlags |= kEngineChangeLocation;
+ _vm->_graphics->freeCnv(&Graphics::_font);
+ } else {
+ _vm->_graphics->loadExternalCnv("slidecnv", &Graphics::_font);
+ _vm->_graphics->_proportionalFont = false;
+ uint16 _ax = _vm->_graphics->getStringWidth(v8C[_language]);
+ _vm->_graphics->displayString((SCREEN_WIDTH - _ax)/2, 70, v8C[_language]);
+ _ax = _vm->_graphics->getStringWidth(v7C[_language]);
+ _vm->_graphics->displayString((SCREEN_WIDTH - _ax)/2, 100, v7C[_language]);
+ _ax = _vm->_graphics->getStringWidth(v6C[_language]);
+ _vm->_graphics->displayString((SCREEN_WIDTH - _ax)/2, 130, v6C[_language]);
+ _ax = _vm->_graphics->getStringWidth(v5C[_language]);
+ _vm->_graphics->displayString((SCREEN_WIDTH - _ax)/2, 160, v5C[_language]);
+
+ _vm->_graphics->copyScreen(Graphics::kBitFront, Graphics::kBitBack);
+ _vm->_graphics->copyScreen(Graphics::kBitFront, Graphics::kBit2);
+ waitUntilLeftClick();
+
+ _vm->_graphics->freeCnv(&Graphics::_font);
+ _vm->_menu->selectCharacter();
+ }
+
+ removeNode(&_yourself._zone._node);
+ _vm->_locationNames[0][0] = '\0';
+ _vm->_numLocations = 0;
+ _commandFlags = 0;
+
+ _engineFlags |= kEngineQuit;
+
+ freeZones(_zones._next);
+ freeNodeList(_zones._next);
+ _zones._next = NULL;
+
+ freeZones(_animations._next);
+ freeNodeList(_animations._next);
+ _animations._next = NULL;
+
+ _engineFlags &= ~kEngineQuit;
+
+ addNode(&_animations, &_yourself._zone._node);
+ _score = 0;
+
+ return;
+}
+
+void _c_ridux(void *parm) {
+ _vm->changeCharacter("minidino");
+ return;
+}
+
+void _c_testResult(void *parm) {
+ _vm->_graphics->swapBuffers();
+ _vm->parseLocation("common");
+ closeArchive();
+
+ _vm->_graphics->loadExternalCnv("slidecnv", &Graphics::_font);
+ _vm->_graphics->_proportionalFont = false;
+
+ uint16 _ax = _vm->_graphics->getStringWidth(_slideText[0]);
+ _vm->_graphics->displayString((SCREEN_WIDTH - _ax)/2, 38, _slideText[0]);
+ _ax = _vm->_graphics->getStringWidth(_slideText[1]);
+ _vm->_graphics->displayString((SCREEN_WIDTH - _ax)/2, 58, _slideText[1]);
+
+ _vm->_graphics->copyScreen(Graphics::kBitFront, Graphics::kBitBack);
+ _vm->_graphics->copyScreen(Graphics::kBitFront, Graphics::kBit2);
+
+ _vm->_graphics->freeCnv(&Graphics::_font);
+
+ return;
+}
+
+} // namespace Parallaction
diff --git a/engines/parallaction/commands.cpp b/engines/parallaction/commands.cpp
new file mode 100644
index 0000000000..aa726edaad
--- /dev/null
+++ b/engines/parallaction/commands.cpp
@@ -0,0 +1,345 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * 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 "parallaction/parallaction.h"
+#include "parallaction/parser.h"
+#include "parallaction/commands.h"
+#include "parallaction/zone.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
+
+extern char *_callableNames[];
+
+
+Command *parseCommands(ArchivedFile *file) {
+// printf("parseCommands()\n");
+
+ Node root;
+ memset(&root, 0, sizeof(root));
+
+ parseFillBuffers();
+
+ while (scumm_stricmp(_tokens[0], "ENDCOMMANDS") && scumm_stricmp(_tokens[0], "ENDZONE")) {
+// printf("token[0] = %s\n", _tokens[0]);
+
+ Command *cmd = (Command*)memAlloc(sizeof(Command));
+ memset(cmd, 0, sizeof(Command));
+
+ cmd->_id = _vm->searchTable(_tokens[0], commands_names);
+ uint16 _si = 1;
+
+// printf("cmd id = %i\n", cmd->_id);
+
+ switch (cmd->_id) {
+ case CMD_SET: // set
+ case CMD_CLEAR: // clear
+ case CMD_TOGGLE: // toggle
+ if (_vm->searchTable(_tokens[1], _globalTable) == -1) {
+ do {
+ char _al = _vm->searchTable(_tokens[_si], _localFlagNames);
+ _si++;
+ cmd->u._flags |= 1 << (_al - 1);
+ } while (!scumm_stricmp(_tokens[_si++], "|"));
+ _si--;
+ } else {
+ cmd->u._flags |= kFlagsGlobal;
+ do {
+ char _al = _vm->searchTable(_tokens[1], _globalTable);
+ _si++;
+ cmd->u._flags |= 1 << (_al - 1);
+ } while (!scumm_stricmp(_tokens[_si++], "|"));
+ _si--;
+ }
+ break;
+
+ case CMD_START: // start
+ case CMD_STOP: // stop
+ cmd->u._animation = findAnimation(_tokens[_si]);
+ _si++;
+ if (cmd->u._animation == NULL) {
+ strcpy(_forwardedAnimationNames[_numForwards], _tokens[_si-1]);
+ _forwardedCommands[_numForwards] = cmd;
+ _numForwards++;
+ }
+ break;
+
+ case CMD_SPEAK: // speak
+ case CMD_GET: // get
+ case CMD_OPEN: // open
+ case CMD_CLOSE: // close
+ case CMD_ON: // on
+ case CMD_OFF: // off
+ cmd->u._zone = findZone(_tokens[_si]);
+ _si++;
+ break;
+
+ case CMD_LOCATION: // location
+ cmd->u._string = (char*)memAlloc(strlen(_tokens[_si])+1);
+ strcpy(cmd->u._string, _tokens[_si]);
+ _si++;
+ break;
+
+ case CMD_CALL: // call
+ cmd->u._callable = _vm->searchTable(_tokens[_si], _callableNames) - 1;
+ _si++;
+ break;
+
+ case CMD_DROP: // drop
+ cmd->u._object = _vm->searchTable(_tokens[_si], _objectsNames);
+ _si++;
+ break;
+
+ case CMD_QUIT: // quit
+ break;
+
+ case CMD_MOVE: // move
+ cmd->u._move._x = atoi(_tokens[_si]);
+ _si++;
+ cmd->u._move._y = atoi(_tokens[_si]);
+ _si++;
+ break;
+
+ }
+
+ 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 = _vm->searchTable(&_tokens[_si][2], _localFlagNames);
+ cmd->_flagsOff |= 1 << (_al - 1);
+ } else {
+ byte _al = _vm->searchTable(_tokens[_si], _localFlagNames);
+ 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 = _vm->searchTable(&_tokens[_si][2], _globalTable);
+ cmd->_flagsOff |= 1 << (_al - 1);
+ } else {
+ byte _al = _vm->searchTable(_tokens[_si], _localFlagNames);
+ cmd->_flagsOn |= 1 << (_al - 1);
+ }
+
+ _si++;
+
+ } while (!scumm_stricmp(_tokens[_si++], "|"));
+
+ }
+
+ addNode(&root, &cmd->_node);
+ parseFillBuffers();
+
+ }
+
+ return (Command*)root._next;
+}
+
+
+void freeCommands(Command *list) {
+
+ Command *cmd = list;
+
+ while (cmd) {
+ Command *v4 = (Command*)cmd->_node._next;
+
+ if (cmd->_id == 6) memFree(cmd->u._zone); // open
+ memFree(cmd);
+
+ cmd = v4;
+ }
+
+ return;
+}
+
+
+
+void runCommands(Command *list, Zone *z) {
+// printf("runCommands()\n");
+
+ Command *cmd = list;
+ for ( ; cmd; cmd = (Command*)cmd->_node._next) {
+ CommandData *u = &cmd->u;
+ uint32 v8 = _localFlags[_vm->_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;
+
+// printf("localflags: %x\n", v8);
+// printf("%s (on flags: %x, off flags: %x)\n", commands_names[cmd->_id-1], cmd->_flagsOn, cmd->_flagsOff);
+
+ switch (cmd->_id) {
+
+ case CMD_SET: // set
+ if (cmd->u._flags & kFlagsGlobal) {
+ cmd->u._flags &= ~kFlagsGlobal;
+ _commandFlags |= cmd->u._flags;
+ } else {
+ _localFlags[_vm->_currentLocationIndex] |= cmd->u._flags;
+ }
+ break;
+
+ case CMD_CLEAR: // clear
+ if (cmd->u._flags & kFlagsGlobal) {
+ cmd->u._flags &= ~kFlagsGlobal;
+ _commandFlags &= ~cmd->u._flags;
+ } else {
+ _localFlags[_vm->_currentLocationIndex] &= ~cmd->u._flags;
+ }
+ break;
+
+ case CMD_TOGGLE: // toggle
+ if (cmd->u._flags & kFlagsGlobal) {
+ cmd->u._flags &= ~kFlagsGlobal;
+ _commandFlags ^= cmd->u._flags;
+ } else {
+ _localFlags[_vm->_currentLocationIndex] ^= cmd->u._flags;
+ }
+ break;
+
+ case CMD_START: // start
+ cmd->u._zone->_flags |= kFlagsActing;
+ break;
+
+ case CMD_STOP: // stop
+ cmd->u._zone->_flags &= ~kFlagsActing;
+ break;
+
+ case CMD_SPEAK: // speak
+ _activeZone = u->_zone;
+ break;
+
+ case CMD_GET: // get
+ u->_zone->_flags &= ~kFlagsFixed;
+ if (!runZone(u->_zone)) {
+ runCommands(u->_zone->_commands);
+ }
+ break;
+
+ case CMD_DROP: // drop
+ dropItem( u->_object );
+ break;
+
+ case CMD_OPEN: // open
+ u->_zone->_flags &= ~kFlagsClosed;
+ if (u->_zone->u.door->_cnv._count != 0) {
+ addJob(&jobToggleDoor, (void*)u->_zone, JOBPRIORITY_TOGGLEDOOR );
+ }
+ break;
+
+ case CMD_CLOSE: // close
+ u->_zone->_flags |= kFlagsClosed;
+ break;
+
+ case CMD_ON: // on
+ u->_zone->_flags &= ~kFlagsRemove;
+ u->_zone->_flags |= kFlagsActive;
+ if ((u->_zone->_type & 0xFFFF) == kZoneGet) {
+ addJob(&jobDisplayDroppedItem, u->_zone, JOBPRIORITY_ADDREMOVEITEMS );
+ }
+ break;
+
+ case CMD_OFF: // off
+ u->_zone->_flags |= kFlagsRemove;
+ break;
+
+ case CMD_LOCATION: // location
+ strcpy(_location, u->_string);
+ _engineFlags |= kEngineChangeLocation;
+ break;
+
+ case CMD_CALL: // call
+ _callables[u->_callable](z);
+ break;
+
+ case CMD_QUIT: // quit
+ _engineFlags |= kEngineQuit;
+ break;
+
+ case CMD_MOVE: { // move
+ if ((_yourself._zone._flags & kFlagsRemove) || (_yourself._zone._flags & kFlagsActive) == 0) {
+ continue;
+ }
+
+ WalkNode *vC = buildWalkPath(u->_move._x, u->_move._y);
+
+ addJob(&jobWalk, vC, JOBPRIORITY_WALK );
+ _engineFlags |= kEngineWalking;
+ }
+ break;
+
+ }
+ }
+
+ return;
+
+}
+
+} // namespace Parallaction
+
diff --git a/engines/parallaction/commands.h b/engines/parallaction/commands.h
new file mode 100644
index 0000000000..7a95aee1cd
--- /dev/null
+++ b/engines/parallaction/commands.h
@@ -0,0 +1,61 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * 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 "parallaction/defs.h"
+
+namespace Parallaction {
+
+enum CommandFlags {
+ kFlagsExit = 0x10000000,
+ kFlagsEnter = 0x20000000,
+ kFlagsGlobal = 0x40000000
+};
+
+union CommandData {
+ uint32 _flags;
+ Animation * _animation;
+ Zone* _zone;
+ char* _string;
+ uint16 _callable;
+ uint16 _object;
+ struct {
+ int16 _x;
+ int16 _y;
+ } _move;
+};
+
+struct Command {
+ Node _node;
+
+ uint16 _id;
+ CommandData u;
+ uint32 _flagsOn;
+ uint32 _flagsOff;
+
+};
+
+} // namespace Parallaction
+
+#endif
diff --git a/engines/parallaction/debug.cpp b/engines/parallaction/debug.cpp
new file mode 100644
index 0000000000..02837b3bf9
--- /dev/null
+++ b/engines/parallaction/debug.cpp
@@ -0,0 +1,80 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * 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/graphics.h"
+
+namespace Parallaction {
+
+
+const char *_jobDescriptions[] = {
+ "0 - draw label",
+ "1 - draw mouse",
+ "2 - delay remove Job (erase label) || show inventory",
+ "3 - draw animations",
+ "4 - NONE",
+ "5 - NONE",
+ "6 - NONE",
+ "7 - NONE",
+ "8 - NONE",
+ "9 - NONE",
+ "10 - NONE",
+ "11 - NONE",
+ "12 - NONE",
+ "13 - NONE",
+ "14 - NONE",
+ "15 - delay remove Job (erase label) || run scripts || erase animations",
+ "16 - NONE",
+ "17 - job_12d4 (put item on screen) || jobRemovePickedItem (remove item from screen)",
+ "18 - toggle door",
+ "19 - walk",
+ "20 - erase label || hide inventory",
+ "21 - erase mouse"
+};
+
+void *memAlloc(uint32 size) {
+ return malloc(size);
+}
+
+void memFree(void *m) {
+ free(m);
+ return;
+}
+
+
+void beep() {
+// sound(1500);
+// delay(100);
+// nosound();
+ return;
+}
+
+void errorFileNotFound(const char *s) {
+ error("File '%s' not found", s);
+}
+
+
+
+} // namespace Parallaction
diff --git a/engines/parallaction/defs.h b/engines/parallaction/defs.h
new file mode 100644
index 0000000000..4ae99bcf29
--- /dev/null
+++ b/engines/parallaction/defs.h
@@ -0,0 +1,108 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * 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_DEFS_H
+#define PARALLACTION_DEFS_H
+
+#include "common/stdafx.h"
+#include "common/system.h"
+
+namespace Parallaction {
+
+#define PATH_LEN 200
+
+
+
+
+struct Node {
+ Node* _prev;
+ Node* _next;
+};
+
+struct WalkNode {
+ Node _node;
+ int32 _x;
+ int32 _y;
+};
+
+struct Point {
+ int16 _x;
+ int16 _y;
+};
+
+struct Rect {
+ int16 _left;
+ int16 _top;
+ int16 _right;
+ int16 _bottom;
+};
+
+struct SpeakData;
+struct Question;
+typedef Question Dialogue;
+struct Instruction;
+struct LocalVariable;
+
+struct StaticCnv {
+ uint16 _width; //
+ uint16 _height; //
+ byte* _data0; // bitmap
+ byte* _data1; // unused
+ byte* _data2; // backup of underlying background
+};
+
+
+struct Cnv {
+ uint16 _width; //
+ uint16 _height; //
+ byte** _array; // frames data
+ byte** field_8; // unused
+ uint16 _count; // # of frames
+};
+
+
+struct ArchivedFile;
+struct Animation;
+struct Zone;
+
+struct Command;
+
+typedef void (*callable)(void*);
+
+struct Credit {
+ const char *_role;
+ const char *_name;
+};
+
+void *memAlloc(uint32 size);
+void memFree(void *m);
+void errorFileNotFound(const char*);
+
+void beep();
+char *skip_whitespace(char *s);
+
+} // namespace Parallaction
+
+
+#endif
+
+
diff --git a/engines/parallaction/detection.cpp b/engines/parallaction/detection.cpp
new file mode 100644
index 0000000000..45273f0c50
--- /dev/null
+++ b/engines/parallaction/detection.cpp
@@ -0,0 +1,97 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * 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 "base/plugins.h"
+
+#include "common/advancedDetector.h"
+#include "common/file.h"
+
+#include "parallaction/parallaction.h"
+
+namespace Parallaction {
+static DetectedGameList GAME_detectGames(const FSList &fslist);
+}
+
+static const PlainGameDescriptor parallactionGames[] = {
+ {"nippon", "Nippon Safes Inc."},
+ {0, 0}
+};
+
+ADVANCED_DETECTOR_DEFINE_PLUGIN(PARALLACTION, Parallaction::Parallaction, Parallaction::GAME_detectGames, parallactionGames, 0);
+
+REGISTER_PLUGIN(PARALLACTION, "Parallaction engine", "Nippon Safes Inc. (C) Dynabyte");
+
+
+namespace Parallaction {
+
+#define FILE_MD5_BYTES 5000
+
+static const PARALLACTIONGameDescription gameDescriptions[] = {
+ {
+ {
+ "nippon",
+ "",
+ {
+ { "disk1", 0, "610363308258e926dbabd5a9e7bb769f"},
+ { "disk2", 0, "bfdd7bcfbc226f4acf3f67fa9efa2826"},
+ { "disk3", 0, "eec08180240888d76e3cfe3e183d5d5d"},
+ { "disk4", 0, "5bffddc7db226bdaa7dd3e10e5a15e68"},
+ { "en", 0, "65cbfa81eafe308621184796ed116700"},
+ { "fr", 0, "ac20c743ea10f2cb4491f76c5644582c"},
+ { "ge", 0, "50916bfa34aee1380e0e959b37eceb5a"},
+ { "it", 0, "89964aef04d2c53a615ee8983caf2775"},
+ { NULL, 0, NULL}
+ },
+ Common::EN_ANY,
+ Common::kPlatformPC,
+ },
+ GType_Nippon,
+ 0,
+ },
+ { { NULL, NULL, {NULL, 0, NULL}, Common::UNK_LANG, Common::kPlatformUnknown }, 0, 0 }
+};
+
+
+bool Parallaction::detectGame() {
+ int i = Common::ADVANCED_DETECTOR_DETECT_INIT_GAME(
+ (const byte *)gameDescriptions,
+ sizeof(PARALLACTIONGameDescription),
+ FILE_MD5_BYTES,
+ parallactionGames
+ );
+ _gameDescription = &gameDescriptions[i];
+ return true;
+}
+
+DetectedGameList GAME_detectGames(const FSList &fslist) {
+ return Common::ADVANCED_DETECTOR_DETECT_GAMES_FUNCTION(
+ fslist,
+ (const byte *)gameDescriptions,
+ sizeof(PARALLACTIONGameDescription),
+ FILE_MD5_BYTES,
+ parallactionGames
+ );
+}
+
+} // End of namespace Parallaction
diff --git a/engines/parallaction/dialogue.cpp b/engines/parallaction/dialogue.cpp
new file mode 100644
index 0000000000..eacc3af67b
--- /dev/null
+++ b/engines/parallaction/dialogue.cpp
@@ -0,0 +1,644 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * 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 "parallaction/commands.h"
+#include "parallaction/parallaction.h"
+#include "parallaction/graphics.h"
+#include "parallaction/disk.h"
+#include "parallaction/inventory.h"
+#include "parallaction/parser.h"
+#include "parallaction/zone.h"
+
+namespace Parallaction {
+
+#define SKIPPED_ANSWER 1000
+
+#define MAX_BALLOON_WIDTH 130
+
+#define MAX_PASSWORD_LENGTH 7
+
+#define QUESTION_BALLOON_X 140
+#define QUESTION_BALLOON_Y 10
+#define QUESTION_CHARACTER_X 190
+#define QUESTION_CHARACTER_Y 80
+
+#define ANSWER_CHARACTER_X 10
+#define ANSWER_CHARACTER_Y 80
+
+
+void enterDialogue();
+void exitDialogue();
+
+int16 selectAnswer(Question *q, StaticCnv*);
+int16 getHoverAnswer(int16 x, int16 y, Question *q);
+
+int16 _answerBalloonX[10] = { 80, 120, 150, 150, 150, 0, 0, 0, 0, 0 };
+int16 _answerBalloonY[10] = { 10, 70, 130, 0, 0, 0, 0, 0, 0, 0 };
+int16 _answerBalloonW[10] = { 0 };
+int16 _answerBalloonH[10] = { 0 };
+
+
+char *parseDialogueString();
+
+Dialogue *parseDialogue(ArchivedFile *file) {
+// printf("parseDialogue()\n");
+ uint16 num_questions = 0;
+ uint16 v50[20];
+ char *_questions_names[20];
+ Question *_questions[20];
+
+ for (uint16 _si = 0; _si < 20; _si++) {
+ v50[_si] = 0;
+ }
+
+ parseFillBuffers();
+
+ while (scumm_stricmp(_tokens[0], "enddialogue")) {
+ if (scumm_stricmp(_tokens[0], "Question")) continue;
+
+ _questions[num_questions] = (Dialogue*)memAlloc(sizeof(Dialogue));
+ Dialogue *vB4 = _questions[num_questions];
+ memset(_questions[num_questions], 0, sizeof(Dialogue));
+
+ _questions_names[num_questions] = (char*)memAlloc(strlen(_tokens[1])+1);
+ strcpy(_questions_names[num_questions], _tokens[1]);
+
+ vB4->_text = parseDialogueString();
+// printf("Question: '%s'\n", vB4->_text);
+
+ parseFillBuffers();
+ vB4->_mood = atoi(_tokens[0]);
+
+ uint16 _di = 0;
+
+ parseFillBuffers();
+ while (scumm_stricmp(_tokens[0], "endquestion")) { // parse answers
+
+ char** v60 = _localFlagNames;
+ uint16 v56 = 1;
+
+ if (_tokens[1][0]) {
+
+ if (!scumm_stricmp(_tokens[1], "global")) {
+ v56 = 2;
+ v60 = _globalTable;
+ vB4->_yesFlags[_di] |= kFlagsGlobal;
+ }
+
+ do {
+
+ if (!scumm_strnicmp(_tokens[v56], "no", 2)) {
+ byte _al = _vm->searchTable(_tokens[v56]+2, v60);
+ vB4->_noFlags[_di] |= 1 << (_al - 1);
+ } else {
+ byte _al = _vm->searchTable(_tokens[v56]+2, v60);
+ vB4->_yesFlags[_di] |= 1 << (_al - 1);
+ }
+
+ v56++;
+
+ } while (!scumm_stricmp(_tokens[v56], "|"));
+
+ }
+
+ vB4->_answers[_di] = parseDialogueString();
+
+// printf("answer[%i]: '%s'\n", _di, vB4->_answers[_di]);
+
+ parseFillBuffers();
+ vB4->_answer_moods[_di] = atoi(_tokens[0]);
+ vB4->_following._names[_di] = parseDialogueString();
+
+ parseFillBuffers();
+ if (!scumm_stricmp(_tokens[0], "commands")) {
+ vB4->_commands[_di] = parseCommands(file);
+ parseFillBuffers();
+ }
+
+ _di++;
+ }
+
+ parseFillBuffers();
+ num_questions++;
+
+ }
+
+ _questions_names[num_questions] = NULL;
+
+ for (uint16 _si = 0; _si <num_questions; _si++) {
+
+ for (uint16 v5A = 0; v5A < 5; v5A++) {
+ if (_questions[_si]->_answers[v5A] == 0) continue;
+
+ int16 v58 = _vm->searchTable(_questions[_si]->_following._names[v5A], _questions_names);
+ memFree(_questions[_si]->_following._names[v5A]);
+
+ if (v58 == -1) {
+ _questions[_si]->_following._questions[v5A] = 0;
+ } else {
+ _questions[_si]->_following._questions[v5A] = _questions[v58-1];
+
+ if (v50[v58]) {
+ _questions[_si]->_answer_moods[v5A] |= 0x10;
+ }
+
+ v50[v58] = 1;
+ }
+ }
+ }
+
+ for (uint16 _si = 0; _si < num_questions; _si++)
+ memFree(_questions_names[_si]);
+
+ return _questions[0];
+}
+
+
+char *parseDialogueString() {
+
+ char vC8[200];
+ char *vD0 = NULL;
+ do {
+
+ vD0 = parseNextLine(vC8, 200);
+ if (vD0 == 0) return NULL;
+
+ vD0 = skip_whitespace(vD0);
+
+ } while (strlen(vD0) == 0);
+
+ vD0[strlen(vD0)-1] = '\0'; // deletes the trailing '0xA' inserted by parseNextLine
+ // this is critical for Graphics::displayBalloonString to work properly
+
+ char *vCC = (char*)memAlloc(strlen(vD0)+1);
+ strcpy(vCC, vD0);
+
+ return vCC;
+}
+
+
+void freeDialogue(Dialogue *d) {
+
+ if (!d) return;
+
+ uint16 _si;
+ for (_si = 0; _si < 5; _si++) {
+ if (d->_answer_moods[_si] & 0x10)
+ freeDialogue(d->_following._questions[_si]);
+ }
+
+ for (_si = 0; _si < 5; _si++) {
+ freeCommands(d->_commands[_si]);
+ memFree(d->_answers[_si]);
+ }
+
+ memFree(d->_text);
+ memFree(d);
+
+ return;
+}
+
+
+
+void runDialogue(SpeakData *data) {
+
+ enterDialogue();
+
+ if (!scumm_stricmp(_location, "museum")) {
+ _vm->_graphics->freeCnv( &_tempFrames );
+ }
+
+ char v20[PATH_LEN];
+ char *v24 = _vm->_characterName;
+ if (!scumm_strnicmp(v24, "mini", 4)) {
+ v24+=4;
+ }
+
+ if (_engineFlags & kEngineMiniDonna) {
+ sprintf(v20, "%stta", v24);
+ } else {
+ sprintf(v20, "%stal", v24);
+ }
+
+ _vm->_graphics->loadExternalCnv(v20, &_characterFace);
+ _vm->_graphics->loadExternalCnv("comiccnv", &Graphics::_font);
+
+ Cnv v6E;
+ StaticCnv v5C, v48;
+
+ if (!scumm_stricmp(data->_name, "yourself") || data->_name[0] == '\0') {
+ memcpy(&v6E, &_characterFace, sizeof(Cnv));
+ } else {
+ _vm->_graphics->loadCnv(data->_name, &v6E);
+ }
+
+ v5C._width = v6E._width;
+ v5C._height = v6E._height;
+
+ v48._width = _characterFace._width;
+ v48._height = _characterFace._height;
+
+ bool displayedAnswers = false;
+ int16 question_width = 0, question_height = 0;
+ bool askPassword = false;
+ uint16 _di = 0;
+ Command *v34 = NULL;
+
+// printf("enter Dialogue\n");
+
+ Dialogue *v60 = data->_dialogue;
+ while (v60) {
+
+ v5C._data0 = v6E._array[v60->_mood & 0xF];
+// v5C._data1 = v6E.field_8[v60->_mood & 0xF];
+ v48._data0 = _characterFace._array[v60->_mood & 0xF];
+// v48._data1 = _characterFace.field_8[v60->_mood & 0xF];
+
+ // display Question if any
+ if (scumm_stricmp(v60->_text, "NULL")) {
+ _vm->_graphics->flatBlitCnv(
+ &v5C,
+ QUESTION_CHARACTER_X,
+ QUESTION_CHARACTER_Y,
+ Graphics::kBitFront,
+ v5C._data1
+ );
+
+ _vm->_graphics->getStringExtent(
+ v60->_text,
+ MAX_BALLOON_WIDTH,
+ &question_width,
+ &question_height
+ );
+
+ _vm->_graphics->drawBalloon(
+ QUESTION_BALLOON_X,
+ QUESTION_BALLOON_Y,
+ question_width,
+ question_height,
+ v60->_mood & 0x10
+ );
+
+ _vm->_graphics->displayWrappedString(
+ v60->_text,
+ QUESTION_BALLOON_X,
+ QUESTION_BALLOON_Y,
+ MAX_BALLOON_WIDTH,
+ 0
+ );
+
+ waitUntilLeftClick();
+ _vm->_graphics->copyScreen(Graphics::kBitBack, Graphics::kBitFront);
+ }
+
+ if (v60->_answers[0] == NULL) break;
+
+ _answerBalloonY[0] = 10;
+ displayedAnswers = false;
+
+
+ if (scumm_stricmp(v60->_answers[0], "NULL")) {
+
+ uint16 _si = 0;
+ while (_si < 5 && v60->_answers[_si]) {
+
+ uint32 v28 = _localFlags[_vm->_currentLocationIndex];
+ if (v60->_yesFlags[_si] & kFlagsGlobal) {
+ v28 = _commandFlags | kFlagsGlobal;
+ }
+
+ // display suitable answers
+ if (((v60->_yesFlags[_si] & v28) == v60->_yesFlags[_si]) && ((v60->_noFlags[_si] & ~v28) == v60->_noFlags[_si])) {
+
+ _vm->_graphics->getStringExtent(
+ v60->_answers[_si],
+ MAX_BALLOON_WIDTH,
+ &_answerBalloonW[_si],
+ &_answerBalloonH[_si]
+ );
+
+ _vm->_graphics->drawBalloon(
+ _answerBalloonX[_si],
+ _answerBalloonY[_si],
+ _answerBalloonW[_si],
+ _answerBalloonH[_si],
+ 1
+ );
+
+ _answerBalloonY[_si+1] = 10 + _answerBalloonY[_si] + _answerBalloonH[_si];
+
+ askPassword = _vm->_graphics->displayWrappedString(
+ v60->_answers[_si],
+ _answerBalloonX[_si],
+ _answerBalloonY[_si],
+ MAX_BALLOON_WIDTH,
+ 3
+ );
+
+ displayedAnswers = true;
+ } else {
+ _answerBalloonY[_si+1] = _answerBalloonY[_si];
+ _answerBalloonY[_si] = SKIPPED_ANSWER;
+ }
+
+ _si++;
+
+ }
+
+ if (displayedAnswers == true) {
+
+ _vm->_graphics->flatBlitCnv(
+ &v48,
+ ANSWER_CHARACTER_X,
+ ANSWER_CHARACTER_Y,
+ Graphics::kBitFront,
+ v48._data1
+ );
+
+ if (askPassword == false) {
+
+ _di = selectAnswer(v60, &v48);
+
+ } else {
+
+ char password[100];
+ uint16 passwordLen = 0;
+
+ while (askPassword == true) {
+ strcpy(password, ".......");
+ _vm->_graphics->copyScreen(Graphics::kBitBack, Graphics::kBitFront);
+
+ _vm->_graphics->drawBalloon(
+ _answerBalloonX[0],
+ _answerBalloonY[0],
+ _answerBalloonW[0],
+ _answerBalloonH[0],
+ 1
+ );
+
+ _vm->_graphics->displayWrappedString(
+ v60->_answers[0],
+ _answerBalloonX[0],
+ _answerBalloonY[0],
+ MAX_BALLOON_WIDTH,
+ 3
+ );
+
+ _vm->_graphics->flatBlitCnv(
+ &v48,
+ ANSWER_CHARACTER_X,
+ ANSWER_CHARACTER_Y,
+ Graphics::kBitFront,
+ v48._data1
+ );
+
+ _vm->_graphics->displayBalloonString(
+ _answerBalloonX[0] + 5,
+ _answerBalloonY[0] + _answerBalloonH[0] - 15,
+ "> ",
+ 0
+ );
+
+ OSystem::Event e;
+
+ while (e.kbd.ascii != 0xD && passwordLen < MAX_PASSWORD_LENGTH) {
+
+ if (!g_system->pollEvent(e)) continue;
+ if (e.type != OSystem::EVENT_KEYDOWN) continue;
+ if (!isdigit(e.kbd.ascii)) continue;
+
+ password[passwordLen] = e.kbd.ascii;
+ passwordLen++;
+ password[passwordLen] = '\0';
+
+ _vm->_graphics->displayBalloonString(
+ _answerBalloonX[0] + 5,
+ _answerBalloonY[0] + _answerBalloonH[0] - 15,
+ password,
+ 0
+ );
+
+ g_system->delayMillis(20);
+ }
+
+ if ((!scumm_stricmp(_vm->_characterName, "dough") && !scumm_strnicmp(password, "1732461", 7)) ||
+ (!scumm_stricmp(_vm->_characterName, "donna") && !scumm_strnicmp(password, "1622", 4)) ||
+ (!scumm_stricmp(_vm->_characterName, "dino") && !scumm_strnicmp(password, "179", 3))) {
+
+ askPassword = false;
+
+ }
+
+ _di = 0;
+
+ }
+
+ }
+
+ _vm->_graphics->copyScreen(Graphics::kBitBack, Graphics::kBitFront);
+
+ v34 = v60->_commands[_di];
+ v60 = (Dialogue*)v60->_following._questions[_di];
+
+ } else {
+ v60 = NULL;
+ }
+ } else {
+
+ v60 = (Dialogue*)v60->_following._questions[_di];
+
+ }
+
+ }
+
+// printf("exit Dialogue\n");
+
+ _vm->_graphics->copyScreen(Graphics::kBitBack, Graphics::kBitFront);
+ _vm->_graphics->freeCnv(&_characterFace);
+
+ if (scumm_stricmp(data->_name, "yourself") || data->_name[0] == '\0') {
+ _vm->_graphics->freeCnv(&v6E);
+ }
+
+ _vm->_graphics->freeCnv(&Graphics::_font);
+ exitDialogue();
+
+ if (!scumm_stricmp(_location, "museum")) {
+
+ closeArchive();
+ strcpy(_vm->_disk, "disk1");
+ openArchive(_vm->_disk);
+ _vm->_graphics->loadCnv("dino", &_tempFrames);
+
+ memcpy(&_yourself._cnv, &_tempFrames, sizeof(Cnv));
+
+ }
+
+ runCommands(v34);
+
+ return;
+
+}
+
+int16 selectAnswer(Question *q, StaticCnv *cnv) {
+
+ int16 v6 = 0;
+ int16 numAvailableAnswers = 0;
+ int16 _si = 0;
+ int16 _di = 0;
+
+ for (; q->_answers[v6]; v6++) {
+ if (_answerBalloonY[v6] == SKIPPED_ANSWER) continue;
+
+ _di = v6;
+ numAvailableAnswers++;
+ }
+
+ _answerBalloonY[v6] = 2000;
+
+ if (numAvailableAnswers == 1) {
+
+ _vm->_graphics->displayWrappedString(
+ q->_answers[_di],
+ _answerBalloonX[_di],
+ _answerBalloonY[_di],
+ MAX_BALLOON_WIDTH,
+ 0
+ );
+
+ cnv->_data0 = _characterFace._array[q->_answer_moods[_di] & 0xF];
+// cnv->_data1 = _characterFace.field_8[q->_answer_moods[_di] & 0xF];
+
+ _vm->_graphics->flatBlitCnv(
+ cnv,
+ ANSWER_CHARACTER_X,
+ ANSWER_CHARACTER_Y,
+ Graphics::kBitFront,
+ cnv->_data1
+ );
+
+ waitUntilLeftClick();
+ return _di;
+ }
+
+ int16 v2 = -1;
+
+ _mouseButtons = kMouseNone;
+ while (_mouseButtons != kMouseLeftUp) {
+
+ _vm->updateInput();
+ _si = getHoverAnswer(_mousePos._x, _mousePos._y, q);
+
+ if (_si != v2) {
+ if (_si != -1) {
+ _vm->_graphics->displayWrappedString(
+ q->_answers[v2],
+ _answerBalloonX[v2],
+ _answerBalloonY[v2],
+ MAX_BALLOON_WIDTH,
+ 3
+ );
+ }
+
+ _vm->_graphics->displayWrappedString(
+ q->_answers[_si],
+ _answerBalloonX[_si],
+ _answerBalloonY[_si],
+ MAX_BALLOON_WIDTH,
+ 0
+ );
+
+ cnv->_data0 = _characterFace._array[q->_answer_moods[_si] & 0xF];
+// cnv->_data1 = _characterFace.field_8[q->_answer_moods[_si] & 0xF];
+
+ _vm->_graphics->flatBlitCnv(
+ cnv,
+ ANSWER_CHARACTER_X,
+ ANSWER_CHARACTER_Y,
+ Graphics::kBitFront,
+ cnv->_data1
+ );
+
+ }
+
+ v2 = _si;
+ }
+
+ return _si;
+}
+
+
+//
+// finds out which answer is currently selected
+//
+int16 getHoverAnswer(int16 x, int16 y, Question *q) {
+
+ int16 top = 1000;
+ int16 bottom = 1000;
+
+ for (int16 _si = 0; _si < 5; _si++) {
+ if (q->_answers[_si] == NULL) break;
+
+ if (_answerBalloonY[_si] != SKIPPED_ANSWER) {
+ top = _answerBalloonY[_si];
+ }
+
+ int16 _di = _si + 1;
+ for (; _answerBalloonY[_di] == SKIPPED_ANSWER; _di++) ;
+
+ bottom = _answerBalloonY[_di];
+
+ // mouse position is compared only with y coordinates
+ if (y > top && y < bottom) return _si;
+
+ }
+
+ return 0;
+
+}
+
+// backups background mask and path
+//
+//
+void enterDialogue() {
+
+ _vm->_graphics->backupBackgroundMask(Graphics::kMask0);
+ _vm->_graphics->backupBackgroundPath(Graphics::kPath0);
+
+ return;
+}
+
+// restores background mask and path
+// rebuilds inventory
+//
+void exitDialogue() {
+
+ _vm->_graphics->restoreBackgroundMask(Graphics::kMask0);
+ _vm->_graphics->restoreBackgroundPath(Graphics::kPath0);
+
+ refreshInventory(_vm->_characterName);
+
+ return;
+}
+
+
+} // namespace Parallaction
diff --git a/engines/parallaction/disk.h b/engines/parallaction/disk.h
new file mode 100644
index 0000000000..bff58ad73e
--- /dev/null
+++ b/engines/parallaction/disk.h
@@ -0,0 +1,61 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * 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_DISK_H
+#define PARALLACTION_DISK_H
+
+#include "parallaction/defs.h"
+
+namespace Parallaction {
+
+//------------------------------------------------------
+// ARCHIVE MANAGEMENT
+//------------------------------------------------------
+
+struct ArchivedFile {
+ uint16 _index;
+ uint32 _offset;
+ uint32 _cursor;
+ uint16 field_A; // unused
+ uint16 field_C; // unused
+ uint32 _endOffset;
+};
+
+void openArchive(const char *file);
+void closeArchive();
+
+ArchivedFile *openArchivedFile(const char *name);
+void closeArchivedFile(ArchivedFile*);
+
+uint16 getArchivedFileLength(const char *name);
+
+int16 readArchivedFile(ArchivedFile*, void *buffer, uint16 size);
+char *readArchivedFileText(char *buf, uint16 size, void*);
+
+
+
+
+} // namespace Parallaction
+
+
+
+#endif
diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp
new file mode 100644
index 0000000000..15237b5c54
--- /dev/null
+++ b/engines/parallaction/graphics.cpp
@@ -0,0 +1,1361 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * 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/file.h"
+
+#include "parallaction/graphics.h"
+#include "parallaction/parser.h"
+#include "parallaction/parallaction.h"
+#include "parallaction/inventory.h"
+#include "parallaction/disk.h"
+
+
+extern OSystem *g_system;
+
+namespace Parallaction {
+
+
+byte * _maskBackup;
+byte * _pathBackup;
+
+
+
+uint16 _bgLayers[4];
+
+// FIXME:
+extern byte _glyphWidths[];
+
+Cnv Graphics::_font;
+bool Graphics::_proportionalFont = false;
+Point Graphics::_labelPosition[2] = { { 0, 0 }, { 0, 0 } };
+StaticCnv Graphics::_mouseComposedArrow;
+byte * Graphics::_buffers[];
+
+#define PALETTE_BACKUP PALETTE_SIZE
+
+PaletteFxRange _palettefx[6];
+byte _palette[PALETTE_SIZE];
+
+byte _black_palette[PALETTE_SIZE] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+
+#define BALLOON_WIDTH 12
+#define BALLOON_HEIGHT 10
+
+byte _resBalloon[2][BALLOON_WIDTH*BALLOON_HEIGHT] = {
+ {
+ 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02,
+ 0x02, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x00, 0x01, 0x01, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x00, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ },
+ {
+ 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02,
+ 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x02, 0x02, 0x02,
+ 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x00, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02
+ }
+};
+
+void Graphics::drawBalloon(int16 left, int16 top, uint16 width, uint16 height, uint16 winding) {
+// printf("Graphics::drawBalloon(%i, %i, %i, %i, %i)...", left, top, width, height, winding);
+
+ width+=5;
+ floodFill(0, left, top, left+width, top+height, kBitFront);
+ floodFill(1, left+1, top+2, left+width-1, top+height-1, kBitFront);
+
+ winding = (winding == 0 ? 1 : 0);
+ byte *s = _resBalloon[winding];
+ byte *d = _buffers[kBitFront] + (left + width/2 - 5) + (top + height - 1) * SCREEN_WIDTH;
+
+ for (uint16 i = 0; i < BALLOON_HEIGHT; i++) {
+ for (uint16 j = 0; j < BALLOON_WIDTH; j++) {
+ if (*s != 2) *d = *s;
+ d++;
+ s++;
+ }
+
+ d += (SCREEN_WIDTH - BALLOON_WIDTH);
+ }
+
+// printf("done\n");
+
+ return;
+}
+
+
+
+//
+// palette management
+//
+
+void Graphics::setPalette(byte *palette) {
+// printf("setPalette()\n");
+// memcpy(_palette, palette, PALETTE_SIZE);
+
+ byte syspal[PALETTE_COLORS*4];
+
+ for (uint32 i = 0; i < PALETTE_COLORS; i++) {
+ syspal[i*4] = (palette[i*3] << 2) | (palette[i*3] >> 4);
+ syspal[i*4+1] = (palette[i*3+1] << 2) | (palette[i*3+1] >> 4);
+ syspal[i*4+2] = (palette[i*3+2] << 2) | (palette[i*3+2] >> 4);
+ syspal[i*4+3] = 0;
+ }
+
+ g_system->setPalette(syspal, 0, PALETTE_COLORS);
+ g_system->updateScreen();
+ return;
+}
+
+void Graphics::getBlackPalette(byte *palette) {
+ memcpy(palette, _black_palette, PALETTE_SIZE);
+ return;
+}
+
+void Graphics::palUnk0(byte *palette) {
+#if 0
+ for (uint16 i = 0; i < PALETTE_SIZE; i++) {
+ palette[PALETTE_BACKUP+i] = _palette[i]/2;
+ }
+#endif
+ Graphics::setPalette(palette);
+
+ return;
+}
+
+
+void Graphics::buildBWPalette(byte *palette) {
+
+ for (uint16 i = 0; i < PALETTE_COLORS; i++) {
+ byte max;
+
+ if (_palette[i*3+1] > _palette[i*3+2]) {
+ max = _palette[i*3+1];
+ } else {
+ max = _palette[i*3+2];
+ }
+
+ if (_palette[i*3] > max) {
+ max = _palette[i*3];
+ } else {
+ if (_palette[i*3+1] > _palette[i*3+2]) {
+ max = _palette[i*3+1];
+ } else {
+ max = _palette[i*3+2];
+ }
+ }
+
+ palette[i*3] = max;
+ palette[i*3+1] = max;
+ palette[i*3+2] = max;
+ }
+
+ return;
+}
+
+void Graphics::fadePalette(byte *palette) {
+
+ for (uint16 i = 0; i < PALETTE_SIZE; i++)
+ if (palette[i] < _palette[i]) palette[i]++;
+
+
+ return;
+}
+
+void Graphics::quickFadePalette(byte *palette) {
+
+ for (uint16 i = 0; i <= PALETTE_SIZE; i++) {
+ if (palette[i] == _palette[i]) continue;
+ palette[i] += (palette[i] < _palette[i] ? 4 : -4);
+ }
+
+ return;
+}
+
+//
+// palette Animation
+//
+// FIXME: the effect is different from the original
+//
+void Graphics::animatePalette(byte *palette) {
+// printf("Graphics::animatePalette()\n");
+
+ byte tmp[3];
+
+ for (uint16 i = 0; i < 4; i++) {
+
+ if ((_palettefx[i]._flags & 1) == 0) continue; // animated palette
+
+ _palettefx[i]._timer += _palettefx[i]._step * 2; // update timer
+
+ if (_palettefx[i]._timer < 0x4000) continue; // check timeout
+
+ _palettefx[i]._timer = 0; // reset timer
+
+ if (_palettefx[i]._flags & 2) { // forward
+
+ tmp[0] = _palette[_palettefx[i]._first * 3];
+ tmp[1] = _palette[_palettefx[i]._first * 3 + 1];
+ tmp[2] = _palette[_palettefx[i]._first * 3 + 2];
+
+ memmove(palette+_palettefx[i]._first*3, _palette+(_palettefx[i]._first+1)*3, (_palettefx[i]._last - _palettefx[i]._first)*3);
+
+ palette[_palettefx[i]._last * 3] = tmp[0];
+ palette[_palettefx[i]._last * 3 + 1] = tmp[1];
+ palette[_palettefx[i]._last * 3 + 2] = tmp[2];
+
+ } else { // backward
+
+ tmp[0] = _palette[_palettefx[i]._last * 3];
+ tmp[1] = _palette[_palettefx[i]._last * 3 + 1];
+ tmp[2] = _palette[_palettefx[i]._last * 3 + 2];
+
+ memmove(palette+(_palettefx[i]._first+1)*3, _palette+_palettefx[i]._first*3, (_palettefx[i]._last - _palettefx[i]._first)*3);
+
+ palette[_palettefx[i]._first * 3] = tmp[0];
+ palette[_palettefx[i]._first * 3 + 1] = tmp[1];
+ palette[_palettefx[i]._first * 3 + 2] = tmp[2];
+
+ }
+
+ }
+
+ return;
+}
+
+
+
+
+void Graphics::updateScreen() {
+// printf("Graphics::updateScreen()\n");
+ g_system->copyRectToScreen(_buffers[kBitFront], SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+ g_system->updateScreen();
+ return;
+}
+
+
+void Graphics::swapBuffers() {
+ byte *temp = _buffers[kBitFront];
+ _buffers[kBitFront] = _buffers[kBitBack];
+ _buffers[kBitBack] = temp;
+ updateScreen();
+ return;
+}
+
+
+//
+// graphic primitives
+//
+void Graphics::clearScreen(Graphics::Buffers buffer) {
+ memset(_buffers[buffer], 0, SCREEN_WIDTH*SCREEN_HEIGHT);
+
+ if (buffer == kBitFront) updateScreen();
+
+ return;
+}
+
+
+void Graphics::copyScreen(Graphics::Buffers srcbuffer, Graphics::Buffers dstbuffer) {
+ memcpy(_buffers[dstbuffer], _buffers[srcbuffer], SCREEN_WIDTH*SCREEN_HEIGHT);
+
+ if (dstbuffer == kBitFront) updateScreen();
+
+ return;
+}
+
+
+void Graphics::copyRect(Graphics::Buffers srcbuffer, uint16 sx, uint16 sy, Graphics::Buffers dstbuffer, uint16 dx, uint16 dy, uint16 w, uint16 h) {
+
+ byte *s = _buffers[srcbuffer] + (sx + sy * SCREEN_WIDTH);
+ byte *d = _buffers[dstbuffer] + (dx + dy * SCREEN_WIDTH);
+
+ for (uint16 i = 0; i < h; i++) {
+ memcpy(d, s, w);
+
+ s += SCREEN_WIDTH;
+ d += SCREEN_WIDTH;
+ }
+
+ if (dstbuffer == kBitFront) updateScreen();
+
+ return;
+
+}
+
+
+void Graphics::floodFill(byte color, uint16 left, uint16 top, uint16 right, uint16 bottom, Graphics::Buffers buffer) {
+// printf("Graphics::floodFill(%i, %i, %i, %i, %i)\n", color, left, top, right, bottom);
+
+ byte *d = _buffers[buffer] + (left + top * SCREEN_WIDTH);
+ uint16 w = right - left + 1;
+ uint16 h = bottom - top + 1;
+
+ for (uint16 i = 0; i < h; i++) {
+ memset(d, color, w);
+
+ d += SCREEN_WIDTH;
+ }
+
+ if (buffer == kBitFront) updateScreen();
+
+ return;
+}
+
+
+void Graphics::flatBlit(uint16 w, uint16 h, int16 x, int16 y, byte *data, Graphics::Buffers buffer) {
+// printf("Graphics::flatBlit(%i, %i, %i, %i)\n", w, h, x, y);
+
+ int16 left = 0, top = 0;
+ int16 right = w, bottom = h;
+
+ if (x + w > SCREEN_WIDTH) right = SCREEN_WIDTH - x;
+ if (y + h > SCREEN_HEIGHT) bottom = SCREEN_HEIGHT - y;
+
+ if (x < 0) { // partially left clipped
+ left = -x;
+ x = 0;
+ }
+
+ if (y < 0) { // partially top clipped
+ top = -y;
+ y = 0;
+ }
+
+ if (left > right || top > bottom || x >= SCREEN_WIDTH || y >= SCREEN_HEIGHT) return; // fully clipped
+
+ byte *s = data + left + top * w;
+ byte *d = _buffers[buffer] + x + y * SCREEN_WIDTH;
+
+ for (uint16 i = top; i < bottom; i++) {
+ for (uint16 j = left; j < right; j++) {
+ if (*s != 0) *d = *s;
+ s++;
+ d++;
+ }
+
+ s += (w - right + left);
+ d += (SCREEN_WIDTH - right + left);
+ }
+
+ if (buffer == kBitFront) updateScreen();
+
+ return;
+
+}
+
+
+void Graphics::blit(uint16 w, uint16 h, int16 x, int16 y, uint16 z, byte *data, Graphics::Buffers buffer, Graphics::Buffers mask) {
+// printf("Graphics::blit(%i, %i, %i, %i, %i)\n", w, h, x, y, z);
+
+ int16 left = 0, top = 0;
+ int16 right = w, bottom = h;
+
+ if (x + w > SCREEN_WIDTH) right = SCREEN_WIDTH - x;
+ if (y + h > SCREEN_HEIGHT) bottom = SCREEN_HEIGHT - y;
+
+ if (x < 0) { // partially left clipped
+ left = -x;
+ x = 0;
+ }
+
+ if (y < 0) { // partially top clipped
+ top = -y;
+ y = 0;
+ }
+
+ if (left > right || top > bottom || x >= SCREEN_WIDTH || y >= SCREEN_HEIGHT) return; // fully clipped
+
+ byte *s = data + left + top * w;
+ byte *d = _buffers[buffer] + x + y * SCREEN_WIDTH;
+
+ for (uint16 i = top; i < bottom; i++) {
+
+ uint16 r = x % 4;
+ byte *m = _buffers[mask] + x/4 + (y + i - top)*SCREENMASK_WIDTH;
+
+ for (uint16 j = left; j < right; j++) {
+ if (*s != 0) {
+ uint16 v = ((3 << (r << 1)) & *m) >> (r << 1);
+ if (z >= v) *d = *s;
+ }
+
+ r++;
+ if (r==4) m++;
+ r &= 0x3;
+
+ s++;
+ d++;
+ }
+
+ s += (w - right + left);
+ d += (SCREEN_WIDTH - right + left);
+ }
+
+ if (buffer == kBitFront) updateScreen();
+
+ return;
+
+}
+
+
+void jobDisplayLabel(void *parm, Job *j) {
+
+ StaticCnv *cnv = (StaticCnv*)parm;
+
+ if (cnv->_data0 == NULL) return;
+ _vm->_graphics->flatBlitCnv(cnv, Graphics::_labelPosition[0]._x, Graphics::_labelPosition[0]._y, Graphics::kBitBack, cnv->_data1);
+
+ return;
+}
+
+void jobEraseLabel(void *parm, Job *j) {
+ StaticCnv *cnv = (StaticCnv*)parm;
+
+ int16 _si, _di;
+
+ if (_vm->_activeItem._id != 0) {
+ _si = _mousePos._x + 16 - cnv->_width/2;
+ _di = _mousePos._y + 34;
+ } else {
+ _si = _mousePos._x + 8 - cnv->_width/2;
+ _di = _mousePos._y + 33;
+ }
+
+ if (_si < 0) _si = 0;
+ if (_di > 190) _di = 190;
+
+ if (cnv->_width > SCREEN_WIDTH)
+ _si = SCREEN_WIDTH - _si;
+
+
+ _vm->_graphics->restoreBackground(Graphics::_labelPosition[1]._x, Graphics::_labelPosition[1]._y, cnv->_width, cnv->_height);
+
+ Graphics::_labelPosition[1]._x = Graphics::_labelPosition[0]._x;
+ Graphics::_labelPosition[1]._y = Graphics::_labelPosition[0]._y;
+ Graphics::_labelPosition[0]._x = _si;
+ Graphics::_labelPosition[0]._y = _di;
+
+ return;
+}
+
+void Graphics::initMouse(uint16 arg_0) {
+
+ loadExternalStaticCnv("pointer", &_mouseComposedArrow);
+
+ byte temp[16*16];
+ memcpy(temp, _mouseArrow, 16*16);
+
+ uint16 k = 0;
+ for (uint16 i = 0; i < 4; i++) {
+ for (uint16 j = 0; j < 64; j++) _mouseArrow[k++] = temp[i + j * 4];
+ }
+
+ return;
+}
+
+void Graphics::setMousePointer(int16 index) {
+
+ if (index == kCursorArrow) { // standard mouse pointer
+
+ StaticCnv cnv;
+
+ cnv._width = 16;
+ cnv._height = 16;
+ cnv._data0 = _mouseArrow;
+
+ g_system->setMouseCursor(_mouseArrow, 16, 16, 0, 0, 0);
+ g_system->showMouse(true);
+
+ } else {
+
+ // FIXME: standard mouse arrow must be combined with item
+ // but it is not at the moment
+
+ // inventory item pointer
+ StaticCnv mouse_pointer;
+ memcpy(&mouse_pointer, &_mouseComposedArrow, sizeof(StaticCnv));
+ byte *v8 = mouse_pointer._data0;
+
+ // FIXME: target offseting is not clear
+ extractInventoryGraphics(index, v8 + 7 + 32 * 7);
+
+ g_system->setMouseCursor(v8, 32, 32, 0, 0, 0);
+
+ }
+
+ return;
+}
+
+
+
+
+//
+// Cnv management
+//
+void Graphics::flatBlitCnv(StaticCnv *cnv, int16 x, int16 y, Graphics::Buffers buffer, byte *unused) {
+ flatBlit(cnv->_width, cnv->_height, x, y, cnv->_data0, buffer);
+ return;
+}
+
+
+void Graphics::blitCnv(StaticCnv *cnv, int16 x, int16 y, uint16 z, Graphics::Buffers buffer, Graphics::Buffers mask) {
+ blit(cnv->_width, cnv->_height, x, y, z, cnv->_data0, buffer, mask);
+ return;
+}
+
+
+void Graphics::backupCnvBackground(StaticCnv *cnv, int16 x, int16 y) {
+
+ byte *s = _buffers[kBit2] + x + y * SCREEN_WIDTH;
+ byte *d = cnv->_data2;
+
+ for (uint16 i = 0; i < cnv->_height ; i++) {
+ memcpy(d, s, cnv->_width);
+
+ s += SCREEN_WIDTH;
+ d += cnv->_width;
+ }
+
+ return;
+}
+
+
+void Graphics::backupCnvBackgroundTransparent(StaticCnv *cnv, int16 x, int16 y) {
+
+ byte *t = cnv->_data0;
+ byte *s = _buffers[kBitBack] + x + y * SCREEN_WIDTH;
+ byte *d = cnv->_data2;
+
+ for (uint16 i = 0; i < cnv->_height ; i++) {
+ for (uint16 j = 0; j < cnv->_width ; j++) {
+ *d = (*t) ? *s : 0;
+
+ d++;
+ t++;
+ s++;
+ }
+
+ s += (SCREEN_WIDTH - cnv->_width);
+ }
+
+ return;
+}
+
+
+// restores a cnv backup on the background
+//
+//
+void Graphics::restoreCnvBackground(StaticCnv *cnv, int16 x, int16 y) {
+
+ byte *temp = cnv->_data0;
+ cnv->_data0 = cnv->_data2;
+
+ flatBlitCnv(cnv, x, y, kBitBack, cnv->_data1);
+ flatBlitCnv(cnv, x, y, kBit2, cnv->_data1);
+
+ cnv->_data0 = temp;
+
+ return;
+}
+
+
+
+//
+// strings
+//
+void Graphics::displayString(uint16 x, uint16 y, const char *text) {
+
+ uint16 len = strlen(text);
+ StaticCnv tmp;
+
+ for (uint16 i = 0; i < len; i++) {
+ char c = mapChar(text[i]);
+
+ tmp._width = _font._width;
+ tmp._height = _font._height;
+ tmp._data0 = _font._array[c];
+
+ flatBlitCnv(&tmp, x, y, kBitFront, NULL);
+
+ x += (_proportionalFont ? _glyphWidths[(int)c] : 8);
+
+ }
+
+ return;
+}
+
+
+void Graphics::displayBalloonString(uint16 x, uint16 y, const char *text, byte color) {
+
+ uint16 len = strlen(text);
+
+ for (uint16 i = 0; i < len; i++) {
+
+ char c = mapChar(text[i]);
+ uint16 w = _proportionalFont ? _glyphWidths[(int)c] : 8;
+ byte *s = _font._array[c];
+ byte *d = _buffers[kBitFront] + x + y*SCREEN_WIDTH;
+
+// printf("%i\n", text[i]);
+
+ for (uint16 j = 0; j < _font._height; j++) {
+ for (uint16 k = 0; k < w; k++) {
+ *d = (*s) ? 1 : color;
+ d++;
+ s++;
+ }
+
+ s += (8 - w);
+ d += (SCREEN_WIDTH - w);
+ }
+
+ x += w;
+ }
+
+ updateScreen();
+
+ return;
+}
+
+
+
+bool Graphics::displayWrappedString(char *text, uint16 x, uint16 y, uint16 maxwidth, byte color) {
+// printf("Graphics::displayWrappedString(%s, %i, %i, %i, %i)...", text, x, y, maxwidth, color);
+
+ uint16 lines = 0;
+ bool rv = false;
+ uint16 linewidth = 0;
+
+ _proportionalFont = true;
+ uint16 rx = x + 10;
+ uint16 ry = y + 4;
+
+ char token[40];
+
+ while (strlen(text) > 0) {
+
+ text = parseNextToken(text, token, 40, " ");
+ linewidth += getStringWidth(token);
+
+ if (linewidth > maxwidth) {
+ // wrap line
+ lines++;
+ rx = x + 10; // x
+ ry = y + 4 + lines*10; // y
+ linewidth = getStringWidth(token);
+ }
+
+ if (!scumm_stricmp(token, "%s")) {
+ sprintf(token, "%d", _score);
+ }
+ if (!scumm_stricmp(token, "%p")) {
+ rv = true;
+ } else
+ displayBalloonString(rx, ry, token, color);
+
+ rx += getStringWidth(token) + getStringWidth(" ");
+ linewidth += getStringWidth(" ");
+
+ text = skip_whitespace(text);
+ }
+
+// printf("done\n");
+
+ return rv;
+
+}
+
+
+
+uint16 Graphics::getStringWidth(const char *text) {
+ uint16 len = strlen(text);
+
+ if (_proportionalFont == 0) {
+ // fixed font
+ return len*8;
+ }
+
+ // proportional font
+ uint16 w = 0;
+ for (uint16 i = 0; i < len; i++) {
+ char c = mapChar(text[i]);
+ w += _glyphWidths[(int)c];
+ }
+
+ return w;
+}
+
+
+void Graphics::getStringExtent(char *text, uint16 maxwidth, int16* width, int16* height) {
+
+ uint16 lines = 0;
+ uint16 w = 0;
+ *width = 0;
+
+ _proportionalFont = true;
+
+ char token[40];
+
+ while (strlen(text) != 0) {
+
+ text = parseNextToken(text, token, 40, " ");
+ w += getStringWidth(token);
+
+ if (w > maxwidth) {
+ w -= getStringWidth(token);
+ lines++;
+ if (w > *width)
+ *width = w;
+
+ w = getStringWidth(token);
+ }
+
+ w += getStringWidth(" ");
+ text = skip_whitespace(text);
+ }
+
+ if (*width < w) *width = w;
+ *width += 10;
+
+ *height = lines * 10 + 20;
+
+ return;
+}
+
+
+// backups background mask
+//
+//
+void Graphics::backupBackgroundMask(Graphics::Buffers mask) {
+
+ byte *s = _buffers[mask];
+ byte *d = _maskBackup;
+
+ memcpy(d, s, SCREENMASK_WIDTH*SCREEN_HEIGHT);
+
+ return;
+}
+
+// restores background mask
+//
+//
+void Graphics::restoreBackgroundMask(Graphics::Buffers mask) {
+
+ byte *s = _maskBackup;
+ byte *d = _buffers[mask];
+
+ memcpy(d, s, SCREENMASK_WIDTH*SCREEN_HEIGHT);
+
+ return;
+}
+
+// backups background path
+//
+//
+void Graphics::backupBackgroundPath(Graphics::Buffers path) {
+
+ byte *s = _buffers[path];
+ byte *d = _pathBackup;
+
+ memcpy(d, s, SCREENPATH_WIDTH*SCREEN_HEIGHT);
+
+ return;
+}
+
+//
+// restores background path
+//
+void Graphics::restoreBackgroundPath(Graphics::Buffers path) {
+
+ byte *s = _pathBackup;
+ byte *d = _buffers[path];
+
+ memcpy(d, s, SCREENPATH_WIDTH*SCREEN_HEIGHT);
+
+ return;
+}
+
+//
+// decompress a graphics block
+//
+uint16 Graphics::decompressChunk(byte *src, byte *dst, uint16 size) {
+
+ uint16 written = 0;
+ uint16 read = 0;
+ uint16 len = 0;
+
+ for (; written != size; written += len) {
+
+ len = src[read];
+ read++;
+
+ if (len <= 127) {
+ // copy run
+
+ len++;
+ memcpy(dst+written, src+read, len);
+ read += len;
+
+ } else {
+ // expand run
+
+ len = 257 - len;
+ memset(dst+written, src[read], len);
+ read++;
+
+ }
+
+ }
+
+ return read;
+}
+
+void Graphics::restoreBackground(int16 left, int16 top, uint16 width, uint16 height) {
+// printf("restoreBackground(%i, %i, %i, %i)\n", left, top, width, height);
+
+ if (left < 0) left = 0;
+ if (top < 0) top = 0;
+
+ if (left >= SCREEN_WIDTH) return;
+ if (top >= SCREEN_HEIGHT) return;
+
+ if (left+width >= SCREEN_WIDTH) width = SCREEN_WIDTH - left;
+ if (top+height >= SCREEN_HEIGHT) height = SCREEN_HEIGHT - top;
+
+ copyRect(kBit2, left, top, kBitBack, left, top, width, height);
+
+ return;
+}
+
+
+void Graphics::makeCnvFromString(StaticCnv *cnv, char *text) {
+// printf("makeCnvFromString('%s')\n", text);
+
+ uint16 len = strlen(text);
+
+ cnv->_width = _font._width * len;
+ cnv->_height = _font._height;
+
+// printf("%i x %i\n", cnv->_width, cnv->_height);
+
+ cnv->_data0 = (byte*)memAlloc(cnv->_width * cnv->_height);
+
+ for (uint16 i = 0; i < len; i++) {
+ char c = mapChar(text[i]);
+
+ byte *s = _font._array[c];
+ byte *d = cnv->_data0 + _font._width * i;
+
+ for (uint16 j = 0; j < _font._height; j++) {
+ memcpy(d, s, 8);
+
+ s += 8;
+ d += cnv->_width;
+ }
+ }
+
+ return;
+}
+
+//
+// internal character mapping
+//
+char Graphics::mapChar(char c) {
+ byte b = (byte)c;
+
+ if (b == 0xA5) return 0x5F;
+ if (b == 0xDF) return 0x60;
+
+ if (b > 0x7F) return b - 0x7F;
+
+ return b - 0x20;
+}
+
+
+//
+// loads a cnv from an external file
+//
+void Graphics::loadExternalCnv(const char *filename, Cnv *cnv) {
+// printf("Graphics::loadExternalCnv(%s)...", filename);
+
+ char path[PATH_LEN];
+
+ sprintf(path, "%s.cnv", filename);
+
+ Common::File stream;
+
+ if (!stream.open(path))
+ errorFileNotFound(path);
+
+ cnv->_count = cnv->_width = cnv->_height = 0;
+
+ stream.read(&cnv->_count, 1);
+ stream.read(&cnv->_width, 1);
+ stream.read(&cnv->_height, 1);
+
+ cnv->_array = (byte**)memAlloc(cnv->_count * sizeof(byte*));
+
+ uint16 size = cnv->_width*cnv->_height;
+ for (uint16 i = 0; i < cnv->_count; i++) {
+ cnv->_array[i] = (byte*)memAlloc(size);
+ stream.read(cnv->_array[i], size);
+ }
+
+ stream.close();
+
+// printf("done\n");
+
+
+ return;
+}
+
+
+
+
+void Graphics::loadExternalStaticCnv(const char *filename, StaticCnv *cnv) {
+
+ char path[PATH_LEN];
+
+ sprintf(path, "%s.cnv", filename);
+
+ Common::File stream;
+
+ if (!stream.open(path))
+ errorFileNotFound(path);
+
+ cnv->_width = cnv->_height = 0;
+
+ stream.skip(1);
+ stream.read(&cnv->_width, 1);
+ stream.read(&cnv->_height, 1);
+
+ uint16 size = cnv->_width*cnv->_height;
+
+ cnv->_data0 = (byte*)memAlloc(size);
+ stream.read(cnv->_data0, size);
+
+ stream.close();
+
+ return;
+}
+
+
+
+
+
+void Graphics::loadStaticCnv(const char *filename, StaticCnv *cnv) {
+// printf("Graphics::loadStaticCnv(%s)\n", filename);
+
+ char path[PATH_LEN];
+
+ strcpy(path, filename);
+ ArchivedFile *file = openArchivedFile(path);
+ if (!file) {
+ sprintf(path, "%s.pp", filename);
+ file = openArchivedFile(path);
+ if (!file) errorFileNotFound(path);
+ }
+
+ cnv->_width = cnv->_height = 0;
+
+ byte unk;
+ readArchivedFile(file, &unk, 1);
+ readArchivedFile(file, &cnv->_width, 1);
+ readArchivedFile(file, &cnv->_height, 1);
+
+ uint16 compressedsize = getArchivedFileLength(path) - 3;
+ byte *compressed = (byte*)memAlloc(compressedsize);
+
+ uint16 size = cnv->_width*cnv->_height;
+ cnv->_data0 = (byte*)memAlloc(size);
+
+ readArchivedFile(file, compressed, compressedsize);
+ closeArchivedFile(file);
+
+ decompressChunk(compressed, cnv->_data0, size);
+ memFree(compressed);
+
+ return;
+}
+
+
+
+
+void Graphics::loadCnv(const char *filename, Cnv *cnv) {
+// printf("Graphics::loadCnv(%s)\n", filename);
+
+ char path[PATH_LEN];
+
+ strcpy(path, filename);
+ ArchivedFile *file = openArchivedFile(path);
+ if (!file) {
+ sprintf(path, "%s.pp", filename);
+ file = openArchivedFile(path);
+ if (!file) errorFileNotFound(path);
+ }
+
+ cnv->_count = cnv->_width = cnv->_height = 0;
+
+ readArchivedFile(file, &cnv->_count, 1);
+ readArchivedFile(file, &cnv->_width, 1);
+ readArchivedFile(file, &cnv->_height, 1);
+
+ uint16 framesize = cnv->_width*cnv->_height;
+
+ cnv->_array = (byte**)memAlloc(cnv->_count * sizeof(byte*));
+
+ uint32 size = getArchivedFileLength(path) - 3;
+
+ byte *buf = (byte*)memAlloc(size);
+ readArchivedFile(file, buf, size);
+
+ byte *s = buf;
+
+ for (uint16 i = 0; i < cnv->_count; i++) {
+ cnv->_array[i] = (byte*)memAlloc(framesize);
+ uint16 read = decompressChunk(s, cnv->_array[i], framesize);
+
+// printf("frame %i decompressed: %i --> %i\n", i, read, framesize);
+
+ s += read;
+ }
+
+ closeArchivedFile(file);
+
+ memFree(buf);
+
+ return;
+}
+
+
+
+
+
+
+
+void Graphics::freeCnv(Cnv *cnv) {
+// printf("Graphics::freeCnv()\n");
+
+ if (!cnv) return;
+
+ for (uint16 _si = 0; _si < cnv->_count; _si++) {
+ memFree(cnv->_array[_si]);
+ }
+ memFree(cnv->_array);
+
+ return;
+}
+
+
+
+void Graphics::freeStaticCnv(StaticCnv *cnv) {
+// printf("free_static_cnv()\n");
+
+ if (!cnv) return;
+
+ if (!cnv || !cnv->_data0) return;
+ memFree(cnv->_data0);
+ cnv->_data0 = NULL;
+
+ return;
+}
+
+
+//
+// slides (background images) are stored compressed by scanline in a rle fashion
+//
+// the uncompressed data must then be unpacked to get:
+// * color data [bits 0-5]
+// * mask data [bits 6-7] (z buffer)
+// * path data [bit 8] (walkable areas)
+//
+
+uint16 _swap_16(uint16 *v) {
+
+ uint16 v2 = *v;
+ uint16 v3 = *v & 0xFF;
+ *v = (v3 << 8) | ((v2 >> 8) & 0xFF);
+
+ return *v;
+}
+
+
+void unpackBackgroundScanline(byte *src, byte *screen, byte *mask, byte *path) {
+
+ // update mask, path and screen
+ for (uint16 i = 0; i < SCREEN_WIDTH; i++) {
+ path[i/8] |= ((src[i] & 0x80) >> 7) << (i & 7);
+ mask[i/4] |= ((src[i] & 0x60) >> 5) << ((i & 3) << 1);
+ screen[i] = src[i] & 0x1F;
+ }
+
+ return;
+}
+
+
+
+
+void Graphics::loadBackground(const char *filename, Graphics::Buffers buffer) {
+// printf("Graphics::loadBackground(%s)\n", filename);
+
+ ArchivedFile *file = openArchivedFile(filename);
+ if (!file) errorFileNotFound(filename);
+
+// byte palette[PALETTE_SIZE];
+ byte v150[4];
+ readArchivedFile(file, _palette, PALETTE_SIZE);
+ readArchivedFile(file, &v150, 4);
+ readArchivedFile(file, _palettefx, sizeof(PaletteFxRange)*6);
+
+// setPalette(palette);
+
+ uint16 _si;
+ for (_si = 0; _si < 4; _si++) {
+ byte _al = v150[_si];
+ _bgLayers[_si] = _al;
+ }
+
+ for (_si = 0; _si < 6; _si++) {
+ _swap_16(&_palettefx[_si]._timer);
+ _swap_16(&_palettefx[_si]._step);
+ _swap_16(&_palettefx[_si]._flags);
+ }
+
+#if 0
+ uint16 v147;
+ for (v147 = 0; v147 < PALETTE_SIZE; v147++) {
+ byte _al = _palette[v147];
+ _palette[PALETTE_SIZE+v147] = _al / 2;
+ }
+#endif
+
+ memset(_buffers[kPath0], 0, SCREENPATH_WIDTH*SCREEN_HEIGHT);
+ memset(_buffers[kMask0], 0, SCREENMASK_WIDTH*SCREEN_HEIGHT);
+
+ byte *v4 = (byte*)memAlloc(SCREEN_SIZE);
+ readArchivedFile(file, v4, SCREEN_SIZE);
+
+ byte v144[SCREEN_WIDTH];
+
+ byte *s = v4;
+ for (uint16 i = 0; i < SCREEN_HEIGHT; i++) {
+ s += decompressChunk(s, v144, SCREEN_WIDTH);
+ unpackBackgroundScanline(v144, _buffers[buffer]+SCREEN_WIDTH*i, _buffers[kMask0]+SCREENMASK_WIDTH*i, _buffers[kPath0]+SCREENPATH_WIDTH*i);
+ }
+
+ memFree(v4);
+ closeArchivedFile(file);
+
+ return;
+}
+
+//
+// read background path and mask from a file
+//
+// mask and path are normally combined (via OR) into the background picture itself
+// read the comment on the top of this file for more
+//
+void Graphics::loadMaskAndPath(const char *filename) {
+
+ ArchivedFile *file = openArchivedFile(filename);
+ if (!file) errorFileNotFound(filename);
+
+ byte v4[4];
+ readArchivedFile(file, v4, 4);
+ readArchivedFile(file, _buffers[kPath0], SCREENPATH_WIDTH*SCREEN_HEIGHT);
+ readArchivedFile(file, _buffers[kMask0], SCREENMASK_WIDTH*SCREEN_HEIGHT);
+
+ for (uint16 _si = 0; _si < 4; _si++) _bgLayers[_si] = v4[_si];
+
+ closeArchivedFile(file);
+ return;
+}
+
+
+void Graphics::copyRect(Graphics::Buffers dstbuffer, uint16 x, uint16 y, uint16 w, uint16 h, byte *src, uint16 pitch) {
+
+ byte *d = _buffers[dstbuffer] + x + SCREEN_WIDTH * y;
+ byte *s = src;
+
+ for (uint16 _si = 0; _si < h; _si++) {
+ memcpy(d, s, w);
+
+ s += pitch;
+ d += SCREEN_WIDTH;
+ }
+
+
+}
+
+
+void Graphics::drawBorder(Graphics::Buffers buffer, uint16 x, uint16 y, uint16 w, uint16 h, byte color) {
+
+ byte *d = _buffers[buffer] + x + SCREEN_WIDTH * y;
+
+ for (uint16 i = 0; i < h; i++) {
+ d[i] = color;
+ d[i + SCREEN_WIDTH * (h-1)] = color;
+ d[i * SCREEN_WIDTH] = color;
+ d[i * SCREEN_WIDTH + w - 1] = color;
+ }
+
+ return;
+}
+
+void Graphics::grabRect(Graphics::Buffers srcbuffer, byte *dst, uint16 x, uint16 y, uint16 w, uint16 h, uint16 pitch) {
+
+ byte *s = _buffers[srcbuffer] + x + SCREEN_WIDTH * y;
+
+ for (uint16 i = 0; i < h; i++) {
+ memcpy(dst, s, w);
+
+ s += SCREEN_WIDTH;
+ dst += pitch;
+ }
+
+ return;
+}
+
+
+void Graphics::maskOpNot(uint16 x, uint16 y, uint16 unused, Graphics::Buffers mask) {
+
+ uint16 _ax = x + y * SCREEN_WIDTH;
+ _buffers[mask][_ax >> 2] &= ~(3 << ((_ax & 3) << 1));
+
+ return;
+}
+
+
+
+void Graphics::maskClearRectangle(uint16 left, uint16 top, uint16 right, uint16 bottom, Graphics::Buffers mask) {
+
+ uint16 _di = left/4 + top*80;
+
+ for (uint16 _si = top; _si < bottom; _si++) {
+ memset(&_buffers[mask][_di], 0, (right - left)/4+1);
+ _di += 80;
+ }
+
+ return;
+
+}
+
+// HACK
+// this routine is only invoked from the 'intgrotta scenario'
+//
+void Graphics::intGrottaHackMask() {
+ memset(_buffers[kMask0] + 3600, 0, 3600);
+ _bgLayers[1] = 500;
+ return;
+}
+
+uint16 Graphics::queryPath(uint16 x, uint16 y) {
+
+ byte *v6 = _buffers[kPath0];
+
+ byte _al = v6[y*40 + x/8];
+ byte _dl = 1 << (x % 8);
+
+ return _al & _dl;
+
+}
+
+int16 Graphics::queryMask(int16 v) {
+
+ for (uint16 _si = 0; _si < 3; _si++) {
+ if (_bgLayers[_si+1] > v) return _si;
+ }
+
+ return 3;
+}
+
+void Graphics::initBuffers() {
+
+ _buffers[kBitFront] = (byte*)memAlloc(SCREEN_SIZE);
+ _buffers[kBitBack] = (byte*)memAlloc(SCREEN_SIZE);
+ _buffers[kBit2] = (byte*)memAlloc(SCREEN_SIZE);
+ _buffers[kBit3] = (byte*)memAlloc(SCREEN_SIZE); // this buffer is also used by menu so it must stay this size
+
+ _buffers[kMask0] = (byte*)memAlloc(SCREENMASK_WIDTH * SCREEN_HEIGHT);
+ _buffers[kPath0] = (byte*)memAlloc(SCREENPATH_WIDTH * SCREEN_HEIGHT);
+
+ _maskBackup = (byte*)memAlloc(SCREENMASK_WIDTH * SCREEN_HEIGHT);
+ _pathBackup = (byte*)memAlloc(SCREENPATH_WIDTH * SCREEN_HEIGHT);
+
+ return;
+}
+
+
+Graphics::Graphics(Parallaction* vm) :
+ _vm(vm) {
+
+ g_system->beginGFXTransaction();
+
+ g_system->initSize(SCREEN_WIDTH, SCREEN_HEIGHT);
+
+ g_system->endGFXTransaction();
+
+ initBuffers();
+
+ byte palette[PALETTE_SIZE];
+ getBlackPalette(palette);
+ setPalette(palette);
+
+ initMouse( 0 );
+
+ return;
+}
+
+Graphics::~Graphics() {
+
+ memFree(_buffers[kMask0]);
+ memFree(_buffers[kPath0]);
+
+ memFree(_buffers[kBitFront]);
+ memFree(_buffers[kBitBack]);
+ memFree(_buffers[kBit2]);
+ memFree(_buffers[kBit3]);
+
+ return;
+}
+
+
+} // namespace Parallaction
diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h
new file mode 100644
index 0000000000..8363b93629
--- /dev/null
+++ b/engines/parallaction/graphics.h
@@ -0,0 +1,185 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * 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_GRAPHICS_H
+#define PARALLACTION_GRAPHICS_H
+
+#include "parallaction/defs.h"
+
+namespace Parallaction {
+
+
+
+#define SCREEN_WIDTH 320
+#define SCREEN_HEIGHT 200
+#define SCREEN_SIZE SCREEN_WIDTH*SCREEN_HEIGHT
+
+#define SCREENMASK_WIDTH SCREEN_WIDTH/4
+#define SCREENPATH_WIDTH SCREEN_WIDTH/8
+
+#define PALETTE_COLORS 32
+#define PALETTE_SIZE PALETTE_COLORS*3
+
+#pragma pack(push, 1)
+
+struct PaletteFxRange {
+
+ uint16 _timer;
+ uint16 _step;
+ uint16 _flags;
+ byte _first;
+ byte _last;
+
+};
+
+#pragma pack(pop)
+
+extern byte _palette[];
+
+#define NUM_BUFFERS 6
+
+class Parallaction;
+
+class Graphics {
+
+public:
+ enum Buffers {
+ // bit buffers
+ kBitFront,
+ kBitBack,
+ kBit2,
+ kBit3,
+ // mask buffers
+ kMask0,
+ // path buffers
+ kPath0
+ };
+
+public:
+
+ // dialogue and text
+ void drawBalloon(int16 left, int16 top, uint16 width, uint16 height, uint16 arg_8);
+ void displayBalloonString(uint16 x, uint16 y, const char *text, byte color);
+ void displayString(uint16 x, uint16 y, const char *text);
+ bool displayWrappedString(char *text, uint16 x, uint16 y, uint16 maxwidth, byte color);
+ uint16 getStringWidth(const char *text);
+ void getStringExtent(char *text, uint16 maxwidth, int16* width, int16* height);
+
+ // cnv management
+ void makeCnvFromString(StaticCnv *cnv, char *text);
+ void loadExternalCnv(const char *filename, Cnv *cnv);
+ void loadExternalStaticCnv(const char *filename, StaticCnv *cnv);
+ void loadCnv(const char *filename, Cnv *cnv);
+ void loadStaticCnv(const char *filename, StaticCnv *cnv);
+ void freeCnv(Cnv *cnv);
+ void freeStaticCnv(StaticCnv *cnv);
+ void backupCnvBackground(StaticCnv *cnv, int16 x, int16 y);
+ void backupCnvBackgroundTransparent(StaticCnv *cnv, int16 x, int16 y);
+ void restoreCnvBackground(StaticCnv *cnv, int16 x, int16 y);
+
+ // location
+ void loadBackground(const char *filename, Graphics::Buffers buffer);
+ void loadMaskAndPath(const char *filename);
+ uint16 queryPath(uint16 x, uint16 y);
+ int16 queryMask(int16 v);
+ void intGrottaHackMask();
+ void restoreBackground(int16 left, int16 top, uint16 width, uint16 height);
+ void backupBackgroundMask(Graphics::Buffers mask);
+ void restoreBackgroundMask(Graphics::Buffers mask);
+ void backupBackgroundPath(Graphics::Buffers path);
+ void restoreBackgroundPath(Graphics::Buffers path);
+
+ // intro
+ void maskClearRectangle(uint16 left, uint16 top, uint16 right, uint16 bottom, Graphics::Buffers mask);
+ void maskOpNot(uint16 x, uint16 y, uint16 unused, Graphics::Buffers mask);
+
+ // low level
+ void swapBuffers();
+ void updateScreen();
+ void clearScreen(Graphics::Buffers buffer);
+ void copyScreen(Graphics::Buffers srcbuffer, Graphics::Buffers dstbuffer);
+ void copyRect(Graphics::Buffers srcbuffer, uint16 sx, uint16 sy, Graphics::Buffers dstbuffer, uint16 dx, uint16 dy, uint16 w, uint16 h);
+ void copyRect(Graphics::Buffers dstbuffer, uint16 x, uint16 y, uint16 w, uint16 h, byte *src, uint16 pitch);
+ void grabRect(Graphics::Buffers srcbuffer, byte *dst, uint16 x, uint16 y, uint16 w, uint16 h, uint16 pitch);
+ void drawBorder(Graphics::Buffers buffer, uint16 x, uint16 y, uint16 w, uint16 h, byte color);
+ void floodFill(byte color, uint16 left, uint16 top, uint16 right, uint16 bottom, Graphics::Buffers buffer);
+ void flatBlitCnv(StaticCnv *cnv, int16 x, int16 y, Graphics::Buffers buffer, byte *unused);
+ void blitCnv(StaticCnv *cnv, int16 x, int16 y, uint16 z, Graphics::Buffers buffer, Graphics::Buffers mask);
+
+ // palette
+ void animatePalette(byte *palette);
+ void setPalette(byte *palette);
+ void getBlackPalette(byte *palette);
+ void palUnk0(byte *palette);
+ void buildBWPalette(byte *palette);
+ void quickFadePalette(byte *palette);
+ void fadePalette(byte *palette);
+
+ // init
+ Graphics(Parallaction* vm);
+ virtual ~Graphics();
+
+ void setMousePointer(int16 index);
+
+
+public:
+ static Point _labelPosition[2];
+ static bool _proportionalFont;
+ static Cnv _font;
+
+protected:
+ Parallaction* _vm;
+
+ static byte * _buffers[NUM_BUFFERS];
+
+ static byte _mouseArrow[256];
+ static StaticCnv _mouseComposedArrow;
+
+protected:
+ //
+ // decompress a graphics block (size is *target* size)
+ //
+ // returns amount of byte read
+ //
+ uint16 decompressChunk(byte *src, byte *dst, uint16 size);
+
+ //
+ // maps a character for representation
+ //
+ char mapChar(char c);
+
+ void flatBlit(uint16 w, uint16 h, int16 x, int16 y, byte *data, Graphics::Buffers buffer);
+ void blit(uint16 w, uint16 h, int16 x, int16 y, uint16 z, byte *data, Graphics::Buffers buffer, Graphics::Buffers mask);
+
+
+ void initBuffers();
+ void initMouse(uint16 arg_0);
+
+
+};
+
+
+} // Parallaction
+
+
+#endif
+
diff --git a/engines/parallaction/intro.cpp b/engines/parallaction/intro.cpp
new file mode 100644
index 0000000000..06b02b48f9
--- /dev/null
+++ b/engines/parallaction/intro.cpp
@@ -0,0 +1,334 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * 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 "parallaction/parallaction.h"
+#include "parallaction/menu.h"
+#include "parallaction/music.h"
+#include "parallaction/graphics.h"
+#include "parallaction/zone.h"
+
+namespace Parallaction {
+
+static Animation *_rightHandAnim;
+
+static uint16 _rightHandPositions[684] = {
+ 0x0064, 0x0046, 0x006c, 0x0046, 0x0074, 0x0046, 0x007c, 0x0046,
+ 0x0084, 0x0046, 0x008c, 0x0046, 0x0094, 0x0046, 0x009c, 0x0046,
+ 0x00a4, 0x0046, 0x00ac, 0x0046, 0x00b4, 0x0046, 0x00bc, 0x0046,
+ 0x00c4, 0x0046, 0x00cc, 0x0046, 0x00d4, 0x0046, 0x00dc, 0x0046,
+ 0x00e4, 0x0046, 0x00ec, 0x0046, 0x00f4, 0x0046, 0x00fc, 0x0046,
+ 0x0104, 0x0046, 0x00ff, 0x0042, 0x00ff, 0x004a, 0x00ff, 0x0052,
+ 0x00ff, 0x005a, 0x00ff, 0x0062, 0x00ff, 0x006a, 0x00ff, 0x0072,
+ 0x00ff, 0x007a, 0x00ff, 0x0082, 0x00ff, 0x008a, 0x00ff, 0x0092,
+ 0x00ff, 0x009a, 0x00ff, 0x00a2, 0x0104, 0x0097, 0x00fc, 0x0097,
+ 0x00f4, 0x0097, 0x00ec, 0x0097, 0x00e4, 0x0097, 0x00dc, 0x0097,
+ 0x00d4, 0x0097, 0x00cc, 0x0097, 0x00c4, 0x0097, 0x00bc, 0x0097,
+ 0x00b4, 0x0097, 0x00ac, 0x0097, 0x00a4, 0x0097, 0x009c, 0x0097,
+ 0x0094, 0x0097, 0x008c, 0x0097, 0x0084, 0x0097, 0x007c, 0x0097,
+ 0x0074, 0x0097, 0x006c, 0x0097, 0x0064, 0x0097, 0x0066, 0x0042,
+ 0x0066, 0x004a, 0x0066, 0x0052, 0x0066, 0x005a, 0x0066, 0x0062,
+ 0x0066, 0x006a, 0x0066, 0x0072, 0x0066, 0x007a, 0x0066, 0x0082,
+ 0x0066, 0x008a, 0x0066, 0x0092, 0x0066, 0x009a, 0x0066, 0x00a2,
+ 0x008c, 0x0091, 0x0099, 0x0042, 0x0099, 0x004a, 0x0099, 0x0052,
+ 0x0099, 0x005a, 0x0099, 0x0062, 0x0099, 0x006a, 0x0099, 0x0072,
+ 0x0099, 0x007a, 0x0099, 0x0082, 0x0099, 0x008a, 0x0099, 0x0092,
+ 0x0099, 0x009a, 0x0099, 0x00a2, 0x00a0, 0x004d, 0x00cc, 0x0042,
+ 0x00cc, 0x004a, 0x00cc, 0x0052, 0x00cc, 0x005a, 0x00cc, 0x0062,
+ 0x00cc, 0x006a, 0x00cc, 0x0072, 0x00cc, 0x007a, 0x00cc, 0x0082,
+ 0x00cc, 0x008a, 0x00cc, 0x0092, 0x00cc, 0x009a, 0x00cc, 0x00a2,
+ 0x00ca, 0x0050, 0x00b1, 0x0050, 0x0081, 0x0052, 0x007e, 0x0052,
+ 0x007c, 0x0055, 0x007c, 0x005c, 0x007e, 0x005e, 0x0080, 0x005e,
+ 0x0082, 0x005c, 0x0082, 0x0054, 0x0080, 0x0052, 0x0078, 0x0052,
+ 0x007c, 0x005e, 0x0077, 0x0061, 0x0074, 0x006e, 0x0074, 0x0078,
+ 0x0076, 0x007a, 0x0079, 0x0078, 0x0079, 0x0070, 0x0078, 0x0070,
+ 0x0078, 0x006b, 0x007b, 0x0066, 0x007a, 0x006f, 0x0084, 0x006f,
+ 0x0085, 0x0066, 0x0086, 0x0070, 0x0085, 0x0070, 0x0085, 0x0079,
+ 0x0088, 0x0079, 0x008a, 0x0078, 0x008a, 0x006c, 0x0087, 0x0061,
+ 0x0085, 0x005f, 0x0082, 0x005f, 0x0080, 0x0061, 0x007e, 0x0061,
+ 0x007b, 0x005f, 0x007c, 0x006f, 0x007c, 0x0071, 0x0079, 0x0074,
+ 0x0079, 0x0089, 0x0076, 0x008c, 0x0076, 0x008e, 0x007a, 0x008e,
+ 0x007f, 0x0089, 0x007f, 0x0083, 0x007e, 0x0083, 0x007e, 0x0077,
+ 0x0080, 0x0077, 0x0080, 0x0083, 0x0080, 0x008b, 0x0084, 0x0090,
+ 0x0088, 0x0090, 0x0088, 0x008e, 0x0085, 0x008b, 0x0085, 0x0074,
+ 0x0082, 0x0071, 0x00b2, 0x0052, 0x00b0, 0x0054, 0x00b0, 0x0056,
+ 0x00ae, 0x0058, 0x00af, 0x0059, 0x00af, 0x005e, 0x00b2, 0x0061,
+ 0x00b5, 0x0061, 0x00b8, 0x005e, 0x00b8, 0x005a, 0x00b9, 0x0059,
+ 0x00b9, 0x0058, 0x00b7, 0x0056, 0x00b7, 0x0054, 0x00b5, 0x0052,
+ 0x00b2, 0x0052, 0x00ae, 0x005a, 0x00ab, 0x005b, 0x00ab, 0x006d,
+ 0x00ae, 0x0072, 0x00b8, 0x0072, 0x00bc, 0x006d, 0x00bc, 0x005b,
+ 0x00b9, 0x005a, 0x00bc, 0x005c, 0x00be, 0x005c, 0x00c1, 0x005f,
+ 0x00c4, 0x0067, 0x00c4, 0x006d, 0x00c1, 0x0076, 0x00c0, 0x0077,
+ 0x00bd, 0x0077, 0x00bb, 0x0075, 0x00bd, 0x0073, 0x00bb, 0x0072,
+ 0x00be, 0x0070, 0x00be, 0x006a, 0x00a9, 0x006a, 0x00a9, 0x0070,
+ 0x00ac, 0x0072, 0x00aa, 0x0073, 0x00ac, 0x0075, 0x00aa, 0x0077,
+ 0x00a7, 0x0077, 0x00a3, 0x006d, 0x00a3, 0x0067, 0x00a6, 0x005f,
+ 0x00a9, 0x005c, 0x00ab, 0x005c, 0x00ac, 0x0077, 0x00ac, 0x007c,
+ 0x00ab, 0x007c, 0x00ab, 0x0084, 0x00ac, 0x0084, 0x00ac, 0x008b,
+ 0x00a9, 0x008e, 0x00a9, 0x0090, 0x00ae, 0x0090, 0x00ae, 0x008d,
+ 0x00b2, 0x008c, 0x00b2, 0x0087, 0x00b1, 0x0086, 0x00b1, 0x007b,
+ 0x00b2, 0x0079, 0x00b4, 0x0079, 0x00b4, 0x007d, 0x00b5, 0x007d,
+ 0x00b5, 0x0087, 0x00b4, 0x0087, 0x00b4, 0x008c, 0x00b6, 0x008c,
+ 0x00b9, 0x0091, 0x00b4, 0x0091, 0x00bd, 0x008f, 0x00ba, 0x008c,
+ 0x00ba, 0x0083, 0x00bb, 0x0082, 0x00bb, 0x0075, 0x00cc, 0x006e,
+ 0x00d4, 0x006c, 0x00db, 0x0069, 0x00d9, 0x0068, 0x00d9, 0x0064,
+ 0x00dc, 0x0064, 0x00dc, 0x0060, 0x00df, 0x0056, 0x00e5, 0x0052,
+ 0x00e7, 0x0052, 0x00ec, 0x0056, 0x00ef, 0x005d, 0x00f1, 0x0065,
+ 0x00f3, 0x0064, 0x00f3, 0x0069, 0x00f0, 0x0069, 0x00ec, 0x0065,
+ 0x00ec, 0x005e, 0x00e9, 0x005f, 0x00e9, 0x005a, 0x00e7, 0x0058,
+ 0x00e4, 0x0058, 0x00e3, 0x0054, 0x00e3, 0x0058, 0x00e1, 0x005c,
+ 0x00e4, 0x0061, 0x00e7, 0x0061, 0x00e9, 0x005f, 0x00eb, 0x005d,
+ 0x00e4, 0x0062, 0x00e0, 0x0064, 0x00e0, 0x0069, 0x00e2, 0x006b,
+ 0x00e0, 0x0072, 0x00e0, 0x0077, 0x00ec, 0x0077, 0x00ec, 0x0071,
+ 0x00ea, 0x006b, 0x00ec, 0x006a, 0x00ec, 0x0063, 0x00e7, 0x0063,
+ 0x00e7, 0x0065, 0x00e1, 0x0069, 0x00e3, 0x0068, 0x00e6, 0x0069,
+ 0x00ec, 0x005e, 0x00ea, 0x006b, 0x00e7, 0x006b, 0x00e7, 0x006a,
+ 0x00e5, 0x006a, 0x00e5, 0x006b, 0x00e2, 0x006b, 0x00df, 0x006c,
+ 0x00dc, 0x006f, 0x00dc, 0x0071, 0x00da, 0x0073, 0x00d8, 0x0073,
+ 0x00d8, 0x006f, 0x00dc, 0x006b, 0x00dc, 0x0069, 0x00dd, 0x0068,
+ 0x00ef, 0x0068, 0x00f0, 0x0069, 0x00f0, 0x006b, 0x00f4, 0x006f,
+ 0x00f4, 0x0072, 0x00f3, 0x0073, 0x00f2, 0x0073, 0x00f0, 0x0071,
+ 0x00f0, 0x006f, 0x00ec, 0x006b, 0x00ec, 0x007a, 0x00eb, 0x007b,
+ 0x00eb, 0x007f, 0x00ec, 0x0080, 0x00ec, 0x0084, 0x00eb, 0x0085,
+ 0x00eb, 0x008b, 0x00ec, 0x008c, 0x00ec, 0x008f, 0x00ed, 0x0091,
+ 0x00e9, 0x0091, 0x00e9, 0x008f, 0x00e7, 0x008d, 0x00e7, 0x0090,
+ 0x00e7, 0x0089, 0x00e8, 0x0088, 0x00e8, 0x0086, 0x00e7, 0x0085,
+ 0x00e7, 0x007d, 0x00e6, 0x007c, 0x00e6, 0x0078, 0x00e5, 0x007d,
+ 0x00e5, 0x0085, 0x00e4, 0x0086, 0x00e4, 0x0088, 0x00e5, 0x0089,
+ 0x00e5, 0x0090, 0x00e5, 0x008b, 0x00e3, 0x0091, 0x00df, 0x0091,
+ 0x00e0, 0x0090, 0x00e0, 0x008c, 0x00e2, 0x008b, 0x00e1, 0x0085,
+ 0x00e0, 0x0084, 0x00e0, 0x0080, 0x00e1, 0x007f, 0x00e1, 0x007c,
+ 0x00e0, 0x007b, 0x00e0, 0x0077
+};
+
+extern Credit _credits[];
+
+
+void _c_startIntro(void *parm) {
+ _rightHandAnim = findAnimation("righthand");
+ stopMusic();
+ loadMusic("intro");
+ playMusic();
+ _engineFlags |= kEngineMouse;
+
+ return;
+}
+
+void _c_endIntro(void *parm) {
+
+ _vm->_graphics->loadExternalCnv("slidecnv", &_vm->_graphics->_font);
+ _vm->_graphics->_proportionalFont = false;
+
+ uint16 _di;
+ for (uint16 _si = 0; _si < 7; _si++) {
+ _di = _vm->_graphics->getStringWidth(_credits[_si]._role);
+ _vm->_graphics->displayString((SCREEN_WIDTH - _di)/2, 80, _credits[_si]._role);
+
+ _di = _vm->_graphics->getStringWidth(_credits[_si]._name);
+ _vm->_graphics->displayString((SCREEN_WIDTH - _di)/2, 100, _credits[_si]._name);
+
+ for (uint16 v2 = 0; v2 < 100; v2++) {
+ _vm->updateInput();
+ if (_mouseButtons != kMouseLeftUp)
+ _vm->waitTime( 1 );
+ }
+
+ _vm->_graphics->copyScreen(Graphics::kBitBack, Graphics::kBitFront);
+ }
+
+ waitUntilLeftClick();
+ _vm->_graphics->freeCnv(&Graphics::_font);
+
+ _engineFlags &= ~kEngineMouse;
+ _vm->_menu->selectCharacter();
+
+ return;
+}
+
+void _c_moveSheet(void *parm) {
+
+ static uint16 x = 319;
+
+ if (x > 66)
+ x -= 16;
+
+ uint16 _ax = (x + 32 > 319) ? 319 : (x + 32);
+ _vm->_graphics->floodFill(1, x, 47, _ax, 199, Graphics::kBitBack);
+ _vm->_graphics->floodFill(1, x, 47, _ax, 199, Graphics::kBit2);
+
+ if (x >= 104) return;
+
+ _ax = (x + 247 > 319) ? 319 : (x + 247);
+ _vm->_graphics->floodFill(12, x+215, 47, _ax, 199, Graphics::kBitBack);
+ _vm->_graphics->floodFill(12, x+215, 47, _ax, 199, Graphics::kBit2);
+
+ return;
+}
+
+
+void introFunc1(uint16 oldX, uint16 oldY, uint16 newX, uint16 newY, Graphics::Buffers mask) {
+
+ uint16 unused = 0;
+ int16 dx = newX - oldX;
+ int16 dy = newY - oldY;
+
+ _vm->_graphics->maskOpNot(oldX, oldY, unused, mask);
+ _vm->_graphics->maskOpNot(newX, newY, unused, mask);
+
+ if (abs(dx) >= abs(dy)) {
+
+ int16 v4 = abs(dy);
+ if (dx >= 0 && dy >= 0) {
+ for (uint16 i = 1; i < dx; i++) {
+ v4 += dy;
+ if (abs(dx) < v4) {
+ oldY++;
+ v4 -= dx;
+ }
+ _vm->_graphics->maskOpNot(i + oldX, oldY, unused, mask);
+ }
+ }
+
+ if (dx < 0 && dy >= 0) {
+ for (uint16 i = 1; i > abs(dx); i++) {
+ v4 += dy;
+ if (abs(dx) < v4) {
+ oldY++;
+ v4 -= abs(dx);
+ }
+ _vm->_graphics->maskOpNot(oldX - i, oldY, unused, mask);
+ }
+ }
+
+ if (dx < 0 && dy < 0) {
+ for (uint16 i = 1; i > abs(dx); i++) {
+ v4 += dy;
+ if (abs(v4) > abs(dx)) {
+ oldY--;
+ v4 -= abs(dx);
+ }
+ _vm->_graphics->maskOpNot(oldX - i, oldY, unused, mask);
+ }
+ }
+
+ if (dx >= 0 && dy < 0) {
+ for (uint16 i = 1; i < dx; i++) {
+ v4 -= dy;
+ if (v4 > dx) {
+ oldY--;
+ v4 -= dx;
+ }
+ _vm->_graphics->maskOpNot(i + oldX, oldY, unused, mask);
+ }
+ }
+
+ }
+
+ if (abs(dy) < abs(dx)) {
+
+ int16 v4 = abs(dx);
+
+ if (dx >= 0 && dy >= 0) {
+ for (uint16 i = 1; i < dy; i++) {
+ v4 += dx;
+ if (v4 > dy) {
+ oldX++;
+ v4 -= dy;
+ }
+ _vm->_graphics->maskOpNot(oldX, i + oldY, unused, mask);
+ }
+ }
+
+ if (dx < 0 && dy >= 0) {
+ for (uint16 i = 1; i < dy; i++) {
+ v4 -= dx;
+ if (v4 > dy) {
+ oldX--;
+ v4 -= dy;
+ }
+ _vm->_graphics->maskOpNot(oldX, i + oldY, unused, mask);
+ }
+ }
+
+ if (dx < 0 && dy < 0) {
+ for (uint16 i = 1; i < abs(dy); i++) {
+ v4 -= abs(dx);
+ if (v4 > abs(dy)) {
+ oldX--;
+ v4 -= abs(dy);
+ }
+ _vm->_graphics->maskOpNot(oldX, oldY - i, unused, mask);
+ }
+ }
+
+ if (dx >= 0 && dy < 0) {
+ for (uint16 i = 1; i < abs(dy); i++) {
+ v4 += abs(dx);
+ if (v4 > abs(dy)) {
+ oldX++;
+ v4 -= abs(dy);
+ }
+ _vm->_graphics->maskOpNot(oldX, oldY - i, unused, mask);
+ }
+ }
+
+ }
+
+
+ return;
+}
+
+
+void _c_sketch(void *parm) {
+
+ static uint16 index = 1;
+
+ uint16 _4 = _rightHandPositions[2*index+1];
+ uint16 _3 = _rightHandPositions[2*index];
+ uint16 _2 = _rightHandPositions[2*(index-1)+1];
+ uint16 _1 = _rightHandPositions[2*(index-1)];
+
+ introFunc1(_1, _2, _3, _4, Graphics::kMask0 );
+
+ _rightHandAnim->_zone.pos._position._x = _rightHandPositions[index*2];
+ _rightHandAnim->_zone.pos._position._y = _rightHandPositions[index*2+1] - 20;
+
+ index++;
+
+ return;
+}
+
+
+
+
+void _c_shade(void *parm) {
+
+ _vm->_graphics->maskClearRectangle(_rightHandAnim->_zone.pos._position._x - 36,
+ _rightHandAnim->_zone.pos._position._y - 36,
+ _rightHandAnim->_zone.pos._position._x,
+ _rightHandAnim->_zone.pos._position._y,
+ Graphics::kMask0 );
+
+ return;
+
+}
+
+} // namespace Parallaction
diff --git a/engines/parallaction/inventory.cpp b/engines/parallaction/inventory.cpp
new file mode 100644
index 0000000000..89218f9a88
--- /dev/null
+++ b/engines/parallaction/inventory.cpp
@@ -0,0 +1,401 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * 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 "parallaction/parallaction.h"
+#include "parallaction/zone.h"
+#include "parallaction/graphics.h"
+#include "parallaction/inventory.h"
+
+
+namespace Parallaction {
+
+//
+// inventory is kept in Graphics::kBit3 at 0 offset
+// it is a grid made of (at most) 30 cells, 24x24 pixels each,
+// arranged in 6 lines
+//
+// inventory items are stored in cnv files in a 32x24 grid
+// but only 24x24 pixels are actually copied to graphic memory
+//
+
+#define INVENTORY_MAX_ITEMS 30
+
+#define INVENTORYITEM_PITCH 32
+#define INVENTORYITEM_WIDTH 24
+#define INVENTORYITEM_HEIGHT 24
+
+#define INVENTORY_ITEMS_PER_LINE 5
+#define INVENTORY_LINES 6
+
+#define INVENTORY_WIDTH (INVENTORY_ITEMS_PER_LINE*INVENTORYITEM_WIDTH)
+#define INVENTORY_HEIGHT (INVENTORY_LINES*INVENTORYITEM_HEIGHT)
+
+Cnv _characterInventory;
+uint16 _numInvLines = 0;
+static Point _invPosition = { 0, 0 };
+
+InventoryItem _inventory[INVENTORY_MAX_ITEMS] = {
+ { kZoneDoor, 1 }, // open/close icon
+ { kZoneExamine, 3 }, // examine icon
+ { kZoneGet, 2 }, // pick up/use icon
+ { kZoneSpeak, 4 }, // speak icon
+ { 0, 0 }, // items...
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 },
+ { 0, 0 }
+};
+
+void drawInventoryItem(uint16 pos, InventoryItem *item);
+
+
+// get inventory item index at position (x,y)
+// in screen coordinates
+//
+int16 Parallaction::getHoverInventoryItem(int16 x, int16 y) {
+
+ int16 _di = x;
+
+ int16 _si = -1;
+ do {
+ _si++;
+ } while (_inventory[_si]._id != 0);
+
+ _si = (_si + 4) / INVENTORY_ITEMS_PER_LINE;
+
+ if (_invPosition._x >= _di) return -1;
+ if ((_invPosition._x + INVENTORY_WIDTH) <= _di) return -1;
+
+ if (_invPosition._y >= y) return -1;
+ if ((_si * INVENTORYITEM_HEIGHT + _invPosition._y) <= y) return -1;
+
+ return ((_di - _invPosition._x) / INVENTORYITEM_WIDTH) + (INVENTORY_ITEMS_PER_LINE * ((y - _invPosition._y) / INVENTORYITEM_HEIGHT));
+
+}
+
+
+int16 pickupItem(Zone *z) {
+
+ uint16 _si;
+ for (_si = 0; _inventory[_si]._id != 0; _si++) ;
+ if (_si == INVENTORY_MAX_ITEMS) return -1;
+
+ _inventory[_si]._id = (z->u.get->_icon << 16) & 0xFFFF0000;
+ _inventory[_si]._index = z->u.get->_icon;
+
+ addJob(jobRemovePickedItem, z, JOBPRIORITY_ADDREMOVEITEMS);
+
+ if (_inventory[_si]._id == 0) return 0;
+
+ refreshInventoryItem(_vm->_characterName, _si);
+
+ return 0;
+}
+
+
+void addInventoryItem(uint16 item) {
+
+ uint16 _si = 0;
+ while (_inventory[_si]._id != 0) _si++;
+
+ _inventory[_si]._id = (item << 16) & 0xFFFF0000;
+ _inventory[_si]._index = item;
+
+ refreshInventoryItem(_vm->_characterName, _si);
+
+ return;
+}
+
+
+void dropItem(uint16 v) {
+
+ uint16 _di = 0;
+ for (uint16 _si = 0; _si < INVENTORY_MAX_ITEMS; _si++) {
+
+ if (v + 4 == _inventory[_si]._index) {
+ _di = 1;
+ }
+
+ if (_di == 0) continue;
+
+ memcpy(&_inventory[_si], &_inventory[_si+1], sizeof(InventoryItem));
+ }
+
+ refreshInventory(_vm->_characterName);
+
+ return;
+}
+
+
+int16 isItemInInventory(int32 v) {
+
+ for (uint16 _si = 0; _si < INVENTORY_MAX_ITEMS; _si++) {
+ if (_inventory[_si]._id == (uint)v)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+
+void drawInventoryItem(uint16 pos, InventoryItem *item) {
+
+ uint16 line = pos / INVENTORY_ITEMS_PER_LINE;
+ uint16 col = pos % INVENTORY_ITEMS_PER_LINE;
+
+ _vm->_graphics->copyRect(
+ Graphics::kBit3,
+ col * INVENTORYITEM_WIDTH,
+ line * _characterInventory._height,
+ INVENTORYITEM_WIDTH,
+ _characterInventory._height,
+ _characterInventory._array[item->_index],
+ INVENTORYITEM_PITCH
+ );
+
+ return;
+}
+
+
+//
+// draws a color border around the specified position in the inventory
+//
+void highlightInventoryItem(int16 pos, byte color) {
+
+ if (color != 12) color = 19;
+
+ if (pos == -1) return;
+
+ uint16 line = pos / INVENTORY_ITEMS_PER_LINE;
+ uint16 col = pos % INVENTORY_ITEMS_PER_LINE;
+
+ _vm->_graphics->drawBorder(
+ Graphics::kBit3,
+ col * INVENTORYITEM_WIDTH,
+ line * _characterInventory._height,
+ INVENTORYITEM_WIDTH,
+ _characterInventory._height,
+ color
+ );
+
+ return;
+}
+
+
+
+
+void extractInventoryGraphics(int16 pos, byte *dst) {
+// printf("extractInventoryGraphics(%i)\n", pos);
+
+ int16 line = pos / INVENTORY_ITEMS_PER_LINE;
+ int16 col = pos % INVENTORY_ITEMS_PER_LINE;
+
+ _vm->_graphics->grabRect(
+ Graphics::kBit3,
+ dst,
+ col * INVENTORYITEM_WIDTH,
+ line * _characterInventory._height,
+ INVENTORYITEM_WIDTH,
+ _characterInventory._height,
+ INVENTORYITEM_PITCH
+ );
+
+ return;
+}
+
+void jobShowInventory(void *parm, Job *j) {
+// printf("job_showInventory()...");
+
+ _numInvLines = 0;
+
+ while (_inventory[_numInvLines]._id != 0) _numInvLines++;
+
+ _numInvLines = (_numInvLines + 4) / INVENTORY_ITEMS_PER_LINE;
+
+ _vm->_graphics->copyRect(
+ Graphics::kBit3,
+ 0,
+ 0,
+ Graphics::kBitBack,
+ _invPosition._x,
+ _invPosition._y,
+ INVENTORY_WIDTH,
+ _numInvLines * INVENTORYITEM_HEIGHT
+ );
+
+
+// printf("done\n");
+
+ return;
+}
+
+
+
+void jobHideInventory(void *parm, Job *j) {
+// printf("job_hideInventory()\n");
+
+ static uint16 count = 0;
+
+ _engineFlags |= kEngineMouse;
+
+ count++;
+ if (count == 2) {
+ count = 0;
+ j->_finished = 1;
+ _engineFlags &= ~kEngineMouse;
+ }
+
+ _vm->_graphics->copyRect(
+ Graphics::kBit2,
+ _invPosition._x,
+ _invPosition._y,
+ Graphics::kBitBack,
+ _invPosition._x,
+ _invPosition._y,
+ INVENTORY_WIDTH,
+ _numInvLines * INVENTORYITEM_HEIGHT
+ );
+
+ return;
+}
+
+
+
+void openInventory() {
+// printf("openInventory()\n");
+
+ uint16 _si = 0;
+ _engineFlags |= kEngineInventory;
+
+ while (_inventory[_si]._id != 0) _si++;
+
+ uint16 _LOCALinventory_lines = (_si + 4) / INVENTORY_ITEMS_PER_LINE;
+
+ _invPosition._x = _mousePos._x - (INVENTORY_WIDTH / 2);
+ if (_invPosition._x < 0)
+ _invPosition._x = 0;
+
+ if ((_invPosition._x + INVENTORY_WIDTH) > SCREEN_WIDTH)
+ _invPosition._x = SCREEN_WIDTH - INVENTORY_WIDTH;
+
+ _invPosition._y = _mousePos._y - 2 - (_LOCALinventory_lines * INVENTORYITEM_HEIGHT);
+ if (_invPosition._y < 0)
+ _invPosition._y = 0;
+
+ if (_invPosition._y > SCREEN_HEIGHT - _LOCALinventory_lines * INVENTORYITEM_HEIGHT)
+ _invPosition._y = SCREEN_HEIGHT - _LOCALinventory_lines * INVENTORYITEM_HEIGHT;
+
+ return;
+
+}
+
+
+
+void closeInventory() {
+// printf("closeInventory()\n");
+
+ _engineFlags &= ~kEngineInventory;
+}
+
+
+
+// refreshes inventory view
+//
+void redrawInventory() {
+
+
+ for (uint16 _si = 0; _si < INVENTORY_MAX_ITEMS; _si++) {
+ drawInventoryItem(_si, &_inventory[_si]);
+ }
+
+}
+
+void initInventory() {
+ _characterInventory._count = 0;
+}
+
+void cleanInventory() {
+
+ for (uint16 _si = 4; _si < 30; _si++) {
+ _inventory[_si]._id = 0;
+ _inventory[_si]._index = 0;
+ }
+
+ return;
+}
+
+
+// loads character's icons set
+
+void loadCharacterItems(const char *character) {
+
+ if (!scumm_strnicmp("mini", character, 4)) character += 4;
+
+ char filename[PATH_LEN];
+ sprintf(filename, "%sobj", character);
+
+ _vm->_graphics->loadExternalCnv(filename, &_characterInventory);
+
+ return;
+}
+
+void refreshInventory(const char *character) {
+ loadCharacterItems(character);
+ redrawInventory();
+ _vm->_graphics->freeCnv(&_characterInventory);
+
+ return;
+}
+
+
+void refreshInventoryItem(const char *character, uint16 index) {
+ loadCharacterItems(character);
+ drawInventoryItem(index, &_inventory[index]);
+ _vm->_graphics->freeCnv(&_characterInventory);
+
+ return;
+}
+
+} // namespace Parallaction
diff --git a/engines/parallaction/inventory.h b/engines/parallaction/inventory.h
new file mode 100644
index 0000000000..d08fa52813
--- /dev/null
+++ b/engines/parallaction/inventory.h
@@ -0,0 +1,56 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * 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_INVENTORY_H
+#define PARALLACTION_INVENTORY_H
+
+
+
+namespace Parallaction {
+
+struct Cnv;
+
+struct InventoryItem {
+ uint32 _id;
+ uint16 _index;
+};
+
+extern InventoryItem _inventory[];
+
+void initInventory();
+void openInventory();
+void closeInventory();
+int16 isItemInInventory(int32 v);
+void cleanInventory();
+void addInventoryItem(uint16 item);
+
+void redrawInventory();
+void highlightInventoryItem(int16 pos, byte color);
+void refreshInventoryItem(const char *character, uint16 index);
+void refreshInventory(const char *character);
+
+void extractInventoryGraphics(int16 pos, byte *dst);
+
+
+} // namespace Parallaction
+
+#endif
diff --git a/engines/parallaction/loadsave.cpp b/engines/parallaction/loadsave.cpp
new file mode 100644
index 0000000000..2cfa7c388e
--- /dev/null
+++ b/engines/parallaction/loadsave.cpp
@@ -0,0 +1,531 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * 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 "parallaction/parallaction.h"
+#include "parallaction/disk.h"
+#include "parallaction/inventory.h"
+#include "parallaction/graphics.h"
+#include "parallaction/zone.h"
+
+#include "common/savefile.h"
+
+namespace Parallaction {
+
+
+extern char _gameNames[][20];
+
+void Parallaction::doLoadGame(uint16 _di) {
+
+ _introSarcData3 = 200;
+ _introSarcData2 = 1;
+
+ char filename[PATH_LEN];
+ sprintf(filename, "game.%d", _di);
+
+ Common::InSaveFile *f = _saveFileMan->openForLoading(filename);
+ if (!f) return;
+
+ f->readLine(_vm->_characterName, 15);
+ f->readLine(_location, 15);
+
+ strcat(_location, ".");
+
+ char s[20];
+ f->readLine(s, 15);
+ _firstPosition._x = atoi(s);
+
+ f->readLine(s, 15);
+ _firstPosition._y = atoi(s);
+
+ f->readLine(s, 15);
+ _score = atoi(s);
+
+ f->readLine(s, 15);
+ _commandFlags = atoi(s);
+
+ f->readLine(s, 15);
+
+ _engineFlags |= kEngineQuit;
+ freeZones(_zones._next);
+ freeNodeList(_zones._next);
+ _zones._next = NULL;
+ _engineFlags &= ~kEngineQuit;
+
+ _numLocations = atoi(s);
+
+ uint16 _si;
+ for (_si = 0; _si < _numLocations; _si++) {
+ f->readLine(s, 20);
+ s[strlen(s)] = '\0';
+
+ strcpy(_locationNames[_si], s);
+
+ f->readLine(s, 15);
+ _localFlags[_si] = atoi(s);
+ }
+ _locationNames[_si][0] = '\0';
+
+ for (_si = 0; _si < 30; _si++) {
+ f->readLine(s, 15);
+ _inventory[_si]._id = atoi(s);
+
+ f->readLine(s, 15);
+ _inventory[_si]._index = atoi(s);
+ }
+
+ delete f;
+
+ _engineFlags &= ~kEngineMiniDonna;
+ if (!scumm_stricmp(_vm->_characterName, "donnatras")) {
+ _engineFlags |= kEngineMiniDonna;
+ strcpy(_vm->_characterName, "donna");
+ }
+ if (!scumm_stricmp(_vm->_characterName, "minidonnatras")) {
+ _engineFlags |= kEngineMiniDonna;
+ strcpy(_vm->_characterName, "minidonna");
+ }
+
+ if (_vm->_characterName[0] == 'm') {
+ strcpy(filename, _vm->_characterName+4);
+ } else {
+ strcpy(filename, _vm->_characterName);
+ }
+ strcat(filename, ".tab");
+ freeTable(_objectsNames);
+ initTable(filename, _objectsNames);
+
+ refreshInventory(_vm->_characterName);
+
+ parseLocation("common");
+ closeArchive();
+
+ strcat(_location, _vm->_characterName);
+ _engineFlags |= kEngineChangeLocation;
+
+ printf("game loaded: character %s, location %s\n", _vm->_characterName, _location);
+// getch();
+
+ return;
+}
+
+
+
+
+// FIXME: implements this (select a file slot for load/save)
+int16 selectSaveFile(uint16 arg_0) {
+ return 0;
+}
+
+
+
+void Parallaction::loadGame() {
+
+ bool marks[10];
+ _saveFileMan->listSavefiles("game.", marks, 10);
+
+ int16 _di = selectSaveFile( 0 );
+ if (_di > 10) return;
+
+ doLoadGame(_di);
+
+ return;
+}
+
+void Parallaction::doSaveGame(uint16 _di) {
+
+ char path[PATH_LEN];
+ sprintf(path, "game.%d", _di);
+
+ Common::OutSaveFile *f = _saveFileMan->openForSaving(path);
+
+ char s[30];
+
+ if (_engineFlags & kEngineMiniDonna) {
+ sprintf(s, "%stras\n", _vm->_characterName);
+ } else {
+ sprintf(s, "%s\n", _vm->_characterName);
+ }
+ f->writeString(s);
+
+ sprintf(s, "%s\n", _saveData1);
+ f->writeString(s);
+ sprintf(s, "%d\n", _yourself._zone.pos._position._x);
+ f->writeString(s);
+ sprintf(s, "%d\n", _yourself._zone.pos._position._y);
+ f->writeString(s);
+ sprintf(s, "%d\n", _score);
+ f->writeString(s);
+ sprintf(s, "%uld\n", _commandFlags);
+ f->writeString(s);
+
+ sprintf(s, "%d\n", _numLocations);
+ f->writeString(s);
+ for (uint16 _si = 0; _si < _numLocations; _si++) {
+ sprintf(s, "%s\n%uld\n", _locationNames[_si], _localFlags[_si]);
+ f->writeString(s);
+ }
+
+ for (uint16 _si = 0; _si < 30; _si++) {
+ sprintf(s, "%uld\n%d\n", _inventory[_si]._id, _inventory[_si]._index);
+ f->writeString(s);
+ }
+
+ delete f;
+
+ refreshInventory(_vm->_characterName);
+
+ return;
+
+
+}
+
+// FIXME: only to be implemented for text mode selection
+void textModeFunc1( char *) {
+
+}
+
+
+
+void Parallaction::saveGame() {
+
+// strcpy(v30, asc_1C91A);
+
+ if (!scumm_stricmp(_location, "caveau")) return;
+
+ bool marks[10];
+ _saveFileMan->listSavefiles("game.", marks, 10);
+
+ int16 _di = selectSaveFile( 1 );
+ if (_di > 10) return;
+
+
+ printf("saving game %i...", _di);
+ doSaveGame(_di);
+ printf("done\n");
+// getch();
+
+ return;
+
+
+}
+
+#if 0
+int16 selectSaveFile(uint16 arg_0) {
+
+ REGISTERS pregs;
+ pregs._ax = (void*)(uint32)dos_videomode;
+ int86(0x10, &pregs);
+
+// window(0 ,0, 23, 79);
+ puts(" FILE NAME ");
+
+ if (arg_0 != 0) {
+ printf("(Use \x18 \x19 \x10 to edit then press enter)\n\n");
+ } else {
+ puts("\n");
+ }
+
+ uint16 _si;
+ for (_si = 0; _si < 11; _si++) {
+ printf(" %s \n", _gameNames[_si]);
+ }
+
+ int16 _di = editSaveFileName(3, 13, 0, 12, 1, arg_0);
+
+ pregs._ax = (void*)0x93;
+ int86(0x10, &pregs);
+
+ set_vga_mode_x(0);
+ byte palette[PALETTE_SIZE];
+ _vm->_graphics->getBlackPalette(palette);
+ _vm->_graphics->setPalette(palette);
+
+
+ _vm->_graphics->copyScreen(Graphics::kBit2, Graphics::kBitBack);
+ _vm->_graphics->copyScreen(Graphics::kBitBack, Graphics::kBitFront);
+
+ if (arg_0 != 0) {
+ _vm->_graphics->setPalette(_palette);
+ }
+
+ _vm->_graphics->swapBuffers();
+
+ return _si;
+}
+
+int16 editSaveFileName(uint16 arg_0, uint16 arg_2, uint16 arg_4, uint16 arg_6, uint16 arg_8, uint16 arg_A) {
+ uint16 _di = arg_0;
+ uint16 _si = _di;
+ uint16 v4 = _di;
+ uint16 v1 = 0;
+
+ do {
+
+ set_cursor(_si, arg_4);
+
+ while (v1 == 0) {
+ int16 v6 = get_kb();
+ byte _al = v6 & 0xFF;
+ if (_al == 0) {
+
+ _al = (v6 & 0xFF00) >> 8;
+ if (_al == 'H') {
+ if (_si<=_di)
+ _si = arg_2;
+ else
+ _si = _si - arg_8;
+
+ v1 = 1;
+ } else
+ if (_al == 'M') {
+
+ } else
+ if (_al == 'P') {
+ if (_si>=arg_2)
+ _si = _di;
+ else
+ _si = _si + arg_8;
+
+ v1 = 1;
+ }
+
+ if (_si != 0xD && arg_A != 0) {
+
+ set_cursor(_si, arg_4+1);
+ v1 = 1;
+ textModeFunc1( _gameNames[(_si - _di)/arg_8] );
+
+ return (_si - _di)/arg_8 + 1;
+
+ }
+
+ } else
+ if (_al == 0xD) return (_si - _di)/arg_8 + 1;
+ }
+
+ v1 = 0;
+ set_cursor(v4, arg_4);
+ v4 = _si;
+
+ } while (true);
+
+ return 0;
+
+}
+#endif
+
+#if 0
+void loadGame() {
+
+ uint16 v6 = 0;
+ uint16 v4 = 0;
+ uint16 v2 = 0;
+ uint16 _bx;
+
+ FILE* stream = fopen("savegame", "r");
+ if (stream) {
+ for (uint16 _si = 0; _si < 10; _si++) {
+ fgets(_gameNames[_si], 18, stream);
+ _bx = strlen(_gameNames[_si]) - 1;
+ _gameNames[_si][_bx] = '\0';
+ }
+ fclose(stream);
+ }
+
+ int16 _di = selectSaveFile( 0 );
+ if (_di > 10) return;
+
+ _introSarcData3 = 200;
+ _introSarcData2 = 1;
+ _moveSarcExaZones[0] = 0;
+ _moveSarcZones[0] = 0;
+
+ char filename[PATH_LEN];
+ sprintf(filename, "game.%d", _di);
+ stream = fopen(filename, "r");
+ if (!stream) return;
+
+ fgets(_vm->_characterName, 15, stream);
+ _vm->_characterName[strlen(_vm->_characterName)] = '\0';
+
+ fgets(_location, 15, stream);
+ _location[strlen(_location)] = '.';
+
+ char s[20];
+ fgets(s, 15, stream);
+ _firstPosition._x = atoi(s);
+
+ fgets(s, 15, stream);
+ _firstPosition._y = atoi(s);
+
+ fgets(s, 15, stream);
+ _score = atoi(s);
+
+ fgets(s, 15, stream);
+ _commandFlags = atoi(s);
+
+ fgets(s, 15, stream);
+
+ _engineFlags |= kEngineQuit;
+ freeZones(_zones._next);
+ freeNodeList(_zones._next);
+ _zones._next = NULL;
+ _engineFlags &= ~kEngineQuit;
+
+ _numLocations = atoi(s);
+
+ uint16 _si;
+ for (_si = 0; _si < _numLocations; _si++) {
+ fgets(s, 20, stream);
+ s[strlen(s)] = '\0';
+
+ strcpy(_locationNames[_si], s);
+
+ fgets(s, 15, stream);
+ _localFlags[_si] = atoi(s);
+ }
+ _locationNames[_si] = '\0';
+
+ for (_si = 0; _si < 30; _si++) {
+ fgets(s, 15, stream);
+ _inventory[_si]._id = atoi(s);
+
+ fgets(s, 15, stream);
+ _inventory[_si]._index = atoi(s);
+ }
+
+ fclose(stream);
+
+ _engineFlags &= ~kEngineMiniDonna;
+ if (!scumm_stricmp(_vm->_characterName, "donnatras")) {
+ _engineFlags |= kEngineMiniDonna;
+ strcpy(_vm->_characterName, "donna");
+ }
+ if (!scumm_stricmp(_vm->_characterName, "minidonnatras")) {
+ _engineFlags |= kEngineMiniDonna;
+ strcpy(_vm->_characterName, "minidonna");
+ }
+
+ if (_vm->_characterName[0] == 'm') {
+ strcpy(filename, _vm->_characterName+4);
+ } else {
+ strcpy(filename, _vm->_characterName);
+ }
+ strcat(filename, ".tab");
+ freeTable(_objectsNames);
+ initTable(filename, _objectsNames);
+
+ refreshInventory();
+
+ parseLocation("common");
+ closeArchive();
+
+ strcat(_location, _vm->_characterName);
+ _engineFlags |= kEngineChangeLocation;
+
+ return;
+}
+
+
+int16 get_kb() {
+
+ REGISTERS pregs;
+ pregs._ax = 0;
+ int86(0x16, &pregs);
+
+ return (int16)(int32)pregs._ax;
+
+}
+
+
+#endif
+
+#if 0
+void saveGame() {
+
+// strcpy(v30, asc_1C91A);
+ uint16 v8 = 0, v6 = 0;
+ int16 v4 = -1;
+ int16 v2 = 0;
+
+ if (!scumm_stricmp(_location, "caveau")) return;
+
+ FILE* stream = fopen("savegame", "r");
+ if (stream) {
+ for (uint16 _si = 0; _si < 10; _si++) {
+ fgets(_gameNames[_si], 18, stream);
+ uint16 _bx = strlen(_gameNames[_si]) - 1;
+ _gameNames[_si][_bx] = '\0';
+ }
+ fclose(stream);
+ }
+
+ int16 _di = selectSaveFile( 1 );
+ if (_di > 10) return;
+
+ stream = fopen("savegame", "w");
+ if (stream) {
+ for (uint16 _si = 0; _si < 10; _si++) {
+ fputs(_gameNames[_si], stream);
+ fputs("\n", stream);
+ }
+ fclose(stream);
+ }
+
+ char path[PATH_LEN];
+ sprintf(path, "game.%d", _di);
+ stream = fopen(path, "w");
+ if (!stream) return;
+
+ if (_engineFlags & kEngineMiniDonna) {
+ fprintf(stream, "%stras\n", _vm->_characterName);
+ } else {
+ fprintf(stream, "%s\n", _vm->_characterName);
+ }
+
+ fprintf(stream, "%s\n", _saveData1);
+ fprintf(stream, "%d\n", _yourself._zone.pos._position._x);
+ fprintf(stream, "%d\n", _yourself._zone.pos._position._y);
+ fprintf(stream, "%d\n", _score);
+ fprintf(stream, "%ld\n", _commandFlags);
+
+ fprintf(stream, "%d\n", _numLocations);
+ for (uint16 _si = 0; _si < _numLocations; _si++) {
+ fprintf(stream, "%s\n%ld\n", _locationNames[_si], _localFlags[_si]);
+ }
+
+ for (uint16 _si = 0; _si < 30; _si++) {
+ fprintf(stream, "%ld\n%d\n", _inventory[_si]._id, _inventory[_si]._index);
+ }
+
+ fclose(stream);
+
+ refreshInventory();
+
+ return;
+}
+#endif
+
+
+
+} // namespace Parallaction
diff --git a/engines/parallaction/location.cpp b/engines/parallaction/location.cpp
new file mode 100644
index 0000000000..788027a9ac
--- /dev/null
+++ b/engines/parallaction/location.cpp
@@ -0,0 +1,483 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * 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 "parallaction/parallaction.h"
+#include "parallaction/graphics.h"
+#include "parallaction/disk.h"
+#include "parallaction/parser.h"
+#include "parallaction/music.h"
+#include "parallaction/commands.h"
+#include "parallaction/zone.h"
+
+namespace Parallaction {
+
+void resolveLocationForwards();
+void loadExternalMaskPath(char *filename);
+void switchBackground(char *name);
+void parseWalkNodes(ArchivedFile *file, Node *list);
+void freeAnimations();
+
+
+void Parallaction::parseLocation(const char *filename) {
+// printf("parseLocation(%s)\n", filename);
+
+ char *location_src = NULL;
+
+ uint16 _si = 1;
+ _vm->_graphics->_proportionalFont = false;
+ _vm->_graphics->loadExternalCnv("topazcnv", &Graphics::_font);
+
+ char archivefile[PATH_LEN];
+
+ if (_characterName[0] == 'm') {
+ sprintf(archivefile, "%s%s", _characterName+4, _languageDir);
+ } else {
+ if (_characterName[0] == 'D') strcpy(archivefile, _languageDir);
+ else {
+ sprintf(archivefile, "%s%s", _characterName, _languageDir);
+ }
+ }
+ strcat(archivefile, filename);
+ strcat(archivefile, ".loc");
+
+ if (strcmp(_disk, "null")) closeArchive();
+
+ _languageDir[2] = '\0';
+ openArchive(_languageDir);
+ _languageDir[2] = '/';
+ ArchivedFile *file = openArchivedFile(archivefile);
+ if (!file) {
+ sprintf(archivefile, "%s%s.loc", _languageDir, filename);
+ file = openArchivedFile(archivefile);
+ if (!file) errorFileNotFound(filename);
+ }
+
+ uint32 count = file->_endOffset - file->_offset;
+ location_src = (char*)memAlloc(0x4000);
+
+ parseInit(location_src);
+
+ readArchivedFile(file, location_src, count);
+ closeArchivedFile(file);
+ closeArchive();
+
+ parseFillBuffers();
+ while (scumm_stricmp(_tokens[0], "ENDLOCATION")) {
+// printf("token[0] = %s\n", _tokens[0]);
+
+ if (!scumm_stricmp(_tokens[0], "LOCATION")) {
+ char *background = strchr(_tokens[1], '.');
+ if (background) {
+ background[0] = '\0';
+ background++;
+ } else
+ background = _tokens[1];
+
+ _currentLocationIndex = -1;
+ uint16 _di = 0;
+ while (_locationNames[_di][0] != '\0') {
+ if (!scumm_stricmp(_locationNames[_di], filename)) {
+ _currentLocationIndex = _di + 1;
+ }
+ _di++;
+ }
+
+ if (_currentLocationIndex == -1) {
+ strcpy(_locationNames[_numLocations], filename);
+ _numLocations++;
+ _currentLocationIndex = _numLocations;
+ _locationNames[_numLocations][0] = '\0';
+ _localFlags[_currentLocationIndex] = 0;
+ } else {
+ _localFlags[_currentLocationIndex] |= 1; // 'visited'
+ }
+
+ strcpy(_location, _tokens[1]);
+ switchBackground(background);
+
+ if (_tokens[2][0] != '\0') {
+ _yourself._zone.pos._position._x = atoi(_tokens[2]);
+ _yourself._zone.pos._position._y = atoi(_tokens[3]);
+ }
+
+ if (_tokens[4][0] != '\0') {
+ _yourself._frame = atoi(_tokens[4]);
+ }
+ }
+ if (!scumm_stricmp(_tokens[0], "DISK")) {
+ strcpy(_disk, _tokens[1]);
+ strcpy(archivefile, _disk);
+ openArchive(archivefile);
+ }
+ if (!scumm_stricmp(_tokens[0], "LOCALFLAGS")) {
+ _si = 1; // _localFlagNames[0] = 'visited'
+ while (_tokens[_si][0] != '\0') {
+ _localFlagNames[_si] = (char*)memAlloc(strlen(_tokens[_si])+1);
+ strcpy(_localFlagNames[_si], _tokens[_si]);
+ _si++;
+ }
+ _localFlagNames[_si] = 0;
+ }
+ if (!scumm_stricmp(_tokens[0], "COMMANDS")) {
+ _locationCommands = parseCommands(file);
+ }
+ if (!scumm_stricmp(_tokens[0], "ACOMMANDS")) {
+ _locationACommands = parseCommands(file);
+ }
+ if (!scumm_stricmp(_tokens[0], "FLAGS")) {
+ if ((_localFlags[_currentLocationIndex] & 1) == 0) {
+ // only for 1st visit
+ _localFlags[_currentLocationIndex] = 0;
+ _si = 1;
+
+ do {
+ byte _al = searchTable(_tokens[_si], _localFlagNames);
+ _localFlags[_currentLocationIndex] |= 1 << (_al - 1);
+
+ _si++;
+ if (scumm_stricmp(_tokens[_si], "|")) break;
+ _si++;
+ } while (true);
+ }
+ }
+ if (!scumm_stricmp(_tokens[0], "COMMENT")) {
+ _locationComment = parseComment(file);
+ }
+ if (!scumm_stricmp(_tokens[0], "ENDCOMMENT")) {
+ _locationEndComment = parseComment(file);
+ }
+ if (!scumm_stricmp(_tokens[0], "ZONE")) {
+ parseZone(file, &_zones, _tokens[1]);
+ }
+ if (!scumm_stricmp(_tokens[0], "NODES")) {
+ parseWalkNodes(file, &_locationWalkNodes);
+ }
+ if (!scumm_stricmp(_tokens[0], "ANIMATION")) {
+ parseAnimation(file, &_animations, _tokens[1]);
+ }
+ if (!scumm_stricmp(_tokens[0], "SOUND")) {
+ strcpy(_soundFile, _tokens[1]);
+ }
+ parseFillBuffers();
+ }
+
+ resolveLocationForwards();
+ _vm->_graphics->freeCnv(&Graphics::_font);
+ memFree(location_src);
+
+ return;
+}
+
+void resolveLocationForwards() {
+// printf("resolveLocationForwards()\n");
+// printf("# forwards: %i\n", _numForwards);
+
+ for (uint16 _si = 0; _forwardedCommands[_si]; _si++) {
+ _forwardedCommands[_si]->u._animation = findAnimation(_forwardedAnimationNames[_si]);
+ _forwardedCommands[_si] = NULL;
+ }
+
+ _numForwards = 0;
+ return;
+}
+
+
+void freeLocation() {
+
+ uint16 _si = 1;
+ while (_localFlagNames[_si] != 0) {
+ memFree(_localFlagNames[_si]);
+ _localFlagNames[_si] = NULL;
+ _si++;
+ }
+
+ freeNodeList(_locationWalkNodes._next);
+ _locationWalkNodes._next = NULL;
+
+ freeZones(_zones._next);
+ freeNodeList(_zones._next);
+ memset(&_zones, 0, sizeof(Node));
+
+ freeZones(_animations._next);
+ freeAnimations();
+ freeNodeList(_animations._next);
+ memset(&_animations, 0, sizeof(Node));
+
+ if (_locationComment) {
+ memFree(_locationComment);
+ }
+ _locationComment = NULL;
+
+ if (_locationCommands) {
+ freeNodeList(&_locationCommands->_node);
+ }
+ _locationCommands = NULL;
+
+
+ if (_locationACommands) {
+ freeNodeList(&_locationACommands->_node);
+ }
+ _locationACommands = NULL;
+
+ return;
+}
+
+
+
+void parseWalkNodes(ArchivedFile *file, Node *list) {
+
+ parseFillBuffers();
+ while (scumm_stricmp(_tokens[0], "ENDNODES")) {
+
+ if (!scumm_stricmp(_tokens[0], "COORD")) {
+
+ WalkNode *v4 = (WalkNode*)memAlloc(sizeof(WalkNode));
+ v4->_x = atoi(_tokens[1]) - _yourself._cnv._width/2;
+ v4->_y = atoi(_tokens[2]) - _yourself._cnv._height;
+
+ addNode(list, &v4->_node);
+
+ }
+
+ parseFillBuffers();
+ }
+
+ return;
+
+}
+
+void switchBackground(char *name) {
+// printf("switchBackground(%s)\n", name);
+
+ byte palette[PALETTE_SIZE];
+
+ uint16 v2 = 0;
+ if (!scumm_stricmp(_location, "final")) {
+ _vm->_graphics->clearScreen(Graphics::kBitBack);
+ for (uint16 _si = 0; _si <= 93; ) {
+ palette[_si] = v2;
+ palette[_si+1] = v2;
+ palette[_si+2] = v2;
+ v2 += 4;
+ _si += 3;
+ }
+
+ _vm->_graphics->palUnk0(palette);
+ }
+
+ char dest[PATH_LEN];
+ strcpy(dest, _location);
+ strcat(dest, ".dyn");
+ _vm->_graphics->loadBackground(dest, Graphics::kBitBack);
+ _vm->_graphics->copyScreen(Graphics::kBitBack, Graphics::kBit2);
+
+ if (!scumm_stricmp(_location, name)) return;
+
+ // load external masks and paths only for certain locations
+ sprintf(dest, "%s.msk", name);
+ _vm->_graphics->loadMaskAndPath(dest);
+
+ return;
+}
+
+
+
+void Parallaction::changeLocation(char *location) {
+
+// printf("changeLocation('%s')\n", location);
+ if (_musicData1 != 0) {
+ if (!scumm_stricmp(_characterName, "dino"))
+ loadMusic("dino");
+ else
+ if (!scumm_stricmp(_characterName, "donna"))
+ loadMusic("donna");
+ else
+ loadMusic("nuts");
+
+ playMusic();
+ _musicData1 = 0;
+ }
+
+ if (!scumm_stricmp(location, "night") || !scumm_stricmp(location, "intsushi")) {
+ stopMusic();
+ loadMusic("soft");
+ playMusic();
+ }
+
+ if (!scumm_stricmp(location, "museo") ||
+ !scumm_stricmp(location, "caveau") ||
+ !scumm_strnicmp(location, "plaza1", 6) ||
+ !scumm_stricmp(location, "estgrotta") ||
+ !scumm_stricmp(location, "intgrottadopo") ||
+ !scumm_stricmp(location, "endtgz") ||
+ !scumm_stricmp(location, "common")) {
+
+ stopMusic();
+ _musicData1 = 1;
+ }
+
+ if (_engineFlags & kEngineMouse) changeCursor( kCursorArrow );
+
+ strcpy(_newLocation, location);
+
+ removeNode(&_yourself._zone._node);
+ freeLocation();
+
+ char *tmp = strchr(_newLocation, '.');
+ if (tmp) {
+ *tmp = '\0';
+
+ if (!scumm_strnicmp(tmp+1, "slide", 5)) {
+ char filename[200];
+ sprintf(filename, "%s.slide", _newLocation);
+ _vm->_graphics->loadBackground(filename, Graphics::kBitBack);
+ _vm->_graphics->palUnk0(_palette);
+ _vm->_graphics->copyScreen(Graphics::kBitBack, Graphics::kBitFront);
+
+ _vm->_graphics->_proportionalFont = false;
+ _vm->_graphics->loadExternalCnv("slidecnv", &Graphics::_font);
+
+ uint16 _ax = strlen(_slideText[0]);
+ _ax <<= 3; // text width
+ uint16 _dx = (SCREEN_WIDTH - _ax) >> 1; // center text
+ _vm->_graphics->displayString(_dx, 14, _slideText[0]); // displays text on screen
+
+ _vm->_graphics->freeCnv(&Graphics::_font);
+ waitUntilLeftClick();
+
+ tmp = strchr(tmp+1, '.');
+ strcpy(_newLocation, tmp+1);
+ tmp = strchr(_newLocation, '.');
+
+ if (tmp) {
+ *tmp = '\0';
+ changeCharacter(tmp+1);
+ strcpy(_characterName, tmp+1);
+ }
+
+ } else {
+ changeCharacter(tmp+1);
+ strcpy(_characterName, tmp+1);
+ }
+ }
+
+ addNode(&_animations, &_yourself._zone._node);
+ strcpy(_saveData1, _newLocation);
+
+ parseLocation(_newLocation);
+ _vm->_graphics->copyScreen(Graphics::kBitBack, Graphics::kBit2);
+
+ _yourself._zone.pos._oldposition._x = -1000;
+ _yourself._zone.pos._oldposition._y = -1000;
+
+ _yourself.field_50 = 0;
+ if (_firstPosition._x != -1000) {
+ _yourself._zone.pos._position._x = _firstPosition._x;
+ _yourself._zone.pos._position._y = _firstPosition._y;
+ _yourself._frame = _firstFrame;
+ _firstPosition._y = -1000;
+ _firstPosition._x = -1000;
+ }
+
+ byte palette[PALETTE_SIZE];
+ for (uint16 _si = 0; _si < PALETTE_SIZE; _si++) palette[_si] = 0;
+ _vm->_graphics->palUnk0(palette);
+ _vm->_graphics->copyScreen(Graphics::kBitBack, Graphics::kBitFront);
+ if (_locationCommands) {
+ runCommands(_locationCommands);
+ runJobs();
+ _vm->_graphics->swapBuffers();
+ runJobs();
+ _vm->_graphics->swapBuffers();
+ }
+
+ if (_locationComment) doLocationEnterTransition();
+ runJobs();
+ _vm->_graphics->swapBuffers();
+
+ _vm->_graphics->palUnk0(_palette);
+ if (_locationACommands) runCommands(_locationACommands);
+
+ return;
+
+}
+
+// displays transition before a new location
+//
+// clears screen (in white??)
+// shows location comment (if any)
+// waits for mouse click
+// fades towards game palette
+//
+// THE FINAL PALETTE IS NOT THE SAME AS THE MAIN PALETTE!!!!!!
+//
+void Parallaction::doLocationEnterTransition() {
+// printf("doLocationEnterTransition()\n");
+
+ byte v60[PALETTE_SIZE];
+ if (_localFlags[_currentLocationIndex] & 1) return; // visited
+
+ _vm->_graphics->buildBWPalette(v60);
+ _vm->_graphics->setPalette(v60);
+
+ jobRunScripts(NULL, NULL);
+ jobEraseAnimations(NULL, NULL);
+ jobDisplayAnimations(NULL, NULL);
+
+ _vm->_graphics->loadExternalCnv("comiccnv", &Graphics::_font);
+ _vm->_graphics->swapBuffers();
+ _vm->_graphics->copyScreen(Graphics::kBitFront, Graphics::kBitBack);
+
+ int16 v7C, v7A;
+ _vm->_graphics->getStringExtent(_locationComment, 130, &v7C, &v7A);
+ _vm->_graphics->floodFill(0, 5, 5, 10 + v7C, 5 + v7A, Graphics::kBitFront);
+ _vm->_graphics->floodFill(1, 6, 6, 9 + v7C, 4 + v7A, Graphics::kBitFront);
+ _vm->_graphics->displayWrappedString(_locationComment, 3, 5, 130, 0);
+
+ _vm->_graphics->freeCnv( &Graphics::_font );
+
+ // FIXME: ???
+#if 0
+ do {
+ mouseFunc1();
+ } while (_mouseButtons != kMouseLeftUp);
+#endif
+
+ waitUntilLeftClick();
+
+ _vm->_graphics->copyScreen(Graphics::kBitBack, Graphics::kBitFront );
+
+ // fades maximum intensity palette towards approximation of main palette
+ for (uint16 _si = 0; _si<6; _si++) {
+ waitTime( 1 );
+ _vm->_graphics->quickFadePalette(v60);
+ _vm->_graphics->setPalette(v60);
+ }
+
+ return;
+}
+
+void mouseFunc1() {
+ // FIXME: implement this
+}
+
+} // namespace Parallaction
diff --git a/engines/parallaction/menu.cpp b/engines/parallaction/menu.cpp
new file mode 100644
index 0000000000..d4a910e809
--- /dev/null
+++ b/engines/parallaction/menu.cpp
@@ -0,0 +1,427 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * 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 "parallaction/menu.h"
+#include "parallaction/disk.h"
+#include "parallaction/music.h"
+#include "parallaction/inventory.h"
+#include "parallaction/graphics.h"
+#include "parallaction/parallaction.h"
+
+
+namespace Parallaction {
+
+const char *introMsg1[] = {
+ "INSERISCI IL CODICE",
+ "ENTREZ CODE",
+ "ENTER CODE",
+ "GIB DEN KODE EIN"
+};
+
+const char *introMsg2[] = {
+ "CODICE ERRATO",
+ "CODE ERRONE",
+ "WRONG CODE",
+ "GIB DEN KODE EIN"
+};
+
+const char *introMsg3[] = {
+ "PRESS LEFT MOUSE BUTTON",
+ "TO SEE INTRO",
+ "PRESS RIGHT MOUSE BUTTON",
+ "TO START"
+};
+
+const char *newGameMsg[] = {
+ "NUOVO GIOCO",
+ "NEUF JEU",
+ "NEW GAME",
+ "NEUES SPIEL"
+};
+
+const char *loadGameMsg[] = {
+ "GIOCO SALVATO",
+ "JEU SAUVE'",
+ "SAVED GAME",
+ "SPIEL GESPEICHERT"
+};
+
+
+#define BLOCK_WIDTH 16
+#define BLOCK_HEIGHT 24
+
+#define BLOCK_X 112
+#define BLOCK_Y 130
+
+#define BLOCK_SELECTION_X (BLOCK_X-1)
+#define BLOCK_SELECTION_Y (BLOCK_Y-1)
+
+#define BLOCK_X_OFFSET (BLOCK_WIDTH+1)
+#define BLOCK_Y_OFFSET 9
+
+// destination slots for code blocks
+//
+#define SLOT_X 61
+#define SLOT_Y 64
+#define SLOT_WIDTH (BLOCK_WIDTH+2)
+
+
+static uint16 _dinoKey[] = { 5, 3, 6, 1, 4, 7 }; //
+static uint16 _donnaKey[] = { 0, 2, 8, 5, 5, 1 };
+static uint16 _doughKey[] = { 1, 7 ,7, 2, 2, 6 };
+
+
+Menu::Menu(Parallaction *engine) {
+ _engine = engine;
+}
+
+Menu::~Menu() {
+ //
+}
+
+
+void Menu::start() {
+
+ openArchive("disk1");
+ _vm->_graphics->_proportionalFont = false;
+
+ _vm->_graphics->loadExternalCnv("slidecnv", &Graphics::_font);
+
+ _vm->_graphics->Graphics::loadBackground("intro.slide", Graphics::kBitBack);
+ _vm->_graphics->palUnk0(_palette);
+ _vm->_graphics->copyScreen(Graphics::kBitBack, Graphics::kBitFront);
+
+ g_system->delayMillis(2000);
+
+ _vm->_graphics->loadBackground("minintro.slide", Graphics::kBitBack);
+ _vm->_graphics->palUnk0(_palette);
+ _vm->_graphics->copyScreen(Graphics::kBitBack, Graphics::kBitFront);
+
+ g_system->delayMillis(2000);
+
+ _vm->_graphics->loadBackground("lingua.slide", Graphics::kBitBack);
+ _vm->_graphics->palUnk0(_palette);
+ _vm->_graphics->copyScreen(Graphics::kBitBack, Graphics::kBitFront);
+
+ _vm->_graphics->displayString(60, 30, "SELECT LANGUAGE");
+
+ _vm->_graphics->copyScreen(Graphics::kBitFront, Graphics::kBitBack);
+ _vm->_graphics->copyScreen(Graphics::kBitBack, Graphics::kBit2);
+ _language = chooseLanguage();
+
+ switch (_language) {
+ case 0:
+ strcpy(_engine->_languageDir, "it/");
+ break;
+
+ case 1:
+ strcpy(_engine->_languageDir, "fr/");
+ break;
+
+ case 2:
+ strcpy(_engine->_languageDir, "en/");
+ break;
+
+ case 3:
+ strcpy(_engine->_languageDir, "ge/");
+ break;
+ }
+
+ _vm->_graphics->loadBackground("restore.slide", Graphics::kBitBack);
+ _vm->_graphics->palUnk0(_palette);
+ _vm->_graphics->copyScreen(Graphics::kBitBack, Graphics::kBitFront);
+
+ _vm->_graphics->copyScreen(Graphics::kBitBack, Graphics::kBit2);
+ _vm->_graphics->copyScreen(Graphics::kBitBack, Graphics::kBit3);
+
+ if (selectGame() == 0) {
+ newGame();
+ }
+
+ closeArchive();
+
+ return;
+}
+
+void Menu::newGame() {
+// printf("newGame()\n");
+
+ const char **v14 = introMsg3;
+
+ _vm->_graphics->loadBackground("test.dyn", Graphics::kBitBack);
+ _vm->_graphics->palUnk0(_palette);
+ _vm->_graphics->swapBuffers();
+
+ uint16 _ax = (SCREEN_WIDTH - _vm->_graphics->getStringWidth(v14[0])) / 2;
+ _vm->_graphics->displayString(_ax, 50, v14[0]);
+
+ _ax = (SCREEN_WIDTH - _vm->_graphics->getStringWidth(v14[1])) / 2;
+ _vm->_graphics->displayString(_ax, 70, v14[1]);
+
+ _ax = (SCREEN_WIDTH - _vm->_graphics->getStringWidth(v14[2])) / 2;
+ _vm->_graphics->displayString(_ax, 100, v14[2]);
+
+ _ax = (SCREEN_WIDTH - _vm->_graphics->getStringWidth(v14[3])) / 2;
+ _vm->_graphics->displayString(_ax, 120, v14[3]);
+
+ _vm->_graphics->copyScreen(Graphics::kBitFront, Graphics::kBitBack);
+
+
+ _mouseButtons = kMouseNone;
+
+ for (; _mouseButtons != kMouseLeftUp; ) {
+ _vm->updateInput();
+ if (_mouseButtons == kMouseRightUp) break;
+ }
+
+ if (_mouseButtons != kMouseRightUp) return; // show intro
+
+ _vm->_graphics->freeCnv(&Graphics::_font);
+ closeArchive();
+
+ selectCharacter();
+
+ char *v4 = strchr(_location, '.') + 1;
+ strcpy(_engine->_characterName, v4);
+
+ return; // start game
+}
+
+uint16 Menu::chooseLanguage() {
+
+ _engine->changeCursor(kCursorArrow);
+
+ do {
+ _engine->updateInput();
+ _vm->_graphics->swapBuffers();
+
+ uint16 _di = _mousePos._x;
+ uint16 v2 = _mousePos._y;
+
+ if (_mouseButtons == kMouseLeftUp) {
+ for (uint16 _si = 0; _si < 4; _si++) {
+
+ if (80 + _si*49 >= _di) continue;
+ if (110 - _si*25 >= v2) continue;
+
+ if (128 + _si*49 <= _di) continue;
+ if (180 - _si*25 <= v2) continue;
+
+ beep();
+ return _si;
+ }
+ }
+
+ _engine->waitTime( 1 );
+
+ } while (true);
+
+ // never reached !!!
+ return 0;
+}
+
+
+
+uint16 Menu::selectGame() {
+// printf("selectGame()\n");
+
+ uint16 _si = 0;
+ uint16 _di = 3;
+
+ _engine->updateInput();
+ while (_mouseButtons != kMouseLeftUp) {
+
+ _engine->updateInput();
+ _vm->_graphics->swapBuffers();
+ _engine->waitTime( 1 );
+
+ _si = 0;
+ if (_mousePos._x > 160)
+ _si = 1;
+
+ if (_si == _di) continue;
+
+ _di = _si;
+ _vm->_graphics->copyScreen(Graphics::kBit3, Graphics::kBitFront);
+
+ if (_si != 0) {
+ // load a game
+ _vm->_graphics->displayString(60, 30, loadGameMsg[_language]);
+ } else {
+ // new game
+ _vm->_graphics->displayString(60, 30, newGameMsg[_language]);
+ }
+
+ _vm->_graphics->copyScreen(Graphics::kBitFront, Graphics::kBit2);
+ _vm->_graphics->copyScreen(Graphics::kBitFront, Graphics::kBitBack);
+
+ }
+
+ if (_si == 0) return 0; // new game
+
+ // load game
+ _vm->_graphics->freeCnv(&Graphics::_font);
+
+ strcpy(_location, "fogne");
+ strcpy(_engine->_characterName, "dough");
+
+// loadGame();
+ closeArchive();
+
+ return 1; // load game
+}
+
+
+//
+// character selection and protection
+//
+void Menu::selectCharacter() {
+
+ uint16 _di = 0;
+ bool askPassword = true;
+
+ uint16 _donna_points = 0;
+ uint16 _dino_points = 0;
+ uint16 _dough_points = 0;
+
+
+ StaticCnv v14;
+
+ v14._data0 = (byte*)memAlloc(33);
+ v14._data2 = v14._data0;
+ v14._width = BLOCK_WIDTH;
+ v14._height = BLOCK_HEIGHT;
+
+ _engine->changeCursor(kCursorArrow);
+ stopMusic();
+ _vm->_graphics->_proportionalFont = false;
+
+ _vm->_graphics->loadExternalCnv("slidecnv", &Graphics::_font);
+ openArchive("disk1");
+
+ _vm->_graphics->loadBackground("password.slide", Graphics::kBitBack);
+ _vm->_graphics->copyScreen(Graphics::kBitBack, Graphics::kBit2);
+ _vm->_graphics->palUnk0(_palette);
+
+ _vm->_graphics->copyScreen(Graphics::kBitBack, Graphics::kBitFront);
+ _vm->_graphics->copyScreen(Graphics::kBitBack, Graphics::kBit3);
+
+ while (askPassword == true) {
+
+ askPassword = false;
+ _di = 0;
+ _vm->_graphics->displayString(60, 30, introMsg1[_language]);
+ _vm->_graphics->copyScreen(Graphics::kBitFront, Graphics::kBit2);
+ _vm->_graphics->copyScreen(Graphics::kBitFront, Graphics::kBitBack);
+ _mouseButtons = kMouseNone;
+
+ while (_di < 6) {
+ do {
+ _engine->updateInput();
+ //job_eraseMouse();
+ //job_drawMouse();
+ _vm->_graphics->swapBuffers();
+ _engine->waitTime(1);
+
+ } while (_mouseButtons != kMouseLeftUp);
+
+
+ _mouseButtons = kMouseNone;
+ uint16 x = _mousePos._x;
+ uint16 y = _mousePos._y;
+
+ uint16 _si = 0;
+
+ while (_si < 9) {
+
+ if ((_si * BLOCK_X_OFFSET + BLOCK_SELECTION_X < x) &&
+ ((_si + 1) * BLOCK_X_OFFSET + BLOCK_SELECTION_X > x) &&
+ (BLOCK_SELECTION_Y - _si * BLOCK_Y_OFFSET < y) &&
+ (BLOCK_SELECTION_Y + BLOCK_HEIGHT - _si * BLOCK_Y_OFFSET > y)) {
+
+ _vm->_graphics->backupCnvBackground(&v14, _si * BLOCK_X_OFFSET + BLOCK_X, BLOCK_Y - _si * BLOCK_Y_OFFSET);
+
+ _vm->_graphics->flatBlitCnv(&v14, _di * SLOT_WIDTH + SLOT_X, SLOT_Y, Graphics::kBitBack, 0);
+ _vm->_graphics->flatBlitCnv(&v14, _di * SLOT_WIDTH + SLOT_X, SLOT_Y, Graphics::kBitFront, 0);
+ _vm->_graphics->flatBlitCnv(&v14, _di * SLOT_WIDTH + SLOT_X, SLOT_Y, Graphics::kBit2, 0);
+
+ beep();
+
+ if (_dinoKey[_di] == _si) {
+ _dino_points++; // dino
+ } else
+ if (_donnaKey[_di] == _si) {
+ _donna_points++; // donna
+ } else
+ if (_doughKey[_di] == _si) {
+ _dough_points++; // dough
+ } else
+ askPassword = true;
+
+ _di++;
+ }
+
+ _si++;
+
+ }
+ }
+
+ if (askPassword == false) continue;
+
+ _vm->_graphics->copyScreen(Graphics::kBit3, Graphics::kBitFront);
+ _vm->_graphics->displayString(60, 30, introMsg1[_language]);
+
+ g_system->delayMillis(2000);
+
+ _vm->_graphics->copyScreen(Graphics::kBit3, Graphics::kBitFront);
+ }
+
+
+ strcpy(_location, "test");
+ if (_dino_points > _donna_points && _dino_points > _dough_points) {
+ strcat(_location, ".dino");
+ } else {
+ if (_donna_points > _dino_points && _donna_points > _dough_points) {
+ strcat(_location, ".donna");
+ } else {
+ strcat(_location, ".dough");
+ }
+ }
+
+ byte palette[PALETTE_SIZE];
+ _vm->_graphics->getBlackPalette(palette);
+ _vm->_graphics->setPalette(palette);
+
+ _engineFlags |= kEngineChangeLocation;
+ closeArchive();
+
+ memFree(v14._data0);
+ _vm->_graphics->freeCnv(&Graphics::_font);
+
+ refreshInventory(_vm->_characterName);
+
+ return;
+
+}
+
+
+} // namespace Parallaction
diff --git a/engines/parallaction/menu.h b/engines/parallaction/menu.h
new file mode 100644
index 0000000000..694627ec6b
--- /dev/null
+++ b/engines/parallaction/menu.h
@@ -0,0 +1,57 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * 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_MENU_H
+#define PARALLACTION_MENU_H
+
+#include "parallaction/defs.h"
+
+namespace Parallaction {
+
+class Parallaction;
+
+class Menu {
+
+public:
+ Menu(Parallaction *engine);
+ virtual ~Menu();
+
+ void start();
+ void selectCharacter();
+
+protected:
+ void newGame();
+ uint16 chooseLanguage();
+ uint16 selectGame();
+
+public:
+
+
+protected:
+ Parallaction* _engine;
+
+
+};
+
+#endif
+
+} // namespace Parallaction
diff --git a/engines/parallaction/module.mk b/engines/parallaction/module.mk
new file mode 100644
index 0000000000..8a4f8d24e6
--- /dev/null
+++ b/engines/parallaction/module.mk
@@ -0,0 +1,31 @@
+MODULE := engines/parallaction
+
+MODULE_OBJS := \
+ animation.o \
+ archive.o \
+ callables.o \
+ commands.o \
+ debug.o \
+ detection.o \
+ dialogue.o \
+ graphics.o \
+ intro.o \
+ inventory.o \
+ loadsave.o \
+ location.o \
+ menu.o \
+ music.o \
+ parser.o \
+ parallaction.o \
+ staticres.o \
+ table.o \
+ walk.o \
+ zone.o
+
+# This module can be built as a plugin
+ifdef BUILD_PLUGINS
+PLUGIN := 1
+endif
+
+# Include common rules
+include $(srcdir)/rules.mk
diff --git a/engines/parallaction/music.cpp b/engines/parallaction/music.cpp
new file mode 100644
index 0000000000..8031f20432
--- /dev/null
+++ b/engines/parallaction/music.cpp
@@ -0,0 +1,125 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * 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/file.h"
+#include "parallaction/parallaction.h"
+
+namespace Parallaction {
+
+// NOTE: these two guys are never changed.
+static int16 _musicFlag2 = 1;
+static int16 _musicFlag1 = 1;
+
+static bool _allocated = false;
+static bool _playing = false;
+// UNUSED
+// static char byte_14D22[10] = { 0 };
+static const char *_musicFilesNames[] = { "intro", "dino", "donna", "nuts", "soft", "boogie2" };
+static uint16 _musicFilesSizes[] = { 18805, 5486, 6195, 13006, 15818, 7507 };
+static byte *_musicBits = NULL;
+
+// TODO
+// move this into a proper midi driver and decode the numeric commands
+void _music_command(int32, int32, int32, int32) {
+
+}
+
+void stopMusic() {
+
+ if (_musicFlag1 == 0 && _musicFlag2 == 0) return;
+ if (_playing == false) return;
+ if (_allocated == false) return;
+
+ _music_command(4, 0, 0, 0); // stop
+ _music_command(5, 0, 0, 0); // reset timer
+
+ memFree(_musicBits);
+
+ _allocated = false;
+ _playing = false;
+
+ return;
+}
+
+void playMusic() {
+
+ if (_musicFlag1 == 0 && _musicFlag2 == 0) return;
+ if (_playing == true) return;
+ if (_allocated == false) return;
+
+ _music_command(0, 0, 0, 0); // init driver
+ _music_command(1, 0, 0, 0); // init timer
+ _music_command(17, 1, 0, 0); // set source segment
+ _music_command(7, 1, 0, 0); // set source offset and do SOMETHING
+
+ _music_command(2, (uint32)_musicBits, 0, 0); // play
+
+ _playing = true;
+
+ return;
+}
+
+void loadMusic(const char *filename) {
+
+ uint16 _di = 0;
+
+ if (!scumm_strnicmp(_location, "museo", 5)) return;
+ if (!scumm_strnicmp(_location, "intgrottadopo", 13)) return;
+ if (!scumm_strnicmp(_location, "caveau", 6)) return;
+ if (!scumm_strnicmp(_location, "estgrotta", 9)) return;
+ if (!scumm_strnicmp(_location, "plaza1", 6)) return;
+ if (!scumm_strnicmp(_location, "endtgz", 6)) return;
+
+ if (_musicFlag1 == 0 && _musicFlag2 == 0) return;
+ if (_allocated == true) return;
+
+// UNUSED
+// strcpy(byte_14D22, filename);
+
+ for (uint16 _si = 0; _si < 6; _si++) {
+ if (!strcmp(filename, _musicFilesNames[_si])) {
+ _di = _musicFilesSizes[_si];
+ }
+ }
+
+ if (_di == 0 ) return;
+
+ char path[PATH_LEN];
+ sprintf(path, "%s.mid", filename);
+
+ Common::File stream;
+
+ if (!stream.open(path))
+ return;
+
+ _musicBits = (byte*)memAlloc(_di);
+ if (!_musicBits) return;
+
+ stream.read(_musicBits, _di);
+ stream.close();
+
+ _allocated = true;
+
+ return;
+}
+
+} // namespace Parallaction
diff --git a/engines/parallaction/music.h b/engines/parallaction/music.h
new file mode 100644
index 0000000000..4f3f211002
--- /dev/null
+++ b/engines/parallaction/music.h
@@ -0,0 +1,34 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * 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_MUSIC_H
+#define PARALLACTION_MUSIC_H
+
+namespace Parallaction {
+
+void stopMusic();
+void playMusic();
+void loadMusic(const char *filename);
+
+} // namespace Parallaction
+
+#endif
diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp
new file mode 100644
index 0000000000..3b5d6abd21
--- /dev/null
+++ b/engines/parallaction/parallaction.cpp
@@ -0,0 +1,939 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * 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 "parallaction/parallaction.h"
+#include "parallaction/menu.h"
+#include "parallaction/disk.h"
+#include "parallaction/music.h"
+#include "parallaction/inventory.h"
+#include "parallaction/graphics.h"
+#include "parallaction/zone.h"
+
+#include "common/util.h"
+#include "common/file.h"
+
+
+namespace Parallaction {
+
+// FIXME: remove this
+Parallaction *_vm = NULL;
+
+// public stuff
+Point _mousePos = { 0, 0 };
+uint16 _mouseButtons = 0;
+
+
+char _saveData1[30] = { '\0' };
+uint16 _language = 0;
+char _location[100] = "fogne";
+uint32 _engineFlags = 0;
+char *_objectsNames[100];
+Zone *_activeZone = NULL;
+Animation _yourself;
+uint16 _score = 1;
+Command *_locationACommands = NULL;
+Command *_locationCommands = NULL;
+char *_locationComment = NULL;
+char *_locationEndComment = NULL;
+uint32 _localFlags[120] = { 0 };
+
+char *_localFlagNames[32] = {
+ "visited",
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+Command * _forwardedCommands[20] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+char _forwardedAnimationNames[20][20];
+uint16 _numForwards = 0;
+char _soundFile[20];
+char _slideText[2][40];
+Point _firstPosition = { -1000, -1000 };
+char _newLocation[100];
+char *_globalTable[32];
+uint16 _firstFrame = 0;
+Cnv _characterFace;
+byte _mouseHidden = 0;
+Node _locationWalkNodes = { 0, 0 };
+uint32 _commandFlags = 0;
+Cnv _tempFrames;
+uint16 _introSarcData3 = 200;
+uint16 _introSarcData2 = 1;
+
+// private stuff
+
+
+
+
+static Job *_jDrawInventory = NULL;
+static Job *_jDrawLabel = NULL;
+static Job *_jEraseLabel = NULL;
+static Zone *_hoverZone = NULL;
+static Job *_jRunScripts = NULL;
+
+static Cnv _miniCharacterFrames;
+
+static Job _jobs = { { NULL, NULL }, 0, 0, 0, NULL, 0 };
+
+
+
+
+Parallaction::Parallaction(OSystem *syst) :
+ Engine(syst) {
+
+ // FIXME
+ _vm = this;
+
+ _skipMenu = false;
+
+ _transCurrentHoverItem = 0;
+ _actionAfterWalk = false; // actived when the character needs to move before taking an action
+ _activeItem._index = 0;
+ _activeItem._id = 0;
+ _procCurrentHoverItem = -1;
+
+ _musicData1 = 0;
+ strcpy(_characterName1, "null");
+
+
+ _baseTime = 0;
+
+ Common::File::addDefaultDirectory( _gameDataPath );
+
+}
+
+
+Parallaction::~Parallaction() {
+
+}
+
+
+int Parallaction::init() {
+
+ // Detect game
+ if (!detectGame()) {
+ GUIErrorMessage("No valid games were found in the specified directory.");
+ return -1;
+ }
+
+ strcpy(_location, "night");
+ strcpy(_characterName, "drki");
+ strcpy(_languageDir, "it/");
+ _skipMenu = true;
+
+ _engineFlags = 0;
+
+// strcpy(_characterName, "dough");
+ memset(_locationNames, 0, 120*32);
+ _numLocations = 0;
+
+
+
+
+ _yourself._zone.pos._position._x = 150;
+ _yourself._zone.pos._position._y = 100;
+ initInventory();
+ _yourself._z = 10;
+
+ _yourself._zone.pos._oldposition._x = -1000;
+ _yourself._zone.pos._oldposition._y = -1000;
+ _yourself._frame = 0;
+
+ _yourself._zone._flags = kFlagsActive | kFlagsNoName;
+ _yourself._zone._type = kZoneYou;
+
+ _yourself._zone._label._data0 = NULL;
+ _yourself._zone._name = "yourself";
+
+ addNode(&_animations, &_yourself._zone._node);
+ _graphics = new Graphics(this);
+
+
+ return 0;
+}
+
+
+
+
+
+int Parallaction::go() {
+
+ initGame();
+ runGame();
+
+ return 0;
+}
+
+void Parallaction::initGame() {
+
+ _menu = new Menu(this);
+
+ initGlobals();
+ if (_skipMenu == false) {
+ _menu->start();
+ }
+
+ char *v4 = strchr(_location, '.');
+ if (v4) {
+ *v4 = '\0';
+ }
+
+ _engineFlags &= ~kEngineChangeLocation;
+ changeCharacter(_characterName);
+
+ strcpy(_saveData1, _location);
+ parseLocation(_location);
+
+ if (_firstPosition._x != -1000) {
+ _yourself._zone.pos._position._x = _firstPosition._x;
+ _yourself._zone.pos._position._y = _firstPosition._y;
+ _yourself._frame = _firstFrame;
+ _firstPosition._y = -1000;
+ _firstPosition._x = -1000;
+ }
+
+ return;
+}
+
+void Parallaction::initGlobals() {
+
+ initTable("global.tab", _globalTable);
+}
+
+//
+// broken input management
+//
+uint16 Parallaction::updateInput() {
+
+ OSystem::Event e;
+ uint16 KeyDown = 0;
+
+ _mouseButtons = kMouseNone;
+
+ while (g_system->pollEvent(e)) {
+
+ switch (e.type) {
+ case OSystem::EVENT_KEYDOWN:
+ if (e.kbd.ascii == ' ') KeyDown = kEvQuitGame;
+ if (e.kbd.ascii == 'l') KeyDown = kEvLoadGame;
+ if (e.kbd.ascii == 's') KeyDown = kEvSaveGame;
+ break;
+
+ case OSystem::EVENT_LBUTTONDOWN:
+ _mouseButtons = kMouseLeftDown;
+ break;
+
+ case OSystem::EVENT_LBUTTONUP:
+ _mouseButtons = kMouseLeftUp;
+ break;
+
+ case OSystem::EVENT_RBUTTONDOWN:
+ _mouseButtons = kMouseRightDown;
+ break;
+
+ case OSystem::EVENT_RBUTTONUP:
+ _mouseButtons = kMouseRightUp;
+ break;
+
+ case OSystem::EVENT_MOUSEMOVE:
+ _mousePos._x = e.mouse.x;
+ _mousePos._y = e.mouse.y;
+ break;
+
+ case OSystem::EVENT_QUIT:
+ _engineFlags |= kEngineQuit;
+ break;
+
+ default:
+ break;
+
+ }
+
+ }
+
+ return KeyDown;
+
+}
+
+
+void waitUntilLeftClick() {
+
+ OSystem::Event e;
+
+ for (;;) {
+ g_system->pollEvent(e);
+ g_system->delayMillis(10);
+ if (e.type == OSystem::EVENT_LBUTTONUP)
+ break;
+
+ if (e.type == OSystem::EVENT_QUIT) {
+ _engineFlags |= kEngineQuit;
+ break;
+ }
+ }
+
+
+ return;
+}
+
+
+void Parallaction::runGame() {
+// printf("runGame()\n");
+
+ addJob(jobEraseAnimations, (void*)1, JOBPRIORITY_RUNSTUFF);
+ _jRunScripts = addJob(jobRunScripts, 0, JOBPRIORITY_RUNSTUFF);
+ addJob(jobDisplayAnimations, 0, JOBPRIORITY_DRAWANIMATIONS);
+
+ _graphics->copyScreen(Graphics::kBitBack, Graphics::kBit2);
+
+ if (_locationCommands)
+ runCommands(_locationCommands);
+
+ runJobs();
+
+ _graphics->copyScreen(Graphics::kBitBack, Graphics::kBitFront);
+
+ if (_locationComment)
+ doLocationEnterTransition();
+
+ changeCursor(kCursorArrow);
+
+ if (_locationACommands)
+ runCommands(_locationACommands);
+
+// printf("entering game loop...\n");
+
+ while ((_engineFlags & kEngineQuit) == 0) {
+ _keyDown = updateInput();
+
+ if ((_mouseHidden == 0) && ((_engineFlags & kEngineMouse) == 0) && ((_engineFlags & kEngineWalking) == 0)) {
+ InputData *v8 = translateInput();
+ if (v8) processInput(v8);
+ }
+
+ if (_activeZone) {
+ Zone *z = _activeZone; // speak Zone or sound
+ _activeZone = NULL;
+ if (runZone( z ) == 0)
+ runCommands( z->_commands, z );
+ }
+
+ if (_engineFlags & kEngineChangeLocation) {
+ _engineFlags &= ~kEngineChangeLocation;
+ changeLocation(_location);
+ continue;
+ }
+
+ g_system->delayMillis(30);
+
+// printflags();
+ runJobs();
+
+ if ((_engineFlags & kEnginePauseJobs) == 0 || (_engineFlags & kEngineInventory)) {
+ _graphics->swapBuffers();
+ byte palette[PALETTE_SIZE];
+ memcpy(palette, _palette, sizeof(palette));
+ _graphics->animatePalette(palette);
+ _graphics->setPalette(palette);
+ }
+
+ }
+
+// printf("exiting game loop...\n");
+
+ delete _menu;
+
+ return;
+}
+
+
+void Parallaction::processInput(InputData *data) {
+// printf("processInput()\n");
+ Zone *z;
+ WalkNode *v4;
+
+ switch (data->_event) {
+ case kEvEnterZone:
+ _graphics->_labelPosition[1]._x = -1000;
+ _graphics->_labelPosition[1]._y = -1000;
+ _graphics->_labelPosition[0]._x = -1000;
+ _graphics->_labelPosition[0]._y = -1000;
+ _jDrawLabel = addJob(&jobDisplayLabel, (void*)data->_data, JOBPRIORITY_DRAWLABEL);
+ _jEraseLabel = addJob(&jobEraseLabel, (void*)data->_data, JOBPRIORITY_HIDEINVENTORY);
+ break;
+
+ case kEvExitZone:
+ removeJob(_jDrawLabel);
+ addJob(&jobWaitRemoveJob, _jEraseLabel, JOBPRIORITY_RUNSTUFF);
+ _jDrawLabel = NULL;
+ break;
+
+ case kEvAction:
+ _procCurrentHoverItem = -1;
+ _hoverZone = NULL;
+ pauseJobs();
+ z = (Zone*)data->_data;
+ if (runZone(z) == 0) {
+ runCommands( z->_commands, z );
+ }
+ resumeJobs();
+ break;
+
+ case kEvOpenInventory:
+ _procCurrentHoverItem = -1;
+ _hoverZone = 0;
+ if (_jDrawLabel != 0) {
+ removeJob(_jDrawLabel);
+ _jDrawLabel = NULL;
+ addJob(&jobWaitRemoveJob, _jEraseLabel, JOBPRIORITY_SHOWINVENTORY);
+ }
+ if (hitZone(kZoneYou, _mousePos._x, _mousePos._y) == 0)
+ changeCursor(kCursorArrow);
+ removeJob(_jRunScripts);
+ _jDrawInventory = addJob(&jobShowInventory, 0, JOBPRIORITY_SHOWINVENTORY);
+ openInventory();
+ break;
+
+ case kEvCloseInventory: // closes inventory and possibly select item
+ closeInventory();
+ if ((data->_data != -1) && (_inventory[data->_data]._id != 0)) {
+ // activates item
+ changeCursor(data->_data);
+ }
+ _jRunScripts = addJob(&jobRunScripts, 0, JOBPRIORITY_RUNSTUFF);
+ addJob(&jobHideInventory, 0, JOBPRIORITY_HIDEINVENTORY);
+ removeJob(_jDrawInventory);
+ break;
+
+ case kEvHoverInventory:
+ highlightInventoryItem(_procCurrentHoverItem, 12); // disable
+ highlightInventoryItem(data->_data, 19); // enable
+ _procCurrentHoverItem = data->_data;
+ break;
+
+ case kEvWalk:
+ _hoverZone = 0;
+ changeCursor(kCursorArrow);
+ if (_yourself._zone._flags & kFlagsRemove) break;
+ if ((_yourself._zone._flags & kFlagsActive) == 0) break;
+ v4 = buildWalkPath(data->_mousePos._x, data->_mousePos._y);
+ addJob(jobWalk, v4, JOBPRIORITY_WALK);
+ _engineFlags |= kEngineWalking; // inhibits processing of input until walking is over
+ break;
+
+ case kEvQuitGame:
+ _engineFlags |= kEngineQuit;
+ break;
+
+ case kEvSaveGame:
+ _hoverZone = NULL;
+ changeCursor(kCursorArrow);
+ saveGame();
+ break;
+
+ case kEvLoadGame:
+ _hoverZone = NULL;
+ changeCursor(kCursorArrow);
+ loadGame();
+ break;
+
+ }
+
+ return;
+}
+
+
+
+Parallaction::InputData *Parallaction::translateInput() {
+// printf("translateInput(%c)\n", _keyDown);
+
+ if (_keyDown == kEvQuitGame) {
+ _input._event = kEvQuitGame;
+ return &_input;
+ }
+
+ if (_keyDown == kEvSaveGame) {
+ _input._event = kEvSaveGame;
+ return &_input;
+ }
+
+ if (_keyDown == kEvLoadGame) {
+ _input._event = kEvLoadGame;
+ return &_input;
+ }
+
+ _input._mousePos._x = _mousePos._x;
+ _input._mousePos._y = _mousePos._y;
+
+ if (((_engineFlags & kEnginePauseJobs) == 0) && ((_engineFlags & kEngineInventory) == 0)) {
+
+ if (_actionAfterWalk == true) {
+// printf("1\n");
+
+ // if walking is over, then take programmed action
+
+ _input._event = kEvAction;
+ _actionAfterWalk = false;
+ return &_input;
+ }
+
+ Zone *z = hitZone(_activeItem._id, _mousePos._x, _mousePos._y);
+
+ if (_mouseButtons == kMouseRightDown) {
+// printf("2\n");
+
+ // right button down shows inventory
+
+ if (hitZone(kZoneYou, _mousePos._x, _mousePos._y) && (_activeItem._id != 0)) {
+// printf("2.1\n");
+
+ _activeItem._index = (_activeItem._id >> 16) & 0xFFFF;
+ _engineFlags |= kEngineDragging;
+ }
+
+
+ _input._event = kEvOpenInventory;
+ _transCurrentHoverItem = -1;
+ return &_input;
+ }
+
+ if (((_mouseButtons == kMouseLeftUp) && (_activeItem._id == 0) && ((_engineFlags & kEngineWalking) == 0)) && ((z == NULL) || ((z->_type & 0xFFFF) != kZoneCommand))) {
+// printf("3\n");
+
+ _input._event = kEvWalk;
+ return &_input;
+ }
+
+ if ((z != _hoverZone) && (_hoverZone != NULL)) {
+// printf("4\n");
+
+ _hoverZone = NULL;
+ _input._event = kEvExitZone;
+// _input._data= &z->_name;
+ return &_input;
+ }
+
+ if (z == NULL) {
+// printf("5\n");
+
+ return NULL;
+ }
+
+ if ((_hoverZone == NULL) && ((z->_flags & kFlagsNoName) == 0)) {
+// printf("6\n");
+
+ _hoverZone = z;
+ _input._event = kEvEnterZone;
+ _input._data= (int32)&z->_label;
+ return &_input;
+ }
+
+ if ((_mouseButtons == kMouseLeftUp) && ((_activeItem._id != 0) || ((z->_type & 0xFFFF) == kZoneCommand))) {
+
+ _input._data = (int32)z;
+ if (z->_flags & kFlagsNoWalk) {
+// printf("7.1\n");
+
+ // character doesn't need to walk to take specified action
+ _input._event = kEvAction;
+
+ } else {
+// printf("7.2\n");
+
+ // action delayed: if Zone defined a moveto position the character is programmed to move there,
+ // else it will move to the mouse position
+
+ _input._event = kEvWalk;
+ _actionAfterWalk = true;
+ if (z->_moveTo._y != 0) {
+ // printf("3.2.2\n");
+ _input._mousePos._x = z->_moveTo._x;
+ _input._mousePos._y = z->_moveTo._y;
+ }
+
+ }
+
+ beep();
+ changeCursor(kCursorArrow);
+ return &_input;
+ }
+
+ }
+
+ if ((_engineFlags & kEngineInventory) == 0) return NULL;
+
+// printf("8\n");
+
+
+ // in inventory
+
+ int16 _si = getHoverInventoryItem(_mousePos._x, _mousePos._y);
+
+ if (_mouseButtons == kMouseRightUp) {
+ // right up hides inventory
+
+ _input._event = kEvCloseInventory;
+ _input._data = getHoverInventoryItem(_mousePos._x, _mousePos._y);
+ highlightInventoryItem(_transCurrentHoverItem, 12); // disable
+
+ if ((_engineFlags & kEngineDragging) == 0) return &_input;
+
+ _engineFlags &= ~kEngineDragging;
+ Zone *z = hitZone(kZoneMerge, _activeItem._index, _inventory[_input._data]._index);
+
+ if (z != NULL) {
+ dropItem(z->u.merge->_obj1 - 4);
+ dropItem(z->u.merge->_obj2 - 4);
+ addInventoryItem(z->u.merge->_obj3);
+ runCommands(z->_commands);
+ }
+
+ return &_input;
+ }
+
+ if (_si == _transCurrentHoverItem) return NULL;
+
+ _transCurrentHoverItem = _si;
+ _input._event = kEvHoverInventory;
+ _input._data = _si;
+ return &_input;
+
+}
+
+uint32 Parallaction::getElapsedTime() {
+ return g_system->getMillis() - _baseTime;
+}
+
+void Parallaction::resetTimer() {
+ _baseTime = g_system->getMillis();
+ return;
+}
+
+
+void Parallaction::waitTime(uint32 t) {
+// printf("waitTime(%i)\n", t);
+
+ uint32 v4 = 0;
+
+ while (v4 < t * (1000 / 18.2)) {
+ v4 = getElapsedTime();
+ }
+
+ resetTimer();
+
+ return;
+}
+
+
+
+
+// changes the mouse pointer
+// index 0 means standard pointer (from pointer.cnv)
+// index > 0 means inventory item
+//
+void Parallaction::changeCursor(int32 index) {
+// printf("changeCursor(%i)\n", index);
+
+ if (index == kCursorArrow) { // standard mouse pointer
+
+ if (_jDrawLabel != NULL) {
+ removeJob(_jDrawLabel);
+ addJob(&jobWaitRemoveJob, _jEraseLabel, JOBPRIORITY_RUNSTUFF);
+ _jDrawLabel = NULL;
+ }
+
+ _activeItem._id = 0;
+
+ } else {
+ _activeItem._id = _inventory[index]._id;
+ }
+
+ _graphics->setMousePointer(index);
+
+ return;
+}
+
+
+
+void freeCharacterFrames() {
+
+ _vm->_graphics->freeCnv(&_tempFrames);
+
+ if (_vm->_characterName[0] != 'D') {
+ _vm->_graphics->freeCnv(&_miniCharacterFrames);
+ _vm->freeTable(_objectsNames);
+ }
+
+ return;
+}
+
+
+
+void Parallaction::changeCharacter(const char *name) {
+// printf("changeCharacter(%s)\n", name);
+
+ uint16 _si = 0;
+
+ if (!scumm_strnicmp(name, "mini", 4)) {
+ name+=4;
+ _si = 1;
+ }
+
+ char v32[20];
+ strcpy(v32, name);
+
+
+
+ if (_engineFlags & kEngineMiniDonna) {
+ strcat(v32, "tras");
+ }
+
+ if (scumm_stricmp(v32, _characterName1)) {
+
+ if (scumm_stricmp(_characterName1, "null")) {
+ freeCharacterFrames();
+ }
+
+ closeArchive();
+
+ strcpy(_disk, "disk1");
+ openArchive("disk1");
+
+ char path[PATH_LEN];
+ strcpy(path, v32);
+ _graphics->loadCnv(path, &_tempFrames);
+
+ if (name[0] != 'D') {
+ sprintf(path, "mini%s", v32);
+ _graphics->loadCnv(path, &_miniCharacterFrames);
+
+ sprintf(path, "%s.tab", name);
+ initTable(path, _objectsNames);
+
+ refreshInventory(name);
+
+ stopMusic();
+
+ if (scumm_stricmp(name, "night") && scumm_stricmp(name, "intsushi")) {
+ if (!scumm_stricmp(name, "dino") || !scumm_stricmp(name, "minidino")) {
+ loadMusic("dino");
+ } else
+ if (!scumm_stricmp(name, "donna") || !scumm_stricmp(name, "minidonna")) {
+ loadMusic("donna");
+ } else {
+ loadMusic("nuts");
+ }
+
+ playMusic();
+ }
+
+ }
+
+ }
+
+ if (_si == 1) {
+ memcpy(&_yourself._cnv, &_miniCharacterFrames, sizeof(Cnv));
+ } else {
+ memcpy(&_yourself._cnv, &_tempFrames, sizeof(Cnv));
+ }
+
+ strcpy(_characterName1, v32);
+
+ return;
+}
+
+void freeNodeList(Node *list) {
+
+ while (list) {
+ Node *v4 = list->_next;
+ memFree(list);
+ list = v4;
+ }
+
+ return;
+}
+
+
+void addNode(Node *list, Node *n) {
+
+ Node *v4 = list->_next;
+
+ if (v4 != NULL) {
+ v4->_prev = n;
+ }
+
+ n->_next = v4;
+ list->_next = n;
+ n->_prev = list;
+
+ return;
+}
+
+void removeNode(Node *n) {
+
+ Node *v4 = n->_next;
+ if (v4 != NULL) {
+ v4->_prev = n->_prev;
+ }
+
+ n->_prev->_next = n->_next;
+
+ return;
+}
+
+
+Job *addJob(JobFn fn, void *parm, uint16 tag) {
+// printf("addJob(%i)\n", tag);
+
+ Job *v8 = (Job*)memAlloc(sizeof(Job));
+
+ v8->_parm = parm;
+ v8->_fn = fn;
+ v8->_tag = tag;
+ v8->_finished = 0;
+ v8->_count = 0;
+
+ Job *v4 = &_jobs;
+
+ while (v4->_node._next && ((Job*)(v4->_node._next))->_tag > tag) {
+ v4 = (Job*)v4->_node._next;
+ }
+
+ addNode(&v4->_node, &v8->_node);
+ return v8;
+}
+
+void removeJob(Job *j) {
+// printf("removeJob(%x, %i)\n", j, j->_tag);
+
+ removeNode(&j->_node);
+ memFree(j);
+ return;
+}
+
+void pauseJobs() {
+ _engineFlags |= kEnginePauseJobs;
+ return;
+}
+
+void resumeJobs() {
+ _engineFlags &= ~kEnginePauseJobs;
+ return;
+}
+
+void runJobs() {
+// printf("runJobs...START\n");
+
+ if (_engineFlags & kEnginePauseJobs) return;
+
+ Job *j = (Job*)_jobs._node._next;
+ while (j) {
+// printf("Job run %s\n", _jobDescriptions[j->_tag]);
+
+ (*j->_fn)(j->_parm, j);
+ Job *v4 = (Job*)j->_node._next;
+
+ if (j->_finished == 1) removeJob(j);
+
+ j = v4;
+ }
+
+// printf("runJobs...DONE\n");
+
+ return;}
+
+// this Job uses a static counter to delay removal
+// and is in fact only used to remove jEraseLabel jobs
+//
+void jobWaitRemoveJob(void *parm, Job *j) {
+// printf("jobWaitRemoveJob(%x)\n", parm);
+
+ Job *arg = (Job*)parm;
+
+ static uint16 count = 0;
+
+ _engineFlags |= kEngineMouse;
+
+ count++;
+ if (count == 2) {
+ count = 0;
+ removeJob(arg);
+ _engineFlags &= ~kEngineMouse;
+ j->_finished = 1;
+ }
+
+ return;
+}
+
+
+} // namespace Parallaction
diff --git a/engines/parallaction/parallaction.h b/engines/parallaction/parallaction.h
new file mode 100644
index 0000000000..fb2221cd6a
--- /dev/null
+++ b/engines/parallaction/parallaction.h
@@ -0,0 +1,311 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * 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_H
+#define PARALLACTION_H
+
+#include "engines/engine.h"
+#include "parallaction/defs.h"
+#include "parallaction/inventory.h"
+#include "common/advancedDetector.h"
+
+
+namespace Parallaction {
+
+// high values mean high priority
+
+#define JOBPRIORITY_DRAWLABEL 0
+#define JOBPRIORITY_DRAWMOUSE 1
+#define JOBPRIORITY_SHOWINVENTORY 2
+#define JOBPRIORITY_DRAWANIMATIONS 3
+#define JOBPRIORITY_RUNSTUFF 15
+#define JOBPRIORITY_ADDREMOVEITEMS 17
+#define JOBPRIORITY_TOGGLEDOOR 18
+#define JOBPRIORITY_WALK 19
+#define JOBPRIORITY_HIDEINVENTORY 20
+#define JOBPRIORITY_ERASEMOUSE 21
+
+enum {
+ kMouseNone = 0,
+ kMouseLeftUp = 1,
+ kMouseLeftDown = 2,
+ kMouseRightUp = 3,
+ kMouseRightDown = 4
+};
+
+
+enum ParallactionGameType {
+ GType_Nippon = 1,
+ GType_BRA
+};
+
+struct PARALLACTIONGameDescription {
+ Common::ADGameDescription desc;
+
+ int gameType;
+ uint32 features;
+};
+
+struct Job;
+typedef void (*JobFn)(void*, Job*);
+
+struct Job {
+ Node _node;
+ uint16 _count; // # of executions left
+ uint16 _tag; // used for ordering
+ uint16 _finished;
+ void * _parm;
+ JobFn _fn;
+};
+
+extern Point _mousePos;
+extern uint16 _mouseButtons;
+
+extern uint16 _score;
+extern uint16 _language;
+extern Zone *_activeZone;
+extern uint32 _engineFlags;
+extern callable _callables[];
+extern Animation _yourself;
+extern Node _zones;
+extern Node _animations;
+extern uint32 _localFlags[];
+extern Command *_forwardedCommands[];
+extern char _forwardedAnimationNames[][20];
+extern uint16 _numForwards;
+extern char _soundFile[];
+extern char _slideText[][40];
+extern uint16 _introSarcData3; // sarcophagus stuff to be saved
+extern uint16 _introSarcData2; // sarcophagus stuff to be saved
+extern char _newLocation[];
+extern char *_globalTable[];
+extern char _saveData1[];
+extern Point _firstPosition; // starting position after load game??
+extern uint16 _firstFrame; // starting frame after load game??
+extern Cnv _characterFace;
+extern byte _mouseHidden;
+extern uint32 _commandFlags;
+extern Cnv _tempFrames;
+
+extern char _location[];
+extern Node _locationWalkNodes;
+extern Command *_locationACommands;
+extern Command *_locationCommands;
+extern char *_locationComment;
+extern char *_locationEndComment;
+
+extern char *_objectsNames[];
+extern char *_zoneTypeNames[];
+extern char *_zoneFlagNames[];
+extern char *_localFlagNames[];
+extern char *commands_names[];
+
+extern char *_instructionNames[];
+extern char *_callableNames[];
+
+void waitUntilLeftClick();
+
+void addNode(Node *list, Node *n);
+void removeNode(Node *n);
+void freeNodeList(Node *list);
+
+Command *parseCommands(ArchivedFile *file);
+void runCommands(Command *list, Zone *z = NULL);
+void freeCommands(Command*);
+
+void freeZones(Node *list);
+
+void freeLocation();
+
+void runDialogue(SpeakData*);
+Dialogue *parseDialogue(ArchivedFile *file);
+
+void changeCharacter(const char *name);
+
+WalkNode *buildWalkPath(uint16 x, uint16 y);
+
+Job *addJob(JobFn fn, void *parm, uint16 tag);
+void removeJob(Job *j);
+void runJobs();
+void pauseJobs();
+void resumeJobs();
+
+void jobRemovePickedItem(void*, Job *j);
+void jobDisplayDroppedItem(void*, Job *j);
+void jobToggleDoor(void*, Job *j);
+void jobEraseAnimations(void *arg_0, Job *j);
+void jobWalk(void*, Job *j);
+void jobRunScripts(void*, Job *j);
+void jobDisplayAnimations(void*, Job *j);
+void jobDisplayLabel(void *parm, Job *j);
+void jobWaitRemoveJob(void *parm, Job *j);
+void jobShowInventory(void *parm, Job *j);
+void jobHideInventory(void *parm, Job *j);
+void jobEraseLabel(void *parm, Job *j);
+
+
+enum EngineFlags {
+ kEngineQuit = (1 << 0),
+ kEnginePauseJobs = (1 << 1),
+ kEngineInventory = (1 << 2),
+ kEngineWalking = (1 << 3),
+ kEngineChangeLocation = (1 << 4),
+ kEngineMouse = (1 << 5),
+ kEngineDragging = (1 << 6),
+ kEngineMiniDonna = (1 << 7)
+};
+
+enum {
+ kEvNone = 0,
+ kEvEnterZone = 1,
+ kEvExitZone = 2,
+ kEvAction = 3,
+ kEvOpenInventory = 4,
+ kEvCloseInventory = 5,
+ kEvHoverInventory = 6,
+ kEvWalk = 7,
+ kEvQuitGame = 1000,
+ kEvSaveGame = 2000,
+ kEvLoadGame = 4000
+};
+
+enum {
+ kCursorArrow = -1
+};
+
+
+
+class Graphics;
+class Menu;
+
+class Parallaction : public Engine {
+
+public:
+
+ Parallaction(OSystem *syst);
+ ~Parallaction();
+
+ int init();
+
+ int go();
+
+
+ void loadGame();
+ void saveGame();
+
+ uint16 updateInput();
+
+ void waitTime(uint32 t);
+
+ void initTable(const char *path, char **table);
+ void freeTable(char** table);
+ int16 searchTable(const char *s, char **table);
+
+ void parseLocation(const char *filename);
+ void changeCursor(int32 index);
+ void changeCharacter(const char *name);
+
+public:
+ int getGameType() const { return _gameDescription->gameType; }
+ uint32 getFeatures() const { return _gameDescription->features; }
+ Common::Language getLanguage() const { return _gameDescription->desc.language; }
+ Common::Platform getPlatform() const { return _gameDescription->desc.platform; }
+
+private:
+ const PARALLACTIONGameDescription *_gameDescription;
+
+public:
+
+ Graphics* _graphics;
+ Menu* _menu;
+ char _characterName[30];
+ char _languageDir[6];
+ char _disk[6];
+
+ char _locationNames[120][32];
+ int16 _currentLocationIndex;
+ uint16 _numLocations;
+
+ InventoryItem _activeItem;
+
+protected: // data
+
+ struct InputData {
+ uint16 _event;
+ Point _mousePos;
+ int32 _data;
+ };
+
+ bool _skipMenu;
+
+ // input-only
+ InputData _input;
+ bool _actionAfterWalk; // actived when the character needs to move before taking an action
+
+ // these two could/should be merged as they carry on the same duty in two member functions,
+ // respectively processInput and translateInput
+ int16 _procCurrentHoverItem;
+ int16 _transCurrentHoverItem;
+
+ uint32 _baseTime;
+
+ uint16 _musicData1; // only used in changeLocation
+ char _characterName1[50]; // only used in changeCharacter
+
+ int16 _keyDown;
+
+protected: // members
+ bool detectGame(void);
+
+ void initGame();
+ void initGlobals();
+
+ void doLoadGame(uint16 _di);
+ void doSaveGame(uint16 _di);
+
+ void runGame();
+ InputData * translateInput();
+ void processInput(InputData*);
+
+ int16 getHoverInventoryItem(int16 x, int16 y);
+
+ uint32 getElapsedTime();
+ void resetTimer();
+
+ void doLocationEnterTransition();
+ void parseZone(ArchivedFile *file, Node *list, char *name);
+ Animation * parseAnimation(ArchivedFile *file, Node *list, char *name);
+ void parseScriptLine(Instruction *inst, Animation *a, LocalVariable *locals);
+ void parseZoneTypeBlock(ArchivedFile *file, Zone *z);
+ void loadProgram(Animation *a, char *filename);
+ void changeLocation(char *location);
+
+};
+
+// FIXME: remove global
+extern Parallaction *_vm;
+
+
+} // namespace Parallaction
+
+
+#endif
diff --git a/engines/parallaction/parser.cpp b/engines/parallaction/parser.cpp
new file mode 100644
index 0000000000..eb943efe41
--- /dev/null
+++ b/engines/parallaction/parser.cpp
@@ -0,0 +1,151 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * 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 "parallaction/defs.h"
+#include "parallaction/parser.h"
+
+
+namespace Parallaction {
+
+char _tokens[20][40];
+static char *_src = NULL;
+
+
+
+void parseInit(char *s) {
+ _src = s;
+}
+
+char *parseNextLine(char *s, uint16 count) {
+
+ uint16 _si;
+ char v2 = 0;
+ for ( _si = 0; _si<count; _si++) {
+
+ v2 = *_src++;
+ if (v2 == 0xA || v2 == -1) break;
+ if (v2 != -1 && _si < count) s[_si] = v2;
+ }
+
+ if (_si == 0 && v2 == -1)
+ return 0;
+
+ s[_si] = 0xA;
+ s[_si+1] = '\0';
+
+ return s;
+}
+
+//
+// a comment can appear both at location and Zone levels
+// comments are displayed into rectangles on the screen
+//
+char *parseComment(ArchivedFile *file) {
+
+ char _tmp_comment[1000] = "\0";
+ char *v194;
+
+ do {
+ char v190[400];
+ v194 = parseNextLine(v190, 400);
+
+ v194[strlen(v194)-1] = '\0';
+ if (!scumm_stricmp(v194, "endtext")) break;
+
+ strcat(_tmp_comment, v194);
+ strcat(_tmp_comment, " ");
+ } while (true);
+
+ v194 = (char*)memAlloc(strlen(_tmp_comment)+1);
+ strcpy(v194, _tmp_comment);
+ _tmp_comment[0] = '\0';
+
+ return v194;
+}
+
+uint16 parseFillBuffers() {
+
+ char tmp[200];
+
+ uint16 _si;
+ for (_si = 0; _si < 20; _si++) _tokens[_si][0] = '\0';
+
+ char *v4;
+ do {
+ v4 = parseNextLine(tmp, 200);
+ if (v4 == NULL) {
+ puts("non ho letto ");
+ exit(0);
+ }
+ v4 = skip_whitespace(v4);
+ } while (strlen(v4) == 0 || v4[0] == '#');
+
+ _si = 0;
+ while (_si < 20 && strlen(v4) > 0) {
+ v4 = parseNextToken(v4, _tokens[_si], 40, " \t\n");
+ if (_tokens[_si][0] == '"' && _tokens[_si][strlen(_tokens[_si]) - 1] != '"') {
+
+ v4 = parseNextToken(v4, _tokens[_si+1], 40, "\"\"\"");
+ strcat(_tokens[_si], _tokens[_si+1]);
+ _tokens[_si][0] = ' ';
+ v4++;
+
+ }
+
+ v4 = skip_whitespace(v4);
+ _si++;
+ }
+
+ return _si;
+}
+
+// looks for next token in a string
+//
+// scans 's' until one of the stop-chars in 'brk' is found
+// builds a token and return the part of the string which hasn't been parsed
+
+char *parseNextToken(char *s, char *tok, uint16 count, const char *brk) {
+
+ while (*s != '\0') {
+
+ if (brk[0] == *s) break;
+ if (brk[1] == *s) break;
+ if (brk[2] == *s) break;
+
+ *tok++ = *s++;
+ }
+
+ *tok = '\0';
+ return s;
+}
+
+
+char *skip_whitespace(char *s) {
+
+ while (*s == 0x20 || *s == 0xA || *s == 0x9) s++;
+
+ return s;
+}
+
+
+
+} // namespace Parallaction
diff --git a/engines/parallaction/parser.h b/engines/parallaction/parser.h
new file mode 100644
index 0000000000..e78d7f5e8b
--- /dev/null
+++ b/engines/parallaction/parser.h
@@ -0,0 +1,43 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * 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_PARSER_H
+#define PARALLACTION_PARSER_H
+
+#include "parallaction/defs.h"
+
+namespace Parallaction {
+
+struct ArchivedFile;
+
+void parseInit(char *s);
+char *parseNextLine(char *s, uint16 count);
+char *parseComment(ArchivedFile *file);
+uint16 parseFillBuffers();
+char *parseNextToken(char *s, char *tok, uint16 count, const char *brk);
+
+extern char _tokens[][40];
+
+} // namespace Parallaction
+
+#endif
+
diff --git a/engines/parallaction/staticres.cpp b/engines/parallaction/staticres.cpp
new file mode 100644
index 0000000000..3a8a6f73d5
--- /dev/null
+++ b/engines/parallaction/staticres.cpp
@@ -0,0 +1,244 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * 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 "parallaction/graphics.h"
+
+namespace Parallaction {
+
+byte Graphics::_mouseArrow[256] = {
+ 0x12, 0x11, 0x11, 0x11, 0x13, 0x12, 0x12, 0x12, 0x13, 0x12, 0x12, 0x11, 0x13, 0x12, 0x12, 0x00,
+ 0x13, 0x12, 0x12, 0x11, 0x13, 0x12, 0x12, 0x12, 0x13, 0x12, 0x12, 0x12, 0x13, 0x12, 0x12, 0x12,
+ 0x13, 0x12, 0x12, 0x12, 0x13, 0x12, 0x12, 0x12, 0x13, 0x12, 0x12, 0x13, 0x13, 0x13, 0x12, 0x00,
+ 0x13, 0x00, 0x12, 0x00, 0x13, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x11, 0x12, 0x12, 0x12, 0x00, 0x12, 0x12, 0x12, 0x00,
+ 0x12, 0x12, 0x12, 0x00, 0x12, 0x12, 0x12, 0x11, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12,
+ 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x13, 0x12, 0x12, 0x12, 0x00, 0x12, 0x12, 0x12, 0x00,
+ 0x13, 0x13, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x00, 0x12, 0x12, 0x12, 0x00, 0x12, 0x12, 0x12, 0x00,
+ 0x12, 0x12, 0x12, 0x00, 0x12, 0x12, 0x12, 0x00, 0x12, 0x12, 0x12, 0x11, 0x12, 0x12, 0x12, 0x12,
+ 0x12, 0x12, 0x12, 0x13, 0x12, 0x12, 0x12, 0x00, 0x12, 0x12, 0x12, 0x00, 0x13, 0x12, 0x12, 0x00,
+ 0x00, 0x12, 0x13, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x11, 0x11, 0x11, 0x00, 0x12, 0x12, 0x12, 0x00, 0x12, 0x12, 0x12, 0x00, 0x12, 0x12, 0x11, 0x00,
+ 0x12, 0x12, 0x12, 0x00, 0x12, 0x12, 0x12, 0x00, 0x12, 0x12, 0x12, 0x00, 0x12, 0x12, 0x12, 0x11,
+ 0x12, 0x12, 0x12, 0x00, 0x12, 0x12, 0x12, 0x00, 0x13, 0x12, 0x12, 0x00, 0x00, 0x12, 0x13, 0x00,
+ 0x00, 0x12, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+
+//
+// proportional font glyphs width
+//
+byte _glyphWidths[126] = {
+ 0x04, 0x03, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x04, 0x04, 0x06, 0x06, 0x03, 0x05, 0x03, 0x05,
+ 0x06, 0x06, 0x06, 0x06, 0x07, 0x06, 0x06, 0x06, 0x06, 0x06, 0x03, 0x03, 0x05, 0x04, 0x05, 0x05,
+ 0x03, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x03, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, 0x07, 0x07, 0x07, 0x05, 0x06, 0x05, 0x08, 0x07,
+ 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x03, 0x04, 0x05, 0x05, 0x06, 0x06, 0x05,
+ 0x05, 0x06, 0x05, 0x05, 0x05, 0x05, 0x06, 0x07, 0x05, 0x05, 0x05, 0x05, 0x02, 0x05, 0x05, 0x07,
+ 0x08, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x04, 0x04, 0x04,
+ 0x05, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x04, 0x06, 0x05, 0x05, 0x05, 0x05
+};
+
+char *_zoneFlagNames[] = {
+ "closed",
+ "active",
+ "remove",
+ "acting",
+ "locked",
+ "fixed",
+ "noname",
+ "nomasked",
+ "looping",
+ "added",
+ "character",
+ "nowalk",
+ 0
+};
+char *_zoneTypeNames[] = {
+ "examine",
+ "door",
+ "get",
+ "merge",
+ "taste",
+ "hear",
+ "feel",
+ "speak",
+ "none",
+ "trap",
+ "yourself",
+ "Command",
+ 0
+};
+
+const char _gameNames[10][20] = {
+ "GAME1",
+ "GAME2",
+ "GAME3",
+ "GAME4",
+ "GAME5",
+ "GAME6",
+ "GAME7",
+ "GAME8",
+ "GAME9",
+ "GAME10"
+};
+
+char *commands_names[] = {
+ "set",
+ "clear",
+ "start",
+ "speak",
+ "get",
+ "location",
+ "open",
+ "close",
+ "on",
+ "off",
+ "call",
+ "toggle",
+ "drop",
+ "quit",
+ "move",
+ "stop",
+ 0
+};
+
+char *_instructionNames[] = {
+ "on",
+ "off",
+ "x",
+ "y",
+ "z",
+ "f",
+ "loop",
+ "endloop",
+ "show",
+ "inc",
+ "dec",
+ "set",
+ "put",
+ "call",
+ "wait",
+ "start",
+ "sound",
+ "move",
+ 0
+};
+
+char *_callableNames[] = {
+ "HBOff",
+ "Projector",
+ "StartIntro",
+ "EndIntro",
+ "MoveSheet",
+ "Sketch",
+ "Shade",
+ "Score",
+ "OffSound",
+ "StartMusic",
+ "CloseMusic",
+ "Fade",
+ "HBOn",
+ "MoveSarc",
+ "ContaFoglie",
+ "ZeroFoglie",
+ "Trasformata",
+ "OffMouse",
+ "OnMouse",
+ "SetMask",
+ "EndComment",
+ "Frankenstain",
+ "Finito",
+ "Ridux",
+ "TestResult",
+ 0
+};
+
+
+void _c_play_boogie(void*);
+void _c_play_boogie(void*);
+void _c_startIntro(void*);
+void _c_endIntro(void*);
+void _c_moveSheet(void*);
+void _c_sketch(void*);
+void _c_shade(void*);
+void _c_score(void*);
+void _c_fade(void*);
+void _c_play_boogie(void*);
+void _c_moveSarc(void*);
+void _c_contaFoglie(void*);
+void _c_zeroFoglie(void*);
+void _c_trasformata(void*);
+void _c_offMouse(void*);
+void _c_onMouse(void*);
+void _c_setMask(void*);
+void _c_endComment(void*);
+void _c_frankenstein(void*);
+void _c_finito(void*);
+void _c_ridux(void*);
+void _c_testResult(void*);
+void _c_null(void*);
+
+typedef void (*callable)(void*);
+
+callable _callables[] = {
+ _c_play_boogie,
+ _c_play_boogie,
+ _c_startIntro,
+ _c_endIntro,
+ _c_moveSheet,
+ _c_sketch,
+ _c_shade,
+ _c_score,
+ _c_null,
+ _c_null,
+ _c_null,
+ _c_fade,
+ _c_play_boogie,
+ _c_moveSarc,
+ _c_contaFoglie,
+ _c_zeroFoglie,
+ _c_trasformata,
+ _c_offMouse,
+ _c_onMouse,
+ _c_setMask,
+ _c_endComment,
+ _c_frankenstein,
+ _c_finito,
+ _c_ridux,
+ _c_testResult
+};
+
+
+Credit _credits[] = {
+ {"Music and Sound Effects", "MARCO CAPRELLI"},
+ {"PC Version", "RICCARDO BALLARINO"},
+ {"Project Manager", "LOVRANO CANEPA"},
+ {"Production", "BRUNO BOZ"},
+ {"Special Thanks to", "LUIGI BENEDICENTI - GILDA and DANILO"},
+ {"Copyright 1992 Euclidea s.r.l ITALY", "All rights reserved"},
+ {"CLICK MOUSE BUTTON TO START", 0}
+};
+
+
+
+} // namespace Parallaction
diff --git a/engines/parallaction/table.cpp b/engines/parallaction/table.cpp
new file mode 100644
index 0000000000..dc0c0a90de
--- /dev/null
+++ b/engines/parallaction/table.cpp
@@ -0,0 +1,134 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * 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/file.h"
+#include "parallaction/parallaction.h"
+#include "parallaction/parser.h"
+#include "parallaction/disk.h"
+
+
+namespace Parallaction {
+
+uint16 tableFillBuffers(Common::SeekableReadStream &stream);
+
+//
+// FIXME
+// this function does the same Job as parseFillBuffers, except that
+// it gets input from a SeekableStream instead of a memory buffer
+//
+uint16 tableFillBuffers(Common::SeekableReadStream &stream) {
+
+ for (uint16 i = 0; i < 20; i++)
+ _tokens[i][0] = '\0';
+
+ char buf[200];
+ char *line = NULL;
+ do {
+ line = stream.readLine(buf, 200);
+ if (line == NULL) return 0;
+
+ line = skip_whitespace(line);
+ } while (strlen(line) == 0 || line[0] == '#');
+
+ uint16 count = 0;
+ while (strlen(line) > 0 && count < 20) {
+ line = parseNextToken(line, _tokens[count], 40, " \t\n");
+ if (_tokens[count][0] == '"' && _tokens[count][strlen(_tokens[count]) - 1] != '"') {
+
+ line = parseNextToken(line, _tokens[count+1], 40, "\"");
+ strcat(_tokens[count], _tokens[count+1] );
+ _tokens[count][0] = ' ';
+ line++;
+
+ }
+
+ line = skip_whitespace(line);
+ count++;
+ }
+
+ return count;
+
+}
+
+void Parallaction::initTable(const char *path, char** table) {
+// printf("initTable(%s)\n", path);
+
+ Common::File stream;
+
+ if (!stream.open(path))
+ errorFileNotFound(path);
+
+ uint16 count = 0;
+
+ tableFillBuffers(stream);
+
+ while (scumm_stricmp(_tokens[0], "ENDTABLE")) {
+
+ table[count] = (char*)memAlloc(strlen(_tokens[0])+1);
+ strcpy(table[count], _tokens[0]);
+
+ count++;
+ tableFillBuffers(stream);
+ }
+
+ table[count] = NULL;
+
+ stream.close();
+
+ return;
+
+}
+
+void Parallaction::freeTable(char** table) {
+
+ uint16 count = 0;
+
+ while (table[count]) {
+
+ memFree(table[count]);
+ table[count] = NULL;
+
+ count++;
+ }
+
+ return;
+
+}
+
+int16 Parallaction::searchTable(const char *s, char **table) {
+
+ int16 count = 0;
+
+ if (!s) return 0;
+
+ while (table[count]) {
+ if (!scumm_stricmp(table[count], s)) return count + 1;
+ count++;
+ }
+
+ return -1;
+}
+
+
+
+} // namespace Parallaction
+
diff --git a/engines/parallaction/walk.cpp b/engines/parallaction/walk.cpp
new file mode 100644
index 0000000000..a44f16aeb5
--- /dev/null
+++ b/engines/parallaction/walk.cpp
@@ -0,0 +1,471 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * 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 "parallaction/defs.h"
+#include "parallaction/parallaction.h"
+#include "parallaction/commands.h"
+#include "parallaction/graphics.h"
+#include "parallaction/zone.h"
+
+namespace Parallaction {
+
+uint16 walkFunc1(int16, int16, WalkNode *);
+uint16 queryPath(uint16 x, uint16 y);
+
+WalkNode _NULL_WALKNODE = { {NULL, NULL}, 0, 0 };
+
+static uint16 _doorData1 = 1000;
+static Zone *_zoneTrap = NULL;
+
+static uint16 walkData1 = 0;
+static uint16 walkData2 = 0; // next walk frame
+static int16 walkData3 = -1000; // unused
+
+
+int32 dotProduct(Point *p1, Point *p2) {
+ return p1->_x * p2->_x + p1->_y * p2->_y;
+}
+
+//
+// x, y: mouse click (foot) coordinates
+//
+WalkNode *buildWalkPath(uint16 x, uint16 y) {
+// printf("buildWalkPath(%i, %i)\n", x, y);
+
+ int16 to_x = x;
+ int16 to_y = y;
+
+ int16 left, bottom, right, top, close, closeY, closeX;
+
+ // looks for closest usable path Point
+ if (queryPath(to_x, to_y) == 0) {
+
+ right = left = to_x;
+
+ do {
+ right++;
+ } while ((queryPath(right, to_y) == 0) && (x < SCREEN_WIDTH));
+
+ do {
+ left--;
+ } while ((queryPath(left, to_y) == 0) && (left > 0));
+
+ right = (right == SCREEN_WIDTH) ? 1000 : right - to_x;
+ left = (left == 0) ? 1000 : to_x - left;
+
+ top = bottom = to_y;
+
+ do {
+ top--;
+ } while ((queryPath(to_x, top) == 0) && (top > 0));
+
+ do {
+ bottom++;
+ } while ((queryPath(to_x, bottom) == 0) && (bottom < SCREEN_HEIGHT));
+
+ top = (top == 0) ? 1000 : to_y - top;
+ bottom = (bottom == SCREEN_HEIGHT) ? 1000 : bottom - to_y;
+
+ closeX = (right >= left) ? left : right;
+ closeY = (top >= bottom) ? bottom : top;
+
+ close = (closeX >= closeY) ? closeY : closeX;
+
+ if (close == right) {
+ to_x += right;
+ walkData3 = (_yourself._cnv._count == 20) ? 7 : 9;
+ } else
+ if (close == left) {
+ to_x -= left;
+ walkData3 = 0;
+ } else
+ if (close == top) {
+ to_y -= top;
+ } else
+ if (close == bottom) {
+ to_y += bottom;
+ walkData3 = (_yourself._cnv._count == 20) ? 17 : 21;
+ }
+
+ }
+// printf("closest path Point: %i, %i\n", to_x, to_y);
+
+
+ WalkNode *v48 = (WalkNode*)memAlloc(sizeof(WalkNode));
+ WalkNode *v44 = (WalkNode*)memAlloc(sizeof(WalkNode));
+
+ v48->_x = to_x - _yourself._cnv._width / 2; // target top left coordinates
+ v48->_y = to_y - _yourself._cnv._height;
+ v48->_node._next = NULL;
+ memcpy(v44, v48, sizeof(WalkNode));
+
+ uint16 v38 = walkFunc1(to_x, to_y, v44);
+ if (v38 == 1) {
+ // destination directly reachable
+// printf("moving to destination (%i, %i)\n", to_x, to_y);
+ memFree(v44);
+ return v48;
+ }
+
+ // path is obstructed: find alternative
+
+ WalkNode v58;
+ memset(&v58, 0, sizeof(WalkNode));
+
+ int16 _si = v48->_x; // _si, _di: target top left coordinates
+ int16 _di = v48->_y;
+ addNode(&v58._node, &v48->_node);
+
+ WalkNode *_closest_node = NULL;
+
+ Point v20;
+ Point v8;
+
+ int32 v30, v34, v2C, v28;
+
+ byte _closest_node_found = 1;
+ bool emptyList = true;
+
+ do {
+
+ v48 = &v58;
+
+ v20._x = _yourself._zone.pos._position._x;
+ v20._y = _yourself._zone.pos._position._y;
+
+ v8._x = _si - _yourself._zone.pos._position._x;
+ v8._y = _di - _yourself._zone.pos._position._y;
+ v34 = v30 = dotProduct(&v8, &v8); // square distance from current position and target
+
+ while (_closest_node_found != 0) {
+
+ _closest_node_found = 0;
+ WalkNode *location_node = (WalkNode*)_locationWalkNodes._next;
+
+ // scans location path nodes searching for the nearest Node
+ // which can't be farther than the target position
+ // otherwise no _closest_node is selected
+ while (location_node != NULL) {
+ v8._x = location_node->_x - _si;
+ v8._y = location_node->_y - _di;
+ v2C = dotProduct(&v8, &v8); // square distance from Node to target position
+
+ v8._x = location_node->_x - v20._x;
+ v8._y = location_node->_y - v20._y;
+ v28 = dotProduct(&v8, &v8); // square distance from Node to current position
+
+ if (v2C < v34 && v28 < v30) {
+ _closest_node_found = 1;
+ v30 = v28;
+ _closest_node = location_node;
+ }
+
+ location_node = (WalkNode*)location_node->_node._next;
+ }
+
+ if (_closest_node_found == 0) break;
+
+ WalkNode *_newnode = (WalkNode*)memAlloc(sizeof(WalkNode));
+ memcpy( _newnode, _closest_node, sizeof(WalkNode));
+ v20._x = _newnode->_x;
+ v20._y = _newnode->_y;
+
+ v34 = v30 = (_si - v20._x) * (_si - v20._x) + (_di - v20._y) * (_di - v20._y);
+
+ addNode(&v48->_node, &_newnode->_node);
+ v48 = _newnode;
+ }
+
+ if (!emptyList) break;
+
+ if (v38 != 0 && v34 > v38) {
+ // no alternative path (gap?)
+ freeNodeList(v58._node._next);
+// printf("can't reach destination, moving to (%i, %i)\n", v44->_x, v44->_y);
+ return v44;
+ } else {
+ _si = ((WalkNode*)(v58._node._next))->_x;
+ _di = ((WalkNode*)(v58._node._next))->_y;
+ emptyList = false;
+ _closest_node_found = 1;
+ }
+
+ } while (true);
+
+ // alternative path exists
+ WalkNode *tmp = (WalkNode*)v58._node._next;
+// printf("moving along path ");
+ while (tmp) {
+// printf(" -> (%i, %i)", tmp->_x, tmp->_y);
+ tmp = (WalkNode*)tmp->_node._next;
+ }
+// printf("\n");
+
+ memFree(v44);
+ return (WalkNode*)v58._node._next;
+}
+
+
+uint16 queryPath(uint16 x, uint16 y) {
+ return _vm->_graphics->queryPath(x, y);
+}
+
+
+//
+// x,y : top left coordinates
+//
+// 0 : Point not reachable
+// 1 : Point reachable
+// other values: square distance to target (not reachable)
+//
+uint16 walkFunc1(int16 x, int16 y, WalkNode *Node) {
+
+ Point v4 = { 0, 0 };
+
+ Point foot = {
+ _yourself._zone.pos._position._x + _yourself._cnv._width/2,
+ _yourself._zone.pos._position._y + _yourself._cnv._height
+ };
+
+ Point v8 = {
+ foot._x,
+ foot._y
+ };
+
+ while (foot._x != x || foot._y != y) {
+
+ if (foot._x < x) {
+ if (queryPath(foot._x + 1, foot._y) != 0) foot._x++;
+ }
+ if (foot._x > x) {
+ if (queryPath(foot._x - 1, foot._y) != 0) foot._x--;
+ }
+ if (foot._y < y) {
+ if (queryPath(foot._x, foot._y + 1) != 0) foot._y++;
+ }
+ if (foot._y > y) {
+ if (queryPath(foot._x, foot._y - 1) != 0) foot._y--;
+ }
+
+ if ((foot._x == v8._x) && (foot._y == v8._y) && ((foot._x != x) || (foot._y != y))) {
+ // foot couldn't move and still away from target
+
+ v4._x = foot._x;
+ v4._y = foot._y;
+
+ while (foot._x != x || foot._y != y) {
+
+ if (foot._x < x) {
+ if (queryPath(foot._x + 1, foot._y) == 0) foot._x++;
+ }
+ if (foot._x > x) {
+ if (queryPath(foot._x - 1, foot._y) == 0) foot._x--;
+ }
+ if (foot._y < y) {
+ if (queryPath(foot._x, foot._y + 1) == 0) foot._y++;
+ }
+ if (foot._y > y) {
+ if (queryPath(foot._x, foot._y - 1) == 0) foot._y--;
+ }
+
+ if ((foot._x == v8._x) && (foot._y == v8._y) && (foot._x != x || foot._y != y))
+ return 0;
+
+ v8._x = foot._x;
+ v8._y = foot._y;
+ }
+
+ Node->_x = v4._x - _yourself._cnv._width / 2;
+ Node->_y = v4._y - _yourself._cnv._height;
+
+ return (x - v4._x) * (x - v4._x) + (y - v4._y) * (y - v4._y);
+ }
+
+ v8._x = foot._x;
+ v8._y = foot._y;
+
+ }
+
+ // there exists an unobstructed path
+ return 1;
+}
+
+
+void jobWalk(void *parm, Job *j) {
+
+ WalkNode *node = (WalkNode*)parm;
+
+ int16 _si = _yourself._zone.pos._position._x;
+ int16 _di = _yourself._zone.pos._position._y;
+
+ _yourself._zone.pos._oldposition._x = _si;
+ _yourself._zone.pos._oldposition._y = _di;
+
+ if ((node->_x == 0) && (node->_y == 0)) {
+ if (node->_node._next == NULL) {
+ j->_finished = 1;
+ checkDoor();
+ memFree(node);
+ return;
+ }
+
+ j->_parm = node->_node._next;
+ memFree(node);
+ node = (WalkNode*)node->_node._next;
+ }
+
+ Point dist = {
+ node->_x - _yourself._zone.pos._position._x,
+ node->_y - _yourself._zone.pos._position._y
+ };
+
+ if (dist._x < 0) dist._x = -dist._x;
+ if (dist._y < 0) dist._y = -dist._y;
+
+ walkData1++;
+
+ // walk frame selection
+ int16 v16;
+ if (_yourself._cnv._count == 20) {
+
+ if (dist._x > dist._y) {
+ walkData2 = (node->_x > _si) ? 0 : 7;
+ walkData1 %= 12;
+ v16 = walkData1 / 2;
+ } else {
+ walkData2 = (node->_y > _di) ? 14 : 17;
+ walkData1 %= 8;
+ v16 = walkData1 / 4;
+ }
+
+ } else {
+
+ if (dist._x > dist._y) {
+ walkData2 = (node->_x > _si) ? 0 : 9;
+ walkData1 %= 16;
+ v16 = walkData1 / 2;
+ } else {
+ walkData2 = (node->_y > _di) ? 18 : 21;
+ walkData1 %= 8;
+ v16 = walkData1 / 4;
+ }
+
+ }
+
+// StaticCnv v14;
+// v14._width = _yourself._cnv._width;
+// v14._height = _yourself._cnv._height;
+// v14._data0 = _yourself._cnv._array[_yourself._frame];
+// v14._data1 = _yourself._cnv.field_8[_yourself._frame];
+// v14._data2 = &_yourself.field_54;
+
+ if ((_si < node->_x) && (_si < SCREEN_WIDTH) && (queryPath(_yourself._cnv._width/2 + _si + 2, _yourself._cnv._height + _di) != 0)) {
+// printf("walk right\n");
+ _si = (_si + 2 < node->_x) ? _si + 2 : node->_x;
+ }
+
+ if ((_si > node->_x) && (_si > -20) && (queryPath(_yourself._cnv._width/2 + _si - 2, _yourself._cnv._height + _di) != 0)) {
+// printf("walk left\n");
+ _si = (_si - 2 > node->_x) ? _si - 2 :node->_x;
+ }
+
+ if ((_di < node->_y) && (_di < (SCREEN_HEIGHT - _yourself._cnv._height)) && (queryPath(_yourself._cnv._width/2 + _si, _yourself._cnv._height + _di + 2) != 0)) {
+// printf("walk down\n");
+ _di = (_di + 2 <= node->_y) ? _di + 2 : node->_y;
+ }
+
+ if ((_di > node->_y) && (_di > -20) && (queryPath(_yourself._cnv._width/2 + _si, _yourself._cnv._height + _di - 2) != 0)) {
+// printf("walk up\n");
+ _di = (_di - 2 >= node->_y) ? _di - 2 : node->_y;
+ }
+
+// printf("hitZone: %i, %i\n", _si, _di);
+ _yourself._zone.pos._position._x = _si;
+ _yourself._zone.pos._position._y = _di;
+
+ if ((_si == _yourself._zone.pos._oldposition._x) && (_di == _yourself._zone.pos._oldposition._y)) {
+
+ j->_finished = 1;
+ checkDoor();
+ freeNodeList(&node->_node);
+
+ } else {
+
+// printf("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n");
+ _yourself._frame = v16 + walkData2 + 1;
+
+ }
+
+ return;
+}
+
+
+uint16 checkDoor() {
+// printf("checkDoor()...");
+
+ if (_vm->_currentLocationIndex != _doorData1) {
+ _doorData1 = _vm->_currentLocationIndex;
+ _zoneTrap = NULL;
+ }
+
+ _engineFlags &= ~kEngineWalking;
+ Zone *z = hitZone(kZoneDoor, _yourself._zone.pos._position._x + _yourself._cnv._width / 2, _yourself._zone.pos._position._y + _yourself._cnv._height);
+
+ if (z != NULL) {
+
+ if ((z->_flags & kFlagsClosed) == 0) {
+ _firstPosition._x = z->u.door->_startPos._x;
+ _firstPosition._y = z->u.door->_startPos._y;
+ _firstFrame = z->u.door->_startFrame;
+ strcpy( _location, z->u.door->_location );
+
+ _engineFlags |= kEngineChangeLocation;
+ _zoneTrap = NULL;
+
+ } else {
+ runCommands(z->_commands, z);
+ }
+ }
+
+ z = hitZone(kZoneTrap, _yourself._zone.pos._position._x + _yourself._cnv._width / 2, _yourself._zone.pos._position._y + _yourself._cnv._height);
+
+ if (z != NULL) {
+ _localFlags[_vm->_currentLocationIndex] |= kFlagsEnter;
+ runCommands(z->_commands, z);
+ _localFlags[_vm->_currentLocationIndex] &= ~kFlagsEnter;
+ _zoneTrap = z;
+ } else
+ if (_zoneTrap != NULL) {
+ _localFlags[_vm->_currentLocationIndex] |= kFlagsExit;
+ runCommands(_zoneTrap->_commands, _zoneTrap);
+ _localFlags[_vm->_currentLocationIndex] &= ~kFlagsExit;
+ _zoneTrap = NULL;
+ }
+
+// printf("done\n");
+
+ _yourself._frame = walkData2;
+ return _yourself._frame;
+}
+
+} // namespace Parallaction
+
diff --git a/engines/parallaction/zone.cpp b/engines/parallaction/zone.cpp
new file mode 100644
index 0000000000..b5eebbba2e
--- /dev/null
+++ b/engines/parallaction/zone.cpp
@@ -0,0 +1,673 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * 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 "parallaction/parser.h"
+#include "parallaction/parallaction.h"
+#include "parallaction/graphics.h"
+#include "parallaction/inventory.h"
+#include "parallaction/zone.h"
+
+namespace Parallaction {
+
+void freeScript(Program*);
+
+void freeDialogue(Dialogue *d);
+
+Node _zones = { NULL, NULL };
+Node _animations = { NULL, NULL };
+
+Zone *findZone(const char *name) {
+
+ Zone *v4 = (Zone*)_zones._next;
+
+ while (v4) {
+ if (!scumm_stricmp(name, v4->_name)) return v4;
+ v4 = (Zone*)v4->_node._next;
+ }
+
+ Animation *a = findAnimation(name);
+ return (a == NULL ? NULL : &a->_zone);
+}
+
+
+
+
+void Parallaction::parseZone(ArchivedFile *file, Node *list, char *name) {
+// printf("parseZone(%s)\n", name);
+
+ if (findZone(name)) {
+ while (scumm_stricmp(_tokens[0], "endzone")) {
+ parseFillBuffers();
+ }
+ return;
+ }
+
+ Zone *z = (Zone*)memAlloc(sizeof(Zone));
+ memset(z, 0, sizeof(Zone));
+
+ z->_name = (char*)memAlloc(strlen(name)+1);
+ strcpy(z->_name, name);
+
+ addNode(list, &z->_node);
+
+ parseFillBuffers();
+ while (scumm_stricmp(_tokens[0], "endzone")) {
+// printf("token[0] = %s\n", _tokens[0]);
+
+ if (!scumm_stricmp(_tokens[0], "limits")) {
+ z->_limits._left = atoi(_tokens[1]);
+ z->_limits._top = atoi(_tokens[2]);
+ z->_limits._right = atoi(_tokens[3]);
+ z->_limits._bottom = atoi(_tokens[4]);
+ }
+ if (!scumm_stricmp(_tokens[0], "moveto")) {
+ z->_moveTo._x = atoi(_tokens[1]);
+ z->_moveTo._y = atoi(_tokens[2]);
+ }
+ if (!scumm_stricmp(_tokens[0], "type")) {
+ if (_tokens[2][0] != '\0') {
+ z->_type = (4 + searchTable(_tokens[2], _objectsNames)) << 16;
+ }
+ int16 _si = searchTable(_tokens[1], _zoneTypeNames);
+ if (_si != -1) {
+ z->_type |= 1 << (_si - 1);
+ parseZoneTypeBlock(file, z);
+ continue;
+ }
+ }
+ if (!scumm_stricmp(_tokens[0], "commands")) {
+ z->_commands = parseCommands(file);
+ }
+ if (!scumm_stricmp(_tokens[0], "label")) {
+// printf("label: %s\n", _tokens[1]);
+ _vm->_graphics->makeCnvFromString(&z->_label, _tokens[1]);
+ }
+ if (!scumm_stricmp(_tokens[0], "flags")) {
+ uint16 _si = 1;
+
+ do {
+ char _al = searchTable(_tokens[_si], _zoneFlagNames);
+ _si++;
+ z->_flags |= 1 << (_al - 1);
+ } while (!scumm_stricmp(_tokens[_si++], "|"));
+ }
+
+ parseFillBuffers();
+ }
+
+ return;
+}
+
+void freeZones(Node *list) {
+
+ Zone *z = (Zone*)list;
+ Zone *v8 = NULL;
+
+ Node nullNode = { 0, 0 };
+
+ for (; z; z=(Zone*)z->_node._next) {
+
+ // TODO: understand and simplify this monster
+ if (((z->_limits._top == -1) || ((z->_limits._left == -2) && ((isItemInInventory(z->u.merge->_obj1) != 0) || (isItemInInventory(z->u.merge->_obj2) != 0)))) &&
+ (_engineFlags & kEngineQuit) == 0) {
+
+ v8 = (Zone*)z->_node._next;
+ removeNode(&z->_node);
+ addNode(&nullNode, &z->_node);
+ z = v8;
+ continue;
+ }
+
+
+ switch (z->_type & 0xFFFF) {
+ case kZoneExamine:
+ memFree(z->u.examine->_filename);
+ memFree(z->u.examine->_description);
+ memFree(z->u.examine);
+ break;
+
+ case kZoneDoor:
+ memFree(z->u.door->_location);
+ memFree(z->u.door->_background);
+ _vm->_graphics->freeCnv(&z->u.door->_cnv);
+ memFree(z->u.door);
+ break;
+
+ case kZoneSpeak:
+ freeDialogue(z->u.speak->_dialogue);
+ memFree(z->u.speak);
+ break;
+
+ case kZoneGet:
+ memFree(z->u.get->_cnv._data2);
+ _vm->_graphics->freeStaticCnv(&z->u.get->_cnv);
+ memFree(z->u.get);
+ break;
+
+ case kZoneHear:
+ memFree(z->u.hear);
+ break;
+
+ case kZoneMerge:
+ memFree(z->u.merge);
+ break;
+
+ default:
+ break;
+ }
+
+ memFree(z->_name);
+ _vm->_graphics->freeStaticCnv(&z->_label);
+ freeCommands(z->_commands);
+
+ }
+
+ return;
+}
+
+
+
+
+
+
+
+
+
+void Parallaction::parseZoneTypeBlock(ArchivedFile *file, Zone *z) {
+// printf("parseZoneTypeBlock()\n");
+
+ ZoneTypeData *u = &z->u;
+
+ switch (z->_type & 0xFFFF) {
+ case kZoneExamine: // examine Zone alloc
+ u->examine = (ExamineData*)memAlloc(sizeof(ExamineData));
+ memset(u->examine, 0, sizeof(ExamineData));
+ break;
+
+ case kZoneDoor: // door Zone alloc
+ u->door = (DoorData*)memAlloc(sizeof(DoorData));
+ memset(u->door, 0, sizeof(DoorData));
+ break;
+
+ case kZoneGet: // get Zone alloc
+ u->get = (GetData*)memAlloc(sizeof(GetData));
+ memset(u->get, 0, sizeof(GetData));
+ break;
+
+ case kZoneMerge: // merge Zone alloc
+ u->merge = (MergeData*)memAlloc(sizeof(MergeData));
+ memset(u->merge, 0, sizeof(MergeData));
+ break;
+
+ case kZoneHear: // hear Zone alloc
+ u->hear = (HearData*)memAlloc(sizeof(HearData));
+ memset(u->hear, 0, sizeof(HearData));
+ break;
+
+ case kZoneSpeak: // speak Zone alloc
+ u->speak = (SpeakData*)memAlloc(sizeof(SpeakData));
+ memset(u->speak, 0, sizeof(SpeakData));
+ break;
+
+ }
+
+ char vC8[PATH_LEN];
+
+// printf("type = %x\n", z->_type);
+
+ do {
+
+ switch (z->_type & 0xFFFF) {
+ case kZoneExamine: // examine Zone init
+ if (!scumm_stricmp(_tokens[0], "file")) {
+ u->examine->_filename = (char*)memAlloc(strlen(_tokens[1])+1);
+ strcpy(u->examine->_filename, _tokens[1]);
+ }
+ if (!scumm_stricmp(_tokens[0], "desc")) {
+ u->examine->_description = parseComment(file);
+ }
+ 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 = (char*)memAlloc(strlen(_tokens[1])+1);
+ strcpy(u->door->_location, _tokens[1]);
+ }
+
+ if (!scumm_stricmp(_tokens[0], "file")) {
+// printf("file: '%s'\n", _tokens[0]);
+
+ Cnv *doorcnv = &u->door->_cnv;
+ strcpy(vC8, _tokens[1]);
+
+ StaticCnv vE0;
+ _vm->_graphics->loadCnv(vC8, doorcnv);
+
+// printf("door width: %i, height: %i\n", doorcnv->_width, doorcnv->_height );
+
+ vE0._width = doorcnv->_width;
+ vE0._height = doorcnv->_height;
+
+ uint16 _ax = (z->_flags & kFlagsClosed ? 0 : 1);
+ vE0._data0 = doorcnv->_array[_ax];
+
+// _ax = (z->_flags & kFlagsClosed ? 0 : 1);
+// vE0._data1 = doorcnv->field_8[_ax];
+
+ vE0._data2 = u->door->_background = (byte*)memAlloc(vE0._width*vE0._height);
+ _vm->_graphics->backupCnvBackground(&vE0, z->_limits._left, z->_limits._top);
+
+ _vm->_graphics->flatBlitCnv(&vE0, z->_limits._left, z->_limits._top, Graphics::kBitBack, vE0._data1);
+ }
+
+ 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")) {
+ StaticCnv *vE4 = &u->get->_cnv;
+ strcpy(vC8, _tokens[1]);
+ _vm->_graphics->loadStaticCnv(vC8, vE4);
+ vE4->_data2 = (byte*)memAlloc(vE4->_width*vE4->_height);
+
+ if ((z->_flags & kFlagsRemove) == 0) {
+ _vm->_graphics->backupCnvBackgroundTransparent(vE4, z->_limits._left, z->_limits._top);
+ _vm->_graphics->flatBlitCnv(vE4, z->_limits._left, z->_limits._top, Graphics::kBitBack, vE4->_data1);
+ }
+ }
+
+ if (!scumm_stricmp(_tokens[0], "icon")) {
+ u->get->_icon = 4 + searchTable(_tokens[1], _objectsNames);
+ }
+ break;
+
+ case kZoneMerge: // merge Zone init
+ if (!scumm_stricmp(_tokens[0], "obj1")) {
+ u->merge->_obj1 = 4 + searchTable(_tokens[1], _objectsNames);
+ }
+ if (!scumm_stricmp(_tokens[0], "obj2")) {
+ u->merge->_obj2 = 4 + searchTable(_tokens[1], _objectsNames);
+ }
+ if (!scumm_stricmp(_tokens[0], "newobj")) {
+ u->merge->_obj3 = 4 + searchTable(_tokens[1], _objectsNames);
+ }
+ break;
+
+ case kZoneHear: // hear Zone init
+ if (!scumm_stricmp(_tokens[0], "sound")) {
+ strcpy(u->hear->_name, _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\n", u.speak._name);
+ }
+ if (!scumm_stricmp(_tokens[0], "Dialogue")) {
+ u->speak->_dialogue = parseDialogue(file);
+ }
+ break;
+ }
+
+ parseFillBuffers();
+ } while (scumm_stricmp(_tokens[0], "endzone"));
+
+ return;
+}
+
+// displays character head commenting an examined object
+//
+// works on the frontbuffer
+//
+void displayCharacterComment(ExamineData *data) {
+ if (data->_description == NULL) return;
+
+// printf("displayCharacterComment()...");
+
+ char v20[20];
+ char *v24 = _vm->_characterName;
+ if (!scumm_strnicmp(v24, "mini", 4)) {
+ v24 += 4;
+ }
+ strcpy(v20, v24);
+
+ if (_engineFlags & kEngineMiniDonna) {
+ sprintf(v20, "%stta", v24);
+ } else {
+ sprintf(v20, "%stal", v24);
+ }
+
+ _vm->_graphics->loadExternalCnv(v20, &_characterFace);
+
+ StaticCnv v3C;
+ v3C._width = _characterFace._width;
+ v3C._height = _characterFace._height;
+ v3C._data0 = _characterFace._array[0];
+// v3C._data1 = _characterFace.field_8[0];
+
+ _vm->_graphics->loadExternalCnv("comiccnv", &Graphics::_font);
+ _vm->_graphics->flatBlitCnv(&v3C, 190, 80, Graphics::kBitFront, v3C._data1);
+
+ int16 v26, v28;
+ _vm->_graphics->getStringExtent(data->_description, 130, &v28, &v26);
+ _vm->_graphics->drawBalloon(140, 10, v28, v26, 0);
+ _vm->_graphics->displayWrappedString(data->_description, 140, 10, 130, 0);
+
+ _vm->_graphics->freeCnv(&Graphics::_font);
+
+// printf("wait left\n");
+
+ waitUntilLeftClick();
+
+ _vm->_graphics->copyScreen(Graphics::kBitBack, Graphics::kBitFront);
+ _vm->_graphics->freeCnv(&_characterFace);
+
+// printf("done\n");
+
+
+ return;
+}
+
+//
+// ZONE TYPE: EXAMINE
+//
+
+// display detail view of an item (and eventually comments)
+//
+// works on the frontbuffer
+//
+
+void displayItemComment(ExamineData *data) {
+
+ if (data->_description == NULL) return;
+
+// printf("displayItemComment()...");
+
+ char v68[PATH_LEN];
+ strcpy(v68, data->_filename);
+ _vm->_graphics->loadStaticCnv(v68, &data->_cnv);
+ _vm->_graphics->flatBlitCnv(&data->_cnv, 140, (SCREEN_HEIGHT - data->_cnv._height)/2, Graphics::kBitFront, data->_cnv._data1);
+ _vm->_graphics->freeStaticCnv(&data->_cnv);
+
+ char *v4 = _vm->_characterName;
+ if (!scumm_strnicmp(v4, "mini", 4)) {
+ v4 += 4;
+ }
+
+ StaticCnv cnv;
+
+ sprintf(v68, "%shead", v4);
+
+ // WORKAROUND
+ // dos file names are in 8.3 format
+ v68[8] = '\0';
+
+ _vm->_graphics->loadExternalStaticCnv(v68, &cnv);
+
+ int16 v6A = 0, v6C = 0;
+
+ _vm->_graphics->loadExternalCnv("comiccnv", &Graphics::_font);
+ _vm->_graphics->getStringExtent(data->_description, 130, &v6C, &v6A);
+ _vm->_graphics->drawBalloon(0, 90, v6C, v6A, 0);
+ _vm->_graphics->flatBlitCnv(&cnv, 100, 152, Graphics::kBitFront, cnv._data1);
+ _vm->_graphics->freeStaticCnv(&cnv);
+ _vm->_graphics->displayWrappedString(data->_description, 0, 90, 130, 0);
+ _vm->_graphics->freeCnv(&Graphics::_font);
+
+ jobEraseAnimations((void*)1, NULL);
+
+ waitUntilLeftClick();
+
+ _vm->_graphics->copyScreen(Graphics::kBitBack, Graphics::kBitFront);
+
+// printf("done\n");
+
+ return;
+}
+
+
+
+uint16 runZone(Zone *z) {
+// printf("runZone('%s')\n", z->_name);
+
+ uint16 subtype = z->_type & 0xFFFF;
+
+// printf("subtype = %x, objecttype = %x\n", 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._count == 0) break;
+ addJob(jobToggleDoor, z, JOBPRIORITY_TOGGLEDOOR);
+ break;
+
+ case kZoneHear:
+ strcpy(_soundFile, z->u.hear->_name);
+ break;
+
+ case kZoneSpeak:
+ runDialogue(z->u.speak);
+ break;
+
+ }
+
+// printf("done executing Zone\n");
+
+ return 0;
+}
+
+//
+// ZONE TYPE: DOOR
+//
+void jobToggleDoor(void *parm, Job *j) {
+
+ static byte count = 0;
+
+ Zone *z = (Zone*)parm;
+
+ Cnv *v18 = &z->u.door->_cnv;
+ StaticCnv v14;
+
+ if (v18) {
+ v14._data2 = z->u.door->_background;
+// v4 = &z->u.door._background;
+
+ v14._width = v18->_width;
+ v14._height = v18->_height;
+ _vm->_graphics->restoreCnvBackground(&v14, z->_limits._left, z->_limits._top);
+
+ uint16 _ax = (z->_flags & kFlagsClosed ? 0 : 1);
+
+ v14._data0 = v18->_array[_ax];
+
+ _vm->_graphics->flatBlitCnv(&v14, z->_limits._left, z->_limits._top, Graphics::kBitBack, v14._data1);
+ _vm->_graphics->flatBlitCnv(&v14, z->_limits._left, z->_limits._top, Graphics::kBit2, v14._data1);
+ }
+
+ count++;
+ if (count == 2) {
+ j->_finished = 1;
+ count = 0;
+ }
+
+ return;
+}
+
+
+
+
+
+
+//
+// ZONE TYPE: GET
+//
+
+void jobRemovePickedItem(void *parm, Job *j) {
+
+ Zone *z = (Zone*)parm;
+
+ static uint16 count = 0;
+
+ if (z->u.get->_cnv._width != 0) {
+ _vm->_graphics->restoreCnvBackground(&z->u.get->_cnv, z->_limits._left, z->_limits._top);
+ }
+
+ count++;
+ if (count == 2) {
+ count = 0;
+ j->_finished = 1;
+ }
+
+ return;
+}
+
+void jobDisplayDroppedItem(void *parm, Job *j) {
+// printf("jobDisplayDroppedItem...\n");
+
+ Zone *z = (Zone*)parm;
+
+ if (&z->u.get->_cnv != NULL) {
+ if (z->u.get->_cnv._data0 != NULL) {
+ _vm->_graphics->backupCnvBackgroundTransparent(&z->u.get->_cnv, z->_limits._left, z->_limits._top);
+ }
+
+ _vm->_graphics->flatBlitCnv(&z->u.get->_cnv, z->_limits._left, z->_limits._top, Graphics::kBitBack, z->u.get->_cnv._data1);
+ _vm->_graphics->flatBlitCnv(&z->u.get->_cnv, z->_limits._left, z->_limits._top, Graphics::kBit2, z->u.get->_cnv._data1);
+ }
+
+ j->_count++;
+ if (j->_count == 2) {
+ j->_count = 0;
+ j->_finished = 1;
+ }
+
+// printf("done\n");
+
+ return;
+}
+
+
+
+
+Zone *hitZone(uint32 type, uint16 x, uint16 y) {
+// printf("hitZone(%i, %i, %i)\n", type, x, y);
+
+ uint16 _di = y;
+ uint16 _si = x;
+ Zone *z = (Zone*)_zones._next;
+
+ for (; z; z = (Zone*)z->_node._next) {
+// printf("Zone name: %s\n", z->_name);
+
+ if (z->_flags & kFlagsRemove) continue;
+
+ if ((_si >= z->_limits._right) ||
+ (_si <= z->_limits._left) ||
+ (_di >= z->_limits._bottom) ||
+ (_di <= z->_limits._top)) {
+
+ // out of Zone, so look for special values
+ if ((z->_limits._left == -2) || (z->_limits._left == -3)) {
+ // only merge zones have _left == -2 or _left == -3
+
+ if (((_si == z->u.merge->_obj1) && (_di == z->u.merge->_obj2)) ||
+ ((_si == z->u.merge->_obj2) && (_di == z->u.merge->_obj1))) {
+
+ // 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->_limits._left != -1) continue;
+ if (_si < _yourself._zone.pos._position._x) continue;
+ if (_si > (_yourself._zone.pos._position._x + _yourself._cnv._width)) continue;
+ if (_di < _yourself._zone.pos._position._y) continue;
+ if (_di > (_yourself._zone.pos._position._y + _yourself._cnv._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;
+
+ }
+
+ Animation *a = (Animation*)_animations._next;
+
+ int16 _a, _b, _c, _d, _e, _f;
+ for (; a; a = (Animation*)a->_zone._node._next) {
+// printf("Animation name: %s\n", a->_zone._name);
+
+ _a = (a->_zone._flags & kFlagsActive) ? 1 : 0; // _a: active Animation
+ _e = ((_si >= a->_zone.pos._position._x + a->_cnv._width) || (_si <= a->_zone.pos._position._x)) ? 0 : 1; // _e: horizontal range
+ _f = ((_di >= a->_zone.pos._position._y + a->_cnv._height) || (_di <= a->_zone.pos._position._y)) ? 0 : 1; // _f: vertical range
+
+ _b = ((type != 0) || (a->_zone._type == kZoneYou)) ? 0 : 1; // _b: (no type specified) AND (Animation is not the character)
+ _c = (a->_zone._type & 0xFFFF0000) ? 0 : 1; // _c: Animation is not an object
+ _d = ((a->_zone._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->_zone._type == type) || (_d != 0))) {
+
+ return &a->_zone;
+
+ }
+
+ }
+
+ return NULL;
+
+}
+
+} // namespace Parallaction
diff --git a/engines/parallaction/zone.h b/engines/parallaction/zone.h
new file mode 100644
index 0000000000..761af51353
--- /dev/null
+++ b/engines/parallaction/zone.h
@@ -0,0 +1,225 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * 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_ZONE_H
+#define PARALLACTION_ZONE_H
+
+#include "parallaction/defs.h"
+
+namespace Parallaction {
+
+enum ZoneTypes {
+ kZoneExamine = 1, // zone displays comment if activated
+ kZoneDoor = 2, // zone activated on click (after some walk if needed)
+ kZoneGet = 4, // for pickable items
+ kZoneMerge = 8, // tags items which can be merged in inventory
+ kZoneTaste = 0x10, // NEVER USED
+ kZoneHear = 0x20, // NEVER USED: they ran out of time before integrating sfx
+ kZoneFeel = 0x40, // NEVER USED
+ kZoneSpeak = 0x80, // tags NPCs the character can talk with
+ kZoneNone = 0x100, // used to prevent parsing on peculiar Animations
+ kZoneTrap = 0x200, // zone activated when character enters
+ kZoneYou = 0x400, // marks the character
+ kZoneCommand = 0x800
+};
+
+
+enum ZoneFlags {
+ kFlagsClosed = 1, // Zone: door is closed / switch is off
+ kFlagsActive = 2, // Zone/Animation: object is visible
+ kFlagsRemove = 4, // Zone/Animation: object is soon to be removed
+ kFlagsActing = 8, // Animation: script execution is active
+ kFlagsLocked = 0x10, // Zone: door or switch cannot be toggled
+ kFlagsFixed = 0x20, // Zone: Zone item cannot be picked up
+ kFlagsNoName = 0x40, // Zone with no name (used to prevent some kEvEnterZone events)
+ kFlagsNoMasked = 0x80, // Animation is to be drawn ignoring z buffer
+ kFlagsLooping = 0x100, // Animation: script is to be executed repeatedly
+ kFlagsAdded = 0x200, // NEVER USED in Nippon Safes
+ kFlagsCharacter = 0x400, //
+ kFlagsNoWalk = 0x800 // Zone: character doesn't need to walk towards object to interact
+};
+
+
+
+
+struct Question {
+ char* _text;
+ char* _answers[5];
+ uint16 _mood;
+ uint16 _answer_moods[5];
+ union {
+ Question* _questions[5];
+ char* _names[5];
+ } _following;
+ Command* _commands[5];
+ uint32 _noFlags[5];
+ uint32 _yesFlags[5];
+};
+
+struct GetData { // size = 24
+ uint32 _icon;
+ StaticCnv _cnv;
+ uint16 field_14; // unused
+ uint16 field_16; // unused
+};
+struct SpeakData { // size = 36
+ char _name[32];
+ Dialogue *_dialogue;
+};
+struct ExamineData { // size = 28
+ StaticCnv _cnv;
+ uint16 _opBase; // unused
+ uint16 field_12; // unused
+ char* _description;
+ char* _filename;
+};
+struct DoorData { // size = 28
+ char* _location;
+ Cnv _cnv;
+ byte* _background;
+ Point _startPos;
+ uint16 _startFrame;
+};
+struct HearData { // size = 20
+ char _name[20];
+};
+struct MergeData { // size = 12
+ uint32 _obj1;
+ uint32 _obj2;
+ uint32 _obj3;
+};
+
+struct ZoneTypeData {
+ GetData *get;
+ SpeakData *speak;
+ ExamineData *examine;
+ DoorData *door;
+ HearData *hear;
+ MergeData *merge;
+};
+
+
+
+
+struct Zone {
+ Node _node;
+ union {
+ Rect _limits; // for zones
+ struct { // for animations
+ Point _position;
+ Point _oldposition;
+ } pos;
+ };
+ uint32 _type;
+ uint32 _flags;
+ char* _name;
+ StaticCnv _label;
+ uint16 field_2C; // unused
+ uint16 field_2E; // unused
+ ZoneTypeData u;
+ Command *_commands;
+ Point _moveTo;
+};
+
+struct LocalVariable {
+ int16 _value;
+ int16 _min;
+ int16 _max;
+};
+
+union LValue {
+ int16 _value;
+ int16* _pvalue;
+ LocalVariable* _local;
+};
+
+enum InstructionFlags {
+ kInstUsesLiteral = 1,
+ kInstUsesLocal = 2,
+ kInstMod = 4,
+ kInstMaskedPut = 8
+};
+
+struct Instruction {
+ Node _node;
+ uint32 _index;
+ uint32 _flags;
+ union {
+ Animation *_a;
+ Zone *_z;
+ uint32 _index;
+ LValue _loopCounter;
+ } _opBase;
+ LValue _opA;
+ LValue _opB;
+};
+
+
+struct Program {
+ Node _node;
+ LocalVariable *_locals;
+ uint16 _loopCounter;
+ Instruction *_ip;
+ Instruction *_loopStart;
+};
+
+
+
+struct Animation {
+ Zone _zone;
+ Program *_program;
+ Cnv _cnv;
+ int16 _frame;
+ uint16 field_50; // unused
+ int16 _z;
+ uint16 field_54; // unused
+ uint16 field_56; // unused
+ uint16 field_58; // unused
+ uint16 field_5A; // unused
+ uint16 field_5C; // unused
+ uint16 field_5E; // unused
+};
+
+extern Node _zones;
+extern Node _animations;
+
+
+Zone *findZone(const char *name);
+uint16 runZone(Zone *z);
+void dropItem(uint16 v);
+int16 pickupItem(Zone *z);
+
+void parseZone(ArchivedFile *file, Node *list, char *name);
+void parseZoneTypeBlock(ArchivedFile *file, Zone *z);
+
+Zone *hitZone(uint32 type, uint16 x, uint16 y);
+uint16 checkDoor();
+
+
+Animation *findAnimation(const char *name);
+void loadProgram(Animation *, char *filename);
+int16 queryBackgroundLayer(int16 v);
+
+
+} // namespace Parallaction
+
+#endif