diff options
author | Eugene Sandulenko | 2007-01-14 21:29:12 +0000 |
---|---|---|
committer | Eugene Sandulenko | 2007-01-14 21:29:12 +0000 |
commit | e5c7ce83b8c7bb5f7d64c53fa8dcc378f667e902 (patch) | |
tree | b9fa4e43e98a703bb60ef9a375c39d3579f610fd /engines | |
parent | 549f818e3195136ee3fbd7cd7e474f5932deb529 (diff) | |
download | scummvm-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')
32 files changed, 9897 insertions, 0 deletions
diff --git a/engines/engines.mk b/engines/engines.mk index a00b509d02..c291a335c8 100644 --- a/engines/engines.mk +++ b/engines/engines.mk @@ -84,3 +84,9 @@ DEFINES += -DDISABLE_TOUCHE else MODULES += engines/touche endif + +ifdef DISABLE_PARALLACTION +DEFINES += -DDISABLE_PARALLACTION +else +MODULES += engines/parallaction +endif 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 |