From e5c7ce83b8c7bb5f7d64c53fa8dcc378f667e902 Mon Sep 17 00:00:00 2001 From: Eugene Sandulenko Date: Sun, 14 Jan 2007 21:29:12 +0000 Subject: Initial import of Parallaction engine svn-id: r25083 --- engines/parallaction/animation.cpp | 728 +++++++++++++++++++++++++++++++++++++ 1 file changed, 728 insertions(+) create mode 100644 engines/parallaction/animation.cpp (limited to 'engines/parallaction/animation.cpp') 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 -- cgit v1.2.3