aboutsummaryrefslogtreecommitdiff
path: root/engines/toon
diff options
context:
space:
mode:
Diffstat (limited to 'engines/toon')
-rw-r--r--engines/toon/anim.cpp738
-rw-r--r--engines/toon/anim.h196
-rw-r--r--engines/toon/audio.cpp629
-rw-r--r--engines/toon/audio.h177
-rw-r--r--engines/toon/character.cpp1043
-rw-r--r--engines/toon/character.h148
-rw-r--r--engines/toon/conversation.cpp49
-rw-r--r--engines/toon/conversation.h50
-rw-r--r--engines/toon/detection.cpp273
-rw-r--r--engines/toon/drew.cpp122
-rw-r--r--engines/toon/drew.h51
-rw-r--r--engines/toon/flux.cpp140
-rw-r--r--engines/toon/flux.h52
-rw-r--r--engines/toon/font.cpp285
-rw-r--r--engines/toon/font.h53
-rw-r--r--engines/toon/hotspot.cpp157
-rw-r--r--engines/toon/hotspot.h73
-rw-r--r--engines/toon/module.mk30
-rw-r--r--engines/toon/movie.cpp114
-rw-r--r--engines/toon/movie.h61
-rw-r--r--engines/toon/path.cpp370
-rw-r--r--engines/toon/path.h93
-rw-r--r--engines/toon/picture.cpp296
-rw-r--r--engines/toon/picture.h66
-rw-r--r--engines/toon/resource.cpp215
-rw-r--r--engines/toon/resource.h82
-rw-r--r--engines/toon/script.cpp504
-rw-r--r--engines/toon/script.h153
-rw-r--r--engines/toon/script_func.cpp1186
-rw-r--r--engines/toon/script_func.h174
-rw-r--r--engines/toon/state.cpp261
-rw-r--r--engines/toon/state.h101
-rw-r--r--engines/toon/text.cpp95
-rw-r--r--engines/toon/text.h51
-rw-r--r--engines/toon/tools.cpp516
-rw-r--r--engines/toon/tools.h83
-rw-r--r--engines/toon/toon.cpp4548
-rw-r--r--engines/toon/toon.h424
38 files changed, 13659 insertions, 0 deletions
diff --git a/engines/toon/anim.cpp b/engines/toon/anim.cpp
new file mode 100644
index 0000000000..53980e3dc1
--- /dev/null
+++ b/engines/toon/anim.cpp
@@ -0,0 +1,738 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "toon/anim.h"
+#include "toon/toon.h"
+#include "toon/tools.h"
+
+namespace Toon {
+
+bool Animation::loadAnimation(Common::String file) {
+ debugC(1, kDebugAnim, "loadAnimation(%s)", file.c_str());
+
+ uint32 fileSize = 0;
+ uint8 *fileData = _vm->resources()->getFileData(file, &fileSize);
+ if (!fileData)
+ return false;
+
+ strcpy(_name, "not_loaded");
+ if (strncmp((char *)fileData, "KevinAguilar", 12))
+ return false;
+
+ strcpy(_name, file.c_str());
+
+ uint32 headerSize = READ_LE_UINT32(fileData + 16);
+ uint32 uncompressedBytes = READ_LE_UINT32(fileData + 20);
+ uint32 compressedBytes = READ_LE_UINT32(fileData + 24);
+ _numFrames = READ_LE_UINT32(fileData + 28);
+ _x1 = READ_LE_UINT32(fileData + 32);
+ _y1 = READ_LE_UINT32(fileData + 36);
+ _x2 = READ_LE_UINT32(fileData + 40);
+ _y2 = READ_LE_UINT32(fileData + 44);
+ _paletteEntries = READ_LE_UINT32(fileData + 56);
+ _fps = READ_LE_UINT32(fileData + 60);
+ uint32 paletteSize = READ_LE_UINT32(fileData + 64);
+
+ uint8 *currentData = fileData + 68;
+ if (_paletteEntries) {
+ if (paletteSize) {
+ _palette = new uint8[paletteSize];
+ memcpy(_palette, currentData, paletteSize);
+ currentData += paletteSize;
+ } else {
+ _palette = 0;
+ }
+ }
+
+ byte *finalBuffer = new byte[uncompressedBytes];
+ if (uncompressedBytes > compressedBytes)
+ decompressLZSS(currentData, finalBuffer, uncompressedBytes);
+ else
+ memcpy(finalBuffer, currentData, uncompressedBytes);
+
+ if (READ_LE_UINT32(finalBuffer) == 0x12345678) {
+ uint8 *data = finalBuffer;
+ _frames = new AnimationFrame[_numFrames];
+ for (int32 e = 0; e < _numFrames; e++) {
+ if (READ_LE_UINT32(data) != 0x12345678)
+ return false;
+
+ int32 oldRef = READ_LE_UINT32(data + 4);
+ uint32 compressedSize = READ_LE_UINT32(data + 8);
+ uint32 decompressedSize = READ_LE_UINT32(data + 12);
+
+ _frames[e]._x1 = READ_LE_UINT32(data + 16);
+ _frames[e]._y1 = READ_LE_UINT32(data + 20);
+ _frames[e]._x2 = READ_LE_UINT32(data + 24);
+ _frames[e]._y2 = READ_LE_UINT32(data + 28);
+
+ uint8 *imageData = data + headerSize;
+ if (oldRef != -1 || decompressedSize == 0) {
+ _frames[e]._ref = oldRef;
+ _frames[e]._data = 0;
+ } else {
+ _frames[e]._ref = -1;
+ _frames[e]._data = new uint8[decompressedSize];
+ if (compressedSize < decompressedSize) {
+ decompressLZSS(imageData, _frames[e]._data, decompressedSize);
+ } else {
+ memcpy(_frames[e]._data, imageData, compressedSize);
+ }
+ }
+
+ data += headerSize + compressedSize;
+ }
+ }
+
+ delete[] finalBuffer;
+ return true;
+}
+
+Animation::Animation(ToonEngine *vm) : _vm(vm) {
+ _palette = 0;
+ _frames = 0;
+}
+
+Animation::~Animation() {
+ delete[] _palette;
+ for (int32 i = 0; i < _numFrames; i++) {
+ delete[] _frames[i]._data;
+ }
+ delete[] _frames;
+}
+
+Common::Rect Animation::getRect() {
+ debugC(5, kDebugAnim, "getRect");
+ return Common::Rect(_x1, _y1, _x2, _y2);
+}
+
+void Animation::drawFrame(Graphics::Surface &surface, int32 frame, int32 xx, int32 yy) {
+ debugC(3, kDebugAnim, "drawFrame(surface, %d, %d, %d)", frame, xx, yy);
+ if (frame < 0)
+ frame = 0;
+
+ if (frame >= _numFrames)
+ frame = _numFrames - 1;
+
+ if (_numFrames == 0)
+ return;
+
+ if (_frames[frame]._ref != -1)
+ frame = _frames[frame]._ref;
+
+ int32 rectX = _frames[frame]._x2 - _frames[frame]._x1;
+ int32 rectY = _frames[frame]._y2 - _frames[frame]._y1;
+ int32 offsX = 0;
+ int32 offsY = 0;
+
+ if (xx + _x1 + _frames[frame]._x1 < 0) {
+ offsX = -(xx + _x1 + _frames[frame]._x1);
+ }
+
+ if (offsX >= rectX)
+ return;
+ else
+ rectX -= offsX;
+
+ if (yy + _y1 + _frames[frame]._y1 < 0) {
+ offsY = -(yy + _y1 + _frames[frame]._y1);
+ }
+
+ if (offsY >= rectY)
+ return;
+ else
+ rectY -= offsY;
+
+ if (rectX + xx + _x1 + _frames[frame]._x1 >= surface.w)
+ rectX = surface.w - xx - _x1 - _frames[frame]._x1;
+
+ if (rectX < 0)
+ return;
+
+ if (rectY + yy + _y1 + _frames[frame]._y1 >= surface.h)
+ rectY = surface.h - yy - _y1 - _frames[frame]._y1;
+
+ if (rectY < 0)
+ return;
+
+ int32 destPitch = surface.pitch;
+ uint8 *srcRow = _frames[frame]._data + offsX + (_frames[frame]._x2 - _frames[frame]._x1) * offsY;
+ uint8 *curRow = (uint8 *)surface.pixels + (yy + _frames[frame]._y1 + _y1 + offsY) * destPitch + (xx + _x1 + _frames[frame]._x1 + offsX);
+ for (int32 y = 0; y < rectY; y++) {
+ uint8 *cur = curRow;
+ uint8 *c = srcRow + y * (_frames[frame]._x2 - _frames[frame]._x1);
+ for (int32 x = 0; x < rectX; x++) {
+ if (*c)
+ *cur = *c;
+ c++;
+ cur++;
+ }
+ curRow += destPitch;
+ }
+}
+
+void Animation::drawFrameWithMask(Graphics::Surface &surface, int32 frame, int32 xx, int32 yy, int32 zz, Picture *mask) {
+ debugC(1, kDebugAnim, "drawFrameWithMask(surface, %d, %d, %d, %d, mask)", frame, xx, yy, zz);
+ warning("STUB: drawFrameWithMask()");
+}
+
+void Animation::drawFrameWithMaskAndScale(Graphics::Surface &surface, int32 frame, int32 xx, int32 yy, int32 zz, Picture *mask, int32 scale) {
+ debugC(5, kDebugAnim, "drawFrameWithMaskAndScale(surface, %d, %d, %d, %d, mask, %d)", frame, xx, yy, zz, scale);
+ if (_frames[frame]._ref != -1)
+ frame = _frames[frame]._ref;
+ int32 rectX = _frames[frame]._x2 - _frames[frame]._x1;
+ int32 rectY = _frames[frame]._y2 - _frames[frame]._y1;
+
+ int32 finalWidth = rectX * scale / 1024;
+ int32 finalHeight = rectY * scale / 1024;
+
+ // compute final x1,y1,x2,y2
+ int32 xx1 = xx + _x1 + _frames[frame]._x1 * scale / 1024;
+ int32 yy1 = yy + _y1 + _frames[frame]._y1 * scale / 1024;
+ int32 xx2 = xx1 + finalWidth;
+ int32 yy2 = yy1 + finalHeight;
+ int32 w = _frames[frame]._x2 - _frames[frame]._x1;
+// Strangerke - Commented (not used)
+// int32 h = _frames[frame]._y2 - _frames[frame]._y1;
+
+ int32 destPitch = surface.pitch;
+ int32 destPitchMask = mask->getWidth();
+ uint8 *c = _frames[frame]._data;
+ uint8 *curRow = (uint8 *)surface.pixels;
+ uint8 *curRowMask = mask->getDataPtr();
+
+ if (strstr(_name, "shadow")) {
+ for (int y = yy1; y < yy2; y++) {
+ for (int x = xx1; x < xx2; x++) {
+ if (x < 0 || x >= 1280 || y < 0 || y >= 400)
+ continue;
+
+ uint8 *cur = curRow + x + y * destPitch;
+ uint8 *curMask = curRowMask + x + y * destPitchMask;
+
+ // find the good c
+ int32 xs = (x - xx1) * 1024 / scale;
+ int32 ys = (y - yy1) * 1024 / scale;
+ uint8 *cc = &c[ys * w + xs];
+ if (*cc && ((*curMask) >= zz))
+ *cur = _vm->getShadowLUT()[*cur];
+ }
+ }
+ } else {
+ for (int y = yy1; y < yy2; y++) {
+ for (int x = xx1; x < xx2; x++) {
+ if (x < 0 || x >= 1280 || y < 0 || y >= 400)
+ continue;
+
+ uint8 *cur = curRow + x + y * destPitch;
+ uint8 *curMask = curRowMask + x + y * destPitchMask;
+
+ // find the good c
+ int32 xs = (x - xx1) * 1024 / scale;
+ int32 ys = (y - yy1) * 1024 / scale;
+ uint8 *cc = &c[ys * w + xs];
+ if (*cc && ((*curMask) >= zz))
+ *cur = *cc;
+ }
+ }
+ }
+}
+
+void Animation::applyPalette(int32 offset, int32 srcOffset, int32 numEntries) {
+ debugC(1, kDebugAnim, "applyPalette(%d, %d, %d)", offset, srcOffset, numEntries);
+ _vm->setPaletteEntries(_palette + srcOffset, offset, numEntries);
+}
+
+int32 Animation::getFrameWidth(int32 frame) {
+ debugC(4, kDebugAnim, "getFrameWidth(%d)", frame);
+ if ((frame < 0) || (frame >= _numFrames))
+ return 0;
+
+ if (_frames[frame]._ref != -1)
+ frame = _frames[frame]._ref;
+
+ return _frames[frame]._x2 - _frames[frame]._x1;
+}
+
+int32 Animation::getFrameHeight(int32 frame) {
+ debugC(4, kDebugAnim, "getFrameHeight(%d)", frame);
+ if (frame < 0 || frame >= _numFrames)
+ return 0;
+
+ if (_frames[frame]._ref != -1)
+ frame = _frames[frame]._ref;
+
+ return _frames[frame]._y2 - _frames[frame]._y1;
+}
+
+int32 Animation::getWidth() const {
+ return _x2 - _x1;
+}
+
+int32 Animation::getHeight() const {
+ return _y2 - _y1;
+}
+
+void Animation::drawFontFrame(Graphics::Surface &surface, int32 frame, int32 xx, int32 yy, byte *colorMap) {
+ debugC(4, kDebugAnim, "drawFontFrame(surface, %d, %d, %d, colorMap)", frame, xx, yy);
+ if (frame < 0)
+ frame = 0;
+
+ if (frame >= _numFrames)
+ frame = _numFrames - 1;
+
+ if (_numFrames == 0)
+ return;
+
+ if (_frames[frame]._ref != -1)
+ frame = _frames[frame]._ref;
+
+ int32 rectX = _frames[frame]._x2 - _frames[frame]._x1;
+ int32 rectY = _frames[frame]._y2 - _frames[frame]._y1;
+
+ if ((xx + _x1 + _frames[frame]._x1 < 0) || (yy + _y1 + _frames[frame]._y1 < 0))
+ return;
+
+ if (rectX + xx + _x1 + _frames[frame]._x1 >= surface.w)
+ rectX = surface.w - xx - _x1 - _frames[frame]._x1;
+
+ if (rectX < 0)
+ return;
+
+ if (rectY + yy + _y1 + _frames[frame]._y1 >= surface.h)
+ rectY = surface.h - yy - _y1 - _frames[frame]._y1;
+
+ if (rectY < 0)
+ return;
+
+ int32 destPitch = surface.pitch;
+ uint8 *c = _frames[frame]._data;
+ uint8 *curRow = (uint8 *)surface.pixels + (yy + _frames[frame]._y1 + _y1) * destPitch + (xx + _x1 + _frames[frame]._x1);
+ for (int32 y = 0; y < rectY; y++) {
+ unsigned char *cur = curRow;
+ for (int32 x = 0; x < rectX; x++) {
+ if (*c && *c < 4)
+ *cur = colorMap[*c];
+ c++;
+ cur++;
+ }
+ curRow += destPitch;
+ }
+}
+
+void Animation::drawFrameOnPicture(int32 frame, int32 xx, int32 yy) {
+ debugC(1, kDebugAnim, "drawFrameOnPicture(%d, %d, %d)", frame, xx, yy);
+ if (frame < 0)
+ frame = 0;
+
+ if (frame >= _numFrames)
+ frame = _numFrames - 1;
+
+ if (_numFrames == 0)
+ return;
+
+ if (_frames[frame]._ref != -1)
+ frame = _frames[frame]._ref;
+
+ int32 rectX = _frames[frame]._x2 - _frames[frame]._x1;
+ int32 rectY = _frames[frame]._y2 - _frames[frame]._y1;
+
+ Picture *pic = _vm->getPicture();
+
+ if ((xx + _x1 + _frames[frame]._x1 < 0) || (yy + _y1 + _frames[frame]._y1 < 0))
+ return;
+
+ if (rectX + xx + _x1 + _frames[frame]._x1 >= pic->getWidth())
+ rectX = pic->getWidth() - xx - _x1 - _frames[frame]._x1;
+
+ if (rectX < 0)
+ return;
+
+ if (rectY + yy + _y1 + _frames[frame]._y1 >= pic->getHeight())
+ rectY = pic->getHeight() - yy - _y1 - _frames[frame]._y1;
+
+ if (rectY < 0)
+ return;
+
+ int32 destPitch = pic->getWidth();
+ uint8 *c = _frames[frame]._data;
+ uint8 *curRow = (uint8 *)pic->getDataPtr() + (yy + _frames[frame]._y1 + _y1) * destPitch + (xx + _x1 + _frames[frame]._x1);
+ for (int32 y = 0; y < rectY; y++) {
+ unsigned char *cur = curRow;
+ for (int32 x = 0; x < rectX; x++) {
+ if (*c)
+ *cur = *c;
+ c++;
+ cur++;
+ }
+ curRow += destPitch;
+ }
+}
+
+void AnimationInstance::update(int32 timeIncrement) {
+ debugC(5, kDebugAnim, "update(%d)", timeIncrement);
+ if (_currentFrame == -1)
+ return;
+
+ if (_rangeStart == _rangeEnd) {
+ _currentFrame = _rangeStart;
+ return;
+ }
+
+ if (_playing) {
+ _currentTime += timeIncrement;
+ _currentFrame = _currentTime / (1000 / _fps);
+ }
+
+ if (_looping) {
+ _currentFrame = (_currentFrame % (_rangeEnd - _rangeStart + 1)) + _rangeStart;
+ } else {
+ if (_currentFrame >= _rangeEnd - _rangeStart) {
+ _playing = false;
+ _currentFrame = _rangeEnd;
+ } else {
+ _currentFrame = _rangeStart + _currentFrame;
+ }
+ }
+}
+
+AnimationInstance::AnimationInstance(ToonEngine *vm, AnimationInstanceType type) : _vm(vm) {
+ _id = 0;
+ _type = type;
+ _animation = 0;
+ _currentFrame = 0;
+ _currentTime = 0;
+ _fps = 15;
+ _looping = true;
+ _playing = false;
+ _rangeEnd = 0;
+ _useMask = false;
+ _alignBottom = false;
+ _rangeStart = 0;
+ _scale = 1024;
+ _x = 0;
+ _y = 0;
+ _z = 0;
+ _layerZ = 0;
+}
+
+
+void AnimationInstance::render() {
+ debugC(5, kDebugAnim, "render()");
+ if (_visible && _animation) {
+ int32 frame = _currentFrame;
+ if (frame < 0)
+ frame = 0;
+
+ if (frame >= _animation->_numFrames)
+ frame = _animation->_numFrames - 1;
+
+ int32 x = _x;
+ int32 y = _y;
+
+ if (_alignBottom) {
+ int32 offsetX = (_animation->_x2 - _animation->_x1) / 2 * (_scale - 1024);
+ int32 offsetY = (_animation->_y2 - _animation->_y1) * (_scale - 1024);
+
+ x -= offsetX >> 10;
+ y -= offsetY >> 10;
+ }
+
+ if (_useMask) {
+ //if (_scale == 100) { // 100% scale
+ // _animation->drawFrameWithMask(_vm->getMainSurface(), _currentFrame, _x, _y, _z, _vm->getMask());
+ //} else {
+ _animation->drawFrameWithMaskAndScale(_vm->getMainSurface(), frame, x, y, _z, _vm->getMask(), _scale);
+ //}
+ } else {
+ _animation->drawFrame(_vm->getMainSurface(), frame, _x, _y);
+ }
+ }
+}
+
+void AnimationInstance::renderOnPicture() {
+ debugC(5, kDebugAnim, "renderOnPicture()");
+ if (_visible && _animation)
+ _animation->drawFrameOnPicture(_currentFrame, _x, _y);
+}
+
+void AnimationInstance::playAnimation() {
+ debugC(6, kDebugAnim, "playAnimation()");
+ _playing = true;
+}
+
+void AnimationInstance::setAnimation(Animation *animation, bool setRange) {
+ debugC(5, kDebugAnim, "setAnimation(animation)");
+ _animation = animation;
+ if (animation && setRange) {
+ _rangeStart = 0;
+ _rangeEnd = animation->_numFrames - 1;
+ }
+}
+
+void AnimationInstance::setAnimationRange(int32 rangeStart, int rangeEnd) {
+ debugC(5, kDebugAnim, "setAnimationRange(%d, %d)", rangeStart, rangeEnd);
+ _rangeStart = rangeStart;
+ _rangeEnd = rangeEnd;
+
+ if (_currentFrame < _rangeStart)
+ _currentFrame = _rangeStart;
+
+ if (_currentFrame > _rangeEnd)
+ _currentFrame = _rangeEnd;
+}
+
+void AnimationInstance::setPosition(int32 x, int32 y, int32 z, bool relative) {
+ debugC(5, kDebugAnim, "setPosition(%d, %d, %d, %d)", x, y, z, (relative) ? 1 : 0);
+ if (relative || !_animation) {
+ _x = x;
+ _y = y;
+ _z = z;
+ } else {
+ _x = x - _animation->_x1;
+ _y = y - _animation->_y1;
+ _z = z;
+ }
+}
+
+void AnimationInstance::moveRelative(int32 dx, int32 dy, int32 dz) {
+ debugC(1, kDebugAnim, "moveRelative(%d, %d, %d)", dx, dy, dz);
+ _x += dx;
+ _y += dy;
+ _z += dz;
+}
+
+void AnimationInstance::forceFrame(int32 position) {
+ debugC(5, kDebugAnim, "forceFrame(%d)", position);
+ _currentFrame = position;
+ _rangeStart = position;
+ _rangeEnd = position;
+}
+
+void AnimationInstance::setFrame(int32 position) {
+ debugC(5, kDebugAnim, "setFrame(%d)", position);
+ _currentFrame = position;
+}
+
+void AnimationInstance::setFps(int32 fps) {
+ debugC(4, kDebugAnim, "setFps(%d)", fps);
+ _fps = fps;
+}
+
+void AnimationInstance::stopAnimation() {
+ debugC(5, kDebugAnim, "stopAnimation()");
+ _playing = false;
+}
+
+void AnimationInstance::setVisible(bool visible) {
+ debugC(1, kDebugAnim, "setVisible(%d)", (visible) ? 1 : 0);
+ _visible = visible;
+}
+
+void AnimationInstance::setScale(int32 scale, bool align) {
+ debugC(4, kDebugAnim, "setScale(%d)", scale);
+ _scale = scale;
+ _alignBottom = align;
+}
+
+void AnimationInstance::setUseMask(bool useMask) {
+ debugC(1, kDebugAnim, "setUseMask(%d)", (useMask) ? 1 : 0);
+ _useMask = useMask;
+}
+
+void AnimationInstance::getRect(int32 *x1, int32 *y1, int32 *x2, int32 *y2) const {
+ debugC(5, kDebugAnim, "getRect(%d, %d, %d, %d)", *x1, *y1, *x2, *y2);
+ int32 rectX = _animation->_frames[_currentFrame]._x2 - _animation->_frames[_currentFrame]._x1;
+ int32 rectY = _animation->_frames[_currentFrame]._y2 - _animation->_frames[_currentFrame]._y1;
+
+ int32 finalWidth = rectX * _scale / 1024;
+ int32 finalHeight = rectY * _scale / 1024;
+
+ // compute final x1,y1,x2,y2
+ *x1 = _x + _animation->_x1 + _animation->_frames[_currentFrame]._x1 * _scale / 1024;
+ *y1 = _y + _animation->_y1 + _animation->_frames[_currentFrame]._y1 * _scale / 1024;
+ *x2 = *x1 + finalWidth;
+ *y2 = *y1 + finalHeight;
+}
+
+void AnimationInstance::setX(int32 x, bool relative) {
+ debugC(1, kDebugAnim, "setX(%d, %d)", x, (relative) ? 1 : 0);
+ if (relative || !_animation)
+ _x = x;
+ else
+ _x = x - _animation->_x1;
+}
+
+void AnimationInstance::setY(int32 y, bool relative) {
+ debugC(1, kDebugAnim, "setY(%d, %d)", y, (relative) ? 1 : 0);
+ if (relative || !_animation)
+ _y = y;
+ else
+ _y = y - _animation->_y1;
+}
+
+void AnimationInstance::setZ(int32 z, bool relative) {
+ debugC(1, kDebugAnim, "setZ(%d, %d)", z, (relative) ? 1 : 0);
+ _z = z;
+}
+
+void AnimationInstance::setLayerZ(int32 z) {
+ _layerZ = z;
+}
+
+int32 AnimationInstance::getLayerZ() const {
+ return _layerZ;
+}
+
+int32 AnimationInstance::getX2() const {
+ return _x + _animation->_x1;
+}
+
+int32 AnimationInstance::getY2() const {
+ return _y + _animation->_y1;
+}
+
+int32 AnimationInstance::getZ2() const {
+ return _z;
+}
+
+void AnimationInstance::save(Common::WriteStream *stream) {
+ // we don't load the animation here
+ // it must be loaded externally to avoid leaks.
+ stream->writeSint32LE(_currentFrame);
+ stream->writeSint32LE(_currentTime);
+ stream->writeSint32LE(_layerZ);
+ stream->writeSint32LE(_x);
+ stream->writeSint32LE(_y);
+ stream->writeSint32LE(_z);
+ stream->writeSint32LE(_scale);
+ stream->writeSint32LE(_playing);
+ stream->writeSint32LE(_looping);
+ stream->writeSint32LE(_rangeStart);
+ stream->writeSint32LE(_rangeEnd);
+ stream->writeSint32LE(_rangeStart);
+ stream->writeSint32LE(_fps);
+ stream->writeSint32LE(_id);
+ stream->writeSint32LE(_type);
+ stream->writeSint32LE(_visible);
+ stream->writeSint32LE(_useMask);
+}
+void AnimationInstance::load(Common::ReadStream *stream) {
+ _currentFrame = stream->readSint32LE();
+ _currentTime = stream->readSint32LE();
+ _layerZ = stream->readSint32LE();
+ _x = stream->readSint32LE();
+ _y = stream->readSint32LE();
+ _z = stream->readSint32LE();
+ _scale = stream->readSint32LE();
+ _playing = stream->readSint32LE();
+ _looping = stream->readSint32LE();
+ _rangeStart = stream->readSint32LE();
+ _rangeEnd = stream->readSint32LE();
+ _rangeStart = stream->readSint32LE();
+ _fps = stream->readSint32LE();
+ _id = stream->readSint32LE();
+ _type = (AnimationInstanceType)stream->readSint32LE();
+ _visible = stream->readSint32LE();
+ _useMask = stream->readSint32LE();
+}
+
+
+
+void AnimationInstance::setLooping(bool enable) {
+ debugC(6, kDebugAnim, "setLooping(%d)", (enable) ? 1 : 0);
+ _looping = enable;
+}
+
+void AnimationInstance::reset() {
+ _currentFrame = 0;
+ _currentTime = 0;
+}
+
+AnimationManager::AnimationManager(ToonEngine *vm) : _vm(vm) {
+}
+
+void AnimationManager::addInstance(AnimationInstance *instance) {
+ _instances.push_back(instance);
+}
+
+void AnimationManager::removeInstance(AnimationInstance *instance) {
+ debugC(1, kDebugAnim, "removeInstance(instance)");
+ int32 found = -1;
+ for (uint32 i = 0; i < _instances.size(); i++) {
+ if (_instances[i] == instance) {
+ found = i;
+ break;
+ }
+ }
+
+ if (found > -1)
+ _instances.remove_at(found);
+}
+
+void AnimationManager::removeAllInstances(AnimationInstanceType type) {
+ debugC(1, kDebugAnim, "removeInstance(type)");
+ for (int32 i = (int32)_instances.size(); i >= 0; i--) {
+ if (_instances[i]->getType() & type)
+ _instances.remove_at(i);
+ }
+}
+
+void AnimationManager::update(int32 timeIncrement) {
+ debugC(5, kDebugAnim, "update(%d)", timeIncrement);
+ for (uint32 i = 0; i < _instances.size(); i++)
+ _instances[i]->update(timeIncrement);
+}
+
+void AnimationManager::render() {
+ debugC(5, kDebugAnim, "render()");
+ // sort the instance by layer z
+ // bubble sort (replace by faster afterwards)
+ bool changed = true;
+ while (changed) {
+ changed = false;
+ for (uint32 i = 0; i < _instances.size() - 1; i++) {
+ if ((_instances[i]->getLayerZ() > _instances[i + 1]->getLayerZ()) ||
+ ((_instances[i]->getLayerZ() == _instances[i + 1]->getLayerZ()) &&
+ (_instances[i]->getId() < _instances[i+1]->getId()))) {
+ AnimationInstance *instance = _instances[i];
+ _instances[i] = _instances[i + 1];
+ _instances[i + 1] = instance;
+ changed = true;
+ }
+ }
+ }
+
+ for (uint32 i = 0; i < _instances.size(); i++) {
+ if (_instances[i]->getVisible())
+ _instances[i]->render();
+ }
+}
+
+AnimationInstance *AnimationManager::createNewInstance(AnimationInstanceType type) {
+ return new AnimationInstance(_vm, type);
+}
+
+} // End of namespace Toon
diff --git a/engines/toon/anim.h b/engines/toon/anim.h
new file mode 100644
index 0000000000..01475276c5
--- /dev/null
+++ b/engines/toon/anim.h
@@ -0,0 +1,196 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef TOON_ANIM_H
+#define TOON_ANIM_H
+
+#include "common/stream.h"
+#include "common/array.h"
+#include "common/func.h"
+#include "graphics/surface.h"
+
+#include "toon/script.h"
+
+namespace Toon {
+
+class Picture;
+class ToonEngine;
+
+struct AnimationFrame {
+ int32 _x1;
+ int32 _y1;
+ int32 _x2;
+ int32 _y2;
+ int32 _ref;
+ uint8 *_data;
+};
+
+class Animation {
+public:
+ Animation(ToonEngine *vm);
+ ~Animation();
+
+ int32 _x1;
+ int32 _y1;
+ int32 _x2;
+ int32 _y2;
+ int32 _numFrames;
+ int32 _fps;
+ AnimationFrame *_frames;
+ uint8 *_palette;
+ int32 _paletteEntries;
+ char _name[32];
+
+ bool loadAnimation(Common::String file);
+ void drawFrame(Graphics::Surface &surface, int32 frame, int32 x, int32 y);
+ void drawFontFrame(Graphics::Surface &surface, int32 frame, int32 x, int32 y, byte *colorMap);
+ void drawFrameOnPicture(int32 frame, int32 x, int32 y);
+ void drawFrameWithMask(Graphics::Surface &surface, int32 frame, int32 xx, int32 yy, int32 zz, Picture *mask);
+ void drawFrameWithMaskAndScale(Graphics::Surface &surface, int32 frame, int32 xx, int32 yy, int32 zz, Picture *mask, int32 scale);
+ void drawStrip(int32 offset = 0);
+ void applyPalette(int32 offset, int32 srcOffset, int32 numEntries);
+ int32 getFrameWidth(int32 frame);
+ int32 getFrameHeight(int32 frame);
+ int32 getWidth() const;
+ int32 getHeight() const;
+ Common::Rect getRect();
+protected:
+ ToonEngine *_vm;
+};
+
+enum AnimationInstanceType {
+ kAnimationCharacter = 1,
+ kAnimationScene = 2,
+ kAnimationCursor = 4
+};
+
+class AnimationInstance {
+public:
+ AnimationInstance(ToonEngine *vm, AnimationInstanceType type);
+ void update(int32 timeIncrement);
+ void render();
+ void renderOnPicture();
+ void setAnimation(Animation *animation, bool setRange = true);
+ void playAnimation();
+ void setAnimationRange(int32 rangeStart, int rangeEnd);
+ void setFps(int32 fps);
+ void setLooping(bool enable);
+ void stopAnimation();
+ void setFrame(int32 position);
+ void forceFrame(int32 position);
+ void setPosition(int32 x, int32 y, int32 z, bool relative = false);
+ Animation *getAnimation() const { return _animation; }
+ void setScale(int32 scale, bool align = false);
+ void setVisible(bool visible);
+ bool getVisible() const { return _visible; }
+ void setUseMask(bool useMask);
+ void moveRelative(int32 dx, int32 dy, int32 dz);
+ void getRect(int32 *x1, int32 *y1, int32 *x2, int32 *y2) const;
+ int32 getX() const { return _x; }
+ int32 getY() const { return _y; }
+ int32 getZ() const { return _z; }
+ int32 getX2() const;
+ int32 getY2() const;
+ int32 getZ2() const;
+ int32 getFrame() const { return _currentFrame; }
+ void reset();
+ void save(Common::WriteStream *stream);
+ void load(Common::ReadStream *stream);
+
+ void setId(int32 id) { _id = id; }
+ int32 getId() const { return _id; }
+
+ void setX(int32 x, bool relative = false);
+ void setY(int32 y, bool relative = false);
+ void setZ(int32 z, bool relative = false);
+ void setLayerZ(int32 layer);
+ int32 getLayerZ() const;
+
+ AnimationInstanceType getType() const { return _type; }
+
+protected:
+ int32 _currentFrame;
+ int32 _currentTime;
+ int32 _fps;
+ Animation *_animation;
+ int32 _x;
+ int32 _y;
+ int32 _z;
+ int32 _layerZ;
+ int32 _rangeStart;
+ int32 _rangeEnd;
+ int32 _scale;
+ int32 _id;
+
+ AnimationInstanceType _type;
+
+ bool _useMask;
+ bool _playing;
+ bool _looping;
+ bool _visible;
+ bool _alignBottom;
+
+ ToonEngine *_vm;
+};
+
+class AnimationManager {
+public:
+ AnimationManager(ToonEngine *vm);
+ AnimationInstance *createNewInstance(AnimationInstanceType type);
+ void addInstance(AnimationInstance *instance);
+ void removeInstance(AnimationInstance *instance);
+ void removeAllInstances(AnimationInstanceType type);
+ void render();
+ void update(int32 timeIncrement);
+
+protected:
+ ToonEngine *_vm;
+ Common::Array<AnimationInstance *> _instances;
+};
+
+class SceneAnimation {
+public:
+ AnimationInstance *_animInstance;
+ Animation *_animation;
+ int32 _id;
+ bool _active;
+
+ void load(ToonEngine *vm, Common::ReadStream *stream);
+ void save(ToonEngine *vm, Common::WriteStream *stream);
+};
+
+class SceneAnimationScript {
+public:
+ EMCData *_data;
+ EMCState _state;
+ uint32 _lastTimer;
+ bool _frozen;
+ bool _frozenForConversation;
+ bool _active;
+};
+
+} // End of namespace Toon
+
+#endif
diff --git a/engines/toon/audio.cpp b/engines/toon/audio.cpp
new file mode 100644
index 0000000000..4381dad6f7
--- /dev/null
+++ b/engines/toon/audio.cpp
@@ -0,0 +1,629 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "toon/audio.h"
+
+namespace Toon {
+
+static int ADPCM_index[8] = {
+ -1, -1, -1, -1, 2 , 4 , 6 , 8
+};
+static int ADPCM_table[89] = {
+ 7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
+ 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
+ 50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
+ 130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
+ 337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
+ 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
+ 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
+ 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
+ 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
+};
+
+AudioManager::AudioManager(ToonEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) {
+ for (int32 i = 0; i < 16; i++)
+ _channels[i] = 0;
+
+ for (int32 i = 0; i < 4; i++)
+ _audioPacks[i] = 0;
+
+ for (int32 i = 0; i < 4; i++) {
+ _ambientSFXs[i]._delay = 0;
+ _ambientSFXs[i]._enabled = false;
+ _ambientSFXs[i]._id = -1;
+ _ambientSFXs[i]._channel = -1;
+ _ambientSFXs[i]._lastTimer = 0;
+ _ambientSFXs[i]._volume = 255;
+ }
+
+ _voiceMuted = false;
+ _musicMuted = false;
+ _sfxMuted = false;
+}
+
+AudioManager::~AudioManager(void) {
+ for (int32 i = 0; i < 4; i++) {
+ closeAudioPack(i);
+ }
+}
+
+void AudioManager::muteMusic(bool muted) {
+ setMusicVolume(muted ? 0 : 255);
+ _musicMuted = muted;
+}
+
+void AudioManager::muteVoice(bool muted) {
+ if(voiceStillPlaying() && _channels[2]) {
+ _channels[2]->setVolume(muted ? 0 : 255);
+ }
+ _voiceMuted = muted;
+}
+
+void AudioManager::muteSfx(bool muted) {
+ _sfxMuted = muted;
+}
+
+void AudioManager::removeInstance(AudioStreamInstance *inst) {
+ debugC(1, kDebugAudio, "removeInstance(inst)");
+
+ for (int32 i = 0; i < 16; i++) {
+ if (inst == _channels[i])
+ _channels[i] = 0;
+ }
+}
+
+void AudioManager::playMusic(Common::String dir, Common::String music) {
+ debugC(1, kDebugAudio, "playMusic(%s, %s)", dir.c_str(), music.c_str());
+
+ // two musics can be played at same time
+ Common::String path = Common::String::printf("act%d/%s/%s.mus", _vm->state()->_currentChapter, dir.c_str(), music.c_str());
+
+ if (_currentMusicName == music)
+ return;
+
+ _currentMusicName = music;
+
+ Common::SeekableReadStream *srs = _vm->resources()->openFile(path);
+ if (!srs)
+ return;
+
+ // see what channel to take
+ if (_channels[0] && _channels[0]->isPlaying() && _channels[1] && _channels[1]->isPlaying()) {
+ // take the one that is fading
+ if (_channels[0]->isFading()) {
+ _channels[0]->stop(false);
+ _channels[1]->stop(true);
+ _currentMusicChannel = 0;
+ } else {
+ _channels[1]->stop(false);
+ _channels[0]->stop(true);
+ _currentMusicChannel = 1;
+ }
+ } else if (_channels[0] && _channels[0]->isPlaying()) {
+ _channels[0]->stop(true);
+ _currentMusicChannel = 1;
+ } else {
+ if (_channels[1] && _channels[1]->isPlaying())
+ _channels[1]->stop(true);
+ _currentMusicChannel = 0;
+ }
+
+
+ //if (!_channels[_currentMusicChannel])
+ // delete _channels[_currentMusicChannel];
+ _channels[_currentMusicChannel] = new AudioStreamInstance(this, _mixer, srs, true);
+ _channels[_currentMusicChannel]->setVolume(_musicMuted ? 0 : 255);
+ _channels[_currentMusicChannel]->play(true, Audio::Mixer::kMusicSoundType);
+}
+
+bool AudioManager::voiceStillPlaying() {
+ if (!_channels[2])
+ return false;
+
+ return _channels[2]->isPlaying();
+}
+
+void AudioManager::playVoice(int32 id, bool genericVoice) {
+ debugC(1, kDebugAudio, "playVoice(%d, %d)", id, (genericVoice) ? 1 : 0);
+
+ if (voiceStillPlaying()) {
+ // stop current voice
+ _channels[2]->stop(false);
+ }
+
+ Common::SeekableReadStream *stream;
+ if (genericVoice)
+ stream = _audioPacks[0]->getStream(id);
+ else
+ stream = _audioPacks[1]->getStream(id);
+
+ _channels[2] = new AudioStreamInstance(this, _mixer, stream);
+ _channels[2]->play(false, Audio::Mixer::kSpeechSoundType);
+ _channels[2]->setVolume(_voiceMuted ? 0 : 255);
+
+}
+
+int32 AudioManager::playSFX(int32 id, int volume , bool genericSFX) {
+ debugC(4, kDebugAudio, "playSFX(%d, %d)", id, (genericSFX) ? 1 : 0);
+
+ // find a free SFX channel
+ Common::SeekableReadStream *stream;
+
+ if (genericSFX)
+ stream = _audioPacks[2]->getStream(id, true);
+ else
+ stream = _audioPacks[3]->getStream(id, true);
+
+ if (stream->size() == 0)
+ return -1;
+
+ for (int32 i = 3; i < 16; i++) {
+ if (!_channels[i]) {
+ _channels[i] = new AudioStreamInstance(this, _mixer, stream);
+ _channels[i]->play(false, Audio::Mixer::kSFXSoundType);
+ _channels[i]->setVolume(_sfxMuted ? 0 : volume);
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+void AudioManager::stopAllSfxs() {
+ for (int32 i = 3; i < 16; i++) {
+ if (_channels[i] && _channels[i]->isPlaying()) {
+ _channels[i]->stop(false);
+ }
+ }
+}
+
+void AudioManager::stopCurrentVoice() {
+ debugC(1, kDebugAudio, "stopCurrentVoice()");
+
+ if (_channels[2] && _channels[2]->isPlaying())
+ _channels[2]->stop(false);
+}
+
+
+void AudioManager::closeAudioPack(int32 id) {
+ if(_audioPacks[id]) {
+ delete _audioPacks[id];
+ _audioPacks[id] = 0;
+ }
+}
+
+bool AudioManager::loadAudioPack(int32 id, Common::String indexFile, Common::String packFile) {
+ debugC(4, kDebugAudio, "loadAudioPack(%d, %s, %s)", id, indexFile.c_str(), packFile.c_str());
+
+ closeAudioPack(id);
+ _audioPacks[id] = new AudioStreamPackage(_vm);
+ return _audioPacks[id]->loadAudioPackage(indexFile, packFile);
+}
+
+void AudioManager::setMusicVolume(int32 volume) {
+ debugC(1, kDebugAudio, "setMusicVolume(%d)", volume);
+ if (_channels[0])
+ _channels[0]->setVolume(volume);
+
+ if (_channels[1])
+ _channels[1]->setVolume(volume);
+}
+
+void AudioManager::stopMusic() {
+ debugC(1, kDebugAudio, "stopMusic()");
+
+ if (_channels[0])
+ _channels[0]->stop(true);
+ if (_channels[1])
+ _channels[1]->stop(true);
+}
+AudioStreamInstance::~AudioStreamInstance() {
+ if (_man)
+ _man->removeInstance(this);
+}
+
+AudioStreamInstance::AudioStreamInstance(AudioManager *man, Audio::Mixer *mixer, Common::SeekableReadStream *stream , bool looping) {
+ _compBufferSize = 0;
+ _buffer = 0;
+ _bufferMaxSize = 0;
+ _mixer = mixer;
+ _compBuffer = 0;
+ _bufferOffset = 0;
+ _lastADPCMval1 = 0;
+ _lastADPCMval2 = 0;
+ _file = stream;
+ _fadingIn = false;
+ _fadingOut = false;
+ _fadeTime = 0;
+ _stopped = false;
+ _volume = 255;
+ _totalSize = stream->size();
+ _currentReadSize = 8;
+ _man = man;
+ _looping = looping;
+ _musicAttenuation = 1000;
+
+ // preload one packet
+ if (_totalSize > 0) {
+ _file->skip(8);
+ readPacket();
+ } else {
+ stopNow();
+ }
+}
+
+int AudioStreamInstance::readBuffer(int16 *buffer, const int numSamples) {
+ debugC(5, kDebugAudio, "readBuffer(buffer, %d)", numSamples);
+
+ handleFade(numSamples);
+ int32 leftSamples = numSamples;
+ int32 destOffset = 0;
+ if ((_bufferOffset + leftSamples) * 2 >= _bufferSize) {
+ if (_bufferSize - _bufferOffset * 2 > 0) {
+ memcpy(buffer, &_buffer[_bufferOffset], _bufferSize - _bufferOffset * 2);
+ leftSamples -= (_bufferSize - _bufferOffset * 2) / 2;
+ destOffset += (_bufferSize - _bufferOffset * 2) / 2;
+ }
+ if (!readPacket())
+ return 0;
+
+ _bufferOffset = 0;
+ }
+
+ if (leftSamples >= 0) {
+ memcpy(buffer + destOffset, &_buffer[_bufferOffset], MIN(leftSamples * 2, _bufferSize));
+ _bufferOffset += leftSamples;
+ }
+
+ return numSamples;
+}
+
+bool AudioStreamInstance::readPacket() {
+ debugC(5, kDebugAudio, "readPacket()");
+
+ if (_file->eos() || (_currentReadSize >= _totalSize)) {
+ if (_looping) {
+ _file->seek(8);
+ _currentReadSize = 8;
+ _lastADPCMval1 = 0;
+ _lastADPCMval2 = 0;
+ } else {
+ _bufferSize = 0;
+ stopNow();
+ return false;
+ }
+ }
+ int16 numCompressedBytes = _file->readSint16LE();
+ int16 numDecompressedBytes = _file->readSint16LE();
+ _file->readSint32LE();
+
+ if (numCompressedBytes > _compBufferSize) {
+ if (_compBuffer)
+ delete[] _compBuffer;
+ _compBufferSize = numCompressedBytes;
+ _compBuffer = new uint8[_compBufferSize];
+ }
+
+ if (numDecompressedBytes > _bufferMaxSize) {
+ if (_buffer)
+ delete [] _buffer;
+ _bufferMaxSize = numDecompressedBytes;
+ _buffer = new int16[numDecompressedBytes];
+ }
+
+ _bufferSize = numDecompressedBytes;
+ _file->read(_compBuffer, numCompressedBytes);
+ _currentReadSize += 8 + numCompressedBytes;
+
+ decodeADPCM(_compBuffer, _buffer, numCompressedBytes);
+ return true;
+}
+
+void AudioStreamInstance::decodeADPCM(uint8 *comp, int16 *dest, int32 packetSize) {
+ debugC(5, kDebugAudio, "decodeADPCM(comp, dest, %d)", packetSize);
+
+ int32 numSamples = 2 * packetSize;
+ int32 v18 = _lastADPCMval1;
+ int32 v19 = _lastADPCMval2;
+ for (int32 i = 0; i < numSamples; i++) {
+ uint8 comm = *comp;
+
+ int32 v29 = i & 1;
+ int32 v30;
+ if (v29 == 0)
+ v30 = comm & 0xf;
+ else
+ v30 = (comm & 0xf0) >> 4;
+
+ int32 v31 = v30 & 0x8;
+ int32 v32 = v30 & 0x7;
+ int32 v33 = ADPCM_table[v19];
+ int32 v34 = v33 >> 3;
+ if (v32 & 4)
+ v34 += v33;
+
+ if (v32 & 2)
+ v34 += v33 >> 1;
+
+ if (v32 & 1)
+ v34 += v33 >> 2;
+
+ v19 += ADPCM_index[v32];
+ if (v19 < 0)
+ v19 = 0;
+
+ if (v19 > 88)
+ v19 = 88;
+
+ if (v31)
+ v18 -= v34;
+ else
+ v18 += v34;
+
+ if (v18 > 32767)
+ v18 = 32767;
+ else if (v18 < -32768)
+ v18 = -32768;
+
+ *dest = v18;
+ comp += v29;
+ dest++;
+ }
+
+ _lastADPCMval1 = v18;
+ _lastADPCMval2 = v19;
+}
+
+void AudioStreamInstance::play(bool fade, Audio::Mixer::SoundType soundType) {
+ debugC(1, kDebugAudio, "play(%d)", (fade) ? 1 : 0);
+
+ Audio::SoundHandle soundHandle;
+ _stopped = false;
+ _fadingIn = fade;
+ _fadeTime = 0;
+ _soundType = soundType;
+ _musicAttenuation = 1000; // max volume
+ _mixer->playStream(soundType, &_handle, this, -1);
+ handleFade(0);
+}
+
+void AudioStreamInstance::handleFade(int32 numSamples) {
+ debugC(5, kDebugAudio, "handleFade(%d)", numSamples);
+
+ // Fading enabled only for music
+ if (_soundType != Audio::Mixer::kMusicSoundType)
+ return;
+
+ int32 finalVolume = _volume;
+
+ if (_fadingOut) {
+ _fadeTime += numSamples;
+
+ if (_fadeTime > 40960) {
+ _fadeTime = 40960;
+ stopNow();
+ _fadingOut = false;
+ }
+ finalVolume = _volume - _fadeTime * _volume / 40960;
+ } else {
+ if (_fadingIn) {
+ _fadeTime += numSamples;
+ if (_fadeTime > 40960) {
+ _fadeTime = 40960;
+ _fadingIn = false;
+ }
+
+ finalVolume = _volume * _fadeTime / 40960;
+ }
+ }
+
+ // the music is too loud when someone is talking
+ // smoothing to avoid big volume changes
+ if (_man->voiceStillPlaying()) {
+ _musicAttenuation -= numSamples >> 4;
+ if (_musicAttenuation < 250)
+ _musicAttenuation = 250;
+ } else {
+ _musicAttenuation += numSamples >> 5;
+ if (_musicAttenuation > 1000)
+ _musicAttenuation = 1000;
+ }
+
+
+ _mixer->setChannelVolume(_handle, finalVolume * _musicAttenuation / 1000);
+
+}
+
+void AudioStreamInstance::stop(bool fade /*= false*/) {
+ debugC(1, kDebugAudio, "stop(%d)", (fade) ? 1 : 0);
+
+ if (fade) {
+ _fadingIn = false;
+ _fadingOut = true;
+ _fadeTime = 0;
+ } else {
+ stopNow();
+ }
+}
+
+void AudioStreamInstance::stopNow() {
+ debugC(1, kDebugAudio, "stopNow()");
+
+ _stopped = true;
+}
+
+void AudioStreamInstance::setVolume(int32 volume) {
+ debugC(1, kDebugAudio, "setVolume(%d)", volume);
+
+ _volume = volume;
+ _mixer->setChannelVolume(_handle, volume);
+}
+
+AudioStreamPackage::AudioStreamPackage(ToonEngine *vm) : _vm(vm) {
+ _indexBuffer = 0;
+}
+
+AudioStreamPackage::~AudioStreamPackage() {
+ delete[] _indexBuffer;
+ if (_file) {
+ delete _file;
+ _file = 0;
+ }
+}
+
+bool AudioStreamPackage::loadAudioPackage(Common::String indexFile, Common::String streamFile) {
+ debugC(4, kDebugAudio, "loadAudioPackage(%s, %s)", indexFile.c_str(), streamFile.c_str());
+
+ uint32 size = 0;
+ uint8 *fileData = _vm->resources()->getFileData(indexFile, &size);
+ if (!fileData)
+ return false;
+
+ delete[] _indexBuffer;
+
+ _indexBuffer = new uint32[size / 4];
+ memcpy(_indexBuffer, fileData, size);
+
+ _file = _vm->resources()->openFile(streamFile);
+ if (!_file)
+ return false;
+
+ return true;
+}
+
+void AudioStreamPackage::getInfo(int32 id, int32 *offset, int32 *size) {
+ debugC(1, kDebugAudio, "getInfo(%d, offset, size)", id);
+
+ *offset = READ_LE_UINT32(_indexBuffer + id);
+ *size = READ_LE_UINT32(_indexBuffer + id + 1) - READ_LE_UINT32(_indexBuffer + id);
+}
+
+Common::SeekableReadStream *AudioStreamPackage::getStream(int32 id, bool ownMemory) {
+ debugC(1, kDebugAudio, "getStream(%d, %d)", id, (ownMemory) ? 1 : 0);
+
+ int32 offset = 0;
+ int32 size = 0;
+ getInfo(id, &offset, &size);
+ if (ownMemory) {
+ byte *memory = new byte[size];
+ _file->seek(offset);
+ _file->read(memory, size);
+ return new Common::MemoryReadStream(memory, size, DisposeAfterUse::YES);
+ } else {
+ return new Common::SeekableSubReadStream(_file, offset, size + offset);
+ }
+}
+
+void AudioManager::startAmbientSFX(int32 id, int32 delay, int32 mode, int32 volume)
+{
+ int32 found = -1;
+ for (int32 i = 0; i < 4; i++) {
+ if (!_ambientSFXs[i]._enabled) {
+ found = i;
+ break;
+ }
+ }
+
+ if (found < 0)
+ return;
+
+ _ambientSFXs[found]._lastTimer = _vm->getOldMilli() - 1;
+ _ambientSFXs[found]._delay = delay;
+ _ambientSFXs[found]._enabled = true;
+ _ambientSFXs[found]._mode = mode;
+ _ambientSFXs[found]._volume = volume;
+ _ambientSFXs[found]._id = id;
+ updateAmbientSFX();
+
+}
+
+void AudioManager::setAmbientSFXVolume(int32 id, int volume) {
+ for (int32 i = 0; i < 4; i++) {
+ AudioAmbientSFX* ambient = &_ambientSFXs[i];
+ if (ambient->_id == id && ambient->_enabled) {
+ ambient->_volume = volume;
+ if (ambient->_channel >= 0 && _channels[ambient->_channel] && _channels[ambient->_channel]->isPlaying()) {
+ _channels[ambient->_channel]->setVolume(volume);
+ }
+ break;
+ }
+ }
+}
+
+void AudioManager::killAmbientSFX(int32 id)
+{
+ for (int32 i = 0; i < 4; i++) {
+ AudioAmbientSFX* ambient = &_ambientSFXs[i];
+ if (ambient->_id == id && ambient->_enabled) {
+ ambient->_enabled = false;
+ ambient->_id = -1;
+
+ if (_channels[ambient->_channel]) {
+ _channels[ambient->_channel]->stop(false);
+ }
+ }
+
+ }
+}
+
+void AudioManager::killAllAmbientSFX()
+{
+ for (int32 i = 0; i < 4; i++) {
+ AudioAmbientSFX* ambient = &_ambientSFXs[i];
+ if (ambient->_enabled) {
+ ambient->_enabled = false;
+ ambient->_id = -1;
+
+ if (_channels[ambient->_channel] && _channels[ambient->_channel]->isPlaying()) {
+ _channels[ambient->_channel]->stop(false);
+ }
+ }
+ }
+}
+
+void AudioManager::updateAmbientSFX()
+{
+ if (_vm->getMoviePlayer()->isPlaying()) return;
+
+ for (int32 i = 0; i < 4; i++) {
+ AudioAmbientSFX* ambient = &_ambientSFXs[i];
+ if (ambient->_enabled && (ambient->_channel < 0 || !(_channels[ambient->_channel] && _channels[ambient->_channel]->isPlaying()))) {
+ if(ambient->_mode == 1) {
+ if (_vm->randRange(0, 32767) < ambient->_delay) {
+ ambient->_channel = playSFX(ambient->_id, ambient->_volume, false);
+ }
+ } else {
+ if (_vm->getOldMilli() > ambient->_lastTimer) {
+ ambient->_channel = playSFX(ambient->_id, ambient->_volume, false);
+ ambient->_lastTimer = _vm->getOldMilli(); // + 60 * _vm->getTickLength() * ambient->_delay;
+ }
+ }
+ }
+ }
+}
+
+
+} // End of namespace Toon
+
diff --git a/engines/toon/audio.h b/engines/toon/audio.h
new file mode 100644
index 0000000000..e0676c2992
--- /dev/null
+++ b/engines/toon/audio.h
@@ -0,0 +1,177 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef TOON_AUDIO_H
+#define TOON_AUDIO_H
+
+#include "sound/audiostream.h"
+#include "sound/mixer.h"
+#include "toon/toon.h"
+
+namespace Toon {
+
+// used for music/voice/everything
+class AudioManager;
+class AudioStreamInstance : public Audio::AudioStream {
+
+public:
+ AudioStreamInstance(AudioManager *man, Audio::Mixer *mixer, Common::SeekableReadStream *stream, bool looping = false);
+ ~AudioStreamInstance();
+ void play(bool fade = false, Audio::Mixer::SoundType soundType = Audio::Mixer::kMusicSoundType);
+ void stop(bool fade = false);
+
+ bool isPlaying() {
+ return !_stopped;
+ }
+ bool isLooping() {
+ return _looping;
+ }
+ bool isFading() {
+ return _fadingIn || _fadingOut;
+ }
+
+ void setVolume(int32 volume);
+protected:
+ int readBuffer(int16 *buffer, const int numSamples);
+ bool isStereo() const {
+ return false;
+ }
+ int getRate() const {
+ return 22100;
+ }
+ bool endOfData() const {
+ return _stopped;
+ }
+ void handleFade(int32 numSamples);
+ void stopNow();
+
+ bool readPacket();
+ void decodeADPCM(uint8 *comp, int16 *dest, int32 packetSize);
+
+ Common::SeekableReadStream *_file;
+ bool _fadingIn;
+ bool _fadingOut;
+ int32 _fadeTime;
+ uint8 *_compBuffer;
+ int16 *_buffer;
+ int32 _bufferSize;
+ int32 _bufferMaxSize;
+ int32 _bufferOffset;
+ int32 _compBufferSize;
+ Audio::SoundHandle _handle;
+ Audio::Mixer::SoundType _soundType;
+ Audio::Mixer *_mixer;
+ int32 _lastADPCMval1;
+ int32 _lastADPCMval2;
+ bool _stopped;
+ AudioManager *_man;
+ int32 _totalSize;
+ int32 _currentReadSize;
+ bool _looping;
+ int32 _volume;
+ int32 _musicAttenuation;
+};
+
+class AudioStreamPackage {
+
+public:
+ AudioStreamPackage(ToonEngine *vm);
+ ~AudioStreamPackage();
+
+ bool loadAudioPackage(Common::String indexFile, Common::String streamFile);
+ void getInfo(int32 id, int32 *offset, int32 *size);
+ Common::SeekableReadStream *getStream(int32 id, bool ownMemory = false);
+protected:
+ Common::SeekableReadStream *_file;
+ uint32 *_indexBuffer;
+ ToonEngine *_vm;
+};
+
+struct AudioAmbientSFX {
+ int32 _id;
+ int32 _volume;
+ int32 _lastTimer;
+ int32 _delay;
+ int32 _mode;
+ int32 _channel;
+ bool _enabled;
+};
+
+class AudioManager {
+public:
+ void removeInstance(AudioStreamInstance *inst); // called by destructor
+
+ AudioManager(ToonEngine *vm, Audio::Mixer *mixer);
+ ~AudioManager(void);
+
+ bool voiceStillPlaying();
+
+ void playMusic(Common::String dir, Common::String music);
+ void playVoice(int32 id, bool genericVoice);
+ int32 playSFX(int32 id, int volume, bool genericSFX);
+ void stopCurrentVoice();
+ void stopAllSfxs();
+ void setMusicVolume(int32 volume);
+ void stopMusic();
+ void muteVoice(bool mute);
+ void muteMusic(bool mute);
+ void muteSfx(bool mute);
+ bool isVoiceMuted() { return _voiceMuted; }
+ bool isMusicMuted() { return _musicMuted; }
+ bool isSfxMuted() { return _sfxMuted; }
+
+ void startAmbientSFX(int32 id, int32 delay, int32 mode, int32 volume);
+ void killAmbientSFX(int32 id);
+ void killAllAmbientSFX();
+ void updateAmbientSFX();
+ void setAmbientSFXVolume(int32 id, int volume);
+
+ void closeAudioPack(int32 id);
+ bool loadAudioPack(int32 id, Common::String indexFile, Common::String packFile);
+
+ AudioStreamInstance *_channels[16]; // 0-1 : music
+ // 2 : voice
+ // 3-16 : SFX
+
+ AudioStreamPackage *_audioPacks[4]; // 0 : generic streams
+ // 1 : local streams
+ // 2 : generic SFX
+ // 3 : local SFX
+ uint32 _currentMusicChannel;
+ Common::String _currentMusicName;
+ ToonEngine *_vm;
+ Audio::Mixer *_mixer;
+
+protected:
+ bool _voiceMuted;
+ bool _musicMuted;
+ bool _sfxMuted;
+
+ AudioAmbientSFX _ambientSFXs[4];
+};
+
+} // End of namespace Toon
+
+#endif
diff --git a/engines/toon/character.cpp b/engines/toon/character.cpp
new file mode 100644
index 0000000000..f6e244a064
--- /dev/null
+++ b/engines/toon/character.cpp
@@ -0,0 +1,1043 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* $URL$
+* $Id$
+*
+*/
+
+#include "toon/character.h"
+#include "toon/drew.h"
+#include "toon/flux.h"
+#include "toon/path.h"
+
+namespace Toon {
+
+Character::Character(ToonEngine *vm) : _vm(vm) {
+ _animationInstance = 0;
+ _shadowAnimationInstance = 0;
+ _shadowAnim = 0;
+ _x = 0;
+ _y = 0;
+ _z = 0;
+ _finalX = 0;
+ _finalY = 0;
+ _specialAnim = 0;
+ _sceneAnimationId = -1;
+ _idleAnim = 0;
+ _walkAnim = 0;
+ _talkAnim = 0;
+ _facing = 0;
+ _flags = 0;
+ _animFlags = 0;
+ _isTalking = false;
+ _id = 0;
+ _scale = 1024;
+ _blockingWalk = false;
+ _animScriptId = -1;
+ _animSpecialId = -1;
+ _animSpecialDefaultId = 0;
+ _currentPathNodeCount = 0;
+ _currentPathNode = 0;
+ _visible = true;
+ _speed = 150; // 150 = nominal drew speed
+ _lastWalkTime = 0;
+ _numPixelToWalk = 0;
+ _nextIdleTime = _vm->getSystem()->getMillis() + (_vm->randRange(0, 600) + 300) * _vm->getTickLength();
+}
+
+Character::~Character(void) {
+}
+
+void Character::init() {
+
+}
+
+void Character::setFacing(int32 facing) {
+ debugC(4, kDebugCharacter, "setFacing(%d)", facing);
+ _facing = facing;
+}
+
+void Character::setPosition(int32 x, int32 y) {
+ debugC(5, kDebugCharacter, "setPosition(%d, %d)", x, y);
+
+ _x = x;
+ _y = y;
+ if (_animationInstance)
+ _animationInstance->setPosition(_x, _y, _z);
+ return;
+}
+
+bool Character::walkTo(int32 newPosX, int32 newPosY) {
+ debugC(1, kDebugCharacter, "walkTo(%d, %d)", newPosX, newPosY);
+
+ if (!_visible)
+ return true;
+
+ if (_x == newPosX && _y == newPosY)
+ return true;
+
+ _vm->getPathFinding()->resetBlockingRects();
+
+ if (_id == 1) {
+ int32 sizeX = MAX<int32>(5, 40 * _vm->getDrew()->getScale() / 1024);
+ int32 sizeY = MAX<int32>(2, 20 * _vm->getDrew()->getScale() / 1024);
+ _vm->getPathFinding()->addBlockingEllipse(_vm->getDrew()->getFinalX(), _vm->getDrew()->getFinalY(), sizeX, sizeY);
+ }
+
+ _vm->getPathFinding()->findClosestWalkingPoint(newPosX, newPosY, &_finalX, &_finalY, _x, _y);
+ if (_x == _finalX && _y == _finalY)
+ return true;
+
+
+ if (_vm->getPathFinding()->findPath(_x, _y, _finalX, _finalY)) {
+
+ int32 localFinalX = _finalX;
+ int32 localFinalY = _finalY;
+
+ for (int32 a = 0; a < _vm->getPathFinding()->getPathNodeCount(); a++) {
+ _currentPathX[a] = _vm->getPathFinding()->getPathNodeX(a);
+ _currentPathY[a] = _vm->getPathFinding()->getPathNodeY(a);
+ }
+ _currentPathNodeCount = _vm->getPathFinding()->getPathNodeCount();
+ _currentPathNode = 0;
+ stopSpecialAnim();
+ _flags |= 0x1;
+ _lastWalkTime = _vm->getSystem()->getMillis();
+
+ _numPixelToWalk = 0;
+
+ if (_blockingWalk) {
+ while ((_x != newPosX || _y != newPosY) && _currentPathNode < _currentPathNodeCount && !_vm->shouldQuitGame()) {
+ if (_currentPathNode < _currentPathNodeCount - 10) {
+ int32 delta = MIN<int32>(10, _currentPathNodeCount - _currentPathNode);
+ int32 dx = _currentPathX[_currentPathNode+delta] - _x;
+ int32 dy = _currentPathY[_currentPathNode+delta] - _y;
+ setFacing(getFacingFromDirection(dx, dy));
+ playWalkAnim(0, 0);
+ }
+
+ // in 1/1000 pixels
+ _numPixelToWalk += _speed * (_vm->getSystem()->getMillis() - _lastWalkTime) * _scale / 1024;
+ _lastWalkTime = _vm->getSystem()->getMillis();
+
+ while (_numPixelToWalk >= 1000 && _currentPathNode < _currentPathNodeCount) {
+ _x = _currentPathX[_currentPathNode];
+ _y = _currentPathY[_currentPathNode];
+ _currentPathNode += 1;
+ _numPixelToWalk -= 1000;
+ }
+ setPosition(_x, _y);
+
+ _vm->doFrame();
+ }
+ playStandingAnim();
+ _flags &= ~0x1;
+ _currentPathNode = 0;
+ _currentPathNodeCount = 0;
+
+ if (_x != localFinalX || _y != localFinalY) {
+ return false;
+ }
+ }
+ }
+
+ //_vm->getPathFinding()->findClosestWalkingPoint(newPosX, newPosY, &_x, &_y, _x, _y);
+ //setPosition(_x,_y);
+ return true;
+}
+
+void Character::setFlag(int flag) {
+ _flags = flag;
+}
+
+int32 Character::getFlag() {
+ return _flags;
+}
+
+int32 Character::getX() {
+ return _x;
+}
+int32 Character::getY() {
+ return _y;
+}
+
+bool Character::getVisible() {
+ return _visible;
+}
+
+void Character::setVisible(bool visible) {
+ debugC(1, kDebugCharacter, "setVisible(%d)", (visible) ? 1 : 0);
+
+ _visible = visible;
+ if (_animationInstance)
+ _animationInstance->setVisible(visible);
+
+ if (_shadowAnimationInstance)
+ _shadowAnimationInstance->setVisible(visible);
+
+ return;
+}
+
+int32 Character::getFacing() {
+ return _facing;
+}
+
+bool Character::loadWalkAnimation(Common::String animName) {
+ debugC(1, kDebugCharacter, "loadWalkAnimation(%s)", animName.c_str());
+ if (_walkAnim)
+ delete _walkAnim;
+
+ _walkAnim = new Animation(_vm);
+ return _walkAnim->loadAnimation(animName);
+}
+
+bool Character::loadIdleAnimation(Common::String animName) {
+ debugC(1, kDebugCharacter, "loadIdleAnimation(%s)", animName.c_str());
+ if (_idleAnim)
+ delete _idleAnim;
+
+ _idleAnim = new Animation(_vm);
+ return _idleAnim->loadAnimation(animName);
+}
+
+bool Character::loadTalkAnimation(Common::String animName) {
+ debugC(1, kDebugCharacter, "loadTalkAnimation(%s)", animName.c_str());
+ if (_talkAnim)
+ delete _talkAnim;
+
+ _talkAnim = new Animation(_vm);
+ return _talkAnim->loadAnimation(animName);
+}
+
+bool Character::setupPalette() {
+ return false; // only for Drew
+}
+
+void Character::playStandingAnim() {
+
+}
+
+void Character::updateTimers(int32 relativeAdd) {
+ _nextIdleTime += relativeAdd;
+ _lastWalkTime += relativeAdd;
+}
+
+void Character::stopSpecialAnim() {
+ debugC(4, kDebugCharacter, "stopSpecialAnim()");
+// Strangerke - Commented (not used)
+#if 0
+ if (_animSpecialId != _animSpecialDefaultId)
+ delete anim
+#endif
+ if (_animScriptId != -1)
+ _vm->getSceneAnimationScript(_animScriptId)->_frozenForConversation = false;
+
+ //if (_sceneAnimationId != -1)
+ // _animationInstance->setAnimation(_vm->getSceneAnimation(_sceneAnimationId)->_animation);
+
+ bool needStandingAnim = (_animFlags & 0x40) != 0;
+
+ _animSpecialId = -1;
+ _time = 0;
+ _animFlags = 0;
+ _flags &= ~1;
+ _flags &= ~4;
+
+ if (needStandingAnim) {
+ playStandingAnim();
+ }
+}
+
+void Character::update(int32 timeIncrement) {
+ debugC(5, kDebugCharacter, "update(%d)", timeIncrement);
+ if ((_flags & 0x1) && _currentPathNodeCount > 0) {
+ if (_currentPathNode < _currentPathNodeCount) {
+ if (_currentPathNode < _currentPathNodeCount - 10) {
+ int32 delta = MIN<int32>(10, _currentPathNodeCount - _currentPathNode);
+ int32 dx = _currentPathX[_currentPathNode+delta] - _x;
+ int32 dy = _currentPathY[_currentPathNode+delta] - _y;
+ setFacing(getFacingFromDirection(dx, dy));
+ playWalkAnim(0, 0);
+ }
+
+ // in 1/1000 pixels
+ _numPixelToWalk += _speed * (_vm->getSystem()->getMillis() - _lastWalkTime) * _scale / 1024;
+ _lastWalkTime = _vm->getSystem()->getMillis();
+
+ while (_numPixelToWalk > 1000 && _currentPathNode < _currentPathNodeCount) {
+ _x = _currentPathX[_currentPathNode];
+ _y = _currentPathY[_currentPathNode];
+ _currentPathNode += 1;
+ _numPixelToWalk -= 1000;
+ }
+ setPosition(_x, _y);
+ } else {
+ playStandingAnim();
+ _flags &= ~0x1;
+ _currentPathNodeCount = 0;
+ }
+ }
+
+ updateIdle();
+
+#if 0
+ // handle special anims
+ if ((_flags & 4) == 0)
+ return;
+
+
+ if (_animScriptId != -1) {
+ _animationInstance = _vm->getSceneAnimation(this->)
+#endif
+
+ int32 animId = _animSpecialId;
+ if (animId >= 1000)
+ animId = 0;
+
+ if (_animSpecialId < 0)
+ return;
+
+ int32 currentFrame = _animationInstance->getFrame();
+
+ const SpecialCharacterAnimation *anim = getSpecialAnimation(_id, animId);
+
+ if ((_animFlags & 0x10) == 0) {
+ if (_animScriptId != -1 && currentFrame > 0 && !_vm->getSceneAnimationScript(_animScriptId)->_frozen) {
+ if (_vm->getCurrentLineToSay() != _lineToSayId && (_animFlags & 8))
+ stopSpecialAnim();
+ return;
+ }
+
+ if (_id == 1 && (_animFlags & 4)) {
+ if (_animFlags & 0x10)
+ return;
+ } else {
+ if (_id == 1 && (_animFlags & 0x10) && _vm->getCurrentLineToSay() != -1) {
+ return;
+ }
+ if ((_animFlags & 0x40) == 0 && _vm->getCurrentLineToSay() == -1) {
+ stopSpecialAnim();
+ return;
+ }
+
+// Strangerke - Commented (not used)
+#if 0
+ if (_animFlags & 8) {
+ if (anim->_flags7 == 0xff && anim->_flags9 == 0xff) {
+ // start voice
+ }
+ }
+#endif
+
+ if (_animScriptId != -1)
+ _vm->getSceneAnimationScript(_animScriptId)->_frozenForConversation = true;
+
+
+ // TODO setup backup //
+
+ _animFlags |= 0x10;
+ _animationInstance->setAnimation(_specialAnim);
+ _animationInstance->setFrame(0);
+ _time = _vm->getOldMilli() + 8 * _vm->getTickLength();
+ }
+
+ }
+
+ if ((_animFlags & 3) == 2) {
+ if ((((_animFlags & 8) == 8) && _vm->getCurrentLineToSay() != _lineToSayId) || !_vm->getAudioManager()->voiceStillPlaying()) // || (_flags & 8)) && _vm->getAudioManager()->voiceStillPlaying())
+ _animFlags |= 1;
+
+ }
+
+ if (_time > _vm->getOldMilli())
+ return;
+
+ int32 animFlag = anim->_unused;
+ int32 nextFrame = currentFrame + 1;
+ int32 nextTime = _time;
+ int32 animDir = 1;
+ if (!animFlag) {
+ if (_animFlags & 1) {
+ if (anim->_flags7 == 0xff) {
+ if (currentFrame > anim->_flag1 / 2)
+ animDir = 1;
+ else
+ animDir = -1;
+ } else {
+ if (currentFrame >= anim->_flags6) {
+ if (currentFrame < anim->_flags7)
+ currentFrame = anim->_flags7;
+ }
+ if (currentFrame > anim->_flags6)
+ animDir = 1;
+ else
+ animDir = -1;
+ }
+
+ nextFrame = currentFrame + animDir;
+ nextTime = _vm->getOldMilli() + 6 * _vm->getTickLength();
+ } else {
+ if (_animFlags & 0x20) {
+ nextFrame = currentFrame - 1;
+ if (nextFrame == anim->_flags6 - 1) {
+ if (anim->_flags8 != 1 && (_vm->randRange(0, 1) == 1 || anim->_flags8 == 2)) {
+ _animFlags &= ~0x20;
+ nextFrame += 2;
+ if (nextFrame > anim->_flags7)
+ nextFrame = anim->_flags7;
+ } else {
+ nextFrame = anim->_flags7;
+ }
+ }
+ } else {
+ nextFrame = currentFrame + 1;
+// Strangerke - Commented (not used)
+#if 0
+ if (!_vm->getAudioManager()->voiceStillPlaying()) {
+ if (_animFlags & 8) {
+ if ((anim->_flags9 == 0xff && nextFrame == anim->_flags6) ||
+ (anim->_flags9 != 0xff && nextFrame >= anim->_flags9)) {
+ // start really talking
+ }
+ }
+ }
+#endif
+ if (nextFrame == anim->_flags7 + 1 && (_animFlags & 0x40) == 0) {
+ if (anim->_flags8 != 1 && (_vm->randRange(0, 1) || anim->_flags8 == 2)) {
+ _animFlags |= 0x20;
+ nextFrame -= 2;
+ if (nextFrame < anim->_flags6)
+ nextFrame = anim->_flags6;
+ } else {
+ nextFrame = anim->_flags6;
+ }
+ }
+ }
+
+ nextTime = _vm->getOldMilli() + 8 * _vm->getTickLength();
+ }
+ // goto label78
+ }
+ // skipped all this part.
+
+ //label78
+
+
+#if 0
+ if (_id == 0)
+ printf(" drew animation name %s / flag %d / frame %d \n", _specialAnim->_name, _animFlags, nextFrame);
+ if (_id == 1)
+ debugC(0, 0xfff, " flux animation flag %d / frame %d", _animFlags, nextFrame);
+ if (_id == 7)
+ debugC(0, 0xfff, " footman animation flag %d / frame %d", _animFlags, nextFrame);
+#endif
+
+ _time = nextTime;
+ if (nextFrame < 0 || nextFrame >= anim->_flag1) {
+ if ((_animFlags & 2) == 0 || _vm->getCurrentLineToSay() != _lineToSayId) {
+ stopSpecialAnim();
+ return;
+ }
+
+ // lots skipped here
+
+ _animFlags &= ~0x10;
+ _animationInstance->forceFrame(0);
+ return;
+
+ }
+
+ //if ((_flags & 8) == 0 || !_vm->getAudioManager()->voiceStillPlaying( ) || )
+ _animationInstance->forceFrame(nextFrame);
+}
+
+// adapted from Kyra
+int32 Character::getFacingFromDirection(int32 dx, int32 dy) {
+ debugC(4, kDebugCharacter, "getFacingFromDirection(%d, %d)", dx, dy);
+
+ static const int facingTable[] = {
+ //1, 0, 1, 2, 3, 4, 3, 2, 7, 0, 7, 6, 5, 4, 5, 6
+ 5, 6, 5, 4, 3, 2, 3, 4, 7, 6, 7, 0, 1, 2, 1, 0
+ };
+ dx = -dx;
+
+ int32 facingEntry = 0;
+ int32 ydiff = dy;
+ if (ydiff < 0) {
+ ++facingEntry;
+ ydiff = -ydiff;
+ }
+ facingEntry <<= 1;
+
+ int32 xdiff = dx;
+ if (xdiff < 0) {
+ ++facingEntry;
+ xdiff = -xdiff;
+ }
+
+ facingEntry <<= 1;
+
+ if (xdiff >= ydiff) {
+ int32 temp = ydiff;
+ ydiff = xdiff;
+ xdiff = temp;
+ } else {
+ facingEntry += 1;
+ }
+
+ facingEntry <<= 1;
+
+ int32 temp = (ydiff + 1) >> 1;
+
+ if (xdiff < temp)
+ facingEntry += 1;
+
+ return facingTable[facingEntry];
+}
+
+AnimationInstance *Character::getAnimationInstance() {
+ return _animationInstance;
+}
+
+void Character::setAnimationInstance(AnimationInstance *instance) {
+ _animationInstance = instance;
+}
+
+int32 Character::getScale() {
+ return _scale;
+}
+
+void Character::playWalkAnim(int32 startFrame, int32 endFrame) {
+
+}
+
+void Character::setId(int32 id) {
+ _id = id;
+}
+
+int32 Character::getId() {
+ return _id;
+}
+
+void Character::save(Common::WriteStream *stream) {
+ debugC(1, kDebugCharacter, "save(stream)");
+
+ stream->writeSint32LE(_flags);
+ stream->writeSint32LE(_x);
+ stream->writeSint32LE(_y);
+ stream->writeSint32LE(_z);
+ stream->writeSint32LE(_finalX);
+ stream->writeSint32LE(_finalY);
+ stream->writeSint32LE(_scale);
+ stream->writeSint32LE(_id);
+
+ stream->writeSint32LE(_animScriptId);
+ stream->writeSint32LE(_animFlags);
+ stream->writeSint32LE(_animSpecialDefaultId);
+ stream->writeSint32LE(_sceneAnimationId);
+}
+
+void Character::load(Common::ReadStream *stream) {
+ debugC(1, kDebugCharacter, "read(stream)");
+
+ _flags = stream->readSint32LE();
+ _flags &= ~1; // characters are not walking when restoring.
+
+ _x = stream->readSint32LE();
+ _y = stream->readSint32LE();
+ _z = stream->readSint32LE();
+ _finalX = stream->readSint32LE();
+ _finalY = stream->readSint32LE();
+ _scale = stream->readSint32LE();
+ _id = stream->readSint32LE();
+
+ _animScriptId = stream->readSint32LE();
+ _animFlags = stream->readSint32LE();
+ _animSpecialDefaultId = stream->readSint32LE();
+ _sceneAnimationId = stream->readSint32LE();
+
+ if (_sceneAnimationId > -1) {
+ setAnimationInstance(_vm->getSceneAnimation(_sceneAnimationId)->_animInstance);
+ }
+}
+
+void Character::setAnimScript(int32 animScriptId) {
+ _animScriptId = animScriptId;
+}
+
+void Character::setSceneAnimationId(int32 sceneAnimationId) {
+ _sceneAnimationId = sceneAnimationId;
+}
+
+int32 Character::getAnimScript() {
+ return _animScriptId;
+}
+
+void Character::playTalkAnim() {
+
+}
+
+void Character::stopWalk() {
+ debugC(1, kDebugCharacter, "stopWalk()");
+
+ _finalX = _x;
+ _finalY = _y;
+ _flags &= ~0x1;
+ _currentPathNode = 0;
+ _currentPathNodeCount = 0;
+}
+
+const SpecialCharacterAnimation *Character::getSpecialAnimation(int32 characterId, int32 animationId) {
+ debugC(6, kDebugCharacter, "getSpecialAnimation(%d, %d)", characterId, animationId);
+
+ // very nice animation list hardcoded in the executable...
+ static const SpecialCharacterAnimation anims[] = {
+ { "TLK547_?", 9, 0, 0, 0, 0, 0, 1, 5, 8, 1, 8, 0, 255 },
+ { "TLK555_?", 16, 0, 0, 0, 0, 6, 8, 10, 255, 6, 11, 2, 255 },
+ { "LST657_?", 14, 0, 0, 0, 0, 255, 255, 255, 255, 5, 11, 0, 255 },
+ { "TLK587_?", 18, 0, 0, 0, 0, 5, 7, 9, 11, 4, 13, 1, 255 },
+ { "LST659_?", 14, 0, 0, 0, 0, 255, 255, 255, 255, 6, 8, 0, 255 },
+ { "TLK595_?", 11, 0, 0, 0, 0, 3, 6, 255, 255, 1, 7, 0, 255 },
+ { "IDL165_?", 13, 0, 0, 0, 0, 255, 255, 255, 255, 6, 8, 0, 255 },
+ { "LST699_?", 10, 0, 0, 0, 0, 255, 255, 255, 255, 1, 9, 1, 255 },
+ { "LST713_?", 10, 0, 0, 0, 0, 255, 255, 255, 255, 4, 6, 0, 255 },
+ { "IDL169_?", 16, 0, 0, 0, 0, 255, 255, 255, 255, 5, 9, 2, 255 },
+ { "IDL173_?", 19, 0, 0, 0, 0, 255, 255, 255, 255, 4, 17, 1, 255 },
+ { "IDL187_?", 14, 0, 0, 0, 0, 255, 255, 255, 255, 4, 8, 0, 255 },
+ { "IDL185_?", 15, 0, 0, 0, 0, 255, 255, 255, 255, 6, 9, 1, 255 },
+ { "TLK635_?", 16, 0, 0, 0, 0, 5, 8, 10, 12, 4, 12, 0, 255 },
+ { "TLK637_?", 18, 0, 0, 0, 0, 5, 7, 9, 12, 4, 13, 0, 255 },
+ { "TLK551_?", 20, 0, 0, 0, 0, 5, 9, 11, 15, 4, 16, 0, 255 },
+ { "TLK553_?", 20, 0, 0, 0, 0, 7, 9, 11, 13, 6, 15, 0, 255 },
+ { "TLK619_?", 18, 0, 0, 0, 0, 5, 8, 11, 13, 5, 15, 0, 255 },
+ { "TLK601_?", 12, 0, 0, 0, 0, 2, 5, 6, 10, 2, 10, 1, 255 },
+ { "TLK559_?", 18, 0, 0, 0, 0, 4, 6, 10, 12, 4, 13, 0, 255 },
+ { "TLK557_?", 16, 0, 0, 0, 0, 6, 8, 10, 255, 6, 11, 0, 255 },
+ { "TLK561_?", 17, 0, 0, 0, 0, 6, 8, 10, 12, 5, 12, 0, 255 },
+ { "TLK623_?", 19, 0, 0, 0, 0, 6, 8, 10, 13, 6, 14, 0, 255 },
+ { "TLK591_?", 20, 0, 0, 0, 0, 10, 14, 255, 255, 7, 15, 0, 255 },
+ { "TLK567_?", 19, 0, 0, 0, 0, 6, 9, 11, 14, 5, 15, 0, 255 },
+ { "TLK629_?", 18, 0, 0, 0, 0, 6, 8, 10, 11, 6, 12, 0, 255 },
+ { "TLK627_?", 19, 0, 0, 0, 0, 7, 10, 12, 14, 4, 14, 0, 255 },
+ { "TLK631_?", 19, 0, 0, 0, 0, 8, 10, 255, 255, 8, 12, 0, 255 },
+ { "TLK565_?", 17, 0, 0, 0, 0, 4, 7, 9, 11, 3, 12, 0, 255 },
+ { "TLK603_?", 16, 0, 0, 0, 0, 5, 255, 255, 255, 3, 9, 0, 255 },
+ { "TLK573_?", 20, 0, 0, 0, 0, 6, 7, 10, 255, 6, 16, 2, 255 },
+ { "TLK615_?", 17, 0, 0, 0, 0, 6, 8, 10, 12, 5, 12, 0, 255 },
+ { "TLK609_?", 18, 0, 0, 0, 0, 6, 8, 10, 12, 5, 13, 0, 255 },
+ { "TLK611_?", 18, 0, 0, 0, 0, 8, 10, 12, 255, 7, 13, 0, 255 },
+ { "TLK607_?", 16, 0, 0, 0, 0, 4, 7, 9, 11, 4, 12, 0, 255 },
+ { "TLK581_?", 15, 0, 0, 0, 0, 7, 9, 11, 255, 6, 11, 0, 255 },
+ { "SHD107_?", 46, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 255 },
+ { "IHL106_?", 23, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 7 },
+ { "GLV106_?", 23, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 7 },
+ { "FXTKA_?", 11, 0, 0, 0, 0, 7, 255, 255, 255, 2, 9, 0, 255 },
+ { "FXTKF_?", 12, 0, 0, 0, 0, 6, 8, 255, 255, 5, 9, 0, 255 },
+ { "FXTKG_?", 9, 0, 0, 0, 0, 5, 255, 255, 255, 4, 7, 0, 255 },
+ { "FXTKI_?", 12, 0, 0, 0, 0, 6, 255, 255, 255, 5, 9, 0, 255 },
+ { "FXTKL_?", 14, 0, 0, 0, 0, 4, 6, 255, 255, 3, 10, 0, 255 },
+ { "FXTKO_?", 10, 0, 0, 0, 0, 4, 255, 255, 255, 4, 7, 0, 255 },
+ { "FXTKP_?", 9, 0, 0, 0, 0, 4, 6, 255, 255, 3, 7, 0, 255 },
+ { "FXTKQ_?", 10, 0, 0, 0, 0, 4, 6, 255, 255, 3, 7, 0, 255 },
+ { "FXLSA_?", 11, 0, 0, 0, 0, 255, 255, 255, 255, 4, 6, 0, 255 },
+ { "FXLSB_?", 9, 0, 0, 0, 0, 255, 255, 255, 255, 4, 5, 0, 255 },
+ { "FXLSK_?", 8, 0, 0, 0, 0, 255, 255, 255, 255, 5, 6, 0, 255 },
+ { "FXLSM_?", 7, 0, 0, 0, 0, 255, 255, 255, 255, 4, 4, 0, 255 },
+ { "FXLSP_?", 7, 0, 0, 0, 0, 255, 255, 255, 255, 3, 3, 0, 255 },
+ { "FXLSQ_?", 6, 0, 0, 0, 0, 255, 255, 255, 255, 3, 3, 0, 255 },
+ { "FXIDE_?", 10, 0, 0, 0, 0, 255, 255, 255, 255, 5, 7, 0, 255 },
+ { "FXIDI_?", 7, 0, 0, 0, 0, 255, 255, 255, 255, 1, 6, 1, 255 },
+ { "FXRCT1_?", 12, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 255 },
+ { "FXTKB_?", 11, 0, 0, 0, 0, 7, 255, 255, 255, 5, 9, 0, 255 },
+ { "FXTKC_?", 14, 0, 0, 0, 0, 2, 5, 8, 10, 1, 12, 2, 255 },
+ { "FXTKD_?", 14, 0, 0, 0, 0, 5, 7, 9, 255, 4, 11, 0, 255 },
+ { "FXTKE_?", 14, 0, 0, 0, 0, 2, 255, 255, 255, 1, 12, 1, 255 },
+ { "FXTKH_?", 11, 0, 0, 0, 0, 6, 8, 255, 255, 4, 9, 0, 255 },
+ { "FXTKJ_?", 8, 0, 0, 0, 0, 7, 255, 255, 255, 4, 7, 0, 255 },
+ { "FXTKK_?", 13, 0, 0, 0, 0, 6, 8, 255, 255, 5, 9, 0, 255 },
+ { "FXTKM_?", 11, 0, 0, 0, 0, 6, 255, 255, 255, 4, 7, 0, 255 },
+ { "FXTKN_?", 9, 0, 0, 0, 0, 5, 7, 255, 255, 4, 7, 0, 255 },
+ { "FXLSC_?", 9, 0, 0, 0, 0, 255, 255, 255, 255, 3, 6, 1, 255 },
+ { "FXLSD_?", 7, 0, 0, 0, 0, 255, 255, 255, 255, 4, 5, 0, 255 },
+ { "FXLSE_?", 9, 0, 0, 0, 0, 255, 255, 255, 255, 8, 8, 0, 255 },
+ { "FXLSG_?", 11, 0, 0, 0, 0, 255, 255, 255, 255, 6, 8, 2, 255 },
+ { "FXLSI_?", 8, 0, 0, 0, 0, 255, 255, 255, 255, 5, 6, 0, 255 },
+ { "FXLSJ_?", 5, 0, 0, 0, 0, 255, 255, 255, 255, 3, 4, 0, 255 },
+ { "FXLSO_?", 8, 0, 0, 0, 0, 255, 255, 255, 255, 4, 5, 0, 255 },
+ { "FXIDA_?", 15, 0, 0, 0, 0, 255, 255, 255, 255, 1, 12, 1, 255 },
+ { "FXIDB_?", 12, 0, 0, 0, 0, 255, 255, 255, 255, 4, 11, 1, 255 },
+ { "FXIDC_?", 11, 0, 0, 0, 0, 255, 255, 255, 255, 7, 7, 0, 255 },
+ { "FXIDD_?", 15, 0, 0, 0, 0, 255, 255, 255, 255, 6, 6, 0, 255 },
+ { "FXIDG_?", 6, 0, 0, 0, 0, 255, 255, 255, 255, 3, 4, 0, 255 },
+ { "FXVRA_?", 7, 0, 0, 0, 0, 255, 255, 255, 255, 2, 6, 2, 255 },
+ { "FXIDF_?", 15, 0, 0, 0, 0, 255, 255, 255, 255, 9, 11, 0, 255 },
+ { "FXEXA_?", 9, 0, 0, 0, 0, 255, 255, 255, 255, 5, 5, 0, 255 },
+ { "FXEXA_?", 9, 0, 0, 0, 0, 255, 255, 255, 255, 5, 5, 0, 255 },
+ { "FFNTK1", 8, 0, 0, 0, 0, 255, 255, 255, 255, 1, 7, 0, 255 },
+ { "FFTLK1", 10, 0, 0, 0, 0, 255, 255, 255, 255, 1, 9, 0, 1 },
+ { "FFBLS1", 9, 0, 0, 0, 0, 255, 255, 255, 255, 3, 8, 0, 2 },
+ { "FFLOV2", 6, 0, 0, 0, 0, 255, 255, 255, 255, 3, 5, 0, 2 },
+ { "FFWOE1", 11, 0, 0, 0, 0, 255, 255, 255, 255, 3, 9, 0, 2 },
+ { "FFSNF1", 9, 0, 0, 0, 0, 255, 255, 255, 255, 4, 6, 0, 4 },
+ { "FFLAF1", 9, 0, 0, 0, 0, 255, 255, 255, 255, 2, 8, 0, 1 },
+ { "FFSKE1", 11, 0, 0, 0, 0, 255, 255, 255, 255, 3, 10, 0, 2 },
+ { "RGTLK2", 10, 0, 0, 0, 0, 4, 6, 255, 255, 2, 6, 0, 1 },
+ { "RGTLK1", 10, 0, 0, 0, 0, 4, 6, 255, 255, 2, 6, 0, 1 },
+ { "BRTLK1", 26, 0, 0, 0, 0, 255, 255, 255, 255, 2, 23, 0, 255 },
+ { "BREXT1", 14, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 255 },
+ { "BRLRT1", 19, 0, 0, 0, 0, 255, 255, 255, 255, 1, 15, 0, 255 },
+ { "BRBWV1", 12, 0, 0, 0, 0, 255, 255, 255, 255, 3, 8, 0, 255 },
+ { "BRPAT1", 11, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 255 },
+ { "BRBSP1", 7, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 255 },
+ { "BRBEX1", 10, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 255 },
+ { "BRBLK1", 10, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 255 },
+ { "BRBET1", 17, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 255 },
+ { "BRWEX1", 10, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 255 },
+ { "BBTLK2", 26, 0, 0, 0, 0, 255, 255, 255, 255, 2, 23, 1, 255 },
+ { "BBEXT2", 14, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 1, 255 },
+ { "BRLST1", 9, 0, 0, 0, 0, 255, 255, 255, 255, 2, 7, 0, 255 },
+ { "BRLSN1", 13, 0, 0, 0, 0, 255, 255, 255, 255, 1, 13, 2, 255 },
+ { "BRBNO1", 13, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 255 },
+ { "BRBND1", 8, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 255 },
+ { "BBLSN2", 13, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 255 },
+ { "CCTALK", 6, 0, 0, 0, 0, 2, 5, 255, 255, 1, 5, 0, 255 },
+ { "CCBIT1", 13, 0, 0, 0, 0, 3, 5, 9, 11, 2, 11, 2, 255 },
+ { "CCCMP1", 13, 0, 0, 0, 0, 6, 9, 255, 255, 5, 10, 1, 2 },
+ { "CCCOY1", 14, 0, 0, 0, 0, 6, 8, 255, 255, 4, 8, 0, 3 },
+ { "CCFNG1", 5, 0, 0, 0, 0, 255, 255, 255, 255, 4, 4, 0, 255 },
+ { "CCGRB1", 13, 0, 0, 0, 0, 6, 255, 255, 255, 6, 9, 0, 3 },
+ { "CCGST1", 9, 0, 0, 0, 0, 4, 255, 255, 255, 4, 7, 0, 2 },
+ { "CCHCN1", 10, 0, 0, 0, 0, 6, 9, 255, 255, 4, 9, 0, 0 },
+ { "CCHND1", 7, 0, 0, 0, 0, 6, 255, 255, 255, 2, 6, 0, 1 },
+ { "FTTLK2", 11, 0, 0, 0, 0, 1, 4, 6, 9, 1, 10, 0, 2 },
+ { "FTGNO2", 11, 0, 0, 0, 0, 4, 6, 8, 255, 4, 8, 1, 2 },
+ { "FTGST2", 6, 0, 0, 0, 0, 1, 2, 4, 5, 2, 5, 0, 1 },
+ { "FTHND2", 7, 0, 0, 0, 0, 2, 5, 255, 255, 1, 6, 1, 255 },
+ { "FTRNT2", 11, 0, 0, 0, 0, 3, 5, 7, 9, 2, 9, 1, 1 },
+ { "FTSRG2", 10, 0, 0, 0, 0, 4, 6, 8, 255, 3, 8, 1, 1 },
+ { "FTQOT2", 8, 0, 0, 0, 0, 1, 4, 8, 255, 1, 6, 1, 255 },
+ { "FMSTK1", 9, 0, 0, 0, 0, 255, 255, 255, 255, 1, 7, 0, 255 },
+ { "FMCRH1", 13, 0, 0, 0, 0, 255, 255, 255, 255, 3, 10, 0, 255 },
+ { "FMFGR1", 12, 0, 0, 0, 0, 255, 255, 255, 255, 1, 10, 0, 255 },
+ { "FMPRS1", 17, 0, 0, 0, 0, 255, 255, 255, 255, 1, 14, 0, 255 },
+ { "FMAGR1", 12, 0, 0, 0, 0, 255, 255, 255, 255, 2, 9, 0, 255 },
+ { "FMWOE1", 11, 0, 0, 0, 0, 255, 255, 255, 255, 1, 9, 0, 255 },
+ { "FMTOE1", 17, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 255 },
+ { "FM1TK1", 12, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 255 },
+ { "FM2TK1", 6, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 255 },
+ { "FM3TK1", 8, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 255 },
+ { "FMTNB1", 4, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 255 },
+ { "FMLOK1", 6, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 255 },
+ { "FMCST1", 11, 0, 0, 0, 0, 255, 255, 255, 255, 3, 8, 0, 255 },
+ { "FMLUP3", 8, 0, 0, 0, 0, 255, 255, 255, 255, 2, 5, 0, 255 },
+ { "BDTLK1", 8, 0, 0, 0, 0, 255, 255, 255, 255, 1, 7, 0, 255 },
+ { "BDGLE1", 15, 0, 0, 0, 0, 255, 255, 255, 255, 6, 10, 0, 255 },
+ { "BDSHK1", 16, 0, 0, 0, 0, 255, 255, 255, 255, 5, 11, 0, 1 },
+ { "BDWOE1", 22, 0, 0, 0, 0, 255, 255, 255, 255, 9, 16, 0, 2 },
+ { "BDHIP1", 22, 0, 0, 0, 0, 255, 255, 255, 255, 8, 16, 0, 1 },
+ { "BDFLG1", 13, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 255 },
+ { "BDKLT1", 12, 0, 0, 0, 0, 255, 255, 255, 255, 5, 10, 0, 255 },
+ { "BDSWY1", 8, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 255 },
+ { "WPSNK1", 5, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 255 },
+ { "WPLAF1", 10, 0, 0, 0, 0, 255, 255, 255, 255, 5, 9, 1, 1 },
+ { "DOTLK1", 10, 0, 0, 0, 0, 255, 255, 255, 255, 1, 8, 0, 255 },
+ { "DOGST1", 15, 0, 0, 0, 0, 255, 255, 255, 255, 4, 11, 1, 255 },
+ { "DO2DF1", 14, 0, 0, 0, 0, 255, 255, 255, 255, 3, 11, 1, 255 },
+ { "DOSNG1", 11, 0, 0, 0, 0, 255, 255, 255, 255, 8, 9, 1, 255 },
+ { "DOWOE1", 12, 0, 0, 0, 0, 255, 255, 255, 255, 5, 10, 1, 255 },
+ { "DO2ME1", 18, 0, 0, 0, 0, 255, 255, 255, 255, 5, 13, 1, 255 },
+ { "DOGLP1", 9, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 1, 255 },
+ { "DOCRY1", 9, 0, 0, 0, 0, 255, 255, 255, 255, 3, 6, 1, 255 },
+ { "METLK1", 5, 0, 0, 0, 0, 255, 255, 255, 255, 1, 4, 0, 255 },
+ { "MECHT1", 10, 0, 0, 0, 0, 255, 255, 255, 255, 2, 9, 1, 255 },
+ { "ME2DF1", 10, 0, 0, 0, 0, 255, 255, 255, 255, 2, 9, 0, 255 },
+ { "MESNG1", 12, 0, 0, 0, 0, 255, 255, 255, 255, 5, 10, 2, 255 },
+ { "MEWOE1", 13, 0, 0, 0, 0, 255, 255, 255, 255, 3, 10, 1, 255 },
+ { "ME2DO1", 11, 0, 0, 0, 0, 255, 255, 255, 255, 2, 9, 1, 255 },
+ { "MEGLP1", 9, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 1, 255 },
+ { "MECRY1", 12, 0, 0, 0, 0, 255, 255, 255, 255, 6, 9, 1, 255 },
+ { "CSTLK1", 8, 0, 0, 0, 0, 255, 255, 255, 255, 1, 7, 0, 0 },
+ { "CSNUD1", 14, 0, 0, 0, 0, 255, 255, 255, 255, 5, 11, 0, 2 },
+ { "CSSPR1", 11, 0, 0, 0, 0, 255, 255, 255, 255, 4, 8, 0, 2 },
+ { "CSWVE1", 13, 0, 0, 0, 0, 255, 255, 255, 255, 4, 9, 0, 1 },
+ { "CSYEL1", 9, 0, 0, 0, 0, 255, 255, 255, 255, 2, 6, 0, 1 },
+ { "JMTLK1", 7, 0, 0, 0, 0, 1, 4, 255, 255, 1, 6, 0, 0 },
+ { "JMEGO1", 11, 0, 0, 0, 0, 6, 255, 255, 255, 3, 8, 0, 1 },
+ { "JMARS1", 7, 0, 0, 0, 0, 4, 6, 255, 255, 3, 6, 0, 2 },
+ { "JMHIP1", 8, 0, 0, 0, 0, 3, 5, 7, 255, 2, 7, 0, 1 },
+ { "JMBNK1", 2, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 255 },
+ { "MRTLK1", 9, 0, 0, 0, 0, 4, 7, 255, 255, 2, 7, 0, 1 },
+ { "MRHOF1", 8, 0, 0, 0, 0, 3, 5, 255, 255, 2, 5, 0, 255 },
+ { "MRMRN1", 11, 0, 0, 0, 0, 3, 7, 255, 255, 1, 8, 0, 0 },
+ { "MRDPR1", 11, 0, 0, 0, 0, 1, 5, 9, 255, 1, 8, 0, 255 },
+ { "MRGLE1", 13, 0, 0, 0, 0, 5, 9, 255, 255, 3, 10, 0, 2 },
+ { "MRTDF1", 11, 0, 0, 0, 0, 3, 7, 9, 255, 3, 9, 0, 1 },
+ { "MREDF1", 11, 0, 0, 0, 0, 4, 255, 255, 255, 1, 10, 1, 255 },
+ { "MREPL1", 12, 0, 0, 0, 0, 5, 6, 7, 9, 2, 9, 1, 1 },
+ { "MRAPL1", 12, 0, 0, 0, 0, 4, 8, 9, 255, 2, 9, 0, 1 },
+ { "MREVL1", 8, 0, 0, 0, 0, 5, 255, 255, 255, 1, 5, 1, 255 },
+ { "BWDMR1", 16, 0, 0, 0, 0, 4, 7, 9, 11, 3, 14, 0, 1 },
+ { "BWBUF1", 12, 0, 0, 0, 0, 5, 8, 255, 255, 3, 11, 0, 1 },
+ { "BWHIP1", 12, 0, 0, 0, 0, 3, 6, 255, 255, 1, 9, 2, 0 },
+ { "BWHWL1", 14, 0, 0, 0, 0, 255, 255, 255, 255, 1, 4, 2, 255 },
+ { "BWLEN1", 10, 0, 0, 0, 0, 3, 6, 255, 255, 2, 7, 0, 1 },
+ { "BWSRL1", 6, 0, 0, 0, 0, 255, 255, 255, 255, 2, 5, 0, 1 },
+ { "BWWAG1", 6, 0, 0, 0, 0, 4, 10, 14, 18, 1, 4, 0, 0 },
+ { "BWYEL1", 8, 0, 0, 0, 0, 4, 255, 255, 255, 2, 7, 0, 1 },
+ { "BWTLK1", 15, 0, 0, 0, 0, 5, 8, 255, 255, 5, 9, 0, 1 },
+ { "SLTLK1", 19, 0, 0, 0, 0, 255, 255, 255, 255, 1, 18, 0, 255 },
+ { "SLPND1", 12, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 255 },
+ { "SLPNT1", 8, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 255 },
+ { "SLPTR1", 14, 0, 0, 0, 0, 255, 255, 255, 255, 6, 13, 1, 255 },
+ { "SDTLK1", 7, 0, 0, 0, 0, 255, 255, 255, 255, 1, 5, 0, 255 },
+ { "SDPDF1", 10, 0, 0, 0, 0, 255, 255, 255, 255, 3, 6, 0, 255 },
+ { "SDPNT1", 10, 0, 0, 0, 0, 255, 255, 255, 255, 2, 7, 0, 255 },
+ { "SDSLF1", 10, 0, 0, 0, 0, 255, 255, 255, 255, 2, 7, 0, 255 },
+ { "SDSTG1", 10, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 255 },
+ { "SDWVE1", 10, 0, 0, 0, 0, 255, 255, 255, 255, 1, 8, 0, 255 },
+ { "SDSTK1", 9, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 255 },
+ { "SDSMK1", 22, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 255 },
+ { "SDGLN1", 5, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 255 },
+ { "SDLAF1", 8, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 255 },
+ { "RMHIP1", 12, 0, 0, 0, 0, 7, 255, 255, 255, 1, 10, 2, 255 },
+ { "RMGES1", 19, 0, 0, 0, 0, 11, 255, 255, 255, 8, 13, 2, 2 },
+ { "RMPCH1", 18, 0, 0, 0, 0, 12, 255, 255, 255, 6, 13, 0, 2 },
+ { "RMSTH1", 12, 0, 0, 0, 0, 5, 255, 255, 255, 3, 6, 0, 2 },
+ { "RMHND1", 7, 0, 0, 0, 0, 5, 255, 255, 255, 5, 5, 1, 255 },
+ { "RMSTH1", 12, 0, 0, 0, 0, 5, 255, 255, 255, 5, 6, 1, 2 },
+ { "SGHND1", 10, 0, 0, 0, 0, 255, 255, 255, 255, 1, 9, 0, 0 },
+ { "SGSTF1", 13, 0, 0, 0, 0, 255, 255, 255, 255, 1, 12, 0, 255 },
+ { "SGSLP1", 16, 0, 0, 0, 0, 255, 255, 255, 255, 1, 15, 0, 255 },
+ { "SGPHC1", 12, 0, 0, 0, 0, 255, 255, 255, 255, 4, 9, 0, 255 },
+ { "SGHALT", 22, 0, 0, 0, 0, 255, 255, 255, 255, 7, 15, 0, 255 },
+ { "STTLK1", 13, 0, 0, 0, 0, 5, 9, 255, 255, 3, 10, 0, 2 },
+ { "STTNM1", 13, 0, 0, 0, 0, 5, 9, 255, 255, 3, 10, 0, 2 },
+ { "STFST1", 11, 0, 0, 0, 0, 3, 8, 255, 255, 1, 9, 0, 255 },
+ { "STLAF1", 20, 0, 0, 0, 0, 255, 255, 255, 255, 11, 15, 1, 2 },
+ { "STGES1", 13, 0, 0, 0, 0, 5, 7, 255, 255, 3, 7, 0, 2 },
+ { "STFNT1", 10, 0, 0, 0, 0, 4, 6, 255, 255, 255, 255, 0, 2 },
+ { "STSRK1", 10, 0, 0, 0, 0, 255, 255, 255, 255, 1, 3, 2, 0 },
+ { "STRED1", 11, 0, 0, 0, 0, 255, 255, 255, 255, 2, 10, 0, 255 },
+ { "STLKU1", 6, 0, 0, 0, 0, 3, 255, 255, 255, 2, 5, 0, 0 },
+ { "STKEY1", 15, 0, 0, 0, 0, 9, 11, 255, 255, 9, 14, 0, 255 },
+ { "STMKTD1", 7, 0, 0, 0, 0, 3, 6, 255, 255, 1, 6, 0, 255 },
+ { "STTKM1", 21, 0, 0, 0, 0, 12, 13, 15, 16, 12, 17, 0, 1 },
+ { "STMSZ1", 10, 0, 0, 0, 0, 255, 255, 255, 255, 1, 3, 2, 255 },
+ { "STPNV1", 14, 0, 0, 0, 0, 6, 11, 255, 255, 4, 11, 0, 1 },
+ { "STSOM1", 10, 0, 0, 0, 0, 255, 255, 255, 255, 1, 3, 2, 255 },
+ { "MYTLK1", 9, 0, 0, 0, 0, 2, 4, 255, 255, 1, 4, 0, 0 },
+ { "MYSQUAWK", 5, 0, 0, 0, 0, 255, 255, 255, 255, 3, 3, 1, 255 },
+ { "SPTLK", 12, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 255 },
+ { "SPARM", 16, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 255 },
+ { "SPHOP", 18, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 255 },
+ { "SPLNT", 16, 0, 0, 0, 0, 255, 255, 255, 255, 3, 13, 0, 255 },
+ { "SPLAF", 11, 0, 0, 0, 0, 255, 255, 255, 255, 5, 10, 2, 255 },
+ { "SPTFN", 10, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 255 },
+ { "SPPIN", 14, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 255 },
+ { "SPINH1", 21, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 255 },
+ { "SPSFTCOM", 10, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 0, 255 },
+ { "MFTMZ1", 9, 0, 0, 0, 0, 255, 255, 255, 255, 1, 8, 1, 255 },
+ { "MFTLK1", 13, 0, 0, 0, 0, 2, 7, 255, 255, 1, 12, 1, 255 },
+ { "VGCIR1", 15, 0, 0, 0, 0, 5, 9, 255, 255, 2, 13, 1, 255 },
+ { "VGBIT1", 12, 0, 0, 0, 0, 6, 9, 255, 255, 2, 9, 1, 255 },
+ { "VGANG1", 10, 0, 0, 0, 0, 9, 255, 255, 255, 1, 9, 0, 255 },
+ { "VGCOM1", 13, 0, 0, 0, 0, 5, 11, 255, 255, 2, 11, 0, 255 },
+ { "VGCUR1", 8, 0, 0, 0, 0, 4, 8, 255, 255, 2, 7, 0, 255 },
+ { "VGTLK1", 11, 0, 0, 0, 0, 3, 6, 255, 255, 3, 10, 0, 255 },
+ { "VGEXP1", 10, 0, 0, 0, 0, 5, 9, 255, 255, 3, 9, 0, 255 },
+ { "WFTLK1", 8, 0, 0, 0, 0, 255, 255, 255, 255, 1, 7, 0, 1 },
+ { "WFPNT1", 20, 0, 0, 0, 0, 255, 255, 255, 255, 6, 16, 0, 1 },
+ { "WFFST1", 13, 0, 0, 0, 0, 255, 255, 255, 255, 2, 8, 0, 2 },
+ { "WFTNO1", 8, 0, 0, 0, 0, 255, 255, 255, 255, 2, 5, 0, 2 },
+ { "WFSRG1", 11, 0, 0, 0, 0, 255, 255, 255, 255, 3, 8, 0, 1 },
+ { "WFGTK1", 16, 0, 0, 0, 0, 255, 255, 255, 255, 1, 15, 0, 255 },
+ { "WFPAW1", 24, 0, 0, 0, 0, 255, 255, 255, 255, 4, 22, 0, 1 },
+ { "LGTLK", 20, 0, 0, 0, 0, 4, 8, 11, 15, 1, 17, 0, 255 },
+ { "LGSHOUT", 16, 0, 0, 0, 0, 12, 255, 255, 255, 6, 12, 0, 255 },
+ { "POMRN1", 12, 0, 0, 0, 0, 3, 5, 7, 255, 3, 9, 0, 2 },
+ { "POGLE1", 14, 0, 0, 0, 0, 7, 10, 255, 255, 5, 10, 0, 2 },
+ { "PLMRG1", 16, 0, 0, 0, 0, 9, 255, 255, 255, 8, 12, 0, 1 },
+ { "PLCMR1", 16, 0, 0, 0, 0, 8, 10, 255, 255, 8, 12, 0, 3 },
+ { "PLEVL1", 17, 0, 0, 0, 0, 9, 255, 255, 255, 7, 9, 0, 1 },
+ { "PLEDF1", 9, 0, 0, 0, 0, 4, 6, 255, 255, 5, 7, 0, 2 },
+ { "PLTLK1", 11, 0, 0, 0, 0, 5, 8, 255, 255, 5, 8, 0, 1 },
+ { "ELTLK1", 8, 0, 0, 0, 0, 3, 5, 7, 255, 2, 7, 0, 255 },
+ { "ELSNR1", 7, 0, 0, 0, 0, 3, 255, 255, 255, 1, 5, 0, 255 },
+ { "RG2TK1", 10, 0, 0, 0, 0, 4, 6, 255, 255, 2, 6, 0, 1 },
+ { "RG2TK1", 10, 0, 0, 0, 0, 4, 6, 255, 255, 2, 6, 0, 1 },
+ { "C2TALK", 6, 0, 0, 0, 0, 2, 5, 255, 255, 1, 5, 0, 255 },
+ { "C2BIT1", 13, 0, 0, 0, 0, 3, 5, 9, 11, 2, 11, 2, 255 },
+ { "C2CMP1", 13, 0, 0, 0, 0, 6, 9, 255, 255, 5, 10, 1, 2 },
+ { "C2COY1", 14, 0, 0, 0, 0, 6, 8, 255, 255, 4, 8, 0, 3 },
+ { "C2FNG1", 5, 0, 0, 0, 0, 255, 255, 255, 255, 4, 4, 0, 255 },
+ { "C2GRB1", 13, 0, 0, 0, 0, 6, 255, 255, 255, 6, 9, 0, 3 },
+ { "C2GST1", 9, 0, 0, 0, 0, 4, 255, 255, 255, 4, 7, 0, 2 },
+ { "C2HCN1", 10, 0, 0, 0, 0, 6, 9, 255, 255, 4, 9, 0, 0 },
+ { "C2HND1", 7, 0, 0, 0, 0, 6, 255, 255, 255, 2, 6, 0, 1 },
+ { "666TKBB3", 21, 0, 0, 0, 0, 9, 14, 255, 255, 6, 16, 0, 255 },
+ { "665TFLX3", 27, 0, 0, 0, 0, 10, 14, 17, 255, 10, 18, 0, 255 },
+ { "664FXTK3", 18, 0, 0, 0, 0, 5, 7, 11, 13, 3, 15, 0, 255 },
+ { "FDTALK", 15, 0, 0, 0, 0, 9, 255, 255, 255, 7, 9, 0, 255 },
+ { "FDYELL", 16, 0, 0, 0, 0, 10, 255, 255, 255, 8, 10, 0, 255 },
+ { "GLTLK", 20, 0, 0, 0, 0, 6, 12, 18, 255, 1, 19, 0, 255 },
+ { "GLTRN", 4, 0, 0, 0, 0, 3, 255, 255, 255, 1, 2, 0, 255 },
+ { "RAYTALK1", 10, 0, 0, 0, 0, 3, 5, 8, 255, 1, 9, 0, 255 },
+ { "BRTKB1", 17, 0, 0, 0, 0, 255, 255, 255, 255, 2, 14, 0, 255 }
+ };
+
+ static const int32 characterAnims[] = {
+ 0, 39, 81, 89, 91, 108, 117, 124, 138, 146,
+ 148, 156, 164, 169, 174, 179, 184, 193, 197, 207,
+ 213, 218, 233, 235, 244, 245, 246, 246, 246, 246,
+ 253, 253, 253, 253, 260, 262, 264, 269, 271, 273,
+ 282, 284, 285, 287, 289, 290, 291, 291, 291, 291,
+ 289, 289, 289, 289, 289, 289, 289, 289, 289, 289
+ };
+
+ return &anims[characterAnims[characterId] + animationId];
+}
+
+bool Character::loadShadowAnimation(Common::String animName) {
+ debugC(1, kDebugCharacter, "loadShadowAnimation(%s)", animName.c_str());
+
+ _shadowAnim = new Animation(_vm);
+ if (!_shadowAnim->loadAnimation(animName))
+ return false;
+
+ _shadowAnimationInstance = _vm->getAnimationManager()->createNewInstance(kAnimationCharacter);
+ _vm->getAnimationManager()->addInstance(_shadowAnimationInstance);
+ _shadowAnimationInstance->setAnimation(_shadowAnim);
+ _shadowAnimationInstance->setVisible(true);
+ _shadowAnimationInstance->setUseMask(true);
+
+ return true;
+}
+
+void Character::playAnim(int32 animId, int32 unused, int32 flags) {
+ debugC(3, kDebugCharacter, "playAnim(%d, unused, %d)", animId, flags);
+
+ if (animId == 0)
+ animId = _animSpecialDefaultId;
+
+ // get the anim to load
+ const SpecialCharacterAnimation *anim = getSpecialAnimation(_id, animId);
+
+ char animName[20];
+ strcpy(animName, anim->_filename);
+
+ int32 facing = _facing;
+ if (_id == 1) {
+ // flux special case... some animations are not for every facing
+ facing = CharacterFlux::fixFacingForAnimation(facing, animId);
+ }
+
+ if (strchr(animName, '?'))
+ *strchr(animName, '?') = '0' + facing;
+ strcat(animName, ".CAF");
+
+
+ if (_animScriptId != -1 && (flags & 8) == 0)
+ _vm->getSceneAnimationScript(_animScriptId)->_frozenForConversation = true;
+
+ stopSpecialAnim();
+
+ if (flags & 8) {
+ // talker
+ _lineToSayId = _vm->getCurrentLineToSay();
+
+ // make the talker busy
+ _flags |= 1;
+
+ // wait for the character to be ready
+ while (_animScriptId != -1 && _animationInstance->getFrame() > 0 && (_specialAnim && _animationInstance->getAnimation() != _specialAnim)) {
+ _vm->simpleUpdate(false);
+ }
+ }
+
+
+ if (_sceneAnimationId > -1)
+ setAnimationInstance(_vm->getSceneAnimation(_sceneAnimationId)->_animInstance);
+
+
+ _animFlags |= flags;
+
+ if (_specialAnim)
+ delete _specialAnim;
+ _specialAnim = new Animation(_vm);
+ _specialAnim->loadAnimation(animName);
+
+ _animSpecialId = animId;
+
+ _animationInstance->setAnimation(_specialAnim);
+ _animationInstance->setAnimationRange(0, _specialAnim->_numFrames - 1);
+ _animationInstance->reset();
+ _animationInstance->stopAnimation();
+ _animationInstance->setLooping(false);
+}
+
+int32 Character::getAnimFlag() {
+ return _animFlags;
+}
+
+void Character::setAnimFlag(int32 flag) {
+ _animFlags = flag;
+}
+
+int32 Character::getSceneAnimationId() {
+ return _sceneAnimationId;
+}
+
+void Character::setDefaultSpecialAnimationId(int32 defaultAnimationId) {
+ _animSpecialDefaultId = defaultAnimationId;
+}
+
+int32 Character::getFinalX() {
+ return _finalX;
+}
+
+int32 Character::getFinalY() {
+ return _finalY;
+}
+
+void Character::updateIdle() {
+ debugC(5, kDebugCharacter, "updateIdle()");
+
+ // only flux and drew
+ if (_id > 1)
+ return;
+
+ if (_vm->state()->_mouseHidden)
+ _nextIdleTime = _vm->getOldMilli() + (300 + _vm->randRange(0, 600)) * _vm->getTickLength();
+
+ if (_vm->getOldMilli() > _nextIdleTime) {
+ if (((_flags & 1) == 0) || ((_flags & 2) != 0)) {
+ if (!_vm->state()->_inCloseUp && !_vm->state()->_inCutaway && _animSpecialId == -1) {
+ if (!_vm->state()->_mouseHidden) {
+ _nextIdleTime = _vm->getOldMilli() + (300 + _vm->randRange(0, 600)) * _vm->getTickLength();
+ playAnim(getRandomIdleAnim(), 0, 0x40);
+ _flags |= 0x4;
+ }
+ }
+ }
+ }
+}
+} // End of namespace Toon
+
diff --git a/engines/toon/character.h b/engines/toon/character.h
new file mode 100644
index 0000000000..43636b8eb5
--- /dev/null
+++ b/engines/toon/character.h
@@ -0,0 +1,148 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* $URL$
+* $Id$
+*
+*/
+
+#ifndef TOON_CHARACTER_H
+#define TOON_CHARACTER_H
+
+#include "toon/toon.h"
+
+namespace Toon {
+
+class ToonEngine;
+
+struct SpecialCharacterAnimation {
+ char _filename[9]; // 0
+ byte _flag1; // 9
+ short _offsetX; // 10
+ short _offsetY; // 12
+ short _unused; // 14
+ short _unused2; // 16
+ byte _flags2; // 18
+ byte _flags3; // 19
+ byte _flags4; // 20
+ byte _flags5; // 21
+ byte _flags6; // 22
+ byte _flags7; // 23
+ byte _flags8; // 24
+ byte _flags9; // 25
+};
+
+
+class Character {
+public:
+ Character(ToonEngine *vm);
+ virtual ~Character(void);
+ virtual void init();
+ virtual int32 getId();
+ virtual void setId(int32 id);
+ virtual void setFacing(int32 facing);
+ virtual int32 getFacing();
+ virtual void setAnimScript(int32 animScriptId);
+ virtual void setSceneAnimationId(int32 sceneAnimationId);
+ virtual void setDefaultSpecialAnimationId(int32 defaultAnimationId);
+ virtual int32 getAnimScript();
+ virtual int32 getSceneAnimationId();
+ virtual void setFlag(int flag);
+ virtual int32 getFlag();
+ virtual int32 getAnimFlag();
+ virtual void setAnimFlag(int32 flag);
+ virtual void setPosition(int32 x, int32 y);
+ virtual int32 getX();
+ virtual int32 getY();
+ virtual int32 getFinalX();
+ virtual int32 getFinalY();
+ virtual bool walkTo(int32 newPosX, int32 newPosY);
+ virtual bool getVisible();
+ virtual void setVisible(bool visible);
+ virtual bool loadWalkAnimation(Common::String animName);
+ virtual bool loadIdleAnimation(Common::String animName);
+ virtual bool loadTalkAnimation(Common::String animName);
+ virtual bool loadShadowAnimation(Common::String animName);
+ virtual bool setupPalette();
+ virtual void playStandingAnim();
+ virtual void playWalkAnim(int32 start, int32 end);
+ virtual void playTalkAnim();
+ virtual void playAnim(int32 animId, int32 unused, int32 flags);
+ virtual void update(int32 timeIncrement);
+ virtual int32 getScale();
+ virtual AnimationInstance *getAnimationInstance();
+ virtual void setAnimationInstance(AnimationInstance *instance);
+ virtual void save(Common::WriteStream *stream);
+ virtual void load(Common::ReadStream *stream);
+ virtual void stopWalk();
+ virtual void stopSpecialAnim();
+ virtual void updateIdle();
+ virtual int32 getRandomIdleAnim() { return 0; }
+ virtual void updateTimers(int32 relativeAdd);
+ virtual void setTalking(bool talking) { _isTalking = talking; }
+ virtual bool isTalking() { return _isTalking; }
+
+ int32 getFacingFromDirection(int32 dx, int32 dy);
+ static const SpecialCharacterAnimation *getSpecialAnimation(int32 characterId, int32 animationId);
+
+
+protected:
+ ToonEngine *_vm;
+
+ int32 _id;
+ int32 _animScriptId;
+ int32 _animSpecialId;
+ int32 _animSpecialDefaultId;
+ int32 _sceneAnimationId;
+ int32 _lineToSayId;
+ int32 _time;
+ int32 _x;
+ int32 _y;
+ int32 _z;
+ int32 _finalX;
+ int32 _finalY;
+ int32 _facing;
+ int32 _flags;
+ int32 _animFlags;
+ int32 _scale;
+ int32 _nextIdleTime;
+ bool _visible;
+ bool _blockingWalk;
+ int32 _speed;
+ int32 _lastWalkTime;
+ int32 _numPixelToWalk;
+ bool _isTalking;
+
+ AnimationInstance *_animationInstance;
+ AnimationInstance *_shadowAnimationInstance;
+ Animation *_walkAnim;
+ Animation *_idleAnim;
+ Animation *_talkAnim;
+ Animation *_shadowAnim;
+ Animation *_specialAnim;
+
+ int32 _currentPathX[4096];
+ int32 _currentPathY[4096];
+ int32 _currentPathNodeCount;
+ int32 _currentPathNode;
+};
+
+} // End of namespace Toon
+#endif
diff --git a/engines/toon/conversation.cpp b/engines/toon/conversation.cpp
new file mode 100644
index 0000000000..4678ccc1c8
--- /dev/null
+++ b/engines/toon/conversation.cpp
@@ -0,0 +1,49 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* $URL$
+* $Id$
+*
+*/
+
+#include "toon/conversation.h"
+
+namespace Toon {
+
+void Conversation::save(Common::WriteStream *stream, int16 *conversationDataBase) {
+ stream->writeSint32BE(_enable);
+ for (int32 i = 0; i < 10; i++) {
+ stream->writeSint32BE(state[i]._data2);
+ stream->writeSint16BE(state[i]._data3);
+ stream->writeSint32BE((int16 *)state[i]._data4 - conversationDataBase);
+ }
+}
+
+void Conversation::load(Common::ReadStream *stream, int16 *conversationDataBase) {
+ _enable = stream->readSint32BE();
+ for (int32 i = 0; i < 10; i++) {
+ state[i]._data2 = stream->readSint32BE();
+ state[i]._data3 = stream->readSint16BE();
+ state[i]._data4 = conversationDataBase + stream->readSint32BE();
+ }
+}
+
+
+}
diff --git a/engines/toon/conversation.h b/engines/toon/conversation.h
new file mode 100644
index 0000000000..784c681055
--- /dev/null
+++ b/engines/toon/conversation.h
@@ -0,0 +1,50 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* $URL$
+* $Id$
+*
+*/
+
+#ifndef TOON_CONVERSATION_H
+#define TOON_CONVERSATION_H
+
+#include "engines/engine.h"
+#include "common/stream.h"
+
+namespace Toon {
+
+class Conversation {
+public:
+ int32 _enable; // 00
+
+ struct ConvState {
+ int32 _data2; // 04
+ int16 _data3; // 08
+ void *_data4; // 10
+ } state[10];
+
+ void save(Common::WriteStream *stream, int16 *conversationDataBase);
+ void load(Common::ReadStream *stream, int16 *conversationDataBase);
+};
+
+} // End of namespace Toon
+
+#endif
diff --git a/engines/toon/detection.cpp b/engines/toon/detection.cpp
new file mode 100644
index 0000000000..e9649b1560
--- /dev/null
+++ b/engines/toon/detection.cpp
@@ -0,0 +1,273 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/config-manager.h"
+#include "engines/advancedDetector.h"
+#include "common/savefile.h"
+#include "common/system.h"
+#include "base/plugins.h"
+#include "graphics/thumbnail.h"
+#include "toon/toon.h"
+
+static const PlainGameDescriptor ToonGames[] = {
+ { "toon", "Toonstruck" },
+ { 0, 0 }
+};
+
+namespace Toon {
+
+using Common::GUIO_NONE;
+
+static const ADGameDescription gameDescriptions[] = {
+ {
+ "toon", "",
+ {
+ {"local.pak", 0, "3290209ef9bc92692108dd2f45df0736", 3237611},
+ {"arcaddbl.svl", 0, "c418478cd2833c7c983799f948af41ac", 7844688},
+ {"study.svl", 0, "281efa3f33f6712c0f641a605f4d40fd", 2511090},
+ AD_LISTEND
+ },
+ Common::EN_ANY, Common::kPlatformPC, ADGF_NO_FLAGS, GUIO_NONE
+ },
+ {
+ "toon", "",
+ {
+ {"local.pak", 0, "517132c3575b38806d1e7b6f59848072", 3224044},
+ {"arcaddbl.svl", 0, "ff74008827b62fbef1f46f104c438e44", 9699256},
+ {"study.svl", 0, "df056b94ea83f1ed92a539cf636053ab", 2542668},
+ AD_LISTEND
+ },
+ Common::FR_FRA, Common::kPlatformPC, ADGF_NO_FLAGS, GUIO_NONE
+ },
+ {
+ "toon", "",
+ {
+ {"local.pak", 0, "bf5da4c03f78ffbd643f12122319366e", 3250841},
+ {"arcaddbl.svl", 0, "7a0d74f4d66d1c722b946abbeb0834ef", 9122249},
+ {"study.svl", 0, "72fe96a9e10967d3138e918295babc42", 2910283},
+ AD_LISTEND
+ },
+ Common::DE_DEU, Common::kPlatformPC, ADGF_NO_FLAGS, GUIO_NONE
+ },
+ {
+ "toon", "",
+ {
+ {"local.pak", 0, "e8645168a247e2abdbfc2f9fa9d1c0fa", 3232222},
+ {"arcaddbl.svl", 0, "7893ac4cc78d51356baa058bbee7aa28", 8275016},
+ {"study.svl", 0, "b6b1ee2d9d94d53d305856039ab7bde7", 2634620},
+ AD_LISTEND
+ },
+ Common::ES_ESP, Common::kPlatformPC, ADGF_NO_FLAGS, GUIO_NONE
+ },
+ {
+ "toon", "",
+ {
+ {"local.pak", 0, "bf5da4c03f78ffbd643f12122319366e", 3250841},
+ {"wacexdbl.emc", 0, "cfbc2156a31b294b038204888407ebc8", 6974},
+ {"generic.svl", 0, "5eb99850ada22f0b8cf6392262d4dd07", 9404599},
+ AD_LISTEND
+ },
+ Common::DE_DEU, Common::kPlatformPC, ADGF_DEMO, GUIO_NONE
+ },
+
+ AD_TABLE_END_MARKER
+};
+
+static const ADFileBasedFallback fileBasedFallback[] = {
+ { &gameDescriptions[0], { "local.pak", "arcaddbl.svl", "study.svl", 0 } }, // default to english version
+ { 0, { 0 } }
+};
+
+} // End of namespace Toon
+
+static const char * const directoryGlobs[] = {
+ "misc",
+ "act1",
+ "arcaddbl",
+ "act2",
+ "study",
+ 0
+};
+
+static const ADParams detectionParams = {
+ (const byte *)Toon::gameDescriptions,
+ sizeof(ADGameDescription),
+ 5000, // number of md5 bytes
+ ToonGames,
+ 0, // no obsolete targets data
+ "toon",
+ Toon::fileBasedFallback,
+ 0,
+ // Additional GUI options (for every game}
+ Common::GUIO_NONE,
+ // Maximum directory depth
+ 3,
+ // List of directory globs
+ directoryGlobs
+};
+
+class ToonMetaEngine : public AdvancedMetaEngine {
+public:
+ ToonMetaEngine() : AdvancedMetaEngine(detectionParams) {}
+
+ virtual const char *getName() const {
+ return "Toon Engine";
+ }
+
+ virtual const char *getOriginalCopyright() const {
+ return "Toonstruck (C) 1996 Virgin Interactive";
+ }
+
+ virtual bool hasFeature(MetaEngineFeature f) const;
+ virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
+ virtual int getMaximumSaveSlot() const;
+ virtual SaveStateList listSaves(const char *target) const;
+ SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;
+ virtual void removeSaveState(const char *target, int slot) const;
+};
+
+bool ToonMetaEngine::hasFeature(MetaEngineFeature f) const {
+ return
+ (f == kSupportsListSaves) ||
+ (f == kSupportsLoadingDuringStartup) ||
+ (f == kSupportsDeleteSave) ||
+ (f == kSavesSupportMetaInfo) ||
+ (f == kSavesSupportThumbnail) ||
+ (f == kSavesSupportCreationDate);
+}
+
+void ToonMetaEngine::removeSaveState(const char *target, int slot) const {
+ Common::String fileName = Common::String::printf("%s.%03d", target, slot);
+ g_system->getSavefileManager()->removeSavefile(fileName);
+}
+
+int ToonMetaEngine::getMaximumSaveSlot() const { return 99; }
+
+SaveStateList ToonMetaEngine::listSaves(const char *target) const {
+ Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+ Common::StringArray filenames;
+ Common::String pattern = target;
+ pattern += ".???";
+
+ filenames = saveFileMan->listSavefiles(pattern);
+ sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
+
+ SaveStateList saveList;
+ int slotNum = 0;
+ for (Common::StringArray::const_iterator filename = filenames.begin(); filename != filenames.end(); ++filename) {
+ // Obtain the last 3 digits of the filename, since they correspond to the save slot
+ slotNum = atoi(filename->c_str() + filename->size() - 3);
+
+ if (slotNum >= 0 && slotNum <= 99) {
+ Common::InSaveFile *file = saveFileMan->openForLoading(*filename);
+ if (file) {
+ int32 version = file->readSint32BE();
+ if (version != TOON_SAVEGAME_VERSION) {
+ delete file;
+ continue;
+ }
+
+ // read name
+ uint16 nameSize = file->readUint16BE();
+ if (nameSize >= 255) {
+ delete file;
+ continue;
+ }
+ char name[256];
+ file->read(name, nameSize);
+ name[nameSize] = 0;
+
+ saveList.push_back(SaveStateDescriptor(slotNum, name));
+ delete file;
+ }
+ }
+ }
+
+ return saveList;
+}
+
+SaveStateDescriptor ToonMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
+ Common::String fileName = Common::String::printf("%s.%03d", target, slot);
+ Common::InSaveFile *file = g_system->getSavefileManager()->openForLoading(fileName);
+
+ if (file) {
+
+ int32 version = file->readSint32BE();
+ if (version != TOON_SAVEGAME_VERSION) {
+ delete file;
+ return SaveStateDescriptor();
+ }
+
+ uint32 saveNameLength = file->readUint16BE();
+ char saveName[256];
+ file->read(saveName, saveNameLength);
+ saveName[saveNameLength] = 0;
+
+ SaveStateDescriptor desc(slot, saveName);
+
+ Graphics::Surface *thumbnail = new Graphics::Surface();
+ assert(thumbnail);
+ if (!Graphics::loadThumbnail(*file, *thumbnail)) {
+ delete thumbnail;
+ thumbnail = 0;
+ }
+ desc.setThumbnail(thumbnail);
+
+ desc.setDeletableFlag(true);
+ desc.setWriteProtectedFlag(false);
+
+ uint32 saveDate = file->readUint32BE();
+ uint16 saveTime = file->readUint16BE();
+
+ int day = (saveDate >> 24) & 0xFF;
+ int month = (saveDate >> 16) & 0xFF;
+ int year = saveDate & 0xFFFF;
+
+ desc.setSaveDate(year, month, day);
+
+ int hour = (saveTime >> 8) & 0xFF;
+ int minutes = saveTime & 0xFF;
+
+ desc.setSaveTime(hour, minutes);
+
+ delete file;
+ return desc;
+ }
+
+ return SaveStateDescriptor();
+}
+
+bool ToonMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
+ if (desc) {
+ *engine = new Toon::ToonEngine(syst, desc);
+ }
+ return desc != 0;
+}
+
+#if PLUGIN_ENABLED_DYNAMIC(TOON)
+ REGISTER_PLUGIN_DYNAMIC(TOON, PLUGIN_TYPE_ENGINE, ToonMetaEngine);
+#else
+ REGISTER_PLUGIN_STATIC(TOON, PLUGIN_TYPE_ENGINE, ToonMetaEngine);
+#endif
diff --git a/engines/toon/drew.cpp b/engines/toon/drew.cpp
new file mode 100644
index 0000000000..b50a8db3dc
--- /dev/null
+++ b/engines/toon/drew.cpp
@@ -0,0 +1,122 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "toon/drew.h"
+
+namespace Toon {
+
+CharacterDrew::CharacterDrew(ToonEngine *vm) : Character(vm) {
+ _id = 0;
+ _blockingWalk = true;
+ _animationInstance = vm->getAnimationManager()->createNewInstance(kAnimationCharacter);
+ _animationInstance->setUseMask(true);
+ vm->getAnimationManager()->addInstance(_animationInstance);
+}
+
+CharacterDrew::~CharacterDrew(void) {
+}
+
+bool CharacterDrew::setupPalette() {
+ debugC(1, kDebugCharacter, "setupPalette()");
+
+ if (_walkAnim) {
+ _walkAnim->applyPalette(129, 129 * 3, 63);
+ return true;
+ }
+ return false;
+}
+
+void CharacterDrew::setFacing(int32 facing) {
+ debugC(4, kDebugCharacter, "setFacing(%d)", facing);
+ _facing = facing;
+}
+
+void CharacterDrew::setPosition(int32 x, int32 y) {
+ debugC(5, kDebugCharacter, "setPosition(%d, %d)", x, y);
+
+ _z = _vm->getLayerAtPoint(x, y);
+ _scale = _vm->getScaleAtPoint(x, y);
+
+ // work out position and scale of the character sprite
+ int32 width = _walkAnim->getWidth() * _scale / 1024;
+ int32 height = 210 * _scale / 1024;
+ _animationInstance->setPosition(x - width / 2, y - height, _z , false);
+ _animationInstance->setScale(_scale);
+
+ // work out position and scale of the shadow below character
+ int32 shadowWidth = _shadowAnim->getWidth() * _scale / 1024;
+ int32 shadowHeight = _shadowAnim->getHeight() * _scale / 1024;
+
+ _shadowAnimationInstance->setPosition(x - shadowWidth / 2, y - shadowHeight / 2 - 4 , _z , false);
+ _shadowAnimationInstance->setScale(_scale);
+
+ _x = x;
+ _y = y;
+ _animationInstance->setLayerZ(_y);
+}
+
+void CharacterDrew::playStandingAnim() {
+ debugC(4, kDebugCharacter, "playStandingAnim()");
+
+ stopSpecialAnim();
+ _animationInstance->setAnimation(_walkAnim);
+ _animationInstance->setFrame(_facing * 2);
+ _shadowAnimationInstance->setFrame(_facing);
+ _animationInstance->setAnimationRange(_facing * 2, _facing * 2);
+ _animationInstance->stopAnimation();
+ _animationInstance->setLooping(true);
+ //setVisible(true);
+
+}
+
+void CharacterDrew::playWalkAnim(int32 start, int32 end) {
+ debugC(4, kDebugCharacter, "playWalkAnim(%d, %d)", start, end);
+
+ stopSpecialAnim();
+ _animationInstance->setAnimation(_walkAnim);
+ _shadowAnimationInstance->setFrame(_facing);
+ _animationInstance->setAnimationRange(16 + _facing * 14, 16 + _facing * 14 + 13);
+ _animationInstance->playAnimation();
+ _animationInstance->setFps(16);
+ _animationInstance->setLooping(true);
+
+ //setVisible(true);
+}
+
+void CharacterDrew::update(int32 timeIncrement) {
+ debugC(5, kDebugCharacter, "update(%d)", timeIncrement);
+ Character::update(timeIncrement);
+ setPosition(_x, _y);
+
+}
+
+int32 CharacterDrew::getRandomIdleAnim() {
+ debugC(3, kDebugCharacter, "getRandomIdleAnim()");
+
+ static const int32 idle[] = { 6, 9, 10, 11, 12 };
+ return idle[_vm->randRange(0, 4)];
+}
+} // End of namespace Toon
+
diff --git a/engines/toon/drew.h b/engines/toon/drew.h
new file mode 100644
index 0000000000..a5be4c76c3
--- /dev/null
+++ b/engines/toon/drew.h
@@ -0,0 +1,51 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* $URL$
+* $Id$
+*
+*/
+
+#ifndef TOON_DREW_H
+#define TOON_DREW_H
+
+#include "toon/character.h"
+
+
+namespace Toon {
+
+class ToonEngine;
+
+class CharacterDrew : public Character {
+public:
+ CharacterDrew(ToonEngine *vm);
+ virtual ~CharacterDrew(void);
+ bool setupPalette();
+ void setFacing(int32 facing);
+ void playStandingAnim();
+ void setPosition(int32 x, int32 y);
+ void update(int32 timeIncrement);
+ void playWalkAnim(int32 start, int32 end);
+ int32 getRandomIdleAnim();
+};
+
+} // End of namespace Toon
+
+#endif
diff --git a/engines/toon/flux.cpp b/engines/toon/flux.cpp
new file mode 100644
index 0000000000..9dd38cd37a
--- /dev/null
+++ b/engines/toon/flux.cpp
@@ -0,0 +1,140 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* $URL$
+* $Id$
+*
+*/
+
+#include "toon/flux.h"
+
+namespace Toon {
+
+CharacterFlux::CharacterFlux(ToonEngine *vm) : Character(vm) {
+ _id = 1;
+ _animationInstance = vm->getAnimationManager()->createNewInstance(kAnimationCharacter);
+ _animationInstance->setUseMask(true);
+ vm->getAnimationManager()->addInstance(_animationInstance);
+}
+
+CharacterFlux::~CharacterFlux(void) {
+}
+
+void CharacterFlux::playStandingAnim() {
+ debugC(4, kDebugCharacter, "playStandingAnim()");
+
+ _animationInstance->setAnimation(_walkAnim);
+ _animationInstance->setFrame(_facing * 3);
+ _animationInstance->setAnimationRange(_facing * 3, _facing * 3);
+ _animationInstance->stopAnimation();
+ _animationInstance->setLooping(true);
+
+ //s/etVisible(true);
+}
+
+void CharacterFlux::setVisible(bool visible) {
+ if (_vm->state()->_currentChapter == 2) {
+ Character::setVisible(false);
+ } else {
+ Character::setVisible(visible);
+ }
+}
+
+void CharacterFlux::playWalkAnim(int32 start, int32 end) {
+ debugC(4, kDebugCharacter, "playWalkAnim(%d, %d)", start, end);
+
+ _animationInstance->setAnimation(_walkAnim);
+ _animationInstance->setAnimationRange(24 + _facing * 10, 24 + _facing * 10 + 9);
+ _animationInstance->playAnimation();
+ _animationInstance->setFps(16);
+ _animationInstance->setLooping(true);
+}
+
+int32 CharacterFlux::fixFacingForAnimation(int32 originalFacing, int32 animationId) {
+
+ static const byte fixFluxAnimationFacing[] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xee, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x55,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+ byte animFacingFlag = fixFluxAnimationFacing[animationId];
+ int32 v5 = 1 << originalFacing;
+ int32 v6 = 1 << originalFacing;
+ int32 facingMask = 0;
+ do {
+ if (v6 & animFacingFlag) {
+ facingMask = v6;
+ } else if (v5 & animFacingFlag) {
+ facingMask = v5;
+ }
+ v5 >>= 1;
+ v6 <<= 1;
+ }
+ while (!facingMask);
+
+ int32 finalFacing = 0;
+ for (finalFacing = 0; ; ++finalFacing) {
+ facingMask >>= 1;
+ if (!facingMask)
+ break;
+ }
+
+ return finalFacing;
+}
+
+void CharacterFlux::setPosition(int32 x, int32 y) {
+ debugC(5, kDebugCharacter, "setPosition(%d, %d)", x, y);
+
+ _z = _vm->getLayerAtPoint(x, y);
+ _scale = _vm->getScaleAtPoint(x, y);
+ int32 width = _walkAnim->getWidth() * _scale / 1024;
+ int32 height = 165 * _scale / 1024;
+ _animationInstance->setPosition(x - width / 2, y - height, _z , false);
+ _animationInstance->setScale(_scale);
+
+ // in original code, flux shadow scale is 3/4 of real scale
+ int32 shadowScale = _scale * 3 / 4;
+
+ // work out position and scale of the shadow below character
+ int32 shadowWidth = _shadowAnim->getWidth() * shadowScale / 1024;
+ int32 shadowHeight = _shadowAnim->getHeight() * shadowScale / 1024;
+ _shadowAnimationInstance->setPosition(x - shadowWidth / 2, y - shadowHeight / 2 , _z , false);
+ _shadowAnimationInstance->setScale(shadowScale);
+ _x = x;
+ _y = y;
+ _finalX = x;
+ _finalY = y;
+ _animationInstance->setLayerZ(_y);
+}
+
+void CharacterFlux::update(int32 timeIncrement) {
+ debugC(5, kDebugCharacter, "update(%d)", timeIncrement);
+ Character::update(timeIncrement);
+ setPosition(_x, _y);
+}
+
+int32 CharacterFlux::getRandomIdleAnim() {
+ debugC(3, kDebugCharacter, "getRandomIdleAnim()");
+ static const int32 idle[] = { 0xe, 0xf, 0x21, 0x22, 0x24, 0x25, 0x27 };
+ return idle[_vm->randRange(0, 6)];
+}
+
+} // End of namespace Toon
diff --git a/engines/toon/flux.h b/engines/toon/flux.h
new file mode 100644
index 0000000000..7981799cba
--- /dev/null
+++ b/engines/toon/flux.h
@@ -0,0 +1,52 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* $URL$
+* $Id$
+*
+*/
+
+#ifndef TOON_FLUX_H
+#define TOON_FLUX_H
+
+
+#include "toon/character.h"
+
+class ToonEngine;
+
+namespace Toon {
+
+class CharacterFlux : public Character {
+public:
+ CharacterFlux(ToonEngine *vm);
+ virtual ~CharacterFlux(void);
+
+ void setPosition(int32 x, int32 y);
+ void playStandingAnim();
+ void playWalkAnim(int32 start, int32 end);
+ void update(int32 timeIncrement);
+ int32 getRandomIdleAnim();
+ void setVisible(bool visible);
+ static int32 fixFacingForAnimation(int32 originalFacing, int32 animationId);
+};
+
+} // End of namespace Toon
+
+#endif
diff --git a/engines/toon/font.cpp b/engines/toon/font.cpp
new file mode 100644
index 0000000000..8b042f499d
--- /dev/null
+++ b/engines/toon/font.cpp
@@ -0,0 +1,285 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* $URL$
+* $Id$
+*
+*/
+
+#include "toon/font.h"
+
+namespace Toon {
+
+FontRenderer::FontRenderer(ToonEngine *vm) : _vm(vm) {
+ _currentFontColor[0] = 0;
+ _currentFontColor[1] = 0xc8;
+ _currentFontColor[2] = 0xcb;
+ _currentFontColor[3] = 0xce;
+
+}
+
+// mapping extended characters required for foreign versions to font (animation)
+static const byte map_textToFont[0x80] = {
+ '?', '?', '?', '?', 0x03, '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', // 0x8x
+ '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', // 0x9x
+ '?', 0x09, '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', // 0xAx
+ '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', 0x0a, // 0xBx
+ '?', '?', '?', '?', 0x1d, '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', '?', // 0xCx
+ '?', 0x0b, '?', '?', '?', '?', 0x1e, '?', '?', '?', '?', '?', 0x1f, '?', '?', 0x19, // 0xDx
+ 0x0d, 0x04, 0x0e, '?', 0x1a, '?', '?', 0x18, 0x10, 0x0f, 0x12, 0x11, 0x09, 0x05, 0x14, 0x13, // 0xEx
+ 0x23, 0x08, 0x23, 0x06, 0x15, 0x23, 0x1b, 0x23, 0x23, 0x16, 0x07, 0x17, 0x1c, 0x23, 0x23, 0x23 // 0xFx
+};
+
+byte FontRenderer::textToFont(byte c) {
+ // No need to remap simple characters.
+ if (c < 0x80)
+ return c;
+
+ // The Spanish version shows grave accent over the 'e' when it should
+ // be acute. This happens both in the original interpreter and when
+ // using the common map which works for other languages, so we add a
+ // special case for it.
+ if (_vm->_language == Common::ES_ESP && c == 0xe9)
+ return 0x10;
+
+ // Use the common map to convert the extended characters.
+ return map_textToFont[c - 0x80];
+}
+
+void FontRenderer::renderText(int32 x, int32 y, Common::String origText, int32 mode) {
+ debugC(5, kDebugFont, "renderText(%d, %d, %s, %d)", x, y, origText.c_str(), mode);
+
+ int32 xx, yy;
+ computeSize(origText, &xx, &yy);
+
+ if (mode & 2) {
+ y -= yy / 2;
+ } else if (mode & 4) {
+ y -= yy;
+ }
+
+ if (mode & 1) {
+ x -= xx / 2;
+ }
+
+ int32 curX = x;
+ int32 curY = y;
+ int32 height = 0;
+
+ const byte *text = (const byte *)origText.c_str();
+ while (*text) {
+ byte curChar = *text;
+ if (curChar == 13) {
+ curY = curY + height;
+ height = 0;
+ curX = x;
+ } else {
+ curChar = textToFont(curChar);
+ _currentFont->drawFontFrame(_vm->getMainSurface(), curChar, curX, curY, _currentFontColor);
+ curX = curX + _currentFont->getFrameWidth(curChar) - 1;
+ height = MAX(height, _currentFont->getFrameHeight(curChar));
+ }
+ text++;
+ }
+}
+
+void FontRenderer::computeSize(Common::String origText, int32 *retX, int32 *retY) {
+ debugC(4, kDebugFont, "computeSize(%s, retX, retY)", origText.c_str());
+
+ int32 lineWidth = 0;
+ int32 lineHeight = 0;
+ int32 totalHeight = 0;
+ int32 totalWidth = 0;
+
+ const byte *text = (const byte *)origText.c_str();
+ while (*text) {
+ byte curChar = *text;
+ if (curChar < 32) {
+ text++;
+ continue;
+ } else if (curChar == 13) {
+ totalWidth = MAX(totalWidth, lineWidth);
+ totalHeight += lineHeight;
+ lineHeight = 0;
+ lineWidth = 0;
+ } else {
+ curChar = textToFont(curChar);
+ int32 charWidth = _currentFont->getFrameWidth(curChar) - 1;
+ int32 charHeight = _currentFont->getFrameHeight(curChar);
+ lineWidth += charWidth;
+ lineHeight = MAX(lineHeight, charHeight);
+ }
+ text++;
+ }
+
+ totalHeight += lineHeight;
+ totalWidth = MAX(totalWidth, lineWidth);
+
+ *retX = totalWidth;
+ *retY = totalHeight;
+}
+
+void FontRenderer::setFont(Animation *font) {
+ debugC(5, kDebugFont, "setFont(font)");
+
+ _currentFont = font;
+}
+
+void FontRenderer::setFontColorByCharacter(int32 characterId) {
+ debugC(5, kDebugFont, "setFontColorByCharacter(%d)", characterId);
+
+ // unfortunately this table was hardcoded in the original executable
+ static const byte colorsByCharacters[] = {
+ 0xe0, 0xdc, 0xc8, 0xd6, 0xc1, 0xc8, 0xe9, 0xde, 0xc8, 0xeb, 0xe8, 0xc8,
+ 0xd1, 0xcf, 0xc8, 0xd8, 0xd5, 0xc8, 0xfb, 0xfa, 0xc8, 0xd9, 0xd7, 0xc8,
+ 0xe8, 0xe4, 0xc8, 0xe9, 0xfa, 0xc8, 0xeb, 0xe4, 0xc8, 0xeb, 0xe4, 0xc8,
+ 0xd2, 0xea, 0xc8, 0xd3, 0xd0, 0xc8, 0xe1, 0xdd, 0xc8, 0xd9, 0xd7, 0xc8,
+ 0xd9, 0xd7, 0xc8, 0xd9, 0xd7, 0xc8, 0xd9, 0xd7, 0xc8, 0xd9, 0xd7, 0xc8,
+ 0xd2, 0xcf, 0xc8, 0xd1, 0xcf, 0xc8, 0xd9, 0xd7, 0xc8, 0xe3, 0xdd, 0xc8,
+ 0xd9, 0xd7, 0xc8, 0xd9, 0xd7, 0xc8, 0xd9, 0xd7, 0xc8, 0xd9, 0xd7, 0xc8,
+ 0xd9, 0xd7, 0xc8, 0xd9, 0xd7, 0xc8, 0xd9, 0xd7, 0xc8, 0xd9, 0xd7, 0xc8,
+ 0xd9, 0xd7, 0xc8, 0xe6, 0xe4, 0xc8, 0xd9, 0xd7, 0xc8, 0xcd, 0xca, 0xc8,
+ 0xd9, 0xd7, 0xc8, 0xd9, 0xd7, 0xc8, 0xe8, 0xe8, 0xc8, 0xdb, 0xd5, 0xc8,
+ 0xe0, 0xdc, 0xc8, 0xd6, 0xc1, 0xc8, 0xd3, 0xd0, 0xc8, 0xd1, 0xcf, 0xc8,
+ 0xe6, 0xe4, 0xc8, 0xd1, 0xcf, 0xc8, 0xd2, 0xcf, 0xc8, 0xcc, 0xcb, 0xc8,
+ 0xd9, 0xd7, 0xc8, 0xd9, 0xd7, 0xc8, 0xd9, 0xd7, 0xc8, 0xd9, 0xd7, 0xc8,
+ 0xd9, 0xd7, 0xc8, 0xd9, 0xd7, 0xc8, 0xd9, 0xd7, 0xc8, 0xd9, 0xd7, 0xc8,
+ 0xd9, 0xd7, 0xc8, 0xd9, 0xd7, 0xc8, 0xd9, 0xd7, 0xc8, 0xd9, 0xd7, 0xc8
+ };
+
+ setFontColor(colorsByCharacters[characterId * 3 + 2], colorsByCharacters[characterId * 3 + 1], colorsByCharacters[characterId * 3 + 0]);
+}
+
+void FontRenderer::setFontColor(int32 fontColor1, int32 fontColor2, int32 fontColor3) {
+ debugC(5, kDebugFont, "setFontColor(%d, %d, %d)", fontColor1, fontColor2, fontColor3);
+
+ _currentFontColor[0] = 0;
+ _currentFontColor[1] = fontColor1;
+ _currentFontColor[2] = fontColor2;
+ _currentFontColor[3] = fontColor3;
+}
+
+void FontRenderer::renderMultiLineText(int32 x, int32 y, Common::String origText, int32 mode) {
+ debugC(5, kDebugFont, "renderMultiLineText(%d, %d, %s, %d)", x, y, origText.c_str(), mode);
+
+ // divide the text in several lines
+ // based on number of characters or size of lines.
+ byte text[1024];
+ strncpy((char *)text, origText.c_str(), 1023);
+ text[1023] = 0;
+
+ byte *lines[16];
+ int32 lineSize[16];
+ int32 numLines = 0;
+
+ byte *it = text;
+
+ int32 maxWidth = 0;
+ int32 curWidth = 0;
+
+ while (1) {
+ byte *lastLine = it;
+ byte *lastSpace = it;
+ int32 lastSpaceX = 0;
+ int32 curLetterNr = 0;
+ curWidth = 0;
+
+ while (*it && curLetterNr < 50 && curWidth < 580) {
+ byte curChar = *it;
+ if (curChar == 32) {
+ lastSpace = it;
+ lastSpaceX = curWidth;
+ } else
+ curChar = textToFont(curChar);
+
+ int width = _currentFont->getFrameWidth(curChar);
+ curWidth += width - 2;
+ it++;
+ curLetterNr++;
+ }
+
+ if (*lastLine == 0)
+ break;
+
+ lines[numLines] = lastLine;
+
+ if (*it == 0)
+ lineSize[numLines] = curWidth;
+ else
+ lineSize[numLines] = lastSpaceX;
+
+ if (lineSize[numLines] > maxWidth)
+ maxWidth = lineSize[numLines];
+
+ lastLine = lastSpace + 1;
+ numLines++;
+
+ if (*it == 0)
+ break;
+
+ it = lastLine;
+ *lastSpace = 0;
+
+ if (numLines >= 16)
+ break;
+ }
+
+ if (curWidth > maxWidth) {
+ maxWidth = curWidth;
+ }
+ //numLines++;
+
+ // get font height (assumed to be constant)
+ int32 height = _currentFont->getHeight();
+ int textSize = (height - 2) * numLines;
+ y = y - textSize;
+ if (y < 30)
+ y = 30;
+ if (y + textSize > 370)
+ y = 370 - textSize;
+
+ x -= _vm->state()->_currentScrollValue;
+
+ // adapt x
+ if (x - 30 - maxWidth / 2 < 0)
+ x = maxWidth / 2 + 30;
+
+ if (x + 30 + (maxWidth / 2) > 640)
+ x = 640 - (maxWidth / 2) - 30;
+
+ // we have good coordinates now, we can render the multi line
+ int32 curX = x;
+ int32 curY = y;
+
+ for (int32 i = 0; i < numLines; i++) {
+ const byte *line = lines[i];
+ curX = x - lineSize[i] / 2;
+ while (*line) {
+ byte curChar = textToFont(*line);
+ if (curChar != 32) _currentFont->drawFontFrame(_vm->getMainSurface(), curChar, curX + _vm->state()->_currentScrollValue, curY, _currentFontColor);
+ curX = curX + _currentFont->getFrameWidth(curChar) - 2;
+ //height = MAX(height, _currentFont->getFrameHeight(curChar));
+ line++;
+ }
+ curY += height;
+ }
+}
+
+} // End of namespace Toon
diff --git a/engines/toon/font.h b/engines/toon/font.h
new file mode 100644
index 0000000000..e1b00fbf54
--- /dev/null
+++ b/engines/toon/font.h
@@ -0,0 +1,53 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* $URL$
+* $Id$
+*
+*/
+
+#ifndef TOON_FONT_H
+#define TOON_FONT_H
+
+#include "toon/toon.h"
+
+namespace Toon {
+
+class FontRenderer {
+public:
+ FontRenderer(ToonEngine *vm);
+ ~FontRenderer(void);
+
+ void setFont(Animation *font);
+ void computeSize(Common::String origText, int32 *retX, int32 *retY);
+ void renderText(int32 x, int32 y, Common::String origText, int32 mode);
+ void renderMultiLineText(int32 x, int32 y, Common::String origText, int32 mode);
+ void setFontColorByCharacter(int32 characterId);
+ void setFontColor(int32 fontColor1, int32 fontColor2, int32 fontColor3);
+protected:
+ Animation *_currentFont;
+ ToonEngine *_vm;
+ byte _currentFontColor[4];
+ byte textToFont(byte c);
+};
+
+} // End of namespace Toon
+
+#endif
diff --git a/engines/toon/hotspot.cpp b/engines/toon/hotspot.cpp
new file mode 100644
index 0000000000..5af61197d7
--- /dev/null
+++ b/engines/toon/hotspot.cpp
@@ -0,0 +1,157 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* $URL$
+* $Id$
+*
+*/
+
+#include "toon/hotspot.h"
+#include "toon/tools.h"
+
+namespace Toon {
+
+Hotspots::Hotspots(ToonEngine *vm) : _vm(vm) {
+ _items = 0;
+ _numItems = 0;
+}
+
+
+void Hotspots::load(Common::ReadStream *Stream) {
+ delete[] _items;
+
+ _numItems = Stream->readSint16BE();
+ _items = new HotspotData[_numItems];
+
+ for (int32 i = 0; i < _numItems; i++) {
+ for (int32 a = 0; a < 256; a++)
+ _items[i].setData(a, Stream->readSint16BE());
+ }
+}
+
+void Hotspots::save(Common::WriteStream *Stream) {
+
+ Stream->writeSint16BE(_numItems);
+
+ for (int32 i = 0; i < _numItems; i++) {
+ for (int32 a = 0; a < 256; a++)
+ Stream->writeSint16BE(_items[i].getData(a));
+ }
+}
+
+int32 Hotspots::FindBasedOnCorner(int32 x, int32 y) {
+ debugC(1, kDebugHotspot, "FindBasedOnCorner(%d, %d)", x, y);
+
+ for (int32 i = 0; i < _numItems; i++) {
+ if (x == _items[i].getX1()) {
+ if (y == _items[i].getY1()) {
+ if (_items[i].getMode() == -1)
+ return _items[i].getRef();
+
+ return i;
+ }
+ }
+ }
+ return -1;
+}
+
+int32 Hotspots::Find(int32 x, int32 y) {
+ debugC(6, kDebugHotspot, "Find(%d, %d)", x, y);
+
+ int32 priority = -1;
+// Strangerke - Commented (not used)
+// bool found = false;
+ int32 foundId = -1;
+ int32 testId = -1;
+
+ for (int i = 0; i < _numItems; i++) {
+ if (x >= _items[i].getX1() && x <= _items[i].getX2() && y >= _items[i].getY1() && y <= _items[i].getY2()) {
+ if (_items[i].getMode() == -1)
+ testId = _items[i].getRef();
+ else
+ testId = i;
+
+ if (_items[testId].getPriority() > priority) {
+// Strangerke - Commented (not used)
+// found = true;
+ foundId = testId;
+ priority = _items[testId].getPriority();
+ }
+ }
+ }
+ return foundId;
+}
+
+bool Hotspots::LoadRif(Common::String rifName, Common::String additionalRifName) {
+ debugC(1, kDebugHotspot, "LoadRif(%s, %s)", rifName.c_str(), additionalRifName.c_str());
+
+ uint32 size = 0;
+ uint8 *rifData = _vm->resources()->getFileData(rifName, &size);
+ if (!rifData)
+ return false;
+
+ uint32 size2 = 0;
+ uint8 *rifData2 = 0;
+ if (additionalRifName.size())
+ rifData2 = _vm->resources()->getFileData(additionalRifName, &size2);
+
+ // figure out the number of hotspots based on file size
+ int32 rifsize = READ_BE_UINT32(&rifData[4]);
+ int32 rifsize2 = 0;
+
+ if (size2)
+ rifsize2 = READ_BE_UINT32(&rifData2[4]);
+
+ _numItems = (rifsize + rifsize2) / 512;
+
+ if (_items)
+ delete[] _items;
+
+ _items = new HotspotData[_numItems];
+
+ // RIFs are compressed in RNC1
+ RncDecoder decoder;
+ decoder.unpackM1(rifData, _items);
+ if (rifsize2) {
+ RncDecoder decoder2;
+ decoder2.unpackM1(rifData2 , _items + (rifsize >> 9));
+ for (int32 i = 0; i < (rifsize2 >> 9); i++) {
+ HotspotData *hot = _items + (rifsize >> 9) + i;
+ hot->setData(0, hot->getX1() + 1280);
+ hot->setData(2, hot->getX2() + 1280);
+ if (hot->getMode() == -1)
+ hot->setData(5, hot->getRef() + (rifsize >> 9));
+ }
+ }
+
+ return true;
+}
+
+HotspotData *Hotspots::Get(int32 id) {
+ debugC(5, kDebugHotspot, "Get(%d)", id);
+
+ if (id < 0 || id >= _numItems)
+ return 0;
+ else
+ return &_items[id];
+}
+
+} // End of namespace Toon
+
diff --git a/engines/toon/hotspot.h b/engines/toon/hotspot.h
new file mode 100644
index 0000000000..233bcebcb7
--- /dev/null
+++ b/engines/toon/hotspot.h
@@ -0,0 +1,73 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* $URL$
+* $Id$
+*
+*/
+
+#ifndef TOON_HOTSPOT_H
+#define TOON_HOTSPOT_H
+
+#include "toon/toon.h"
+#include "toon/tools.h"
+
+namespace Toon {
+
+class HotspotData {
+public:
+ int16 getX1() const { return READ_LE_INT16(_data + 0); }
+ int16 getY1() const { return READ_LE_INT16(_data + 1); }
+ int16 getX2() const { return READ_LE_INT16(_data + 2); }
+ int16 getY2() const { return READ_LE_INT16(_data + 3); }
+ int16 getMode() const { return READ_LE_INT16(_data + 4); }
+ int16 getRef() const { return READ_LE_INT16(_data + 5); }
+ int16 getPriority() const { return READ_LE_INT16(_data + 7); }
+ int16 getType() const { return READ_LE_INT16(_data + 8); }
+ int16 getData(int32 id) const { return READ_LE_INT16(_data + id); }
+ void setData(int32 id, int16 val) { WRITE_LE_UINT16(&_data[id], val); }
+
+private:
+ int16 _data[256];
+};
+
+class Hotspots {
+public:
+ Hotspots(ToonEngine *vm);
+ ~Hotspots(void);
+
+ bool LoadRif(Common::String rifName, Common::String additionalRifName);
+ int32 Find(int32 x, int32 y);
+ int32 FindBasedOnCorner(int32 x, int32 y);
+ HotspotData *Get(int32 id);
+ int32 getCount() const { return _numItems; }
+
+ void load(Common::ReadStream *Stream);
+ void save(Common::WriteStream *Stream);
+
+protected:
+ HotspotData *_items;
+ int32 _numItems;
+ ToonEngine *_vm;
+};
+
+} // End of namespace Toon
+
+#endif
diff --git a/engines/toon/module.mk b/engines/toon/module.mk
new file mode 100644
index 0000000000..403408e497
--- /dev/null
+++ b/engines/toon/module.mk
@@ -0,0 +1,30 @@
+MODULE := engines/toon
+
+MODULE_OBJS := \
+ anim.o \
+ audio.o \
+ character.o \
+ conversation.o \
+ detection.o \
+ drew.o \
+ flux.o \
+ font.o \
+ hotspot.o \
+ movie.o \
+ path.o \
+ picture.o \
+ resource.o \
+ script.o \
+ script_func.o \
+ state.o \
+ text.o \
+ tools.o \
+ toon.o
+
+# This module can be built as a plugin
+ifeq ($(ENABLE_TOON), DYNAMIC_PLUGIN)
+PLUGIN := 1
+endif
+
+# Include common rules
+include $(srcdir)/rules.mk
diff --git a/engines/toon/movie.cpp b/engines/toon/movie.cpp
new file mode 100644
index 0000000000..91ea98a91f
--- /dev/null
+++ b/engines/toon/movie.cpp
@@ -0,0 +1,114 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* $URL$
+* $Id$
+*
+*/
+
+#include "toon/movie.h"
+
+namespace Toon {
+
+void ToonstruckSmackerDecoder::handleAudioTrack(byte track, uint32 chunkSize, uint32 unpackedSize) {
+ debugC(6, kDebugMovie, "handleAudioTrack(%d, %d, %d)", track, chunkSize, unpackedSize);
+
+ if (track == 1 && chunkSize == 4) {
+ /* uint16 width = */ _fileStream->readUint16LE();
+ uint16 height = _fileStream->readUint16LE();
+
+ _header.flags = (height == getHeight() / 2) ? 4 : 0;
+ } else
+ Graphics::SmackerDecoder::handleAudioTrack(track, chunkSize, unpackedSize);
+}
+
+bool ToonstruckSmackerDecoder::loadFile(const Common::String &filename, int forcedflags) {
+ debugC(1, kDebugMovie, "loadFile(%s, %d)", filename.c_str(), forcedflags);
+
+ if (Graphics::SmackerDecoder::loadFile(filename)) {
+ if (forcedflags & 0x10 || _surface->h == 200) {
+
+ _header.flags = 4;
+ delete this->_surface;
+ _surface = new Graphics::Surface();
+ _surface->create(640, 400, 1);
+ }
+ return true;
+ }
+ return false;
+}
+
+ToonstruckSmackerDecoder::ToonstruckSmackerDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType) : Graphics::SmackerDecoder(mixer, soundType) {
+
+}
+
+Movie::Movie(ToonEngine *vm , ToonstruckSmackerDecoder *decoder) {
+ _vm = vm;
+ _playing = false;
+ _decoder = decoder;
+}
+
+Movie::~Movie() {
+}
+
+void Movie::init() const {
+}
+
+void Movie::play(Common::String video, int32 flags) {
+ debugC(1, kDebugMovie, "play(%s, %d)", video.c_str(), flags);
+
+ _playing = true;
+ if (flags & 1)
+ _vm->getAudioManager()->setMusicVolume(0);
+ _decoder->loadFile(video.c_str(), flags);
+ playVideo();
+ _vm->flushPalette();
+ if (flags & 1)
+ _vm->getAudioManager()->setMusicVolume(_vm->getAudioManager()->isMusicMuted() ? 0 : 255);
+ _decoder->close();
+ _playing = false;
+}
+
+bool Movie::playVideo() {
+ debugC(1, kDebugMovie, "playVideo()");
+
+ int32 x = 0;
+ int32 y = 0;
+ while (!_vm->shouldQuit() && !_decoder->endOfVideo()) {
+ if (_decoder->needsUpdate()) {
+ Graphics::Surface *frame = _decoder->decodeNextFrame();
+ if (frame)
+ _vm->getSystem()->copyRectToScreen((byte *)frame->pixels, frame->pitch, x, y, frame->w, frame->h);
+ _decoder->setSystemPalette();
+ _vm->getSystem()->updateScreen();
+ }
+
+ Common::Event event;
+ while (_vm->getSystem()->getEventManager()->pollEvent(event))
+ if ((event.type == Common::EVENT_KEYDOWN && event.kbd.keycode == Common::KEYCODE_ESCAPE) || event.type == Common::EVENT_LBUTTONUP) {
+ return false;
+ }
+
+ _vm->getSystem()->delayMillis(10);
+ }
+ return !_vm->shouldQuit();
+}
+
+} // End of namespace Toon
diff --git a/engines/toon/movie.h b/engines/toon/movie.h
new file mode 100644
index 0000000000..4d5efb3343
--- /dev/null
+++ b/engines/toon/movie.h
@@ -0,0 +1,61 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* $URL$
+* $Id$
+*
+*/
+
+#ifndef TOON_MOVIE_H
+#define TOON_MOVIE_H
+
+#include "toon/toon.h"
+#include "graphics/video/smk_decoder.h"
+
+namespace Toon {
+
+class ToonstruckSmackerDecoder : public Graphics::SmackerDecoder {
+public:
+ ToonstruckSmackerDecoder(Audio::Mixer *mixer, Audio::Mixer::SoundType soundType = Audio::Mixer::kSFXSoundType);
+ void handleAudioTrack(byte track, uint32 chunkSize, uint32 unpackedSize);
+ bool loadFile(const Common::String &filename, int forcedflags) ;
+};
+
+class Movie {
+public:
+ Movie(ToonEngine *vm, ToonstruckSmackerDecoder *decoder);
+ ~Movie(void);
+
+ void init() const;
+ void play(Common::String video, int32 flags = 0);
+ bool isPlaying() { return _playing; }
+
+protected:
+ bool playVideo();
+ ToonEngine *_vm;
+ Audio::Mixer *_mixer;
+ ToonstruckSmackerDecoder *_decoder;
+ bool _playing;
+
+};
+
+} // End of namespace Toon
+
+#endif
diff --git a/engines/toon/path.cpp b/engines/toon/path.cpp
new file mode 100644
index 0000000000..cec9c7dbf0
--- /dev/null
+++ b/engines/toon/path.cpp
@@ -0,0 +1,370 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* $URL$
+* $Id$
+*
+*/
+
+#include "toon/path.h"
+
+namespace Toon {
+
+int32 PathFindingHeap::init(int32 size) {
+ debugC(1, kDebugPath, "init(%d)", size);
+
+ _data = new HeapDataGrid[size * 2];
+ memset(_data, 0, sizeof(HeapDataGrid) * size * 2);
+ _count = 0;
+ _alloc = size;
+ return size;
+}
+
+int32 PathFindingHeap::unload() {
+ if (_data)
+ delete[] _data;
+ return 0;
+}
+
+int32 PathFindingHeap::clear() {
+ //debugC(1, kDebugPath, "clear()");
+
+ _count = 0;
+ memset(_data, 0, sizeof(HeapDataGrid) * _alloc * 2);
+ return 1;
+}
+
+int32 PathFindingHeap::push(int32 x, int32 y, int32 weight) {
+ //debugC(6, kDebugPath, "push(%d, %d, %d)", x, y, weight);
+
+ _count++;
+ _data[_count]._x = x;
+ _data[_count]._y = y;
+ _data[_count]._weight = weight;
+
+ int32 lMax = _count;
+ int32 lT = 0;
+
+ while (1) {
+ lT = lMax / 2;
+ if (lT < 1)
+ break;
+
+ if (_data[lT]._weight > _data[lMax]._weight) {
+ HeapDataGrid temp;
+ temp = _data[lT];
+ _data[lT] = _data[lMax];
+ _data[lMax] = temp;
+ lMax = lT;
+ } else {
+ break;
+ }
+ }
+ return 1;
+}
+
+int32 PathFindingHeap::pop(int32 *x, int32 *y, int32 *weight) {
+ //debugC(6, kDebugPath, "pop(x, y, weight)");
+
+ if (!_count)
+ return 0;
+
+ *x = _data[1]._x;
+ *y = _data[1]._y;
+ *weight = _data[1]._weight;
+
+ _data[1] = _data[_count];
+ _count--;
+ if (!_count)
+ return 0;
+
+ int32 lMin = 1;
+ int32 lT = 1;
+
+ while (1) {
+ lT = lMin << 1;
+ if (lT <= _count) {
+ if (lT < _count) {
+ if (_data[lT + 1]._weight < _data[lT]._weight)
+ lT++;
+ }
+ if (_data[lT]._weight <= _data[lMin]._weight) {
+ HeapDataGrid temp;
+ temp = _data[lMin];
+ _data[lMin] = _data[lT];
+ _data[lT] = temp;
+
+ lMin = lT;
+ } else {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ return 0;
+}
+
+PathFinding::PathFinding(ToonEngine *vm) : _vm(vm) {
+ _width = 0;
+ _height = 0;
+ _heap = new PathFindingHeap();
+ _gridTemp = 0;
+ _numBlockingRects = 0;
+}
+
+PathFinding::~PathFinding(void) {
+ if (_heap) {
+ _heap->unload();
+ delete _heap;
+ }
+}
+
+bool PathFinding::isWalkable(int32 x, int32 y) {
+ //debugC(6, kDebugPath, "isWalkable(%d, %d)", x, y);
+
+ bool maskWalk = (_currentMask->getData(x, y) & 0x1f) > 0;
+ for (int32 i = 0; i < _numBlockingRects; i++) {
+ if (_blockingRects[i][4] == 0) {
+ if (x >= _blockingRects[i][0] && x <= _blockingRects[i][2] && y >= _blockingRects[i][1] && y < _blockingRects[i][3])
+ return false;
+ } else {
+ int32 dx = abs(_blockingRects[i][0] - x);
+ int32 dy = abs(_blockingRects[i][1] - y);
+ if ((dx << 8) / _blockingRects[i][2] < (1 << 8) && (dy << 8) / _blockingRects[i][3] < (1 << 8)) {
+ return false;
+ }
+ }
+ }
+ return maskWalk;
+}
+
+int32 PathFinding::findClosestWalkingPoint(int32 xx, int32 yy, int32 *fxx, int32 *fyy, int origX, int origY) {
+ debugC(1, kDebugPath, "findClosestWalkingPoint(%d, %d, fxx, fyy, %d, %d)", xx, yy, origX, origY);
+
+ int32 currentFound = -1;
+ int32 dist = -1;
+ int32 dist2 = -1;
+
+ if (origX == -1)
+ origX = xx;
+ if (origY == -1)
+ origY = yy;
+
+ for (int y = 0; y < _height; y++) {
+ for (int x = 0; x < _width; x++) {
+ if (isWalkable(x, y)) {
+ int32 ndist = (x - xx) * (x - xx) + (y - yy) * (y - yy);
+ int32 ndist2 = (x - origX) * (x - origX) + (y - origY) * (y - origY);
+ if (currentFound < 0 || ndist < dist || (ndist == dist && ndist2 < dist2)) {
+ dist = ndist;
+ dist2 = ndist2;
+ currentFound = y * _width + x;
+ }
+ }
+ }
+ }
+
+ if (currentFound != -1) {
+ *fxx = currentFound % _width;
+ *fyy = currentFound / _width;
+ return 1;
+ } else {
+ *fxx = 0;
+ *fyy = 0;
+ return 0;
+ }
+}
+
+int32 PathFinding::findPath(int32 x, int32 y, int32 destx, int32 desty) {
+ debugC(1, kDebugPath, "findPath(%d, %d, %d, %d)", x, y, destx, desty);
+
+ if (x == destx && y == desty) {
+ _gridPathCount = 0;
+ return true;
+ }
+
+ memset(_gridTemp , 0, _width * _height * sizeof(int32));
+ _heap->clear();
+ int32 curX = x;
+ int32 curY = y;
+ int32 curWeight = 0;
+ int32 *sq = _gridTemp;
+
+ sq[curX + curY *_width] = 1;
+ _heap->push(curX, curY, abs(destx - x) + abs(desty - y));
+ int wei = 0;
+
+// Strangerke - Commented (not used)
+// byte *mask = _currentMask->getDataPtr();
+
+ while (_heap->_count) {
+ wei = 0;
+ _heap->pop(&curX, &curY, &curWeight);
+ int curNode = curX + curY * _width;
+
+ int32 endX = MIN<int32>(curX + 1, _width - 1);
+ int32 endY = MIN<int32>(curY + 1, _height - 1);
+ int32 startX = MAX<int32>(curX - 1, 0);
+ int32 startY = MAX<int32>(curY - 1, 0);
+
+ for (int32 px = startX; px <= endX; px++) {
+ for (int py = startY; py <= endY; py++) {
+ if (px != curX || py != curY) {
+ wei = abs(px - curX) + abs(py - curY);
+
+ int32 curPNode = px + py * _width;
+ if (isWalkable(px, py)) { // walkable ?
+ int sum = sq[curNode] + wei;
+ if (sq[curPNode] > sum || !sq[curPNode]) {
+ int newWeight = abs(destx - px) + abs(desty - py);
+ sq[curPNode] = sum;
+ _heap->push(px, py, sq[curPNode] + newWeight);
+ if (!newWeight)
+ goto next; // we found it !
+ }
+ }
+ }
+ }
+ }
+ }
+
+next:
+
+ // let's see if we found a result !
+ if (!_gridTemp[destx + desty * _width]) {
+ // didn't find anything
+ _gridPathCount = 0;
+ return false;
+ }
+
+ curX = destx;
+ curY = desty;
+
+ int32 retPathX[4096];
+ int32 retPathY[4096];
+ int32 numpath = 0;
+
+ retPathX[numpath] = curX;
+ retPathY[numpath] = curY;
+ numpath++;
+ int32 bestscore = sq[destx + desty * _width];
+
+ while (1) {
+ int32 bestX = -1;
+ int32 bestY = -1;
+
+ int32 endX = MIN<int32>(curX + 1, _width - 1);
+ int32 endY = MIN<int32>(curY + 1, _height - 1);
+ int32 startX = MAX<int32>(curX - 1, 0);
+ int32 startY = MAX<int32>(curY - 1, 0);
+
+ for (int32 px = startX; px <= endX; px++) {
+ for (int32 py = startY; py <= endY; py++) {
+ if (px != curX || py != curY) {
+ wei = abs(px - curX) + abs(py - curY);
+
+ int PNode = px + py * _width;
+ if (sq[PNode] && (isWalkable(px, py))) {
+ if (sq[PNode] < bestscore) {
+ bestscore = sq[PNode];
+ bestX = px;
+ bestY = py;
+ }
+ }
+ }
+ }
+ }
+
+ if (bestX < 0 || bestY < 0)
+ return 0;
+
+ retPathX[numpath] = bestX;
+ retPathY[numpath] = bestY;
+ numpath++;
+
+ if ((bestX == x && bestY == y)) {
+ _gridPathCount = numpath;
+
+ memcpy(_tempPathX, retPathX, sizeof(int32) * numpath);
+ memcpy(_tempPathY, retPathY, sizeof(int32) * numpath);
+ return true;
+ }
+
+ curX = bestX;
+ curY = bestY;
+ }
+
+ return false;
+}
+
+void PathFinding::init(Picture *mask) {
+ debugC(1, kDebugPath, "init(mask)");
+
+ _width = mask->getWidth();
+ _height = mask->getHeight();
+ _currentMask = mask;
+ _heap->unload();
+ _heap->init(_width * _height);
+ if (_gridTemp)
+ delete[] _gridTemp;
+ _gridTemp = new int32[_width*_height];
+}
+
+void PathFinding::resetBlockingRects() {
+ _numBlockingRects = 0;
+}
+
+void PathFinding::addBlockingRect(int32 x1, int32 y1, int32 x2, int32 y2) {
+ debugC(1, kDebugPath, "addBlockingRect(%d, %d, %d, %d)", x1, y1, x2, y2);
+
+ _blockingRects[_numBlockingRects][0] = x1;
+ _blockingRects[_numBlockingRects][1] = y1;
+ _blockingRects[_numBlockingRects][2] = x2;
+ _blockingRects[_numBlockingRects][3] = y2;
+ _blockingRects[_numBlockingRects][4] = 0;
+ _numBlockingRects++;
+}
+
+void PathFinding::addBlockingEllipse(int32 x1, int32 y1, int32 w, int32 h) {
+ debugC(1, kDebugPath, "addBlockingRect(%d, %d, %d, %d)", x1, y1, w, h);
+
+ _blockingRects[_numBlockingRects][0] = x1;
+ _blockingRects[_numBlockingRects][1] = y1;
+ _blockingRects[_numBlockingRects][2] = w;
+ _blockingRects[_numBlockingRects][3] = h;
+ _blockingRects[_numBlockingRects][4] = 1;
+ _numBlockingRects++;
+}
+
+
+int32 PathFinding::getPathNodeCount() const {
+ return _gridPathCount;
+}
+
+int32 PathFinding::getPathNodeX(int32 nodeId) const {
+ return _tempPathX[ _gridPathCount - nodeId - 1];
+}
+
+int32 PathFinding::getPathNodeY(int32 nodeId) const {
+ return _tempPathY[ _gridPathCount - nodeId - 1];
+}
+
+} // End of namespace Toon
diff --git a/engines/toon/path.h b/engines/toon/path.h
new file mode 100644
index 0000000000..d8ef2eac02
--- /dev/null
+++ b/engines/toon/path.h
@@ -0,0 +1,93 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* $URL$
+* $Id$
+*
+*/
+
+#ifndef TOON_PATH_H
+#define TOON_PATH_H
+
+#include "toon/toon.h"
+
+namespace Toon {
+
+// binary heap system for fast A*
+struct HeapDataGrid {
+ int16 _x, _y;
+ int16 _weight;
+};
+
+class PathFindingHeap {
+
+private:
+ HeapDataGrid *_data;
+public:
+ int32 _alloc;
+ int32 _count;
+ int32 push(int32 x, int32 y, int32 weight);
+ int32 pop(int32 *x, int32 *y, int32 *weight);
+ int32 init(int32 size);
+ int32 clear();
+ int32 unload();
+};
+
+
+class PathFinding {
+public:
+ PathFinding(ToonEngine *vm);
+ ~PathFinding(void);
+
+ int32 findPath(int32 x, int32 y, int32 destX, int32 destY);
+ int32 findClosestWalkingPoint(int32 xx, int32 yy, int32 *fxx, int32 *fyy, int origX = -1, int origY = -1);
+ bool isWalkable(int32 x, int32 y);
+ void init(Picture *mask);
+
+ void resetBlockingRects();
+ void addBlockingRect(int32 x1, int32 y1, int32 x2, int32 y2);
+ void addBlockingEllipse(int32 x1, int32 y1, int32 w, int32 h);
+
+ int32 getPathNodeCount() const;
+ int32 getPathNodeX(int32 nodeId) const;
+ int32 getPathNodeY(int32 nodeId) const;
+protected:
+ Picture *_currentMask;
+
+ PathFindingHeap *_heap;
+
+ int32 *_gridTemp;
+ int32 _width;
+ int32 _height;
+
+ int32 _tempPathX[4096];
+ int32 _tempPathY[4096];
+ int32 _blockingRects[16][5];
+ int32 _numBlockingRects;
+ int32 _allocatedGridPathCount;
+ int32 _gridPathCount;
+
+ ToonEngine *_vm;
+
+};
+
+} // End of namespace Toon
+
+#endif
diff --git a/engines/toon/picture.cpp b/engines/toon/picture.cpp
new file mode 100644
index 0000000000..11a5572066
--- /dev/null
+++ b/engines/toon/picture.cpp
@@ -0,0 +1,296 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* $URL$
+* $Id$
+*
+*/
+
+#include "toon/picture.h"
+#include "toon/tools.h"
+#include "common/stack.h"
+
+namespace Toon {
+
+bool Picture::loadPicture(Common::String file, bool totalPalette /*= false*/) {
+ debugC(1, kDebugPicture, "loadPicture(%s, %d)", file.c_str(), (totalPalette) ? 1 : 0);
+
+ uint32 size = 0;
+ uint8 *fileData = _vm->resources()->getFileData(file, &size);
+ if (!fileData)
+ return false;
+
+ _useFullPalette = totalPalette;
+
+ uint32 compId = READ_BE_UINT32(fileData);
+
+ switch (compId) {
+ case kCompLZSS: {
+ uint32 dstsize = READ_LE_UINT32(fileData + 4);
+ _data = new uint8[dstsize];
+ decompressLZSS(fileData + 8, _data, dstsize);
+
+ // size can only be 640x400 or 1280x400
+ if (dstsize > 640 * 400 + 768)
+ _width = 1280;
+ else
+ _width = 640;
+
+ _height = 400;
+
+ // do we have a palette ?
+ _paletteEntries = (dstsize & 0x7ff) / 3;
+ if (_paletteEntries) {
+ _palette = new uint8[_paletteEntries * 3];
+ memcpy(_palette, _data + dstsize - (dstsize & 0x7ff), _paletteEntries * 3);
+ _vm->fixPaletteEntries(_palette, _paletteEntries);
+ } else {
+ _palette = 0;
+ }
+ return true;
+ }
+ case kCompSPCN: {
+ uint32 decSize = READ_LE_UINT32(fileData + 10);
+ _data = new uint8[decSize+100];
+ _paletteEntries = READ_LE_UINT16(fileData + 14) / 3;
+
+ if (_paletteEntries) {
+ _palette = new uint8[_paletteEntries * 3];
+ memcpy(_palette, fileData + 16, _paletteEntries * 3);
+ _vm->fixPaletteEntries(_palette, _paletteEntries);
+ }
+
+ // size can only be 640x400 or 1280x400
+ if (decSize > 640 * 400 + 768)
+ _width = 1280;
+ else
+ _width = 640;
+
+ _height = 400;
+
+ // decompress the picture into our buffer
+ decompressSPCN(fileData + 16 + _paletteEntries * 3, _data, decSize);
+ return true;
+ }
+ case kCompRNC1: {
+ Toon::RncDecoder rnc;
+
+ // allocate enough place
+ uint32 decSize = READ_BE_UINT32(fileData + 4);
+
+ _data = new uint8[decSize];
+ rnc.unpackM1(fileData, _data);
+
+ // size can only be 640x400 or 1280x400
+ if (decSize > 640 * 400 + 768)
+ _width = 1280;
+ else
+ _width = 640;
+
+ _height = 400;
+ return true;
+ }
+ case kCompRNC2: {
+ Toon::RncDecoder rnc;
+
+ // allocate enough place
+ uint32 decSize = READ_BE_UINT32(fileData + 4);
+
+ _data = new uint8[decSize];
+
+ decSize = rnc.unpackM2(fileData, _data);
+
+ if (decSize > 640 * 400 + 768)
+ _width = 1280;
+ else
+ _width = 640;
+
+ _height = 400;
+ return true;
+ }
+ }
+ return false;
+}
+
+Picture::Picture(ToonEngine *vm) : _vm(vm) {
+
+}
+
+void Picture::setupPalette() {
+ debugC(1, kDebugPicture, "setupPalette()");
+
+ if (_useFullPalette)
+ _vm->setPaletteEntries(_palette, 0, 256);
+ else
+ _vm->setPaletteEntries(_palette, 1, 128);
+}
+
+void Picture::drawMask(Graphics::Surface &surface, int32 x, int32 y, int32 dx, int32 dy) {
+ debugC(1, kDebugPicture, "drawMask(surface, %d, %d, %d, %d)", x, y, dx, dy);
+
+ for (int32 i = 0; i < 128; i++) {
+ byte color[3];
+ color[0] = i * 2;
+ color[1] = i * 2;
+ color[2] = 255 - i * 2;
+ _vm->setPaletteEntries(color, i, 1);
+ }
+
+ int32 rx = MIN(_width, surface.w - x);
+ int32 ry = MIN(_height, surface.h - y);
+
+ if (rx < 0 || ry < 0)
+ return;
+
+ int32 destPitch = surface.pitch;
+ int32 srcPitch = _width;
+ uint8 *c = _data + _width * dy + dx;
+ uint8 *curRow = (uint8 *)surface.pixels + y * destPitch + x;
+
+ for (int32 yy = 0; yy < ry; yy++) {
+ uint8 *curSrc = c;
+ uint8 *cur = curRow;
+ for (int32 xx = 0; xx < rx; xx++) {
+ //*cur = (*curSrc >> 5) * 8; // & 0x1f;
+ *cur = (*curSrc & 0x1f) ? 127 : 0;
+
+ curSrc++;
+ cur++;
+ }
+ curRow += destPitch;
+ c += srcPitch;
+ }
+}
+
+void Picture::draw(Graphics::Surface &surface, int32 x, int32 y, int32 dx, int32 dy) {
+ debugC(6, kDebugPicture, "draw(surface, %d, %d, %d, %d)", x, y, dx, dy);
+
+ int32 rx = MIN(_width, surface.w - x);
+ int32 ry = MIN(_height, surface.h - y);
+
+ if (rx < 0 || ry < 0)
+ return;
+
+ int32 destPitch = surface.pitch;
+ int32 srcPitch = _width;
+ uint8 *c = _data + _width * dy + dx;
+ uint8 *curRow = (uint8 *)surface.pixels + y * destPitch + x;
+
+ for (int32 yy = 0; yy < ry; yy++) {
+ uint8 *curSrc = c;
+ uint8 *cur = curRow;
+ for (int32 xx = 0; xx < rx; xx++) {
+ *cur = *curSrc;
+ curSrc++;
+ cur++;
+ }
+ curRow += destPitch;
+ c += srcPitch;
+ }
+}
+
+uint8 Picture::getData(int32 x, int32 y) {
+ debugC(6, kDebugPicture, "getData(%d, %d)", x, y);
+
+ if (!_data)
+ return 0;
+
+ return _data[y * _width + x];
+}
+
+// use original work from johndoe
+void Picture::floodFillNotWalkableOnMask(int32 x, int32 y) {
+ debugC(1, kDebugPicture, "floodFillNotWalkableOnMask(%d, %d)", x, y);
+
+ // Stack-based floodFill algorithm based on
+ // http://student.kuleuven.be/~m0216922/CG/files/floodfill.cpp
+ Common::Stack<Common::Point> stack;
+ bool spanLeft, spanRight;
+ stack.push(Common::Point(x, y));
+ while (!stack.empty()) {
+ Common::Point pt = stack.pop();
+ while (_data[pt.x + pt.y * _width] & 0x1F && pt.y >= 0)
+ pt.y--;
+ pt.y++;
+ spanLeft = false;
+ spanRight = false;
+ while (_data[pt.x + pt.y * _width] & 0x1F && pt.y < _height) {
+ _data[pt.x + pt.y * _width] &= 0xE0;
+ if (!spanLeft && pt.x > 0 && _data[pt.x - 1 + pt.y * _width] & 0x1F) {
+ stack.push(Common::Point(pt.x - 1, pt.y));
+ spanLeft = 1;
+ } else if (spanLeft && pt.x > 0 && !(_data[pt.x - 1 + pt.y * _width] & 0x1F)) {
+ spanLeft = 0;
+ }
+ if (!spanRight && pt.x < _width - 1 && _data[pt.x + 1 + pt.y * _width] & 0x1F) {
+ stack.push(Common::Point(pt.x + 1, pt.y));
+ spanRight = 1;
+ } else if (spanRight && pt.x < _width - 1 && !(_data[pt.x + 1 + pt.y * _width] & 0x1F)) {
+ spanRight = 0;
+ }
+ pt.y++;
+ }
+ }
+}
+
+void Picture::drawLineOnMask(int32 x, int32 y, int32 x2, int32 y2, bool walkable) {
+ debugC(1, kDebugPicture, "drawLineOnMask(%d, %d, %d, %d, %d)", x, y, x2, y2, (walkable) ? 1 : 0);
+
+ static int32 lastX = 0;
+ static int32 lastY = 0;
+
+ if (x == -1) {
+ x = lastX;
+ y = lastY;
+ }
+
+ uint32 bx = x << 16;
+ int32 dx = x2 - x;
+ uint32 by = y << 16;
+ int32 dy = y2 - y;
+ uint32 adx = abs(dx);
+ uint32 ady = abs(dy);
+ int32 t = 0;
+ if (adx <= ady)
+ t = ady;
+ else
+ t = adx;
+
+
+ int32 cdx = (dx << 16) / t;
+ int32 cdy = (dy << 16) / t;
+
+ int32 i = t;
+ while (i) {
+ if (!walkable) {
+ _data[_width * (by >> 16) + (bx >> 16)] &= 0xe0;
+ _data[_width * (by >> 16) + (bx >> 16)+1] &= 0xe0;
+ } else {
+ int32 v = _data[_width * (by >> 16) + (bx >> 16) - 1];
+ _data[_width * (by >> 16) + (bx >> 16)] = v;
+ _data[_width * (by >> 16) + (bx >> 16)+1] = v;
+ }
+
+ bx += cdx;
+ by += cdy;
+ i--;
+ }
+}
+} // End of namespace Toon
diff --git a/engines/toon/picture.h b/engines/toon/picture.h
new file mode 100644
index 0000000000..5065843b3c
--- /dev/null
+++ b/engines/toon/picture.h
@@ -0,0 +1,66 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* $URL$
+* $Id$
+*
+*/
+
+#ifndef TOON_PICTURE_H
+#define TOON_PICTURE_H
+
+#include "common/stream.h"
+#include "common/array.h"
+#include "common/func.h"
+#include "common/str.h"
+
+#include "toon/toon.h"
+
+namespace Toon {
+
+class ToonEngine;
+class Picture {
+
+public:
+ Picture(ToonEngine *vm);
+ bool loadPicture(Common::String file, bool totalPalette = false);
+ void setupPalette();
+ void draw(Graphics::Surface &surface, int32 x, int32 y, int32 dx, int32 dy);
+ void drawMask(Graphics::Surface &surface, int32 x, int32 y, int32 dx, int32 dy);
+ void drawLineOnMask(int32 x, int32 y, int32 x2, int32 y2, bool walkable);
+ void floodFillNotWalkableOnMask(int32 x, int32 y);
+ uint8 getData(int32 x, int32 y);
+ uint8 *getDataPtr() { return _data; }
+ int32 getWidth() const { return _width; }
+ int32 getHeight() const { return _height; }
+protected:
+ int32 _width;
+ int32 _height;
+ uint8 *_data;
+ uint8 *_palette; // need to be copied at 3-387
+ int32 _paletteEntries;
+ bool _useFullPalette;
+
+ ToonEngine *_vm;
+};
+
+} // End of namespace Toon
+
+#endif
diff --git a/engines/toon/resource.cpp b/engines/toon/resource.cpp
new file mode 100644
index 0000000000..348aa45ae9
--- /dev/null
+++ b/engines/toon/resource.cpp
@@ -0,0 +1,215 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* $URL$
+* $Id$
+*
+*/
+
+#include "toon/resource.h"
+#include "common/file.h"
+#include "toon/toon.h"
+
+
+namespace Toon {
+
+void Resources::openPackage(Common::String fileName, bool preloadEntirePackage) {
+ debugC(1, kDebugResource, "openPackage(%s, %d)", fileName.c_str(), (preloadEntirePackage) ? 1 : 0);
+
+ Common::File file;
+ bool opened = file.open(fileName);
+
+ if (!opened)
+ return;
+
+
+ PakFile *pakFile = new PakFile();
+ pakFile->open(&file, fileName, preloadEntirePackage);
+
+ if (preloadEntirePackage)
+ file.close();
+
+ _pakFiles.push_back(pakFile);
+}
+
+void Resources::closePackage(Common::String fileName) {
+ for (uint32 i = 0; i < _pakFiles.size(); i++) {
+ if (_pakFiles[i]->getPackName() == fileName) {
+ delete _pakFiles[i];
+ _pakFiles.remove_at(i);
+ return;
+ }
+ }
+}
+
+Resources::Resources(ToonEngine *vm) : _vm(vm) {
+
+}
+
+uint8 *Resources::getFileData(Common::String fileName, uint32 *fileSize) {
+ debugC(4, kDebugResource, "getFileData(%s, fileSize)", fileName.c_str());
+
+ // first try to find files outside of .pak
+ // some patched files have not been included in package.
+ if (Common::File::exists(fileName)) {
+ Common::File file;
+ bool opened = file.open(fileName);
+ if (!opened)
+ return 0;
+
+ *fileSize = file.size();
+ uint8 *memory = (uint8 *)new uint8[*fileSize];
+ file.read(memory, *fileSize);
+ file.close();
+ return memory;
+ } else {
+ for (uint32 i = 0; i < _pakFiles.size(); i++) {
+ uint32 locFileSize = 0;
+ uint8 *locFileData = 0;
+
+ locFileData = _pakFiles[i]->getFileData(fileName, &locFileSize);
+ if (locFileData) {
+ *fileSize = locFileSize;
+ return locFileData;
+ }
+ }
+ return 0;
+ }
+}
+
+Common::SeekableReadStream *Resources::openFile(Common::String fileName) {
+ debugC(1, kDebugResource, "openFile(%s)", fileName.c_str());
+
+ // first try to find files outside of .pak
+ // some patched files have not been included in package.
+ if (Common::File::exists(fileName)) {
+ Common::File *file = new Common::File();
+ bool opened = file->open(fileName);
+ if (!opened) {
+ delete file;
+ return 0;
+ }
+ return file;
+ } else {
+ for (uint32 i = 0; i < _pakFiles.size(); i++) {
+ Common::SeekableReadStream *stream = 0;
+ stream = _pakFiles[i]->createReadStream(fileName);
+ if (stream)
+ return stream;
+ }
+
+ return 0;
+ }
+}
+Common::SeekableReadStream *PakFile::createReadStream(Common::String fileName) {
+ debugC(1, kDebugResource, "createReadStream(%s)", fileName.c_str());
+
+ int32 offset = 0;
+ int32 size = 0;
+ for (uint32 i = 0; i < _numFiles; i++) {
+ if (fileName.compareToIgnoreCase(_files[i]._name) == 0) {
+ size = _files[i]._size;
+ offset = _files[i]._offset;
+ break;
+ }
+ }
+ if (!size)
+ return 0;
+
+ if (_fileHandle)
+ return new Common::SeekableSubReadStream(_fileHandle, offset, offset + size);
+ else
+ return new Common::MemoryReadStream(_buffer + offset, size);
+}
+
+uint8 *PakFile::getFileData(Common::String fileName, uint32 *fileSize) {
+ debugC(4, kDebugResource, "getFileData(%s, fileSize)", fileName.c_str());
+
+ for (uint32 i = 0; i < _numFiles; i++) {
+ if (fileName.compareToIgnoreCase(_files[i]._name) == 0) {
+ *fileSize = _files[i]._size;
+ return _buffer + _files[i]._offset;
+ }
+ }
+
+ return 0;
+}
+
+void PakFile::open(Common::SeekableReadStream *rs, Common::String packName, bool preloadEntirePackage) {
+ debugC(1, kDebugResource, "open(rs, %d)", (preloadEntirePackage) ? 1 : 0);
+
+ char buffer[64];
+ int32 currentPos = 0;
+ _numFiles = 0;
+ _packName = packName;
+
+ while (1) {
+ rs->seek(currentPos);
+ rs->read(buffer, 64);
+
+ int32 offset = READ_LE_UINT32(buffer);
+ char *name = buffer + 4;
+
+ if (!*name)
+ break;
+
+ int32 nameSize = strlen(name) + 1;
+ int32 nextOffset = READ_LE_UINT32(buffer + 4 + nameSize);
+ currentPos += 4 + nameSize;
+
+ PakFile::File newFile;
+ strcpy(newFile._name, name);
+ newFile._offset = offset;
+ newFile._size = nextOffset - offset;
+ _numFiles++;
+ _files.push_back(newFile);
+ }
+
+ if (preloadEntirePackage) {
+ _bufferSize = rs->size();
+ _buffer = new uint8[_bufferSize];
+ rs->seek(0);
+ rs->read(_buffer, _bufferSize);
+ }
+}
+
+void PakFile::close() {
+ if (_buffer) {
+ delete[] _buffer;
+ }
+
+ if (_fileHandle) {
+ _fileHandle->close();
+ delete _fileHandle;
+ }
+}
+
+PakFile::~PakFile() {
+ close();
+}
+
+
+PakFile::PakFile() {
+ _fileHandle = 0;
+ _buffer = 0;
+ _bufferSize = 0;
+}
+
+} // End of namespace Toon
diff --git a/engines/toon/resource.h b/engines/toon/resource.h
new file mode 100644
index 0000000000..3a080fe894
--- /dev/null
+++ b/engines/toon/resource.h
@@ -0,0 +1,82 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* $URL$
+* $Id$
+*
+*/
+
+#ifndef TOON_RESOURCE_H
+#define TOON_RESOURCE_H
+
+#include "common/array.h"
+#include "common/str.h"
+#include "common/file.h"
+#include "common/stream.h"
+
+namespace Toon {
+
+class PakFile {
+public:
+ PakFile();
+ ~PakFile();
+
+ void open(Common::SeekableReadStream *rs, Common::String packName, bool preloadEntirePackage);
+ uint8 *getFileData(Common::String fileName, uint32 *fileSize);
+ Common::String getPackName() { return _packName; }
+ Common::SeekableReadStream *createReadStream(Common::String fileName);
+ void close();
+
+protected:
+ struct File {
+ char _name[13];
+ int32 _offset;
+ int32 _size;
+ };
+ Common::String _packName;
+
+ uint8 *_buffer;
+ int32 _bufferSize;
+
+ uint32 _numFiles;
+ Common::Array<File> _files;
+ Common::File *_fileHandle;
+
+
+};
+
+class ToonEngine;
+
+class Resources {
+public:
+ Resources(ToonEngine *vm);
+ void openPackage(Common::String file, bool preloadEntirePackage);
+ void closePackage(Common::String fileName);
+ Common::SeekableReadStream *openFile(Common::String file);
+ uint8 *getFileData(Common::String fileName, uint32 *fileSize);
+
+protected:
+ ToonEngine *_vm;
+ Common::Array<PakFile *> _pakFiles;
+
+};
+
+} // End of namespace Toon
+#endif
diff --git a/engines/toon/script.cpp b/engines/toon/script.cpp
new file mode 100644
index 0000000000..31d9f94f36
--- /dev/null
+++ b/engines/toon/script.cpp
@@ -0,0 +1,504 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* $URL$
+* $Id$
+*
+*/
+
+
+#include "common/endian.h"
+#include "common/stream.h"
+#include "common/util.h"
+#include "common/system.h"
+
+#include "toon/toon.h"
+#include "toon/script.h"
+
+namespace Toon {
+EMCInterpreter::EMCInterpreter(ToonEngine *vm) : _vm(vm), _scriptData(0), _filename(0) {
+
+#define OPCODE(x) { &EMCInterpreter::x, #x }
+ static const OpcodeEntry opcodes[] = {
+ // 0x00
+ OPCODE(op_jmp),
+ OPCODE(op_setRetValue),
+ OPCODE(op_pushRetOrPos),
+ OPCODE(op_push),
+ // 0x04
+ OPCODE(op_push),
+ OPCODE(op_pushReg),
+ OPCODE(op_pushBPNeg),
+ OPCODE(op_pushBPAdd),
+ // 0x08
+ OPCODE(op_popRetOrPos),
+ OPCODE(op_popReg),
+ OPCODE(op_popBPNeg),
+ OPCODE(op_popBPAdd),
+ // 0x0C
+ OPCODE(op_addSP),
+ OPCODE(op_subSP),
+ OPCODE(op_sysCall),
+ OPCODE(op_ifNotJmp),
+ // 0x10
+ OPCODE(op_negate),
+ OPCODE(op_eval),
+ OPCODE(op_setRetAndJmp)
+ };
+ _opcodes = opcodes;
+#undef OPCODE
+}
+
+bool EMCInterpreter::callback(Common::IFFChunk &chunk) {
+ switch (chunk._type) {
+ case MKID_BE('TEXT'):
+ _scriptData->text = new byte[chunk._size];
+ assert(_scriptData->text);
+ if (chunk._stream->read(_scriptData->text, chunk._size) != chunk._size)
+ error("Couldn't read TEXT chunk from file '%s'", _filename);
+ break;
+
+ case MKID_BE('ORDR'):
+ _scriptData->ordr = new uint16[chunk._size >> 1];
+ assert(_scriptData->ordr);
+ if (chunk._stream->read(_scriptData->ordr, chunk._size) != chunk._size)
+ error("Couldn't read ORDR chunk from file '%s'", _filename);
+
+ for (int i = (chunk._size >> 1) - 1; i >= 0; --i)
+ _scriptData->ordr[i] = READ_BE_UINT16(&_scriptData->ordr[i]);
+ break;
+
+ case MKID_BE('DATA'):
+ _scriptData->data = new uint16[chunk._size >> 1];
+ assert(_scriptData->data);
+ if (chunk._stream->read(_scriptData->data, chunk._size) != chunk._size)
+ error("Couldn't read DATA chunk from file '%s'", _filename);
+
+ for (int i = (chunk._size >> 1) - 1; i >= 0; --i)
+ _scriptData->data[i] = READ_BE_UINT16(&_scriptData->data[i]);
+ break;
+
+ default:
+ warning("Unexpected chunk '%s' of size %d found in file '%s'", Common::tag2string(chunk._type).c_str(), chunk._size, _filename);
+ }
+
+ return false;
+}
+
+bool EMCInterpreter::load(const char *filename, EMCData *scriptData, const Common::Array<const OpcodeV2 *> *opcodes) {
+ Common::SeekableReadStream *stream = _vm->resources()->openFile(filename);
+ if (!stream) {
+ error("Couldn't open script file '%s'", filename);
+ return false; // for compilers that don't support NORETURN
+ }
+
+ memset(scriptData, 0, sizeof(EMCData));
+
+ _scriptData = scriptData;
+ _filename = filename;
+
+ IFFParser iff(*stream);
+ Common::Functor1Mem< Common::IFFChunk &, bool, EMCInterpreter > c(this, &EMCInterpreter::callback);
+ iff.parse(c);
+
+ if (!_scriptData->ordr)
+ error("No ORDR chunk found in file: '%s'", filename);
+
+ if (!_scriptData->data)
+ error("No DATA chunk found in file: '%s'", filename);
+
+ if (stream->err())
+ error("Read error while parsing file '%s'", filename);
+
+ delete stream;
+
+ _scriptData->sysFuncs = opcodes;
+
+ strncpy(_scriptData->filename, filename, 13);
+ _scriptData->filename[12] = 0;
+
+ _scriptData = 0;
+ _filename = 0;
+
+ return true;
+}
+
+void EMCInterpreter::unload(EMCData *data) {
+ if (!data)
+ return;
+
+ delete[] data->text;
+ delete[] data->ordr;
+ delete[] data->data;
+
+ data->text = 0;
+ data->ordr = data->data = 0;
+}
+
+void EMCInterpreter::init(EMCState *scriptStat, const EMCData *data) {
+ scriptStat->dataPtr = data;
+ scriptStat->ip = 0;
+ scriptStat->stack[EMCState::kStackLastEntry] = 0;
+ scriptStat->bp = EMCState::kStackSize + 1;
+ scriptStat->sp = EMCState::kStackLastEntry;
+ scriptStat->running = false;
+}
+
+bool EMCInterpreter::start(EMCState *script, int function) {
+ if (!script->dataPtr)
+ return false;
+
+ uint16 functionOffset = script->dataPtr->ordr[function];
+ if (functionOffset == 0xFFFF)
+ return false;
+
+ script->ip = &script->dataPtr->data[functionOffset+1];
+
+ return true;
+}
+
+bool EMCInterpreter::isValid(EMCState *script) {
+ if (!script->ip || !script->dataPtr || _vm->shouldQuitGame())
+ return false;
+ return true;
+}
+
+bool EMCInterpreter::run(EMCState *script) {
+
+ if (script->running)
+ return false;
+
+ _parameter = 0;
+
+ if (!script->ip)
+ return false;
+
+ script->running = true;
+
+
+ // Should be no Problem at all to cast to uint32 here, since that's the biggest ptrdiff the original
+ // would allow, of course that's not realistic to happen to be somewhere near the limit of uint32 anyway.
+ const uint32 instOffset = (uint32)((const byte *)script->ip - (const byte *)script->dataPtr->data);
+ int16 code = *script->ip++;
+ int16 opcode = (code >> 8) & 0x1F;
+
+ if (code & 0x8000) {
+ opcode = 0;
+ _parameter = code & 0x7FFF;
+ } else if (code & 0x4000) {
+ _parameter = (int8)(code);
+ } else if (code & 0x2000) {
+ _parameter = *script->ip++;
+ } else {
+ _parameter = 0;
+ }
+
+ if (opcode > 18) {
+ error("Unknown script opcode: %d in file '%s' at offset 0x%.08X", opcode, script->dataPtr->filename, instOffset);
+ } else {
+ static bool EMCDebug = false;
+ if (EMCDebug)
+ debugC(5, 0, "[0x%.08X] EMCInterpreter::%s([%d/%u])", instOffset * 2, _opcodes[opcode].desc, _parameter, (uint)_parameter);
+ //debug(0, "[0x%.08X] EMCInterpreter::%s([%d/%u])", instOffset, _opcodes[opcode].desc, _parameter, (uint)_parameter);
+
+ (this->*(_opcodes[opcode].proc))(script);
+ }
+
+ script->running = false;
+ return (script->ip != 0);
+}
+
+#pragma mark -
+#pragma mark - Command implementations
+#pragma mark -
+
+void EMCInterpreter::op_jmp(EMCState *script) {
+ script->ip = script->dataPtr->data + _parameter;
+}
+
+void EMCInterpreter::op_setRetValue(EMCState *script) {
+ script->retValue = _parameter;
+}
+
+void EMCInterpreter::op_pushRetOrPos(EMCState *script) {
+ switch (_parameter) {
+ case 0:
+ script->stack[--script->sp] = script->retValue;
+ break;
+
+ case 1:
+ script->stack[--script->sp] = script->ip - script->dataPtr->data + 1;
+ script->stack[--script->sp] = script->bp;
+ script->bp = script->sp + 2;
+ break;
+
+ default:
+ script->ip = 0;
+ }
+}
+
+void EMCInterpreter::op_push(EMCState *script) {
+ script->stack[--script->sp] = _parameter;
+}
+
+void EMCInterpreter::op_pushReg(EMCState *script) {
+ script->stack[--script->sp] = script->regs[_parameter];
+}
+
+void EMCInterpreter::op_pushBPNeg(EMCState *script) {
+ script->stack[--script->sp] = script->stack[(-(int32)(_parameter + 2)) + script->bp];
+}
+
+void EMCInterpreter::op_pushBPAdd(EMCState *script) {
+ script->stack[--script->sp] = script->stack[(_parameter - 1) + script->bp];
+}
+
+void EMCInterpreter::op_popRetOrPos(EMCState *script) {
+ switch (_parameter) {
+ case 0:
+ script->retValue = script->stack[script->sp++];
+ break;
+
+ case 1:
+ if (script->sp >= EMCState::kStackLastEntry) {
+ script->ip = 0;
+ } else {
+ script->bp = script->stack[script->sp++];
+ script->ip = script->dataPtr->data + script->stack[script->sp++];
+ }
+ break;
+
+ default:
+ script->ip = 0;
+ }
+}
+
+void EMCInterpreter::op_popReg(EMCState *script) {
+ script->regs[_parameter] = script->stack[script->sp++];
+}
+
+void EMCInterpreter::op_popBPNeg(EMCState *script) {
+ script->stack[(-(int32)(_parameter + 2)) + script->bp] = script->stack[script->sp++];
+}
+
+void EMCInterpreter::op_popBPAdd(EMCState *script) {
+ script->stack[(_parameter - 1) + script->bp] = script->stack[script->sp++];
+}
+
+void EMCInterpreter::op_addSP(EMCState *script) {
+ script->sp += _parameter;
+}
+
+void EMCInterpreter::op_subSP(EMCState *script) {
+ script->sp -= _parameter;
+}
+
+void EMCInterpreter::op_sysCall(EMCState *script) {
+ const uint8 id = _parameter;
+
+ assert(script->dataPtr->sysFuncs);
+ assert(id < script->dataPtr->sysFuncs->size());
+
+ if ((*script->dataPtr->sysFuncs)[id] && ((*script->dataPtr->sysFuncs)[id])->isValid()) {
+ script->retValue = (*(*script->dataPtr->sysFuncs)[id])(script);
+ } else {
+ script->retValue = 0;
+ warning("Unimplemented system call 0x%.02X/%d used in file '%s'", id, id, script->dataPtr->filename);
+ }
+}
+
+void EMCInterpreter::op_ifNotJmp(EMCState *script) {
+ if (!script->stack[script->sp++]) {
+ _parameter &= 0x7FFF;
+ script->ip = script->dataPtr->data + _parameter;
+ }
+}
+
+void EMCInterpreter::op_negate(EMCState *script) {
+ int16 value = script->stack[script->sp];
+ switch (_parameter) {
+ case 0:
+ if (!value)
+ script->stack[script->sp] = 1;
+ else
+ script->stack[script->sp] = 0;
+ break;
+
+ case 1:
+ script->stack[script->sp] = -value;
+ break;
+
+ case 2:
+ script->stack[script->sp] = ~value;
+ break;
+
+ default:
+ warning("Unknown negation func: %d", _parameter);
+ script->ip = 0;
+ }
+}
+
+void EMCInterpreter::op_eval(EMCState *script) {
+ int16 ret = 0;
+ bool error = false;
+
+ int16 val1 = script->stack[script->sp++];
+ int16 val2 = script->stack[script->sp++];
+
+ switch (_parameter) {
+ case 0:
+ ret = (val2 && val1) ? 1 : 0;
+ break;
+
+ case 1:
+ ret = (val2 || val1) ? 1 : 0;
+ break;
+
+ case 2:
+ ret = (val1 == val2) ? 1 : 0;
+ break;
+
+ case 3:
+ ret = (val1 != val2) ? 1 : 0;
+ break;
+
+ case 4:
+ ret = (val1 > val2) ? 1 : 0;
+ break;
+
+ case 5:
+ ret = (val1 >= val2) ? 1 : 0;
+ break;
+
+ case 6:
+ ret = (val1 < val2) ? 1 : 0;
+ break;
+
+ case 7:
+ ret = (val1 <= val2) ? 1 : 0;
+ break;
+
+ case 8:
+ ret = val1 + val2;
+ break;
+
+ case 9:
+ ret = val2 - val1;
+ break;
+
+ case 10:
+ ret = val1 * val2;
+ break;
+
+ case 11:
+ ret = val2 / val1;
+ break;
+
+ case 12:
+ ret = val2 >> val1;
+ break;
+
+ case 13:
+ ret = val2 << val1;
+ break;
+
+ case 14:
+ ret = val1 & val2;
+ break;
+
+ case 15:
+ ret = val1 | val2;
+ break;
+
+ case 16:
+ ret = val2 % val1;
+ break;
+
+ case 17:
+ ret = val1 ^ val2;
+ break;
+
+ default:
+ warning("Unknown evaluate func: %d", _parameter);
+ error = true;
+ }
+
+ if (error)
+ script->ip = 0;
+ else
+ script->stack[--script->sp] = ret;
+}
+
+void EMCInterpreter::op_setRetAndJmp(EMCState *script) {
+ if (script->sp >= EMCState::kStackLastEntry) {
+ script->ip = 0;
+ } else {
+ script->retValue = script->stack[script->sp++];
+ uint16 temp = script->stack[script->sp++];
+ script->stack[EMCState::kStackLastEntry] = 0;
+ script->ip = &script->dataPtr->data[temp];
+ }
+}
+
+void EMCInterpreter::saveState(EMCState *script, Common::WriteStream *stream) {
+ stream->writeSint16LE(script->bp);
+ stream->writeSint16LE(script->sp);
+ if (!script->ip) {
+ stream->writeSint16LE(-1);
+ } else {
+ stream->writeSint16LE(script->ip - script->dataPtr->data);
+ }
+
+ for (int32 i = 0; i < EMCState::kStackSize; i++) {
+ stream->writeSint16LE(script->stack[i]);
+ }
+
+ for (int32 i = 0; i < 30; i++) {
+ stream->writeSint16LE(script->regs[i]);
+ }
+
+ stream->writeSint16LE(script->retValue);
+ stream->writeByte(script->running);
+}
+void EMCInterpreter::loadState(EMCState *script, Common::ReadStream *stream) {
+ script->bp = stream->readSint16LE();
+ script->sp = stream->readSint16LE();
+
+ int16 scriptIp = stream->readSint16LE();
+ if (scriptIp == -1) {
+ script->ip = 0;
+ } else {
+ script->ip = scriptIp + script->dataPtr->data;
+ }
+
+ for (int32 i = 0; i < EMCState::kStackSize; i++) {
+ script->stack[i] = stream->readSint16LE();
+ }
+
+ for (int32 i = 0; i < 30; i++) {
+ script->regs[i] = stream->readSint16LE();
+ }
+
+ script->retValue = stream->readSint16LE();
+ script->running = stream->readByte();
+}
+
+} // End of namespace Toon
+
diff --git a/engines/toon/script.h b/engines/toon/script.h
new file mode 100644
index 0000000000..d7f45096c2
--- /dev/null
+++ b/engines/toon/script.h
@@ -0,0 +1,153 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* $URL$
+* $Id$
+*
+*/
+
+#ifndef TOON_SCRIPT_H
+#define TOON_SCRIPT_H
+
+#include "common/stream.h"
+#include "common/array.h"
+#include "common/func.h"
+#include "common/iff_container.h"
+
+
+// Based on Kyra script interpretor
+namespace Toon {
+
+struct EMCState;
+class ScriptFunc;
+typedef Common::Functor1Mem<EMCState *, int32, ScriptFunc> OpcodeV2;
+
+struct EMCData {
+ char filename[13];
+
+ byte *text;
+ uint16 *data;
+ uint16 *ordr;
+ uint16 dataSize;
+
+ const Common::Array<const OpcodeV2 *> *sysFuncs;
+};
+
+struct EMCState {
+ enum {
+ kStackSize = 100,
+ kStackLastEntry = kStackSize - 1
+ };
+
+ const uint16 *ip;
+ const EMCData *dataPtr;
+ int16 retValue;
+ uint16 bp;
+ uint16 sp;
+ int16 regs[30]; // VM registers
+ int16 stack[kStackSize]; // VM stack
+ bool running;
+};
+
+#define stackPos(x) (state->stack[state->sp+x])
+#define stackPosString(x) ((const char *)&state->dataPtr->text[READ_BE_UINT16(&state->dataPtr->text[stackPos(x)<<1])])
+
+class Resource;
+class ToonEngine;
+
+class IFFParser : public Common::IFFParser {
+public:
+ IFFParser(Common::ReadStream &input) : Common::IFFParser(&input) {
+ // It seems Westwood missunderstood the 'size' field of the FORM chunk.
+ //
+ // For EMC scripts (type EMC2) it's filesize instead of filesize - 8,
+ // means accidently including the 8 bytes used by the chunk header for the FORM
+ // chunk.
+ //
+ // For TIM scripts (type AVFS) it's filesize - 12 instead of filesize - 8,
+ // means it will not include the size of the 'type' field in the FORM chunk,
+ // instead of only not including the chunk header size.
+ //
+ // Both lead to some problems in our IFF parser, either reading after the end
+ // of file or producing a "Chunk overread" error message. To work around this
+ // we need to adjust the size field properly.
+ if (_formType == MKID_BE('EMC2'))
+ _formChunk.size -= 8;
+ else if (_formType == MKID_BE('AVFS'))
+ _formChunk.size += 4;
+ }
+};
+
+class EMCInterpreter {
+public:
+ EMCInterpreter(ToonEngine *vm);
+
+ bool load(const char *filename, EMCData *data, const Common::Array<const OpcodeV2 *> *opcodes);
+ void unload(EMCData *data);
+
+ void init(EMCState *scriptState, const EMCData *data);
+ bool start(EMCState *script, int function);
+
+ void saveState(EMCState *script, Common::WriteStream *stream);
+ void loadState(EMCState *script, Common::ReadStream *stream);
+
+ bool isValid(EMCState *script);
+
+ bool run(EMCState *script);
+protected:
+ ToonEngine *_vm;
+ int16 _parameter;
+
+ const char *_filename;
+ EMCData *_scriptData;
+
+ bool callback(Common::IFFChunk &chunk);
+
+ typedef void (EMCInterpreter::*OpcodeProc)(EMCState *);
+ struct OpcodeEntry {
+ OpcodeProc proc;
+ const char *desc;
+ };
+
+ const OpcodeEntry *_opcodes;
+private:
+ void op_jmp(EMCState *);
+ void op_setRetValue(EMCState *);
+ void op_pushRetOrPos(EMCState *);
+ void op_push(EMCState *);
+ void op_pushReg(EMCState *);
+ void op_pushBPNeg(EMCState *);
+ void op_pushBPAdd(EMCState *);
+ void op_popRetOrPos(EMCState *);
+ void op_popReg(EMCState *);
+ void op_popBPNeg(EMCState *);
+ void op_popBPAdd(EMCState *);
+ void op_addSP(EMCState *);
+ void op_subSP(EMCState *);
+ void op_sysCall(EMCState *);
+ void op_ifNotJmp(EMCState *);
+ void op_negate(EMCState *);
+ void op_eval(EMCState *);
+ void op_setRetAndJmp(EMCState *);
+};
+} // End of namespace Toon
+
+#endif
+
diff --git a/engines/toon/script_func.cpp b/engines/toon/script_func.cpp
new file mode 100644
index 0000000000..f571f324ef
--- /dev/null
+++ b/engines/toon/script_func.cpp
@@ -0,0 +1,1186 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* $URL$
+* $Id$
+*
+*/
+
+#include "toon/script_func.h"
+#include "toon/script.h"
+#include "toon/state.h"
+#include "toon/toon.h"
+#include "toon/anim.h"
+#include "toon/hotspot.h"
+#include "toon/drew.h"
+#include "toon/flux.h"
+
+namespace Toon {
+
+#define SetOpcodeTable(x) table = &x;
+#define Opcode(x) table->push_back(new OpcodeV2(this, &ScriptFunc::x))
+#define OpcodeUnImpl() table->push_back(new OpcodeV2(this, 0))
+
+ScriptFunc::ScriptFunc(ToonEngine *vm) {
+ Common::Array<const OpcodeV2 *> *table = 0;
+
+ _vm = vm;
+ _opcodes.reserve(176);
+ SetOpcodeTable(_opcodes);
+
+ Opcode(sys_Cmd_Dummy); // dd offset sub_2B160
+ Opcode(sys_Cmd_Change_Actor_X_And_Y); // dd offset sub_2A710
+ Opcode(sys_Cmd_Init_Talking_Character); // dd offset sub_2A4E0
+ Opcode(sys_Cmd_Draw_Actor_Standing), // dd offset sub_2A650
+ Opcode(sys_Cmd_Get_Actor_X), // dd offset sub_2ADC0
+ Opcode(sys_Cmd_Get_Actor_Y), // dd offset sub_2ADD0
+ Opcode(sys_Cmd_Get_Actor_Facing), // dd offset sub_2A790
+ Opcode(sys_Cmd_Get_Last_Scene), // dd offset sub_29F80
+ Opcode(sys_Cmd_Debug_Print), // dd offset sub_2A510
+ Opcode(sys_Cmd_Flip_Screens), // dd offset sub_2A180
+ Opcode(sys_Cmd_Play_Flic), // dd offset sub_2A080
+ Opcode(sys_Cmd_Force_Facing), // dd offset sub_29F90
+ Opcode(sys_Cmd_Restart_Thread), // dd offset sub_29F30
+ Opcode(sys_Cmd_Walk_Actor_To_Point), // dd offset sub_2A440
+ Opcode(sys_Cmd_Set_Sack_Visible), // dd offset sub_29920
+ Opcode(sys_Cmd_Set_Actor_Facing), // dd offset sub_2AD60
+ Opcode(sys_Cmd_Confiscate_Inventory), // dd offset sub_29EB0
+ Opcode(sys_Cmd_Character_Talks), // dd offset sub_29F00
+ Opcode(sys_Cmd_Visited_Scene), // dd offset sub_29E80
+ Opcode(sys_Cmd_Query_Rif_Flag), // dd offset sub_29D20
+ Opcode(sys_Cmd_Query_Scroll), // dd offset sub_29D60
+ Opcode(sys_Cmd_Set_Initial_Location), // dd offset sub_2AD80
+ Opcode(sys_Cmd_Make_Line_Non_Walkable), // dd offset sub_29FC0
+ Opcode(sys_Cmd_Make_Line_Walkable), // dd offset sub_2A050
+ Opcode(sys_Cmd_Walk_Actor_On_Condition), // dd offset sub_29D70
+ Opcode(sys_Cmd_Set_Actor_Facing_Point), // dd offset sub_29E60
+ Opcode(sys_Cmd_Set_Inventory_Slot), // dd offset sub_2B0D0
+ Opcode(sys_Cmd_Get_Inventory_Slot), // dd offset sub_2B0F0
+ Opcode(sys_Cmd_Add_Item_To_Inventory), // dd offset sub_2AE50
+ Opcode(sys_Cmd_Set_Actor_RGB_Modifiers), // dd offset sub_29CA0
+ Opcode(sys_Cmd_Init_Conversation_AP), // dd offset sub_2B130
+ Opcode(sys_Cmd_Actor_Talks), // dd offset sub_2ADA0
+ Opcode(sys_Cmd_Say_Lines), // dd offset sub_29B20
+ Opcode(sys_Cmd_Set_Rif_Flag), // dd offset sub_2A320
+ Opcode(sys_Cmd_Empty_Inventory), // dd offset sub_2AE10
+ Opcode(sys_Cmd_Set_Anim_Scale_Size), // dd offset sub_29BD0
+ Opcode(sys_Cmd_Delete_Item_From_Inventory), // dd offset sub_2AE70
+ Opcode(sys_Cmd_Specific_Item_In_Inventory), // dd offset sub_2A740
+ Opcode(sys_Cmd_Run_Script), // dd offset sub_29AF0
+ Opcode(sys_Cmd_Query_Game_Flag), // dd offset sub_2A3E0
+ Opcode(sys_Cmd_Reset_Game_Flag), // dd offset sub_2A420
+ Opcode(sys_Cmd_Set_Game_Flag), // dd offset sub_2A400
+ Opcode(sys_Cmd_Create_Mouse_Item), // dd offset sub_2A4B0
+ Opcode(sys_Cmd_Destroy_Mouse_Item), // dd offset sub_2A4D0
+ Opcode(sys_Cmd_Get_Mouse_State), // dd offset sub_2A860
+ Opcode(sys_Cmd_Hide_Mouse), // dd offset sub_2A5D0
+ Opcode(sys_Cmd_Exit_Conversation), // dd offset sub_29AE0
+ Opcode(sys_Cmd_Set_Mouse_Pos), // dd offset sub_2A810
+ Opcode(sys_Cmd_Show_Mouse), // dd offset sub_2A5F0
+ Opcode(sys_Cmd_In_Close_Up), // dd offset sub_29FB0
+ Opcode(sys_Cmd_Set_Scroll_Lock), // dd offset sub_298B0
+ Opcode(sys_Cmd_Fill_Area_Non_Walkable), // dd offset sub_29FF0
+ Opcode(sys_Cmd_Set_Scroll_Coords), // dd offset sub_298D0
+ Opcode(sys_Cmd_Hide_Cutaway), // dd offset sub_2A0F0
+ Opcode(sys_Cmd_Show_Cutaway), // dd offset sub_2A100
+ Opcode(sys_Cmd_Pause_Ticks), // dd offset sub_2A360
+ Opcode(sys_Cmd_In_Conversation), // dd offset sub_29C60
+ Opcode(sys_Cmd_Character_Talking), // dd offset sub_29C70
+ Opcode(sys_Cmd_Set_Flux_Facing_Point), // dd offset sub_29980
+ Opcode(sys_Cmd_Set_Flux_Facing), // dd offset sub_299A0
+ Opcode(sys_Cmd_Set_Flux_Coords), // dd offset sub_299C0
+ Opcode(sys_Cmd_Set_Flux_Visible), // dd offset sub_299F0
+ Opcode(sys_Cmd_Get_Flux_X), // dd offset sub_29A40
+ Opcode(sys_Cmd_Get_Flux_Y), // dd offset sub_29A50
+ Opcode(sys_Cmd_Get_Flux_Facing), // dd offset sub_29A60
+ Opcode(sys_Cmd_Get_Flux_Flags), // dd offset sub_29A70
+ Opcode(sys_Cmd_Query_Flux_Coords), // dd offset sub_29A90
+ Opcode(sys_Cmd_Have_A_Conversation), // dd offset sub_2B110
+ Opcode(sys_Cmd_Walk_Flux_To_Point), // dd offset sub_29AC0
+ Opcode(sys_Cmd_Get_Actor_Final_X), // dd offset sub_29940
+ Opcode(sys_Cmd_Get_Actor_Final_Y), // dd offset sub_29960
+ Opcode(sys_Cmd_Query_Scene_Anim_Loaded), // dd offset sub_29870
+ Opcode(sys_Cmd_Play_Flux_Anim), // dd offset sub_29820
+ Opcode(sys_Cmd_Set_Anim_Priority), // dd offset sub_29790
+ Opcode(sys_Cmd_Place_Scene_Anim), // dd offset sub_2A7A0
+ Opcode(sys_Cmd_Update_Scene_Animations), // dd offset sub_2AE30
+ Opcode(sys_Cmd_Get_Drew_Scale), // dd offset sub_297E0
+ Opcode(sys_Cmd_Query_Drew_Flags), // dd offset sub_29800
+ Opcode(sys_Cmd_Set_Music), // dd offset sub_29720
+ Opcode(sys_Cmd_Query_Speech), // dd offset sub_296D0
+ Opcode(sys_Cmd_Enter_New_Scene), // dd offset sub_2A550
+ Opcode(sys_Cmd_Enter_Same_Scene), // dd offset sub_2ADE0
+ Opcode(sys_Cmd_Is_Pixel_Walkable), // dd offset sub_2A4F0
+ Opcode(sys_Cmd_Show_Screen), // dd offset sub_2A0C0
+ Opcode(sys_Cmd_Hide_Screen), // dd offset sub_2A0F0
+ Opcode(sys_Cmd_Dummy), // dd offset sub_295D0
+ Opcode(sys_Cmd_Set_Special_Enter_X_And_Y), // dd offset sub_2A590
+ Opcode(sys_Cmd_Get_Mouse_X), // dd offset sub_296B0
+ Opcode(sys_Cmd_Get_Mouse_Y), // dd offset sub_296C0
+ Opcode(sys_Cmd_Fade_Palette), // dd offset sub_29650
+ Opcode(sys_Cmd_Music_Enabled), // dd offset sub_29620
+ Opcode(sys_Cmd_Dummy), // dd offset sub_295F0
+ Opcode(sys_Cmd_Dummy), // dd offset sub_29610
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Random), // dd offset sub_2A600
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Wait_Key), // dd offset sub_2AE20
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Draw_Scene_Anim_WSA_Frame_To_Back), // dd offset sub_2A940
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Set_Scene_Anim_Wait), // dd offset sub_2A870
+ Opcode(sys_Cmd_Init_Scene_Anim), // dd offset sub_2AC60
+ Opcode(sys_Cmd_Set_Scene_Animation_Active_Flag), // dd offset sub_2AB10
+ Opcode(sys_Cmd_Draw_Scene_Anim_WSA_Frame), // dd offset sub_2A8D0
+ Opcode(sys_Cmd_Move_Scene_Anim), // dd offset sub_2AA90
+ Opcode(sys_Cmd_Run_Actor_Default_Script), // dd offset sub_2A4E0
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Set_Location_Data), // dd offset sub_2AE90
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Set_CountDown_Timer), // dd offset sub_2AFC0
+ Opcode(sys_Cmd_Query_CountDown_Timer), // dd offset sub_2AFE0
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Proceed_To_Next_Chapter), // dd offset sub_2AFF0
+ Opcode(sys_Cmd_Play_Sfx_Plus), // dd offset sub_2A1D0
+ Opcode(sys_Cmd_Play_Sfx), // dd offset sub_2A1A0
+ Opcode(sys_Cmd_Set_Ambient_Sfx), // dd offset sub_2A260
+ Opcode(sys_Cmd_Kill_Ambient_Sfx), // dd offset sub_2A300
+ Opcode(sys_Cmd_Set_Ambient_Sfx_Plus), // dd offset sub_2A290
+ Opcode(sys_Cmd_Set_Ambient_Volume), // dd offset sub_2A240
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Freeze_Scene_Animation), // dd offset sub_2AB90
+ Opcode(sys_Cmd_Unfreeze_Scene_Animation), // dd offset sub_2ABB0
+ Opcode(sys_Cmd_Scene_Animation_Frozen), // dd offset sub_2ABD0
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Set_Script_Game_Data_Global), // dd offset sub_2ABF0
+ Opcode(sys_Cmd_Get_Script_Game_Data_Global), // dd offset sub_2AC30
+ Opcode(sys_Cmd_Say_Line), // dd offset loc_2A190
+ Opcode(sys_Cmd_Knight_Puzzle_Get_Coord), // dd offset sub_2A110
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Add_Scene_Anim), // dd offset sub_2AC60
+ Opcode(sys_Cmd_Remove_Scene_Anim), // dd offset sub_2ACE0
+ Opcode(sys_Cmd_Disable_Timer), // dd offset sub_2AD00
+ Opcode(sys_Cmd_Enable_Timer), // dd offset sub_2AD20
+ Opcode(sys_Cmd_Set_Timer), // dd offset sub_2AD40
+ Opcode(sys_Cmd_Set_Palette_Color), // dd offset sub_2B020
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Number_Of_NPCs), // dd offset loc_2A190
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Dummy), // dd offset sub_2B160
+ Opcode(sys_Cmd_Get_Config_Language), // dd offset sub_2B0C0
+ Opcode(sys_Cmd_Dummy); // dd offset sub_2B160
+}
+
+ScriptFunc::~ScriptFunc(void) {
+
+}
+
+char *GetText(int32 i, EMCState *state) {
+ short stack = stackPos(i);
+ unsigned short textoffset = READ_BE_UINT16(&((unsigned short *)(state->dataPtr->text))[stack]);
+ char *text = (char *)&state->dataPtr->text[textoffset];
+ return text;
+}
+
+int32 ScriptFunc::sys_Cmd_Dummy(EMCState *state) {
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Change_Actor_X_And_Y(EMCState *state) {
+ _vm->getDrew()->setPosition(stackPos(0), stackPos(1));
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Init_Talking_Character(EMCState *state) {
+ // really does nothing in original
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Draw_Actor_Standing(EMCState *state) {
+
+ int32 arg1 = stackPos(0);
+ int32 arg2 = stackPos(1);
+
+ if (arg2 > -1)
+ _vm->getDrew()->setFacing(arg2);
+
+ if (arg1 < 0) {
+ _vm->getDrew()->setVisible(false);
+ } else {
+ _vm->getDrew()->setVisible(true);
+ _vm->getDrew()->playStandingAnim();
+ }
+
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Get_Actor_X(EMCState *state) {
+ return _vm->getDrew()->getX();
+}
+
+int32 ScriptFunc::sys_Cmd_Get_Actor_Y(EMCState *state) {
+ return _vm->getDrew()->getY();
+}
+
+int32 ScriptFunc::sys_Cmd_Get_Actor_Final_X(EMCState *state) {
+ return _vm->getDrew()->getFinalX();
+}
+
+int32 ScriptFunc::sys_Cmd_Get_Actor_Final_Y(EMCState *state) {
+ return _vm->getDrew()->getFinalY();
+}
+
+int32 ScriptFunc::sys_Cmd_Get_Actor_Facing(EMCState *state) {
+ return _vm->getDrew()->getFacing();
+}
+
+int32 ScriptFunc::sys_Cmd_Get_Last_Scene(EMCState *state) {
+ return _vm->state()->_lastVisitedScene;
+}
+
+int32 ScriptFunc::sys_Cmd_Debug_Print(EMCState *state) {
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Flip_Screens(EMCState *state) {
+ _vm->flipScreens();
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Play_Flic(EMCState *state) {
+
+ char name[256];
+
+ // workaround for the video of the beginning
+ if (strstr(GetText(0, state), "209"))
+ sprintf(name, "misc/%s", GetText(0, state));
+ else
+ strcpy(name, _vm->createRoomFilename(GetText(0, state)).c_str());
+
+// Strangerke - Commented (not used)
+// int32 Flags = stackPos(1);
+ int32 stopMusic = stackPos(2);
+ _vm->getMoviePlayer()->play(name, stopMusic);
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Force_Facing(EMCState *state) {
+ _vm->getDrew()->setFacing(stackPos(0));
+ _vm->getDrew()->playStandingAnim();
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Restart_Thread(EMCState *state) {
+
+ int32 sceneId = stackPos(0);
+ _vm->getScript()->init(&_vm->getSceneAnimationScript(sceneId)->_state, _vm->getSceneAnimationScript(sceneId)->_data);
+ _vm->getScript()->start(&_vm->getSceneAnimationScript(sceneId)->_state, 9 + sceneId);
+
+ if (!stackPos(1))
+ _vm->setSceneAnimationScriptUpdate(false);
+
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Walk_Actor_To_Point(EMCState *state) {
+ return _vm->getDrew()->walkTo(stackPos(0), stackPos(1));
+}
+
+int32 ScriptFunc::sys_Cmd_Set_Sack_Visible(EMCState *state) {
+ _vm->state()->_sackVisible = stackPos(0) > 0;
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Set_Actor_Facing(EMCState *state) {
+ _vm->getDrew()->setFacing(stackPos(0));
+ _vm->getDrew()->playStandingAnim();
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Confiscate_Inventory(EMCState *state) {
+ for (int32 i = 0; i < _vm->state()->_numInventoryItems; i++) {
+ _vm->state()->_confiscatedInventory[_vm->state()->_numConfiscatedInventoryItems] = _vm->state()->_inventory[i];
+ _vm->state()->_numConfiscatedInventoryItems++;
+ }
+ _vm->state()->_numInventoryItems = 0;
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Character_Talks(EMCState *state) {
+ _vm->characterTalk(stackPos(0), false);
+ //_vm->characterTalk(stackPos(0));
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Visited_Scene(EMCState *state) {
+ return _vm->state()->_locations[stackPos(0)]._visited ? 1 : 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Query_Rif_Flag(EMCState *state) {
+
+ int32 hs = _vm->getHotspots()->FindBasedOnCorner(stackPos(0), stackPos(1));
+ if (hs >= 0)
+ return _vm->getHotspots()->Get(hs)->getData(stackPos(2));
+
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Query_Scroll(EMCState *state) {
+ return _vm->state()->_currentScrollValue;
+}
+
+int32 ScriptFunc::sys_Cmd_Set_Initial_Location(EMCState *state) {
+ int32 initialLocation = stackPos(0);
+ _vm->state()->_currentScene = initialLocation;
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Make_Line_Non_Walkable(EMCState *state) {
+ _vm->makeLineNonWalkable(stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+
+ // we have to store some info for savegame
+ _vm->getSaveBufferStream()->writeSint16BE(2); // 2 = sys_Cmd_Make_Line_Non_Walkable
+ _vm->getSaveBufferStream()->writeSint16BE(stackPos(0));
+ _vm->getSaveBufferStream()->writeSint16BE(stackPos(1));
+ _vm->getSaveBufferStream()->writeSint16BE(stackPos(2));
+ _vm->getSaveBufferStream()->writeSint16BE(stackPos(3));
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Make_Line_Walkable(EMCState *state) {
+ _vm->makeLineWalkable(stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+
+ // we have to store some info for savegame
+ _vm->getSaveBufferStream()->writeSint16BE(3); // 3 = sys_Cmd_Make_Line_Walkable
+ _vm->getSaveBufferStream()->writeSint16BE(stackPos(0));
+ _vm->getSaveBufferStream()->writeSint16BE(stackPos(1));
+ _vm->getSaveBufferStream()->writeSint16BE(stackPos(2));
+ _vm->getSaveBufferStream()->writeSint16BE(stackPos(3));
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Walk_Actor_On_Condition(EMCState *state) {
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Set_Actor_Facing_Point(EMCState *state) {
+ int32 fx = stackPos(0);
+ int32 fy = stackPos(1);
+ _vm->getDrew()->setFacing(_vm->getDrew()->getFacingFromDirection(fx - _vm->getDrew()->getX(), fy - _vm->getDrew()->getY()));
+ return 1;
+}
+
+int32 ScriptFunc::sys_Cmd_Set_Inventory_Slot(EMCState *state) {
+ _vm->state()->_inventory[stackPos(1)] = stackPos(0);
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Get_Inventory_Slot(EMCState *state) {
+ return _vm->state()->_inventory[stackPos(0)];
+}
+
+int32 ScriptFunc::sys_Cmd_Add_Item_To_Inventory(EMCState *state) {
+ _vm->addItemToInventory(stackPos(0));
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Set_Actor_RGB_Modifiers(EMCState *state) {
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Init_Conversation_AP(EMCState *state) {
+ debugC(0, 0xfff, "init_conversation_ap %d %d %d %d", stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+ _vm->initCharacter(stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Actor_Talks(EMCState *state) {
+ _vm->characterTalk(stackPos(0), false);
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Say_Lines(EMCState *state) {
+ //_vm->sayLines(2, 1440);
+ _vm->sayLines(stackPos(0), stackPos(1));
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Set_Rif_Flag(EMCState *state) {
+ int32 hs = _vm->getHotspots()->FindBasedOnCorner(stackPos(0), stackPos(1));
+ if (hs >= 0)
+ _vm->getHotspots()->Get(hs)->setData(stackPos(2), stackPos(3));
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Empty_Inventory(EMCState *state) {
+
+ for (int32 i = 0; i < _vm->state()->_numInventoryItems; i++)
+ _vm->state()->_inventory[i] = 0;
+
+ _vm->state()->_numInventoryItems = 0;
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Set_Anim_Scale_Size(EMCState *state) {
+ int32 animID = stackPos(0);
+ int32 scale = stackPos(1);
+
+ SceneAnimation *sceneAnim = _vm->getSceneAnimation(animID);
+ if (sceneAnim) {
+ sceneAnim->_animInstance->setUseMask(true);
+ sceneAnim->_animInstance->setScale(scale,true);
+ }
+ return 0;
+}
+int32 ScriptFunc::sys_Cmd_Delete_Item_From_Inventory(EMCState *state) {
+ for (int32 i = 0; i < _vm->state()->_numInventoryItems; i++) {
+ if (stackPos(0) == _vm->state()->_inventory[i])
+ _vm->state()->_inventory[i] = 0;
+ }
+ _vm->rearrangeInventory();
+ return 0;
+}
+int32 ScriptFunc::sys_Cmd_Specific_Item_In_Inventory(EMCState *state) {
+ for (int32 i = 0; i < _vm->state()->_numInventoryItems; i++) {
+ if (_vm->state()->_inventory[i] == stackPos(0))
+ return 1;
+ }
+ if (_vm->state()->_mouseState == stackPos(0))
+ return 1;
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Run_Script(EMCState *state) {
+ return _vm->runEventScript(_vm->getMouseX(), _vm->getMouseY(), 2, stackPos(0), 0);
+}
+
+int32 ScriptFunc::sys_Cmd_Query_Game_Flag(EMCState *state) {
+ int32 arg = stackPos(0);
+ return (_vm->state()->_gameFlag[arg >> 3] & (1 << (arg & 7))) != 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Reset_Game_Flag(EMCState *state) {
+ int32 arg = stackPos(0);
+ _vm->state()->_gameFlag[arg >> 3] &= ~(1 << (arg & 7));
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Set_Game_Flag(EMCState *state) {
+ int32 arg = stackPos(0);
+ _vm->state()->_gameFlag[arg >> 3] |= (1 << (arg & 7));
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Create_Mouse_Item(EMCState *state) {
+ _vm->createMouseItem(stackPos(0));
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Destroy_Mouse_Item(EMCState *state) {
+ _vm->deleteMouseItem();
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Get_Mouse_State(EMCState *state) {
+ return _vm->state()->_mouseState;
+}
+
+int32 ScriptFunc::sys_Cmd_Hide_Mouse(EMCState *state) {
+ _vm->state()->_mouseHidden = true;
+ //if (Game.MouseHiddenCount > 0) Game.MouseHiddenCount = 1;
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Exit_Conversation(EMCState *state) {
+ _vm->state()->_exitConversation = true;
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Set_Mouse_Pos(EMCState *state) {
+ if (_vm->state()->_inCloseUp) {
+ _vm->getSystem()->warpMouse(stackPos(0), stackPos(1));
+ } else {
+ _vm->getSystem()->warpMouse(stackPos(0) - _vm->state()->_currentScrollValue, stackPos(1));
+ }
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Show_Mouse(EMCState *state) {
+ _vm->state()->_mouseHidden = false;
+ //if (Game.MouseHiddenCount < 0) Game.MouseHiddenCount = 0;
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_In_Close_Up(EMCState *state) {
+ return _vm->state()->_inCloseUp;
+}
+
+int32 ScriptFunc::sys_Cmd_Set_Scroll_Lock(EMCState *state) {
+ _vm->state()->_currentScrollLock = stackPos(0) > 0;
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Fill_Area_Non_Walkable(EMCState *state) {
+ _vm->getMask()->floodFillNotWalkableOnMask(stackPos(0), stackPos(1));
+
+ // we have to store some info for savegame
+ _vm->getSaveBufferStream()->writeSint16BE(4); // 4 = sys_Cmd_Make_Line_Walkable
+ _vm->getSaveBufferStream()->writeSint16BE(stackPos(0));
+ _vm->getSaveBufferStream()->writeSint16BE(stackPos(1));
+
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Set_Scroll_Coords(EMCState *state) {
+ _vm->state()->_currentScrollValue = stackPos(0);
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Hide_Cutaway(EMCState *state) {
+ _vm->hideCutaway();
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Show_Cutaway(EMCState *state) {
+ _vm->showCutaway("");
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Pause_Ticks(EMCState *state) {
+
+ if (!_vm->isUpdatingSceneAnimation() || _vm->getScriptRegionNested() > 0) {
+ if (stackPos(1))
+ _vm->waitTicks(stackPos(0), true);
+ else
+ _vm->waitTicks(stackPos(0), false);
+ } else {
+ uint32 sceneId = _vm->getCurrentUpdatingSceneAnimation();
+ uint32 waitTicks = stackPos(0);
+ if (waitTicks < 1) waitTicks = 1;
+
+ waitTicks *= _vm->getTickLength();
+
+ if (sceneId < 40) {
+ int32 nextTicks = waitTicks + _vm->getSceneAnimationScript(sceneId)->_lastTimer;
+ if (nextTicks < _vm->getOldMilli())
+ _vm->getSceneAnimationScript(sceneId)->_lastTimer = _vm->getOldMilli() + waitTicks;
+ else
+ _vm->getSceneAnimationScript(sceneId)->_lastTimer = nextTicks;
+ }
+ return 0;
+ }
+
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_In_Conversation(EMCState *state) {
+ return _vm->state()->_inConversation;
+}
+
+int32 ScriptFunc::sys_Cmd_Character_Talking(EMCState *state) {
+ int32 characterId = stackPos(0);
+ Character *character = _vm->getCharacterById(characterId);
+ if (character)
+ return character->isTalking();
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Set_Flux_Facing_Point(EMCState *state) {
+ int32 fx = stackPos(0);
+ int32 fy = stackPos(1);
+ _vm->getFlux()->setFacing(_vm->getFlux()->getFacingFromDirection(fx - _vm->getFlux()->getX(), fy - _vm->getFlux()->getY()));
+ _vm->getFlux()->playStandingAnim();
+ return 1;
+}
+
+int32 ScriptFunc::sys_Cmd_Set_Flux_Facing(EMCState *state) {
+ _vm->getFlux()->setFacing(stackPos(0));
+ _vm->getFlux()->playStandingAnim();
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Set_Flux_Coords(EMCState *state) {
+ _vm->getFlux()->stopWalk();
+ _vm->getFlux()->setPosition(stackPos(0), stackPos(1));
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Set_Flux_Visible(EMCState *state) {
+ _vm->getFlux()->setVisible(stackPos(0) > 0);
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Get_Flux_X(EMCState *state) {
+ return _vm->getFlux()->getX();
+}
+
+int32 ScriptFunc::sys_Cmd_Get_Flux_Y(EMCState *state) {
+ return _vm->getFlux()->getY();
+}
+
+int32 ScriptFunc::sys_Cmd_Get_Flux_Facing(EMCState *state) {
+ return _vm->getFlux()->getFacing();
+}
+
+int32 ScriptFunc::sys_Cmd_Get_Flux_Flags(EMCState *state) {
+ return (_vm->getFlux()->getFlag() & stackPos(0)) != 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Query_Flux_Coords(EMCState *state) {
+ return (stackPos(0) == _vm->getFlux()->getX()) && (stackPos(1) == _vm->getFlux()->getY());
+}
+
+int32 ScriptFunc::sys_Cmd_Have_A_Conversation(EMCState *state) {
+ _vm->haveAConversation(stackPos(0));
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Walk_Flux_To_Point(EMCState *state) {
+ _vm->getFlux()->walkTo(stackPos(0), stackPos(1));
+ return 1;
+}
+
+int32 ScriptFunc::sys_Cmd_Query_Scene_Anim_Loaded(EMCState *state) {
+ return _vm->getSceneAnimation(stackPos(0))->_active;
+}
+
+int32 ScriptFunc::sys_Cmd_Play_Flux_Anim(EMCState *state) {
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Set_Anim_Priority(EMCState *state) {
+
+ SceneAnimation *sceneAnim = _vm->getSceneAnimation(stackPos(0));
+ sceneAnim->_animInstance->setLayerZ(stackPos(1));
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Place_Scene_Anim(EMCState *state) {
+ int32 sceneId = stackPos(0);
+ int32 x = stackPos(1);
+ int32 y = stackPos(2);
+ int32 frame = stackPos(5);
+
+ SceneAnimation *sceneAnim = _vm->getSceneAnimation(sceneId);
+ sceneAnim->_animInstance->setPosition(x, y, sceneAnim->_animInstance->getZ(), false);
+ sceneAnim->_animInstance->forceFrame(frame);
+ _vm->setSceneAnimationScriptUpdate(false);
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Update_Scene_Animations(EMCState *state) {
+ //debugC(0, 0xfff, "UpdateAnimations");
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Get_Drew_Scale(EMCState *state) {
+ int32 scale = _vm->getDrew()->getScale();
+ if (!scale)
+ return 1024;
+ return scale;
+}
+
+int32 ScriptFunc::sys_Cmd_Query_Drew_Flags(EMCState *state) {
+ return (_vm->getDrew()->getFlag() & stackPos(0)) != 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Set_Music(EMCState *state) {
+
+ char *newMus = GetText(0, state);
+ _vm->getAudioManager()->playMusic(_vm->state()->_locations[_vm->state()->_currentScene]._name, newMus);
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Query_Speech(EMCState *state) {
+ if (_vm->getAudioManager()->voiceStillPlaying())
+ return 1;
+ else
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Enter_New_Scene(EMCState *state) {
+ _vm->exitScene();
+ _vm->getDrew()->setFacing(stackPos(1));
+ _vm->loadScene(stackPos(0));
+ _vm->setSceneAnimationScriptUpdate(false);
+
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Enter_Same_Scene(EMCState *state) {
+ _vm->exitScene();
+ _vm->loadScene(_vm->state()->_currentScene);
+ _vm->setSceneAnimationScriptUpdate(false);
+
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Is_Pixel_Walkable(EMCState *state) {
+ return (_vm->getMask()->getData(stackPos(0), stackPos(1)) & 0x1f) > 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Show_Screen(EMCState *state) {
+ _vm->showCutaway(GetText(0, state));
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Hide_Screen(EMCState *state) {
+ _vm->hideCutaway();
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Set_Special_Enter_X_And_Y(EMCState *state) {
+ _vm->state()->_nextSpecialEnterX = stackPos(0);
+ _vm->state()->_nextSpecialEnterY = stackPos(1);
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Get_Mouse_X(EMCState *state) {
+ return _vm->getMouseX();
+}
+
+int32 ScriptFunc::sys_Cmd_Get_Mouse_Y(EMCState *state) {
+ return _vm->getMouseY();
+}
+
+int32 ScriptFunc::sys_Cmd_Fade_Palette(EMCState *state) {
+ debugC(0, 0xfff, "fadePalette %d %d", stackPos(0), stackPos(1));
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Music_Enabled(EMCState *state) {
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Random(EMCState *state) {
+ int32 randMin = stackPos(0);
+ int32 randMax = stackPos(1);
+ int32 t = 0;
+
+ if (randMin > randMax) {
+ t = randMin;
+ randMin = randMax;
+ randMax = t;
+ }
+ return _vm->randRange(randMin, randMax);
+}
+
+int32 ScriptFunc::sys_Cmd_Wait_Key(EMCState *state) {
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Draw_Scene_Anim_WSA_Frame_To_Back(EMCState *state) {
+ // draw the frame in the backbuffer (picture then)
+
+ int32 animId = stackPos(0);
+ int32 frame = stackPos(1);
+
+ if (frame < 0)
+ return 0;
+
+ SceneAnimation *sceneAnim = _vm->getSceneAnimation(animId);
+
+ if (sceneAnim->_active) {
+ sceneAnim->_animInstance->setFrame(frame);
+ sceneAnim->_animInstance->setAnimationRange(frame, frame);
+ sceneAnim->_animInstance->stopAnimation();
+ sceneAnim->_animInstance->renderOnPicture();
+
+ // we have to store some info for savegame
+ _vm->getSaveBufferStream()->writeSint16BE(1); // 1 = Draw_Scene_Anim_WSA_Frame_To_Back
+ _vm->getSaveBufferStream()->writeSint16BE(frame);
+ _vm->getSaveBufferStream()->writeSint16BE(strlen(sceneAnim->_animInstance->getAnimation()->_name) + 1);
+ _vm->getSaveBufferStream()->write(sceneAnim->_animInstance->getAnimation()->_name, strlen(sceneAnim->_animInstance->getAnimation()->_name) + 1);
+ _vm->getSaveBufferStream()->writeSint16BE(sceneAnim->_animInstance->getX());
+ _vm->getSaveBufferStream()->writeSint16BE(sceneAnim->_animInstance->getY());
+ _vm->getSaveBufferStream()->writeSint16BE(sceneAnim->_animInstance->getZ());
+ _vm->getSaveBufferStream()->writeSint16BE(sceneAnim->_animInstance->getLayerZ());
+
+ }
+ return 1;
+}
+
+int32 ScriptFunc::sys_Cmd_Set_Scene_Anim_Wait(EMCState *state) {
+ int32 sceneId = stackPos(0);
+ int32 waitTicks = stackPos(1);
+ if (waitTicks < 1) waitTicks = 1;
+
+ // WORKAROUND : To fix the timing problem in the Gift-O-Matic
+ // The animation was too fast and the player was unable to click fast enough to get objects
+ // Here we slow down the animation
+ if (_vm->state()->_currentScene == 24) {
+ if (_vm->getCurrentUpdatingSceneAnimation() == 6) {
+ if (waitTicks == 1) {
+ waitTicks = 10;
+ _vm->setSceneAnimationScriptUpdate(false);
+ }
+ }
+ }
+
+ // WORKAROUND : In Wolf place, the animation to move the pot was too fast and the player was unable to
+ // progress into the game.
+ if (_vm->state()->_currentScene == 29) {
+ if (_vm->getCurrentUpdatingSceneAnimation() == 8 || _vm->getCurrentUpdatingSceneAnimation() == 7) {
+ if (waitTicks == 1) {
+ waitTicks = 5;
+ _vm->setSceneAnimationScriptUpdate(false);
+ }
+ }
+ }
+
+ // WORKAROUND : In transformed hangar, everything is too fast..
+ if (_vm->state()->_currentScene == 19) {
+ waitTicks = 10;
+ _vm->setSceneAnimationScriptUpdate(false);
+ }
+
+ // WORKAROUND : Slow down just a little the guards dance animation so that the voices don't cut
+ if (_vm->state()->_currentScene == 2 && (sceneId == 2 || sceneId == 3)) {
+ waitTicks = 7;
+ _vm->setSceneAnimationScriptUpdate(false);
+ }
+
+ waitTicks *= _vm->getTickLength();
+
+ if (sceneId >= 0 && sceneId < 40) {
+ int32 nextTicks = waitTicks + _vm->getSceneAnimationScript(sceneId)->_lastTimer;
+ //debugC(0,0xff, "sw : assigining %d to lasttimer of %d (current tick %d old milli %d) ",nextTicks, sceneId , _vm->getSystem()->getMillis(), _vm->getOldMilli());
+ if (nextTicks < _vm->getOldMilli())
+ _vm->getSceneAnimationScript(sceneId)->_lastTimer = _vm->getOldMilli() + waitTicks;
+ else
+ _vm->getSceneAnimationScript(sceneId)->_lastTimer = nextTicks;
+ }
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Init_Scene_Anim(EMCState *state) {
+ int32 animId = stackPos(0);
+ int32 flags = stackPos(1);
+
+ SceneAnimation *sceneAnim = _vm->getSceneAnimation(animId);
+ if (sceneAnim->_active)
+ return 0;
+
+ sceneAnim->_animation = new Animation(_vm);
+ sceneAnim->_animation->loadAnimation(GetText(12, state));
+ sceneAnim->_animInstance = _vm->getAnimationManager()->createNewInstance(kAnimationScene);
+ sceneAnim->_animInstance->setAnimation(sceneAnim->_animation);
+ sceneAnim->_animInstance->setVisible((flags & 1) != 0);
+ sceneAnim->_animInstance->setAnimationRange(stackPos(11), stackPos(11));
+ sceneAnim->_animInstance->setFrame(stackPos(11));
+
+ _vm->getAnimationManager()->addInstance(sceneAnim->_animInstance);
+
+ debugC(0, 0xfff, "Init Anim %s %d %d %d %d %d %d %d %d %d %d %d %d %d\n", GetText(12, state), stackPos(0), stackPos(1), stackPos(2), stackPos(3),
+ stackPos(4), stackPos(5), stackPos(6), stackPos(7), stackPos(8), stackPos(9), stackPos(10), stackPos(11), stackPos(12));
+
+ int32 dx = stackPos(4);
+ int32 dy = stackPos(5);
+ int32 x = stackPos(2);
+ int32 layerZ = stackPos(3);
+
+ if (dx == -2)
+ sceneAnim->_animInstance->moveRelative(640, 0, 0);
+ else if (dx < 0) {
+ dx = sceneAnim->_animation->_x1;
+ }
+ else if (dx >= 0)
+ sceneAnim->_animInstance->setX(dx);
+
+ if (dy >= 0)
+ sceneAnim->_animInstance->setY(dy);
+ else
+ dy = sceneAnim->_animation->_y1;
+
+ if (flags & 0x20) {
+ sceneAnim->_animInstance->setZ(_vm->getLayerAtPoint(x, layerZ));
+ sceneAnim->_animInstance->setUseMask(true);
+ }
+
+ if (layerZ >= 0) {
+ sceneAnim->_animInstance->setLayerZ(layerZ);
+ } else {
+ dy = dy + sceneAnim->_animation->_y2 - sceneAnim->_animation->_y1 - 1;
+ sceneAnim->_animInstance->setLayerZ(dy);
+ }
+
+ sceneAnim->_animInstance->setId(stackPos(0));
+
+
+ sceneAnim->_active = true;
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Set_Scene_Animation_Active_Flag(EMCState *state) {
+ int32 animId = stackPos(0);
+ int32 activeFlag = stackPos(1);
+
+ SceneAnimation *sceneAnim = _vm->getSceneAnimation(animId);
+
+ if (sceneAnim->_active)
+ sceneAnim->_animInstance->setVisible(activeFlag > 0);
+
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Draw_Scene_Anim_WSA_Frame(EMCState *state) {
+ int32 animId = stackPos(0);
+ int32 frame = stackPos(1);
+
+ if (frame < 0)
+ return 0;
+
+ SceneAnimation *sceneAnim = _vm->getSceneAnimation(animId);
+
+ if (sceneAnim->_active) {
+ sceneAnim->_animInstance->setAnimation(sceneAnim->_animation);
+ sceneAnim->_animInstance->setFrame(frame);
+ sceneAnim->_animInstance->setAnimationRange(frame, frame);
+ sceneAnim->_animInstance->stopAnimation();
+ }
+ _vm->setSceneAnimationScriptUpdate(false);
+
+ // WORKAROUND : Too fast animations...
+ if (_vm->state()->_currentScene == 26 && animId == 22)
+ _vm->pauseSceneAnimationScript(_vm->getCurrentUpdatingSceneAnimation(), 3);
+
+ if (_vm->state()->_currentScene == 14) {
+ if (animId == 3 || animId == 2 || animId == 4)
+ _vm->pauseSceneAnimationScript(_vm->getCurrentUpdatingSceneAnimation(), 2);
+ else if (animId == 20 || animId == 15 || animId == 21 || animId == 16 || animId == 17 || animId == 18)
+ _vm->pauseSceneAnimationScript(_vm->getCurrentUpdatingSceneAnimation(), 1);
+ else if (animId == 9) {
+ _vm->pauseSceneAnimationScript(_vm->getCurrentUpdatingSceneAnimation(), 6);
+ }
+ }
+
+ if (_vm->state()->_currentScene == 29) {
+ if (animId == 16 || animId == 26 || animId == 36)
+ _vm->pauseSceneAnimationScript(_vm->getCurrentUpdatingSceneAnimation(), 2);
+ }
+
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Move_Scene_Anim(EMCState *state) {
+ int32 animId = stackPos(0);
+
+ SceneAnimation *sceneAnim = _vm->getSceneAnimation(animId);
+ sceneAnim->_animInstance->moveRelative(stackPos(1), stackPos(2), 0);
+ _vm->setSceneAnimationScriptUpdate(false);
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Run_Actor_Default_Script(EMCState *state) {
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Set_Location_Data(EMCState *state) {
+ // initial setup of locations
+ int32 locationId = stackPos(0);
+ debugC(0, 0, "setlocationdata(%d) %s %x %s %s %d %d", locationId, GetText(1, state), stackPos(2), GetText(3, state), GetText(4, state), stackPos(5), stackPos(6));
+ strcpy(_vm->state()->_locations[locationId]._name, GetText(1, state));
+ strcpy(_vm->state()->_locations[locationId]._music, GetText(3, state));
+ strcpy(_vm->state()->_locations[locationId]._cutaway, GetText(4, state));
+ _vm->state()->_locations[locationId]._flags = stackPos(2);
+ _vm->state()->_locations[locationId]._visited = false;
+ _vm->state()->_locations[locationId]._numSceneAnimations = stackPos(5);
+
+ return 0;
+
+}
+
+int32 ScriptFunc::sys_Cmd_Set_CountDown_Timer(EMCState *state) {
+ // game timer is in ticks
+ _vm->state()->_gameTimer = stackPos(0) * _vm->getTickLength();
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Query_CountDown_Timer(EMCState *state) {
+ return _vm->state()->_gameTimer;
+}
+
+int32 ScriptFunc::sys_Cmd_Proceed_To_Next_Chapter(EMCState *state) {
+
+ _vm->state()->_currentChapter = stackPos(0);
+ _vm->exitScene();
+ _vm->loadScene(stackPos(1));
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Play_Sfx_Plus(EMCState *state) {
+ //debugC(0,0xfff, "playSfx ( %d , %d, %d, %d, %d )", stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4));
+ _vm->playSFX(stackPos(0), stackPos(1));
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Play_Sfx(EMCState *state) {
+ //debugC(0,0xfff, "playSfx ( %d , %d)", stackPos(0), stackPos(1));
+ _vm->playSFX(stackPos(0), stackPos(1));
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Set_Ambient_Sfx(EMCState *state) {
+ //printf("Ambient Sfx : %d %d %d %d\n", stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+ _vm->getAudioManager()->startAmbientSFX(stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Kill_Ambient_Sfx(EMCState *state) {
+ //printf("Kill Sfx : %d \n", stackPos(0));
+ _vm->getAudioManager()->killAmbientSFX(stackPos(0));
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Set_Ambient_Sfx_Plus(EMCState *state) {
+ //printf("Ambient Sfx Plus: %d %d %d %d %d %d %d %d\n", stackPos(0), stackPos(1), stackPos(2), stackPos(3), stackPos(4), stackPos(5), stackPos(6), stackPos(7));
+ _vm->getAudioManager()->startAmbientSFX(stackPos(0), stackPos(1), stackPos(2), stackPos(3));
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Set_Ambient_Volume(EMCState *state) {
+ //printf("Ambient Volume : %d %d \n", stackPos(0), stackPos(1));
+ _vm->getAudioManager()->setAmbientSFXVolume(stackPos(0), stackPos(1));
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Freeze_Scene_Animation(EMCState *state) {
+
+ _vm->getSceneAnimationScript(stackPos(0))->_frozen = true;
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Unfreeze_Scene_Animation(EMCState *state) {
+ _vm->getSceneAnimationScript(stackPos(0))->_frozen = false;
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Scene_Animation_Frozen(EMCState *state) {
+ return _vm->getSceneAnimationScript(stackPos(0))->_frozen ? 1 : 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Set_Script_Game_Data_Global(EMCState *state) {
+ _vm->state()->_gameGlobalData[stackPos(0)] = stackPos(1);
+ return stackPos(1);
+}
+
+int32 ScriptFunc::sys_Cmd_Get_Script_Game_Data_Global(EMCState *state) {
+ return _vm->state()->_gameGlobalData[stackPos(0)];
+}
+
+int32 ScriptFunc::sys_Cmd_Say_Line(EMCState *state) {
+ _vm->sayLines(1 , stackPos(0));
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Knight_Puzzle_Get_Coord(EMCState *state) {
+ static const uint16 knightCoords[] = {
+ 0x327, 0x0fa, 0x354, 0x0f8, 0x383, 0x0f4, 0x3a4, 0x0f0, 0x3d3, 0x0ed,
+ 0x3fd, 0x0ef, 0x2fe, 0x12d, 0x2fe, 0x12d, 0x310, 0x109, 0x349, 0x103,
+ 0x378, 0x103, 0x3a4, 0x102, 0x3d5, 0x102, 0x403, 0x103, 0x2fe, 0x12d,
+ 0x2fe, 0x12d, 0x2fe, 0x12d, 0x2fe, 0x12d, 0x369, 0x123, 0x3a4, 0x123,
+ 0x3d8, 0x121, 0x410, 0x124, 0x2fe, 0x12d, 0x2fe, 0x12d, 0x2fe, 0x12d,
+ 0x2fe, 0x12d, 0x35d, 0x14f, 0x3a2, 0x149, 0x3db, 0x149, 0x415, 0x14a,
+ 0x2fe, 0x12d, 0x2fe, 0x12d
+ };
+
+ return knightCoords[stackPos(2) + 2 * (8 * stackPos(1) + stackPos(0))];
+}
+
+int32 ScriptFunc::sys_Cmd_Add_Scene_Anim(EMCState *state) {
+ return sys_Cmd_Init_Scene_Anim(state);
+}
+
+int32 ScriptFunc::sys_Cmd_Remove_Scene_Anim(EMCState *state) {
+ int32 sceneId = stackPos(0);
+
+ if (!_vm->getSceneAnimation(sceneId)->_active)
+ return 0;
+
+ SceneAnimation *sceneAnim = _vm->getSceneAnimation(sceneId);
+ sceneAnim->_active = false;
+ _vm->getAnimationManager()->removeInstance(sceneAnim->_animInstance);
+ sceneAnim->_animation = 0;
+ sceneAnim->_animInstance = 0;
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Disable_Timer(EMCState *state) {
+ _vm->disableTimer(stackPos(0));
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Enable_Timer(EMCState *state) {
+ _vm->enableTimer(stackPos(0));
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Set_Timer(EMCState *state) {
+ _vm->setTimer(stackPos(0), stackPos(1));
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Set_Palette_Color(EMCState *state) {
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Number_Of_NPCs(EMCState *state) {
+ return 0;
+}
+
+int32 ScriptFunc::sys_Cmd_Get_Config_Language(EMCState *state) {
+ return 0;
+}
+
+} // End of namespace Toon
diff --git a/engines/toon/script_func.h b/engines/toon/script_func.h
new file mode 100644
index 0000000000..76b7b0ada1
--- /dev/null
+++ b/engines/toon/script_func.h
@@ -0,0 +1,174 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* $URL$
+* $Id$
+*
+*/
+
+#ifndef SCRIPT_FUNC_H
+#define SCRIPT_FUNC_H
+
+#include "common/array.h"
+#include "toon/script.h"
+
+namespace Toon {
+
+class ScriptFunc;
+
+typedef Common::Functor1Mem<EMCState *, int32, ScriptFunc> OpcodeV2;
+
+class ScriptFunc {
+public:
+ ScriptFunc(ToonEngine *vm);
+ ~ScriptFunc(void);
+ Common::Array<const OpcodeV2 *> _opcodes;
+ ToonEngine *_vm;
+
+#define SYSFUNC(x) int32 x(EMCState*)
+ SYSFUNC(sys_Cmd_Dummy);
+ SYSFUNC(sys_Cmd_Change_Actor_X_And_Y);
+ SYSFUNC(sys_Cmd_Init_Talking_Character);
+ SYSFUNC(sys_Cmd_Draw_Actor_Standing);
+ SYSFUNC(sys_Cmd_Get_Actor_X);
+ SYSFUNC(sys_Cmd_Get_Actor_Y);
+ SYSFUNC(sys_Cmd_Get_Actor_Facing);
+ SYSFUNC(sys_Cmd_Get_Last_Scene);
+ SYSFUNC(sys_Cmd_Debug_Print);
+ SYSFUNC(sys_Cmd_Flip_Screens);
+ SYSFUNC(sys_Cmd_Play_Flic);
+ SYSFUNC(sys_Cmd_Force_Facing);
+ SYSFUNC(sys_Cmd_Restart_Thread);
+ SYSFUNC(sys_Cmd_Walk_Actor_To_Point);
+ SYSFUNC(sys_Cmd_Set_Sack_Visible);
+ SYSFUNC(sys_Cmd_Set_Actor_Facing);
+ SYSFUNC(sys_Cmd_Confiscate_Inventory);
+ SYSFUNC(sys_Cmd_Character_Talks);
+ SYSFUNC(sys_Cmd_Visited_Scene);
+ SYSFUNC(sys_Cmd_Query_Rif_Flag);
+ SYSFUNC(sys_Cmd_Query_Scroll);
+ SYSFUNC(sys_Cmd_Set_Initial_Location);
+ SYSFUNC(sys_Cmd_Make_Line_Non_Walkable);
+ SYSFUNC(sys_Cmd_Make_Line_Walkable);
+ SYSFUNC(sys_Cmd_Walk_Actor_On_Condition);
+ SYSFUNC(sys_Cmd_Set_Actor_Facing_Point);
+ SYSFUNC(sys_Cmd_Set_Inventory_Slot);
+ SYSFUNC(sys_Cmd_Get_Inventory_Slot);
+ SYSFUNC(sys_Cmd_Add_Item_To_Inventory);
+ SYSFUNC(sys_Cmd_Set_Actor_RGB_Modifiers);
+ SYSFUNC(sys_Cmd_Init_Conversation_AP);
+ SYSFUNC(sys_Cmd_Actor_Talks);
+ SYSFUNC(sys_Cmd_Say_Lines);
+ SYSFUNC(sys_Cmd_Set_Rif_Flag);
+ SYSFUNC(sys_Cmd_Empty_Inventory);
+ SYSFUNC(sys_Cmd_Set_Anim_Scale_Size);
+ SYSFUNC(sys_Cmd_Delete_Item_From_Inventory);
+ SYSFUNC(sys_Cmd_Specific_Item_In_Inventory);
+ SYSFUNC(sys_Cmd_Run_Script);
+ SYSFUNC(sys_Cmd_Query_Game_Flag);
+ SYSFUNC(sys_Cmd_Reset_Game_Flag);
+ SYSFUNC(sys_Cmd_Set_Game_Flag);
+ SYSFUNC(sys_Cmd_Create_Mouse_Item);
+ SYSFUNC(sys_Cmd_Destroy_Mouse_Item);
+ SYSFUNC(sys_Cmd_Get_Mouse_State);
+ SYSFUNC(sys_Cmd_Hide_Mouse);
+ SYSFUNC(sys_Cmd_Exit_Conversation);
+ SYSFUNC(sys_Cmd_Set_Mouse_Pos);
+ SYSFUNC(sys_Cmd_Show_Mouse);
+ SYSFUNC(sys_Cmd_In_Close_Up);
+ SYSFUNC(sys_Cmd_Set_Scroll_Lock);
+ SYSFUNC(sys_Cmd_Fill_Area_Non_Walkable);
+ SYSFUNC(sys_Cmd_Set_Scroll_Coords);
+ SYSFUNC(sys_Cmd_Hide_Cutaway);
+ SYSFUNC(sys_Cmd_Show_Cutaway);
+ SYSFUNC(sys_Cmd_Pause_Ticks);
+ SYSFUNC(sys_Cmd_In_Conversation);
+ SYSFUNC(sys_Cmd_Character_Talking);
+ SYSFUNC(sys_Cmd_Set_Flux_Facing_Point);
+ SYSFUNC(sys_Cmd_Set_Flux_Facing);
+ SYSFUNC(sys_Cmd_Set_Flux_Coords);
+ SYSFUNC(sys_Cmd_Set_Flux_Visible);
+ SYSFUNC(sys_Cmd_Get_Flux_X);
+ SYSFUNC(sys_Cmd_Get_Flux_Y);
+ SYSFUNC(sys_Cmd_Get_Flux_Facing);
+ SYSFUNC(sys_Cmd_Get_Flux_Flags);
+ SYSFUNC(sys_Cmd_Query_Flux_Coords);
+ SYSFUNC(sys_Cmd_Have_A_Conversation);
+ SYSFUNC(sys_Cmd_Walk_Flux_To_Point);
+ SYSFUNC(sys_Cmd_Query_Scene_Anim_Loaded);
+ SYSFUNC(sys_Cmd_Play_Flux_Anim);
+ SYSFUNC(sys_Cmd_Set_Anim_Priority);
+ SYSFUNC(sys_Cmd_Place_Scene_Anim);
+ SYSFUNC(sys_Cmd_Update_Scene_Animations);
+ SYSFUNC(sys_Cmd_Get_Drew_Scale);
+ SYSFUNC(sys_Cmd_Query_Drew_Flags);
+ SYSFUNC(sys_Cmd_Set_Music);
+ SYSFUNC(sys_Cmd_Query_Speech);
+ SYSFUNC(sys_Cmd_Enter_New_Scene);
+ SYSFUNC(sys_Cmd_Enter_Same_Scene);
+ SYSFUNC(sys_Cmd_Is_Pixel_Walkable);
+ SYSFUNC(sys_Cmd_Show_Screen);
+ SYSFUNC(sys_Cmd_Hide_Screen);
+ SYSFUNC(sys_Cmd_Set_Special_Enter_X_And_Y);
+ SYSFUNC(sys_Cmd_Get_Mouse_X);
+ SYSFUNC(sys_Cmd_Get_Mouse_Y);
+ SYSFUNC(sys_Cmd_Fade_Palette);
+ SYSFUNC(sys_Cmd_Music_Enabled);
+ SYSFUNC(sys_Cmd_Random);
+ SYSFUNC(sys_Cmd_Wait_Key);
+ SYSFUNC(sys_Cmd_Draw_Scene_Anim_WSA_Frame_To_Back);
+ SYSFUNC(sys_Cmd_Set_Scene_Anim_Wait);
+ SYSFUNC(sys_Cmd_Init_Scene_Anim);
+ SYSFUNC(sys_Cmd_Set_Scene_Animation_Active_Flag);
+ SYSFUNC(sys_Cmd_Draw_Scene_Anim_WSA_Frame);
+ SYSFUNC(sys_Cmd_Move_Scene_Anim);
+ SYSFUNC(sys_Cmd_Run_Actor_Default_Script);
+ SYSFUNC(sys_Cmd_Set_Location_Data);
+ SYSFUNC(sys_Cmd_Set_CountDown_Timer);
+ SYSFUNC(sys_Cmd_Query_CountDown_Timer);
+ SYSFUNC(sys_Cmd_Proceed_To_Next_Chapter);
+ SYSFUNC(sys_Cmd_Play_Sfx_Plus);
+ SYSFUNC(sys_Cmd_Play_Sfx);
+ SYSFUNC(sys_Cmd_Set_Ambient_Sfx);
+ SYSFUNC(sys_Cmd_Kill_Ambient_Sfx);
+ SYSFUNC(sys_Cmd_Set_Ambient_Sfx_Plus);
+ SYSFUNC(sys_Cmd_Set_Ambient_Volume);
+ SYSFUNC(sys_Cmd_Freeze_Scene_Animation);
+ SYSFUNC(sys_Cmd_Unfreeze_Scene_Animation);
+ SYSFUNC(sys_Cmd_Scene_Animation_Frozen);
+ SYSFUNC(sys_Cmd_Set_Script_Game_Data_Global);
+ SYSFUNC(sys_Cmd_Get_Script_Game_Data_Global);
+ SYSFUNC(sys_Cmd_Say_Line);
+ SYSFUNC(sys_Cmd_Knight_Puzzle_Get_Coord);
+ SYSFUNC(sys_Cmd_Add_Scene_Anim);
+ SYSFUNC(sys_Cmd_Remove_Scene_Anim);
+ SYSFUNC(sys_Cmd_Disable_Timer);
+ SYSFUNC(sys_Cmd_Enable_Timer);
+ SYSFUNC(sys_Cmd_Set_Timer);
+ SYSFUNC(sys_Cmd_Set_Palette_Color);
+ SYSFUNC(sys_Cmd_Number_Of_NPCs);
+ SYSFUNC(sys_Cmd_Get_Config_Language);
+ SYSFUNC(sys_Cmd_Get_Actor_Final_X);
+ SYSFUNC(sys_Cmd_Get_Actor_Final_Y);
+};
+
+} // End of namespace Toon
+
+#endif
diff --git a/engines/toon/state.cpp b/engines/toon/state.cpp
new file mode 100644
index 0000000000..71674688d5
--- /dev/null
+++ b/engines/toon/state.cpp
@@ -0,0 +1,261 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* $URL$
+* $Id$
+*
+*/
+
+#include "toon/state.h"
+#include "toon/toon.h"
+
+namespace Toon {
+
+void Location::save(Common::WriteStream *stream) {
+ stream->write(_cutaway, 64);
+ stream->write(_music, 64);
+ stream->write(_name, 64);
+ stream->writeSint16BE(_numRifBoxes);
+ stream->writeSint16BE(_numSceneAnimations);
+ stream->writeSByte(_visited);
+
+ for (int32 i = 0; i < _numRifBoxes * 2; i++) {
+ stream->writeSint16BE(_rifBoxesFlags[i]);
+ }
+}
+void Location::load(Common::ReadStream *stream) {
+ stream->read(_cutaway, 64);
+ stream->read(_music, 64);
+ stream->read(_name, 64);
+ _numRifBoxes = stream->readSint16BE();
+ _numSceneAnimations = stream->readSint16BE();
+ _visited = stream->readSByte();
+
+ for (int32 i = 0; i < _numRifBoxes * 2; i++) {
+ _rifBoxesFlags[i] = stream->readSint16BE();
+ }
+}
+
+State::State(void) {
+ for (int32 i = 0; i < 64; i++) {
+ _locations[i]._visited = false;
+ _locations[i]._numSceneAnimations = 0;
+ _locations[i]._numRifBoxes = 0;
+ }
+
+ memset(_gameFlag, 0, sizeof(_gameFlag));
+ memset(_gameGlobalData, -1, sizeof(_gameGlobalData));
+
+ for (int32 i = 0; i < 2; i++) {
+ _timerEnabled[i] = false;
+ _timerTimeout[i] = 0;
+ _timerDelay[i] = -1;
+ }
+
+ _lastVisitedScene = -1;
+ _currentScene = -1;
+
+ _currentScrollLock = false;
+ _currentScrollValue = 0;
+
+ _gameTimer = 0;
+ _currentChapter = 1;
+
+ _showConversationIcons = false;
+
+ _inCloseUp = false;
+ _inConversation = false;
+
+ _mouseState = -1;
+ _mouseHidden = false;
+
+ _firstConverstationLine = false;
+
+ _sackVisible = false; // to change
+ _inCutaway = false;
+
+ _inInventory = false;
+ _numInventoryItems = 0; //To chhange
+ _numConfiscatedInventoryItems = 0;
+
+ _nextSpecialEnterX = -1;
+ _nextSpecialEnterY = -1;
+
+#if 0
+ for (int i = 0; i < 30; i++) {
+ _inventory[i] = 90 + i;
+ if (_inventory[i] == 41)
+ _inventory[i] = 42;
+ }
+
+ _inventory[0] = 53;
+ _inventory[1] = 22;
+ _inventory[2] = 93;
+ _inventory[3] = 49;
+ _inventory[4] = 47;
+ _inventory[5] = 14;
+ _numInventoryItems = 6; //To change
+#endif
+
+ memset(_conversationState, 0, sizeof(Conversation) * 60);
+}
+
+State::~State(void) {
+
+}
+
+int32 State::getGameFlag(int32 flagId) {
+ return (_gameFlag[flagId >> 3] & (1 << (flagId & 7))) != 0;
+}
+
+bool State::hasItemInInventory(int32 item) {
+ debugC(1, kDebugState, "hasItemInInventory(%d)", item);
+
+ for (int32 i = 0; i < _numInventoryItems; i++) {
+ if (_inventory[i] == item)
+ return true;
+ }
+ return false;
+}
+
+void State::save(Common::WriteStream *stream) {
+
+ for (int32 i = 0; i < 256; i++) {
+ _locations[i].save(stream);
+ }
+
+ for (int32 i = 0; i < 256; i++) {
+ stream->writeSint16BE(_gameGlobalData[i]);
+ }
+
+ for (int32 i = 0; i < 256; i++) {
+ stream->writeSint16BE(_gameFlag[i]);
+ }
+
+ stream->writeSint16BE(_lastVisitedScene);
+ stream->writeSint16BE(_currentScene);
+ stream->writeSint16BE(_currentScrollValue);
+ stream->writeSByte(_currentScrollLock);
+
+ for (int32 i = 0; i < 35; i++) {
+ stream->writeSint16BE(_inventory[i]);
+ }
+
+ for (int32 i = 0; i < 35; i++) {
+ stream->writeSint16BE(_confiscatedInventory[i]);
+ }
+
+ stream->writeSint32BE(_numInventoryItems);
+ stream->writeSint32BE(_numConfiscatedInventoryItems);
+
+ stream->writeSByte(_inCloseUp);
+ stream->writeSByte(_inCutaway);
+ stream->writeSByte(_inConversation);
+ stream->writeSByte(_inInventory);
+ stream->writeSByte(_showConversationIcons);
+
+ stream->writeSint16BE(_mouseState);
+
+ stream->writeSint16BE(_currentConversationId);
+ stream->writeSByte(_firstConverstationLine);
+ stream->writeSByte(_exitConversation);
+ stream->writeSByte(_mouseHidden);
+ stream->writeSByte(_sackVisible);
+ stream->writeSint32BE(_gameTimer);
+ stream->writeSByte(_currentChapter);
+
+ stream->writeByte(_timerEnabled[0]);
+ stream->writeByte(_timerEnabled[1]);
+
+ stream->writeSint32BE(_timerTimeout[0]);
+ stream->writeSint32BE(_timerTimeout[1]);
+
+ stream->writeSint32BE(_timerDelay[0]);
+ stream->writeSint32BE(_timerDelay[1]);
+}
+
+void State::load(Common::ReadStream *stream) {
+ for (int32 i = 0; i < 256; i++) {
+ _locations[i].load(stream);
+ }
+
+ for (int32 i = 0; i < 256; i++) {
+ _gameGlobalData[i] = stream->readSint16BE();
+ }
+
+ for (int32 i = 0; i < 256; i++) {
+ _gameFlag[i] = stream->readSint16BE();
+ }
+
+ _lastVisitedScene = stream->readSint16BE();
+ _currentScene = stream->readSint16BE();
+ _currentScrollValue = stream->readSint16BE();
+ _currentScrollLock = stream->readSByte();
+
+ for (int32 i = 0; i < 35; i++) {
+ _inventory[i] = stream->readSint16BE();
+ }
+
+ for (int32 i = 0; i < 35; i++) {
+ _confiscatedInventory[i] = stream->readSint16BE();
+ }
+
+ _numInventoryItems = stream->readSint32BE();
+ _numConfiscatedInventoryItems = stream->readSint32BE();
+
+ _inCloseUp = stream->readSByte();
+ _inCutaway = stream->readSByte();
+ _inConversation = stream->readSByte();
+ _inInventory = stream->readSByte();
+ _showConversationIcons = stream->readSByte();
+
+ _mouseState = stream->readSint16BE();
+
+ _currentConversationId = stream->readSint16BE();
+ _firstConverstationLine = stream->readSByte();
+ _exitConversation = stream->readSByte();
+ _mouseHidden = stream->readSByte();
+ _sackVisible = stream->readSByte();
+ _gameTimer = stream->readSint32BE();
+ _currentChapter = stream->readSByte();
+
+ _timerEnabled[0] = stream->readByte();
+ _timerEnabled[1] = stream->readByte();
+
+ _timerTimeout[0] = stream->readSint32BE();
+ _timerTimeout[1] = stream->readSint32BE();
+
+ _timerDelay[0] = stream->readSint32BE();
+ _timerDelay[1] = stream->readSint32BE();
+}
+
+void State::loadConversations(Common::ReadStream *stream) {
+ for (int32 i = 0; i < 60; i++) {
+ _conversationState[i].load(stream, _conversationData);
+ }
+}
+
+void State::saveConversations(Common::WriteStream *stream) {
+ for (int32 i = 0; i < 60; i++) {
+ _conversationState[i].save(stream, _conversationData);
+ }
+}
+
+} // End of namespace Toon
diff --git a/engines/toon/state.h b/engines/toon/state.h
new file mode 100644
index 0000000000..283e378443
--- /dev/null
+++ b/engines/toon/state.h
@@ -0,0 +1,101 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* $URL$
+* $Id$
+*
+*/
+
+#ifndef TOON_STATE_H
+#define TOON_STATE_H
+
+#include "common/file.h"
+#include "common/str.h"
+#include "toon/conversation.h"
+
+namespace Toon {
+
+struct Location {
+ char _name[64];
+ char _music[64];
+ char _cutaway[64];
+ bool _visited;
+ int32 _numSceneAnimations;
+ int32 _flags;
+ int32 _numRifBoxes;
+ int16 _rifBoxesFlags[256];
+
+ void save(Common::WriteStream *stream);
+ void load(Common::ReadStream *stream);
+};
+
+class State {
+public:
+ State(void);
+ ~State(void);
+
+ Location _locations[256];
+ int16 _gameGlobalData[256];
+ uint8 _gameFlag[256];
+ int16 _lastVisitedScene;
+ int16 _currentScene;
+ int16 _currentScrollValue;
+ bool _currentScrollLock;
+ int16 _inventory[35];
+ int16 _confiscatedInventory[35];
+ int32 _numInventoryItems;
+ int32 _numConfiscatedInventoryItems;
+ bool _inCloseUp;
+ bool _inCutaway;
+ bool _inConversation;
+ bool _inInventory;
+ bool _showConversationIcons;
+ int16 _mouseState;
+ int16 *_conversationData;
+ Conversation _conversationState[60];
+ int16 _currentConversationId;
+ bool _firstConverstationLine;
+ bool _exitConversation;
+ bool _mouseHidden;
+ bool _sackVisible;
+ int32 _gameTimer;
+ int8 _currentChapter;
+ int32 _nextSpecialEnterX;
+ int32 _nextSpecialEnterY;
+
+
+ bool _timerEnabled[2];
+ int32 _timerTimeout[2];
+ int32 _timerDelay[2];
+
+ int32 getGameFlag(int32 flagId);
+ bool hasItemInInventory(int32 item);
+
+ void load(Common::ReadStream *stream);
+ void save(Common::WriteStream *stream);
+
+ void loadConversations(Common::ReadStream *stream);
+ void saveConversations(Common::WriteStream *stream);
+
+};
+
+} // End of namespace Toon
+
+#endif
diff --git a/engines/toon/text.cpp b/engines/toon/text.cpp
new file mode 100644
index 0000000000..c18e0cbdc8
--- /dev/null
+++ b/engines/toon/text.cpp
@@ -0,0 +1,95 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* $URL$
+* $Id$
+*
+*/
+
+#include "toon/text.h"
+
+namespace Toon {
+
+
+TextResource::TextResource(ToonEngine *vm) : _vm(vm) {
+ _numTexts = 0;
+ _textData = 0;
+}
+
+TextResource::~TextResource(void) {
+
+}
+
+bool TextResource::loadTextResource(Common::String fileName) {
+ debugC(1, kDebugText, "loadTextResource(%s)", fileName.c_str());
+
+ uint32 fileSize = 0;
+ uint8 *data = _vm->resources()->getFileData(fileName, &fileSize);
+ if (!data)
+ return false;
+
+ _textData = new uint8[fileSize];
+ memcpy(_textData, data, fileSize);
+ _numTexts = READ_LE_UINT16(data);
+
+ return true;
+}
+
+int32 TextResource::getNext(int32 offset) {
+ debugC(1, kDebugText, "getNext(%d)", offset);
+
+ uint16 *table = (uint16 *)_textData + 1;
+ int a = getId(offset);
+ return table[a+1];
+}
+
+int32 TextResource::getId(int32 offset) {
+ debugC(1, kDebugText, "getId(%d)", offset);
+
+ uint16 *table = (uint16 *)_textData + 1;
+ int32 found = -1;
+ for (int32 i = 0; i < _numTexts; i++) {
+ if (offset == table[i]) {
+ found = i;
+ break;
+ }
+ }
+ return found;
+}
+
+char *TextResource::getText(int32 offset) {
+ debugC(6, kDebugText, "getText(%d)", offset);
+
+ uint16 *table = (uint16 *)_textData + 1;
+ int32 found = -1;
+ for (int32 i = 0; i < _numTexts; i++) {
+ if (offset == table[i]) {
+ found = i;
+ break;
+ }
+ }
+ if (found < 0)
+ return NULL;
+
+ int32 realOffset = ((uint16 *)_textData + 1 + _numTexts)[found];
+ return (char *)_textData + realOffset;
+}
+
+} // End of namespace Toon
diff --git a/engines/toon/text.h b/engines/toon/text.h
new file mode 100644
index 0000000000..9a35471e4f
--- /dev/null
+++ b/engines/toon/text.h
@@ -0,0 +1,51 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* $URL$
+* $Id$
+*
+*/
+
+#ifndef TOON_TEXT_H
+#define TOON_TEXT_H
+
+#include "toon/toon.h"
+
+namespace Toon {
+
+class TextResource {
+public:
+ TextResource(ToonEngine *vm);
+ ~TextResource(void);
+
+ bool loadTextResource(Common::String fileName);
+ char *getText(int32 id);
+ int32 getId(int32 offset);
+ int32 getNext(int32 offset);
+
+protected:
+ int32 _numTexts;
+ uint8 *_textData;
+ ToonEngine *_vm;
+};
+
+} // End of namespace Toon
+
+#endif
diff --git a/engines/toon/tools.cpp b/engines/toon/tools.cpp
new file mode 100644
index 0000000000..a03a2d57ce
--- /dev/null
+++ b/engines/toon/tools.cpp
@@ -0,0 +1,516 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* $URL$
+* $Id$
+*
+*/
+
+#include "toon/tools.h"
+#include "toon/toon.h"
+
+namespace Toon {
+
+uint32 decompressLZSS(byte *src, byte *dst, int dstsize) {
+ debugC(5, kDebugTools, "decompressLZSS(src, dst, %d)", dstsize);
+
+ byte *srcp = src;
+ byte *dstp = dst;
+ uint16 bitbuf;
+ int32 len, ofs;
+ len = 0;
+ while (dstsize > 0) {
+ bitbuf = 0x100 | *(srcp++);
+ while (bitbuf != 1 && dstsize > 0) {
+ if (bitbuf & 1) {
+ ofs = READ_LE_UINT16(srcp);
+ srcp += 2;
+ len = ((ofs & 0xF000) >> 12) + 3;
+ ofs = ofs | 0xF000;
+ dstsize -= len;
+ if (dstsize < 0)
+ break;
+ while (len--) {
+ *dstp = *(byte *)(dstp + (signed short)ofs);
+ dstp++;
+ }
+ } else {
+ len = 0;
+ while ((bitbuf & 2) == 0) {
+ len++;
+ bitbuf >>= 1;
+ }
+ len++;
+ dstsize -= len;
+ if (dstsize < 0)
+ break;
+ while (len--)
+ *(dstp++) = *(srcp++);
+ }
+ bitbuf >>= 1;
+ }
+ }
+ len += dstsize;
+ if (len < 0)
+ return 0;
+
+ while (len--)
+ *(dstp++) = *(srcp++);
+
+ return (dstp - dst);
+}
+
+uint32 decompressSPCN(byte *src, byte *dst, uint32 dstsize) {
+ debugC(1, kDebugTools, "decompressSPCN(src, dst, %d)", dstsize);
+
+ byte *srcp = src;
+ byte *dstp = dst, *dste = dst + dstsize;
+ byte val;
+ uint16 len, ofs;
+ if (!(*srcp & 0x80)) srcp++;
+ while (dstp < dste) {
+ val = *(srcp++);
+ if (val & 0x80) {
+ if (val & 0x40) {
+ if (val == 0xFE) {
+ len = READ_LE_UINT16(srcp);
+ while (len--)
+ *(dstp++) = srcp[2];
+ srcp += 3;
+ } else {
+ if (val == 0xFF) {
+ len = READ_LE_UINT16(srcp);
+ srcp += 2;
+ } else {
+ len = (val & 0x3F) + 3;
+ }
+ ofs = READ_LE_UINT16(srcp);
+ srcp += 2;
+ while (len--) {
+ *dstp = *(byte *)(dstp - ofs);
+ dstp++;
+ }
+ }
+ } else {
+ len = val & 0x3F;
+ while (len--)
+ *(dstp++) = *(srcp++);
+ }
+ } else {
+ len = (val >> 4) + 3;
+ ofs = ((val & 0x0F) << 8) | *(srcp++);
+ while (len--) {
+ *dstp = *(byte *)(dstp - ofs);
+ dstp++;
+ }
+ }
+ }
+ return (dstp - dst);
+}
+
+
+//return codes
+#define NOT_PACKED 0
+#define PACKED_CRC -1
+#define UNPACKED_CRC -2
+
+//other defines
+#define TABLE_SIZE (16 * 8)
+#define MIN_LENGTH 2
+#define HEADER_LEN 18
+
+RncDecoder::RncDecoder() {
+ initCrc();
+}
+
+RncDecoder::~RncDecoder() { }
+
+void RncDecoder::initCrc() {
+ debugC(1, kDebugTools, "initCrc()");
+
+ uint16 cnt = 0;
+ uint16 tmp1 = 0;
+ uint16 tmp2 = 0;
+
+ for (tmp2 = 0; tmp2 < 0x100; tmp2++) {
+ tmp1 = tmp2;
+ for (cnt = 8; cnt > 0; cnt--) {
+ if (tmp1 % 2) {
+ tmp1 >>= 1;
+ tmp1 ^= 0x0a001;
+ } else
+ tmp1 >>= 1;
+ }
+ _crcTable[tmp2] = tmp1;
+ }
+}
+
+//calculate 16 bit crc of a block of memory
+uint16 RncDecoder::crcBlock(const uint8 *block, uint32 size) {
+ debugC(1, kDebugTools, "crcBlock(block, %d)", size);
+
+ uint16 crc = 0;
+ uint8 *crcTable8 = (uint8 *)_crcTable; //make a uint8* to crc_table
+ uint8 tmp;
+ uint32 i;
+
+ for (i = 0; i < size; i++) {
+ tmp = *block++;
+ crc ^= tmp;
+ tmp = (uint8)((crc >> 8) & 0x00FF);
+ crc &= 0x00FF;
+ crc = *(uint16 *)&crcTable8[crc << 1];
+ crc ^= tmp;
+ }
+
+ return crc;
+}
+
+uint16 RncDecoder::inputBits(uint8 amount) {
+ debugC(5, kDebugTools, "inputBits(%d)", amount);
+
+ uint16 newBitBuffh = _bitBuffh;
+ uint16 newBitBuffl = _bitBuffl;
+ int16 newBitCount = _bitCount;
+ uint16 remBits, returnVal;
+
+ returnVal = ((1 << amount) - 1) & newBitBuffl;
+ newBitCount -= amount;
+
+ if (newBitCount < 0) {
+ newBitCount += amount;
+ remBits = (newBitBuffh << (16 - newBitCount));
+ newBitBuffh >>= newBitCount;
+ newBitBuffl >>= newBitCount;
+ newBitBuffl |= remBits;
+ _srcPtr += 2;
+ newBitBuffh = READ_LE_UINT16(_srcPtr);
+ amount -= newBitCount;
+ newBitCount = 16 - amount;
+ }
+ remBits = (newBitBuffh << (16 - amount));
+ _bitBuffh = newBitBuffh >> amount;
+ _bitBuffl = (newBitBuffl >> amount) | remBits;
+ _bitCount = (uint8)newBitCount;
+
+ return returnVal;
+}
+
+void RncDecoder::makeHufftable(uint16 *table) {
+ debugC(1, kDebugTools, "makeHufftable(table)");
+
+ uint16 bitLength, i, j;
+ uint16 numCodes = inputBits(5);
+
+ if (!numCodes)
+ return;
+
+ uint8 huffLength[16];
+ for (i = 0; i < numCodes; i++)
+ huffLength[i] = (uint8)(inputBits(4) & 0x00FF);
+
+ uint16 huffCode = 0;
+
+ for (bitLength = 1; bitLength < 17; bitLength++) {
+ for (i = 0; i < numCodes; i++) {
+ if (huffLength[i] == bitLength) {
+ *table++ = (1 << bitLength) - 1;
+
+ uint16 b = huffCode >> (16 - bitLength);
+ uint16 a = 0;
+
+ for (j = 0; j < bitLength; j++)
+ a |= ((b >> j) & 1) << (bitLength - j - 1);
+ *table++ = a;
+
+ *(table + 0x1e) = (huffLength[i] << 8) | (i & 0x00FF);
+ huffCode += 1 << (16 - bitLength);
+ }
+ }
+ }
+}
+
+uint16 RncDecoder::inputValue(uint16 *table) {
+ debugC(5, kDebugTools, "inputValue(table)");
+
+ uint16 valOne, valTwo, value = _bitBuffl;
+
+ do {
+ valTwo = (*table++) & value;
+ valOne = *table++;
+ } while (valOne != valTwo);
+
+ value = *(table + 0x1e);
+ inputBits((uint8)((value >> 8) & 0x00FF));
+ value &= 0x00FF;
+
+ if (value >= 2) {
+ value--;
+ valOne = inputBits((uint8)value & 0x00FF);
+ valOne |= (1 << value);
+ value = valOne;
+ }
+
+ return value;
+}
+
+int RncDecoder::getbit() {
+ debugC(6, kDebugTools, "getbits()");
+
+ if (_bitCount == 0) {
+ _bitBuffl = *_srcPtr++;
+ _bitCount = 8;
+ }
+ byte temp = (_bitBuffl & 0x80) >> 7;
+ _bitBuffl <<= 1;
+ _bitCount--;
+ return temp;
+}
+
+int32 RncDecoder::unpackM1(const void *input, void *output) {
+ debugC(1, kDebugTools, "unpackM1(input, output)");
+
+ uint8 *outputLow, *outputHigh;
+ const uint8 *inputHigh, *inputptr = (const uint8 *)input;
+
+ uint32 unpackLen = 0;
+ uint32 packLen = 0;
+ uint16 counts = 0;
+ uint16 crcUnpacked = 0;
+ uint16 crcPacked = 0;
+
+
+ _bitBuffl = 0;
+ _bitBuffh = 0;
+ _bitCount = 0;
+
+ //Check for "RNC "
+ if (READ_BE_UINT32(inputptr) != RNC1_SIGNATURE)
+ return NOT_PACKED;
+
+ inputptr += 4;
+
+ // read unpacked/packed file length
+ unpackLen = READ_BE_UINT32(inputptr);
+ inputptr += 4;
+ packLen = READ_BE_UINT32(inputptr);
+ inputptr += 4;
+
+ uint8 blocks = *(inputptr + 5);
+
+ //read CRC's
+ crcUnpacked = READ_BE_UINT16(inputptr);
+ inputptr += 2;
+ crcPacked = READ_BE_UINT16(inputptr);
+ inputptr += 2;
+ inputptr = (inputptr + HEADER_LEN - 16);
+
+ if (crcBlock(inputptr, packLen) != crcPacked)
+ return PACKED_CRC;
+
+ inputptr = (((const uint8 *)input) + HEADER_LEN);
+ _srcPtr = inputptr;
+
+ inputHigh = ((const uint8 *)input) + packLen + HEADER_LEN;
+ outputLow = (uint8 *)output;
+ outputHigh = *(((const uint8 *)input) + 16) + unpackLen + outputLow;
+
+ if (!((inputHigh <= outputLow) || (outputHigh <= inputHigh))) {
+ _srcPtr = inputHigh;
+ _dstPtr = outputHigh;
+ memcpy((_dstPtr - packLen), (_srcPtr - packLen), packLen);
+ _srcPtr = (_dstPtr - packLen);
+ }
+
+ _dstPtr = (uint8 *)output;
+ _bitCount = 0;
+
+ _bitBuffl = READ_LE_UINT16(_srcPtr);
+ inputBits(2);
+
+ do {
+ makeHufftable(_rawTable);
+ makeHufftable(_posTable);
+ makeHufftable(_lenTable);
+
+ counts = inputBits(16);
+
+ do {
+ uint32 inputLength = inputValue(_rawTable);
+ uint32 inputOffset;
+
+ if (inputLength) {
+ memcpy(_dstPtr, _srcPtr, inputLength); //memcpy is allowed here
+ _dstPtr += inputLength;
+ _srcPtr += inputLength;
+ uint16 a = READ_LE_UINT16(_srcPtr);
+ uint16 b = READ_LE_UINT16(_srcPtr + 2);
+
+ _bitBuffl &= ((1 << _bitCount) - 1);
+ _bitBuffl |= (a << _bitCount);
+ _bitBuffh = (a >> (16 - _bitCount)) | (b << _bitCount);
+ }
+
+ if (counts > 1) {
+ inputOffset = inputValue(_posTable) + 1;
+ inputLength = inputValue(_lenTable) + MIN_LENGTH;
+
+ // Don't use memcpy here! because input and output overlap.
+ uint8 *tmpPtr = (_dstPtr - inputOffset);
+ while (inputLength--)
+ *_dstPtr++ = *tmpPtr++;
+ }
+ } while (--counts);
+ } while (--blocks);
+
+ if (crcBlock((uint8 *)output, unpackLen) != crcUnpacked)
+ return UNPACKED_CRC;
+
+ // all is done..return the amount of unpacked bytes
+ return unpackLen;
+}
+
+int32 RncDecoder::unpackM2(const void *input, void *output) {
+ debugC(1, kDebugTools, "unpackM2(input, output)");
+
+ const uint8 *inputptr = (const uint8 *)input;
+
+ uint32 unpackLen = 0;
+ uint32 packLen = 0;
+ uint16 crcUnpacked = 0;
+ uint16 crcPacked = 0;
+
+// Strangerke - Commented (not used)
+// uint16 counts = 0;
+
+ _bitBuffl = 0;
+ _bitCount = 0;
+
+ //Check for "RNC "
+ if (READ_BE_UINT32(inputptr) != RNC2_SIGNATURE)
+ return NOT_PACKED;
+
+ inputptr += 4;
+
+ // read unpacked/packed file length
+ unpackLen = READ_BE_UINT32(inputptr);
+ inputptr += 4;
+ packLen = READ_BE_UINT32(inputptr);
+ inputptr += 4;
+
+ //read CRC's
+ crcUnpacked = READ_BE_UINT16(inputptr);
+ inputptr += 2;
+ crcPacked = READ_BE_UINT16(inputptr);
+ inputptr += 2;
+ inputptr = (inputptr + HEADER_LEN - 16);
+
+ if (crcBlock(inputptr, packLen) != crcPacked)
+ return PACKED_CRC;
+
+ inputptr = (((const uint8 *)input) + HEADER_LEN);
+ _srcPtr = inputptr;
+ _dstPtr = (uint8 *)output;
+
+
+ uint16 ofs, len;
+ byte ofs_hi, ofs_lo;
+
+ len = 0;
+ ofs_hi = 0;
+ ofs_lo = 0;
+
+ getbit();
+ getbit();
+
+ while (1) {
+
+ bool loadVal = false;
+
+ while (getbit() == 0)
+ *_dstPtr++ = *_srcPtr++;
+
+ len = 2;
+ ofs_hi = 0;
+ if (getbit() == 0) {
+ len = (len << 1) | getbit();
+ if (getbit() == 1) {
+ len--;
+ len = (len << 1) | getbit();
+ if (len == 9) {
+ len = 4;
+ while (len--)
+ ofs_hi = (ofs_hi << 1) | getbit();
+ len = (ofs_hi + 3) * 4;
+ while (len--)
+ *_dstPtr++ = *_srcPtr++;
+ continue;
+ }
+ }
+ loadVal = true;
+ } else {
+ if (getbit() == 1) {
+ len++;
+ if (getbit() == 1) {
+ len = *_srcPtr++;
+ if (len == 0) {
+ if (getbit() == 1)
+ continue;
+ else
+ break;
+ }
+ len += 8;
+ }
+ loadVal = true;
+ } else {
+ loadVal = false;
+ }
+ }
+
+ if (loadVal) {
+ if (getbit() == 1) {
+ ofs_hi = (ofs_hi << 1) | getbit();
+ if (getbit() == 1) {
+ ofs_hi = ((ofs_hi << 1) | getbit()) | 4;
+ if (getbit() == 0)
+ ofs_hi = (ofs_hi << 1) | getbit();
+ } else if (ofs_hi == 0) {
+ ofs_hi = 2 | getbit();
+ }
+ }
+ }
+
+ ofs_lo = *_srcPtr++;
+ ofs = (ofs_hi << 8) | ofs_lo;
+ while (len--) {
+ *_dstPtr = *(byte *)(_dstPtr - ofs - 1);
+ _dstPtr++;
+ }
+
+ }
+
+ if (crcBlock((uint8 *)output, unpackLen) != crcUnpacked)
+ return UNPACKED_CRC;
+
+ // all is done..return the amount of unpacked bytes
+ return unpackLen;
+}
+
+} // End of namespace Toon
diff --git a/engines/toon/tools.h b/engines/toon/tools.h
new file mode 100644
index 0000000000..05fc5c9cda
--- /dev/null
+++ b/engines/toon/tools.h
@@ -0,0 +1,83 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* $URL$
+* $Id$
+*
+*/
+
+#ifndef TOON_TOOLS_H
+#define TOON_TOOLS_H
+
+#include "common/scummsys.h"
+#include "common/endian.h"
+
+#define RNC1_SIGNATURE 0x524E4301 // "RNC\001"
+#define RNC2_SIGNATURE 0x524E4302 // "RNC\002"
+
+namespace Toon {
+
+const uint32 kCompLZSS = 0x4C5A5353;
+const uint32 kCompSPCN = 0x5350434E;
+const uint32 kCompRNC1 = 0x524E4301;
+const uint32 kCompRNC2 = 0x524E4302;
+
+#define READ_LE_INT16(x) (int16) READ_LE_UINT16(x)
+#define READ_LE_INT32(x) (int32) READ_LE_UINT32(x)
+
+#define WRITE_LE_INT16(x,y) WRITE_LE_UINT16(x,(int16)y)
+#define WRITE_LE_INT32(x,y) WRITE_LE_UINT32(x,(int32)y)
+
+uint32 decompressSPCN(byte *src, byte *dst, uint32 dstsize);
+uint32 decompressLZSS(byte *src, byte *dst, int dstsize);
+
+class RncDecoder {
+
+protected:
+ uint16 _rawTable[64];
+ uint16 _posTable[64];
+ uint16 _lenTable[64];
+ uint16 _crcTable[256];
+
+ uint16 _bitBuffl;
+ uint16 _bitBuffh;
+ uint8 _bitCount;
+
+ const uint8 *_srcPtr;
+ uint8 *_dstPtr;
+
+public:
+ RncDecoder();
+ ~RncDecoder();
+ int32 unpackM1(const void *input, void *output);
+ int32 unpackM2(const void *input, void *output);
+
+protected:
+ void initCrc();
+ uint16 crcBlock(const uint8 *block, uint32 size);
+ uint16 inputBits(uint8 amount);
+ void makeHufftable(uint16 *table);
+ uint16 inputValue(uint16 *table);
+ int getbit();
+};
+
+} // End of namespace Toon
+
+#endif
diff --git a/engines/toon/toon.cpp b/engines/toon/toon.cpp
new file mode 100644
index 0000000000..7a6a2fc87a
--- /dev/null
+++ b/engines/toon/toon.cpp
@@ -0,0 +1,4548 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* $URL$
+* $Id$
+*
+*/
+
+#include "common/system.h"
+#include "common/events.h"
+#include "common/debug-channels.h"
+#include "common/archive.h"
+#include "common/config-manager.h"
+#include "common/EventRecorder.h"
+#include "engines/util.h"
+#include "graphics/surface.h"
+#include "graphics/thumbnail.h"
+#include "gui/saveload.h"
+#include "gui/about.h"
+#include "gui/message.h"
+#include "toon/resource.h"
+#include "toon/toon.h"
+#include "toon/anim.h"
+#include "toon/picture.h"
+#include "toon/hotspot.h"
+#include "toon/flux.h"
+#include "toon/drew.h"
+#include "toon/path.h"
+
+namespace Toon {
+
+
+void ToonEngine::init() {
+ _currentScriptRegion = 0;
+ _resources = new Resources(this);
+ _animationManager = new AnimationManager(this);
+ _moviePlayer = new Movie(this, new ToonstruckSmackerDecoder(_mixer));
+ _hotspots = new Hotspots(this);
+
+ _mainSurface = new Graphics::Surface();
+ _mainSurface->create(1280, 400, 1);
+
+ _finalPalette = new uint8[768];
+ _backupPalette = new uint8[768];
+ _additionalPalette1 = new uint8[69];
+ _additionalPalette2 = new uint8[69];
+ _cutawayPalette = new uint8[768];
+ _universalPalette = new uint8[96];
+ _fluxPalette = new uint8[24];
+
+ memset(_finalPalette, 0, 768);
+ memset(_backupPalette, 0, 768);
+ memset(_additionalPalette1, 0, 69);
+ memset(_additionalPalette2, 0, 69);
+ memset(_cutawayPalette, 0, 768);
+ memset(_universalPalette, 0, 96);
+ memset(_fluxPalette, 0, 24);
+
+ _conversationData = new int16[4096];
+ memset(_conversationData, 0, 4096 * sizeof(int16));
+
+ _shouldQuit = false;
+ _scriptStep = 0;
+
+ _cursorOffsetX = 0;
+ _cursorOffsetY = 0;
+ _currentHotspotItem = 0;
+
+ _currentTextLine = 0;
+ _currentTextLineId = -1;
+ _currentTextLineX = 0;
+ _currentTextLineY = 0;
+ _currentTextLineCharacterId = 0;
+
+ _saveBufferStream = new Common::MemoryWriteStreamDynamic();
+
+ _firstFrame = false;
+
+ const Common::FSNode gameDataDir(ConfMan.get("path"));
+ SearchMan.addSubDirectoryMatching(gameDataDir, "misc");
+
+ syncSoundSettings();
+
+ _pathFinding = new PathFinding(this);
+
+ resources()->openPackage("misc/local.pak", true);
+ resources()->openPackage("misc/onetime.pak", true);
+ resources()->openPackage("misc/drew.pak", true);
+
+ for (int32 i = 0; i < 32; i++)
+ _characters[i] = 0;
+
+ _characters[0] = new CharacterDrew(this);
+ _characters[1] = new CharacterFlux(this);
+ _drew = _characters[0];
+ _flux = _characters[1];
+
+ // preload walk anim for flux and drew
+ _drew->loadWalkAnimation("stndwalk.caf");
+ _drew->setupPalette();
+ _drew->loadShadowAnimation("shadow.caf");
+
+ _flux->loadWalkAnimation("fxstwalk.caf");
+ _flux->loadShadowAnimation("shadow.caf");
+
+ loadAdditionalPalette("universe.pal", 3);
+ loadAdditionalPalette("flux.pal", 4);
+ setupGeneralPalette();
+
+ _script_func = new ScriptFunc(this);
+ _gameState = new State();
+ _gameState->_conversationData = _conversationData;
+
+ memset(_sceneAnimations, 0, sizeof(_sceneAnimations));
+ memset(_sceneAnimationScripts, 0, sizeof(_sceneAnimationScripts));
+
+
+ _gameState->_currentChapter = 1;
+ initChapter();
+ loadCursor();
+ initFonts();
+
+ _dialogIcons = new Animation(this);
+ _dialogIcons->loadAnimation("dialogue.caf");
+
+ _inventoryIcons = new Animation(this);
+ _inventoryIcons->loadAnimation("inventry.caf");
+
+ _inventoryIconSlots = new Animation(this);
+ _inventoryIconSlots->loadAnimation("iconslot.caf");
+
+ _genericTexts = new TextResource(this);
+ _genericTexts->loadTextResource("generic.tre");
+
+ _audioManager = new AudioManager(this, _mixer);
+ _audioManager->loadAudioPack(0, "generic.svi", "misc/generic.svl");
+ _audioManager->loadAudioPack(2, "generic.sei", "generic.sel");
+
+ _lastMouseButton = 0;
+ _mouseButton = 0;
+}
+
+void ToonEngine::waitForScriptStep() {
+ // Wait after a specified number of script steps when executing a script
+ // to lower CPU usage
+ if (++_scriptStep >= 40) {
+ g_system->delayMillis(1);
+ _scriptStep = 0;
+ }
+}
+
+void ToonEngine::parseInput() {
+
+ Common::EventManager *_event = _system->getEventManager();
+
+ _mouseX = _event->getMousePos().x;
+ _mouseY = _event->getMousePos().y;
+ _mouseButton = _event->getButtonState();
+
+ Common::Event event;
+ while (_event->pollEvent(event)) {
+ switch (event.type) {
+ case Common::EVENT_KEYUP:
+ if (event.kbd.ascii == 27 || event.kbd.ascii == 32) {
+ _audioManager->stopCurrentVoice();
+ }
+ if (event.kbd.keycode == Common::KEYCODE_F5) {
+ if(canSaveGameStateCurrently())
+ saveGame(-1, Common::String());
+ }
+ if (event.kbd.keycode == Common::KEYCODE_F6) {
+ if(canLoadGameStateCurrently())
+ loadGame(-1);
+ }
+ if (event.kbd.ascii == 't') {
+ _showConversationText = !_showConversationText;
+ }
+ if (event.kbd.ascii == 'm') {
+ _audioManager->muteMusic(!_audioManager->isMusicMuted());
+ }
+ if (event.kbd.ascii == 'd') {
+ _audioManager->muteVoice(!_audioManager->isVoiceMuted());
+ }
+ if (event.kbd.ascii == 's') {
+ _audioManager->muteSfx(!_audioManager->isSfxMuted());
+ }
+
+ if (event.kbd.flags & Common::KBD_ALT) {
+ int32 slotNum = event.kbd.ascii - '0';
+ if (slotNum >= 0 && slotNum <= 9 && canSaveGameStateCurrently()) {
+ if (saveGame(slotNum, Common::String())) {
+ // ok
+ char buf[256];
+ snprintf(buf, 256, "Saved game in slot #%d ", slotNum);
+ GUI::TimedMessageDialog dialog(buf, 1000);
+ dialog.runModal();
+ } else {
+ char buf[256];
+ snprintf(buf, 256, "Could not quick save into slot #%d", slotNum);
+ GUI::MessageDialog dialog2(buf, "OK", 0);
+ //warning("%s", buf);
+ dialog2.runModal();
+
+ }
+ }
+ }
+
+ if (event.kbd.flags & Common::KBD_CTRL) {
+ int32 slotNum = event.kbd.ascii - '0';
+ if (slotNum >= 0 && slotNum <= 9 && canLoadGameStateCurrently()) {
+ if (loadGame(slotNum)) {
+ // ok
+ char buf[256];
+ snprintf(buf, 256, "Savegame #%d quick loaded", slotNum);
+ GUI::TimedMessageDialog dialog(buf, 1000);
+ dialog.runModal();
+ } else {
+ char buf[256];
+ snprintf(buf, 256, "Could not quick load the savegame #%d", slotNum);
+ GUI::MessageDialog dialog(buf, "OK", 0);
+ warning("%s", buf);
+ dialog.runModal();
+ }
+ }
+ }
+ break;
+// Strangerke - Commented (not used)
+// case Common::EVENT_LBUTTONDOWN:
+// break;
+// case Common::EVENT_RBUTTONDOWN:
+// break;
+// case Common::EVENT_LBUTTONUP:
+// break;
+// case Common::EVENT_RBUTTONUP:
+// break;
+// case Common::EVENT_WHEELUP:
+// break;
+// case Common::EVENT_WHEELDOWN:
+// break;
+ default:
+ break;
+ }
+ }
+
+ if (!_gameState->_inConversation && !_gameState->_mouseHidden && !_gameState->_inInventory) {
+ selectHotspot();
+ clickEvent();
+ }
+
+}
+
+void ToonEngine::enableTimer(int32 timerId) {
+ _gameState->_timerEnabled[timerId] = true;
+}
+void ToonEngine::setTimer(int32 timerId, int32 timerWait) {
+ _gameState->_timerTimeout[timerId] = getOldMilli() + timerWait * getTickLength();
+ _gameState->_timerDelay[timerId] = timerWait;
+}
+void ToonEngine::disableTimer(int32 timerId) {
+ _gameState->_timerEnabled[timerId] = false;
+}
+void ToonEngine::updateTimers() {
+ for (int32 i = 0; i < 2; i++) {
+ if (_gameState->_timerEnabled[i]) {
+ if (_gameState->_timerDelay[i] > -1 && getOldMilli() > _gameState->_timerTimeout[i]) {
+ if (i == 0) {
+
+ EMCState *status = &_scriptState[_currentScriptRegion];
+ _script->init(status, &_scriptData);
+
+ // setup registers
+ status->regs[0] = _mouseX;
+ status->regs[1] = _mouseY;
+ status->regs[2] = 0;
+
+ _currentScriptRegion++;
+
+ _script->start(status, 7);
+ while (_script->run(status))
+ waitForScriptStep();
+
+ _currentScriptRegion--;
+
+ _gameState->_timerTimeout[i] = getOldMilli() + _gameState->_timerDelay[i] * getTickLength();
+
+ return;
+
+ }
+ }
+ }
+ }
+}
+
+void ToonEngine::updateScrolling(bool force, int32 timeIncrement) {
+ static int32 lastScrollOffset = 320;
+ if (!_audioManager->voiceStillPlaying() && !_gameState->_currentScrollLock && (_drew->getFlag() & 1) == 0) {
+ if (_drew->getFacing() & 3) {
+ if (_drew->getFacing() <= 4)
+ lastScrollOffset = 200;
+ else
+ lastScrollOffset = 440;
+ }
+
+ if (_gameState->_inCutaway || _gameState->_inInventory || _gameState->_inCloseUp)
+ return;
+
+ int32 desiredScrollValue = _drew->getX() - lastScrollOffset;
+
+ if ((_gameState->_locations[_gameState->_currentScene]._flags & 0x80) == 0) {
+ if (desiredScrollValue < 0)
+ desiredScrollValue = 0;
+ if (desiredScrollValue >= _currentPicture->getWidth() - 640)
+ desiredScrollValue = _currentPicture->getWidth() - 640;
+
+ if (force) {
+ _gameState->_currentScrollValue = desiredScrollValue;
+ return;
+ } else {
+ if (_gameState->_currentScrollValue < desiredScrollValue) {
+ _gameState->_currentScrollValue += timeIncrement / 2;
+
+ if (_gameState->_currentScrollValue > desiredScrollValue)
+ _gameState->_currentScrollValue = desiredScrollValue;
+ } else if (_gameState->_currentScrollValue > desiredScrollValue) {
+ _gameState->_currentScrollValue -= timeIncrement / 2;
+
+ if (_gameState->_currentScrollValue < desiredScrollValue)
+ _gameState->_currentScrollValue = desiredScrollValue;
+ }
+ }
+ }
+ }
+}
+
+void ToonEngine::update(int32 timeIncrement) {
+ // to make sure we're updating the game at 5fps at least
+ if (timeIncrement > 200)
+ timeIncrement = 200;
+
+ updateAnimationSceneScripts(timeIncrement);
+ updateCharacters(timeIncrement);
+ updateTimer(timeIncrement);
+ updateTimers();
+ updateScrolling(false, timeIncrement);
+ _audioManager->updateAmbientSFX();
+ _animationManager->update(timeIncrement);
+ _cursorAnimationInstance->update(timeIncrement);
+
+ if (!_audioManager->voiceStillPlaying()) {
+ _currentTextLine = 0;
+ _currentTextLineId = -1;
+ }
+}
+
+void ToonEngine::updateTimer(int32 timeIncrement) {
+ if (_gameState->_gameTimer > 0) {
+ debugC(0, 0xfff, "updateTimer(%d)", timeIncrement);
+ _gameState->_gameTimer -= timeIncrement;
+ if (_gameState->_gameTimer < 0)
+ _gameState->_gameTimer = 0;
+ }
+}
+
+void ToonEngine::render() {
+ if (_gameState->_inCutaway)
+ _currentCutaway->draw(*_mainSurface, 0, 0, 0, 0);
+ else
+ _currentPicture->draw(*_mainSurface, 0, 0, 0, 0);
+
+ //_currentMask->drawMask(*_mainSurface,0,0,0,0);
+ _animationManager->render();
+
+ drawInfoLine();
+ drawConversationLine();
+ drawConversationIcons();
+ drawSack();
+ //drawPalette();
+
+#if 0
+ char test[256];
+ if (_mouseX > 0 && _mouseX < 640 && _mouseY > 0 && _mouseY < 400) {
+ sprintf(test, "%d %d / mask %d layer %d z %d", _mouseX, _mouseY, getMask()->getData(_mouseX, _mouseY), getLayerAtPoint(_mouseX, _mouseY), getZAtPoint(_mouseX, _mouseY));
+
+ int32 c = *(uint8 *)_mainSurface->getBasePtr(_mouseX, _mouseY);
+ sprintf(test, "%d %d / color id %d %d,%d,%d", _mouseX, _mouseY, c, _finalPalette[c*3+0], _finalPalette[c*3+1], _finalPalette[c*3+2]);
+
+ _fontRenderer->setFont(_fontToon);
+ _fontRenderer->renderText(40, 150, Common::String(test), 0);
+ }
+#endif
+
+ if (_firstFrame) {
+ copyToVirtualScreen(false);
+ fadeIn(5);
+ _firstFrame = false;
+ } else {
+ copyToVirtualScreen(true);
+ }
+}
+
+void ToonEngine::doMagnifierEffect() {
+ int32 posX = _mouseX + state()->_currentScrollValue - _cursorOffsetX;
+ int32 posY = _mouseY - _cursorOffsetY - 2;
+
+ Graphics::Surface &surface = *_mainSurface;
+
+ // fast sqrt table lookup (values up to 144 only)
+ static const byte intSqrt[] = {
+ 0, 1, 1, 1, 2, 2, 2, 2, 2, 3,
+ 3, 3, 3, 3, 3, 3, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 12
+ };
+
+ byte tempBuffer[25*25];
+ for (int32 y = -12; y <= 12; y++) {
+ for (int32 x = -12; x <= 12; x++) {
+ int32 destPitch = surface.pitch;
+ uint8 *curRow = (uint8 *)surface.pixels + (posY + y) * destPitch + (posX + x);
+ tempBuffer[(y+12) * 25 + x + 12] = *curRow;
+ }
+ }
+
+ for (int32 y = -12; y <= 12; y++) {
+ for (int32 x = -12; x <= 12; x++) {
+ int32 dist = y * y + x * x;
+ if (dist > 144)
+ continue;
+ int32 destPitch = surface.pitch;
+ uint8 *curRow = (uint8 *)surface.pixels + (posY + y) * destPitch + (posX + x);
+ int32 lerp = (512 + intSqrt[dist] * 256 / 12);
+ *curRow = tempBuffer[(y*lerp/1024+12) * 25 + x*lerp/1024 + 12];
+ }
+ }
+}
+
+void ToonEngine::copyToVirtualScreen(bool updateScreen) {
+ // render cursor last
+ if (!_gameState->_mouseHidden) {
+ if (_cursorAnimationInstance->getFrame() == 7) // magnifier icon needs a special effect
+ doMagnifierEffect();
+ _cursorAnimationInstance->setPosition(_mouseX - 40 + state()->_currentScrollValue - _cursorOffsetX, _mouseY - 40 - _cursorOffsetY, 0, false);
+ _cursorAnimationInstance->render();
+ }
+ _system->copyRectToScreen((byte *)_mainSurface->pixels + state()->_currentScrollValue, 1280, 0, 0, 640, 400);
+ if (updateScreen) {
+ _system->updateScreen();
+ _shouldQuit = shouldQuit(); // update game quit flag - this shouldn't be called all the time, as it's a virtual function
+ }
+}
+
+void ToonEngine::doFrame() {
+
+ if (_gameState->_inInventory) {
+ renderInventory();
+ } else {
+ render();
+
+ int32 currentTimer = _system->getMillis();
+// Strangerke - Commented (not used)
+// int32 elapsedTime = currentTimer - _oldTimer;
+
+ update(currentTimer - _oldTimer);
+ _oldTimer = currentTimer;
+ _oldTimer2 = currentTimer;
+ }
+ parseInput();
+}
+
+enum MainMenuSelections {
+ MAINMENUHOTSPOT_NONE = 0,
+ MAINMENUHOTSPOT_START = 1,
+ MAINMENUHOTSPOT_INTRO = 2,
+ MAINMENUHOTSPOT_LOADGAME = 3,
+ MAINMENUHOTSPOT_HOTKEYS = 4,
+ MAINMENUHOTSPOT_CREDITS = 5,
+ MAINMENUHOTSPOT_QUIT = 6,
+ MAINMENUHOTSPOT_HOTKEYSCLOSE = 7
+};
+
+enum MainMenuMasks {
+ MAINMENUMASK_BASE = 1,
+ MAINMENUMASK_HOTKEYS = 2,
+ MAINMENUMASK_EVERYWHERE = 3
+};
+
+struct MainMenuFile {
+ int menuMask;
+ int id;
+ const char *animationFile;
+ int animateOnFrame;
+};
+
+#define MAINMENU_ENTRYCOUNT 12
+static const MainMenuFile mainMenuFiles[] = {
+ { MAINMENUMASK_BASE, MAINMENUHOTSPOT_START, "STARTBUT.CAF", 0 }, // "Start" button
+ { MAINMENUMASK_BASE, MAINMENUHOTSPOT_INTRO, "INTROBUT.CAF", 0 }, // "Intro" button
+ { MAINMENUMASK_BASE, MAINMENUHOTSPOT_LOADGAME, "LOADBUT.CAF", 0 }, // "Load Game" button
+ { MAINMENUMASK_BASE, MAINMENUHOTSPOT_HOTKEYS, "HOTBUT.CAF", 0 }, // "Hot Keys" button
+ { MAINMENUMASK_BASE, MAINMENUHOTSPOT_CREDITS, "CREDBUT.CAF", 0 }, // "Credits" button
+ { MAINMENUMASK_BASE, MAINMENUHOTSPOT_QUIT, "QUITBUT.CAF", 0 }, // "Quit" button
+ { MAINMENUMASK_BASE, MAINMENUHOTSPOT_NONE, "LEGALTXT.CAF", 0 }, // Legal Text
+
+ { MAINMENUMASK_EVERYWHERE, MAINMENUHOTSPOT_NONE, "TOONGLOW.CAF", 6 }, // Clown glow
+ { MAINMENUMASK_EVERYWHERE, MAINMENUHOTSPOT_NONE, "TOONSTRK.CAF", 6 }, // Toonstruck title
+ { MAINMENUMASK_EVERYWHERE, MAINMENUHOTSPOT_NONE, "EYEGLOW.CAF", 4 }, // Clown eye glow
+ { MAINMENUMASK_EVERYWHERE, MAINMENUHOTSPOT_NONE, "PROPHEAD.CAF", 4 }, // Clown propellor head
+ { MAINMENUMASK_HOTKEYS, MAINMENUHOTSPOT_HOTKEYSCLOSE, "HOTKEYS.CAF", 0 } // Hotkeys display - clicking on it will close hotkeys
+};
+
+struct MainMenuEntry {
+ int menuMask;
+ int id;
+ Animation *animation;
+ Common::Rect rect;
+ int animateOnFrame;
+ int animateCurFrame;
+ int activeFrame;
+};
+
+bool ToonEngine::showMainmenu(bool &loadedGame) {
+ Picture *mainmenuPicture = new Picture(this);
+ mainmenuPicture->loadPicture("TITLESCR.CPS", true);
+ mainmenuPicture->setupPalette();
+
+ MainMenuEntry entries[MAINMENU_ENTRYCOUNT];
+
+ for (int entryNr = 0; entryNr < MAINMENU_ENTRYCOUNT; entryNr++) {
+ entries[entryNr].menuMask = mainMenuFiles[entryNr].menuMask;
+ entries[entryNr].id = mainMenuFiles[entryNr].id;
+ entries[entryNr].animation = new Animation(this);
+ entries[entryNr].animation->loadAnimation(mainMenuFiles[entryNr].animationFile);
+ if (entries[entryNr].id != MAINMENUHOTSPOT_NONE)
+ entries[entryNr].rect = entries[entryNr].animation->getRect();
+ entries[entryNr].animateOnFrame = mainMenuFiles[entryNr].animateOnFrame;
+ entries[entryNr].animateCurFrame = 0;
+ entries[entryNr].activeFrame = 0;
+ }
+
+ setCursor(1);
+
+ bool doExit = false;
+ bool exitGame = false;
+ int clickingOn, clickRelease;
+ int menuMask = MAINMENUMASK_BASE;
+ AudioStreamInstance *mainmenuMusic = NULL;
+ bool musicPlaying = false;
+
+ while (!doExit) {
+ clickingOn = MAINMENUHOTSPOT_NONE;
+ clickRelease = false;
+
+ if (!musicPlaying) {
+ Common::SeekableReadStream *mainmenuMusicFile = resources()->openFile("misc/BR091013.MUS");
+ mainmenuMusic = new AudioStreamInstance(_audioManager, _mixer, mainmenuMusicFile, true);
+ mainmenuMusic->play(false);
+ musicPlaying = true;
+ }
+
+ while (!clickRelease) {
+ mainmenuPicture->draw(*_mainSurface, 0, 0, 0, 0);
+
+ for (int entryNr = 0; entryNr < MAINMENU_ENTRYCOUNT; entryNr++) {
+ if (entries[entryNr].menuMask & menuMask) {
+ if (entries[entryNr].animateOnFrame) {
+ entries[entryNr].animateCurFrame++;
+ if (entries[entryNr].animateOnFrame <= entries[entryNr].animateCurFrame) {
+ entries[entryNr].activeFrame++;
+ if (entries[entryNr].activeFrame >= entries[entryNr].animation->_numFrames)
+ entries[entryNr].activeFrame = 0;
+ entries[entryNr].animateCurFrame = 0;
+ }
+ }
+ int32 frameNr = entries[entryNr].activeFrame;
+ if ((entries[entryNr].id == clickingOn) && (clickingOn != MAINMENUHOTSPOT_NONE))
+ frameNr = 1;
+ entries[entryNr].animation->drawFrame(*_mainSurface, frameNr, 0, 0);
+ }
+ }
+
+ parseInput();
+ copyToVirtualScreen(true);
+ _system->delayMillis(17);
+
+ if (_mouseButton & 1) {
+ // left mouse button pushed down
+ clickingOn = MAINMENUHOTSPOT_NONE;
+ for (int entryNr = 0; entryNr < MAINMENU_ENTRYCOUNT; entryNr++) {
+ if (entries[entryNr].menuMask & menuMask) {
+ if (entries[entryNr].id != MAINMENUHOTSPOT_NONE) {
+ if (entries[entryNr].rect.contains(_mouseX, _mouseY))
+ clickingOn = entries[entryNr].id;
+ }
+ }
+ }
+ } else {
+ // left mouse button released/not pushed down
+ if (clickingOn != MAINMENUHOTSPOT_NONE)
+ clickRelease = true;
+ }
+ if (_shouldQuit) {
+ clickingOn = MAINMENUHOTSPOT_NONE;
+ clickRelease = true;
+ doExit = true;
+ }
+ }
+
+ if (clickingOn != MAINMENUHOTSPOT_NONE) {
+ _audioManager->playSFX(10, 128, true);
+ }
+
+ switch (clickingOn) {
+ case MAINMENUHOTSPOT_HOTKEYS:
+ menuMask = MAINMENUMASK_HOTKEYS;
+ continue;
+ case MAINMENUHOTSPOT_HOTKEYSCLOSE:
+ menuMask = MAINMENUMASK_BASE;
+ continue;
+ }
+
+ if (musicPlaying) {
+ //stop music
+ mainmenuMusic->stop(false);
+ musicPlaying = false;
+ }
+
+
+
+ switch (clickingOn) {
+ case MAINMENUHOTSPOT_START:
+ // Start game (actually exit main menu)
+ loadedGame = false;
+ doExit = true;
+ break;
+ case MAINMENUHOTSPOT_INTRO:
+ // Play intro movies
+ getMoviePlayer()->play("MISC/209_1M.SMK", 0x10);
+ getMoviePlayer()->play("MISC/209_2M.SMK", 0x10);
+ getMoviePlayer()->play("MISC/209_3M.SMK", 0x10);
+ break;
+ case MAINMENUHOTSPOT_LOADGAME:
+ doExit = loadGame(-1);
+ loadedGame = doExit;
+ exitGame = false;
+ break;
+ case MAINMENUHOTSPOT_CREDITS:
+ // Play credits movie
+ getMoviePlayer()->play("MISC/CREDITS.SMK", 0x0);
+ break;
+ case MAINMENUHOTSPOT_QUIT:
+ exitGame = true;
+ doExit = true;
+ break;
+ }
+ }
+
+ return !exitGame;
+}
+
+Common::Error ToonEngine::run() {
+
+ if (!loadToonDat())
+ return Common::kUnknownError;
+
+ g_eventRec.registerRandomSource(_rnd, "toon");
+
+ initGraphics(640, 400, true);
+ init();
+
+ // do we need to load directly a game?
+ bool loadedGame = false;
+ int32 slot = ConfMan.getInt("save_slot");
+ if (slot > -1) {
+ loadedGame = loadGame(slot);
+ }
+
+ if (!loadedGame) {
+
+ // play producer intro
+ getMoviePlayer()->play("MISC/VIELOGOM.SMK", 0x10);
+
+ // show mainmenu
+ if (!showMainmenu(loadedGame)) {
+ return Common::kNoError;
+ }
+ }
+
+ //loadScene(17);
+ //loadScene(37);
+ if (!loadedGame) {
+ newGame();
+ }
+
+// Strangerke - Commented (not used)
+// int32 oldTimer = _system->getMillis();
+ while (!_shouldQuit && _gameState->_currentScene != -1)
+ doFrame();
+ return Common::kNoError;
+}
+
+ToonEngine::ToonEngine(OSystem *syst, const ADGameDescription *gameDescription)
+ : Engine(syst), _gameDescription(gameDescription), _language(gameDescription->language) {
+ _system = syst;
+ _tickLength = 16;
+ _currentMask = 0;
+ _currentPicture = 0;
+ _roomScaleData = 0;
+ _shadowLUT = 0;
+ _showConversationText = true;
+ _isDemo = _gameDescription->flags & ADGF_DEMO;
+
+ DebugMan.addDebugChannel(kDebugAnim, "Anim", "Animation debug level");
+ DebugMan.addDebugChannel(kDebugCharacter, "Character", "Character debug level");
+ DebugMan.addDebugChannel(kDebugAudio, "Audio", "Audio debug level");
+ DebugMan.addDebugChannel(kDebugHotspot, "Hotspot", "Hotspot debug level");
+ DebugMan.addDebugChannel(kDebugFont, "Font", "Font debug level");
+ DebugMan.addDebugChannel(kDebugPath, "Path", "Path debug level");
+ DebugMan.addDebugChannel(kDebugMovie, "Movie", "Movie debug level");
+ DebugMan.addDebugChannel(kDebugPicture, "Picture", "Picture debug level");
+ DebugMan.addDebugChannel(kDebugResource, "Resource", "Resource debug level");
+ DebugMan.addDebugChannel(kDebugState, "State", "State debug level");
+ DebugMan.addDebugChannel(kDebugTools, "Tools", "Tools debug level");
+ DebugMan.addDebugChannel(kDebugText, "Text", "Text debug level");
+
+ switch (_language) {
+ case Common::EN_GRB:
+ case Common::EN_USA:
+ case Common::EN_ANY:
+ _gameVariant = 0;
+ break;
+ case Common::FR_FRA:
+ _gameVariant = 1;
+ break;
+ case Common::DE_DEU:
+ _gameVariant = 2;
+ break;
+ case Common::RU_RUS:
+ _gameVariant = 3;
+ break;
+ case Common::ES_ESP:
+ _gameVariant = 4;
+ break;
+ default:
+ // 0 - english
+ _gameVariant = 0;
+ break;
+ }
+}
+
+ToonEngine::~ToonEngine() {
+
+}
+
+void ToonEngine::flushPalette() {
+
+ uint8 vmpalette[1024];
+ for (int32 i = 0; i < 256; i++) {
+ vmpalette[i*4+0] = _finalPalette[i*3+0];
+ vmpalette[i*4+1] = _finalPalette[i*3+1];
+ vmpalette[i*4+2] = _finalPalette[i*3+2];
+ vmpalette[i*4+3] = 0;
+ }
+ _system->setPalette(vmpalette, 0, 256);
+}
+void ToonEngine::setPaletteEntries(uint8 *palette, int32 offset, int32 num) {
+ memcpy(_finalPalette + offset * 3, palette, num * 3);
+ uint8 vmpalette[1024];
+ for (int32 i = 0; i < num; i++) {
+ vmpalette[i*4+0] = palette[i*3+0];
+ vmpalette[i*4+1] = palette[i*3+1];
+ vmpalette[i*4+2] = palette[i*3+2];
+ vmpalette[i*4+3] = 0;
+ }
+ _system->setPalette(vmpalette, offset, num);
+}
+
+void ToonEngine::simpleUpdate(bool waitCharacterToTalk) {
+ int32 elapsedTime = _system->getMillis() - _oldTimer2;
+ _oldTimer2 = _system->getMillis();
+ _oldTimer = _oldTimer2;
+
+ if (!_audioManager->voiceStillPlaying() && !waitCharacterToTalk) {
+ _currentTextLine = 0;
+ _currentTextLineId = -1;
+ }
+
+ updateCharacters(elapsedTime);
+ updateAnimationSceneScripts(elapsedTime);
+ updateTimer(elapsedTime);
+ _animationManager->update(elapsedTime);
+ _audioManager->updateAmbientSFX();
+ render();
+
+
+}
+
+void ToonEngine::fixPaletteEntries(uint8 *palette, int num) {
+ // some color values are coded on 6bits ( for old 6bits DAC )
+ for (int32 i = 0; i < num * 3; i++) {
+ int32 a = palette[i];
+ a = a * 4;
+ if (a > 255)
+ a = 255;
+ palette[i] = a;
+ }
+}
+
+// adapted from KyraEngine
+void ToonEngine::updateAnimationSceneScripts(int32 timeElapsed) {
+
+
+ static int32 numReentrant = 0;
+ numReentrant++;
+
+// Strangerke - Commented (not used)
+// uint32 nextTime = _system->getMillis() + _tickLength;
+ const int startScript = _lastProcessedSceneScript;
+
+ _updatingSceneScriptRunFlag = true;
+
+ do {
+ if (_sceneAnimationScripts[_lastProcessedSceneScript]._lastTimer <= _system->getMillis() &&
+ !_sceneAnimationScripts[_lastProcessedSceneScript]._frozen && !_sceneAnimationScripts[_lastProcessedSceneScript]._frozenForConversation) {
+ _animationSceneScriptRunFlag = true;
+
+ while (_animationSceneScriptRunFlag && _sceneAnimationScripts[_lastProcessedSceneScript]._lastTimer <= _system->getMillis() && !_shouldQuit) {
+ if (!_script->run(&_sceneAnimationScripts[_lastProcessedSceneScript]._state))
+ _animationSceneScriptRunFlag = false;
+
+ //waitForScriptStep();
+
+ if (_sceneAnimationScripts[_lastProcessedSceneScript]._frozen || _sceneAnimationScripts[_lastProcessedSceneScript]._frozenForConversation)
+ break;
+ }
+
+ }
+
+ if (!_script->isValid(&_sceneAnimationScripts[_lastProcessedSceneScript]._state)) {
+ _script->start(&_sceneAnimationScripts[_lastProcessedSceneScript]._state, 9 + _lastProcessedSceneScript);
+ _animationSceneScriptRunFlag = false;
+ }
+
+ ++_lastProcessedSceneScript;
+ if (_lastProcessedSceneScript >= state()->_locations[state()->_currentScene]._numSceneAnimations)
+ _lastProcessedSceneScript = 0;
+
+ } while (_lastProcessedSceneScript != startScript && !_shouldQuit);
+
+
+ _updatingSceneScriptRunFlag = false;
+ numReentrant--;
+
+}
+
+void ToonEngine::loadScene(int32 SceneId, bool forGameLoad) {
+ char temp[256];
+ char temp2[256];
+
+
+ _firstFrame = true;
+
+ _gameState->_lastVisitedScene = _gameState->_currentScene;
+ _gameState->_currentScene = SceneId;
+
+ _saveBufferStream->seek(0);
+
+ if (SceneId == -1) {
+ // this scene -1 is loaded at the very end of the game
+ getAudioManager()->stopMusic();
+ getMoviePlayer()->play("CREDITS.SMK");
+ return;
+ }
+
+ // find out in what chapter we are (the script function ProcessToNextChapter is actually not called )
+ // the location flag has the chapter info in it
+ int32 flag = _gameState->_locations[SceneId]._flags;
+ if (flag) {
+ _gameState->_currentChapter = 0;
+ do {
+ _gameState->_currentChapter++;
+ flag >>= 1;
+ } while ((flag & 1) == 0);
+ }
+
+ for (int32 i = 0; i < 8; i++) {
+ if (_characters[i]) _characters[i]->setFlag(0);
+ }
+ _drew->playStandingAnim();
+ _drew->setVisible(true);
+
+ // hide flux in chapter 2
+ if (_gameState->_currentChapter == 1) {
+ _flux->playStandingAnim();
+ _flux->setVisible(true);
+ } else {
+ _flux->setVisible(false);
+ }
+
+ _lastMouseButton = 0;
+ _mouseButton = 0;
+ _currentHotspotItem = 0;
+
+ if (!forGameLoad) {
+ _gameState->_sackVisible = true;
+ _gameState->_inCloseUp = false;
+ _gameState->_inConversation = false;
+ _gameState->_inInventory = false;
+ _gameState->_inCutaway = false;
+ _gameState->_currentScrollValue = 0;
+ _gameState->_currentScrollLock = false;
+ _gameState->_inCloseUp = false;
+ }
+
+ if (_gameState->_mouseState >= 0)
+ addItemToInventory(_gameState->_mouseState);
+
+ _gameState->_mouseState = -1;
+ _mouseButton = 0;
+ _lastMouseButton = 0x3;
+
+
+ // load package
+ strcpy(temp, createRoomFilename(Common::String::printf("%s.pak", _gameState->_locations[_gameState->_currentScene]._name).c_str()).c_str());
+ resources()->openPackage(temp, true);
+
+ strcpy(temp, state()->_locations[SceneId]._name);
+ strcat(temp, ".npp");
+ loadAdditionalPalette(temp, 0);
+
+ strcpy(temp, state()->_locations[SceneId]._name);
+ strcat(temp, ".np2");
+ loadAdditionalPalette(temp, 1);
+
+ strcpy(temp, state()->_locations[SceneId]._name);
+ strcat(temp, ".cup");
+ loadAdditionalPalette(temp, 2);
+
+ // load artwork
+ strcpy(temp, state()->_locations[SceneId]._name);
+ strcat(temp, ".cps");
+ _currentPicture = new Picture(this);
+ _currentPicture->loadPicture(temp);
+ _currentPicture->setupPalette();
+
+ strcpy(temp, state()->_locations[SceneId]._name);
+ strcat(temp, ".msc");
+ _currentMask = new Picture(this);
+ if (_currentMask->loadPicture(temp))
+ _pathFinding->init(_currentMask);
+
+ strcpy(temp, state()->_locations[SceneId]._name);
+ strcat(temp, ".tre");
+ _roomTexts = new TextResource(this);
+ _roomTexts->loadTextResource(temp);
+
+
+ strcpy(temp, state()->_locations[SceneId]._name);
+ strcat(temp, ".dat");
+ uint32 fileSize;
+ uint8 *sceneData = resources()->getFileData(temp, &fileSize);
+ if (sceneData) {
+ _roomScaleData = new uint8[fileSize];
+ memcpy(_roomScaleData, sceneData, fileSize);
+ }
+
+ strcpy(temp, state()->_locations[SceneId]._name);
+ strcat(temp, ".svi");
+ strcpy(temp2, createRoomFilename(Common::String::printf("%s.svl", _gameState->_locations[_gameState->_currentScene]._name).c_str()).c_str());
+ _audioManager->loadAudioPack(1, temp, temp2);
+ strcpy(temp, state()->_locations[SceneId]._name);
+ strcpy(temp2, state()->_locations[SceneId]._name);
+ strcat(temp, ".sei");
+ strcat(temp2, ".sel");
+ _audioManager->loadAudioPack(3, temp, temp2);
+
+ strcpy(temp, state()->_locations[SceneId]._name);
+ strcat(temp, ".ric");
+ if (state()->_locations[SceneId]._flags & 0x40) {
+ strcpy(temp2, state()->_locations[SceneId]._cutaway);
+ strcat(temp2, ".ric");
+ } else {
+ strcpy(temp2, "");
+ }
+ _hotspots->LoadRif(temp, temp2);
+ restoreRifFlags(_gameState->_currentScene);
+
+
+ strcpy(temp, state()->_locations[SceneId]._name);
+ strcat(temp, ".cnv");
+ uint32 convfileSize;
+ uint8 *convData = resources()->getFileData(temp, &convfileSize);
+ if (convData) {
+ assert(convfileSize < 4096 * sizeof(int16));
+ memcpy(_conversationData , convData, convfileSize);
+ prepareConversations();
+ }
+
+ // load script
+ strcpy(temp, state()->_locations[SceneId]._name);
+ strcat(temp, ".emc");
+
+ _oldTimer = _system->getMillis();
+ _oldTimer2 = _oldTimer;
+
+ // fix the weird scaling issue during one frame when entering new scene
+ _drew->update(0);
+ _flux->update(0);
+
+
+ _script->load(temp, &_scriptData, &_script_func->_opcodes);
+ _script->init(&_scriptState[0], &_scriptData);
+ _script->init(&_scriptState[1], &_scriptData);
+ _script->init(&_scriptState[2], &_scriptData);
+ _script->init(&_scriptState[3], &_scriptData);
+
+ //_script->RoomScript->Decompile("decomp.txt");
+ //RoomScript->Decompile2("decomp2.txt");
+
+ for (int i = 0; i < state()->_locations[SceneId]._numSceneAnimations; i++) {
+ _sceneAnimationScripts[i]._data = &_scriptData;
+ _script->init(&_sceneAnimationScripts[i]._state, _sceneAnimationScripts[i]._data);
+ if (!forGameLoad) {
+ _script->start(&_sceneAnimationScripts[i]._state, 9 + i);
+ _sceneAnimationScripts[i]._lastTimer = getSystem()->getMillis();
+ _sceneAnimationScripts[i]._frozen = false;
+ _sceneAnimationScripts[i]._frozenForConversation = false;
+ }
+ }
+
+ // launch mus
+#if 0
+ SoundManager.StopMusic();
+ SoundManager.UnloadMusic();
+ SoundManager.LoadMusic(GameLocations[Scene].name, GameLocations[Scene].mus);
+ SoundManager.PlayMusic();
+#endif
+
+ playRoomMusic();
+
+ _lastProcessedSceneScript = 0;
+ _gameState->_locations[SceneId]._visited = true;
+
+
+ setupGeneralPalette();
+ createShadowLUT();
+
+ state()->_mouseHidden = false;
+
+ if (!forGameLoad) {
+
+ _script->start(&_scriptState[0], 0);
+
+ while (_script->run(&_scriptState[0]))
+ waitForScriptStep();
+
+ _script->start(&_scriptState[0], 8);
+
+ while (_script->run(&_scriptState[0]))
+ waitForScriptStep();
+
+ if (_gameState->_nextSpecialEnterX != -1 && _gameState->_nextSpecialEnterY != -1) {
+ _drew->setPosition(_gameState->_nextSpecialEnterX, _gameState->_nextSpecialEnterY);
+ _gameState->_nextSpecialEnterX = -1;
+ _gameState->_nextSpecialEnterY = -1;
+ }
+
+ _script->start(&_scriptState[0], 3);
+
+ while (_script->run(&_scriptState[0]))
+ waitForScriptStep();
+
+ _script->start(&_scriptState[0], 4);
+
+ while (_script->run(&_scriptState[0]))
+ waitForScriptStep();
+
+ }
+}
+
+void ToonEngine::setupGeneralPalette() {
+ setPaletteEntries(_additionalPalette1, 232, 23);
+ setPaletteEntries(_universalPalette, 200, 32);
+ setPaletteEntries(_fluxPalette, 192, 8);
+
+ if (_drew)
+ _drew->setupPalette();
+}
+
+void ToonEngine::loadAdditionalPalette(Common::String fileName, int32 mode) {
+
+ uint32 size = 0;
+ uint8 *palette = resources()->getFileData(fileName, &size);
+ if (!palette)
+ return;
+
+ switch (mode) {
+ case 0:
+ memcpy(_additionalPalette1, palette, 69);
+ fixPaletteEntries(_additionalPalette1, 23);
+ break;
+ case 1:
+ memcpy(_additionalPalette2, palette, 69);
+ fixPaletteEntries(_additionalPalette2, 23);
+ break;
+ case 2:
+ memcpy(_cutawayPalette, palette, 768);
+ fixPaletteEntries(_cutawayPalette, 256);
+ break;
+ case 3:
+ memcpy(_universalPalette, palette, 96);
+ fixPaletteEntries(_universalPalette, 32);
+ break;
+ case 4:
+ memcpy(_fluxPalette, palette, 24);
+ fixPaletteEntries(_fluxPalette , 8);
+ break;
+ default:
+ warning("loadAdditionalPalette() - Unknown mode");
+ }
+}
+
+void ToonEngine::initChapter() {
+
+ EMCData data;
+ EMCState status;
+ memset(&data, 0, sizeof(data));
+ memset(&status, 0, sizeof(status));
+
+ _script = new EMCInterpreter(this);
+
+ _script->load("_START01.EMC", &data, &_script_func->_opcodes);
+ _script->init(&status, &data);
+ _script->start(&status, 0);
+ while (_script->run(&status))
+ waitForScriptStep();
+
+ setupGeneralPalette();
+
+}
+
+void ToonEngine::loadCursor() {
+ _cursorAnimation = new Animation(this);
+ _cursorAnimation->loadAnimation("MOUSE.CAF");
+ _cursorAnimationInstance = _animationManager->createNewInstance(kAnimationCursor);
+ _cursorAnimationInstance->setAnimation(_cursorAnimation);
+ _cursorAnimationInstance->setVisible(true);
+ _cursorAnimationInstance->setFrame(0);
+ _cursorAnimationInstance->setAnimationRange(0, 0);
+ _cursorAnimationInstance->setFps(8);
+
+ setCursor(5);
+}
+
+void ToonEngine::setCursor(int32 type, bool inventory, int32 offsetX, int offsetY) {
+
+ static const int32 offsets[] = {
+ 0, 1, 1, 6, 7, 1, 8, 10, 18, 10,
+ 28, 8, 36, 10, 46, 10, 56, 10, 66, 10,
+ 76, 10, 86, 10, 96, 10, 106, 10, 116, 10,
+ 126, 10
+ };
+
+ if (!inventory) {
+ _cursorAnimationInstance->setAnimation(_cursorAnimation);
+ _cursorAnimationInstance->setAnimationRange(offsets[type * 2 + 0], offsets[type * 2 + 0] + offsets[type * 2 + 1] - 1);
+ _cursorAnimationInstance->playAnimation();
+ } else {
+ _cursorAnimationInstance->setAnimation(_inventoryIcons);
+ _cursorAnimationInstance->setAnimationRange(type, type);
+ _cursorAnimationInstance->playAnimation();
+ }
+
+ _cursorOffsetX = offsetX;
+ _cursorOffsetY = offsetY;
+}
+
+void ToonEngine::setSceneAnimationScriptUpdate(bool enable) {
+ _animationSceneScriptRunFlag = enable;
+}
+
+bool ToonEngine::isUpdatingSceneAnimation() {
+ return _updatingSceneScriptRunFlag;
+}
+
+int32 ToonEngine::getCurrentUpdatingSceneAnimation() {
+ return _lastProcessedSceneScript;
+}
+
+int32 ToonEngine::randRange(int32 minStart, int32 maxStart) {
+ return _rnd.getRandomNumberRng(minStart, maxStart);
+}
+
+int32 ToonEngine::runEventScript(int32 x, int32 y, int32 mode, int32 id, int32 scriptId) {
+
+ if (_currentScriptRegion >= 4)
+ return 0;
+
+ EMCState *status = &_scriptState[_currentScriptRegion];
+ _script->init(status, &_scriptData);
+
+ // setup registers
+ status->regs[0] = x;
+ status->regs[1] = y;
+ status->regs[2] = 0;
+ status->regs[3] = 0;
+ status->regs[4] = _gameState->_mouseState; //
+ status->regs[5] = 0;
+ status->regs[6] = scriptId;
+ status->regs[7] = mode;
+ status->regs[8] = id;
+
+ _currentScriptRegion++;
+
+ _script->start(status, 1);
+ while (_script->run(status))
+ waitForScriptStep();
+
+ _currentScriptRegion--;
+
+ return status->regs[2];
+}
+
+void ToonEngine::clickEvent() {
+ bool leftButton = false;
+ bool rightButton = false;
+
+ if ((_lastMouseButton & 0x1) == 0 && (_mouseButton & 0x1) == 1)
+ leftButton = true;
+ if ((_lastMouseButton & 0x2) == 0 && (_mouseButton & 0x2) == 2)
+ rightButton = true;
+
+ _lastMouseButton = _mouseButton;
+ if (!leftButton && !rightButton)
+ return;
+
+ if (_gameState->_sackVisible) {
+ if (_mouseX > 0 && _mouseX < 40 && _mouseY > 356 && _mouseY < 396) {
+ if (_gameState->_mouseState >= 0 && !rightButton) {
+ addItemToInventory(_gameState->_mouseState);
+ setCursor(0, false, 0, 0);
+ _currentHotspotItem = 0;
+ return;
+ } else {
+ showInventory();
+ }
+ return;
+ }
+ }
+
+ // with inventory
+ if (rightButton && _gameState->_mouseState >= 0) {
+ addItemToInventory(_gameState->_mouseState);
+ setCursor(0, false, 0, 0);
+ _currentHotspotItem = 0;
+ return;
+ }
+
+
+ int32 mouseX = _mouseX;
+ if (_gameState->_inCutaway) {
+ mouseX += 1280;
+ }
+
+ // find hotspot
+ int32 hot = _hotspots->Find(mouseX + state()->_currentScrollValue , _mouseY);
+ HotspotData *currentHot = 0;
+ if (hot > -1) {
+ currentHot = _hotspots->Get(hot);
+ }
+
+ if (_currentHotspotItem == -3) {
+ if (_gameState->_mouseState <= 0) {
+ if (leftButton)
+ createMouseItem(104);
+ else
+ characterTalk(518);
+ }
+ }
+ if (_currentHotspotItem == -4) {
+ if (_gameState->_mouseState >= 0) {
+ if (leftButton)
+ if (!handleInventoryOnInventory(0, _gameState->_mouseState)) {
+ playSoundWrong();
+ }
+ return;
+ }
+ }
+
+
+ if (!currentHot) {
+ int32 xx, yy;
+
+ if (_gameState->_inCutaway || _gameState->_inInventory || _gameState->_inCloseUp)
+ return;
+
+ if (_pathFinding->findClosestWalkingPoint(_mouseX + _gameState->_currentScrollValue , _mouseY, &xx, &yy))
+ _drew->walkTo(xx, yy);
+ return;
+ }
+
+ int commandId = 0;
+ if (_gameState->_mouseState < 0) {
+ // left or right click
+ if (rightButton)
+ commandId = 2 + 8;
+ else
+ commandId = 0 + 8;
+ } else {
+ commandId = 2 * (_gameState->_mouseState - 1) + 16;
+ }
+
+ _drew->stopWalk();
+
+ int16 command = currentHot->getData(commandId);
+ int16 argument = currentHot->getData(commandId + 1);
+ int16 priority = currentHot->getPriority();
+// Strangerke - Commented (not used)
+// int16 ref = currentHot->getRef();
+// int16 pad1 = currentHot->getData(6);
+
+ if (!_gameState->_inCutaway && !_gameState->_inCloseUp) {
+ if (leftButton && (currentHot->getData(4) != 2 || _gameState->_mouseState >= 0) && currentHot->getData(5) != -1) {
+ if (currentHot->getData(5)) {
+ if (!_drew->walkTo(currentHot->getData(5), currentHot->getData(6))) {
+ // walk was canceled ?
+ return;
+ }
+ } else {
+ if (!_drew->walkTo(_mouseX, _mouseY)) {
+ // walk was canceled ?
+ return;
+ }
+ }
+ }
+ }
+
+ int32 result = 0;
+
+ switch (command) {
+ case 1:
+ sayLines(1, argument);
+ break;
+ case 2:
+ result = runEventScript(_mouseX, _mouseY, command, argument, priority);
+ break;
+ case 3:
+ runEventScript(_mouseX, _mouseY, command, argument, priority);
+ result = 0;
+ break;
+ case 4:
+ playSFX(argument, 128);
+ break;
+ case 5:
+ break;
+ case 6:
+ createMouseItem(argument);
+ currentHot->setData(7, -1);
+ break;
+ case 7:
+ // switch to CloseUp
+// Strangerke - Commented (not used)
+// int closeup = 1;
+ break;
+ case 8:
+ // face flux
+ sayLines(1, argument);
+ break;
+ case 9:
+ case 10:
+// Strangerke - Commented (not used)
+// if (rand() % 1 == 1) {
+// } else {
+// }
+ // setFluxFacingPoint(x,y)
+ sayLines(2, argument);
+ break;
+ case 11:
+ sayLines(3, argument);
+ break;
+ default:
+ playSoundWrong();
+ return;
+ }
+
+ if (result == 3) {
+ int32 val = _scriptState[_currentScriptRegion].regs[4];
+ currentHot->setData(4, currentHot->getData(4) & val);
+ }
+ if (result == 2 || result == 3) {
+ int32 val = _scriptState[_currentScriptRegion].regs[6];
+ currentHot->setData(7, val);
+ }
+
+ if (result == 1) {
+ int32 val = _scriptState[_currentScriptRegion].regs[4];
+ currentHot->setData(4, currentHot->getData(4) & val);
+ }
+
+}
+
+void ToonEngine::selectHotspot() {
+ int32 x1 = 0;
+ int32 x2 = 0;
+ int32 y1 = 0;
+ int32 y2 = 0;
+
+ int32 mouseX = _mouseX;
+
+ if (_gameState->_inCutaway)
+ mouseX += 1280;
+
+ if (_gameState->_sackVisible) {
+ if (_mouseX > 0 && _mouseX < 40 && _mouseY > 356 && _mouseY < 396) {
+ _currentHotspotItem = -2;
+
+ if (_gameState->_mouseState < 0) {
+ int mode = 3;
+ setCursor(mode);
+ } else {
+ setCursor(_gameState->_mouseState, true, -18, -14);
+ }
+
+ return;
+ }
+ }
+
+ if (_gameState->_mouseState > 0) {
+ // picked drew?
+ getDrew()->getAnimationInstance()->getRect(&x1, &y1, &x2, &y2);
+ if (_mouseX + _gameState->_currentScrollValue >= x1 && _mouseX + _gameState->_currentScrollValue <= x2 && _mouseY >= y1 && _mouseY <= y2) {
+ _currentHotspotItem = -4;
+ return;
+ }
+ }
+
+ if (getFlux()->getVisible()) {
+ getFlux()->getAnimationInstance()->getRect(&x1, &y1, &x2, &y2);
+ if (_mouseX + _gameState->_currentScrollValue >= x1 && _mouseX + _gameState->_currentScrollValue <= x2 && _mouseY >= y1 && _mouseY <= y2) {
+ _currentHotspotItem = -3;
+
+ if (_gameState->_mouseState < 0) {
+ int mode = 3;
+ setCursor(mode);
+ } else {
+ setCursor(_gameState->_mouseState, true, -18, -14);
+ }
+
+ return;
+ }
+ }
+
+ int32 hot = _hotspots->Find(mouseX + state()->_currentScrollValue, _mouseY);
+ if (hot != -1) {
+ HotspotData *hotspot = _hotspots->Get(hot);
+ int32 item = hotspot->getData(14);
+ if (hotspot->getType() == 3)
+ item += 2000;
+
+ // update palette based on ticks if we're in "use from inventory mode"
+ if (_gameState->_mouseState >= 0) {
+
+ int32 tick = _system->getMillis() / _tickLength;
+ int32 animReverse = tick & 0x10;
+ int32 animStep = tick & 0xf;
+
+ byte color[3];
+ if (animReverse == 0) {
+ color[0] = 16 * animStep;
+ color[1] = 0;
+ color[2] = 0;
+ } else {
+ color[0] = 16 * (15 - animStep);
+ color[1] = 0;
+ color[2] = 0;
+ }
+ setPaletteEntries(color, 255, 1);
+ }
+
+#if 0
+ if (item == _currentHotspotItem)
+ return;
+#endif
+ _currentHotspotItem = item;
+ if (_gameState->_mouseState < 0) {
+ int mode = hotspot->getMode();
+ setCursor(mode);
+ } else {
+ setCursor(_gameState->_mouseState, true, -18, -14);
+ }
+ } else {
+ _currentHotspotItem = 0;
+
+ if (_gameState->_mouseState < 0) {
+ setCursor(0);
+ } else {
+ byte color[3];
+ color[0] = 0;
+ color[1] = 0;
+ color[2] = 0;
+ setCursor(_gameState->_mouseState, true, -18, -14);
+ setPaletteEntries(color, 255, 1);
+ }
+ }
+}
+
+void ToonEngine::exitScene() {
+
+ fadeOut(5);
+
+ // disable all scene animation
+ for (int32 i = 0; i < 64; i++) {
+ if (_sceneAnimations[i]._active) {
+ delete _sceneAnimations[i]._animation;
+ _sceneAnimations[i]._active = false;
+ _animationManager->removeInstance(_sceneAnimations[i]._animInstance);
+ _sceneAnimations[i]._animInstance = 0;
+ _sceneAnimations[i]._animation = 0;
+ }
+ }
+ for (int32 i = 0; i < 64; i++) {
+ _sceneAnimationScripts[i]._frozen = true;
+ _sceneAnimationScripts[i]._active = false;
+ }
+
+ // remove all characters except drew and flux
+ for (int32 i = 0; i < 8; i++) {
+ if (_characters[i] != _drew && _characters[i] != _flux) {
+ if (_characters[i]) {
+ delete _characters[i];
+ _characters[i] = 0;
+ }
+ } else {
+ _characters[i]->stopSpecialAnim();
+ }
+ }
+
+ for (int32 i = 0; i < 2; i++) {
+ _gameState->_timerEnabled[i] = false;
+ }
+
+ // put back our item if inventory if needed
+ if (_gameState->_mouseState >= 0) {
+ addItemToInventory(_gameState->_mouseState);
+ _gameState->_mouseState = -1;
+ }
+
+ _audioManager->killAllAmbientSFX();
+ _audioManager->stopAllSfxs();
+ _audioManager->stopCurrentVoice();
+ _currentTextLine = 0;
+ _currentTextLineId = -1;
+ _currentTextLineCharacterId = 0;
+
+ char temp[256];
+ strcpy(temp, createRoomFilename(Common::String::printf("%s.pak", _gameState->_locations[_gameState->_currentScene]._name).c_str()).c_str());
+ resources()->closePackage(temp);
+
+
+ _drew->stopWalk();
+ _flux->stopWalk();
+
+ storeRifFlags(_gameState->_currentScene);
+}
+
+// flip between the cutaway scene and the normal scene
+void ToonEngine::flipScreens() {
+ _gameState->_inCloseUp = !_gameState->_inCloseUp;
+
+ if (_gameState->_inCloseUp) {
+ _gameState->_currentScrollValue = 640;
+ setPaletteEntries(_cutawayPalette, 1, 128);
+ setPaletteEntries(_additionalPalette2, 232, 23);
+ } else {
+ _gameState->_currentScrollValue = 0;
+ _currentPicture->setupPalette();
+ setupGeneralPalette();
+ }
+ flushPalette();
+}
+
+void ToonEngine::fadeIn(int32 numFrames) {
+ for (int32 f = 0; f < numFrames; f++) {
+
+ uint8 vmpalette[1024];
+ for (int32 i = 0; i < 256; i++) {
+ vmpalette[i*4+0] = f * _finalPalette[i*3+0] / (numFrames - 1);
+ vmpalette[i*4+1] = f * _finalPalette[i*3+1] / (numFrames - 1);
+ vmpalette[i*4+2] = f * _finalPalette[i*3+2] / (numFrames - 1);
+ vmpalette[i*4+3] = 0;
+ }
+ _system->setPalette(vmpalette, 0, 256);
+ _system->updateScreen();
+ _system->delayMillis(_tickLength);
+ }
+}
+
+void ToonEngine::fadeOut(int32 numFrames) {
+ for (int32 f = 0; f < numFrames; f++) {
+
+ uint8 vmpalette[1024];
+ for (int32 i = 0; i < 256; i++) {
+ vmpalette[i*4+0] = (numFrames - f - 1) * _finalPalette[i*3+0] / (numFrames - 1);
+ vmpalette[i*4+1] = (numFrames - f - 1) * _finalPalette[i*3+1] / (numFrames - 1);
+ vmpalette[i*4+2] = (numFrames - f - 1) * _finalPalette[i*3+2] / (numFrames - 1);
+ vmpalette[i*4+3] = (numFrames - f - 1);
+ }
+ _system->setPalette(vmpalette, 0, 256);
+ _system->updateScreen();
+ _system->delayMillis(_tickLength);
+ }
+}
+
+void ToonEngine::initFonts() {
+ _fontRenderer = new FontRenderer(this);
+ _fontToon = new Animation(this);
+ _fontToon->loadAnimation("misc/toonfont.caf");
+
+ _fontEZ = new Animation(this);
+ _fontEZ->loadAnimation("misc/ezfont.caf");
+}
+
+void ToonEngine::drawInfoLine() {
+ if (_currentHotspotItem != 0 && !_gameState->_mouseHidden && !_gameState->_inConversation) {
+ const char *infoTool = NULL;
+ if (_currentHotspotItem >= 0 && _currentHotspotItem < 2000) {
+ infoTool = _roomTexts->getText(_currentHotspotItem);
+ } else if (_currentHotspotItem <= -1) {
+// static const char * const specialInfoLine[] = { "Exit non defined", "Bottomless Bag", "Flux", "Drew Blanc" };
+ infoTool = _specialInfoLine[-1 - _currentHotspotItem];
+ } else {
+ int32 loc = _currentHotspotItem - 2000;
+ // location names are hardcoded ...
+ infoTool = getLocationString(loc, _gameState->_locations[loc]._visited);
+ }
+ if (infoTool) {
+ _fontRenderer->setFontColor(0xc8, 0xdd, 0xe3);
+ _fontRenderer->setFont(_fontToon);
+ _fontRenderer->renderText(320 + _gameState->_currentScrollValue, 398, infoTool, 5);
+ }
+ }
+}
+
+const char *ToonEngine::getLocationString(int32 locationId, bool alreadyVisited) {
+ if (alreadyVisited)
+ return _locationDirVisited[locationId];
+ else
+ return _locationDirNotVisited[locationId];
+}
+
+int32 ToonEngine::getScaleAtPoint(int32 x, int32 y) {
+ if (!_currentMask)
+ return 1024;
+
+ int32 maskData = _currentMask->getData(x, y) & 0x1f;
+ return _roomScaleData[maskData+2] * 1024 / 100;
+}
+
+int32 ToonEngine::getLayerAtPoint(int32 x, int32 y) {
+ if (!_currentMask)
+ return 0;
+
+ int32 maskData = _currentMask->getData(x, y) & 0x1f;
+ return _roomScaleData[maskData+130] << 5;
+}
+
+int32 ToonEngine::getZAtPoint(int32 x, int32 y) {
+ if (!_currentMask)
+ return 0;
+ return _currentMask->getData(x, y) & 0x1f;
+}
+
+void ToonEngine::storeRifFlags(int32 location) {
+
+ if (_gameState->_locations[location]._numRifBoxes != _hotspots->getCount()) {
+ _gameState->_locations[location]._numRifBoxes = _hotspots->getCount();
+ }
+
+ for (int32 i = 0; i < _hotspots->getCount(); i++) {
+ _gameState->_locations[location]._rifBoxesFlags[i * 2 + 0] = _hotspots->Get(i)->getData(4);
+ _gameState->_locations[location]._rifBoxesFlags[i * 2 + 1] = _hotspots->Get(i)->getData(7);
+ }
+}
+
+void ToonEngine::restoreRifFlags(int32 location) {
+ if (_hotspots) {
+ if (!_gameState->_locations[location]._visited) {
+ for (int32 i = 0; i < _hotspots->getCount(); i++) {
+ _gameState->_locations[location]._rifBoxesFlags[i * 2 + 0] = _hotspots->Get(i)->getData(4);
+ _gameState->_locations[location]._rifBoxesFlags[i * 2 + 1] = _hotspots->Get(i)->getData(7);
+ }
+ _gameState->_locations[location]._numRifBoxes = _hotspots->getCount();
+ } else {
+ if (_gameState->_locations[location]._numRifBoxes != _hotspots->getCount())
+ return;
+
+ for (int32 i = 0; i < _hotspots->getCount(); i++) {
+ _hotspots->Get(i)->setData(4, _gameState->_locations[location]._rifBoxesFlags[i * 2 + 0]);
+ _hotspots->Get(i)->setData(7, _gameState->_locations[location]._rifBoxesFlags[i * 2 + 1]);
+ }
+ }
+ }
+}
+
+void ToonEngine::sayLines(int numLines, int dialogId) {
+ // exit conversation state
+
+ // if (inInventory)
+ // character_talks(dialogid, -1, 0, 0);
+ // else
+
+#if 0
+ int oldShowMouse = 0;
+
+ if (Game.MouseHiddenCount <= 0) {
+ Game.MouseHiddenCount = 1;
+ oldShowMouse = 1;
+ }
+#endif
+
+ int32 currentLine = dialogId;
+
+ for (int32 i = 0; i < numLines; i++) {
+ if (!characterTalk(currentLine))
+ break;
+
+ while (_audioManager->voiceStillPlaying() && !_shouldQuit)
+ doFrame();
+
+ // find next line
+ if (currentLine < 1000)
+ currentLine = _roomTexts->getNext(currentLine);
+ else
+ currentLine = _genericTexts->getNext(currentLine - 1000) + 1000;
+ }
+
+#if 0
+ if (oldShowMouse)
+ Game.MouseHiddenCount = 0;
+#endif
+
+}
+
+int32 ToonEngine::simpleCharacterTalk(int32 dialogid) {
+ int32 myId = 0;
+
+// Strangerke - Commented (not used)
+#if 0
+ char *myLine;
+ if (dialogid < 1000) {
+ myLine = _roomTexts->getText(dialogid);
+ myId = dialogid;
+ } else {
+ myLine = _genericTexts->getText(dialogid - 1000);
+ myId = dialogid - 1000;
+ }
+ debugC(0, 0xfff, "Talker = %d will say '%s' \n", READ_LE_UINT16(c - 2), myLine);
+#endif
+
+ if (_audioManager->voiceStillPlaying())
+ _audioManager->stopCurrentVoice();
+
+ if (dialogid < 1000) {
+ myId = _roomTexts->getId(dialogid);
+ _audioManager->playVoice(myId, false);
+ } else {
+ myId = _genericTexts->getId(dialogid - 1000);
+ _audioManager->playVoice(myId, true);
+ }
+
+ return 1;
+}
+
+void ToonEngine::playTalkAnimOnCharacter(int32 animID, int32 characterId, bool talker) {
+ if (animID || talker) {
+// Strangerke - Commented (not used)
+#if 0
+ if (_gameState->_inCutaway || _gameState->_inInventory) {
+ if (talker) {
+ // character talks
+ }
+ } else
+#endif
+ if (characterId == 0) {
+ _drew->playAnim(animID, 0, (talker ? 8 : 0) + 2);
+ } else if (characterId == 1) {
+ // stop flux if he is walking
+ if (_flux->getFlag() & 1) {
+ _flux->stopWalk();
+ }
+ _flux->playAnim(animID, 0, (talker ? 8 : 0) + 2);
+ _flux->setFlag(_flux->getFlag() | 1);
+ } else {
+ Character *character = getCharacterById(characterId);
+ if (character) {
+ character->playAnim(animID, 0, (talker ? 8 : 0) + 2);
+ }
+ }
+ } else {
+ Character *character = getCharacterById(characterId);
+ if (character)
+ character->setAnimFlag(character->getAnimFlag() | 1);
+ }
+}
+
+int32 ToonEngine::characterTalk(int32 dialogid, bool blocking) {
+ if (blocking == false && _audioManager->voiceStillPlaying()) {
+ if (_currentTextLineCharacterId == 0 || _currentTextLineCharacterId == 1) {
+ // Drew or Flux is already talking, and this voice is not important
+ // skip it
+ return 0;
+ }
+ }
+
+ int32 myId = 0;
+ char *myLine;
+ if (dialogid < 1000) {
+ myLine = _roomTexts->getText(dialogid);
+ myId = dialogid;
+ } else {
+ myLine = _genericTexts->getText(dialogid - 1000);
+ myId = dialogid - 1000;
+ }
+
+ if (!myLine)
+ return 0;
+
+ bool oldMouseHidden = _gameState->_mouseHidden;
+ if (blocking) {
+ _gameState->_mouseHidden = true;
+ }
+
+
+ // get what is before the string
+ int a = READ_LE_UINT16(myLine - 2);
+ char *b = myLine - 2 - 4 * a;
+
+ char *c = b - 2; // v6
+ int numParticipants = READ_LE_UINT16(c); // num dialogue participants
+
+ char *e = c - 2 - 4 * numParticipants;
+ READ_LE_UINT16(e);
+
+// Strangerke - Commented (not used)
+// char *g = e - 2 * f;
+
+ // flag as talking
+// Strangerke - Commented (not used)
+// char *h = c;
+
+
+ // if one voice is still playing, wait !
+ if (blocking) {
+ while (_audioManager->voiceStillPlaying() && !_shouldQuit)
+ doFrame();
+
+ char *cc = c;
+ Character *waitChar;
+ for (int32 i = 0; i < numParticipants - 1; i++) {
+ // listener
+ int32 listenerId = READ_LE_UINT16(cc - 2);
+ cc -= 4;
+ waitChar = getCharacterById(listenerId);
+ if (waitChar) {
+ while ((waitChar->getAnimFlag() & 0x10) == 0x10 && !_shouldQuit)
+ doFrame();
+ }
+
+ }
+ int32 talkerId = READ_LE_UINT16(cc - 2);
+
+ waitChar = getCharacterById(talkerId);
+ if (waitChar && !_gameState->_inInventory) {
+ while ((waitChar->getAnimFlag() & 0x10) == 0x10 && !_shouldQuit)
+ doFrame();
+ }
+ } else {
+ if (_audioManager->voiceStillPlaying())
+ _audioManager->stopCurrentVoice();
+ }
+
+ for (int32 i = 0; i < numParticipants - 1; i++) {
+ // listener
+ int32 listenerId = READ_LE_UINT16(c - 2);
+ int32 listenerAnimId = READ_LE_UINT16(c - 4);
+ if (blocking) playTalkAnimOnCharacter(listenerAnimId, listenerId, false);
+ c -= 4;
+ }
+
+ int32 talkerId = READ_LE_UINT16(c - 2);
+ int32 talkerAnimId = READ_LE_UINT16(c - 4);
+
+ _currentTextLine = myLine;
+ _currentTextLineCharacterId = talkerId;
+ _currentTextLineId = dialogid;
+
+ if (blocking) {
+ Character *character = getCharacterById(talkerId);
+ if (character)
+ character->setTalking(true);
+
+ playTalkAnimOnCharacter(talkerAnimId, talkerId, true);
+
+ // set once more the values, they may have been overwritten when the engine
+ // waits for the character to be ready.
+ _currentTextLine = myLine;
+ _currentTextLineCharacterId = talkerId;
+ _currentTextLineId = dialogid;
+
+
+ } else {
+ Character *character = getCharacterById(talkerId);
+ if (character)
+ character->stopSpecialAnim();
+ }
+
+ debugC(0, 0xfff, "Talker = %d (num participants : %d) will say '%s'", talkerId , numParticipants, myLine);
+
+
+ getTextPosition(talkerId, &_currentTextLineX, &_currentTextLineY);
+
+ if (dialogid < 1000) {
+ myId = _roomTexts->getId(dialogid);
+ _audioManager->playVoice(myId, false);
+ } else {
+ myId = _genericTexts->getId(dialogid - 1000);
+ _audioManager->playVoice(myId, true);
+ }
+
+ if (blocking) {
+ while (_audioManager->voiceStillPlaying() && !_shouldQuit)
+ doFrame();
+ _gameState->_mouseHidden = oldMouseHidden && _gameState->_mouseHidden;
+
+ Character *character = getCharacterById(talkerId);
+ if (character)
+ character->setTalking(false);
+ }
+
+
+ return 1;
+}
+
+void ToonEngine::haveAConversation(int32 convId) {
+ setCursor(0);
+
+ _gameState->_inConversation = true;
+ _gameState->_showConversationIcons = false;
+ _gameState->_exitConversation = false;
+ _gameState->_sackVisible = false;
+ Conversation *conv = &state()->_conversationState[convId];
+ _gameState->_currentConversationId = convId;
+
+ // change the music to the "conversation" music if needed.
+ playRoomMusic();
+
+ if (conv->_enable) {
+ // fix dialog script based on new flags
+ for (int32 i = 0; i < 10; i++) {
+ if (conv->state[i]._data2 == 1 || conv->state[i]._data2 == 3) {
+ if (getConversationFlag(_gameState->_currentScene, conv->state[i]._data3))
+ conv->state[i]._data2 = 1;
+ else
+ conv->state[i]._data2 = 3;
+ }
+ }
+
+ // if current voice stream sub 15130
+ processConversationClick(conv , 2);
+ doFrame();
+ }
+
+
+ _mouseButton = 0;
+ _gameState->_firstConverstationLine = true;
+
+ while (!_gameState->_exitConversation && !_shouldQuit) {
+ _gameState->_mouseHidden = false;
+ _gameState->_showConversationIcons = true;
+ int32 oldMouseButton = _mouseButton;
+ while (!_shouldQuit) {
+ doFrame();
+
+ if (_mouseButton != 0) {
+ if (!oldMouseButton)
+ break;
+ } else {
+ oldMouseButton = 0;
+ }
+ }
+ int selected = -1;
+ int a = 0;
+ for (int i = 0; i < 10; i++) {
+ if (conv->state[i]._data2 == 1) {
+ if (_mouseX > 50 + a * 60 && _mouseX < 100 + a * 60 && _mouseY >= 336 && _mouseY <= 386) {
+ selected = i;
+ break;
+ }
+ a++;
+ }
+ }
+ if (_shouldQuit) return;
+ _gameState->_showConversationIcons = false;
+ _gameState->_mouseHidden = 1;
+
+
+ if (selected < 0 || selected == 1 || selected == 3) {
+ if (_gameState->_firstConverstationLine)
+ processConversationClick(conv, 3);
+ else
+ processConversationClick(conv, 1);
+ break;
+ } else {
+ processConversationClick(conv, selected);
+ }
+ }
+
+// Strangerke - Commented (not used)
+// int cur = 0;
+
+ for (int i = 0; i < 10; i++) {
+ if (conv->state[i]._data2 == 2) {
+ if (i != 3)
+ conv->state[i]._data2 = 1;
+ }
+ }
+
+ _gameState->_exitConversation = false;
+ _gameState->_inConversation = false;
+ _gameState->_currentConversationId = -1;
+ _gameState->_mouseHidden = false;
+ _gameState->_sackVisible = true;
+
+ // switch back to original music
+ playRoomMusic();
+
+}
+
+void ToonEngine::drawConversationIcons() {
+ if (!_gameState->_inConversation || !_gameState->_showConversationIcons)
+ return;
+ int32 aa = 50 + _gameState->_currentScrollValue;
+ for (int32 i = 0; i < 10; i++) {
+ if (_gameState->_conversationState[_gameState->_currentConversationId].state[i]._data2 == 1) {
+ _dialogIcons->drawFrame(*_mainSurface, (i + _gameState->_currentScene) & 7, aa, 336);
+ _dialogIcons->drawFrame(*_mainSurface, 7 + _gameState->_conversationState[_gameState->_currentConversationId].state[i]._data3, aa, 339);
+ aa += 60;
+ }
+ }
+}
+
+void ToonEngine::prepareConversations() {
+ Conversation *allConvs = _gameState->_conversationState;
+ for (int32 i = 0; i < 60; i++) {
+
+ allConvs[i].state[0]._data2 = 1;
+ if (!allConvs[i].state[0]._data3) {
+ allConvs[i].state[0]._data3 = 1;
+ }
+ allConvs[i].state[1]._data2 = 1;
+ allConvs[i].state[1]._data3 = 6;
+ allConvs[i].state[3]._data2 = 2;
+
+ }
+ int numConversations = READ_LE_UINT16(_conversationData + 1);
+ int16 *curConversation = _conversationData + 3;
+ for (int i = 0; i < numConversations; i++) {
+ Conversation *conv = &allConvs[ READ_LE_UINT16(curConversation)];
+ if (!conv->_enable) {
+
+ conv->_enable = 1;
+
+ int16 offset1 = READ_LE_UINT16(curConversation + 1);
+ void *convData1 = (char *)_conversationData + offset1;
+ conv->state[0]._data4 = convData1;
+
+ int16 offset2 = READ_LE_UINT16(curConversation + 2);
+ void *convData2 = (char *)_conversationData + offset2;
+ conv->state[1]._data4 = convData2;
+
+ int16 offset3 = READ_LE_UINT16(curConversation + 3);
+ void *convData3 = (char *)_conversationData + offset3;
+ conv->state[2]._data4 = convData3;
+
+ int16 offset4 = READ_LE_UINT16(curConversation + 4);
+ void *convData4 = (char *)_conversationData + offset4;
+ conv->state[3]._data4 = convData4;
+ }
+ curConversation += 5;
+ }
+}
+
+void ToonEngine::processConversationClick(Conversation *conv, int32 status) {
+ Conversation::ConvState *v2 = (Conversation::ConvState *)&conv->state[status];
+
+ int16 *i = (int16 *)((char *)v2->_data4 + 2);
+
+ _gameState->_firstConverstationLine = false;
+ while (READ_LE_INT16(i) >= 0) {
+ if (READ_LE_INT16(i) < 100) {
+ if (_gameState->_exitConversation == false) {
+ characterTalk(READ_LE_INT16(i + 1));
+ }
+ } else {
+ runConversationCommand(&i);
+ }
+ i += 2;
+ }
+
+ int16 command = READ_LE_INT16(i);
+ int16 value = READ_LE_INT16(i + 1);
+
+ if (command == -1) {
+ v2->_data2 = 0;
+ } else if (command == -2) {
+ v2->_data4 = (char *)_conversationData + value;
+ v2->_data3 = READ_LE_INT16(v2->_data4);
+ } else if (command == -3) {
+ v2->_data2 = 2;
+ v2->_data4 = (char *)_conversationData + value;
+ v2->_data3 = READ_LE_INT16(v2->_data4);
+ }
+
+ int16 *v7 = i + 2;
+ int16 v8 = READ_LE_INT16(v7);
+ if (v8 == -1) {
+ _gameState->_mouseHidden = false;
+ } else {
+retry:
+ while (1) {
+ v7 += 1;
+ int16 *v14 = (int16 *)((char *)_conversationData + v8);
+
+ // find free dialogue slot
+ for (int j = 0; j < 10; j++) {
+ if (!conv->state[j]._data2) {
+ conv->state[j]._data3 = READ_LE_INT16(v14);
+ conv->state[j]._data4 = v14;
+ if (getConversationFlag(_gameState->_currentScene, conv->state[j]._data3))
+ conv->state[j]._data2 = 1;
+ else
+ conv->state[j]._data2 = 3;
+
+ v8 = READ_LE_INT16(v7);
+ if (v8 == -1)
+ return;
+
+ goto retry;
+ }
+ }
+
+ if (v8 != -1)
+ continue;
+
+ break;
+ }
+ }
+
+}
+
+// hardcoded conversation flag to know if one dialogue icon must be displayed or not
+// based on game events...
+int32 ToonEngine::getConversationFlag(int32 locationId, int32 param) {
+ if (locationId == 1) {
+ if (param == 0x34)
+ return _gameState->getGameFlag(93);
+
+ if (param != 55)
+ return 1;
+
+ if (!_gameState->getGameFlag(262))
+ return 1;
+
+ return 0;
+ } else if (locationId == 2) {
+ if (param == 36 && _gameState->getGameFlag(149))
+ return 0;
+ return 1;
+ } else if (locationId == 7) {
+ if (param == 30)
+ return _gameState->getGameFlag(132);
+ else
+ return 1;
+ } else if (locationId == 8) {
+ if (param == 0x20) {
+ if (!_gameState->getGameFlag(73) && !_gameState->getGameFlag(151) && !_gameState->getGameFlag(152) && !_gameState->getGameFlag(153))
+ return 1;
+ return 0;
+ }
+ if (param == 33) {
+ if (!_gameState->getGameFlag(73) && !_gameState->getGameFlag(151) && !_gameState->getGameFlag(152) && !_gameState->getGameFlag(153))
+ return 0;
+ return 1;
+ }
+ } else if (locationId == 0xb) {
+ if (param == 0x12) {
+ if (!_gameState->hasItemInInventory(71))
+ return 1;
+ else
+ return 0;
+ }
+ if (param == 74) {
+ if (_gameState->hasItemInInventory(71))
+ return 1;
+ else
+ return 0;
+ }
+ return 1;
+ } else if (locationId == 0xc) {
+ if (param == 0x3d && _gameState->getGameFlag(154)) {
+ return 0;
+ }
+ if (param == 76 && !_gameState->getGameFlag(79)) {
+ return 0;
+ }
+ if (param == 0x4e && !_gameState->hasItemInInventory(32)) {
+ return 0;
+ }
+ if (param == 0x4f && !_gameState->hasItemInInventory(92)) {
+ return 0;
+ }
+ if (param == 80 && !_gameState->hasItemInInventory(91)) {
+ return 0;
+ }
+ if (param == 0x4d && _gameState->getGameFlag(79)) {
+ return 0;
+ }
+ } else if (locationId == 0xd) {
+ if (param == 0x2f && _gameState->getGameFlag(81)) {
+ return 0;
+ }
+ if (param == 48 && _gameState->getGameFlag(81)) {
+ return 0;
+ }
+ } else if (locationId == 0x10) {
+ switch (param) {
+ case 0x3e8:
+ if (!(_gameState->_gameGlobalData[30] & 1))
+ return 0;
+ break;
+ case 0x3e9:
+ if (!(_gameState->_gameGlobalData[30] & 2))
+ return 0;
+ break;
+ case 0x3ea:
+ if (!(_gameState->_gameGlobalData[30] & 4))
+ return 0;
+ break;
+ case 0x3eb:
+ if (!(_gameState->_gameGlobalData[30] & 8))
+ return 0;
+ break;
+ case 0x3ec:
+ if (!(_gameState->_gameGlobalData[30] & 16))
+ return 0;
+ break;
+ case 0x3ed:
+ if (!(_gameState->_gameGlobalData[30] & 32))
+ return 0;
+ break;
+ case 0x3ee:
+ if (!(_gameState->_gameGlobalData[30] & 64))
+ return 0;
+ break;
+ default:
+ break;
+ };
+ return 1;
+ } else if (locationId == 0x12) {
+ if (param == 0x28 && _gameState->getGameFlag(91)) {
+ return 0;
+ }
+ if (param == 41 && (!_gameState->getGameFlag(96) || _gameState->getGameFlag(91))) {
+ return 0;
+ }
+ } else if (locationId == 0x13) {
+ if (param == 0x32 && _gameState->getGameFlag(107)) {
+ return 0;
+ }
+ if (param == 68 && !_gameState->getGameFlag(107)) {
+ return 0;
+ }
+ } else if (locationId == 0x14) {
+ if (param == 1000 && !_gameState->getGameFlag(82)) {
+ return 0;
+ }
+ } else if (locationId == 0x25) {
+ if (param == 7 && _gameState->_gameGlobalData[28] != 1) {
+ return 0;
+ }
+ if (param == 8 && _gameState->_gameGlobalData[28] != 1) {
+ return 0;
+ }
+ if (param == 9 && _gameState->_gameGlobalData[28] != 1) {
+ return 0;
+ }
+ if (param == 75 && _gameState->_gameGlobalData[28] != 2) {
+ return 0;
+ }
+ } else if (locationId == 72) {
+ if (param == 63 && _gameState->getGameFlag(105)) {
+ return 0;
+ }
+ if (param == 67 && !_gameState->getGameFlag(105)) {
+ return 0;
+ }
+ if (param == 0x40 && !_gameState->getGameFlag(105)) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+int32 ToonEngine::runConversationCommand(int16 **command) {
+
+ int16 *v5 = *command;
+
+ int v2 = READ_LE_INT16(v5);
+ int v4 = READ_LE_INT16(v5+1);
+ int result = v2 - 100;
+ switch (v2) {
+ case 100:
+ result = runEventScript(_mouseX, _mouseY, 2, v4, 0);
+ break;
+ case 101:
+ _gameState->_exitConversation = true;
+ break;
+ case 102:
+ playSoundWrong();
+ break;
+ case 104:
+ *command = (int16 *)((char *)_conversationData + v4);
+ *command = (int16 *)((char *)_conversationData + v4 - 4);
+ break;
+ //
+ case 105:
+ if (getConversationFlag(_gameState->_currentScene, v4)) {
+ result = READ_LE_INT16(*command + 4);
+ *command = (int16 *)((char *)_conversationData + result);
+ *command = (int16 *)((char *)_conversationData + result - 4);
+ } else {
+ int16 *newPtr = *command + 1;
+ *command = newPtr;
+ }
+ break;
+ case 103:
+ return result;
+ break;
+ }
+ return result;
+}
+
+int32 ToonEngine::waitTicks(int32 numTicks, bool breakOnMouseClick) {
+// Strangerke - Commented (not used)
+// Common::EventManager *_event = _system->getEventManager();
+
+ uint32 nextTime = _system->getMillis() + numTicks * _tickLength;
+ while (_system->getMillis() < nextTime || numTicks == -1) {
+ //if (!_animationSceneScriptRunFlag)
+ // break;
+ updateAnimationSceneScripts(0);
+ getMouseEvent();
+ simpleUpdate();
+
+ if (breakOnMouseClick && (_mouseButton & 0x2))
+ break;
+ }
+ return 0;
+}
+
+void ToonEngine::renderInventory() {
+ if (!_gameState->_inInventory)
+ return;
+
+ _inventoryPicture->draw(*_mainSurface, 0, 0, 0, 0);
+
+ // draw items on screen
+ for (int32 i = 0; i < _gameState->_numInventoryItems; i++) {
+ int32 x = 57 * (i % 7) + 114;
+ int32 y = ((9 * (i % 7)) & 0xf) + 56 * (i / 7) + 80;
+ _inventoryIconSlots->drawFrame(*_mainSurface, i % 12, x + _gameState->_currentScrollValue, y);
+ if (_gameState->_inventory[i])
+ _inventoryIcons->drawFrame(*_mainSurface, _gameState->_inventory[i], x + _gameState->_currentScrollValue + 2, y + 2);
+ }
+
+ drawConversationLine();
+ if (!_audioManager->voiceStillPlaying()) {
+ _currentTextLineCharacterId = -1;
+ _currentTextLine = 0;
+ _currentTextLineId = -1;
+ }
+
+ if (_firstFrame) {
+ copyToVirtualScreen(false);
+ _firstFrame = false;
+ fadeIn(5);
+ }
+ copyToVirtualScreen();
+}
+
+int32 ToonEngine::showInventory() {
+ int32 oldScrollValue = _gameState->_currentScrollValue;
+// Strangerke - Commented (not used)
+// Common::EventManager *_event = _system->getEventManager();
+ _inventoryPicture = new Picture(this);
+ fadeOut(5);
+ _inventoryPicture->loadPicture("SACK128.CPS", true);
+ _inventoryPicture->setupPalette();
+
+ if (_gameState->_mouseState >= 0) {
+ setCursor(_gameState->_mouseState, true, -18, -14);
+
+ // make sure we have a free spot
+ if (!_gameState->hasItemInInventory(0)) {
+ _gameState->_inventory[_gameState->_numInventoryItems] = 0;
+ _gameState->_numInventoryItems++;
+ }
+ } else {
+ setCursor(0);
+ }
+
+ _gameState->_inInventory = true;
+ _gameState->_currentScrollValue = 0;
+
+ int32 oldMouseButton = 0x3;
+ int32 justPressedButton = 0;
+ _firstFrame = true;
+
+ while (!_shouldQuit) {
+ getMouseEvent();
+
+ justPressedButton = _mouseButton & ~oldMouseButton;
+ oldMouseButton = _mouseButton;
+
+ if (justPressedButton & 0x3) {
+ // find out what object we're on
+ int32 foundObj = -1;
+ for (int32 i = 0; i < _gameState->_numInventoryItems; i++) {
+ int32 x = 57 * (i % 7) + 114;
+ int32 y = ((9 * (i % 7)) & 0xf) + 56 * (i / 7) + 80;
+ if (_mouseX >= (_gameState->_currentScrollValue + x - 6) &&
+ _mouseX <= (_gameState->_currentScrollValue + x + 44 + 7) &&
+ _mouseY >= y - 6 && _mouseY <= y + 50) {
+ foundObj = i;
+ break;
+ }
+ }
+
+ if (justPressedButton & 0x1) {
+ if (_gameState->_mouseState < 0) {
+ if (foundObj >= 0) {
+ // take an object
+ int32 item = _gameState->_inventory[foundObj];
+
+ int32 modItem = getSpecialInventoryItem(item);
+ if (modItem) {
+
+ if (modItem == -1) {
+ _gameState->_mouseState = item;
+ _gameState->_inventory[foundObj] = 0;
+ } else {
+ _gameState->_mouseState = modItem;
+ if (!_gameState->hasItemInInventory(0)) {
+ _gameState->_inventory[_gameState->_numInventoryItems] = 0;
+ _gameState->_numInventoryItems++;
+ }
+ }
+
+ setCursor(_gameState->_mouseState, true, -18, -14);
+ }
+
+ } else {
+ break;
+ }
+ } else {
+ if (foundObj >= 0 && _gameState->_inventory[foundObj] == 0) { // empty place
+ _gameState->_inventory[foundObj] = _gameState->_mouseState;
+ setCursor(0, false);
+ _gameState->_mouseState = -1;
+ } else if (foundObj >= 0 && _gameState->_inventory[foundObj] > 0) {
+ if (!handleInventoryOnInventory(_gameState->_mouseState, _gameState->_inventory[foundObj]))
+ playSoundWrong();
+ } else {
+ // quit the inventory mode with the icon
+ break;
+ }
+ }
+
+ } else if (justPressedButton & 0x2) { // right button
+ if (foundObj >= 0) {
+ // talk about the object
+ if (!handleInventoryOnInventory(_gameState->_inventory[foundObj], -1))
+ characterTalk(1000 + _gameState->_inventory[foundObj]);
+ } else {
+ // go out
+ break;
+ }
+ }
+ }
+
+ renderInventory();
+
+ }
+
+ _gameState->_currentScrollValue = oldScrollValue;
+ _gameState->_inInventory = false;
+ _mouseButton = 0;
+ _lastMouseButton = 0x3;
+
+ fadeOut(5);
+ if (_gameState->_inCloseUp) {
+ _gameState->_inCloseUp = false;
+ flipScreens();
+ } else if (_gameState->_inCutaway) {
+ _currentCutaway->setupPalette();
+ setupGeneralPalette();
+ } else {
+ _currentPicture->setupPalette();
+ setupGeneralPalette();
+ }
+ flushPalette();
+ _firstFrame = true;
+
+ return 0;
+}
+
+void ToonEngine::getMouseEvent() {
+ Common::EventManager *_event = _system->getEventManager();
+
+ Common::Event event;
+ while (_event->pollEvent(event) && !_shouldQuit)
+ ;
+
+ _mouseX = _event->getMousePos().x;
+ _mouseY = _event->getMousePos().y;
+ _mouseButton = _event->getButtonState();
+}
+
+void ToonEngine::drawSack() {
+ if (_gameState->_sackVisible) {
+ _inventoryIcons->drawFrame(*_mainSurface, 0, _gameState->_currentScrollValue, 356);
+ }
+}
+
+void ToonEngine::addItemToInventory(int32 item) {
+
+ if (item == 103 || item == 104 || item == 89 || item == 82) {
+ // can't add that to inventory
+ _gameState->_mouseState = -1;
+ return;
+ }
+
+ if (item == 41) {
+ // confiscated inventory
+ for (int32 i = 0; i < _gameState->_numConfiscatedInventoryItems; i++)
+ addItemToInventory(_gameState->_confiscatedInventory[i]);
+
+ _gameState->_numConfiscatedInventoryItems = 0;
+ _gameState->_mouseState = -1;
+ return;
+ }
+
+ for (int32 i = 0; i < _gameState->_numInventoryItems; i++) {
+ if (_gameState->_inventory[i] == 0) {
+ _gameState->_inventory[i] = item;
+ _gameState->_mouseState = -1;
+ return;
+ }
+ }
+ _gameState->_inventory[_gameState->_numInventoryItems] = item;
+ _gameState->_numInventoryItems++;
+ _gameState->_mouseState = -1;
+}
+
+void ToonEngine::createMouseItem(int32 item) {
+ _gameState->_mouseState = item;
+ setCursor(_gameState->_mouseState, true, -18, -14);
+}
+
+void ToonEngine::deleteMouseItem() {
+ _gameState->_mouseState = -1;
+ rearrangeInventory();
+ setCursor(0);
+}
+
+void ToonEngine::showCutaway(Common::String cutawayPicture) {
+ _gameState->_inCutaway = true;
+ _currentCutaway = new Picture(this);
+ if (cutawayPicture == "") {
+ cutawayPicture = Common::String(_gameState->_locations[_gameState->_currentScene]._cutaway) + ".CPS";
+ }
+ _currentCutaway->loadPicture(cutawayPicture, false);
+ _currentCutaway->setupPalette();
+ _oldScrollValue = _gameState->_currentScrollValue;
+ _gameState->_currentScrollValue = 0;
+ flushPalette();
+}
+
+void ToonEngine::hideCutaway() {
+ _gameState->_inCutaway = false;
+ _gameState->_sackVisible = true;
+ delete _currentCutaway;
+ _gameState->_currentScrollValue = _oldScrollValue;
+ _currentCutaway = 0;
+ _currentPicture->setupPalette();
+ flushPalette();
+}
+
+void ToonEngine::updateCharacters(int32 timeElapsed) {
+ for (int32 i = 0; i < 8; i++) {
+ if (_characters[i]) {
+ _characters[i]->update(timeElapsed);
+ }
+ }
+}
+
+void ToonEngine::drawPalette() {
+ for (int32 i = 0; i < 256; i++) {
+ int32 x = i % 32;
+ int32 y = i / 32;
+ _mainSurface->fillRect(Common::Rect(x * 16, y * 16, x * 16 + 16, y * 16 + 16), i);
+ }
+}
+
+void ToonEngine::rearrangeInventory() {
+ for (int32 i = 0; i < _gameState->_numInventoryItems; i++) {
+ if (_gameState->_inventory[i] == 0) {
+ // move all the following items from one
+ for (int32 j = i + 1; j < _gameState->_numInventoryItems; j++) {
+ _gameState->_inventory[j-1] = _gameState->_inventory[j];
+ }
+ _gameState->_numInventoryItems--;
+ }
+ }
+}
+
+void ToonEngine::newGame() {
+
+ if (_isDemo) {
+ addItemToInventory(59);
+ addItemToInventory(67);
+ addItemToInventory(11);
+ addItemToInventory(19);
+ loadScene(_gameState->_currentScene);
+ } else {
+ //loadScene(4);
+ loadScene(_gameState->_currentScene);
+ }
+}
+
+
+void ToonEngine::playSFX(int32 id, int32 volume) {
+ if (id < 0)
+ _audioManager->playSFX(-id + 1, volume, true);
+ else
+ _audioManager->playSFX(id , volume, false);
+}
+
+void ToonEngine::playSoundWrong() {
+ _audioManager->playSFX(rand() & 7, 128, true);
+}
+
+void ToonEngine::getTextPosition(int32 characterId, int32 *retX, int32 *retY) {
+
+ if (characterId < 0)
+ characterId = 0;
+
+ // default position is the center of current screen
+ *retX = _gameState->_currentScrollValue + 320;
+ *retY = 70;
+
+ // hardcoded special cases...
+ if (characterId == 0) {
+ // drew
+ int32 x = _drew->getX();
+ int32 y = _drew->getY();
+ if (x >= _gameState->_currentScrollValue && x <= _gameState->_currentScrollValue + 640) {
+ if (!_gameState->_inCutaway && !_gameState->_inInventory) {
+ *retX = x;
+ *retY = y - ((_drew->getScale() * 256 / 1024) >> 1) - 45;
+ }
+ }
+ } else if (characterId == 1) {
+ // flux
+ int32 x = _flux->getX();
+ int32 y = _flux->getY();
+ if (x >= _gameState->_currentScrollValue && x <= _gameState->_currentScrollValue + 640) {
+ if (!_gameState->_inCutaway) {
+ *retX = x;
+ *retY = y - ((_drew->getScale() * 100 / 1024) >> 1) - 30;
+ }
+ }
+ } else if (characterId == 5 || characterId == 39) {
+ *retX = 80;
+ *retY = 120;
+ } else if (characterId == 14) {
+ *retX = 257;
+ *retY = 132;
+ } else if (characterId == 18) {
+ *retX = 80;
+ *retY = 180;
+ } else if (characterId == 21) {
+ *retX = 363;
+ *retY = 193;
+ } else if (characterId == 23) {
+ *retX = 532;
+ *retY = 178;
+ } else if (characterId == 33) {
+ *retX = 167;
+ *retY = 172;
+ } else {
+
+ // more "standard" code by character
+ Character *character = getCharacterById(characterId);
+ if (character && !_gameState->_inCutaway) {
+ if (character->getAnimationInstance()) {
+ if (character->getX() >= _gameState->_currentScrollValue && character->getX() <= _gameState->_currentScrollValue + 640) {
+ int32 x1, y1, x2, y2;
+ character->getAnimationInstance()->getRect(&x1, &y1, &x2, &y2);
+ *retX = (x1 + x2) / 2;
+ *retY = y1;
+ }
+ }
+ }
+ }
+}
+
+Character *ToonEngine::getCharacterById(int32 charId) {
+
+ for (int32 i = 0; i < 8; i++) {
+ if (_characters[i] && _characters[i]->getId() == charId)
+ return _characters[i];
+ }
+ return 0;
+}
+
+void ToonEngine::drawConversationLine() {
+ if (_currentTextLine && _showConversationText) {
+ _fontRenderer->setFontColorByCharacter(_currentTextLineCharacterId);
+ _fontRenderer->setFont(_fontToon);
+ _fontRenderer->renderMultiLineText(_currentTextLineX, _currentTextLineY, Common::String(_currentTextLine), 0);
+ }
+}
+
+void ToonEngine::pauseEngineIntern(bool pause) {
+
+ Engine::pauseEngineIntern(pause);
+
+ static int32 pauseStart = 0;
+ if (pause) {
+ pauseStart = _system->getMillis();
+
+ } else {
+ _oldTimer = _system->getMillis();
+ _oldTimer2 = _oldTimer;
+
+ int32 diff = _oldTimer - pauseStart;
+
+ // we have to add the difference between the start and the current time
+ // to all "timer based" values.
+ for (int32 i = 0; i < _gameState->_locations[_gameState->_currentScene]._numSceneAnimations; i++) {
+ _sceneAnimationScripts[i]._lastTimer += diff;
+ }
+ for (int32 i = 0; i < 8; i++) {
+ if (_characters[i]) {
+ _characters[i]->updateTimers(diff);
+ }
+ }
+
+ _gameState->_timerTimeout[0] += diff;
+ _gameState->_timerTimeout[1] += diff;
+ }
+}
+
+bool ToonEngine::canSaveGameStateCurrently() {
+ return !_gameState->_inInventory && !_gameState->_inConversation && !_gameState->_inCutaway && !_gameState->_mouseHidden && !_moviePlayer->isPlaying();
+}
+
+bool ToonEngine::canLoadGameStateCurrently() {
+ return !_gameState->_inInventory && !_gameState->_inConversation && !_gameState->_inCutaway && !_gameState->_mouseHidden && !_moviePlayer->isPlaying();
+}
+
+Common::String ToonEngine::getSavegameName(int nr) {
+ return _targetName + Common::String::printf(".%03d", nr);
+}
+
+bool ToonEngine::saveGame(int32 slot, Common::String saveGameDesc) {
+ const EnginePlugin *plugin = NULL;
+ int16 savegameId;
+ Common::String savegameDescription;
+ EngineMan.findGame(_gameDescription->gameid, &plugin);
+
+ if (slot == -1) {
+ GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Save game:", "Save");
+ dialog->setSaveMode(true);
+ savegameId = dialog->runModal(plugin, ConfMan.getActiveDomainName());
+ savegameDescription = dialog->getResultString();
+ delete dialog;
+ } else {
+ savegameId = slot;
+ if (!saveGameDesc.empty()) {
+ savegameDescription = saveGameDesc;
+ } else {
+ savegameDescription = Common::String::printf("Quick save #%d", slot);
+ }
+ }
+
+ if (savegameId < 0)
+ return false; // dialog aborted
+
+ Common::String savegameFile = getSavegameName(savegameId);
+ Common::SaveFileManager *saveMan = g_system->getSavefileManager();
+ Common::OutSaveFile *saveFile = saveMan->openForSaving(savegameFile);
+ if (!saveFile)
+ return false;
+
+ // save savegame header
+ saveFile->writeSint32BE(TOON_SAVEGAME_VERSION);
+
+ if (savegameDescription == "") {
+ savegameDescription = "Untitled savegame";
+ }
+
+ saveFile->writeSint16BE(savegameDescription.size() + 1);
+ saveFile->write(savegameDescription.c_str(), savegameDescription.size() + 1);
+
+ Graphics::saveThumbnail(*saveFile);
+
+ TimeDate curTime;
+ _system->getTimeAndDate(curTime);
+
+ uint32 saveDate = (curTime.tm_mday & 0xFF) << 24 | ((curTime.tm_mon + 1) & 0xFF) << 16 | ((curTime.tm_year + 1900) & 0xFFFF);
+ uint16 saveTime = (curTime.tm_hour & 0xFF) << 8 | ((curTime.tm_min) & 0xFF);
+
+ saveFile->writeUint32BE(saveDate);
+ saveFile->writeUint16BE(saveTime);
+
+
+ // save global state
+ _gameState->save(saveFile);
+ _gameState->saveConversations(saveFile);
+ _hotspots->save(saveFile);
+
+ // save current time to be able to patch the time when loading
+ saveFile->writeSint32BE(getOldMilli());
+
+ // save script states
+ for (int32 i = 0; i < 4; i++) {
+ _script->saveState(&_scriptState[i], saveFile);
+ }
+
+ // save animation script states
+ for (int32 i = 0; i < state()->_locations[_gameState->_currentScene]._numSceneAnimations; i++) {
+ saveFile->writeByte(_sceneAnimationScripts[i]._active);
+ saveFile->writeByte(_sceneAnimationScripts[i]._frozen);
+ saveFile->writeSint32BE(_sceneAnimationScripts[i]._lastTimer);
+ _script->saveState(&_sceneAnimationScripts[i]._state, saveFile);
+ }
+
+ // save scene animations
+ for (int32 i = 0; i < 64; i++) {
+ _sceneAnimations[i].save(this, saveFile);
+ }
+
+
+ for (int32 i = 0; i < 8; i++) {
+ if (_characters[i]) {
+ saveFile->writeSByte(i);
+ _characters[i]->save(saveFile);
+ }
+ }
+ saveFile->writeSByte(-1);
+
+ // save "command buffer"
+ saveFile->writeSint16BE(_saveBufferStream->pos());
+ if (_saveBufferStream->pos() > 0) {
+ saveFile->write(_saveBufferStream->getData(), _saveBufferStream->pos());
+ saveFile->writeSint16BE(0);
+ }
+
+ delete saveFile;
+
+ return true;
+}
+
+bool ToonEngine::loadGame(int32 slot) {
+ const EnginePlugin *plugin = NULL;
+ int16 savegameId;
+ EngineMan.findGame(_gameDescription->gameid, &plugin);
+
+ if (slot == -1) {
+ GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Restore game:", "Restore");
+ dialog->setSaveMode(false);
+ savegameId = dialog->runModal(plugin, ConfMan.getActiveDomainName());
+ delete dialog;
+ } else {
+ savegameId = slot;
+ }
+ if (savegameId < 0)
+ return false; // dialog aborted
+
+ Common::String savegameFile = getSavegameName(savegameId);
+ Common::SaveFileManager *saveMan = g_system->getSavefileManager();
+ Common::InSaveFile *loadFile = saveMan->openForLoading(savegameFile);
+ if (!loadFile)
+ return false;
+
+ int32 saveGameVersion = loadFile->readSint32BE();
+ if (saveGameVersion != TOON_SAVEGAME_VERSION) {
+ delete loadFile;
+ return false;
+ }
+ int32 saveGameNameSize = loadFile->readSint16BE();
+ loadFile->skip(saveGameNameSize);
+
+ // We don't need the thumbnail here, so just read it and discard it
+ Graphics::skipThumbnail(*loadFile);
+
+ loadFile->skip(6); // date & time skip
+
+ if (_gameState->_currentScene != -1) {
+ exitScene();
+ }
+
+
+ _gameState->load(loadFile);
+ loadScene(_gameState->_currentScene, true);
+ _gameState->loadConversations(loadFile);
+ _hotspots->load(loadFile);
+
+ // read the old time
+ int32 savedTime = loadFile->readSint32BE();
+ int32 timerDiff = _system->getMillis() - savedTime;
+
+ // load script states
+ for (int32 i = 0; i < 4; i++) {
+ _script->loadState(&_scriptState[i], loadFile);
+ }
+
+ // load animation script states
+ for (int32 i = 0; i < state()->_locations[_gameState->_currentScene]._numSceneAnimations; i++) {
+ _sceneAnimationScripts[i]._active = loadFile->readByte();
+ _sceneAnimationScripts[i]._frozen = loadFile->readByte();
+ _sceneAnimationScripts[i]._frozenForConversation = false;
+ int32 oldTimer = loadFile->readSint32BE();
+ _sceneAnimationScripts[i]._lastTimer = MAX<int32>(0,oldTimer + timerDiff);
+ _script->loadState(&_sceneAnimationScripts[i]._state, loadFile);
+ }
+
+ // load scene animations
+ for (int32 i = 0; i < 64; i++) {
+ _sceneAnimations[i].load(this, loadFile);
+ }
+
+ _gameState->_timerTimeout[0] += timerDiff;
+ _gameState->_timerTimeout[1] += timerDiff;
+
+ /*
+ int32 diff = _conversationData - _gameState->_conversationData;
+
+ for (int32 i = 0; i < 60; i++) {
+ if (_gameState->_conversationState[i]._enable) {
+ // we have to fix up our pointers...
+ for (int32 a = 0; a < 10; a++) {
+ if (_gameState->_conversationState[i].state[a]._data4)
+ _gameState->_conversationState[i].state[a]._data4 = (int16 *)_gameState->_conversationState[i].state[a]._data4 + diff;
+ }
+ }
+ }
+ */
+
+ _gameState->_conversationData = _conversationData;
+ _firstFrame = true;
+
+ // read characters info
+ while (1) {
+ int8 c = loadFile->readSByte();
+ if (c < 0)
+ break;
+
+ if (!_characters[c]) {
+ _characters[c] = new Character(this);
+ }
+ _characters[c]->load(loadFile);
+ //_characters[c]->setVisible(true);
+ _characters[c]->update(0);
+ }
+
+ // load "command buffer"
+ int32 size = loadFile->readSint16BE();
+ if (size) {
+ uint8 *buf = new uint8[size+2];
+ loadFile->read(buf, size + 2);
+
+ Common::MemoryReadStream rStr(buf, size + 2);
+ while (1) {
+ int16 command = rStr.readSint16BE();
+ if (!command) break;
+ switch (command) {
+ case 1: {
+ int16 frame = rStr.readSint16BE();
+ int16 animLen = rStr.readSint16BE();
+ char animName[32];
+ rStr.read(animName, animLen);
+ int16 x = rStr.readSint16BE();
+ int16 y = rStr.readSint16BE();
+// int16 z = rStr.readSint16BE();
+// int16 layerZ = rStr.readSint16BE();
+ rStr.readSint16BE();
+ rStr.readSint16BE();
+
+ Animation *anim = new Animation(this);
+ anim->loadAnimation(animName);
+ anim->drawFrameOnPicture(frame, x, y);
+ delete anim;
+ break;
+ }
+ case 2: {
+ int16 x = rStr.readSint16BE();
+ int16 y = rStr.readSint16BE();
+ int16 x1 = rStr.readSint16BE();
+ int16 y1 = rStr.readSint16BE();
+ makeLineNonWalkable(x, y, x1, y1);
+ break;
+ }
+ case 3: {
+ int16 x = rStr.readSint16BE();
+ int16 y = rStr.readSint16BE();
+ int16 x1 = rStr.readSint16BE();
+ int16 y1 = rStr.readSint16BE();
+ makeLineWalkable(x, y, x1, y1);
+ break;
+ }
+ case 4: {
+ int16 x = rStr.readSint16BE();
+ int16 y = rStr.readSint16BE();
+ getMask()->floodFillNotWalkableOnMask(x, y);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ _saveBufferStream->write(buf, size);
+ delete loadFile;
+ }
+ return true;
+}
+
+// another special case for inventory
+int32 ToonEngine::getSpecialInventoryItem(int32 item) {
+
+ // butter
+ if (item == 12) {
+ for (int32 i = 0; i < _gameState->_numInventoryItems; i++) {
+ if (_gameState->_inventory[i] == 12)
+ _gameState->_inventory[i] = 11;
+ }
+ return 11;
+
+ } else if (item == 84) {
+ if (_gameState->getGameFlag(26)) {
+ characterTalk(1726);
+ return 0;
+ } else {
+ if (!_gameState->hasItemInInventory(102) && !_gameState->hasItemInInventory(90) && !_gameState->hasItemInInventory(89)) {
+ characterTalk(1416);
+ return 102;
+ } else {
+ return 0;
+ }
+ }
+ }
+
+ return -1;
+}
+
+void ToonEngine::initCharacter(int32 characterId, int32 animScriptId, int32 sceneAnimationId, int32 animToPlayId) {
+ // find a new index
+ int32 characterIndex = -1;
+ for (int32 i = 0; i < 8; i++) {
+ if (_characters[i] && _characters[i]->getId() == characterId) {
+ characterIndex = i;
+ break;
+ }
+
+ if (!_characters[i]) {
+ characterIndex = i;
+ break;
+ }
+ }
+
+ if (characterIndex == -1) {
+ return;
+ }
+
+// Strangerke - Commented (not used)
+// if (_characters[characterIndex])
+// delete current char
+
+ _characters[characterIndex] = new Character(this);
+ _characters[characterIndex]->setId(characterId);
+ _characters[characterIndex]->setAnimScript(animScriptId);
+ _characters[characterIndex]->setDefaultSpecialAnimationId(animToPlayId);
+ _characters[characterIndex]->setSceneAnimationId(sceneAnimationId);
+ _characters[characterIndex]->setFlag(0);
+ _characters[characterIndex]->setVisible(true);
+ if (sceneAnimationId != -1)
+ _characters[characterIndex]->setAnimationInstance(_sceneAnimations[sceneAnimationId]._animInstance);
+}
+
+int32 ToonEngine::handleInventoryOnFlux(int32 itemId) {
+
+ switch (itemId) {
+ case 8:
+ sayLines(1, 1332);
+ break;
+ case 0x14:
+ case 0x15:
+ case 0x45:
+ sayLines(1, 1304);
+ break;
+ case 0x68:
+ _gameState->_mouseState = 0;
+ setCursor(0, false, 0, 0);
+ break;
+ case 116:
+ sayLines(1, 1306);
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+void ToonEngine::storePalette() {
+ memcpy(_backupPalette, _finalPalette, 768);
+}
+
+void ToonEngine::restorePalette() {
+ memcpy(_finalPalette, _backupPalette, 768);
+ flushPalette();
+}
+
+const char *ToonEngine::getSpecialConversationMusic(int32 conversationId) {
+ static const char * const specialMusic[] = {
+ 0, 0,
+ "BR091013", "BR091013",
+ "NET1214", "NET1214",
+ 0, 0,
+ "CAR1365B", "CAR1365B",
+ 0, 0,
+ 0, 0,
+ "CAR14431", "CAR14431",
+ 0, 0,
+ 0, 0,
+ "SCD16520", "SCD16520",
+ "SCD16520", "SCD16520",
+ "SCD16522", "SCD16522",
+ 0, 0,
+ "KPM8719", "KPM8719",
+ 0, 0,
+ "CAR1368B", "CAR1368B",
+ 0, 0,
+ 0, 0,
+ "KPM6337", "KPM6337",
+ "CAR20471", "CAR20471",
+ "CAR136_1", "KPM87_57",
+ 0, 0,
+ "CAR13648", "CAR13648",
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ "SCD16526", "SCD16526",
+ 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
+ };
+
+ return specialMusic[randRange(0, 1) + conversationId * 2];
+}
+
+void ToonEngine::viewInventoryItem(Common::String str, int32 lineId, int32 itemDest) {
+ storePalette();
+ fadeOut(5);
+
+ Picture *pic = new Picture(this);
+ pic->loadPicture(str, false);
+ pic->setupPalette();
+ flushPalette();
+
+ if (lineId) {
+ characterTalk(lineId, false);
+ }
+
+ uint32 oldMouseButton = _mouseButton;
+ uint32 justPressedButton = 0;
+ _firstFrame = true;
+
+ int32 oldScrollValue = _gameState->_currentScrollValue;
+ _gameState->_currentScrollValue = 0;
+
+ while (!_shouldQuit) {
+ getMouseEvent();
+
+ justPressedButton = _mouseButton & ~oldMouseButton;
+ oldMouseButton = _mouseButton;
+
+ if (justPressedButton) {
+ break;
+ }
+
+ pic->draw(*_mainSurface, 0, 0, 0, 0);
+
+ drawConversationLine();
+ if (!_audioManager->voiceStillPlaying()) {
+ _currentTextLineCharacterId = -1;
+ _currentTextLine = 0;
+ _currentTextLineId = -1;
+ }
+
+ if (_firstFrame) {
+ copyToVirtualScreen(false);
+ _firstFrame = false;
+ fadeIn(5);
+ }
+
+ copyToVirtualScreen();
+ }
+
+ fadeOut(5);
+ restorePalette();
+ _firstFrame = true;
+ _gameState->_currentScrollValue = oldScrollValue;
+ delete pic;
+
+}
+
+int32 ToonEngine::handleInventoryOnInventory(int32 itemDest, int32 itemSrc) {
+ switch (itemDest) {
+ case 0:
+ return handleInventoryOnDrew(itemSrc);
+ case 1:
+ if (itemSrc == 71) {
+ sayLines(2, 1212);
+ return 1;
+ }
+ break;
+ case 5:
+ if (itemSrc == 15) {
+ characterTalk(1492);
+ } else if (itemSrc == 0x2f) {
+ characterTalk(1488);
+ } else if (itemSrc == 88) {
+ sayLines(2, 1478);
+ } else {
+ return 0;
+ }
+ break;
+ case 6:
+ if (itemSrc == -1) {
+ viewInventoryItem("BLUEPRNT.CPS", 1006, itemDest);
+ return 1;
+ } else
+ return 0;
+ break;
+ case 8:
+ if (itemSrc == -1) {
+ viewInventoryItem("BOOK.CPS", 0, itemDest);
+ return 1;
+ } else {
+ return 0;
+ }
+ break;
+ case 11:
+ if (itemSrc == 0xb) {
+ _gameState->_mouseState = -1;
+ replaceItemFromInventory(11,12);
+ setCursor(0, false, 0, 0);
+ rearrangeInventory();
+ return 1;
+ //
+ } else if (itemSrc == 24) {
+ characterTalk(1244);
+ return 1;
+ } else if (itemSrc == 0x1a || itemSrc == 0x40 || itemSrc == 71) {
+ sayLines(2, 1212);
+ return 1;
+ }
+ break;
+ case 12:
+ if (itemSrc == 24) {
+ characterTalk(1244);
+ return 1;
+ } else if (itemSrc == 0x1a || itemSrc == 0x40 || itemSrc == 71) {
+ sayLines(2, 1212);
+ return 1;
+ }
+ break;
+ case 13:
+ if (itemSrc == 0x35 || itemSrc == 0x36) {
+ characterTalk(1204);
+ return 1;
+ } else if (itemSrc >= 0x6b && itemSrc <= 0x72) {
+ characterTalk(1312);
+ return 1;
+ }
+ break;
+ case 14:
+ if (itemSrc == -1) {
+ deleteItemFromInventory(14);
+ addItemToInventory(15);
+ addItemToInventory(42);
+ rearrangeInventory();
+ return 1;
+ } else if (itemSrc == 43) {
+ characterTalk(1410);
+ return 1;
+ } else if (itemSrc == 49) {
+ characterTalk(1409);
+ return 1;
+ }
+ break;
+ case 16:
+ if (itemSrc == 55) {
+ characterTalk(1400);
+ replaceItemFromInventory(55, 98);
+ return 1;
+ }
+ break;
+ case 19:
+ if (itemSrc == 0x34) {
+ characterTalk(1322);
+ return 1;
+ } else if (itemSrc == 107) {
+ sayLines(2 , 1300);
+ replaceItemFromInventory(107, 111);
+ _gameState->_mouseState = -1;
+ setCursor(0, false, 0, 0);
+ rearrangeInventory();
+ return 1;
+ } else if (itemSrc == 0x6c) {
+ sayLines(2, 1300);
+ replaceItemFromInventory(108, 112);
+ _gameState->_mouseState = -1;
+ setCursor(0, false, 0, 0);
+ rearrangeInventory();
+ return 1;
+ } else if (itemSrc == 0x6d) {
+ sayLines(2, 1300);
+ replaceItemFromInventory(109, 113);
+ _gameState->_mouseState = -1;
+ setCursor(0, false, 0, 0);
+ rearrangeInventory();
+ return 1;
+ } else if (itemSrc == 110) {
+ sayLines(2, 1300);
+ replaceItemFromInventory(110, 114);
+ _gameState->_mouseState = -1;
+ setCursor(0, false, 0, 0);
+ rearrangeInventory();
+ return 1;
+ }
+ break;
+ case 20:
+ if (itemSrc == 35) {
+ createMouseItem(21);
+ replaceItemFromInventory(35, 36);
+ return 1;
+ } else if (itemSrc == 0x24) {
+ createMouseItem(21);
+ replaceItemFromInventory(36, 37);
+ return 1;
+ } else if (itemSrc == 37) {
+ deleteItemFromInventory(37);
+ createMouseItem(21);
+ rearrangeInventory();
+ return 1;
+ } else if (itemSrc == 0x6b || itemSrc == 0x6c || itemSrc == 0x6f || itemSrc == 108 || itemSrc == 112) {
+ sayLines(2, 1292);
+ return 1;
+ }
+ break;
+ case 21:
+ switch (itemSrc) {
+
+ case 107:
+ characterTalk(1296);
+ replaceItemFromInventory(107, 109);
+ _gameState->_mouseState = -1;
+ setCursor(0, false, 0, 0);
+ rearrangeInventory();
+ return 1;
+ case 108:
+ characterTalk(1298);
+ replaceItemFromInventory(108, 110);
+ _gameState->_mouseState = -1;
+ setCursor(0, false, 0, 0);
+ rearrangeInventory();
+ return 1;
+ case 111:
+ characterTalk(1296);
+ replaceItemFromInventory(111, 113);
+ _gameState->_mouseState = -1;
+ setCursor(0, false, 0, 0);
+ rearrangeInventory();
+ return 1;
+ case 112:
+ characterTalk(1298);
+ replaceItemFromInventory(112, 114);
+ _gameState->_mouseState = -1;
+ setCursor(0, false, 0, 0);
+ rearrangeInventory();
+ return 1;
+ }
+ break;
+ case 22:
+ if (itemSrc == 32) {
+ characterTalk(1252);
+ return 1;
+ }
+ break;
+ case 24:
+ if (itemSrc == 0xc) {
+ characterTalk(1244);
+ return 1;
+ } else if (itemSrc == 79) {
+ characterTalk(1280);
+ return 1;
+ }
+ break;
+ case 26:
+ if (itemSrc == 0x5e) {
+ characterTalk(1316);
+ return 1;
+ } else if (itemSrc == 95) {
+ characterTalk(1320);
+ return 1;
+ }
+ break;
+ case 31:
+ if (itemSrc == 61) {
+ characterTalk(1412);
+ deleteItemFromInventory(61);
+ createMouseItem(62);
+ rearrangeInventory();
+ return 1;
+ }
+ break;
+ case 32:
+ if (itemSrc == 22) {
+ characterTalk(1252);
+ return 1;
+ }
+ break;
+ case 33:
+ if (itemSrc == 117) {
+ characterTalk(1490);
+ return 1;
+ }
+ break;
+ case 34:
+ if (itemSrc == 61) {
+ characterTalk(1414);
+ return 1;
+ }
+ break;
+ case 35:
+ if (itemSrc == -1) {
+ characterTalk(1035);
+ return 1;
+ } else if (itemSrc == 20) {
+ replaceItemFromInventory(20, 21);
+ createMouseItem(36);
+ return 1;
+ } else if (itemSrc == 68) {
+ replaceItemFromInventory(68, 69);
+ createMouseItem(36);
+ return 1;
+ } else if (itemSrc >= 107 && itemSrc <= 114) {
+ characterTalk(1314);
+ return 1;
+ } else {
+ characterTalk(1208);
+ return 1;
+ }
+ break;
+ case 36:
+ if (itemSrc == -1) {
+ characterTalk(1035);
+ return 1;
+ } else if (itemSrc == 20) {
+ replaceItemFromInventory(20, 21);
+ createMouseItem(37);
+ return 1;
+ } else if (itemSrc == 68) {
+ replaceItemFromInventory(68, 69);
+ createMouseItem(37);
+ return 1;
+ } else if (itemSrc >= 107 && itemSrc <= 114) {
+ characterTalk(1314);
+ return 1;
+ } else {
+ characterTalk(1208);
+ return 1;
+ }
+ break;
+ case 37:
+ if (itemSrc == -1) {
+ characterTalk(1035);
+ return 1;
+ } else if (itemSrc == 20) {
+ replaceItemFromInventory(20, 21);
+ _gameState->_mouseState = -1;
+ setCursor(0, false, 0, 0);
+ rearrangeInventory();
+ return 1;
+ } else if (itemSrc == 68) {
+ replaceItemFromInventory(68, 69);
+ _gameState->_mouseState = -1;
+ setCursor(0, false, 0, 0);
+ rearrangeInventory();
+ return 1;
+ } else if (itemSrc >= 107 && itemSrc <= 114) {
+ characterTalk(1314);
+ return 1;
+ } else {
+ characterTalk(1208);
+ return 1;
+ }
+ break;
+ case 38:
+ if (itemSrc == 15) {
+ characterTalk(1492);
+ return 1;
+ } else if (itemSrc == 0x2f) {
+ characterTalk(1488);
+ return 1;
+ } else if (itemSrc == 88) {
+ sayLines(2, 1478);
+ return 1;
+ }
+ break;
+ case 40:
+ if (itemSrc == 53) {
+ replaceItemFromInventory(53, 54);
+ characterTalk(1222);
+ return 1;
+ } else if (itemSrc == 0x36) {
+ characterTalk(1228);
+ return 1;
+ } else if (itemSrc == 0x5b) {
+ characterTalk(1230);
+ return 1;
+ } else if (itemSrc == 92) {
+ characterTalk(1220);
+ return 1;
+ }
+ break;
+ case 43:
+ if (itemSrc == 14) {
+ characterTalk(1410);
+ return 1;
+ }
+ break;
+ case 47:
+ if (itemSrc == -1)
+ characterTalk(1047);
+ else
+ characterTalk(1488);
+
+ return 1;
+ case 49:
+ if (itemSrc == 0xe) {
+ characterTalk(1409);
+ return 1;
+ } else if (itemSrc == 38 || itemSrc == 5 || itemSrc == 0x42) {
+ characterTalk(1476);
+ return 1;
+ } else if (itemSrc == 0x34) {
+ characterTalk(1260);
+ return 1;
+ } else if (itemSrc == 0x47) {
+ characterTalk(1246);
+ return 1;
+ } else if (itemSrc == 0x36) {
+ sayLines(2, 1324);
+ return 1;
+ }
+ break;
+ case 52:
+ if (itemSrc == 0x13) {
+ characterTalk(1322);
+ return 1;
+ } else if (itemSrc == 94) {
+ characterTalk(1282);
+ return 1;
+ }
+ break;
+ case 53:
+ if (itemSrc == 40) {
+ createMouseItem(54);
+ characterTalk(1222);
+ return 1;
+ } else if (itemSrc == 0x31) {
+ sayLines(2, 1324);
+ return 1;
+ } else if (itemSrc == 0x34) {
+ characterTalk(1310);
+ return 1;
+ } else if (itemSrc == 91) {
+ characterTalk(1218);
+ return 1;
+ }
+
+ break;
+ case 54:
+ if (itemSrc == 40) {
+ characterTalk(1228);
+ return 1;
+ } else if (itemSrc == 0x34) {
+ characterTalk(1310);
+ return 1;
+ } else if (itemSrc == 0x5b) {
+ characterTalk(1226);
+ replaceItemFromInventory(91, 92);
+ return 1;
+ } else if (itemSrc == 92) {
+ characterTalk(1220);
+ return 1;
+ }
+
+ break;
+ case 55:
+ if (itemSrc == 16) {
+ createMouseItem(98);
+ characterTalk(1400);
+ return 1;
+ }
+ break;
+ case 61:
+ if (itemSrc == 0x1f) {
+ characterTalk(1412);
+ deleteItemFromInventory(31);
+ createMouseItem(62);
+ rearrangeInventory();
+ return 1;
+ } else if (itemSrc == 0x21 || itemSrc == 0x22) {
+ characterTalk(1414);
+ return 1;
+ }
+ break;
+ case 64:
+ if (itemSrc == 0xb) {
+ sayLines(2, 1212);
+ return 1;
+ } else if (itemSrc == 0x5e || itemSrc == 0x5f) {
+ characterTalk(1318);
+ return 1;
+ }
+ break;
+ case 66:
+ if (itemSrc == 15) {
+ characterTalk(1492);
+ return 1;
+ } else if (itemSrc == 0x2f) {
+ characterTalk(1488);
+ return 1;
+ } else if (itemSrc == 88) {
+ sayLines(2, 1478);
+ characterTalk(1478);
+ return 1;
+ }
+ break;
+ case 67:
+ if (itemSrc == 79) {
+ sayLines(2, 1212);
+ return 1;
+ }
+ break;
+ case 68:
+ if (itemSrc == 35) {
+ createMouseItem(69);
+ replaceItemFromInventory(35, 36);
+ return 1;
+ } else if (itemSrc == 0x24) {
+ createMouseItem(69);
+ replaceItemFromInventory(36, 37);
+ return 1;
+ } else if (itemSrc == 37) {
+ deleteItemFromInventory(37);
+ createMouseItem(69);
+ rearrangeInventory();
+ return 1;
+ } else if (itemSrc == 0x6b || itemSrc == 113 || itemSrc == 0x6f || itemSrc == 109) {
+ sayLines(2, 1288);
+ return 1;
+ }
+ break;
+ case 69:
+ switch (itemSrc) {
+ case 107:
+ characterTalk(1296);
+ replaceItemFromInventory(107, 108);
+ _gameState->_mouseState = -1;
+ setCursor(0, false, 0, 0);
+ rearrangeInventory();
+ return 1;
+ case 109:
+ characterTalk(1298);
+ replaceItemFromInventory(109, 110);
+ _gameState->_mouseState = -1;
+ setCursor(0, false, 0, 0);
+ rearrangeInventory();
+ return 1;
+ case 111:
+ characterTalk(1296);
+ replaceItemFromInventory(111, 112);
+ _gameState->_mouseState = -1;
+ setCursor(0, false, 0, 0);
+ rearrangeInventory();
+ return 1;
+ case 113:
+ characterTalk(1298);
+ replaceItemFromInventory(113, 114);
+ _gameState->_mouseState = -1;
+ setCursor(0, false, 0, 0);
+ rearrangeInventory();
+ return 1;
+ }
+ break;
+ case 71:
+ if (itemSrc == 0xc || itemSrc == 1 || itemSrc == 0x41 || itemSrc == 67 || itemSrc == 0x4c || itemSrc == 57) {
+ sayLines(2, 1212);
+ return 1;
+ } else if (itemSrc == 79) {
+ characterTalk(1238);
+ return 1;
+ }
+ break;
+ case 79:
+ if (itemSrc == 1 || itemSrc == 67 || itemSrc == 76 || itemSrc == 57 || itemSrc == 0x41) {
+ sayLines(2, 1212);
+ return 1;
+ } else if (itemSrc == 0x18) {
+ characterTalk(1280);
+ return 1;
+ } else if (itemSrc == 0x47) {
+ characterTalk(1238);
+ return 1;
+ }
+ break;
+ case 82:
+ if (itemSrc == 84) {
+ sayLines(2, 1424);
+ return 1;
+ } else if (itemSrc == 0x58) {
+ deleteItemFromInventory(88);
+ createMouseItem(89);
+ rearrangeInventory();
+ characterTalk(1428);
+ return 1;
+ } else if (itemSrc == 117) {
+ sayLines(2, 1496);
+ return 1;
+ }
+ break;
+ case 84:
+ if (itemSrc == 0x58) {
+ replaceItemFromInventory(88, 90);
+ characterTalk(1090);
+ return 1;
+ } else if (itemSrc == 117) {
+ characterTalk(1494);
+ return 1;
+ }
+ break;
+ case 88:
+ if (itemSrc == 82) {
+ deleteItemFromInventory(82);
+ createMouseItem(89);
+ rearrangeInventory();
+ characterTalk(1428);
+ return 1;
+ } else if (itemSrc == 0x54) {
+ createMouseItem(90);
+ characterTalk(1090);
+ return 1;
+ } else if (itemSrc == 102) {
+ deleteItemFromInventory(102);
+ createMouseItem(90);
+ rearrangeInventory();
+ characterTalk(1090);
+ return 1;
+ }
+ break;
+ case 89:
+ if (itemSrc == 117) {
+ sayLines(2, 1496);
+ return 1;
+ }
+ break;
+ case 90:
+ if (itemSrc == 117) {
+ sayLines(2, 1494);
+ return 1;
+ }
+ break;
+ case 91:
+ if (itemSrc == 0x28) {
+ characterTalk(1230);
+ return 1;
+ } else if (itemSrc == 54) {
+ createMouseItem(92);
+ return 1;
+ }
+ break;
+ case 92:
+ if (itemSrc == 0x28 || itemSrc == 54) {
+ characterTalk(1220);
+ return 1;
+ }
+ break;
+ case 94:
+ if (itemSrc == 26) {
+ characterTalk(1316);
+ return 1;
+ } else if (itemSrc == 0x34) {
+ characterTalk(1282);
+ return 1;
+ } else if (itemSrc == 64) {
+ characterTalk(1318);
+ return 1;
+ }
+ break;
+ case 95:
+ if (itemSrc == 26) {
+ characterTalk(1320);
+ return 1;
+ } else if (itemSrc == 0x40) {
+ characterTalk(1318);
+ return 1;
+ } else if (itemSrc == 115) {
+ characterTalk(1284);
+ replaceItemFromInventory(115, 116);
+ createMouseItem(93);
+ return 1;
+ }
+ break;
+ case 96:
+ if (itemSrc == 0x34) {
+ characterTalk(1234);
+ return 1;
+ } else if (itemSrc == 71) {
+ sayLines(2, 1212);
+ return 1;
+ }
+ break;
+ case 97:
+ if (itemSrc == 15) {
+ characterTalk(1492);
+ return 1;
+ } else if (itemSrc == 0x2f) {
+ characterTalk(1488);
+ return 1;
+ } else if (itemSrc == 88) {
+ sayLines(2, 1478);
+ return 1;
+ }
+ break;
+ case 100:
+ if (itemSrc == 117) {
+ characterTalk(1490);
+ return 1;
+ }
+ break;
+ case 102:
+ if (itemSrc == -1) {
+ characterTalk(1102);
+ return 1;
+ } else if (itemSrc == 84) {
+ _gameState->_mouseState = -1;
+ setCursor(0, false, 0, 0);
+ rearrangeInventory();
+ characterTalk(1418);
+ return 1;
+ } else if (itemSrc == 88) {
+ deleteItemFromInventory(88);
+ createMouseItem(90);
+ rearrangeInventory();
+ characterTalk(1090);
+ return 1;
+ } else if (itemSrc == 117) {
+ characterTalk(1494);
+ return 1;
+ } else {
+ characterTalk(1426);
+ return 1;
+ }
+ break;
+ case 106:
+ if (itemSrc == 13) {
+ characterTalk(1308);
+ return 1;
+ }
+ break;
+ case 107:
+ if (itemSrc == 19) {
+ sayLines(2, 1300);
+ deleteItemFromInventory(19);
+ createMouseItem(111);
+ rearrangeInventory();
+ return 1;
+ } else if (itemSrc == 0x15) {
+ characterTalk(1296);
+ deleteItemFromInventory(21);
+ createMouseItem(109);
+ rearrangeInventory();
+ return 1;
+ } else if (itemSrc == 0x23) {
+ characterTalk(1314);
+ return 1;
+ } else if (itemSrc == 69) {
+ characterTalk(1296);
+ deleteItemFromInventory(69);
+ createMouseItem(108);
+ rearrangeInventory();
+ return 1;
+ }
+ break;
+ case 108:
+ if (itemSrc == 19) {
+ sayLines(2, 1300);
+ deleteItemFromInventory(19);
+ createMouseItem(112);
+ rearrangeInventory();
+ return 1;
+ } else if (itemSrc == 0x15) {
+ characterTalk(1298);
+ deleteItemFromInventory(21);
+ createMouseItem(110);
+ rearrangeInventory();
+ return 1;
+ } else if (itemSrc == 35) {
+ characterTalk(1314);
+ return 1;
+ }
+ break;
+ case 109:
+ if (itemSrc == 19) {
+ sayLines(2, 1300);
+ deleteItemFromInventory(19);
+ createMouseItem(113);
+ rearrangeInventory();
+ return 1;
+ } else if (itemSrc == 0x23) {
+ characterTalk(1314);
+ return 1;
+ } else if (itemSrc == 69) {
+ characterTalk(1298);
+ deleteItemFromInventory(69);
+ createMouseItem(110);
+ rearrangeInventory();
+ return 1;
+ }
+ break;
+ case 110:
+ if (itemSrc == 0x13) {
+ sayLines(2, 1300);
+ deleteItemFromInventory(19);
+ createMouseItem(114);
+ rearrangeInventory();
+ return 1;
+ } else if (itemSrc == 35) {
+ characterTalk(1314);
+ return 1;
+ }
+ break;
+ case 111:
+ if (itemSrc == 21) {
+ characterTalk(1296);
+ deleteItemFromInventory(21);
+ createMouseItem(113);
+ rearrangeInventory();
+ return 1;
+ } else if (itemSrc == 0x23) {
+ characterTalk(1314);
+ return 1;
+ } else if (itemSrc == 69) {
+ characterTalk(1296);
+ deleteItemFromInventory(69);
+ createMouseItem(112);
+ rearrangeInventory();
+ return 1;
+ }
+ break;
+ case 112:
+ if (itemSrc == 0x15) {
+ characterTalk(1298);
+ deleteItemFromInventory(21);
+ createMouseItem(114);
+ rearrangeInventory();
+ return 1;
+ } else if (itemSrc == 35) {
+ characterTalk(1314);
+ return 1;
+ }
+ break;
+ case 113:
+ if (itemSrc == 0x23) {
+ characterTalk(1314);
+ return 1;
+ } else if (itemSrc == 69) {
+ characterTalk(1298);
+ deleteItemFromInventory(69);
+ createMouseItem(114);
+ rearrangeInventory();
+ return 1;
+ }
+ break;
+ case 114:
+ if (itemSrc == 35) {
+ characterTalk(1314);
+ return 1;
+ }
+ break;
+ case 115:
+ if (itemSrc == 95) {
+ replaceItemFromInventory(95, 93);
+ createMouseItem(116);
+ return 1;
+ }
+ break;
+ case 117:
+ if (itemSrc == 90 || itemSrc == 33) {
+ characterTalk(1490);
+ } else if (itemSrc == 102 || itemSrc == 84) {
+ characterTalk(1494);
+ } else if (itemSrc == 0x59 || itemSrc == 0x52) {
+ characterTalk(1496);
+ }
+ }
+ return 0;
+}
+int32 ToonEngine::handleInventoryOnDrew(int32 itemId) {
+ switch (itemId) {
+ case 1:
+ sayLines(1, 1232);
+ return 1;
+ case 2:
+ sayLines(2, 1202);
+ return 1;
+ case 7:
+ if (_gameState->_currentScene == 32) {
+ runEventScript(_mouseX, _mouseY, 2, 107, 0);
+ } else if (_gameState->_currentScene < 37) {
+ sayLines(2, 1258);
+ } else {
+ sayLines(2, 1462);
+ }
+ return 1;
+ case 8:
+ sayLines(2, 1328);
+ return 1;
+ case 0xc:
+ sayLines(1, 1266);
+ return 1;
+ case 0xd:
+ sayLines(1, 1206);
+ return 1;
+ case 16:
+ sayLines(1, 1438);
+ return 1;
+ case 0x12:
+ if (_gameState->_currentScene == 30) {
+ runEventScript(_mouseX, _mouseY, 2, 106, 0);
+ _gameState->_mouseState = -1;
+ } else {
+ sayLines(2, 1200);
+ }
+ return 1;
+ case 0x14:
+ sayLines(1, 1216);
+ return 1;
+ case 22:
+ if (_gameState->_currentScene != 39 && _gameState->_currentScene != 50 && _gameState->_currentScene != 49) {
+ if (_gameState->_currentScene < 37) {
+ sayLines(1, 1256);
+ } else {
+ sayLines(1, 1456);
+ }
+ } else {
+ runEventScript(_mouseX, _mouseY, 2, 100 , 0);
+ }
+ return 1;
+ case 0x18:
+ sayLines(1, 1216);
+ return 1;
+ case 0x23:
+ sayLines(1, 1210);
+ return 1;
+ case 0x31:
+ sayLines(1, 1262);
+ return 1;
+ case 50:
+ if (_gameState->_currentScene == 37) {
+ runEventScript(_mouseX, _mouseY, 2, 103, 0);
+ return 1;
+ };
+ break;
+ case 0x36:
+ if (_gameState->_currentScene == 46) {
+ runEventScript(_mouseX, _mouseY, 2, 102, 0);
+ } else {
+ sayLines(1, 1224);
+ }
+ return 1;
+ case 0x37:
+ sayLines(1, 1408);
+ return 1;
+ case 0x20:
+ sayLines(1, 1254);
+ return 1;
+ case 0x21:
+ sayLines(1, 1268);
+ return 1;
+ case 0x22:
+ if (_gameState->_currentScene == 52) {
+ runEventScript(_mouseX, _mouseY, 2, 104, 0);
+ return 1;
+ } else {
+ _gameState->_mouseHidden = true;
+ _drew->setFacing(4);
+ sayLines(1, 1465);
+ sayLines(1, randRange(0, 1) + 1468);
+ createMouseItem(33);
+ _gameState->_mouseHidden = false;
+ return 1;
+ }
+ break;
+ case 31:
+ sayLines(1, 1436);
+ return 1;
+ case 0x1a:
+ sayLines(1, 1216);
+ return 1;
+ case 0x39:
+ sayLines(1, 1270);
+ return 1;
+ case 0x3a:
+ sayLines(1, 1444);
+ return 1;
+ case 0x3b:
+ sayLines(1, 1272);
+ return 1;
+ case 0x3f:
+ if (_gameState->_currentScene != 10 && _gameState->_currentScene != 30 && _gameState->_currentScene != 22) {
+ sayLines(1, 1274);
+ } else {
+ runEventScript(_mouseX, _mouseY, 2, 109, 0);
+ }
+ return 1;
+ case 0x41:
+ sayLines(1, 1232);
+ return 1;
+
+ case 0x4b:
+ if (_gameState->_currentScene != 53) {
+ _gameState->_mouseHidden = true;
+ _drew->setFacing(4);
+ sayLines(1, 1437);
+ sayLines(2, 1440);
+ _gameState->_mouseHidden = false;
+ } else {
+ runEventScript(_mouseX, _mouseY, 2 , 101, 0);
+ }
+ return 1;
+ case 79:
+ sayLines(1, 1242);
+ return 1;
+ case 0x4c:
+ sayLines(1, 1232);
+ return 1;
+ case 71:
+ sayLines(1, 1250);
+ return 1;
+ case 0x43:
+ sayLines(1, 1216);
+ return 1;
+ case 0x60:
+ sayLines(2, 1236);
+ return 1;
+ case 99:
+ if (_gameState->_currentScene == 43) {
+ runEventScript(_mouseX, _mouseY, 2, 105, 0);
+ }
+ _gameState->_mouseState = -1;
+ setCursor(0, false, 0, 0);
+ sayLines(1, 1555);
+ return 1;
+ case 0x5a:
+ sayLines(1, 1432);
+ return 1;
+ case 0x58:
+ sayLines(1, 1432);
+ return 1;
+ case 0x65:
+ if (_gameState->_currentScene == 52) {
+ runEventScript(_mouseX, _mouseY, 2, 104, 0);
+ } else {
+ _gameState->_mouseHidden = true;
+ _drew->setFacing(4);
+ sayLines(1, 1464);
+ sayLines(1, 1468 + randRange(0, 1));
+ createMouseItem(100);
+ _gameState->_mouseHidden = false;
+ }
+ return 1;
+ case 0x74:
+ sayLines(1, 1286);
+ return 1;
+ case 0x75:
+ sayLines(1, 1482);
+ return 1;
+ case 118:
+ sayLines(2, 1500);
+ return 1;
+ case 115:
+ sayLines(1, 1216);
+ return 1;
+ case 0x67:
+ if (_gameState->_currentScene == 52 || _gameState->_currentScene == 53) {
+ runEventScript(_mouseX, _mouseY, 2, 108, 0);
+ }
+ return 1;
+ }
+ return 0;
+}
+
+void ToonEngine::deleteItemFromInventory(int32 item) {
+ for (int32 i = 0; i < _gameState->_numInventoryItems; i++) {
+ if (_gameState->_inventory[i] == item) {
+ _gameState->_inventory[i] = 0;
+ rearrangeInventory();
+ return;
+ }
+ }
+}
+
+void ToonEngine::replaceItemFromInventory(int32 item, int32 newitem) {
+ for (int32 i = 0; i < _gameState->_numInventoryItems; i++) {
+ if (_gameState->_inventory[i] == item) {
+ _gameState->_inventory[i] = newitem;
+ return;
+ }
+ }
+}
+
+int32 ToonEngine::pauseSceneAnimationScript(int32 animScriptId, int32 tickToWait) {
+ int32 nextTicks = getTickLength() * tickToWait + getSceneAnimationScript(animScriptId)->_lastTimer;
+ if (nextTicks < getOldMilli()) {
+ getSceneAnimationScript(animScriptId)->_lastTimer = getOldMilli() + getTickLength() * tickToWait;
+ } else {
+ getSceneAnimationScript(animScriptId)->_lastTimer = nextTicks;
+ }
+ return nextTicks;
+}
+
+Common::String ToonEngine::createRoomFilename(Common::String name) {
+ Common::String file = Common::String::printf("ACT%d/%s/%s", _gameState->_currentChapter, _gameState->_locations[_gameState->_currentScene]._name, name.c_str());
+ return file;
+}
+
+void ToonEngine::createShadowLUT() {
+ // here we create the redirection table that will be used to draw shadows
+ // for each color of the palette we find the closest color in the palette that could be used for shadowed color.
+
+ // In the original program, the scale factor is 0.77f
+ // we will use 77 / 100 here.
+
+ if (!_shadowLUT) {
+ _shadowLUT = new uint8[256];
+ }
+
+ uint32 scaleNum = 77;
+ uint32 scaleDenom = 100;
+
+ for (int32 i = 0; i < 255; i++) {
+
+ // goal color
+ uint32 destR = _finalPalette[i*3+0] * scaleNum / scaleDenom;
+ uint32 destG = _finalPalette[i*3+1] * scaleNum / scaleDenom;
+ uint32 destB = _finalPalette[i*3+2] * scaleNum / scaleDenom;
+
+ // search only in the "picture palette" which is in colors 1-128 and 200-255
+ int32 colorDist = 0xffffff;
+ int32 foundColor = 0;
+
+ for (int32 c = 1; c < 129; c++) {
+
+ int32 diffR = _finalPalette[c*3+0] - destR;
+ int32 diffG = _finalPalette[c*3+1] - destG;
+ int32 diffB = _finalPalette[c*3+2] - destB;
+
+ if (colorDist > diffR * diffR + diffG * diffG + diffB * diffB) {
+ colorDist = diffR * diffR + diffG * diffG + diffB * diffB;
+ foundColor = c;
+ }
+ }
+
+ for (int32 c = 200; c < 256; c++) {
+
+ int32 diffR = _finalPalette[c*3+0] - destR;
+ int32 diffG = _finalPalette[c*3+1] - destG;
+ int32 diffB = _finalPalette[c*3+2] - destB;
+
+ if (colorDist > diffR * diffR + diffG * diffG + diffB * diffB) {
+ colorDist = diffR * diffR + diffG * diffG + diffB * diffB;
+ foundColor = c;
+ }
+ }
+
+ _shadowLUT[i] = foundColor;
+
+ }
+}
+
+bool ToonEngine::loadToonDat() {
+ Common::File in;
+ char buf[256];
+ int majVer, minVer;
+
+ in.open("toon.dat");
+
+ if (!in.isOpen()) {
+ Common::String errorMessage = "You're missing the 'toon.dat' file. Get it from the ScummVM website";
+ GUIErrorMessage(errorMessage);
+ warning("%s", errorMessage.c_str());
+ return false;
+ }
+
+ // Read header
+ in.read(buf, 4);
+ buf[4] = '\0';
+
+ if (strcmp(buf, "TOON")) {
+ Common::String errorMessage = "File 'toon.dat' is corrupt. Get it from the ScummVM website";
+ GUIErrorMessage(errorMessage);
+ warning("%s", errorMessage.c_str());
+ return false;
+ }
+
+ majVer = in.readByte();
+ minVer = in.readByte();
+
+ if ((majVer != TOON_DAT_VER_MAJ) || (minVer != TOON_DAT_VER_MIN)) {
+ snprintf(buf, 256, "File 'toon.dat' is wrong version. Expected %d.%d but got %d.%d. Get it from the ScummVM website", TOON_DAT_VER_MAJ, TOON_DAT_VER_MIN, majVer, minVer);
+ GUIErrorMessage(buf);
+ warning("%s", buf);
+
+ return false;
+ }
+
+ _numVariant = in.readUint16BE();
+
+ _locationDirNotVisited = loadTextsVariante(in);
+ _locationDirVisited = loadTextsVariante(in);
+ _specialInfoLine = loadTextsVariante(in);
+
+ return true;
+}
+
+char **ToonEngine::loadTextsVariante(Common::File &in) {
+ int numTexts;
+ int entryLen;
+ int len;
+ char **res = 0;
+ char *pos = 0;
+
+ for (int varnt = 0; varnt < _numVariant; varnt++) {
+ numTexts = in.readUint16BE();
+ entryLen = in.readUint16BE();
+ pos = (char *)malloc(entryLen);
+ if (varnt == _gameVariant) {
+ res = (char **)malloc(sizeof(char *) * numTexts);
+ res[0] = pos;
+ in.read(res[0], entryLen);
+ res[0] += DATAALIGNMENT;
+ } else {
+ in.read(pos, entryLen);
+ }
+
+ pos += DATAALIGNMENT;
+
+ for (int i = 1; i < numTexts; i++) {
+ pos -= 2;
+
+ len = READ_BE_UINT16(pos);
+ pos += 2 + len;
+
+ if (varnt == _gameVariant)
+ res[i] = pos;
+ }
+ }
+
+ return res;
+}
+
+void ToonEngine::makeLineNonWalkable(int32 x, int32 y, int32 x2, int32 y2) {
+ _currentMask->drawLineOnMask(x, y, x2, y2, false);
+}
+
+void ToonEngine::makeLineWalkable(int32 x, int32 y, int32 x2, int32 y2) {
+ _currentMask->drawLineOnMask(x, y, x2, y2, true);
+}
+
+void ToonEngine::playRoomMusic() {
+ if(_gameState->_inConversation) {
+ const char* music = getSpecialConversationMusic(_gameState->_currentConversationId);
+ if (music) {
+ _audioManager->playMusic(_gameState->_locations[_gameState->_currentScene]._name, music);
+ return;
+ }
+ }
+
+ _audioManager->playMusic(_gameState->_locations[_gameState->_currentScene]._name, _gameState->_locations[_gameState->_currentScene]._music);
+}
+
+void SceneAnimation::save(ToonEngine *vm, Common::WriteStream *stream) {
+ stream->writeByte(_active);
+ stream->writeSint32BE(_id);
+
+ if (!_active)
+ return;
+
+ if (_animInstance) {
+ stream->writeByte(1);
+ _animInstance->save(stream);
+ } else {
+ stream->writeByte(0);
+ }
+
+ if (!_animation) {
+ stream->writeByte(0);
+ } else {
+ stream->writeByte(strlen(_animation->_name) + 1);
+ stream->write(_animation->_name, strlen(_animation->_name) + 1);
+ }
+}
+void SceneAnimation::load(ToonEngine *vm, Common::ReadStream *stream) {
+
+ _active = stream->readByte();
+ _id = stream->readSint32BE();
+
+
+ if (!_active)
+ return;
+
+ if (stream->readByte() == 1) {
+ _animInstance = vm->getAnimationManager()->createNewInstance(kAnimationScene);
+ _animInstance->load(stream);
+ vm->getAnimationManager()->addInstance(_animInstance);
+ }
+
+ // load animation if any
+ char animationName[256];
+ *animationName = 0;
+ int8 strSize = stream->readByte();
+ if (!strSize) {
+ _animation = 0;
+ if (_animInstance)
+ _animInstance->setAnimation(0);
+ } else {
+ stream->read(animationName, strSize);
+ animationName[strSize] = 0;
+
+ _animation = new Animation(vm);
+ _animation->loadAnimation(animationName);
+
+ if (_animInstance) {
+ _animInstance->setAnimation(_animation, false);
+ }
+ }
+}
+
+} // End of namespace Toon
diff --git a/engines/toon/toon.h b/engines/toon/toon.h
new file mode 100644
index 0000000000..299cb403b1
--- /dev/null
+++ b/engines/toon/toon.h
@@ -0,0 +1,424 @@
+/* ScummVM - Graphic Adventure Engine
+*
+* ScummVM is the legal property of its developers, whose names
+* are too numerous to list here. Please refer to the COPYRIGHT
+* file distributed with this source distribution.
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*
+* $URL$
+* $Id$
+*
+*/
+
+#ifndef TOON_TOON_H
+#define TOON_TOON_H
+
+#include "engines/advancedDetector.h"
+#include "engines/engine.h"
+#include "graphics/surface.h"
+#include "common/random.h"
+#include "common/error.h"
+#include "toon/resource.h"
+#include "toon/script.h"
+#include "toon/script_func.h"
+#include "toon/state.h"
+#include "toon/picture.h"
+#include "toon/anim.h"
+#include "toon/movie.h"
+#include "toon/font.h"
+#include "toon/text.h"
+#include "toon/audio.h"
+
+#define TOON_DAT_VER_MAJ 0 // 1 byte
+#define TOON_DAT_VER_MIN 3 // 1 byte
+#define TOON_SAVEGAME_VERSION 4
+#define DATAALIGNMENT 4
+
+/**
+ * This is the namespace of the Toon engine.
+ *
+ * Status of this engine: ???
+ *
+ * Games using this engine:
+ * - Toonstruck
+ */
+namespace Toon {
+
+enum ToonGameType {
+ GType_TOON = 1
+};
+
+enum ToonDebugChannels {
+ kDebugAnim = 1 << 0,
+ kDebugCharacter = 1 << 1,
+ kDebugAudio = 1 << 2,
+ kDebugHotspot = 1 << 3,
+ kDebugFont = 1 << 4,
+ kDebugPath = 1 << 5,
+ kDebugMovie = 1 << 6,
+ kDebugPicture = 1 << 7,
+ kDebugResource = 1 << 8,
+ kDebugState = 1 << 9,
+ kDebugTools = 1 << 10,
+ kDebugText = 1 << 11
+};
+
+class Picture;
+class Movie;
+class Hotspots;
+class Character;
+class CharacterDrew;
+class CharacterFlux;
+class FontRenderer;
+class TextResource;
+class AudioManager;
+class PathFinding;
+
+class ToonEngine : public Engine {
+public:
+ ToonEngine(OSystem *syst, const ADGameDescription *gameDescription);
+ ~ToonEngine();
+
+ const ADGameDescription *_gameDescription;
+ Common::Language _language;
+ byte _numVariant;
+ byte _gameVariant;
+ char **_locationDirNotVisited;
+ char **_locationDirVisited;
+ char **_specialInfoLine;
+
+ Common::Error run();
+ bool showMainmenu(bool &loadedGame);
+ void init();
+ bool loadToonDat();
+ char **loadTextsVariante(Common::File &in);
+ void setPaletteEntries(uint8 *palette, int32 offset, int32 num);
+ void fixPaletteEntries(uint8 *palette, int num);
+ void flushPalette();
+ void parseInput();
+ void initChapter();
+ void initFonts();
+ void loadScene(int32 SceneId, bool forGameLoad = false);
+ void exitScene();
+ void loadCursor();
+ void setCursor(int32 type, bool inventory = false, int32 offsetX = 0, int offsetY = 0);
+ void loadAdditionalPalette(Common::String fileName, int32 mode);
+ void setupGeneralPalette();
+ void render();
+ void update(int32 timeIncrement);
+ void doFrame();
+ void updateAnimationSceneScripts(int32 timeElapsed);
+ void updateCharacters(int32 timeElapsed);
+ void setSceneAnimationScriptUpdate(bool enable);
+ bool isUpdatingSceneAnimation();
+ int32 getCurrentUpdatingSceneAnimation();
+ int32 randRange(int32 minStart, int32 maxStart);
+ void selectHotspot();
+ void clickEvent();
+ int32 runEventScript(int32 x, int32 y, int32 mode, int32 id, int32 scriptId);
+ void flipScreens();
+ void drawInfoLine();
+ void drawConversationLine();
+ const char *getLocationString(int32 locationId, bool alreadyVisited);
+ int32 getScaleAtPoint(int32 x, int32 y);
+ int32 getZAtPoint(int32 x, int32 y);
+ int32 getLayerAtPoint(int32 x, int32 y);
+ int32 characterTalk(int32 dialogid, bool blocking = true);
+ int32 simpleCharacterTalk(int32 dialogid);
+ void sayLines(int numLines, int dialogId);
+ void haveAConversation(int32 convId);
+ void processConversationClick(Conversation *conv, int32 status);
+ int32 runConversationCommand(int16 **command);
+ void prepareConversations();
+ void drawConversationIcons();
+ void simpleUpdate(bool waitCharacterToTalk = false);
+ int32 waitTicks(int32 numTicks, bool breakOnMouseClick);
+ void copyToVirtualScreen(bool updateScreen = true);
+ void getMouseEvent();
+ int32 showInventory();
+ void drawSack();
+ void addItemToInventory(int32 item);
+ void deleteItemFromInventory(int32 item);
+ void replaceItemFromInventory(int32 item, int32 destItem);
+ void rearrangeInventory();
+ void createMouseItem(int32 item);
+ void deleteMouseItem();
+ void showCutaway(Common::String cutawayPicture);
+ void hideCutaway();
+ void drawPalette();
+ void newGame();
+ void playSoundWrong();
+ void playSFX(int32 id, int32 volume);
+ void storeRifFlags(int32 location);
+ void restoreRifFlags(int32 location);
+ void getTextPosition(int32 characterId, int32 *retX, int32 *retY);
+ int32 getConversationFlag(int32 locationId, int32 param);
+ int32 getSpecialInventoryItem(int32 item);
+ Character *getCharacterById(int32 charId);
+ Common::String getSavegameName(int nr);
+ bool loadGame(int32 slot);
+ bool saveGame(int32 slot, Common::String saveGameDesc);
+ void fadeIn(int32 numFrames) ;
+ void fadeOut(int32 numFrames) ;
+ void initCharacter(int32 characterId, int32 animScriptId, int32 animToPlayId, int32 sceneAnimationId);
+ int32 handleInventoryOnFlux(int32 itemId);
+ int32 handleInventoryOnInventory(int32 itemDest, int32 itemSrc);
+ int32 handleInventoryOnDrew(int32 itemId);
+ int32 pauseSceneAnimationScript(int32 animScriptId, int32 tickToWait);
+ void updateTimer(int32 timeIncrement);
+ Common::String createRoomFilename(Common::String name);
+ void createShadowLUT();
+ void playTalkAnimOnCharacter(int32 animID, int32 characterId, bool talker);
+ void updateScrolling(bool force, int32 timeIncrement);
+ void enableTimer(int32 timerId);
+ void setTimer(int32 timerId, int32 timerWait);
+ void disableTimer(int32 timerId);
+ void updateTimers();
+ void makeLineNonWalkable(int32 x, int32 y, int32 x2, int32 y2);
+ void makeLineWalkable(int32 x, int32 y, int32 x2, int32 y2);
+ void renderInventory();
+ void viewInventoryItem(Common::String str, int32 lineId, int32 itemDest);
+ void storePalette();
+ void restorePalette();
+ const char *getSpecialConversationMusic(int32 locationId);
+ void playRoomMusic();
+ void waitForScriptStep();
+ void doMagnifierEffect();
+
+ bool canSaveGameStateCurrently();
+ bool canLoadGameStateCurrently();
+ void pauseEngineIntern(bool pause);
+
+ Resources *resources() {
+ return _resources;
+ }
+
+ State *state() {
+ return _gameState;
+ }
+
+ Graphics::Surface &getMainSurface() {
+ return *_mainSurface;
+ }
+
+ Picture *getMask() {
+ return _currentMask;
+ }
+
+ Picture *getPicture() {
+ return _currentPicture;
+ }
+
+ AnimationManager *getAnimationManager() {
+ return _animationManager;
+ }
+
+ Movie *getMoviePlayer() {
+ return _moviePlayer;
+ }
+
+ SceneAnimation *getSceneAnimation(int32 id) {
+ return &_sceneAnimations[id];
+ }
+
+ SceneAnimationScript *getSceneAnimationScript(int32 id) {
+ return &_sceneAnimationScripts[id];
+ }
+
+ EMCInterpreter *getScript() {
+ return _script;
+ }
+
+ Hotspots *getHotspots() {
+ return _hotspots;
+ }
+
+ Character *getCharacter(int32 charId) {
+ return _characters[charId];
+ }
+
+ uint8 *getShadowLUT() {
+ return _shadowLUT;
+ }
+
+ int32 getCurrentLineToSay() {
+ return _currentTextLineId;
+ }
+
+ int32 getCurrentCharacterTalking() {
+ return _currentTextLineCharacterId;
+ }
+
+ CharacterDrew *getDrew() {
+ return (CharacterDrew *)_drew;
+ }
+
+ CharacterFlux *getFlux() {
+ return (CharacterFlux *)_flux;
+ }
+
+ int32 getTickLength() {
+ return _tickLength;
+ }
+
+ int32 getOldMilli() {
+ return _oldTimer2;
+ }
+
+ OSystem *getSystem() {
+ return _system;
+ }
+
+ AudioManager *getAudioManager() {
+ return _audioManager;
+ }
+
+ int32 getScriptRegionNested() {
+ return _currentScriptRegion;
+ }
+
+ int32 getMouseX() {
+ return _mouseX;
+ }
+
+ int32 getMouseY() {
+ return _mouseY;
+ }
+
+ PathFinding *getPathFinding() {
+ return _pathFinding;
+ }
+
+ Common::WriteStream *getSaveBufferStream() {
+ return _saveBufferStream;
+ }
+
+ bool shouldQuitGame() const {
+ return _shouldQuit;
+ }
+
+ Common::Error saveGameState(int slot, const char *desc) {
+
+ return (saveGame(slot, desc) ? Common::kWritingFailed : Common::kNoError);
+ }
+
+ Common::Error loadGameState(int slot) {
+ return (loadGame(slot) ? Common::kReadingFailed : Common::kNoError);
+ }
+
+ bool hasFeature(EngineFeature f) const {
+ return
+ (f == kSupportsRTL) ||
+ (f == kSupportsLoadingDuringRuntime) ||
+ (f == kSupportsSavingDuringRuntime);
+ }
+
+protected:
+ OSystem *_system;
+ int32 _tickLength;
+ Resources *_resources;
+ TextResource *_genericTexts;
+ TextResource *_roomTexts;
+ State *_gameState;
+ uint8 *_finalPalette;
+ uint8 *_backupPalette;
+ uint8 *_additionalPalette1;
+ uint8 *_additionalPalette2;
+ uint8 *_cutawayPalette;
+ uint8 *_universalPalette;
+ uint8 *_fluxPalette;
+ uint8 *_roomScaleData;
+ uint8 *_shadowLUT;
+
+ Picture *_currentPicture;
+ Picture *_currentMask;
+ Picture *_currentCutaway;
+ Picture *_inventoryPicture;
+ PathFinding *_pathFinding;
+
+ EMCInterpreter *_script;
+ EMCData _scriptData;
+ EMCState _scriptState[4];
+ int32 _currentScriptRegion; // script region ( nested script run )
+
+ ScriptFunc *_script_func;
+
+ SceneAnimation _sceneAnimations[64];
+ SceneAnimationScript _sceneAnimationScripts[64];
+ int32 _lastProcessedSceneScript;
+ bool _animationSceneScriptRunFlag;
+ bool _updatingSceneScriptRunFlag;
+
+ Graphics::Surface *_mainSurface;
+
+ AnimationInstance *_cursorAnimationInstance;
+ Animation *_cursorAnimation;
+ Animation *_dialogIcons;
+ Animation *_inventoryIcons;
+ Animation *_inventoryIconSlots;
+ int32 _cursorOffsetX;
+ int32 _cursorOffsetY;
+
+ char *_currentTextLine;
+ int32 _currentTextLineId;
+ int32 _currentTextLineX;
+ int32 _currentTextLineY;
+ int32 _currentTextLineCharacterId;
+
+ int32 _oldScrollValue;
+
+ AnimationManager *_animationManager;
+
+ Character *_characters[32];
+ Character *_drew;
+ Character *_flux;
+
+ Hotspots *_hotspots;
+ int32 _currentHotspotItem;
+
+ bool _shouldQuit;
+ int32 _scriptStep;
+
+ int32 _mouseX;
+ int32 _mouseY;
+ int32 _mouseButton;
+ int32 _lastMouseButton;
+
+ int32 _oldTimer;
+ int32 _oldTimer2;
+
+ Movie *_moviePlayer;
+
+ Common::RandomSource _rnd;
+
+ FontRenderer *_fontRenderer;
+ Animation *_fontToon;
+ Animation *_fontEZ;
+
+ AudioManager *_audioManager;
+
+ Common::MemoryWriteStreamDynamic *_saveBufferStream;
+
+ int16 *_conversationData;
+
+ bool _firstFrame;
+ bool _isDemo;
+ bool _showConversationText;
+};
+
+} // End of namespace Toon
+
+#endif