aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
authorGregory Montoir2006-11-03 21:23:07 +0000
committerGregory Montoir2006-11-03 21:23:07 +0000
commit13d9cdbd26b1c07edf47b9e4731b9d652a294ba5 (patch)
tree4ecb39b0e40f592b36fbd5ef427e2ad4ea29ebd1 /engines
parentc71e6599bc160329319c0c05ca453184a45fb0f7 (diff)
downloadscummvm-rg350-13d9cdbd26b1c07edf47b9e4731b9d652a294ba5.tar.gz
scummvm-rg350-13d9cdbd26b1c07edf47b9e4731b9d652a294ba5.tar.bz2
scummvm-rg350-13d9cdbd26b1c07edf47b9e4731b9d652a294ba5.zip
added 'touche' engine for the game 'Touche: The Adventures of the 5th Musketeer'
svn-id: r24592
Diffstat (limited to 'engines')
-rw-r--r--engines/engines.mk15
-rw-r--r--engines/touche/graphics.cpp210
-rw-r--r--engines/touche/graphics.h54
-rw-r--r--engines/touche/module.mk19
-rw-r--r--engines/touche/opcodes.cpp822
-rw-r--r--engines/touche/plugin.cpp154
-rw-r--r--engines/touche/resource.cpp645
-rw-r--r--engines/touche/saveload.cpp418
-rw-r--r--engines/touche/staticres.cpp659
-rw-r--r--engines/touche/touche.cpp3271
-rw-r--r--engines/touche/touche.h778
-rw-r--r--engines/touche/ui.cpp557
12 files changed, 7597 insertions, 5 deletions
diff --git a/engines/engines.mk b/engines/engines.mk
index d4be1c1674..a00b509d02 100644
--- a/engines/engines.mk
+++ b/engines/engines.mk
@@ -45,19 +45,19 @@ endif
ifdef DISABLE_SAGA
DEFINES += -DDISABLE_SAGA
-else
+else
MODULES += engines/saga
endif
ifdef DISABLE_KYRA
DEFINES += -DDISABLE_KYRA
-else
+else
MODULES += engines/kyra
endif
ifdef DISABLE_GOB
DEFINES += -DDISABLE_GOB
-else
+else
MODULES += engines/gob
endif
@@ -69,13 +69,18 @@ endif
ifdef DISABLE_CINE
DEFINES += -DDISABLE_CINE
-else
+else
MODULES += engines/cine
endif
ifdef DISABLE_AGI
DEFINES += -DDISABLE_AGI
-else
+else
MODULES += engines/agi
endif
+ifdef DISABLE_TOUCHE
+DEFINES += -DDISABLE_TOUCHE
+else
+MODULES += engines/touche
+endif
diff --git a/engines/touche/graphics.cpp b/engines/touche/graphics.cpp
new file mode 100644
index 0000000000..ec0c63ff79
--- /dev/null
+++ b/engines/touche/graphics.cpp
@@ -0,0 +1,210 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id: $
+ *
+ */
+
+#include "common/stdafx.h"
+#include "common/endian.h"
+
+#include "touche/graphics.h"
+
+namespace Touche {
+
+int Graphics::getStringWidth16(const char *str) {
+ int w = 0;
+ while (*str) {
+ char chr = *str++;
+ w += getCharWidth16((uint8)chr);
+ if (*str == '\\') {
+ break;
+ }
+ }
+ return w;
+}
+
+int Graphics::getCharWidth16(uint8 chr) {
+ assert(chr >= 32 && chr < 174);
+ const uint8 *chrData = _fontData + _fontOffs[chr - 32];
+ return chrData[2];
+}
+
+void Graphics::drawString16(uint8 *dst, int dstPitch, uint16 color, int x, int y, const char *str) {
+ while (*str) {
+ uint8 chr = (uint8)*str++;
+ x += drawChar16(dst, dstPitch, chr, x, y, color);
+ }
+}
+
+int Graphics::drawChar16(uint8 *dst, int dstPitch, uint8 chr, int x, int y, uint16 color) {
+ dst += y * dstPitch + x;
+ uint8 color1 = color & 0xFF;
+ uint8 color2 = color >> 8;
+ assert(chr >= 32 && chr < 174);
+ const uint8 *chrData = _fontData + _fontOffs[chr - 32];
+ int chrHeight = chrData[1];
+ int chrWidth = chrData[2];
+ chrData += 3;
+ while (chrHeight--) {
+ int shiftCount = 0;
+ int mask = 0;
+ for (int i = 0; i < chrWidth; ++i) {
+ if (shiftCount == 0) {
+ mask = READ_BE_UINT16(chrData); chrData += 2;
+ shiftCount = 8;
+ }
+ int b = (mask & 0xC000) >> 14;
+ mask <<= 2;
+ --shiftCount;
+ if (b) {
+ if (b & 2) {
+ dst[i] = color2;
+ } else {
+ dst[i] = color1;
+ }
+ }
+ }
+ dst += dstPitch;
+ }
+ return chrWidth;
+}
+
+void Graphics::fillRect(uint8 *dst, int dstPitch, int x, int y, int w, int h, uint8 color) {
+ dst += y * dstPitch + x;
+ while (h--) {
+ memset(dst, color, w);
+ dst += dstPitch;
+ }
+}
+
+void Graphics::drawRect(uint8 *dst, int dstPitch, int x, int y, int w, int h, uint8 color1, uint8 color2) {
+ int x1 = x;
+ int y1 = y;
+ int x2 = x + w - 1;
+ int y2 = y + h - 1;
+ drawLineHV(dst, dstPitch, x1, y1, x2, y1, color1);
+ drawLineHV(dst, dstPitch, x1, y1, x1, y2, color1);
+ drawLineHV(dst, dstPitch, x2, y1 + 1, x2, y2, color2);
+ drawLineHV(dst, dstPitch, x1 + 1, y2, x2, y2, color2);
+}
+
+void Graphics::drawLineHV(uint8 *dst, int dstPitch, int x1, int y1, int x2, int y2, uint8 color) {
+ if (x2 < x1) {
+ SWAP(x2, x1);
+ }
+ if (y2 < y1) {
+ SWAP(y2, y1);
+ }
+ if (y1 == y2) {
+ for (int x = x1; x < x2; ++x) {
+ dst[y1 * dstPitch + x] = color;
+ }
+ } else {
+ for (int y = y1; y < y2; ++y) {
+ dst[y * dstPitch + x1] = color;
+ }
+ }
+}
+
+void Graphics::drawLine(uint8 *dst, int dstPitch, int x1, int y1, int x2, int y2, uint8 color) {
+ assert(x1 >= 0 && y1 >= 0 && x2 >= 0 && y2 >= 0);
+
+ dst += y1 * dstPitch + x1;
+
+ int yInc, dy = y2 - y1;
+ if (dy < 0) {
+ dy = -dy;
+ yInc = -dstPitch;
+ } else {
+ yInc = dstPitch;
+ }
+
+ int xInc, dx = x2 - x1;
+ if (dx < 0) {
+ dx = -dx;
+ xInc = -1;
+ } else {
+ xInc = 1;
+ }
+
+ int step = 0;
+
+ if (dx > dy) {
+ for (int i = 0; i < dx + 1; ++i) {
+ *dst = color;
+ dst += xInc;
+ step += dy;
+ if (step > dx) {
+ step -= dx;
+ dst += yInc;
+ }
+ }
+ } else {
+ for (int i = 0; i < dy + 1; ++i) {
+ *dst = color;
+ dst += yInc;
+ step += dx;
+ if (step > 0) {
+ step -= dy;
+ dst += xInc;
+ }
+ }
+ }
+}
+
+void Graphics::copyRect(uint8 *dst, int dstPitch, int dstX, int dstY, const uint8 *src, int srcPitch, int srcX, int srcY, int w, int h, int flags) {
+ if (w != 0 && h != 0) {
+ if (flags & kHFlipped) {
+ srcY += h - 1;
+ srcPitch = -srcPitch;
+ }
+ int u = 1;
+ if (flags & kVFlipped) {
+ srcX += w - 1;
+ u = -1;
+ }
+ dst += dstY * dstPitch + dstX;
+ src += srcY * srcPitch + srcX;
+ while (h--) {
+ for (int i = 0; i < w; ++i) {
+ if ((flags & kTransparent) == 0 || src[u * i] != 0) {
+ dst[i] = src[u * i];
+ }
+ }
+ dst += dstPitch;
+ src += srcPitch;
+ }
+ }
+}
+
+void Graphics::copyMask(uint8 *dst, int dstPitch, int dstX, int dstY, const uint8 *src, int srcPitch, int srcX, int srcY, int w, int h, uint8 fillColor) {
+ dst += dstY * dstPitch * dstX;
+ src += srcY * srcPitch + srcX;
+ while (h--) {
+ for (int i = 0; i < w; ++i) {
+ if (src[i] != 0) {
+ dst[i] = fillColor;
+ }
+ }
+ dst += dstPitch;
+ src += srcPitch;
+ }
+}
+
+} // namespace Touche
diff --git a/engines/touche/graphics.h b/engines/touche/graphics.h
new file mode 100644
index 0000000000..a55e60c4f3
--- /dev/null
+++ b/engines/touche/graphics.h
@@ -0,0 +1,54 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id: $
+ *
+ */
+
+#ifndef TOUCHE_GRAPHICS_H
+#define TOUCHE_GRAPHICS_H
+
+#include "common/util.h"
+
+namespace Touche {
+
+struct Graphics {
+ enum {
+ kVFlipped = 1 << 0,
+ kHFlipped = 1 << 1,
+ kTransparent = 1 << 2
+ };
+
+ static int getStringWidth16(const char *str);
+ static int getCharWidth16(uint8 chr);
+ static void drawString16(uint8 *dst, int dstPitch, uint16 color, int x, int y, const char *str);
+ static int drawChar16(uint8 *dst, int dstPitch, uint8 chr, int x, int y, uint16 color);
+ static void fillRect(uint8 *dst, int dstPitch, int x, int y, int w, int h, uint8 color);
+ static void drawRect(uint8 *dst, int dstPitch, int x, int y, int w, int h, uint8 color1, uint8 color2);
+ static void drawLineHV(uint8 *dst, int dstPitch, int x1, int y1, int x2, int y2, uint8 color);
+ static void drawLine(uint8 *dst, int dstPitch, int x1, int y1, int x2, int y2, uint8 color);
+ static void copyRect(uint8 *dst, int dstPitch, int dstX, int dstY, const uint8 *src, int srcPitch, int srcX, int srcY, int w, int h, int flags = 0);
+ static void copyMask(uint8 *dst, int dstPitch, int dstX, int dstY, const uint8 *src, int srcPitch, int srcX, int srcY, int w, int h, uint8 fillColor);
+
+ static const uint16 _fontOffs[];
+ static const uint8 _fontData[];
+};
+
+} // namespace Touche
+
+#endif
diff --git a/engines/touche/module.mk b/engines/touche/module.mk
new file mode 100644
index 0000000000..c2d12ca813
--- /dev/null
+++ b/engines/touche/module.mk
@@ -0,0 +1,19 @@
+MODULE := engines/touche
+
+MODULE_OBJS := \
+ graphics.o \
+ plugin.o \
+ opcodes.o \
+ resource.o \
+ saveload.o \
+ staticres.o \
+ touche.o \
+ ui.o
+
+# This module can be built as a plugin
+ifdef BUILD_PLUGINS
+PLUGIN := 1
+endif
+
+# Include common rules
+include $(srcdir)/rules.mk
diff --git a/engines/touche/opcodes.cpp b/engines/touche/opcodes.cpp
new file mode 100644
index 0000000000..fc71d2835c
--- /dev/null
+++ b/engines/touche/opcodes.cpp
@@ -0,0 +1,822 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id: $
+ *
+ */
+
+#include "common/stdafx.h"
+
+#include "touche/touche.h"
+
+namespace Touche {
+
+void ToucheEngine::op_nop() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_nop()");
+}
+
+void ToucheEngine::op_jnz() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_jnz()");
+ if (*_script.stackDataPtr != 0) {
+ _script.dataOffset = _script.readNextWord();
+ } else {
+ _script.dataOffset += 2;
+ }
+}
+
+void ToucheEngine::op_jz() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_jz()");
+ if (*_script.stackDataPtr == 0) {
+ _script.dataOffset = _script.readNextWord();
+ } else {
+ _script.dataOffset += 2;
+ }
+}
+
+void ToucheEngine::op_jmp() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_jmp()");
+ _script.dataOffset = _script.readNextWord();
+}
+
+void ToucheEngine::op_true() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_true()");
+ *_script.stackDataPtr = -1;
+}
+
+void ToucheEngine::op_false() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_false()");
+ *_script.stackDataPtr = 0;
+}
+
+void ToucheEngine::op_push() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_push()");
+ --_script.stackDataPtr;
+ *_script.stackDataPtr = 0;
+}
+
+void ToucheEngine::op_testFalse() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_testFalse()");
+ if (*_script.stackDataPtr == 0) {
+ *_script.stackDataPtr = -1;
+ } else {
+ *_script.stackDataPtr = 0;
+ }
+}
+
+void ToucheEngine::op_add() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_add()");
+ int16 val = *_script.stackDataPtr++;
+ *_script.stackDataPtr += val;
+}
+
+void ToucheEngine::op_sub() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_sub()");
+ int16 val = *_script.stackDataPtr++;
+ *_script.stackDataPtr -= val;
+}
+
+void ToucheEngine::op_mul() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_mul()");
+ int16 val = *_script.stackDataPtr++;
+ *_script.stackDataPtr *= val;
+}
+
+void ToucheEngine::op_div() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_div()");
+ int16 val = *_script.stackDataPtr++;
+ if (val != 0) {
+ *_script.stackDataPtr /= val;
+ } else {
+ *_script.stackDataPtr = 0;
+ }
+}
+
+void ToucheEngine::op_mod() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_mod()");
+ int16 val = *_script.stackDataPtr++;
+ if (val != 0) {
+ *_script.stackDataPtr %= val;
+ } else {
+ *_script.stackDataPtr = 0;
+ }
+}
+
+void ToucheEngine::op_and() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_and()");
+ uint16 val = *_script.stackDataPtr++;
+ *_script.stackDataPtr &= val;
+}
+
+void ToucheEngine::op_or() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_or()");
+ uint16 val = *_script.stackDataPtr++;
+ *_script.stackDataPtr |= val;
+}
+
+void ToucheEngine::op_not() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_not()");
+ uint16 val = *_script.stackDataPtr;
+ *_script.stackDataPtr = ~val;
+}
+
+void ToucheEngine::op_testGreater() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_testGreater()");
+ int16 val = *_script.stackDataPtr++;
+ if (val > *_script.stackDataPtr) {
+ *_script.stackDataPtr = -1;
+ } else {
+ *_script.stackDataPtr = 0;
+ }
+}
+
+void ToucheEngine::op_testEquals() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_testEquals()");
+ int16 val = *_script.stackDataPtr++;
+ if (val == *_script.stackDataPtr) {
+ *_script.stackDataPtr = -1;
+ } else {
+ *_script.stackDataPtr = 0;
+ }
+}
+
+void ToucheEngine::op_testLower() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_testLower()");
+ int16 val = *_script.stackDataPtr++;
+ if (val < *_script.stackDataPtr) {
+ *_script.stackDataPtr = -1;
+ } else {
+ *_script.stackDataPtr = 0;
+ }
+}
+
+void ToucheEngine::op_fetchScriptWord() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_fetchScriptWord()");
+ int16 val = _script.readNextWord();
+ *_script.stackDataPtr = val;
+}
+
+void ToucheEngine::op_testGreaterOrEquals() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_testGreaterOrEquals()");
+ int16 val = *_script.stackDataPtr++;
+ if (val >= *_script.stackDataPtr) {
+ *_script.stackDataPtr = -1;
+ } else {
+ *_script.stackDataPtr = 0;
+ }
+}
+
+void ToucheEngine::op_testLowerOrEquals() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_testLowerOrEquals()");
+ int16 val = *_script.stackDataPtr++;
+ if (val <= *_script.stackDataPtr) {
+ *_script.stackDataPtr = -1;
+ } else {
+ *_script.stackDataPtr = 0;
+ }
+}
+
+void ToucheEngine::op_testNotEquals() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_testNotEquals()");
+ int16 val = *_script.stackDataPtr++;
+ if (val != *_script.stackDataPtr) {
+ *_script.stackDataPtr = -1;
+ } else {
+ *_script.stackDataPtr = 0;
+ }
+}
+
+void ToucheEngine::op_endConversation() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_endConversation()");
+ _script.quitFlag = 1;
+ _conversationEnded = true;
+ _disabledInputCounter = false;
+}
+
+void ToucheEngine::op_stopScript() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_stopScript()");
+ _script.quitFlag = 1;
+}
+
+void ToucheEngine::op_getFlag() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_getFlag()");
+ uint16 fl = _script.readNextWord();
+ *_script.stackDataPtr = _flagsTable[fl];
+}
+
+void ToucheEngine::op_setFlag() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_setFlag()");
+ uint16 flag = _script.readNextWord();
+ int16 val = *_script.stackDataPtr;
+ _flagsTable[flag] = val;
+ switch (flag) {
+ case 104:
+ _currentKeyCharNum = val;
+ break;
+ case 612:
+ _flagsTable[613] = getRandomNumber(val);
+ break;
+ case 614:
+ case 615:
+ _fullRedrawCounter = 1;
+ break;
+ default:
+ break;
+ }
+}
+
+void ToucheEngine::op_fetchScriptByte() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_fetchScriptByte()");
+ int16 val = _script.readNextByte();
+ *_script.stackDataPtr = val;
+}
+
+void ToucheEngine::op_getScriptValue() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_getScriptValue()");
+ uint8 index = _script.readNextByte();
+ assert(index < _script.stackDataBasePtr[2]);
+ *_script.stackDataPtr = _script.stackDataBasePtr[3 + index];
+}
+
+void ToucheEngine::op_setScriptValue() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_setScriptValue()");
+ uint8 index = _script.readNextByte();
+ assert(index < _script.stackDataBasePtr[2]);
+ _script.stackDataBasePtr[3 + index] = *_script.stackDataPtr;
+}
+
+void ToucheEngine::op_getKeyCharWalkBox() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_getKeyCharWalkBox()");
+ int16 keyChar = _script.readNextWord();
+ if (keyChar == 256) {
+ keyChar = _currentKeyCharNum;
+ }
+ *_script.stackDataPtr = _keyCharsTable[keyChar].walkDataNum;
+}
+
+void ToucheEngine::op_startSound() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_startSound()");
+ _newSoundNum = _script.readNextWord();
+ _newSoundDelay = _script.readNextWord();
+ _newSoundPriority = 1;
+}
+
+void ToucheEngine::op_initKeyCharTalk() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_initKeyCharTalk()");
+ int16 keyChar = _script.readNextWord();
+ if (keyChar == 256) {
+ keyChar = _currentKeyCharNum;
+ }
+ int16 num = _script.readNextWord();
+ if (num == -1) {
+ num = _script.readNextWord();
+ num = _keyCharsTable[num].pointsDataNum;
+ }
+ sortPointsData(-1, num);
+ buildWalkPointsList(keyChar);
+ _keyCharsTable[keyChar].flags &= ~0x10;
+ if (_script.keyCharNum == keyChar) {
+ removeFromTalkTable(_script.keyCharNum);
+ _keyCharsTable[keyChar].waitingKeyCharPosTable[0] = -1;
+ _keyCharsTable[keyChar].waitingKeyCharPosTable[2] = -1;
+ _keyCharsTable[keyChar].waitingKeyChar = _script.keyCharNum;
+ _keyCharsTable[keyChar].waitingKeyCharPosTable[1] = num;
+ _script.quitFlag = 3;
+ }
+}
+
+void ToucheEngine::op_loadRoom() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_loadRoom()");
+ int16 num = _script.readNextWord();
+ res_loadRoom(num);
+}
+
+void ToucheEngine::op_updateRoom() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_updateRoom()");
+ int16 area = _script.readNextWord();
+ updateRoomAreas(area, 0);
+}
+
+void ToucheEngine::op_startTalk() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_startTalk()");
+ int16 keyChar = _script.readNextWord();
+ int16 num = _script.readNextWord();
+ if (num == 750) {
+ return;
+ }
+ if (keyChar == 256) {
+ keyChar = _currentKeyCharNum;
+ num += _currentKeyCharNum & 1;
+ }
+ addToTalkTable(keyChar, num, _script.keyCharNum);
+ _script.quitFlag = 3;
+}
+
+void ToucheEngine::op_loadSprite() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_loadSprite()");
+ int16 index = _script.readNextWord();
+ int16 num = _script.readNextWord();
+ res_loadSprite(num, index);
+}
+
+void ToucheEngine::op_loadSequence() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_loadSequence()");
+ int16 index = _script.readNextWord();
+ int16 num = _script.readNextWord();
+ res_loadSequence(num, index);
+}
+
+void ToucheEngine::op_setKeyCharBox() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_setKeyCharBox()");
+ int16 keyChar = _script.readNextWord();
+ int16 num = _script.readNextWord();
+ if (keyChar == 256) {
+ keyChar = _currentKeyCharNum;
+ }
+ setKeyCharBox(keyChar, num);
+}
+
+void ToucheEngine::op_initKeyCharScript() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_initKeyCharScript()");
+ int16 keyChar = _script.readNextWord();
+ int16 color = _script.readNextWord();
+ int16 f1 = _script.readNextWord();
+ int16 f2 = _script.readNextWord();
+ int16 f3 = _script.readNextWord();
+ setKeyCharTextColor(keyChar, color);
+ initKeyCharScript(keyChar, f1, f2, f3);
+}
+
+void ToucheEngine::op_setKeyCharFrame() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_setKeyCharFrame()");
+ int16 keyChar = _script.readNextWord();
+ int16 val1 = _script.readNextWord();
+ int16 val2 = _script.readNextWord();
+ int16 val3 = _script.readNextWord();
+ if (keyChar == 256) {
+ keyChar = _currentKeyCharNum;
+ }
+ setKeyCharFrame(keyChar, val1, val2, val3);
+}
+
+void ToucheEngine::op_setKeyCharDirection() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_setKeyCharDirection()");
+ int16 keyChar = _script.readNextWord();
+ int16 dir = _script.readNextWord();
+ if (keyChar == 256) {
+ keyChar = _currentKeyCharNum;
+ }
+ setKeyCharFacingDirection(keyChar, dir);
+}
+
+void ToucheEngine::op_clearConversationChoices() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_clearConversationChoices()");
+ clearConversationChoices();
+}
+
+void ToucheEngine::op_addConversationChoice() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_addConversationChoice()");
+ int16 num = _script.readNextWord();
+ addConversationChoice(num);
+}
+
+void ToucheEngine::op_removeConversationChoice() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_removeConversationChoice()");
+ int16 num = _script.readNextWord();
+ removeConversationChoice(num);
+}
+
+void ToucheEngine::op_getInventoryItem() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_getInventoryItem()");
+ int16 keyChar = _script.readNextWord();
+ uint16 item = _script.readNextWord();
+ if (keyChar == 256) {
+ keyChar = _currentKeyCharNum;
+ }
+ assert(keyChar >= 0 && keyChar < NUM_KEYCHARS);
+ assert(item < sizeof(_keyCharsTable[keyChar].inventoryItems));
+ *_script.stackDataPtr = _keyCharsTable[keyChar].inventoryItems[item];
+}
+
+void ToucheEngine::op_setInventoryItem() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_setInventoryItem()");
+ int16 keyChar = _script.readNextWord();
+ uint16 item = _script.readNextWord();
+ if (item == 4) {
+ setKeyCharMoney();
+ }
+ if (keyChar == 256) {
+ keyChar = _currentKeyCharNum;
+ }
+ assert(keyChar >= 0 && keyChar < NUM_KEYCHARS);
+ assert(item < sizeof(_keyCharsTable[keyChar].inventoryItems));
+ _keyCharsTable[keyChar].inventoryItems[item] = *_script.stackDataPtr;
+ if (item == 4 && !_hideInventoryTexts) {
+ drawAmountOfMoneyInInventory();
+ }
+}
+
+void ToucheEngine::op_startEpisode() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_startEpisode()");
+ _newEpisodeNum = _script.readNextWord();
+ _flagsTable[0] = _script.readNextWord();
+ _disabledInputCounter = 1;
+ _script.quitFlag = 1;
+}
+
+void ToucheEngine::op_setConversationNum() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_setConversationNum()");
+ _conversationNum = _script.readNextWord();
+}
+
+void ToucheEngine::op_enableInventoryItem() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_enableInventoryItem()");
+ int16 flag = _script.readNextWord();
+ int16 item = _script.readNextWord();
+ int16 rnd = _script.readNextWord();
+ changeInventoryItemState(flag, item, rnd, 1);
+}
+
+void ToucheEngine::op_enableInput() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_enableInput()");
+ ++_disabledInputCounter;
+}
+
+void ToucheEngine::op_disableInput() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_disableInput()");
+ if (_disabledInputCounter != 0) {
+ --_disabledInputCounter;
+ }
+}
+
+void ToucheEngine::op_faceKeyChar() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_faceKeyChar()");
+ int16 keyChar1 = _script.readNextWord();
+ int16 keyChar2 = _script.readNextWord();
+ if (keyChar1 == 256) {
+ keyChar1 = _currentKeyCharNum;
+ }
+ if (_keyCharsTable[keyChar1].xPos <= _keyCharsTable[keyChar2].xPos) {
+ _keyCharsTable[keyChar2].facingDirection = 3;
+ } else {
+ _keyCharsTable[keyChar2].facingDirection = 0;
+ }
+}
+
+void ToucheEngine::op_getKeyCharCurrentAnim() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_getKeyCharCurrentAnim()");
+ int16 keyChar = _script.readNextWord();
+ assert(keyChar >= 0 && keyChar < NUM_KEYCHARS);
+ *_script.stackDataPtr = _keyCharsTable[keyChar].currentAnim;
+}
+
+void ToucheEngine::op_getCurrentKeyChar() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_getCurrentKeyChar()");
+ *_script.stackDataPtr = _currentKeyCharNum;
+}
+
+void ToucheEngine::op_isKeyCharActive() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_isKeyCharActive()");
+ int16 keyChar = _script.readNextWord();
+ if (keyChar == 256) {
+ keyChar = _currentKeyCharNum;
+ }
+ assert(keyChar >= 0 && keyChar < NUM_KEYCHARS);
+ *_script.stackDataPtr = _keyCharsTable[keyChar].num != 0 ? 1 : 0;
+}
+
+void ToucheEngine::op_setPalette() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_setPalette()");
+ int16 r = _script.readNextWord();
+ int16 g = _script.readNextWord();
+ int16 b = _script.readNextWord();
+ setPalette(0, 240, r, g, b);
+}
+
+void ToucheEngine::op_changeWalkPath() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_changeWalkPath()");
+ int16 num1 = _script.readNextWord();
+ int16 num2 = _script.readNextWord();
+ int16 val = _script.readNextWord();
+ changeWalkPath(num1, num2, val);
+}
+
+void ToucheEngine::op_lockWalkPath() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_lockWalkPath()");
+ int16 num1 = _script.readNextWord();
+ int16 num2 = _script.readNextWord();
+ lockWalkPath(num1, num2);
+}
+
+void ToucheEngine::op_initializeKeyChar() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_initializeKeyChar()");
+ int16 keyChar = _script.readNextWord();
+ if (keyChar == 256) {
+ keyChar = _currentKeyCharNum;
+ }
+ initKeyChars(keyChar);
+}
+
+void ToucheEngine::op_setupWaitingKeyChars() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_setupWaitingKeyChars()");
+ int16 keyChar = _script.readNextWord();
+ if (keyChar == 256) {
+ keyChar = _currentKeyCharNum;
+ }
+ int16 val1 = _script.readNextWord();
+ int16 val2 = _script.readNextWord();
+ if (val1 == -1) {
+ _waitingSetKeyCharNum2 = keyChar;
+ _waitingSetKeyCharNum1 = val2;
+ _waitingSetKeyCharNum3 = _script.keyCharNum;
+ _script.quitFlag = 3;
+ } else {
+ _keyCharsTable[_script.keyCharNum].waitingKeyCharPosTable[0] = -1;
+ _keyCharsTable[_script.keyCharNum].waitingKeyCharPosTable[1] = -1;
+ _keyCharsTable[_script.keyCharNum].waitingKeyCharPosTable[2] = -1;
+ _keyCharsTable[_script.keyCharNum].waitingKeyChar = keyChar;
+ assert(val1 >= 0 && val1 < 3);
+ _keyCharsTable[_script.keyCharNum].waitingKeyCharPosTable[val1] = val2;
+ _script.quitFlag = 3;
+ }
+}
+
+void ToucheEngine::op_updateRoomAreas() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_setupWaitingKeyChars()");
+ int16 area = _script.readNextWord();
+ updateRoomAreas(area, 1);
+}
+
+void ToucheEngine::op_unlockWalkPath() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_unlockWalkPath()");
+ int16 num1 = _script.readNextWord();
+ int16 num2 = _script.readNextWord();
+ unlockWalkPath(num1, num2);
+}
+
+void ToucheEngine::op_addItemToInventoryAndRedraw() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_addItemToInventoryAndRedraw()");
+ int16 inventory = _script.readNextWord();
+ int16 item = *_script.stackDataPtr;
+ if (inventory == 256) {
+ inventory = _currentKeyCharNum;
+ }
+ addItemToInventory(inventory, item);
+ if (_currentKeyCharNum == inventory && !_hideInventoryTexts) {
+ drawInventory(_currentKeyCharNum, 1);
+ }
+}
+
+void ToucheEngine::op_giveItemTo() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_giveItemTo()");
+ _giveItemToCounter = 1;
+ _giveItemToObjectNum = _script.readNextWord();
+ _giveItemToKeyCharNum = _script.keyCharNum;
+ _script.quitFlag = 3;
+}
+
+void ToucheEngine::op_resetHitBoxes() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_resetHitBoxes()");
+ int16 num = _script.readNextWord();
+ if (num & 0x4000) {
+ num &= 0xFF;
+ _keyCharsTable[num].strNum = 1;
+ } else {
+ for (uint i = 0; i < _programHitBoxTable.size(); ++i) {
+ if (_programHitBoxTable[i].item == num) {
+ _programHitBoxTable[i].str = _programHitBoxTable[i].defaultStr;
+ break;
+ }
+ }
+ }
+}
+
+void ToucheEngine::op_fadePalette() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_fadePalette()");
+ int16 fadeOut = _script.readNextWord();
+ if (fadeOut) {
+ fadePalette(0, 240, 255, -2, 128);
+ } else {
+ fadePalette(0, 240, 0, 2, 128);
+ }
+}
+
+void ToucheEngine::op_disableInventoryItem() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_disableInventoryItem()");
+ int16 flag = _script.readNextWord();
+ int16 item = _script.readNextWord();
+ int16 rnd = _script.readNextWord();
+ changeInventoryItemState(flag, item, rnd, 0);
+}
+
+void ToucheEngine::op_getInventoryItemFlags() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_getInventoryItemFlags()");
+ int16 item = _script.readNextWord();
+ int16 flags = _inventoryItemsInfoTable[item];
+ if (flags & 0x10) {
+ flags &= 0xF;
+ } else {
+ flags &= ~0xF;
+ }
+ *_script.stackDataPtr = flags;
+}
+
+void ToucheEngine::op_drawInventory() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_drawInventory()");
+ int16 num = _script.readNextWord();
+ drawInventory(num, 1);
+}
+
+void ToucheEngine::op_stopKeyCharScript() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_stopKeyCharScript()");
+ int16 keyChar = _script.readNextWord();
+ if (keyChar == 256) {
+ keyChar = _currentKeyCharNum;
+ }
+ assert(keyChar >= 0 && keyChar < NUM_KEYCHARS);
+ _keyCharsTable[keyChar].flags |= kScriptStopped;
+}
+
+void ToucheEngine::op_restartKeyCharScript() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_restartKeyCharScript()");
+ int16 keyChar = _script.readNextWord();
+ if (keyChar == 256) {
+ keyChar = _currentKeyCharNum;
+ }
+ assert(keyChar >= 0 && keyChar < NUM_KEYCHARS);
+ KeyChar *key = &_keyCharsTable[keyChar];
+ key->flags &= ~(kScriptStopped | kScriptPaused);
+ key->scriptDataOffset = key->scriptDataStartOffset;
+ key->scriptStackPtr = &key->scriptStackTable[39];
+}
+
+void ToucheEngine::op_getKeyCharCurrentWalkBox() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_getKeyCharCurrentWalkBox()");
+ int16 keyChar = _script.readNextWord();
+ if (keyChar == 256) {
+ keyChar = _currentKeyCharNum;
+ }
+ assert(keyChar >= 0 && keyChar < NUM_KEYCHARS);
+ *_script.stackDataPtr = _keyCharsTable[keyChar].currentWalkBox;
+}
+
+void ToucheEngine::op_getKeyCharPointsDataNum() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_getKeyCharPointsDataNum()");
+ int16 keyChar = _script.readNextWord();
+ if (keyChar == 256) {
+ keyChar = _currentKeyCharNum;
+ }
+ assert(keyChar >= 0 && keyChar < NUM_KEYCHARS);
+ *_script.stackDataPtr = _keyCharsTable[keyChar].pointsDataNum;
+}
+
+void ToucheEngine::op_setupFollowingKeyChar() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_setupFollowingKeyChar()");
+ int16 val = _script.readNextWord();
+ int16 keyChar = _script.readNextWord();
+ assert(keyChar >= 0 && keyChar < NUM_KEYCHARS);
+ _keyCharsTable[keyChar].followingKeyCharNum = val;
+ _keyCharsTable[keyChar].flags |= 0x10;
+ _keyCharsTable[keyChar].followingKeyCharPos = -1;
+}
+
+void ToucheEngine::op_startAnimation() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_startAnimation()");
+ int16 num = _script.readNextWord();
+ int16 pos = _script.readNextWord();
+ int16 keyChar = *_script.stackDataPtr;
+ addToAnimationTable(num, pos, keyChar, 3);
+}
+
+void ToucheEngine::op_setKeyCharTextColor() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_setKeyCharTextColor()");
+ int16 keyChar = _script.readNextWord();
+ uint16 color = _script.readNextWord();
+ setKeyCharTextColor(keyChar, color);
+}
+
+void ToucheEngine::op_startMusic() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_startMusic()");
+ _newMusicNum = _script.readNextWord();
+}
+
+void ToucheEngine::op_copyPaletteColor() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_copyPaletteColor()");
+ int16 src = _script.readNextWord();
+ int16 dst = _script.readNextWord();
+ copyPaletteColor(src, dst);
+}
+
+void ToucheEngine::op_delay() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_delay()");
+ int16 delay = _script.readNextWord();
+ _keyCharsTable[_script.keyCharNum].delay = delay;
+ _script.quitFlag = 3;
+}
+
+void ToucheEngine::op_lockHitBox() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_lockHitBox()");
+ int16 num = _script.readNextWord();
+ lockUnlockHitBox(num, 1);
+}
+
+void ToucheEngine::op_removeItemFromInventory() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_removeItemFromInventory()");
+ int16 keyChar = _script.readNextWord();
+ int16 item = *_script.stackDataPtr;
+ if (keyChar == 256) {
+ keyChar = _currentKeyCharNum;
+ }
+ removeItemFromInventory(keyChar, item);
+ if (keyChar == _currentKeyCharNum && !_hideInventoryTexts) {
+ drawInventory(_currentKeyCharNum, 1);
+ }
+}
+
+void ToucheEngine::op_unlockHitBox() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_unlockHitBox()");
+ int16 num = _script.readNextWord();
+ lockUnlockHitBox(num, 0);
+}
+
+void ToucheEngine::op_addRoomArea() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_addRoomArea()");
+ int16 num = _script.readNextWord();
+ uint16 flag = _script.readNextWord();
+ addRoomArea(num, flag);
+}
+
+void ToucheEngine::op_setKeyCharFlags() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_setKeyCharFlags()");
+ int16 keyChar = _script.readNextWord();
+ uint16 flags = _script.readNextWord();
+ flags &= 0xFF00;
+ _keyCharsTable[keyChar].flags |= flags;
+}
+
+void ToucheEngine::op_unsetKeyCharFlags() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_unsetKeyCharFlags()");
+ int16 keyChar = _script.readNextWord();
+ uint16 flags = _script.readNextWord();
+ flags &= 0xFF00;
+ _keyCharsTable[keyChar].flags &= ~flags;
+}
+
+void ToucheEngine::op_loadVoice() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_loadVoice()");
+ int16 num = _script.readNextWord();
+ res_loadSpeech(num);
+}
+
+void ToucheEngine::op_drawSpriteOnBackdrop() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_drawSpriteOnBackdrop()");
+ int16 num = _script.readNextWord();
+ int16 x = _script.readNextWord();
+ int16 y = _script.readNextWord();
+ drawSpriteOnBackdrop(num, x, y);
+}
+
+void ToucheEngine::op_startPaletteFadeIn() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_startPaletteFadeIn()");
+ _flagsTable[290] = 0;
+ _flagsTable[605] = 0;
+ _flagsTable[607] = 0;
+ _flagsTable[608] = 0xFF;
+ _flagsTable[609] = 0xFF;
+ _flagsTable[610] = 0;
+ _flagsTable[603] = _script.readNextWord();
+}
+
+void ToucheEngine::op_startPaletteFadeOut() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_startPaletteFadeOut()");
+ _flagsTable[290] = 0;
+ _flagsTable[605] = 0xFF;
+ _flagsTable[607] = 0;
+ _flagsTable[608] = 0xFF;
+ _flagsTable[609] = 0xFF;
+ _flagsTable[610] = 0;
+ _flagsTable[603] = -_script.readNextWord();
+}
+
+void ToucheEngine::op_setRoomAreaState() {
+ debugC(9, kDebugOpcodes, "ToucheEngine::op_setRoomAreaState()");
+ int16 num = _script.readNextWord();
+ int16 val = _script.readNextWord();
+ setRoomAreaState(num, val);
+}
+
+} // namespace Touche
diff --git a/engines/touche/plugin.cpp b/engines/touche/plugin.cpp
new file mode 100644
index 0000000000..47ec8d1afe
--- /dev/null
+++ b/engines/touche/plugin.cpp
@@ -0,0 +1,154 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id: $
+ *
+ */
+
+#include "common/stdafx.h"
+#include "common/config-manager.h"
+#include "common/fs.h"
+#include "common/md5.h"
+
+#include "base/plugins.h"
+
+#include "touche/touche.h"
+
+struct GameVersion {
+ const char *description;
+ uint32 filesize;
+ const char *md5digest;
+ Common::Language language;
+ Common::Platform platform;
+};
+
+static const GameVersion toucheGameVersionsTable[] = {
+ {
+ "Touche: The Adventures of the Fifth Musketeer",
+ 26350211,
+ "2af0177f8887e3430f345e6b4d8b1414",
+ Common::EN_ANY,
+ Common::kPlatformPC
+ },
+ {
+ "Touche: Les Aventures du Cinquieme Mousquetaire",
+ 26558232,
+ "1caa20bb4d4fc2ce8eb867b6610082b3",
+ Common::FR_FRA,
+ Common::kPlatformPC
+ }
+};
+
+static const PlainGameDescriptor toucheGameDescriptor = {
+ "touche", "Touche: The Adventures of the Fifth Musketeer"
+};
+
+static const char *toucheDetectFileName = "TOUCHE.DAT";
+
+static Common::String Engine_TOUCHE_md5digest(const FilesystemNode *file) {
+ static const int md5DataSize = 4096;
+ uint8 md5digest[16];
+ if (Common::md5_file(*file, md5digest, md5DataSize)) {
+ char md5sum[32 + 1];
+ for (int i = 0; i < 16; ++i) {
+ sprintf(md5sum + i * 2, "%02x", (int)md5digest[i]);
+ }
+ return md5sum;
+ }
+ return "";
+}
+
+static uint32 Engine_TOUCHE_filesize(const FilesystemNode *file) {
+ Common::File f;
+ if (f.open(file->path().c_str())) {
+ return f.size();
+ }
+ return 0;
+}
+
+GameList Engine_TOUCHE_gameIDList() {
+ GameList games;
+ games.push_back(toucheGameDescriptor);
+ return games;
+}
+
+GameDescriptor Engine_TOUCHE_findGameID(const char *gameid) {
+ if (scumm_stricmp(toucheGameDescriptor.gameid, gameid) == 0) {
+ return toucheGameDescriptor;
+ }
+ return GameDescriptor();
+}
+
+DetectedGameList Engine_TOUCHE_detectGames(const FSList &fslist) {
+ bool foundFile = false;
+ FSList::const_iterator file;
+ for (file = fslist.begin(); file != fslist.end(); ++file) {
+ if (file->isDirectory()) {
+ continue;
+ }
+ for (int i = 0; i < ARRAYSIZE(toucheGameVersionsTable); ++i) {
+ if (scumm_stricmp(file->name().c_str(), toucheDetectFileName) == 0) {
+ foundFile = true;
+ break;
+ }
+ }
+ if (foundFile) {
+ break;
+ }
+ }
+ DetectedGameList detectedGames;
+ if (foundFile) {
+ Common::String md5digest = Engine_TOUCHE_md5digest(file);
+ if (!md5digest.empty()) {
+ for (int i = 0; i < ARRAYSIZE(toucheGameVersionsTable); ++i) {
+ const GameVersion *gv = &toucheGameVersionsTable[i];
+ if (md5digest.equalsIgnoreCase(gv->md5digest)) {
+ DetectedGame dg(toucheGameDescriptor.gameid, gv->description, gv->language, gv->platform);
+ detectedGames.push_back(dg);
+ break;
+ }
+ }
+ if (detectedGames.empty()) {
+ const uint32 filesize = Engine_TOUCHE_filesize(file);
+ printf("Datafile size (%d) and MD5 (%s) are unknown !\n", filesize, md5digest.c_str());
+ printf("Please report the details (language, platform, etc.) of this game to the ScummVM team.\n");
+ detectedGames.push_back(toucheGameDescriptor);
+ }
+ }
+ }
+ return detectedGames;
+}
+
+PluginError Engine_TOUCHE_create(OSystem *system, Engine **engine) {
+ FSList fslist;
+ FilesystemNode dir(ConfMan.get("path"));
+ if (!dir.listDir(fslist, FilesystemNode::kListFilesOnly)) {
+ warning("ToucheEngine: invalid game path '%s'", dir.path().c_str());
+ return kInvalidPathError;
+ }
+ DetectedGameList game = Engine_TOUCHE_detectGames(fslist);
+ if (game.size() != 1) {
+ warning("ToucheEngine: Unable to locate game data in '%s'", dir.path().c_str());
+ return kNoGameDataFoundError;
+ }
+ assert(engine);
+ *engine = new Touche::ToucheEngine(system, game[0].language);
+ return kNoError;
+}
+
+REGISTER_PLUGIN(TOUCHE, "Touche: The Adventures of the 5th Musketeer", "Touche: The Adventures of the 5th Musketeer (C) US Gold");
diff --git a/engines/touche/resource.cpp b/engines/touche/resource.cpp
new file mode 100644
index 0000000000..fd6441d8ca
--- /dev/null
+++ b/engines/touche/resource.cpp
@@ -0,0 +1,645 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id: $
+ *
+ */
+
+#include "common/stdafx.h"
+
+#include "sound/flac.h"
+#include "sound/mixer.h"
+#include "sound/mp3.h"
+#include "sound/voc.h"
+#include "sound/vorbis.h"
+
+#include "touche/touche.h"
+#include "touche/graphics.h"
+
+namespace Touche {
+
+enum {
+ kCurrentSpeechDataVersion = 1,
+ kSpeechDataFileHeaderSize = 4
+};
+
+struct CompressedSpeechFile {
+ const char *filename;
+ Audio::AudioStream *(*makeStream)(Common::File *file, uint32 size);
+};
+
+static const CompressedSpeechFile compressedSpeechFilesTable[] = {
+#ifdef USE_MAD
+ { "TOUCHE.SO3", Audio::makeMP3Stream },
+#endif
+#ifdef USE_VORBIS
+ { "TOUCHE.SOG", Audio::makeVorbisStream },
+#endif
+#ifdef USE_FLAC
+ { "TOUCHE.SOF", Audio::makeFlacStream },
+#endif
+ { 0, 0 }
+};
+
+void ToucheEngine::res_openDataFile() {
+ if (!_fData.open("TOUCHE.DAT")) {
+ error("Unable to open 'TOUCHE.DAT' for reading");
+ }
+ for (int i = 0; compressedSpeechFilesTable[i].filename; ++i) {
+ if (_fSpeech[0].open(compressedSpeechFilesTable[i].filename)) {
+ _compressedSpeechData = i;
+ return;
+ }
+ }
+ // _fSpeech[0] opening/closing is driven by the scripts
+ _fSpeech[1].open("OBJ");
+ _compressedSpeechData = -1;
+}
+
+void ToucheEngine::res_closeDataFile() {
+ _fData.close();
+ _fSpeech[0].close();
+ _fSpeech[1].close();
+}
+
+void ToucheEngine::res_allocateTables() {
+ _fData.seek(64);
+ uint32 textDataOffs = _fData.readUint32LE();
+ uint32 textDataSize = _fData.readUint32LE();
+ _textData = (uint8 *)malloc(textDataSize);
+ if (!_textData) {
+ error("Unable to allocate memory for text data");
+ }
+ _fData.seek(textDataOffs);
+ _fData.read(_textData, textDataSize);
+
+ _fData.seek(2);
+ const int bw = _fData.readUint16LE();
+ const int bh = _fData.readUint16LE();
+ uint32 size = bw * bh;
+ _backdropBuffer = (uint8 *)malloc(size);
+ if (!_backdropBuffer) {
+ error("Unable to allocate memory for backdrop buffer");
+ }
+
+ _menuKitData = (uint8 *)malloc(5040);
+ if (!_menuKitData) {
+ error("Unable to allocate memory for menu kit data");
+ }
+
+ _convKitData = (uint8 *)malloc(12160);
+ if (!_convKitData) {
+ error("Unable to allocate memory for conv kit data");
+ }
+
+ for (int i = 0; i < 5; ++i) {
+ _sequenceDataTable[i] = (uint8 *)malloc(16384);
+ if (!_sequenceDataTable[i]) {
+ error("Unable to allocate memory for sequence data %d", i);
+ }
+ }
+
+ _programData = (uint8 *)malloc(61440);
+ if (!_programData) {
+ error("Unable to allocate memory for program data");
+ }
+
+ _mouseData = (uint8 *)malloc(58 * 42);
+ if (!_mouseData) {
+ error("Unable to allocate memory for mouse data");
+ }
+
+ _iconData = (uint8 *)malloc(58 * 42);
+ if (!_iconData) {
+ error("Unable to allocate memory for object data");
+ }
+ for (int i = 0; i < NUM_SPRITES; ++i) {
+ _spritesTable[i].ptr = (uint8 *)malloc(_spritesTable[i].size);
+ if (!_spritesTable[i].ptr) {
+ error("Unable to allocate memory for sprite %d", i);
+ }
+ }
+
+ _offscreenBuffer = (uint8 *)malloc(640 * 400);
+ if (!_offscreenBuffer) {
+ error("Unable to allocate memory for offscreen buffer");
+ }
+}
+
+void ToucheEngine::res_deallocateTables() {
+ free(_textData);
+ _textData = 0;
+
+ free(_backdropBuffer);
+ _backdropBuffer = 0;
+
+ free(_menuKitData);
+ _menuKitData = 0;
+
+ free(_convKitData);
+ _convKitData = 0;
+
+ for (int i = 0; i < 5; ++i) {
+ free(_sequenceDataTable[i]);
+ _sequenceDataTable[i] = 0;
+ }
+
+ free(_programData);
+ _programData = 0;
+
+ free(_mouseData);
+ _mouseData = 0;
+
+ free(_iconData);
+ _iconData = 0;
+
+ for (int i = 0; i < NUM_SPRITES; ++i) {
+ free(_spritesTable[i].ptr);
+ }
+
+ free(_offscreenBuffer);
+ _offscreenBuffer = 0;
+}
+
+uint32 ToucheEngine::res_getDataOffset(ResourceType type, int num, uint32 *size) {
+ debugC(9, kDebugResource, "ToucheEngine::res_getDataOffset() type=%d num=%d", type, num);
+ static const struct ResourceData {
+ int offs;
+ int count;
+ int type;
+ } dataTypesTable[] = {
+ { 0x048, 100, kResourceTypeRoomImage },
+ { 0x228, 30, kResourceTypeSequence },
+ { 0x2A0, 50, kResourceTypeSpriteImage },
+ { 0x390, 100, kResourceTypeIconImage },
+ { 0x6B0, 80, kResourceTypeRoomInfo },
+ { 0x908, 150, kResourceTypeProgram },
+ { 0xB60, 50, kResourceTypeMusic },
+ { 0xC28, 120, kResourceTypeSound }
+ };
+
+ const ResourceData *rd = NULL;
+ for (unsigned int i = 0; i < ARRAYSIZE(dataTypesTable); ++i) {
+ rd = &dataTypesTable[i];
+ if (rd->type == type) {
+ break;
+ }
+ }
+ if (rd == NULL) {
+ error("Invalid resource type %d", type);
+ }
+ if (num < 0 || num > rd->count) {
+ error("Invalid resource number %d (type %d)", num, type);
+ }
+ _fData.seek(rd->offs + num * 4);
+ uint32 offs = _fData.readUint32LE();
+ assert(offs != 0);
+ if (size) {
+ uint32 nextOffs = _fData.readUint32LE();
+ *size = nextOffs - offs;
+ }
+ return offs;
+}
+
+void ToucheEngine::res_loadSpriteImage(int num, uint8 *dst) {
+ debugC(9, kDebugResource, "ToucheEngine::res_loadSpriteImage() num=%d", num);
+ const uint32 offs = res_getDataOffset(kResourceTypeSpriteImage, num);
+ _fData.seek(offs);
+ _currentImageWidth = _fData.readUint16LE();
+ _currentImageHeight = _fData.readUint16LE();
+ for (int i = 0; i < _currentImageHeight; ++i) {
+ res_decodeScanLineImageRLE(dst + _currentImageWidth * i, _currentImageWidth);
+ }
+}
+
+void ToucheEngine::res_loadProgram(int num) {
+ debugC(9, kDebugResource, "ToucheEngine::res_loadProgram() num=%d", num);
+ const uint32 offs = res_getDataOffset(kResourceTypeProgram, num, &_programDataSize);
+ _fData.seek(offs);
+ _fData.read(_programData, _programDataSize);
+}
+
+void ToucheEngine::res_decodeProgramData() {
+ debugC(9, kDebugResource, "ToucheEngine::res_decodeProgramData()");
+
+ uint8 *p;
+ uint8 *programDataEnd = _programData + _programDataSize;
+
+ p = _programData + READ_LE_UINT32(_programData + 32);
+ _script.init(p);
+
+ p = _programData + READ_LE_UINT32(_programData + 4);
+ _programTextDataPtr = p;
+
+ _programRectsTable.clear();
+ p = _programData + READ_LE_UINT32(_programData + 20);
+ while (p < programDataEnd) {
+ int16 x = READ_LE_UINT16(p); p += 2;
+ int16 y = READ_LE_UINT16(p); p += 2;
+ int16 w = READ_LE_UINT16(p); p += 2;
+ int16 h = READ_LE_UINT16(p); p += 2;
+ _programRectsTable.push_back(Common::Rect(x, y, x + w, y + h));
+ if (x == -1) {
+ break;
+ }
+ }
+
+ _programPointsTable.clear();
+ p = _programData + READ_LE_UINT32(_programData + 24);
+ while (p < programDataEnd) {
+ ProgramPointData ppd;
+ ppd.x = READ_LE_UINT16(p); p += 2;
+ ppd.y = READ_LE_UINT16(p); p += 2;
+ ppd.z = READ_LE_UINT16(p); p += 2;
+ ppd.priority = READ_LE_UINT16(p); p += 2;
+ _programPointsTable.push_back(ppd);
+ if (ppd.x == -1) {
+ break;
+ }
+ }
+
+ _programWalkTable.clear();
+ p = _programData + READ_LE_UINT32(_programData + 28);
+ while (p < programDataEnd) {
+ ProgramWalkData pwd;
+ pwd.point1 = READ_LE_UINT16(p); p += 2;
+ if (pwd.point1 == -1) {
+ break;
+ }
+ assert((uint16)pwd.point1 < _programPointsTable.size());
+ pwd.point2 = READ_LE_UINT16(p); p += 2;
+ assert((uint16)pwd.point2 < _programPointsTable.size());
+ pwd.clippingRect = READ_LE_UINT16(p); p += 2;
+ pwd.area1 = READ_LE_UINT16(p); p += 2;
+ pwd.area2 = READ_LE_UINT16(p); p += 2;
+ p += 12; // unused
+ _programWalkTable.push_back(pwd);
+ }
+
+ _programAreaTable.clear();
+ p = _programData + READ_LE_UINT32(_programData + 8);
+ while (p < programDataEnd) {
+ ProgramAreaData pad;
+ int16 x = READ_LE_UINT16(p); p += 2;
+ if (x == -1) {
+ break;
+ }
+ int16 y = READ_LE_UINT16(p); p += 2;
+ int16 w = READ_LE_UINT16(p); p += 2;
+ int16 h = READ_LE_UINT16(p); p += 2;
+ pad.area.r = Common::Rect(x, y, x + w, y + h);
+ pad.area.srcX = READ_LE_UINT16(p); p += 2;
+ pad.area.srcY = READ_LE_UINT16(p); p += 2;
+ pad.id = READ_LE_UINT16(p); p += 2;
+ pad.state = READ_LE_UINT16(p); p += 2;
+ pad.animCount = READ_LE_UINT16(p); p += 2;
+ pad.animNext = READ_LE_UINT16(p); p += 2;
+ _programAreaTable.push_back(pad);
+ }
+
+ _programBackgroundTable.clear();
+ p = _programData + READ_LE_UINT32(_programData + 12);
+ while (p < programDataEnd) {
+ ProgramBackgroundData pbd;
+ int16 x = READ_LE_UINT16(p); p += 2;
+ if (x == -1) {
+ break;
+ }
+ int16 y = READ_LE_UINT16(p); p += 2;
+ int16 w = READ_LE_UINT16(p); p += 2;
+ int16 h = READ_LE_UINT16(p); p += 2;
+ pbd.area.r = Common::Rect(x, y, x + w, y + h);
+ pbd.area.srcX = READ_LE_UINT16(p); p += 2;
+ pbd.area.srcY = READ_LE_UINT16(p); p += 2;
+ pbd.type = READ_LE_UINT16(p); p += 2;
+ pbd.offset = READ_LE_UINT16(p); p += 2;
+ pbd.scaleMul = READ_LE_UINT16(p); p += 2;
+ pbd.scaleDiv = READ_LE_UINT16(p); p += 2;
+ _programBackgroundTable.push_back(pbd);
+ }
+
+ _programHitBoxTable.clear();
+ p = _programData + READ_LE_UINT32(_programData + 16);
+ while (p < programDataEnd) {
+ ProgramHitBoxData phbd;
+ phbd.item = READ_LE_UINT16(p); p += 2;
+ if (phbd.item == 0) {
+ break;
+ }
+ phbd.talk = READ_LE_UINT16(p); p += 2;
+ phbd.state = READ_LE_UINT16(p); p += 2;
+ phbd.str = READ_LE_UINT16(p); p += 2;
+ phbd.defaultStr = READ_LE_UINT16(p); p += 2;
+ for (int i = 0; i < 8; ++i) {
+ phbd.actions[i] = READ_LE_UINT16(p); p += 2;;
+ }
+ for (int i = 0; i < 2; ++i) {
+ int16 x = READ_LE_UINT16(p); p += 2;
+ int16 y = READ_LE_UINT16(p); p += 2;
+ int16 w = READ_LE_UINT16(p); p += 2;
+ int16 h = READ_LE_UINT16(p); p += 2;
+ phbd.hitBoxes[i].left = x;
+ phbd.hitBoxes[i].top = y;
+ phbd.hitBoxes[i].right = x + w;
+ phbd.hitBoxes[i].bottom = y + h;
+ }
+ p += 8; // unused
+ _programHitBoxTable.push_back(phbd);
+ }
+
+ _programActionScriptOffsetTable.clear();
+ p = _programData + READ_LE_UINT32(_programData + 36);
+ while (p < programDataEnd) {
+ ProgramActionScriptOffsetData pasod;
+ pasod.object1 = READ_LE_UINT16(p); p += 2;
+ if (pasod.object1 == 0) {
+ break;
+ }
+ pasod.action = READ_LE_UINT16(p); p += 2;
+ pasod.object2 = READ_LE_UINT16(p); p += 2;
+ pasod.offset = READ_LE_UINT16(p); p += 2;
+ _programActionScriptOffsetTable.push_back(pasod);
+ }
+
+ _programConversationTable.clear();
+ int count = (READ_LE_UINT32(_programData + 44) - READ_LE_UINT32(_programData + 40)) / 6;
+ assert(count >= 0);
+ p = _programData + READ_LE_UINT32(_programData + 40);
+ while (p < programDataEnd && count != 0) {
+ ProgramConversationData pcd;
+ pcd.num = READ_LE_UINT16(p); p += 2;
+ pcd.offset = READ_LE_UINT16(p); p += 2;
+ pcd.msg = READ_LE_UINT16(p); p += 2;
+ _programConversationTable.push_back(pcd);
+ --count;
+ }
+
+ _programKeyCharScriptOffsetTable.clear();
+ p = _programData + READ_LE_UINT32(_programData + 44);
+ while (p < programDataEnd) {
+ ProgramKeyCharScriptOffsetData pksod;
+ pksod.keyChar = READ_LE_UINT16(p); p += 2;
+ if (pksod.keyChar == 0) {
+ break;
+ }
+ pksod.offset = READ_LE_UINT16(p); p += 2;
+ _programKeyCharScriptOffsetTable.push_back(pksod);
+ }
+}
+
+void ToucheEngine::res_loadRoom(int num) {
+ debugC(9, kDebugResource, "ToucheEngine::res_loadRoom() num=%d flag115=%d", num, _flagsTable[115]);
+
+ _currentRoomNum = num;
+ _updatedRoomAreasTable[0] = 1;
+
+ const uint32 offsInfo = res_getDataOffset(kResourceTypeRoomInfo, num);
+ _fData.seek(offsInfo);
+ _fData.readUint16LE();
+ const int roomImageNum = _fData.readUint16LE();
+ _fData.readUint16LE();
+ for (int i = 0; i < 256; ++i) {
+ _fData.read(&_paletteBuffer[i * 4], 3);
+ _paletteBuffer[i * 4 + 3] = 0;
+ }
+
+ const uint32 offsImage = res_getDataOffset(kResourceTypeRoomImage, roomImageNum);
+ _fData.seek(offsImage);
+ res_loadBackdrop();
+
+ if (_flagsTable[115] == 0) {
+ updatePalette();
+ }
+ _fullRedrawCounter = 1;
+ _roomNeedRedraw = true;
+
+ _sequenceEntryTable[5].sprNum = -1;
+ _sequenceEntryTable[5].seqNum = -1;
+ _sequenceEntryTable[6].sprNum = -1;
+ _sequenceEntryTable[6].seqNum = -1;
+}
+
+void ToucheEngine::res_loadSprite(int num, int index) {
+ debugC(9, kDebugResource, "ToucheEngine::res_loadSprite() num=%d index=%d", num, index);
+ assert(index >= 0 && index < NUM_SEQUENCES);
+ _sequenceEntryTable[index].sprNum = num;
+ SpriteData *spr = &_spritesTable[index];
+ const uint32 offs = res_getDataOffset(kResourceTypeSpriteImage, num);
+ _fData.seek(offs);
+ _currentImageWidth = _fData.readUint16LE();
+ _currentImageHeight = _fData.readUint16LE();
+ for (int i = 0; i < _currentImageHeight; ++i) {
+ res_decodeScanLineImageRLE(spr->ptr + _currentImageWidth * i, _currentImageWidth);
+ }
+ spr->bitmapWidth = _currentImageWidth;
+ spr->bitmapHeight = _currentImageHeight;
+ if (_flagsTable[268] == 0) {
+ res_loadImageHelper(spr->ptr, _currentImageWidth, _currentImageHeight);
+ }
+ spr->w = _currentImageWidth;
+ spr->h = _currentImageHeight;
+ Graphics::copyRect(_offscreenBuffer, 640, 0, 0,
+ _backdropBuffer, _currentImageWidth, _flagsTable[614], _flagsTable[615],
+ 640, 100);
+}
+
+void ToucheEngine::res_loadSequence(int num, int index) {
+ debugC(9, kDebugResource, "ToucheEngine::res_loadSequence() num=%d index=%d", num, index);
+ assert(index < NUM_SEQUENCES);
+ _sequenceEntryTable[index].seqNum = num;
+ const uint32 offs = res_getDataOffset(kResourceTypeSequence, num);
+ _fData.seek(offs);
+ _fData.read(_sequenceDataTable[index], 16000);
+}
+
+void ToucheEngine::res_decodeScanLineImageRLE(uint8 *dst, int lineWidth) {
+ int w = 0;
+ while (w < lineWidth) {
+ uint8 code = _fData.readByte();
+ if ((code & 0xC0) == 0xC0) {
+ int len = code & 0x3F;
+ uint8 color = _fData.readByte();
+ memset(dst, color, len);
+ dst += len;
+ w += len;
+ } else {
+ *dst = code;
+ ++dst;
+ ++w;
+ }
+ }
+}
+
+void ToucheEngine::res_loadBackdrop() {
+ debugC(9, kDebugResource, "ToucheEngine::res_loadBackdrop()");
+ _currentBitmapWidth = _fData.readUint16LE();
+ _currentBitmapHeight = _fData.readUint16LE();
+ uint8 *dst = _backdropBuffer;
+ for (int i = 0; i < _currentBitmapHeight; ++i) {
+ res_decodeScanLineImageRLE(dst + _currentBitmapWidth * i, _currentBitmapWidth);
+ }
+ _roomWidth = _currentBitmapWidth;
+ dst = _backdropBuffer;
+ for (int i = 0; i < _currentBitmapWidth; ++i) {
+ if (*dst == 255) {
+ _roomWidth = i;
+ *dst = 0;
+ break;
+ }
+ ++dst;
+ }
+}
+
+void ToucheEngine::res_loadImage(int num, uint8 *dst) {
+ debugC(9, kDebugResource, "ToucheEngine::res_loadImage() num=%d", num);
+ const uint32 offsInfo = res_getDataOffset(kResourceTypeIconImage, num);
+ _fData.seek(offsInfo);
+ _currentImageWidth = _fData.readUint16LE();
+ _currentImageHeight = _fData.readUint16LE();
+ for (int i = 0; i < _currentImageHeight; ++i) {
+ res_decodeScanLineImageRLE(dst + _currentImageWidth * i, _currentImageWidth);
+ }
+ res_loadImageHelper(dst, _currentImageWidth, _currentImageHeight);
+}
+
+void ToucheEngine::res_loadImageHelper(uint8 *imgData, int imgWidth, int imgHeight) {
+ uint8 *p = imgData;
+ for (_currentImageHeight = 0; _currentImageHeight < imgHeight; ++_currentImageHeight, p += imgWidth) {
+ if (*p == 64 || *p == 255) {
+ break;
+ }
+ }
+ p = imgData;
+ for (_currentImageWidth = 0; _currentImageWidth < imgWidth; ++_currentImageWidth, ++p) {
+ if (*p == 64 || *p == 255) {
+ break;
+ }
+ }
+ if (_flagsTable[267] == 0) {
+ for (int i = 0; i < imgWidth * imgHeight; ++i) {
+ uint8 color = imgData[i];
+ if (color != 0) {
+ if (color < 64) {
+ color += 192;
+ } else {
+ color = 0;
+ }
+ }
+ imgData[i] = color;
+ }
+ }
+}
+
+void ToucheEngine::res_loadSound(int priority, int num) {
+ debugC(9, kDebugResource, "ToucheEngine::res_loadSound() num=%d", num);
+ if (priority >= _defaultSoundPriority) {
+ uint32 size;
+ const uint32 offs = res_getDataOffset(kResourceTypeSound, num, &size);
+ _fData.seek(offs);
+ Audio::AudioStream *stream = Audio::makeVOCStream(_fData);
+ if (stream) {
+ _mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_sfxHandle, stream);
+ }
+ }
+}
+
+void ToucheEngine::res_loadMusic(int num) {
+ debugC(9, kDebugResource, "ToucheEngine::res_loadMusic() num=%d", num);
+ warning("UNIMPLEMENTED ToucheEngine::res_loadMusic() num=%d", num);
+ uint32 size;
+ const uint32 offs = res_getDataOffset(kResourceTypeMusic, num, &size);
+ _fData.seek(offs);
+ // XXX start MIDI data playback
+}
+
+void ToucheEngine::res_loadSpeech(int num) {
+ debugC(9, kDebugResource, "ToucheEngine::res_loadSpeech() num=%d", num);
+ if (num == -1) {
+ // XXX stop all sounds currently playing
+ } else {
+ if (_compressedSpeechData < 0) { // uncompressed speech data
+ if (_fSpeech[0].isOpen()) {
+ _fSpeech[0].close();
+ }
+ char filename[10];
+ sprintf(filename, "V%d", num);
+ _fSpeech[0].open(filename);
+ }
+ if (_fSpeech[0].isOpen()) {
+ _flagsTable[617] = num;
+ }
+ }
+}
+
+void ToucheEngine::res_loadSpeechSegment(int num) {
+ debugC(9, kDebugResource, "ToucheEngine::res_loadSpeechSegment() num=%d", num);
+ if (_talkTextMode != kTalkModeTextOnly) {
+ Audio::AudioStream *stream = 0;
+ if (_compressedSpeechData < 0) { // uncompressed speech data
+ int i = 0;
+ if (num >= 750) {
+ num -= 750;
+ i = 1;
+ }
+ if (!_fSpeech[i].isOpen()) {
+ return;
+ }
+ _fSpeech[i].seek(num * 8);
+ uint32 offs = _fSpeech[i].readUint32LE();
+ uint32 size = _fSpeech[i].readUint32LE();
+ if (size == 0) {
+ return;
+ }
+ _fSpeech[i].seek(offs);
+ stream = Audio::makeVOCStream(_fSpeech[i]);
+ } else {
+ if (num >= 750) {
+ num -= 750;
+ _fSpeech[0].seek(kSpeechDataFileHeaderSize);
+ } else {
+ assert(_flagsTable[617] > 0 && _flagsTable[617] < 140);
+ _fSpeech[0].seek(kSpeechDataFileHeaderSize + _flagsTable[617] * 4);
+ }
+ uint32 dataOffs = _fSpeech[0].readUint32LE();
+ if (dataOffs == 0) {
+ return;
+ }
+ _fSpeech[0].seek(dataOffs + num * 8);
+ uint32 offs = _fSpeech[0].readUint32LE();
+ uint32 size = _fSpeech[0].readUint32LE();
+ if (size == 0) {
+ return;
+ }
+ _fSpeech[0].seek(offs);
+ stream = (compressedSpeechFilesTable[_compressedSpeechData].makeStream)(&_fSpeech[0], size);
+ }
+ if (stream) {
+ _speechPlaying = true;
+ _mixer->playInputStream(Audio::Mixer::kSpeechSoundType, &_speechHandle, stream);
+ }
+ }
+}
+
+void ToucheEngine::res_stopSpeech() {
+ debugC(9, kDebugResource, "ToucheEngine::res_stopSpeech()");
+ _mixer->stopHandle(_speechHandle);
+ _speechPlaying = false;
+ _defaultSoundPriority = 0;
+}
+
+} // namespace Touche
diff --git a/engines/touche/saveload.cpp b/engines/touche/saveload.cpp
new file mode 100644
index 0000000000..e46ec24a30
--- /dev/null
+++ b/engines/touche/saveload.cpp
@@ -0,0 +1,418 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id: $
+ *
+ */
+
+#include "common/stdafx.h"
+#include "common/savefile.h"
+
+#include "touche/graphics.h"
+#include "touche/touche.h"
+
+namespace Touche {
+
+enum {
+ kCurrentGameStateVersion = 5,
+ kGameStateDescriptionLen = 32
+};
+
+template <class S, class T>
+static void saveOrLoad(S &s, T &t);
+
+template <>
+static void saveOrLoad(Common::WriteStream &stream, uint16 &i) {
+ stream.writeUint16LE(i);
+}
+
+template <>
+static void saveOrLoad(Common::ReadStream &stream, uint16 &i) {
+ i = stream.readUint16LE();
+}
+
+template <>
+static void saveOrLoad(Common::WriteStream &stream, int16 &i) {
+ stream.writeSint16LE(i);
+}
+
+template <>
+static void saveOrLoad(Common::ReadStream &stream, int16 &i) {
+ i = stream.readSint16LE();
+}
+
+template <class S, class T>
+static void saveOrLoadPtr(S &s, T *&t, T *base);
+
+template <>
+static void saveOrLoadPtr(Common::WriteStream &stream, int16 *&p, int16 *base) {
+ int32 offset = (int32)(p - base);
+ stream.writeSint32LE(offset);
+}
+
+template <>
+static void saveOrLoadPtr(Common::ReadStream &stream, int16 *&p, int16 *base) {
+ int32 offset = stream.readSint32LE();
+ p = base + offset;
+}
+
+template <class S>
+static void saveOrLoad(S &s, Common::Rect &r) {
+ saveOrLoad(s, r.left);
+ saveOrLoad(s, r.top);
+ saveOrLoad(s, r.right);
+ saveOrLoad(s, r.bottom);
+}
+
+template <class S>
+static void saveOrLoad(S &s, SequenceEntry &seq) {
+ saveOrLoad(s, seq.sprNum);
+ saveOrLoad(s, seq.seqNum);
+}
+
+template <class S>
+static void saveOrLoad(S &s, KeyChar &key) {
+ saveOrLoad(s, key.num);
+ saveOrLoad(s, key.flags);
+ saveOrLoad(s, key.currentAnimCounter);
+ saveOrLoad(s, key.strNum);
+ saveOrLoad(s, key.walkDataNum);
+ saveOrLoad(s, key.spriteNum);
+ saveOrLoad(s, key.prevBoundingRect);
+ saveOrLoad(s, key.boundingRect);
+ saveOrLoad(s, key.xPos);
+ saveOrLoad(s, key.yPos);
+ saveOrLoad(s, key.zPos);
+ saveOrLoad(s, key.xPosPrev);
+ saveOrLoad(s, key.yPosPrev);
+ saveOrLoad(s, key.zPosPrev);
+ saveOrLoad(s, key.prevWalkDataNum);
+ saveOrLoad(s, key.textColor);
+ for (uint i = 0; i < 4; ++i) {
+ saveOrLoad(s, key.inventoryItems[i]);
+ }
+ saveOrLoad(s, key.money);
+ saveOrLoad(s, key.pointsDataNum);
+ saveOrLoad(s, key.currentWalkBox);
+ saveOrLoad(s, key.prevPointsDataNum);
+ saveOrLoad(s, key.currentAnim);
+ saveOrLoad(s, key.facingDirection);
+ saveOrLoad(s, key.currentAnimSpeed);
+ for (uint i = 0; i < 16; ++i) {
+ saveOrLoad(s, key.framesList[i]);
+ }
+ saveOrLoad(s, key.framesListCount);
+ saveOrLoad(s, key.currentFrame);
+ saveOrLoad(s, key.anim1Start);
+ saveOrLoad(s, key.anim1Count);
+ saveOrLoad(s, key.anim2Start);
+ saveOrLoad(s, key.anim2Count);
+ saveOrLoad(s, key.anim3Start);
+ saveOrLoad(s, key.anim3Count);
+ saveOrLoad(s, key.followingKeyCharNum);
+ saveOrLoad(s, key.followingKeyCharPos);
+ saveOrLoad(s, key.sequenceDataIndex);
+ saveOrLoad(s, key.sequenceDataOffset);
+ saveOrLoad(s, key.walkPointsListCount);
+ for (uint i = 0; i < 40; ++i) {
+ saveOrLoad(s, key.walkPointsList[i]);
+ }
+ saveOrLoad(s, key.scriptDataStartOffset);
+ saveOrLoad(s, key.scriptDataOffset);
+ saveOrLoadPtr(s, key.scriptStackPtr, &key.scriptStackTable[39]);
+ saveOrLoad(s, key.delay);
+ saveOrLoad(s, key.waitingKeyChar);
+ for (uint i = 0; i < 3; ++i) {
+ saveOrLoad(s, key.waitingKeyCharPosTable[i]);
+ }
+ for (uint i = 0; i < 40; ++i) {
+ saveOrLoad(s, key.scriptStackTable[i]);
+ }
+}
+
+template <class S>
+static void saveOrLoad(S &s, TalkEntry &entry) {
+ saveOrLoad(s, entry.otherKeyChar);
+ saveOrLoad(s, entry.talkingKeyChar);
+ saveOrLoad(s, entry.num);
+}
+
+template <class S>
+static void saveOrLoad(S &s, ProgramHitBoxData &data) {
+ saveOrLoad(s, data.item);
+ saveOrLoad(s, data.talk);
+ saveOrLoad(s, data.state);
+ saveOrLoad(s, data.str);
+ saveOrLoad(s, data.defaultStr);
+ for (uint i = 0; i < 8; ++i) {
+ saveOrLoad(s, data.actions[i]);
+ }
+ for (uint i = 0; i < 2; ++i) {
+ saveOrLoad(s, data.hitBoxes[i]);
+ }
+}
+
+template <class S>
+static void saveOrLoad(S &s, Area &area) {
+ saveOrLoad(s, area.r);
+ saveOrLoad(s, area.srcX);
+ saveOrLoad(s, area.srcY);
+}
+
+template <class S>
+static void saveOrLoad(S &s, ProgramBackgroundData &data) {
+ saveOrLoad(s, data.area);
+ saveOrLoad(s, data.type);
+ saveOrLoad(s, data.offset);
+ saveOrLoad(s, data.scaleMul);
+ saveOrLoad(s, data.scaleDiv);
+}
+
+template <class S>
+static void saveOrLoad(S &s, ProgramAreaData &data) {
+ saveOrLoad(s, data.area);
+ saveOrLoad(s, data.id);
+ saveOrLoad(s, data.state);
+ saveOrLoad(s, data.animCount);
+ saveOrLoad(s, data.animNext);
+}
+
+template <class S>
+static void saveOrLoad(S &s, ProgramWalkData &data) {
+ saveOrLoad(s, data.point1);
+ saveOrLoad(s, data.point2);
+ saveOrLoad(s, data.clippingRect);
+ saveOrLoad(s, data.area1);
+ saveOrLoad(s, data.area2);
+}
+
+template <class S>
+static void saveOrLoad(S &s, ProgramPointData &data) {
+ saveOrLoad(s, data.x);
+ saveOrLoad(s, data.y);
+ saveOrLoad(s, data.z);
+ saveOrLoad(s, data.priority);
+}
+
+void ToucheEngine::saveGameStateData(Common::WriteStream *stream) {
+ setKeyCharMoney();
+ stream->writeUint16LE(_currentEpisodeNum);
+ stream->writeUint16LE(_currentMusicNum);
+ stream->writeUint16LE(_currentRoomNum);
+ stream->writeUint16LE(_flagsTable[614]);
+ stream->writeUint16LE(_flagsTable[615]);
+ stream->writeUint16LE(_disabledInputCounter);
+ for (uint i = 0; i < _programHitBoxTable.size(); ++i) {
+ saveOrLoad(*stream, _programHitBoxTable[i]);
+ }
+ for (uint i = 0; i < _programBackgroundTable.size(); ++i) {
+ saveOrLoad(*stream, _programBackgroundTable[i]);
+ }
+ for (uint i = 0; i < _programAreaTable.size(); ++i) {
+ saveOrLoad(*stream, _programAreaTable[i]);
+ }
+ for (uint i = 0; i < _programWalkTable.size(); ++i) {
+ saveOrLoad(*stream, _programWalkTable[i]);
+ }
+ for (uint i = 0; i < _programPointsTable.size(); ++i) {
+ saveOrLoad(*stream, _programPointsTable[i]);
+ }
+ stream->write(_updatedRoomAreasTable, 200);
+ for (uint i = 0; i < 6; ++i) {
+ saveOrLoad(*stream, _sequenceEntryTable[i]);
+ }
+ for (uint i = 0; i < 1024; ++i) {
+ saveOrLoad(*stream, _flagsTable[i]);
+ }
+ for (uint i = 0; i < 100; ++i) {
+ saveOrLoad(*stream, _inventoryList1[i]);
+ }
+ for (uint i = 0; i < 100; ++i) {
+ saveOrLoad(*stream, _inventoryList2[i]);
+ }
+ for (uint i = 0; i < 6; ++i) {
+ saveOrLoad(*stream, _inventoryList3[i]);
+ }
+ for (uint i = 0; i < NUM_KEYCHARS; ++i) {
+ saveOrLoad(*stream, _keyCharsTable[i]);
+ }
+ for (uint i = 0; i < NUM_INVENTORY_ITEMS; ++i) {
+ saveOrLoad(*stream, _inventoryItemsInfoTable[i]);
+ }
+ for (uint i = 0; i < NUM_TALK_ENTRIES; ++i) {
+ saveOrLoad(*stream, _talkTable[i]);
+ }
+ stream->writeUint16LE(_talkListEnd);
+ stream->writeUint16LE(_talkListCurrent);
+}
+
+void ToucheEngine::loadGameStateData(Common::ReadStream *stream) {
+ setKeyCharMoney();
+ clearDirtyRects();
+ clearAreaTable();
+ _flagsTable[115] = 0;
+ clearRoomArea();
+ int16 room_offs_x, room_offs_y;
+ _currentEpisodeNum = stream->readUint16LE();
+ _currentMusicNum = stream->readUint16LE();
+ _currentRoomNum = stream->readUint16LE();
+ res_loadRoom(_currentRoomNum);
+ room_offs_x = stream->readUint16LE();
+ room_offs_y = stream->readUint16LE();
+ _disabledInputCounter = stream->readUint16LE();
+ res_loadProgram(_currentEpisodeNum);
+ setupEpisode(-1);
+ for (uint i = 0; i < _programHitBoxTable.size(); ++i) {
+ saveOrLoad(*stream, _programHitBoxTable[i]);
+ }
+ for (uint i = 0; i < _programBackgroundTable.size(); ++i) {
+ saveOrLoad(*stream, _programBackgroundTable[i]);
+ }
+ for (uint i = 0; i < _programAreaTable.size(); ++i) {
+ saveOrLoad(*stream, _programAreaTable[i]);
+ }
+ for (uint i = 0; i < _programWalkTable.size(); ++i) {
+ saveOrLoad(*stream, _programWalkTable[i]);
+ }
+ for (uint i = 0; i < _programPointsTable.size(); ++i) {
+ saveOrLoad(*stream, _programPointsTable[i]);
+ }
+ stream->read(_updatedRoomAreasTable, 200);
+ for (uint i = 1; i <= _updatedRoomAreasTable[0]; ++i) {
+ updateRoomAreas(_updatedRoomAreasTable[i], -1);
+ }
+ for (uint i = 0; i < 6; ++i) {
+ saveOrLoad(*stream, _sequenceEntryTable[i]);
+ }
+ for (uint i = 0; i < 1024; ++i) {
+ saveOrLoad(*stream, _flagsTable[i]);
+ }
+ for (uint i = 0; i < 100; ++i) {
+ saveOrLoad(*stream, _inventoryList1[i]);
+ }
+ for (uint i = 0; i < 100; ++i) {
+ saveOrLoad(*stream, _inventoryList2[i]);
+ }
+ for (uint i = 0; i < 6; ++i) {
+ saveOrLoad(*stream, _inventoryList3[i]);
+ }
+ for (uint i = 0; i < NUM_KEYCHARS; ++i) {
+ saveOrLoad(*stream, _keyCharsTable[i]);
+ }
+ for (uint i = 0; i < NUM_INVENTORY_ITEMS; ++i) {
+ saveOrLoad(*stream, _inventoryItemsInfoTable[i]);
+ }
+ for (uint i = 0; i < NUM_TALK_ENTRIES; ++i) {
+ saveOrLoad(*stream, _talkTable[i]);
+ }
+ _talkListEnd = stream->readUint16LE();
+ _talkListCurrent = stream->readUint16LE();
+ _flagsTable[614] = room_offs_x;
+ _flagsTable[615] = room_offs_y;
+ for (uint i = 0; i < 6; ++i) {
+ if (_sequenceEntryTable[i].seqNum != -1) {
+ res_loadSequence(_sequenceEntryTable[i].seqNum, i);
+ }
+ if (_sequenceEntryTable[i].sprNum != -1) {
+ res_loadSprite(_sequenceEntryTable[i].sprNum, i);
+ }
+ }
+ _currentKeyCharNum = _flagsTable[104];
+ _inventoryListCount[0] = 0;
+ _inventoryListCount[3] = 0;
+ _inventoryListCount[6] = 0;
+ drawInventory(_currentKeyCharNum, 1);
+ Graphics::copyRect(_offscreenBuffer, 640, 0, 0, _backdropBuffer, _currentBitmapWidth, _flagsTable[614], _flagsTable[615], 640, 352);
+ updateEntireScreen();
+ if (_flagsTable[617] != 0) {
+ res_loadSpeech(_flagsTable[617]);
+ }
+}
+
+bool ToucheEngine::saveGameState(int num, const char *description) {
+ bool saveOk = false;
+ char gameStateFileName[16];
+ generateGameStateFileName(num, gameStateFileName, 15);
+ Common::OutSaveFile *f = _saveFileMan->openForSaving(gameStateFileName);
+ if (f) {
+ f->writeUint16LE(kCurrentGameStateVersion);
+ f->writeUint16LE(0);
+ char headerDescription[kGameStateDescriptionLen];
+ memset(headerDescription, 0, kGameStateDescriptionLen);
+ strncpy(headerDescription, description, kGameStateDescriptionLen - 1);
+ f->write(headerDescription, kGameStateDescriptionLen);
+ saveGameStateData(f);
+ f->flush();
+ if (!f->ioFailed()) {
+ saveOk = true;
+ } else {
+ warning("Can't write file '%s'", gameStateFileName);
+ }
+ delete f;
+ }
+ return saveOk;
+}
+
+bool ToucheEngine::loadGameState(int num, const char *description) {
+ bool loadOk = false;
+ char gameStateFileName[16];
+ generateGameStateFileName(num, gameStateFileName, 15);
+ Common::InSaveFile *f = _saveFileMan->openForLoading(gameStateFileName);
+ if (f) {
+ uint16 version = f->readUint16LE();
+ if (version < kCurrentGameStateVersion) {
+ warning("Unsupported gamestate version %d\n", version);
+ } else {
+ f->skip(2 + kGameStateDescriptionLen);
+ loadGameStateData(f);
+ if (!f->ioFailed()) {
+ loadOk = true;
+ } else {
+ warning("Can't read file '%s'", gameStateFileName);
+ }
+ }
+ delete f;
+ }
+ return loadOk;
+}
+
+void ToucheEngine::readGameStateDescription(int num, char *description, int len) {
+ char gameStateFileName[16];
+ generateGameStateFileName(num, gameStateFileName, 15);
+ Common::InSaveFile *f = _saveFileMan->openForLoading(gameStateFileName);
+ if (f) {
+ uint16 version = f->readUint16LE();
+ if (version >= kCurrentGameStateVersion) {
+ f->readUint16LE();
+ f->read(description, MIN<int>(len, kGameStateDescriptionLen));
+ description[len] = 0;
+ }
+ delete f;
+ }
+}
+
+void ToucheEngine::generateGameStateFileName(int num, char *dst, int len, bool prefixOnly) const {
+ if (prefixOnly) {
+ snprintf(dst, len, "%s.", _targetName.c_str());
+ } else {
+ snprintf(dst, len, "%s.%d", _targetName.c_str(), num);
+ }
+ dst[len] = 0;
+}
+
+} // namespace Touche
diff --git a/engines/touche/staticres.cpp b/engines/touche/staticres.cpp
new file mode 100644
index 0000000000..db3b256c00
--- /dev/null
+++ b/engines/touche/staticres.cpp
@@ -0,0 +1,659 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id: $
+ *
+ */
+
+#include "common/stdafx.h"
+
+#include "touche/graphics.h"
+#include "touche/touche.h"
+
+namespace Touche {
+
+ToucheEngine::OpcodeProc ToucheEngine::_opcodesTable[NUM_OPCODES] = {
+ /* 0x00 */
+ &ToucheEngine::op_nop,
+ &ToucheEngine::op_jnz,
+ &ToucheEngine::op_jz,
+ &ToucheEngine::op_jmp,
+ /* 0x04 */
+ &ToucheEngine::op_true,
+ &ToucheEngine::op_false,
+ &ToucheEngine::op_push,
+ &ToucheEngine::op_testFalse,
+ /* 0x08 */
+ &ToucheEngine::op_add,
+ &ToucheEngine::op_sub,
+ &ToucheEngine::op_mul,
+ &ToucheEngine::op_div,
+ /* 0x0C */
+ &ToucheEngine::op_mod,
+ &ToucheEngine::op_and,
+ &ToucheEngine::op_or,
+ &ToucheEngine::op_not,
+ /* 0x10 */
+ &ToucheEngine::op_testGreater,
+ &ToucheEngine::op_testEquals,
+ &ToucheEngine::op_testLower,
+ &ToucheEngine::op_fetchScriptWord,
+ /* 0x14 */
+ 0,
+ 0,
+ 0,
+ 0,
+ /* 0x18 */
+ &ToucheEngine::op_testGreaterOrEquals,
+ &ToucheEngine::op_testLowerOrEquals,
+ &ToucheEngine::op_testNotEquals,
+ &ToucheEngine::op_endConversation,
+ /* 0x1C */
+ &ToucheEngine::op_stopScript,
+ &ToucheEngine::op_getFlag,
+ &ToucheEngine::op_setFlag,
+ 0,
+ /* 0x20 */
+ 0,
+ 0,
+ 0,
+ &ToucheEngine::op_fetchScriptByte,
+ /* 0x24 */
+ 0,
+ 0,
+ 0,
+ 0,
+ /* 0x28 */
+ &ToucheEngine::op_getScriptValue,
+ &ToucheEngine::op_setScriptValue,
+ 0,
+ 0,
+ /* 0x2C */
+ 0,
+ 0,
+ &ToucheEngine::op_getKeyCharWalkBox,
+ &ToucheEngine::op_startSound,
+ /* 0x30 */
+ &ToucheEngine::op_initKeyCharTalk,
+ 0,
+ 0,
+ 0,
+ /* 0x34 */
+ &ToucheEngine::op_loadRoom,
+ &ToucheEngine::op_updateRoom,
+ &ToucheEngine::op_startTalk,
+ &ToucheEngine::op_setKeyCharBox,
+ /* 0x38 */
+ &ToucheEngine::op_initKeyCharScript,
+ &ToucheEngine::op_loadSprite,
+ &ToucheEngine::op_loadSequence,
+ &ToucheEngine::op_setKeyCharFrame,
+ /* 0x3C */
+ &ToucheEngine::op_setKeyCharDirection,
+ &ToucheEngine::op_clearConversationChoices,
+ &ToucheEngine::op_addConversationChoice,
+ &ToucheEngine::op_removeConversationChoice,
+ /* 0x40 */
+ &ToucheEngine::op_getInventoryItem,
+ &ToucheEngine::op_setInventoryItem,
+ &ToucheEngine::op_startEpisode,
+ &ToucheEngine::op_setConversationNum,
+ /* 0x44 */
+ &ToucheEngine::op_enableInventoryItem,
+ &ToucheEngine::op_enableInput,
+ &ToucheEngine::op_disableInput,
+ &ToucheEngine::op_faceKeyChar,
+ /* 0x48 */
+ &ToucheEngine::op_getKeyCharCurrentAnim,
+ &ToucheEngine::op_getCurrentKeyChar,
+ &ToucheEngine::op_isKeyCharActive,
+ &ToucheEngine::op_setPalette,
+ /* 0x4C */
+ &ToucheEngine::op_changeWalkPath,
+ &ToucheEngine::op_lockWalkPath,
+ &ToucheEngine::op_initializeKeyChar,
+ &ToucheEngine::op_setupWaitingKeyChars,
+ /* 0x50 */
+ &ToucheEngine::op_updateRoomAreas,
+ &ToucheEngine::op_unlockWalkPath,
+ 0,
+ &ToucheEngine::op_addItemToInventoryAndRedraw,
+ /* 0x54 */
+ &ToucheEngine::op_giveItemTo,
+ &ToucheEngine::op_resetHitBoxes,
+ &ToucheEngine::op_fadePalette,
+ 0,
+ /* 0x58 */
+ &ToucheEngine::op_disableInventoryItem,
+ 0,
+ 0,
+ 0,
+ /* 0x5C */
+ 0,
+ 0,
+ 0,
+ 0,
+ /* 0x60 */
+ 0,
+ &ToucheEngine::op_getInventoryItemFlags,
+ &ToucheEngine::op_drawInventory,
+ &ToucheEngine::op_stopKeyCharScript,
+ /* 0x64 */
+ &ToucheEngine::op_restartKeyCharScript,
+ &ToucheEngine::op_getKeyCharCurrentWalkBox,
+ &ToucheEngine::op_getKeyCharPointsDataNum,
+ &ToucheEngine::op_setupFollowingKeyChar,
+ /* 0x68 */
+ &ToucheEngine::op_startAnimation,
+ &ToucheEngine::op_setKeyCharTextColor,
+ 0,
+ 0,
+ /* 0x6C */
+ 0,
+ 0,
+ 0,
+ 0,
+ /* 0x70 */
+ &ToucheEngine::op_startMusic,
+ 0,
+ 0,
+ &ToucheEngine::op_copyPaletteColor,
+ /* 0x74 */
+ &ToucheEngine::op_delay,
+ &ToucheEngine::op_lockHitBox,
+ &ToucheEngine::op_removeItemFromInventory,
+ &ToucheEngine::op_unlockHitBox,
+ /* 0x78 */
+ &ToucheEngine::op_addRoomArea,
+ &ToucheEngine::op_setKeyCharFlags,
+ 0,
+ 0,
+ /* 0x7C */
+ 0,
+ 0,
+ 0,
+ 0,
+ /* 0x80 */
+ &ToucheEngine::op_unsetKeyCharFlags,
+ &ToucheEngine::op_drawSpriteOnBackdrop,
+ &ToucheEngine::op_loadVoice,
+ 0,
+ /* 0x84 */
+ &ToucheEngine::op_startPaletteFadeIn,
+ &ToucheEngine::op_startPaletteFadeOut,
+ &ToucheEngine::op_setRoomAreaState
+};
+
+SpriteData ToucheEngine::_spritesTable[NUM_SPRITES] = {
+ { 0x34BC0, 0, 0, 0, 0, 0 },
+ { 0x1E848, 0, 0, 0, 0, 0 },
+ { 0x1E848, 0, 0, 0, 0, 0 },
+ { 0x23A50, 0, 0, 0, 0, 0 },
+ { 0x1E848, 0, 0, 0, 0, 0 }
+};
+
+const uint8 ToucheEngine::_directionsTable[] = {
+ 0x7F, 0x7F, 0x7F, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x7F,
+ 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,
+ 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,
+ 0x7F, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,
+ 0x7F, 0x7F, 0x7F, 0x7F, 0x02, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,
+ 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,
+ 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x02, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x02,
+ 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F,
+ 0x7F, 0x7F, 0x7F, 0x7F, 0x00, 0x00, 0x00
+};
+
+char ToucheEngine::_saveLoadDescriptionsTable[10][33] = {
+ "[Empty.1.......................]",
+ "[Empty.2.......................]",
+ "[Empty.3.......................]",
+ "[Empty.4.......................]",
+ "[Empty.5.......................]",
+ "[Empty.6.......................]",
+ "[Empty.7.......................]",
+ "[Empty.8.......................]",
+ "[Empty.9.......................]"
+};
+
+const Common::Rect ToucheEngine::_inventoryAreasTable[13] = {
+ Common::Rect( 0, 354, 50, 400),
+ Common::Rect( 66, 354, 124, 380),
+ Common::Rect( 74, 380, 116, 398),
+ Common::Rect(116, 380, 158, 398),
+ Common::Rect(144, 354, 198, 380),
+ Common::Rect(202, 354, 238, 396),
+ Common::Rect(242, 354, 300, 396),
+ Common::Rect(300, 354, 358, 396),
+ Common::Rect(358, 354, 416, 396),
+ Common::Rect(416, 354, 474, 396),
+ Common::Rect(474, 354, 532, 396),
+ Common::Rect(532, 354, 590, 396),
+ Common::Rect(594, 354, 640, 395)
+};
+
+const uint16 Graphics::_fontOffs[] = {
+ 0x0000, 0x0007, 0x0024, 0x0043, 0x0072, 0x00AD, 0x00E0, 0x0113, 0x0124, 0x0141,
+ 0x015E, 0x0191, 0x01C4, 0x01E3, 0x01F8, 0x0215, 0x0232, 0x0269, 0x0286, 0x02BD,
+ 0x02F4, 0x032B, 0x0362, 0x0399, 0x03D0, 0x0407, 0x043E, 0x045B, 0x047C, 0x0495,
+ 0x04C0, 0x04D9, 0x0510, 0x054B, 0x0582, 0x05B9, 0x05F0, 0x0627, 0x065E, 0x0695,
+ 0x06CC, 0x0703, 0x0720, 0x0757, 0x078E, 0x07C5, 0x07FC, 0x0833, 0x086A, 0x08A1,
+ 0x08D8, 0x090F, 0x0946, 0x097D, 0x09B4, 0x09EB, 0x0A3C, 0x0A73, 0x0AAA, 0x0AE1,
+ 0x0B00, 0x0B1D, 0x0B3C, 0x0B77, 0x0BAA, 0x0BBB, 0x0BF2, 0x0C29, 0x0C60, 0x0C97,
+ 0x0CCE, 0x0CEB, 0x0D2E, 0x0D65, 0x0D82, 0x0DA5, 0x0DDC, 0x0DF9, 0x0E30, 0x0E67,
+ 0x0E9E, 0x0EE1, 0x0F24, 0x0F41, 0x0F78, 0x0F95, 0x0FCC, 0x1003, 0x103A, 0x1071,
+ 0x10B4, 0x10EB, 0x110A, 0x112B, 0x114A, 0x116D, 0x1178, 0x11BB, 0x11F2, 0x1229,
+ 0x1260, 0x1297, 0x12CE, 0x1305, 0x1348, 0x137F, 0x13B6, 0x13ED, 0x1424, 0x1441,
+ 0x145E, 0x149D, 0x14A8, 0x14B3, 0x14EA, 0x14F5, 0x152C, 0x1563, 0x159A, 0x15D1,
+ 0x1608, 0x1613, 0x161E, 0x1629, 0x1634, 0x163F, 0x164A, 0x1655, 0x1660, 0x1697,
+ 0x16B4, 0x16EB, 0x1722, 0x1759, 0x1764, 0x176F, 0x177A, 0x17B1, 0x17BC, 0x17C7,
+ 0x17D2, 0x17DD
+};
+
+const uint8 Graphics::_fontData[] = {
+ 0x01, 0x01, 0x08, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0D, 0x05, 0x3C, 0x03, 0xD7, 0x0D, 0xD7, 0xCD,
+ 0xD7, 0xCD, 0xD7, 0xCD, 0xD7, 0xC3, 0xD7, 0xC0, 0xD7, 0xC0, 0x3F, 0xC0, 0xD7, 0x00, 0xD7, 0xC0,
+ 0x3F, 0xC0, 0x0F, 0x00, 0x02, 0x07, 0x09, 0x3C, 0x3C, 0x00, 0x0C, 0xD7, 0xD7, 0x00, 0x37, 0xD7,
+ 0xD7, 0xC0, 0xF7, 0xD7, 0xD7, 0xC3, 0x55, 0xD7, 0xD7, 0xC0, 0xDF, 0x3F, 0xFF, 0xC3, 0xDF, 0x0F,
+ 0x0F, 0x0D, 0x55, 0x02, 0x0B, 0x0B, 0x00, 0xC3, 0x00, 0x03, 0x03, 0x7D, 0xC0, 0x0D, 0x0F, 0x7D,
+ 0xF0, 0x0D, 0x35, 0x55, 0x70, 0x35, 0x0D, 0xF7, 0xFC, 0xDD, 0x3D, 0xF7, 0xF0, 0xDD, 0xD5, 0x55,
+ 0xC0, 0x35, 0x37, 0xDF, 0xF0, 0x3D, 0x37, 0xDF, 0xC0, 0xDD, 0x0F, 0xFF, 0x00, 0x35, 0x03, 0x0C,
+ 0x00, 0x0D, 0x02, 0x0E, 0x09, 0x03, 0x00, 0x00, 0xF0, 0x0D, 0xC0, 0x03, 0x5C, 0x0D, 0xF0, 0x0D,
+ 0xF7, 0x35, 0x5C, 0x0D, 0xF7, 0xDD, 0xF7, 0x03, 0x5F, 0xDD, 0xFF, 0xC0, 0xFD, 0x35, 0x5F, 0x00,
+ 0x37, 0x3D, 0xF7, 0x00, 0xDF, 0xDD, 0xF7, 0xC3, 0x7F, 0x35, 0x5F, 0xC0, 0xFC, 0x0D, 0xFF, 0x00,
+ 0x30, 0x0D, 0xFC, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x02, 0x0C, 0x0C,
+ 0x0F, 0x00, 0x00, 0x00, 0x35, 0xC0, 0xC0, 0x00, 0xDF, 0x73, 0x70, 0x03, 0xDF, 0x7D, 0xFC, 0x0D,
+ 0x35, 0xF7, 0xF0, 0x37, 0x0F, 0xDF, 0xC0, 0x37, 0x03, 0x7D, 0x70, 0x0D, 0x0D, 0xF7, 0xDC, 0x37,
+ 0x37, 0xF7, 0xDF, 0x37, 0x0F, 0xCD, 0x7F, 0x0D, 0x03, 0x03, 0xFC, 0x03, 0x00, 0x00, 0xF0, 0x00,
+ 0x02, 0x0C, 0x0B, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0xD7, 0x0F, 0xC0, 0x00, 0xD7, 0x35,
+ 0x70, 0x00, 0xD7, 0xDF, 0xDC, 0x00, 0xD7, 0xDF, 0xFF, 0xC0, 0xFF, 0x35, 0x7D, 0x70, 0x3F, 0xDF,
+ 0xF7, 0xFC, 0x00, 0xDF, 0xDF, 0xF0, 0x00, 0x35, 0x7F, 0x00, 0x00, 0x0F, 0xFC, 0x00, 0x00, 0x03,
+ 0xF0, 0x00, 0x00, 0x01, 0x07, 0x05, 0x3C, 0x00, 0xD7, 0x00, 0xD7, 0xC3, 0xD7, 0xC3, 0xD7, 0xCD,
+ 0xFF, 0xCD, 0x3F, 0x0D, 0x01, 0x0D, 0x06, 0x03, 0x00, 0x0D, 0xC3, 0x37, 0xF0, 0x37, 0xC0, 0xDF,
+ 0xC0, 0xDF, 0x00, 0xDF, 0x00, 0xDF, 0x00, 0x37, 0x00, 0x37, 0xC0, 0x0D, 0xC3, 0x03, 0xF0, 0x00,
+ 0xC0, 0x01, 0x0D, 0x06, 0x30, 0x00, 0xDC, 0x00, 0x37, 0x00, 0x37, 0xC0, 0x0D, 0xC0, 0x0D, 0xF0,
+ 0x0D, 0xF3, 0x0D, 0xF0, 0x37, 0xF0, 0x37, 0xC0, 0xDF, 0xC0, 0x3F, 0x00, 0x0C, 0x00, 0x02, 0x0C,
+ 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x03, 0x0F, 0x7C, 0x00,
+ 0x0D, 0x37, 0x77, 0x00, 0x0D, 0x3D, 0x5F, 0xC0, 0xFD, 0xD5, 0xD5, 0xC3, 0x55, 0x3D, 0x5F, 0xF0,
+ 0xFD, 0x37, 0x77, 0xC0, 0x3D, 0x0F, 0x7F, 0xC0, 0x0D, 0x03, 0xFF, 0x00, 0x03, 0x00, 0x30, 0x00,
+ 0x00, 0x02, 0x0C, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00,
+ 0x03, 0x70, 0x00, 0x00, 0x03, 0x7C, 0x00, 0x00, 0x3F, 0x7F, 0x00, 0x00, 0xD5, 0x55, 0xC0, 0x00,
+ 0x3F, 0x7F, 0xF0, 0x00, 0x0F, 0x7F, 0xC0, 0x3C, 0x03, 0x7C, 0x00, 0xD7, 0x00, 0xFC, 0x00, 0xD7,
+ 0x00, 0x30, 0x03, 0x5F, 0x01, 0x0E, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x0F, 0x00, 0x35, 0xC0, 0x35, 0xF0, 0xD7, 0xF0, 0x3F,
+ 0xC0, 0x0F, 0x00, 0x01, 0x09, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3F, 0xC0, 0xD5, 0x70, 0x3F, 0xFC, 0x0F, 0xF0, 0x01, 0x0D, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x3C, 0x03, 0xD7, 0x0D, 0xD7,
+ 0xCD, 0x3F, 0xC3, 0x0F, 0x00, 0x01, 0x0D, 0x08, 0x00, 0x00, 0x00, 0x30, 0x00, 0xDC, 0x03, 0x7F,
+ 0x03, 0x7C, 0x0D, 0xFC, 0x0D, 0xF0, 0x37, 0xF0, 0x37, 0xC0, 0xDF, 0xC0, 0xDF, 0x00, 0x3F, 0x00,
+ 0x0C, 0x00, 0x02, 0x0D, 0x09, 0x0F, 0xF0, 0x00, 0x0F, 0x35, 0x5C, 0x00, 0xF5, 0xD7, 0xD7, 0x03,
+ 0x55, 0xD7, 0xD7, 0xC0, 0xF5, 0xD7, 0xD7, 0xC0, 0x35, 0xD7, 0xD7, 0xC0, 0x35, 0xD7, 0xD7, 0xC0,
+ 0x35, 0xD7, 0xD7, 0xC0, 0x35, 0xD7, 0xD7, 0xC0, 0x35, 0xD7, 0xD7, 0xC0, 0x35, 0x35, 0x5F, 0xC0,
+ 0x35, 0x0F, 0xFF, 0x00, 0x0F, 0x03, 0xFC, 0x00, 0x03, 0x01, 0x0D, 0x07, 0x03, 0xC0, 0x3D, 0x70,
+ 0xD5, 0x7C, 0x3D, 0x7C, 0x0D, 0x7C, 0x0D, 0x7C, 0x0D, 0x7C, 0x0D, 0x7C, 0x0D, 0x7C, 0x0D, 0x7C,
+ 0x0D, 0x7C, 0x03, 0xFC, 0x00, 0xF0, 0x02, 0x0D, 0x09, 0x0F, 0xF0, 0x00, 0x0F, 0x35, 0x5C, 0x00,
+ 0x35, 0xD7, 0xD7, 0x00, 0xD7, 0xD7, 0xD7, 0xC0, 0x3F, 0x3F, 0xD7, 0xC0, 0x0F, 0x0F, 0x5F, 0xC0,
+ 0x0D, 0x0D, 0x7F, 0x00, 0x03, 0x35, 0xFC, 0x00, 0x00, 0xD7, 0xF0, 0x00, 0x3C, 0xD7, 0xFC, 0x00,
+ 0xD7, 0xD5, 0x57, 0x00, 0x35, 0x3F, 0xFF, 0xC0, 0x0F, 0x0F, 0xFF, 0x00, 0x03, 0x02, 0x0D, 0x09,
+ 0x0F, 0xF0, 0x00, 0x00, 0x35, 0x5C, 0x00, 0x00, 0xD7, 0xD7, 0x00, 0x03, 0x3F, 0xD7, 0xC0, 0x0D,
+ 0x0F, 0xD7, 0xC0, 0x0D, 0x0D, 0x5F, 0xC0, 0x35, 0x03, 0xD7, 0x00, 0x35, 0x00, 0xD7, 0xC0, 0xD7,
+ 0x3C, 0xD7, 0xC0, 0xD5, 0xD7, 0xD7, 0xC0, 0x3F, 0x35, 0x5F, 0xC0, 0x0F, 0x0F, 0xFF, 0x00, 0x00,
+ 0x03, 0xFC, 0x00, 0x00, 0x02, 0x0D, 0x09, 0x00, 0x3C, 0x00, 0x3F, 0x00, 0xD7, 0x00, 0xD5, 0x03,
+ 0x57, 0xC0, 0xD7, 0x0D, 0x57, 0xC0, 0xD7, 0x0D, 0x57, 0xC0, 0xD7, 0x35, 0xD7, 0xC0, 0xD5, 0x35,
+ 0xD7, 0xC0, 0xD7, 0xD7, 0xD7, 0xC0, 0x3F, 0xD5, 0x57, 0xC0, 0x3F, 0x3F, 0xD7, 0xC0, 0xD7, 0x0F,
+ 0xD7, 0xC0, 0x35, 0x00, 0x3F, 0xC0, 0x0F, 0x00, 0x0F, 0x00, 0x03, 0x02, 0x0D, 0x09, 0x3F, 0xFC,
+ 0x00, 0x0F, 0xD5, 0x57, 0x00, 0x35, 0xD7, 0xFF, 0xC0, 0xD7, 0xD7, 0xFF, 0x00, 0xD7, 0xD7, 0xF0,
+ 0x00, 0xD7, 0xD5, 0x5C, 0x00, 0xD5, 0xD7, 0xD7, 0x00, 0xD7, 0x3F, 0xD7, 0xC0, 0xD7, 0x3F, 0xD7,
+ 0xC0, 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0x35, 0x5F, 0xC0, 0x35, 0x0F, 0xFF, 0x00, 0x0F, 0x03, 0xFC,
+ 0x00, 0x03, 0x02, 0x0D, 0x09, 0x0F, 0xF0, 0x00, 0x3F, 0x35, 0x5C, 0x00, 0xD5, 0xD7, 0xD7, 0x00,
+ 0x3F, 0xD7, 0xFF, 0xC0, 0x0F, 0xD7, 0xFF, 0x00, 0x03, 0xD5, 0x5C, 0x00, 0x0D, 0xD7, 0xD7, 0x00,
+ 0x0D, 0xD7, 0xD7, 0xC0, 0x0D, 0xD7, 0xD7, 0xC0, 0x35, 0xD7, 0xD7, 0xC0, 0x35, 0x35, 0x5F, 0xC0,
+ 0x35, 0x0F, 0xFF, 0x00, 0x0F, 0x03, 0xFC, 0x00, 0x03, 0x02, 0x0D, 0x09, 0x3F, 0xFC, 0x00, 0x0F,
+ 0xD5, 0x57, 0x00, 0x35, 0x3F, 0xD7, 0xC0, 0xD7, 0x0F, 0x5F, 0xC0, 0xD7, 0x03, 0x5F, 0x00, 0xD7,
+ 0x0D, 0x7F, 0x00, 0x35, 0x0D, 0x7C, 0x00, 0xD7, 0x0D, 0x7C, 0x00, 0xD7, 0x35, 0xFC, 0x00, 0xD7,
+ 0x35, 0xF0, 0x00, 0xD7, 0x35, 0xF0, 0x00, 0x35, 0x0F, 0xF0, 0x00, 0x0F, 0x03, 0xC0, 0x00, 0x03,
+ 0x02, 0x0D, 0x09, 0x0F, 0xF0, 0x00, 0x0F, 0x35, 0x5C, 0x00, 0x35, 0xD7, 0xD7, 0x00, 0xD7, 0xD7,
+ 0xD7, 0xC0, 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0x35, 0x5F, 0xC0, 0xD7, 0xD7, 0xD7, 0x00, 0x35, 0xD7,
+ 0xD7, 0xC0, 0x0F, 0xD7, 0xD7, 0xC0, 0x3F, 0xD7, 0xD7, 0xC0, 0xD7, 0x35, 0x5F, 0xC0, 0x35, 0x0F,
+ 0xFF, 0x00, 0x0F, 0x03, 0xFC, 0x00, 0x03, 0x02, 0x0D, 0x09, 0x0F, 0xF0, 0x00, 0x00, 0x35, 0x5C,
+ 0x00, 0x00, 0xD7, 0xD7, 0x00, 0x00, 0xD7, 0xD7, 0xC0, 0x00, 0xD7, 0xD7, 0xC0, 0xF0, 0xD7, 0xD7,
+ 0xC3, 0x5C, 0x35, 0x57, 0xC3, 0x5F, 0x0F, 0xD7, 0xC0, 0xFF, 0x3F, 0xD7, 0xC0, 0xFC, 0xD7, 0xD7,
+ 0xC3, 0x5C, 0x35, 0x5F, 0xC3, 0x5F, 0x0F, 0xFF, 0x00, 0xFF, 0x03, 0xFC, 0x00, 0x3C, 0x01, 0x0D,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0xD7, 0x03, 0xD7, 0xC3, 0x3F,
+ 0xC0, 0x3F, 0x00, 0xD7, 0x03, 0xD7, 0xC3, 0x3F, 0xC0, 0x0F, 0x03, 0x01, 0x0F, 0x05, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0xD7, 0x00, 0xD7, 0xC0, 0x3F, 0xC0, 0x3F, 0x00,
+ 0xD7, 0x00, 0xD7, 0xC0, 0x37, 0xC0, 0xDF, 0xC0, 0x3F, 0x00, 0x0C, 0x00, 0x01, 0x0B, 0x07, 0x00,
+ 0x00, 0x00, 0xC0, 0x03, 0x70, 0x0D, 0xFC, 0x37, 0xF0, 0xDF, 0xC0, 0x37, 0x00, 0x0D, 0xC0, 0x03,
+ 0x70, 0x00, 0xFC, 0x00, 0x30, 0x02, 0x0A, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0,
+ 0x00, 0x00, 0x03, 0x70, 0x3F, 0xFC, 0x00, 0xDC, 0xD5, 0x57, 0x00, 0x37, 0x3F, 0xFF, 0xC0, 0x0D,
+ 0x3F, 0xFF, 0x00, 0x37, 0xD5, 0x57, 0x00, 0xDF, 0x3F, 0xFF, 0xC3, 0x7F, 0x0F, 0xFF, 0x00, 0xFC,
+ 0x01, 0x0B, 0x07, 0x00, 0x00, 0x30, 0x00, 0xDC, 0x00, 0x37, 0x00, 0x0D, 0xC0, 0x03, 0x70, 0x0D,
+ 0xFC, 0x37, 0xF0, 0xDF, 0xC0, 0x3F, 0x00, 0x0C, 0x00, 0x02, 0x0D, 0x09, 0x0F, 0xF0, 0x00, 0x00,
+ 0x35, 0x5C, 0x00, 0x00, 0xD7, 0xD7, 0x00, 0x00, 0xD7, 0xD7, 0xC0, 0x00, 0x3F, 0xD7, 0xC0, 0x00,
+ 0x0F, 0x5F, 0xC0, 0x00, 0x0D, 0x7F, 0x00, 0x00, 0x0D, 0x7C, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x00,
+ 0x0D, 0x70, 0x00, 0x00, 0x0D, 0x7C, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00,
+ 0x02, 0x0E, 0x0D, 0x03, 0xFF, 0xC0, 0x00, 0x0D, 0x55, 0x70, 0x00, 0x37, 0xFF, 0xDC, 0x00, 0xDF,
+ 0xFF, 0xF7, 0x00, 0xDF, 0xD5, 0xF7, 0xC0, 0xDF, 0x7D, 0xF7, 0xC0, 0xDF, 0x7D, 0xF7, 0xC0, 0xDF,
+ 0x7D, 0xF7, 0xC0, 0xDF, 0x75, 0xDF, 0xC0, 0xDF, 0xDD, 0x7F, 0x00, 0x37, 0xFF, 0xFC, 0x00, 0x0D,
+ 0x5C, 0xF0, 0x00, 0x03, 0xFF, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x02, 0x0D, 0x0B, 0x00, 0xF0,
+ 0x00, 0x3F, 0x03, 0x5C, 0x00, 0xD5, 0x03, 0x5F, 0x00, 0xD7, 0x0D, 0x57, 0x00, 0xD7, 0x0D, 0x57,
+ 0xC0, 0xD7, 0x0D, 0xF7, 0xC0, 0xD5, 0x35, 0xF5, 0xC0, 0xD7, 0x35, 0xF5, 0xF0, 0xD7, 0x35, 0x55,
+ 0xF0, 0xD7, 0xD7, 0xFD, 0x70, 0xD7, 0xD7, 0xFD, 0x7C, 0xD5, 0x3F, 0xC3, 0xFC, 0x3F, 0x0F, 0x00,
+ 0xF0, 0x0F, 0x02, 0x0D, 0x0B, 0x3F, 0xFF, 0x00, 0x03, 0xD5, 0x55, 0xC0, 0x0D, 0xD7, 0xFD, 0x70,
+ 0x35, 0xD7, 0xFD, 0x7C, 0xD7, 0xD7, 0xFD, 0x7C, 0xD7, 0xD5, 0x55, 0xFC, 0xD7, 0xD7, 0xFD, 0x70,
+ 0xD7, 0xD7, 0xFD, 0x7C, 0xD7, 0xD7, 0xCD, 0x7C, 0xD7, 0xD7, 0xFD, 0x7C, 0x35, 0xD5, 0x55, 0xFC,
+ 0x0D, 0x3F, 0xFF, 0xF0, 0x03, 0x0F, 0xFF, 0xC0, 0x00, 0x02, 0x0D, 0x0A, 0x03, 0xFC, 0x00, 0x0F,
+ 0x0D, 0x57, 0x00, 0x35, 0x35, 0xF5, 0xC0, 0x35, 0xD7, 0xFD, 0xF0, 0x35, 0xD7, 0xC3, 0xF0, 0x35,
+ 0xD7, 0xC0, 0xC0, 0x35, 0xD7, 0xC0, 0x00, 0x35, 0xD7, 0xC3, 0x00, 0x35, 0xD7, 0xCD, 0xC0, 0x35,
+ 0x35, 0xF5, 0xF0, 0x35, 0x0D, 0x57, 0xF0, 0x35, 0x03, 0xFF, 0xC0, 0x0F, 0x00, 0xFF, 0x00, 0x03,
+ 0x02, 0x0D, 0x0B, 0x3F, 0xFC, 0x00, 0x03, 0xD5, 0x57, 0x00, 0x0D, 0xD7, 0xF5, 0xC0, 0x0D, 0xD7,
+ 0xFD, 0x70, 0x0D, 0xD7, 0xCD, 0x7C, 0x0D, 0xD7, 0xCD, 0x7C, 0x0D, 0xD7, 0xCD, 0x7C, 0x0D, 0xD7,
+ 0xCD, 0x7C, 0x0D, 0xD7, 0xCD, 0x7C, 0x0D, 0xD7, 0xF5, 0xFC, 0x0D, 0xD5, 0x57, 0xF0, 0x0D, 0x3F,
+ 0xFF, 0xC0, 0x03, 0x0F, 0xFF, 0x00, 0x00, 0x02, 0x0D, 0x0A, 0x3F, 0xFF, 0x00, 0x0F, 0xD5, 0x55,
+ 0xC0, 0x35, 0xD7, 0xFF, 0xF0, 0x35, 0xD7, 0xFF, 0xC0, 0x35, 0xD7, 0xFC, 0x00, 0x35, 0xD5, 0x57,
+ 0x00, 0x35, 0xD7, 0xFF, 0xC0, 0x35, 0xD7, 0xFF, 0x00, 0x35, 0xD7, 0xC0, 0x00, 0x35, 0xD7, 0xFF,
+ 0x00, 0x35, 0xD5, 0x55, 0xC0, 0x35, 0x3F, 0xFF, 0xF0, 0x0F, 0x0F, 0xFF, 0xC0, 0x03, 0x02, 0x0D,
+ 0x0A, 0x3F, 0xFF, 0x00, 0x03, 0xD5, 0x55, 0xC0, 0x0D, 0xD7, 0xFF, 0xF0, 0x35, 0xD7, 0xFF, 0xC0,
+ 0xD7, 0xD7, 0xFC, 0x00, 0xD7, 0xD5, 0x57, 0x00, 0xD7, 0xD7, 0xFF, 0xC0, 0xD7, 0xD7, 0xFF, 0x00,
+ 0xD7, 0xD7, 0xC0, 0x00, 0xD7, 0xD7, 0xC0, 0x00, 0x35, 0xD7, 0xC0, 0x00, 0x0D, 0x3F, 0xC0, 0x00,
+ 0x03, 0x0F, 0x00, 0x00, 0x00, 0x02, 0x0D, 0x0B, 0x03, 0xFF, 0x00, 0x03, 0x0D, 0x55, 0xC0, 0x0D,
+ 0x35, 0xFD, 0x70, 0x0D, 0xD7, 0xFF, 0x7C, 0x0D, 0xD7, 0xC0, 0xFC, 0x0D, 0xD7, 0xFF, 0xF0, 0x0D,
+ 0xD7, 0xD5, 0x70, 0x0D, 0xD7, 0xFD, 0x7C, 0x0D, 0xD7, 0xCD, 0x7C, 0x0D, 0x35, 0xFD, 0x7C, 0x0D,
+ 0x0D, 0x57, 0x7C, 0x0D, 0x03, 0xFF, 0xFC, 0x03, 0x00, 0xFF, 0x30, 0x00, 0x02, 0x0D, 0x0B, 0x3C,
+ 0x03, 0xC0, 0x03, 0xD7, 0x0D, 0x70, 0x0D, 0xD7, 0xCD, 0x7C, 0x0D, 0xD7, 0xCD, 0x7C, 0x0D, 0xD7,
+ 0xFD, 0x7C, 0x0D, 0xD5, 0x55, 0x7C, 0x0D, 0xD7, 0xFD, 0x7C, 0x0D, 0xD7, 0xFD, 0x7C, 0x0D, 0xD7,
+ 0xCD, 0x7C, 0x0D, 0xD7, 0xCD, 0x7C, 0x0D, 0xD7, 0xCD, 0x7C, 0x0D, 0x3F, 0xC3, 0xFC, 0x03, 0x0F,
+ 0x00, 0xF0, 0x00, 0x01, 0x0D, 0x05, 0x3C, 0x00, 0xD7, 0x00, 0xD7, 0xC0, 0xD7, 0xC0, 0xD7, 0xC0,
+ 0xD7, 0xC0, 0xD7, 0xC0, 0xD7, 0xC0, 0xD7, 0xC3, 0xD7, 0xC3, 0xD7, 0xC0, 0x3F, 0xC0, 0x0F, 0x00,
+ 0x02, 0x0D, 0x09, 0x00, 0x3C, 0x00, 0x3C, 0x00, 0xD7, 0x00, 0xD7, 0x00, 0xD7, 0xC0, 0xD7, 0x00,
+ 0xD7, 0xC0, 0xD7, 0x00, 0xD7, 0xC0, 0xD5, 0x00, 0xD7, 0xC0, 0xD5, 0x00, 0xD7, 0xC0, 0xD5, 0x3C,
+ 0xD7, 0xC0, 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0x35, 0x5F, 0xC0, 0xD7, 0x0F,
+ 0xFF, 0x00, 0x3F, 0x03, 0xFC, 0x00, 0x0F, 0x02, 0x0D, 0x0B, 0x3C, 0x0F, 0x00, 0x0F, 0xD7, 0x35,
+ 0xC0, 0x35, 0xD7, 0xD7, 0xF0, 0x35, 0xD7, 0x5F, 0xC0, 0x35, 0xD5, 0x7F, 0x00, 0x35, 0xD5, 0xFC,
+ 0x00, 0x35, 0xD5, 0x70, 0x00, 0x35, 0xD7, 0x5C, 0x00, 0x35, 0xD7, 0xD7, 0x00, 0x35, 0xD7, 0xF5,
+ 0xC0, 0x35, 0xD7, 0xCD, 0x70, 0x35, 0x3F, 0xC3, 0xFC, 0x0F, 0x0F, 0x00, 0xF0, 0x03, 0x02, 0x0D,
+ 0x0A, 0x3C, 0x00, 0x00, 0x3C, 0xD7, 0x00, 0x00, 0xD7, 0xD7, 0xC0, 0x00, 0xD7, 0xD7, 0xC0, 0x00,
+ 0xD5, 0xD7, 0xC0, 0x00, 0xD5, 0xD7, 0xC0, 0x00, 0xD5, 0xD7, 0xC0, 0x00, 0xD5, 0xD7, 0xC0, 0x00,
+ 0xD7, 0xD7, 0xC0, 0x00, 0xD7, 0xD7, 0xFF, 0x00, 0xD7, 0xD5, 0x55, 0xC0, 0xD7, 0x3F, 0xFF, 0xF0,
+ 0x3F, 0x0F, 0xFF, 0xC0, 0x0F, 0x02, 0x0D, 0x0D, 0x3C, 0x00, 0x3C, 0x00, 0xD7, 0x00, 0xD7, 0x00,
+ 0xD7, 0xC0, 0xD7, 0xC0, 0xD5, 0xC3, 0x57, 0xC0, 0xD5, 0xF3, 0x57, 0xC0, 0xD5, 0x7D, 0x57, 0xC0,
+ 0xD5, 0x7D, 0x57, 0xC0, 0xD7, 0x55, 0xD7, 0xC0, 0xD7, 0x55, 0xD7, 0xC0, 0xD7, 0xD7, 0xD7, 0xC0,
+ 0xD7, 0xD7, 0xD7, 0xC0, 0x3F, 0xFF, 0xFF, 0xC0, 0x0F, 0x0F, 0x0F, 0x00, 0x02, 0x0D, 0x0B, 0x3C,
+ 0x03, 0xC0, 0x00, 0xD7, 0x0D, 0x70, 0x00, 0xD5, 0xCD, 0x7C, 0x03, 0xD5, 0x7D, 0x7C, 0x0D, 0xD5,
+ 0x7D, 0x7C, 0x0D, 0xD7, 0x5D, 0x7C, 0x0D, 0xD7, 0x5D, 0x7C, 0x0D, 0xD7, 0xD5, 0x7C, 0x0D, 0xD7,
+ 0xD5, 0x7C, 0x0D, 0xD7, 0xF5, 0x7C, 0x03, 0xD7, 0xCD, 0x7C, 0x00, 0x3F, 0xC3, 0xFC, 0x00, 0x0F,
+ 0x00, 0xF0, 0x00, 0x02, 0x0D, 0x0B, 0x03, 0xFC, 0x00, 0x03, 0x0D, 0x57, 0x00, 0x0D, 0x35, 0xF5,
+ 0xC0, 0x0D, 0xD7, 0xFD, 0x70, 0x0D, 0xD7, 0xCD, 0x7C, 0x0D, 0xD7, 0xCD, 0x7C, 0x0D, 0xD7, 0xCD,
+ 0x7C, 0x0D, 0xD7, 0xCD, 0x7C, 0x0D, 0xD7, 0xCD, 0x7C, 0x0D, 0x35, 0xF5, 0xFC, 0x0D, 0x0D, 0x57,
+ 0xF0, 0x0D, 0x03, 0xFF, 0xC0, 0x03, 0x00, 0xFF, 0x00, 0x00, 0x02, 0x0D, 0x0B, 0x3F, 0xFF, 0x00,
+ 0x00, 0xD5, 0x55, 0xC0, 0x03, 0xD7, 0xFD, 0x70, 0x0D, 0xD7, 0xFD, 0x7C, 0x35, 0xD7, 0xCD, 0x7C,
+ 0x35, 0xD7, 0xFD, 0x7C, 0x35, 0xD5, 0x55, 0xFC, 0x35, 0xD7, 0xFF, 0xF0, 0x35, 0xD7, 0xFF, 0xC0,
+ 0x35, 0xD7, 0xC0, 0x00, 0x0D, 0xD7, 0xC0, 0x00, 0x03, 0x3F, 0xC0, 0x00, 0x00, 0x0F, 0x00, 0x00,
+ 0x00, 0x02, 0x0D, 0x0B, 0x03, 0xFC, 0x00, 0x00, 0x0D, 0x57, 0x00, 0x00, 0x35, 0xF5, 0xC0, 0x00,
+ 0xD7, 0xFD, 0x70, 0x00, 0xD7, 0xCD, 0x7C, 0x00, 0xD7, 0xCD, 0x7C, 0x00, 0xD7, 0xCD, 0x7C, 0x00,
+ 0xD7, 0xFD, 0x7C, 0x00, 0xD7, 0xD5, 0x7C, 0x00, 0x35, 0xF5, 0xFC, 0x00, 0x0D, 0x55, 0x70, 0x00,
+ 0x03, 0xFF, 0xFC, 0x00, 0x00, 0xFF, 0xF0, 0x00, 0x02, 0x0D, 0x0C, 0x3F, 0xFF, 0x00, 0x00, 0xD5,
+ 0x55, 0xC0, 0x03, 0xD7, 0xFD, 0x70, 0x0D, 0xD7, 0xFD, 0x7C, 0x0D, 0xD7, 0xCD, 0x7C, 0x0D, 0xD7,
+ 0xFD, 0x7C, 0x03, 0xD5, 0x55, 0xFC, 0x00, 0xD7, 0xFD, 0x70, 0x03, 0xD7, 0xFD, 0x7C, 0x0D, 0xD7,
+ 0xCD, 0x7C, 0x0D, 0xD7, 0xC3, 0x5C, 0x03, 0x3F, 0xC0, 0xFF, 0x00, 0x0F, 0x00, 0x3C, 0x00, 0x02,
+ 0x0D, 0x0A, 0x0F, 0xFC, 0x00, 0x3F, 0x35, 0x57, 0x00, 0xD5, 0xD7, 0xF5, 0xC0, 0x3F, 0xD7, 0xF5,
+ 0xF0, 0x0F, 0xD7, 0xCF, 0xF0, 0x03, 0x35, 0x7F, 0xC0, 0x03, 0x0F, 0x57, 0x00, 0x03, 0x3F, 0xF5,
+ 0xC0, 0x03, 0xD7, 0x35, 0xF0, 0x03, 0xD7, 0xF5, 0xF0, 0x03, 0x35, 0x57, 0xF0, 0x03, 0x0F, 0xFF,
+ 0xC0, 0x00, 0x03, 0xFF, 0x00, 0x00, 0x02, 0x0D, 0x0B, 0x3F, 0xFF, 0xC0, 0x0F, 0xD5, 0x55, 0x70,
+ 0x35, 0x3F, 0x5F, 0xFC, 0x35, 0x0F, 0x5F, 0xF0, 0x35, 0x03, 0x5F, 0x00, 0x35, 0x03, 0x5F, 0x00,
+ 0x35, 0x03, 0x5F, 0x00, 0x35, 0x03, 0x5F, 0x00, 0x35, 0x03, 0x5F, 0x00, 0x35, 0x03, 0x5F, 0x00,
+ 0x0D, 0x03, 0x5F, 0x00, 0x03, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x02, 0x0D, 0x0B,
+ 0x3C, 0x03, 0xC0, 0x0F, 0xD7, 0x0D, 0x70, 0x35, 0xD7, 0xCD, 0x7C, 0x35, 0xD7, 0xCD, 0x7C, 0x0D,
+ 0xD7, 0xCD, 0x7C, 0x0D, 0xD7, 0xCD, 0x7C, 0x0D, 0xD7, 0xCD, 0x7C, 0x03, 0xD7, 0xCD, 0x7C, 0x03,
+ 0xD7, 0xCD, 0x7C, 0x03, 0x35, 0xF5, 0xFC, 0x00, 0x0D, 0x57, 0xF0, 0x00, 0x03, 0xFF, 0xC0, 0x00,
+ 0x00, 0xFF, 0x00, 0x00, 0x02, 0x0D, 0x0B, 0x3C, 0x03, 0xC0, 0x3C, 0xD7, 0x0D, 0x70, 0xD7, 0xD7,
+ 0xCD, 0x7C, 0xD7, 0x35, 0xF5, 0xFC, 0xD7, 0x35, 0xF5, 0xF0, 0x35, 0x35, 0xF5, 0xF0, 0x35, 0x0D,
+ 0xF7, 0xF0, 0x0D, 0x0D, 0x57, 0xC0, 0x0D, 0x0D, 0x57, 0xC0, 0x03, 0x03, 0x5F, 0xC0, 0x03, 0x03,
+ 0x5F, 0x00, 0x03, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x03, 0x0D, 0x11, 0x3C, 0x03,
+ 0xC0, 0x3C, 0x03, 0xC0, 0xD7, 0x0D, 0x70, 0xD7, 0x0D, 0x70, 0xD7, 0xCD, 0x7C, 0xD7, 0xCD, 0x7C,
+ 0xD7, 0xCD, 0x7C, 0xD7, 0xC3, 0x5C, 0x35, 0xF5, 0x5F, 0x5F, 0xC0, 0xD7, 0x35, 0xF5, 0x5F, 0x5F,
+ 0x00, 0x35, 0x0D, 0x77, 0xDD, 0x7F, 0x00, 0x35, 0x0D, 0x57, 0xD5, 0x7C, 0x00, 0xD7, 0x03, 0x5F,
+ 0xF5, 0xFC, 0x03, 0x5F, 0x03, 0x5F, 0x35, 0xF0, 0x0D, 0x7F, 0x03, 0x5F, 0x35, 0xF0, 0x0D, 0x7C,
+ 0x00, 0xFF, 0x0F, 0xF0, 0x03, 0xFC, 0x00, 0x3C, 0x03, 0xC0, 0x00, 0xF0, 0x02, 0x0D, 0x0C, 0x3C,
+ 0x00, 0xF0, 0x0F, 0xD7, 0x03, 0x5C, 0x35, 0xD7, 0xC3, 0x5F, 0x35, 0x35, 0xCD, 0x7F, 0x0D, 0x0D,
+ 0x75, 0xFC, 0x03, 0x03, 0x57, 0xF0, 0x00, 0x03, 0x57, 0xC0, 0x00, 0x0D, 0x75, 0xC0, 0x00, 0x35,
+ 0xFD, 0x70, 0x00, 0xD7, 0xF3, 0x5C, 0x00, 0xD7, 0xC3, 0x5F, 0x00, 0x3F, 0xC0, 0xFF, 0x00, 0x0F,
+ 0x00, 0x3C, 0x00, 0x02, 0x0D, 0x0D, 0x3C, 0x00, 0x3C, 0x03, 0xD7, 0x00, 0xD7, 0x0D, 0xD7, 0xC0,
+ 0xD7, 0xC3, 0x35, 0xC3, 0x5F, 0xC0, 0x0D, 0x7D, 0x7F, 0x00, 0x03, 0x55, 0xFC, 0x00, 0x00, 0xD7,
+ 0xF0, 0x00, 0x00, 0xD7, 0xC0, 0x00, 0x00, 0xD7, 0xC0, 0x03, 0x00, 0xD7, 0xC0, 0x0D, 0x00, 0xD7,
+ 0xC0, 0x0D, 0x00, 0x3F, 0xC0, 0x03, 0x00, 0x0F, 0x00, 0x00, 0x02, 0x0D, 0x0C, 0x3F, 0xFF, 0xF0,
+ 0x00, 0xD5, 0x55, 0x5C, 0x00, 0x3F, 0xFF, 0x5F, 0x00, 0x0F, 0xFD, 0x7F, 0x00, 0x00, 0x35, 0xFC,
+ 0x00, 0x00, 0xD7, 0xF0, 0x00, 0x03, 0x5F, 0xC0, 0x00, 0x0D, 0x7F, 0x00, 0x00, 0x35, 0xFC, 0x00,
+ 0x00, 0xD7, 0xFF, 0xF0, 0x00, 0xD5, 0x55, 0x5C, 0x00, 0x3F, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFC,
+ 0x00, 0x01, 0x0E, 0x06, 0x3F, 0x00, 0xD5, 0xC3, 0xDF, 0xF3, 0xDF, 0xC0, 0xDF, 0x00, 0xDF, 0x00,
+ 0xDF, 0x00, 0xDF, 0x00, 0xDF, 0x00, 0xDF, 0x00, 0xDF, 0x00, 0xD5, 0xC0, 0x3F, 0xF0, 0x0F, 0xC0,
+ 0x01, 0x0D, 0x08, 0x30, 0x00, 0xDC, 0x00, 0xDF, 0x00, 0x37, 0x00, 0x37, 0xC0, 0x0D, 0xC0, 0x0D,
+ 0xF0, 0x03, 0x70, 0x03, 0x7C, 0x00, 0xDC, 0x00, 0xDF, 0x00, 0x3F, 0x00, 0x0C, 0x01, 0x0E, 0x06,
+ 0x3F, 0x00, 0xD5, 0xC0, 0x3D, 0xF0, 0x0D, 0xF0, 0x0D, 0xF0, 0x0D, 0xF0, 0x0D, 0xF0, 0x0D, 0xF0,
+ 0x0D, 0xF0, 0x0D, 0xF0, 0x3D, 0xF0, 0xD5, 0xF0, 0x3F, 0xF0, 0x0F, 0xC0, 0x02, 0x0E, 0x0A, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x03, 0x70, 0x00, 0x00, 0x0D,
+ 0x5C, 0x00, 0x03, 0x37, 0x77, 0x00, 0x0D, 0xDF, 0x7D, 0xC0, 0x35, 0x3F, 0x7F, 0xF0, 0x0D, 0x0F,
+ 0x7C, 0xC0, 0x03, 0x03, 0x7C, 0x00, 0x00, 0x03, 0x7C, 0x00, 0x00, 0x03, 0x7C, 0x00, 0x00, 0x00,
+ 0xFC, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x02, 0x0C, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x03, 0x70, 0x00, 0x00, 0x0D, 0xFC, 0x00, 0x00, 0x37, 0xFF,
+ 0xC0, 0x00, 0xD5, 0x55, 0x70, 0x00, 0x37, 0xFF, 0xFC, 0x00, 0x0D, 0xFF, 0xF0, 0x00, 0x03, 0x70,
+ 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x01, 0x07, 0x04, 0x0C, 0x00, 0x37,
+ 0x00, 0xD7, 0x00, 0xD7, 0x00, 0xD7, 0x03, 0xDC, 0x0D, 0x30, 0x03, 0x02, 0x0D, 0x09, 0x00, 0x00,
+ 0x00, 0x3C, 0x00, 0x00, 0x00, 0xD7, 0x00, 0x00, 0x00, 0xD7, 0x0F, 0xF0, 0x00, 0xD7, 0x35, 0x5C,
+ 0x00, 0xD5, 0xD7, 0xD7, 0x00, 0xD7, 0x3D, 0x57, 0xC0, 0xD7, 0x35, 0xD7, 0xC0, 0xD7, 0xD7, 0xD7,
+ 0xC0, 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0x35, 0x57, 0xC0, 0xD5, 0x0F, 0xFF, 0xC0, 0x3F, 0x03, 0xFF,
+ 0x00, 0x0F, 0x02, 0x0D, 0x09, 0x3C, 0x00, 0x00, 0x00, 0xD7, 0x00, 0x00, 0x00, 0xD7, 0xC0, 0x00,
+ 0x00, 0xD7, 0xF0, 0x00, 0x0F, 0xD5, 0x5C, 0x00, 0x35, 0xD7, 0xD7, 0x00, 0xD7, 0xD7, 0xD7, 0xC0,
+ 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0xD5, 0x5F, 0xC0,
+ 0x35, 0x3F, 0xFF, 0x00, 0x0F, 0x0F, 0xFC, 0x00, 0x03, 0x02, 0x0D, 0x09, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x0F, 0xF0, 0x00, 0x3F, 0x35, 0x5C, 0x00, 0xD5,
+ 0xD7, 0xD7, 0x03, 0x5F, 0xD7, 0xFF, 0xC3, 0x5F, 0xD7, 0xCF, 0x03, 0x5F, 0xD7, 0xFC, 0x03, 0x5F,
+ 0xD7, 0xD7, 0x03, 0x5F, 0x35, 0x5F, 0xC0, 0xD5, 0x0F, 0xFF, 0x00, 0x3F, 0x03, 0xFC, 0x00, 0x0F,
+ 0x02, 0x0D, 0x09, 0x00, 0x3C, 0x00, 0x00, 0x00, 0xD7, 0x00, 0x00, 0x00, 0xD7, 0xC0, 0x00, 0x0F,
+ 0xD7, 0xC0, 0x0F, 0x35, 0x57, 0xC0, 0x35, 0xD7, 0xD7, 0xC0, 0xD7, 0xD7, 0xD7, 0xC0, 0xD5, 0xD7,
+ 0xD7, 0xC0, 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0x35, 0x57, 0xC0, 0x35, 0x0F,
+ 0xFF, 0xC0, 0x0F, 0x03, 0xFF, 0x00, 0x03, 0x02, 0x0D, 0x09, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00,
+ 0x00, 0x35, 0x00, 0x00, 0x00, 0xD7, 0x0F, 0xF0, 0x00, 0xD7, 0x35, 0x5C, 0x03, 0x55, 0xD7, 0xD7,
+ 0x00, 0xD7, 0xD5, 0x57, 0xC0, 0xD7, 0xD7, 0xFF, 0xC0, 0xD7, 0xD7, 0xFF, 0x00, 0xD7, 0xD7, 0xD7,
+ 0x00, 0xD7, 0x35, 0x5F, 0xC0, 0xD7, 0x0F, 0xFF, 0x00, 0x3F, 0x03, 0xFC, 0x00, 0x0F, 0x01, 0x0D,
+ 0x07, 0x03, 0xC0, 0x0D, 0x70, 0x35, 0xFC, 0x35, 0xF0, 0xD5, 0x70, 0x35, 0xFC, 0x35, 0xF0, 0x35,
+ 0xF0, 0x35, 0xF0, 0x35, 0xF0, 0x35, 0xF0, 0x0F, 0xF0, 0x03, 0xC0, 0x02, 0x10, 0x09, 0x00, 0x00,
+ 0x00, 0x3C, 0x00, 0x00, 0x00, 0xD7, 0x00, 0x00, 0x00, 0xD7, 0x0F, 0xFC, 0x00, 0xD7, 0x35, 0x57,
+ 0x00, 0xD5, 0xD7, 0xD7, 0xC0, 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0xD7, 0xD7,
+ 0xC0, 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0x35, 0x57, 0xC0, 0xD7, 0x3F, 0xD7, 0xC0, 0x3F, 0xD7, 0xD7,
+ 0xC0, 0x0F, 0x35, 0x5F, 0xC0, 0x00, 0x0F, 0xFF, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x02, 0x0D,
+ 0x09, 0x3C, 0x00, 0x00, 0x3C, 0xD7, 0x00, 0x00, 0xD7, 0xD7, 0xC0, 0x00, 0xD7, 0xD7, 0xF0, 0x00,
+ 0x3F, 0xD5, 0x5C, 0x00, 0xD7, 0xD7, 0xD7, 0x00, 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0xD7, 0xD7, 0xC0,
+ 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0x3F, 0xFF, 0xC0,
+ 0x3F, 0x0F, 0x0F, 0x00, 0x0F, 0x01, 0x0D, 0x05, 0x3C, 0x00, 0xD7, 0x00, 0xD7, 0xC0, 0x3F, 0xC0,
+ 0xD7, 0x00, 0xD7, 0xC0, 0xD7, 0xC0, 0xD7, 0xC0, 0xD7, 0xC0, 0xD7, 0xC0, 0xD7, 0xC0, 0x3F, 0xC0,
+ 0x0F, 0x00, 0x01, 0x10, 0x06, 0x0F, 0x00, 0x35, 0xC0, 0x35, 0xF0, 0x0F, 0xF0, 0x35, 0xC0, 0x35,
+ 0xF0, 0x35, 0xF0, 0x35, 0xF0, 0x35, 0xF0, 0x35, 0xF0, 0x35, 0xF0, 0x35, 0xF0, 0x35, 0xF0, 0xD7,
+ 0xF0, 0x3F, 0xC0, 0x0F, 0x00, 0x02, 0x0D, 0x09, 0x3C, 0x00, 0x00, 0xF0, 0xD7, 0x00, 0x03, 0x5C,
+ 0xD7, 0xC0, 0x03, 0x5F, 0xD7, 0xFC, 0x03, 0x5F, 0xD7, 0xD7, 0x03, 0x5F, 0xD7, 0x5F, 0xC3, 0x5F,
+ 0xD5, 0x7F, 0x03, 0x5F, 0xD5, 0xFC, 0x03, 0x5F, 0xD5, 0x70, 0x03, 0x5F, 0xD7, 0x5C, 0x03, 0x5F,
+ 0xD7, 0xD7, 0x03, 0x5F, 0x3F, 0xFF, 0xC0, 0xFF, 0x0F, 0x0F, 0x00, 0x3C, 0x01, 0x0D, 0x05, 0x3C,
+ 0x00, 0xD7, 0x00, 0xD7, 0xC0, 0xD7, 0xC0, 0xD7, 0xC0, 0xD7, 0xC0, 0xD7, 0xC0, 0xD7, 0xC0, 0xD7,
+ 0xC0, 0xD7, 0xC0, 0xD7, 0xC0, 0x3F, 0xC0, 0x0F, 0x00, 0x02, 0x0D, 0x0D, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0xD5, 0x55, 0x5C, 0x00,
+ 0xD7, 0xD7, 0xD7, 0x00, 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0xD7, 0xD7, 0xC0,
+ 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0xD7, 0xD7, 0xC0, 0x3F, 0xFF, 0xFF, 0xC0, 0x0F, 0x0F, 0x0F, 0x00,
+ 0x02, 0x0D, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F,
+ 0xF0, 0x00, 0x0F, 0xD5, 0x5C, 0x00, 0x35, 0xD7, 0xD7, 0x00, 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0xD7,
+ 0xD7, 0xC0, 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0xD7, 0xD7, 0xC0, 0x35, 0x3F,
+ 0xFF, 0xC0, 0x0F, 0x0F, 0x0F, 0x00, 0x03, 0x02, 0x0D, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x3F, 0x35, 0x5C, 0x00, 0xD5, 0xD7, 0xD7,
+ 0x00, 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0xD7, 0xD7,
+ 0xC0, 0xD7, 0x35, 0x5F, 0xC0, 0xD5, 0x0F, 0xFF, 0x00, 0xD7, 0x03, 0xFC, 0x00, 0xD7, 0x02, 0x10,
+ 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF0, 0x00,
+ 0x0F, 0xD5, 0x5C, 0x00, 0x35, 0xD7, 0xD7, 0x00, 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0xD7, 0xD7, 0xC0,
+ 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0xD5, 0x5F, 0xC0, 0x35, 0xD7, 0xFF, 0x00,
+ 0x0F, 0xD7, 0xFC, 0x00, 0x03, 0xD7, 0xC0, 0x00, 0x00, 0x3F, 0xC0, 0x00, 0x00, 0x0F, 0x00, 0x00,
+ 0x00, 0x02, 0x10, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0F, 0xFC, 0x00, 0x3F, 0x35, 0x57, 0x00, 0xD5, 0xD7, 0xD7, 0xC0, 0xD5, 0xD7, 0xD7, 0xC0, 0xD7,
+ 0xD7, 0xD7, 0xC0, 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0x35, 0x57, 0xC0, 0xD7,
+ 0x0F, 0xD7, 0xC0, 0x3F, 0x03, 0xD7, 0xC0, 0x0F, 0x00, 0xD7, 0xC0, 0x00, 0x00, 0x3F, 0xC0, 0x00,
+ 0x00, 0x0F, 0x00, 0x00, 0x01, 0x0D, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xC0, 0xD5,
+ 0x70, 0xD5, 0xFC, 0xD7, 0xF0, 0xD7, 0xC0, 0xD7, 0xC0, 0xD7, 0xC0, 0xD7, 0xC0, 0x3F, 0xC0, 0x0F,
+ 0x00, 0x02, 0x0D, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0xD7,
+ 0x0F, 0xF0, 0x00, 0xD7, 0x35, 0x5C, 0x03, 0x55, 0xD7, 0xD7, 0x00, 0xD7, 0xD7, 0xFF, 0xC0, 0xD7,
+ 0x35, 0x5F, 0x00, 0xD7, 0x3F, 0xD7, 0x00, 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0x35, 0x5F, 0xC0, 0x35,
+ 0x0F, 0xFF, 0x00, 0x0F, 0x03, 0xFC, 0x00, 0x03, 0x01, 0x0D, 0x07, 0x00, 0x00, 0x0F, 0x00, 0x35,
+ 0xC0, 0x35, 0xF0, 0xD5, 0x70, 0x35, 0xFC, 0x35, 0xF0, 0x35, 0xF0, 0x35, 0xF0, 0x35, 0xF0, 0x0D,
+ 0x70, 0x03, 0xFC, 0x00, 0xF0, 0x02, 0x0D, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x3C, 0x3C, 0x00, 0xF0, 0xD7, 0xD7, 0x03, 0x5C, 0xD7, 0xD7, 0xC3, 0x5F,
+ 0xD7, 0xD7, 0xC0, 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0xD7, 0xD7, 0xC0, 0x35, 0xD7, 0xD7, 0xC0, 0x0D,
+ 0x35, 0x57, 0xC0, 0x0D, 0x0F, 0xFF, 0xC0, 0x03, 0x03, 0xFF, 0x00, 0x00, 0x02, 0x0D, 0x0B, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x03, 0xC0, 0x3C, 0xD7,
+ 0x0D, 0x70, 0xD7, 0xD7, 0xCD, 0x7C, 0xD7, 0x35, 0xF5, 0xFC, 0x35, 0x35, 0xF5, 0xF0, 0x35, 0x0D,
+ 0x57, 0xF0, 0x35, 0x03, 0x5F, 0xC0, 0x0D, 0x03, 0x5F, 0x00, 0x0D, 0x00, 0xFF, 0x00, 0x03, 0x00,
+ 0x3C, 0x00, 0x00, 0x02, 0x0D, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3C, 0x00, 0x3C, 0x03, 0xD7, 0x3C, 0xD7, 0x0D, 0xD7, 0xD7, 0xD7, 0xC3, 0x35, 0xD7,
+ 0x5F, 0xC0, 0x35, 0xD7, 0x5F, 0x00, 0x35, 0x55, 0x5F, 0x00, 0x0D, 0x7D, 0x7F, 0x03, 0x0D, 0x7D,
+ 0x7C, 0x0D, 0x03, 0xFF, 0xFC, 0x03, 0x00, 0xF0, 0xF0, 0x00, 0x02, 0x0D, 0x0B, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x03, 0xC0, 0x3C, 0xD7, 0x0D, 0x70,
+ 0xD7, 0x35, 0xF5, 0xFC, 0xD7, 0x0D, 0x57, 0xF0, 0x35, 0x03, 0x5F, 0xC0, 0x35, 0x0D, 0x57, 0x00,
+ 0x0D, 0x35, 0xF5, 0xC0, 0x0D, 0xD7, 0xFD, 0x70, 0x03, 0x3F, 0xC3, 0xFC, 0x03, 0x0F, 0x00, 0xF0,
+ 0x0D, 0x02, 0x10, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x3C, 0x03, 0xC0, 0x0F, 0xD7, 0x0D, 0x70, 0x35, 0xD7, 0xCD, 0x7C, 0x0F, 0x35, 0xF5, 0xFC, 0x03,
+ 0x35, 0xF5, 0xF0, 0x03, 0x0D, 0x57, 0xF0, 0x0D, 0x0D, 0x57, 0xC0, 0x35, 0x03, 0x5F, 0xC0, 0x35,
+ 0x03, 0x5F, 0x00, 0x0F, 0x0D, 0x7F, 0x00, 0x03, 0x35, 0xFC, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00,
+ 0x03, 0xC0, 0x00, 0x00, 0x02, 0x0D, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x3F, 0xFC, 0x00, 0x00, 0xD5, 0x57, 0x00, 0x00, 0x3F, 0xD7, 0xC0, 0x00, 0x0F,
+ 0x5F, 0xC0, 0x00, 0x0D, 0x7F, 0x00, 0x00, 0x35, 0xFC, 0x00, 0x00, 0xD7, 0xFC, 0x00, 0x00, 0xD5,
+ 0x57, 0x00, 0x00, 0x3F, 0xFF, 0xC0, 0x00, 0x0F, 0xFF, 0x00, 0x00, 0x01, 0x0E, 0x07, 0x00, 0x00,
+ 0x03, 0xC0, 0x0D, 0x70, 0x37, 0xFC, 0x37, 0xF0, 0x37, 0xC0, 0xDF, 0xC0, 0xDF, 0x00, 0x37, 0x00,
+ 0x37, 0xC0, 0x37, 0xC0, 0x0D, 0x70, 0x03, 0xFC, 0x00, 0xF0, 0x01, 0x0F, 0x04, 0x30, 0x00, 0xDC,
+ 0x0F, 0xDF, 0x35, 0xDF, 0x0F, 0xDF, 0x03, 0xDF, 0x03, 0xDF, 0x00, 0xDF, 0x00, 0xDF, 0x03, 0xDF,
+ 0x03, 0xDF, 0x0F, 0xDF, 0x35, 0xDF, 0x0F, 0x3F, 0x03, 0x0C, 0x00, 0x01, 0x0E, 0x07, 0x00, 0x00,
+ 0x3C, 0x00, 0xD7, 0x00, 0x3D, 0xC0, 0x0D, 0xF0, 0x0D, 0xF0, 0x03, 0x70, 0x03, 0x7C, 0x0D, 0xFC,
+ 0x0D, 0xF0, 0x3D, 0xF0, 0xD7, 0xF0, 0x3F, 0xC0, 0x0F, 0x00, 0x02, 0x08, 0x0A, 0x00, 0x00, 0x00,
+ 0xC0, 0x00, 0x00, 0x03, 0x70, 0x0F, 0x00, 0x03, 0x70, 0x35, 0xC3, 0x00, 0xC0, 0xDF, 0x7D, 0xC0,
+ 0x00, 0x3F, 0xD7, 0xF0, 0x00, 0x0C, 0x3F, 0xC0, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x01, 0x04, 0x03,
+ 0x30, 0x00, 0xDC, 0x00, 0xDC, 0x00, 0x30, 0x00, 0x02, 0x10, 0x0A, 0x03, 0xFC, 0x00, 0x00, 0x0D,
+ 0x57, 0x00, 0x00, 0x35, 0xF5, 0xC0, 0x00, 0xD7, 0xFD, 0xF0, 0x00, 0xD7, 0xC3, 0xF0, 0x00, 0xD7,
+ 0xC0, 0xC0, 0x00, 0xD7, 0xC0, 0x00, 0x00, 0xD7, 0xC3, 0x00, 0x00, 0xD7, 0xCD, 0xC0, 0x00, 0x35,
+ 0xF5, 0xF0, 0x00, 0x0D, 0x57, 0xF0, 0x00, 0x03, 0x7F, 0xC0, 0x00, 0x03, 0xDF, 0x00, 0x00, 0x01,
+ 0xDF, 0x00, 0x00, 0x03, 0x7C, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x02, 0x0D, 0x09, 0x0C, 0x0C,
+ 0x00, 0x00, 0x37, 0x37, 0x00, 0x00, 0xD7, 0xD7, 0xC0, 0x03, 0x3F, 0xFF, 0xC0, 0x00, 0x3F, 0x3F,
+ 0x00, 0x03, 0xD7, 0xD7, 0x00, 0x0D, 0xD7, 0xD7, 0xC0, 0x35, 0xD7, 0xD7, 0xC0, 0x35, 0xD7, 0xD7,
+ 0xC0, 0x35, 0xD7, 0xD7, 0xC0, 0x35, 0x35, 0x57, 0xC0, 0x0D, 0x0F, 0xFF, 0xC0, 0x03, 0x03, 0xFF,
+ 0x00, 0x00, 0x02, 0x0D, 0x09, 0x00, 0x30, 0x00, 0x03, 0x03, 0xDC, 0x00, 0x0D, 0x0D, 0x7F, 0x00,
+ 0x37, 0x03, 0xFC, 0x00, 0x0F, 0x0F, 0xF0, 0x00, 0x0F, 0x35, 0x5C, 0x00, 0x35, 0xD7, 0xD7, 0x00,
+ 0xD7, 0xD5, 0x57, 0xC0, 0x3D, 0xD7, 0xFF, 0xC0, 0x35, 0xD7, 0xD7, 0x00, 0xD7, 0x35, 0x5F, 0xC0,
+ 0x35, 0x0F, 0xFF, 0x00, 0x0F, 0x03, 0xFC, 0x00, 0x03, 0x02, 0x0D, 0x09, 0x03, 0xC0, 0x00, 0x03,
+ 0x0D, 0x70, 0x00, 0x0D, 0x37, 0xDC, 0x00, 0x35, 0x0F, 0xFF, 0x00, 0x0F, 0x0F, 0xFC, 0x00, 0x03,
+ 0x35, 0x5C, 0x00, 0x0D, 0xD7, 0xD7, 0x00, 0x35, 0x3D, 0x57, 0xC0, 0x0F, 0x35, 0xD7, 0xC0, 0x0D,
+ 0xD7, 0xD7, 0xC0, 0x35, 0x35, 0x57, 0xC0, 0x0D, 0x0F, 0xFF, 0xC0, 0x03, 0x03, 0xFF, 0x00, 0x00,
+ 0x02, 0x0D, 0x09, 0x0C, 0x0C, 0x00, 0x0C, 0x37, 0x37, 0x00, 0x37, 0xD7, 0xD7, 0xC0, 0x0D, 0x3F,
+ 0xFF, 0xC0, 0x03, 0x0F, 0xFF, 0x00, 0x3F, 0x35, 0x5C, 0x00, 0xD5, 0xD7, 0xD7, 0x03, 0x5F, 0x3D,
+ 0x57, 0xC0, 0xF5, 0x35, 0xD7, 0xC0, 0xD7, 0xD7, 0xD7, 0xC3, 0x5F, 0x35, 0x57, 0xC0, 0xD5, 0x0F,
+ 0xFF, 0xC0, 0x3F, 0x03, 0xFF, 0x00, 0x0F, 0x02, 0x0D, 0x09, 0x03, 0x00, 0x00, 0x00, 0x0D, 0xF0,
+ 0x00, 0x03, 0x03, 0x5C, 0x00, 0x0D, 0x00, 0xFF, 0x00, 0x03, 0x0F, 0xF0, 0x00, 0x0F, 0x35, 0x5C,
+ 0x00, 0x35, 0xD7, 0xD7, 0x00, 0xD7, 0x3D, 0x57, 0xC0, 0x3D, 0x35, 0xD7, 0xC0, 0x35, 0xD7, 0xD7,
+ 0xC0, 0xD7, 0x35, 0x57, 0xC0, 0x35, 0x0F, 0xFF, 0xC0, 0x0F, 0x03, 0xFF, 0x00, 0x03, 0x02, 0x0D,
+ 0x09, 0x00, 0xC0, 0x00, 0x00, 0x03, 0x70, 0x00, 0x00, 0x0D, 0xDC, 0x00, 0x00, 0x03, 0x7F, 0x00,
+ 0x03, 0x0F, 0xFC, 0x00, 0x0D, 0x35, 0x5C, 0x00, 0x35, 0xD7, 0xD7, 0x00, 0x35, 0x3D, 0x57, 0xC0,
+ 0x35, 0x35, 0xD7, 0xC0, 0x35, 0xD7, 0xD7, 0xC0, 0x35, 0x35, 0x57, 0xC0, 0x0D, 0x0F, 0xFF, 0xC0,
+ 0x03, 0x03, 0xFF, 0x00, 0x03, 0x02, 0x10, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
+ 0x00, 0x00, 0x00, 0x0D, 0x0F, 0xF0, 0x00, 0x03, 0x35, 0x5C, 0x00, 0x03, 0xD7, 0xD7, 0x00, 0x0D,
+ 0xD7, 0xFF, 0xC0, 0x35, 0xD7, 0xCF, 0x00, 0x35, 0xD7, 0xFC, 0x00, 0x35, 0xD7, 0xD7, 0x00, 0x35,
+ 0x35, 0x5F, 0xC0, 0x0D, 0x0D, 0xFF, 0x00, 0x03, 0x0F, 0x7C, 0x00, 0x00, 0x07, 0x7C, 0x00, 0x00,
+ 0x0D, 0xF0, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00, 0x02, 0x0D, 0x09, 0x03, 0xC0, 0x00, 0x0C, 0x0D,
+ 0x70, 0x00, 0x37, 0x37, 0xDC, 0x00, 0xD7, 0x0F, 0xFF, 0x00, 0x3F, 0x0F, 0xFC, 0x00, 0x0F, 0x35,
+ 0x5C, 0x00, 0x35, 0xD7, 0xD7, 0x00, 0xD7, 0xD5, 0x57, 0xC0, 0xD5, 0xD7, 0xFF, 0xC0, 0xD7, 0xD7,
+ 0xD7, 0x00, 0xD7, 0x35, 0x5F, 0xC0, 0x35, 0x0F, 0xFF, 0x00, 0x0F, 0x03, 0xFC, 0x00, 0x03, 0x02,
+ 0x0D, 0x09, 0x0C, 0x0C, 0x00, 0x03, 0x37, 0x37, 0x00, 0x0D, 0xD7, 0xD7, 0xC0, 0x03, 0x3F, 0xFF,
+ 0xC0, 0x00, 0x0F, 0xFF, 0x00, 0x03, 0x35, 0x5C, 0x00, 0x0D, 0xD7, 0xD7, 0x00, 0x35, 0xD5, 0x57,
+ 0xC0, 0x35, 0xD7, 0xFF, 0xC0, 0x35, 0xD7, 0xD7, 0x00, 0x35, 0x35, 0x5F, 0xC0, 0x0D, 0x0F, 0xFF,
+ 0x00, 0x03, 0x03, 0xFC, 0x00, 0x00, 0x02, 0x0D, 0x09, 0x0C, 0x00, 0x00, 0x03, 0x37, 0xC0, 0x00,
+ 0x0D, 0x0D, 0x70, 0x00, 0x35, 0x03, 0xFC, 0x00, 0x0F, 0x0F, 0xF0, 0x00, 0x03, 0x35, 0x5C, 0x00,
+ 0x03, 0xD7, 0xD7, 0x00, 0x03, 0xD5, 0x57, 0xC0, 0x03, 0xD7, 0xFF, 0xC0, 0x03, 0xD7, 0xD7, 0x00,
+ 0x03, 0x35, 0x5F, 0xC0, 0x03, 0x0F, 0xFF, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x02, 0x0D, 0x09,
+ 0x0C, 0x0C, 0x00, 0x03, 0x37, 0x37, 0x00, 0x0D, 0xD7, 0xD7, 0xC0, 0x37, 0x3F, 0xFF, 0xC0, 0x0F,
+ 0x0F, 0xCF, 0x00, 0x0F, 0x0D, 0x70, 0x00, 0x0D, 0x0D, 0x7C, 0x00, 0x0D, 0x0D, 0x7C, 0x00, 0x0D,
+ 0x0D, 0x7C, 0x00, 0x0D, 0x0D, 0x7C, 0x00, 0x0D, 0x0D, 0x7C, 0x00, 0x0D, 0x03, 0xFC, 0x00, 0x03,
+ 0x00, 0xF0, 0x00, 0x00, 0x01, 0x0D, 0x07, 0x0F, 0x00, 0x35, 0xC0, 0xDF, 0x70, 0x3F, 0xFC, 0x3F,
+ 0x30, 0x35, 0xC0, 0x35, 0xF0, 0x35, 0xF0, 0x35, 0xF0, 0x35, 0xF0, 0x35, 0xF0, 0x0F, 0xF0, 0x03,
+ 0xC0, 0x01, 0x0D, 0x06, 0x30, 0x00, 0xDF, 0x00, 0x35, 0xC0, 0x0F, 0xF0, 0x3C, 0x00, 0xD7, 0x00,
+ 0xD7, 0xC0, 0xD7, 0xC0, 0xD7, 0xC0, 0xD7, 0xC0, 0xD7, 0xC0, 0x3F, 0xC0, 0x0F, 0x00, 0x02, 0x0F,
+ 0x0F, 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x37, 0x37, 0x00, 0x00, 0xD7, 0xD7, 0xC0, 0x00, 0x3F, 0xFF,
+ 0xC0, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0xD5, 0x57, 0xF0, 0x00, 0xDF, 0x57, 0xC0, 0x00, 0xDF, 0x77,
+ 0xC0, 0x00, 0x3D, 0x57, 0xC0, 0x30, 0x0D, 0xF7, 0xC0, 0xDC, 0xF7, 0xF7, 0x70, 0xD7, 0x5F, 0xF5,
+ 0x7C, 0x3D, 0xFF, 0x0F, 0xFC, 0x0F, 0xFC, 0x03, 0xF0, 0x00, 0xC0, 0x00, 0x00, 0x01, 0x04, 0x03,
+ 0x30, 0x00, 0xDC, 0x00, 0xDC, 0x00, 0x30, 0x00, 0x01, 0x04, 0x03, 0x30, 0x00, 0xDC, 0x00, 0xDC,
+ 0x00, 0x30, 0x0F, 0x02, 0x0D, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x0F, 0xF0, 0x3F, 0xC0, 0x35, 0x5C, 0xD5, 0x70, 0xD7, 0xD7, 0x5F, 0x5C, 0x3D, 0x57,
+ 0x55, 0x5F, 0x35, 0xD7, 0x5F, 0xFF, 0xD7, 0xD7, 0x5F, 0xFC, 0xD7, 0xD7, 0x5F, 0x5C, 0x35, 0x55,
+ 0x55, 0x7F, 0x0F, 0xFF, 0xFF, 0xFC, 0x03, 0xFF, 0xFF, 0xF0, 0x01, 0x04, 0x03, 0x30, 0x00, 0xDC,
+ 0x03, 0xDC, 0x0D, 0x30, 0x03, 0x02, 0x0D, 0x09, 0x03, 0xC0, 0x00, 0x30, 0x0D, 0x70, 0x00, 0xDC,
+ 0x37, 0xDC, 0x03, 0x5F, 0x0F, 0xFF, 0x00, 0xFF, 0x0F, 0xFC, 0x00, 0x3F, 0x35, 0x5C, 0x00, 0xD5,
+ 0xD7, 0xD7, 0x03, 0x5F, 0xD7, 0xD7, 0xC3, 0x5F, 0xD7, 0xD7, 0xC3, 0x5F, 0xD7, 0xD7, 0xC3, 0x5F,
+ 0x35, 0x5F, 0xC0, 0xD5, 0x0F, 0xFF, 0x00, 0x3F, 0x03, 0xFC, 0x00, 0x0F, 0x02, 0x0D, 0x09, 0x0C,
+ 0x0C, 0x00, 0x0C, 0x37, 0x37, 0x00, 0x37, 0xD7, 0xD7, 0xC0, 0x0D, 0x3F, 0xFF, 0xC0, 0x03, 0x0F,
+ 0xFF, 0x00, 0x0F, 0x35, 0x5C, 0x00, 0x35, 0xD7, 0xD7, 0x00, 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0xD7,
+ 0xD7, 0xC0, 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0x35, 0x5F, 0xC0, 0x35, 0x0F, 0xFF, 0x00, 0x0F, 0x03,
+ 0xFC, 0x00, 0x03, 0x02, 0x0D, 0x09, 0x0C, 0x00, 0x00, 0x03, 0x37, 0xC0, 0x00, 0x0D, 0x0D, 0x70,
+ 0x00, 0x37, 0x03, 0xFC, 0x00, 0x0F, 0x0F, 0xF0, 0x00, 0x3F, 0x35, 0x5C, 0x00, 0xD7, 0xD7, 0xD7,
+ 0x00, 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0x35, 0x5F,
+ 0xC0, 0x35, 0x0F, 0xFF, 0x00, 0x0F, 0x03, 0xFC, 0x00, 0x03, 0x02, 0x0D, 0x09, 0x03, 0xC0, 0x00,
+ 0x0C, 0x0D, 0x70, 0x00, 0x37, 0x37, 0xDC, 0x00, 0x0D, 0x0F, 0xFF, 0x00, 0x03, 0x3F, 0x3C, 0x00,
+ 0x3C, 0xD7, 0xD7, 0x00, 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0xD7, 0xD7, 0xC0,
+ 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0x35, 0x57, 0xC0, 0x35, 0x0F, 0xFF, 0xC0, 0x0F, 0x03, 0xFF, 0x00,
+ 0x03, 0x02, 0x0D, 0x09, 0x0C, 0x00, 0x00, 0x03, 0x37, 0xC0, 0x00, 0x0D, 0x0D, 0x70, 0x00, 0x0D,
+ 0x03, 0xFC, 0x00, 0x03, 0x3C, 0x3C, 0x00, 0x00, 0xD7, 0xD7, 0x00, 0x00, 0xD7, 0xD7, 0xC0, 0x00,
+ 0xD7, 0xD7, 0xC0, 0x00, 0xD7, 0xD7, 0xC0, 0x00, 0xD7, 0xD7, 0xC0, 0x00, 0x35, 0x57, 0xC0, 0x00,
+ 0x0F, 0xFF, 0xC0, 0x00, 0x03, 0xFF, 0x00, 0x00, 0x01, 0x04, 0x03, 0x30, 0x30, 0xDC, 0xDC, 0xDC,
+ 0xDC, 0x30, 0x30, 0x01, 0x04, 0x03, 0x30, 0x30, 0xDC, 0xDC, 0xDC, 0xDC, 0x30, 0x30, 0x01, 0x04,
+ 0x03, 0x30, 0x30, 0xDC, 0xDC, 0xDC, 0xDC, 0x30, 0x30, 0x01, 0x04, 0x03, 0x30, 0x00, 0xDC, 0x03,
+ 0xDC, 0x03, 0x30, 0x00, 0x01, 0x04, 0x03, 0x30, 0x30, 0xDC, 0xDC, 0xDC, 0xDC, 0x30, 0x30, 0x01,
+ 0x04, 0x03, 0x30, 0x30, 0xDC, 0xDC, 0xDC, 0xDC, 0x30, 0x30, 0x01, 0x04, 0x03, 0x30, 0x30, 0xDC,
+ 0xDC, 0xDC, 0xDC, 0x30, 0x30, 0x01, 0x04, 0x03, 0x30, 0x00, 0xDC, 0x00, 0xDC, 0x00, 0x30, 0x00,
+ 0x02, 0x0D, 0x09, 0x00, 0x30, 0x00, 0x03, 0x03, 0xDC, 0x00, 0x3D, 0x0D, 0x7F, 0x00, 0xD7, 0x03,
+ 0xFC, 0x00, 0x3F, 0x0F, 0xF0, 0x00, 0x3C, 0x35, 0x5C, 0x00, 0xD7, 0xD7, 0xD7, 0x00, 0xD7, 0x3D,
+ 0x57, 0xC0, 0xD7, 0x35, 0xD7, 0xC0, 0xD7, 0xD7, 0xD7, 0xC0, 0xD7, 0x35, 0x57, 0xC0, 0xD7, 0x0F,
+ 0xFF, 0xC0, 0x3F, 0x03, 0xFF, 0x00, 0x0F, 0x01, 0x0D, 0x06, 0x03, 0x00, 0x3D, 0xC0, 0xD7, 0xF0,
+ 0x3F, 0xC0, 0x3C, 0x00, 0xD7, 0x00, 0xD7, 0xC0, 0xD7, 0xC0, 0xD7, 0xC0, 0xD7, 0xC0, 0xD7, 0xC0,
+ 0x3F, 0xC0, 0x0F, 0x00, 0x02, 0x0D, 0x09, 0x00, 0x30, 0x00, 0x00, 0x03, 0xDC, 0x00, 0x0F, 0x0D,
+ 0x7F, 0x00, 0x35, 0x03, 0xFC, 0x00, 0x0F, 0x0F, 0xF0, 0x00, 0xF0, 0x35, 0x5C, 0x03, 0x5F, 0xD7,
+ 0xD7, 0x03, 0x5F, 0xD7, 0xD7, 0xC3, 0x5F, 0xD7, 0xD7, 0xC3, 0x5F, 0xD7, 0xD7, 0xC3, 0x5F, 0x35,
+ 0x5F, 0xC0, 0xD5, 0x0F, 0xFF, 0x00, 0x3F, 0x03, 0xFC, 0x00, 0x0F, 0x02, 0x0D, 0x09, 0x00, 0x30,
+ 0x00, 0x03, 0x03, 0xDC, 0x00, 0x0D, 0x0D, 0x7F, 0x00, 0x37, 0x03, 0xFC, 0x00, 0x0F, 0x3C, 0x3C,
+ 0x00, 0x0F, 0xD7, 0xD7, 0x00, 0x35, 0xD7, 0xD7, 0xC0, 0x35, 0xD7, 0xD7, 0xC0, 0x35, 0xD7, 0xD7,
+ 0xC0, 0x35, 0xD7, 0xD7, 0xC0, 0x35, 0x35, 0x57, 0xC0, 0x35, 0x0F, 0xFF, 0xC0, 0x0F, 0x03, 0xFF,
+ 0x00, 0x03, 0x02, 0x0D, 0x09, 0x0F, 0x0C, 0x00, 0x00, 0x35, 0xF7, 0x00, 0x00, 0xDF, 0x5F, 0xC0,
+ 0x00, 0x3F, 0xFF, 0x00, 0x00, 0x3F, 0xFC, 0x00, 0x00, 0xD5, 0x5C, 0x00, 0x00, 0xD7, 0xD7, 0x00,
+ 0x00, 0xD7, 0xD7, 0xC0, 0x00, 0xD7, 0xD7, 0xC0, 0x00, 0xD7, 0xD7, 0xC0, 0x00, 0xD7, 0xD7, 0xC0,
+ 0x00, 0x3F, 0xFF, 0xC0, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x01, 0x04, 0x03, 0x30, 0x30, 0xDC, 0xDC,
+ 0xDC, 0xDC, 0x30, 0x30, 0x01, 0x04, 0x03, 0x30, 0x30, 0xDC, 0xDC, 0xDC, 0xDC, 0x30, 0x30, 0x01,
+ 0x04, 0x03, 0x30, 0x00, 0xDC, 0x00, 0xDC, 0x00, 0x30, 0x00, 0x02, 0x0D, 0x09, 0x03, 0xC0, 0x00,
+ 0x00, 0x0D, 0x70, 0x00, 0x00, 0x0D, 0x7C, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x00, 0x0D, 0x70, 0x00,
+ 0x00, 0x0D, 0x7C, 0x00, 0x00, 0x35, 0xFC, 0x00, 0x00, 0xD7, 0xFC, 0x00, 0x00, 0xD7, 0xD7, 0x00,
+ 0x00, 0xD7, 0xD7, 0xC0, 0x00, 0x35, 0x5F, 0xC0, 0x00, 0x0F, 0xFF, 0x00, 0x00, 0x03, 0xFC, 0x00,
+ 0x00, 0x01, 0x04, 0x03, 0x30, 0x30, 0xDC, 0xDC, 0xDC, 0xDC, 0x30, 0x30, 0x01, 0x04, 0x03, 0x30,
+ 0x30, 0xDC, 0xDC, 0xDC, 0xDC, 0x30, 0x30, 0x01, 0x04, 0x03, 0x30, 0x30, 0xDC, 0xDC, 0xDC, 0xDC,
+ 0x30, 0x30, 0x01, 0x04, 0x03, 0x30, 0x00, 0xDC, 0x00, 0xDC, 0x00, 0x30, 0x00, 0x01, 0x0F, 0x06,
+ 0x00, 0x00, 0x03, 0x00, 0x0D, 0xC0, 0x35, 0xF0, 0x37, 0xF0, 0x0F, 0xC0, 0x0D, 0xC0, 0x35, 0xF0,
+ 0x35, 0xF0, 0x35, 0xF0, 0x35, 0xF0, 0xD5, 0xF0, 0xD7, 0xF0, 0x3F, 0xC0, 0x0F, 0x00, 0x02, 0x0F,
+ 0x0C, 0x0F, 0xFF, 0xC0, 0x00, 0x35, 0x55, 0x70, 0x00, 0xD7, 0xDF, 0x5C, 0x00, 0xDF, 0x5F, 0x5F,
+ 0x00, 0x3F, 0x5F, 0x5F, 0x00, 0x0F, 0x5D, 0x7F, 0x00, 0x03, 0x5D, 0x5C, 0x00, 0x03, 0x5F, 0x5F,
+ 0x00, 0x0D, 0x57, 0x5F, 0x00, 0x0D, 0x75, 0x7F, 0x00, 0x0D, 0x7F, 0xFC, 0x00, 0x0D, 0xFF, 0xF0,
+ 0x00, 0x35, 0xF0, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x03, 0xC0, 0x00, 0x00
+};
+
+} // namespace Touche
diff --git a/engines/touche/touche.cpp b/engines/touche/touche.cpp
new file mode 100644
index 0000000000..0b418b5e6b
--- /dev/null
+++ b/engines/touche/touche.cpp
@@ -0,0 +1,3271 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id: $
+ *
+ */
+
+#include "common/stdafx.h"
+#include "common/config-manager.h"
+#include "common/system.h"
+
+#include "touche/touche.h"
+#include "touche/graphics.h"
+
+namespace Touche {
+
+ToucheEngine::ToucheEngine(OSystem *system, Common::Language language)
+ : Engine(system), _language(language) {
+
+ _talkTextMode = kTalkModeVoiceAndText;
+
+ _saveLoadCurrentPage = 0;
+ _saveLoadCurrentSlot = 0;
+ _hideInventoryTexts = false;
+
+ _screenRect = Common::Rect(640, 400);
+ _roomAreaRect = Common::Rect(640, 352);
+ clearDirtyRects();
+
+ _defaultSoundPriority = 0;
+ _snd_midiContext.unk2 = 0;
+ _snd_midiContext.unkA = 1;
+ _snd_midiContext.unkB = 0;
+ _snd_midiContext.volume = 0;
+ _snd_midiContext.unkF = 0;
+ _snd_midiContext.currentVolume = 175;
+ _playSoundCounter = 0;
+
+ _processRandomPaletteCounter = 0;
+
+ _roomNeedRedraw = false;
+ _fastWalkMode = false;
+
+ _currentObjectNum = -1;
+ _objectDescriptionNum = 0;
+ _speechPlaying = false;
+
+ _roomNeedRedraw = false;
+ _fullRedrawCounter = 0;
+ _redrawScreenCounter1 = 0;
+ memset(_paletteBuffer, 0, sizeof(_paletteBuffer));
+
+ Common::addSpecialDebugLevel(kDebugEngine, "Engine", "Engine debug level");
+ Common::addSpecialDebugLevel(kDebugGraphics, "Graphics", "Graphics debug level");
+ Common::addSpecialDebugLevel(kDebugResource, "Resource", "Resource debug level");
+ Common::addSpecialDebugLevel(kDebugOpcodes, "Opcodes", "Opcodes debug level");
+ Common::addSpecialDebugLevel(kDebugUserIntf, "UserIntf", "UserInterface debug level");
+}
+
+ToucheEngine::~ToucheEngine() {
+ Common::clearAllSpecialDebugLevels();
+}
+
+int ToucheEngine::init() {
+ _system->beginGFXTransaction();
+ initCommonGFX(true);
+ _system->initSize(640, 400);
+ _system->endGFXTransaction();
+
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume"));
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume"));
+ return 0;
+}
+
+int ToucheEngine::go() {
+ res_openDataFile();
+ res_allocateTables();
+ res_loadSpriteImage(18, _menuKitData);
+ res_loadImageHelper(_menuKitData, _currentImageWidth, _currentImageHeight);
+ res_loadSpriteImage(19, _convKitData);
+ res_loadImageHelper(_convKitData, _currentImageWidth, _currentImageHeight);
+
+ mainLoop();
+
+ res_deallocateTables();
+ res_closeDataFile();
+
+ return 0;
+}
+
+void ToucheEngine::restart() {
+ _displayQuitDialog = false;
+
+ memset(_flagsTable, 0, sizeof(_flagsTable));
+
+ _currentKeyCharNum = 0;
+ initKeyChars(-1);
+
+ for (int i = 0; i < NUM_SEQUENCES; ++i) {
+ _sequenceEntryTable[i].sprNum = -1;
+ _sequenceEntryTable[i].seqNum = -1;
+ }
+
+ _disabledInputCounter = 0;
+ _currentCursorObject = 0;
+ setCursor(0);
+
+ _waitingSetKeyCharNum1 = -1;
+ _waitingSetKeyCharNum2 = -1;
+ _waitingSetKeyCharNum3 = -1;
+
+ _currentEpisodeNum = 0;
+ _newEpisodeNum = ConfMan.getInt("boot_param");
+ if (_newEpisodeNum == 0) {
+ _newEpisodeNum = 90;
+ }
+
+ _newMusicNum = 0;
+ _currentMusicNum = 0;
+
+ _newSoundNum = 0;
+ _newSoundDelay = 0;
+ _newSoundPriority = 0;
+
+ _flagsTable[176] = 0;
+ _keyCharsTable[0].money = 25;
+ _currentAmountOfMoney = 0;
+
+ _giveItemToKeyCharNum = 0;
+ _giveItemToObjectNum = 0;
+ _giveItemToCounter = 0;
+
+ clearAreaTable();
+ clearAnimationTable();
+
+ initInventoryObjectsTable();
+ initInventoryLists();
+ drawInventory(0, 1);
+
+ _talkListEnd = 0;
+ _talkListCurrent = 0;
+ _talkTextRectDefined = false;
+ _talkTextDisplayed = false;
+ _talkTextInitialized = false;
+ _skipTalkText = false;
+ _talkTextSpeed = 0;
+ _keyCharTalkCounter = 0;
+ _talkTableLastTalkingKeyChar = -1;
+ _talkTableLastOtherKeyChar = -1;
+ _talkTableLastStringNum = -1;
+ _objectDescriptionNum = 0;
+ memset(_talkTable, 0, sizeof(_talkTable));
+
+ _conversationChoicesUpdated = false;
+ _conversationReplyNum = -1;
+ _conversationEnded = false;
+ _conversationNum = 0;
+ _drawCharacterConversionRepeatCounter = 0;
+ _currentConversation = 0;
+ _disableConversationScript = false;
+ _conversationAreaCleared = false;
+ memset(_conversationChoicesTable, 0, sizeof(_conversationChoicesTable));
+
+ _flagsTable[901] = 1;
+ if (_language == Common::FR_FRA) {
+ _flagsTable[621] = 1;
+ }
+}
+
+void ToucheEngine::mainLoop() {
+ restart();
+ _inp_mousePos.x = 640 / 2;
+ _inp_mousePos.y = 352 / 2;
+ _inp_mouseButtonClicked = false;
+ _inp_mouseButtonPressed = false;
+ _system->warpMouse(_inp_mousePos.x, _inp_mousePos.y);
+ setPalette(0, 255, 0, 0, 0);
+#ifdef NORMAL_GAME_SPEED
+ const int cycleDelay = 1000 / (1193180 / 32768);
+#else
+ const int cycleDelay = 10;
+#endif
+ uint32 frameTimeStamp = _system->getMillis();
+ for (uint32 cycleCounter = 0; _flagsTable[611] == 0; ++cycleCounter) {
+ if ((cycleCounter & 3) == 0) {
+ runCycle();
+ }
+ if ((cycleCounter & 2) == 0) {
+ fadePaletteFromFlags();
+ }
+ int delay = _system->getMillis() - frameTimeStamp;
+ delay = cycleDelay - delay;
+ if (delay < 1) {
+ delay = 1;
+ }
+ _system->delayMillis(delay);
+ frameTimeStamp = _system->getMillis();
+ }
+}
+
+void ToucheEngine::processEvents() {
+ OSystem::Event event;
+ while (_system->pollEvent(event)) {
+ switch (event.type) {
+ case OSystem::EVENT_QUIT:
+ _flagsTable[611] = 1;
+ break;
+ case OSystem::EVENT_KEYDOWN:
+ _flagsTable[600] = event.kbd.keycode;
+ if (event.kbd.keycode == 27) { // ESC
+ if (_displayQuitDialog) {
+ _flagsTable[611] = ui_displayQuitDialog();
+ }
+ }
+ if (event.kbd.keycode == 286) { // F5
+ if (_flagsTable[618] == 0 && !_hideInventoryTexts) {
+ ui_handleOptions(0);
+ }
+ }
+ if (event.kbd.keycode == 290) { // F9
+ _fastWalkMode = true;
+ }
+ if (event.kbd.keycode == 291) { // F10
+ _fastWalkMode = false;
+ }
+ if (event.kbd.ascii == 't') {
+ ++_talkTextMode;
+ if (_talkTextMode == kTalkModeCount) {
+ _talkTextMode = 0;
+ }
+ ui_displayTextMode(-(92 + _talkTextMode));
+ }
+ if (event.kbd.ascii == 'd') {
+ // enable debugging stuff ?
+ _flagsTable[777] = 1;
+ }
+ if (event.kbd.ascii == ' ') {
+ updateKeyCharTalk(2);
+ }
+ break;
+ case OSystem::EVENT_MOUSEMOVE:
+ _inp_mousePos.x = event.mouse.x;
+ _inp_mousePos.y = event.mouse.y;
+ break;
+ case OSystem::EVENT_LBUTTONDOWN:
+ _inp_mousePos.x = event.mouse.x;
+ _inp_mousePos.y = event.mouse.y;
+ _inp_mouseButtonClicked = true;
+ break;
+ case OSystem::EVENT_LBUTTONUP:
+ _inp_mousePos.x = event.mouse.x;
+ _inp_mousePos.y = event.mouse.y;
+ break;
+ case OSystem::EVENT_RBUTTONDOWN:
+ _inp_mousePos.x = event.mouse.x;
+ _inp_mousePos.y = event.mouse.y;
+ _inp_mouseButtonPressed = true;
+ break;
+ case OSystem::EVENT_RBUTTONUP:
+ _inp_mousePos.x = event.mouse.x;
+ _inp_mousePos.y = event.mouse.y;
+ _inp_mouseButtonPressed = false;
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void ToucheEngine::runCycle() {
+ debugC(9, kDebugEngine, "ToucheEngine::runCycle()");
+ if (_flagsTable[290]) {
+ changePaletteRange();
+ }
+ if (_flagsTable[270]) {
+ playSoundInRange();
+ }
+ if (_conversationEnded) {
+ _disabledInputCounter = 0;
+ _fullRedrawCounter = 1;
+ _roomAreaRect.setHeight(352);
+ _hideInventoryTexts = false;
+ _conversationEnded = false;
+ drawInventory(_currentKeyCharNum, 1);
+ }
+ if (_giveItemToCounter == 1) {
+ _fullRedrawCounter = 1;
+ drawInventory(_giveItemToObjectNum, 1);
+ ++_giveItemToCounter;
+ }
+ if (_giveItemToCounter == -1) {
+ _giveItemToCounter = 0;
+ _roomAreaRect.setHeight(320);
+ _keyCharsTable[_giveItemToKeyCharNum].flags &= ~kScriptPaused;
+ }
+ setupNewEpisode();
+ startNewMusic();
+ startNewSound();
+ updateSpeech();
+ handleConversation();
+ if (scrollRoom(_currentKeyCharNum)) {
+ _fullRedrawCounter |= 1;
+ }
+ redrawRoom();
+ clearDirtyRects();
+ processAreaTable();
+ clearAreaTable();
+ updateRoomRegions();
+ if (_flagsTable[612] != 0) {
+ _flagsTable[613] = getRandomNumber(_flagsTable[612]);
+ }
+ processEvents();
+ sortKeyChars();
+ for (int i = 0; i < NUM_KEYCHARS; ++i) {
+ runKeyCharScript(&_keyCharsTable[i]);
+ }
+ if (_roomNeedRedraw) {
+ scrollRoom(_currentKeyCharNum);
+ redrawRoom();
+ _roomNeedRedraw = false;
+ }
+ updateSpeech();
+ for (int i = 0; i < NUM_KEYCHARS; ++i) {
+ waitForKeyCharPosition(i);
+ }
+ redrawBackground();
+ waitForKeyCharsSet();
+ handleMouseInput(0);
+ for (int i = 0; i < NUM_KEYCHARS; ++i) {
+ drawKeyChar(&_keyCharsTable[i]);
+ }
+ processAnimationTable();
+ updateKeyCharTalk(0);
+ updateDirtyScreenAreas();
+ ++_flagsTable[295];
+ ++_flagsTable[296];
+ ++_flagsTable[297];
+ if (_flagsTable[298]) {
+ --_flagsTable[298];
+ }
+ if (_flagsTable[299]) {
+ --_flagsTable[299];
+ }
+}
+
+int16 ToucheEngine::getRandomNumber(int max) {
+ assert(max > 0);
+ return _rnd.getRandomNumber(max - 1);
+}
+
+void ToucheEngine::changePaletteRange() {
+ if (_processRandomPaletteCounter) {
+ --_processRandomPaletteCounter;
+ } else {
+ int scale = _flagsTable[291] + getRandomNumber(_flagsTable[292]);
+ setPalette(0, 240, scale, scale, scale);
+ _processRandomPaletteCounter = _flagsTable[293] + getRandomNumber(_flagsTable[294]);
+ }
+}
+
+void ToucheEngine::playSoundInRange() {
+ if (_playSoundCounter != 0) {
+ --_playSoundCounter;
+ } else {
+ int16 flag = getRandomNumber(_flagsTable[270]);
+ int16 num = _flagsTable[273 + flag];
+ res_loadSound(0, num);
+ _playSoundCounter = _flagsTable[271] + getRandomNumber(_flagsTable[272]);
+ }
+}
+
+void ToucheEngine::resetSortedKeyCharsTable() {
+ for (int i = 0; i < NUM_KEYCHARS; ++i) {
+ _sortedKeyCharsTable[i] = &_keyCharsTable[i];
+ }
+}
+
+void ToucheEngine::setupEpisode(int num) {
+ debugC(9, kDebugEngine, "ToucheEngine::setupEpisode() num=%d", num);
+ res_stopSpeech();
+ resetTalkingVars();
+ res_loadSpeech(-1);
+ _currentObjectNum = -1;
+ if (num != -1) {
+ _updatedRoomAreasTable[0] = 1;
+ clearAreaTable();
+ initKeyChars(-1);
+ for (int i = 200; i < 300; ++i) {
+ _flagsTable[i] = 0;
+ }
+ _flagsTable[291] = 240;
+ _flagsTable[292] = 16;
+ _flagsTable[293] = 0;
+ _flagsTable[294] = 1;
+ _currentEpisodeNum = num;
+ if (_flagsTable[911] != 0) {
+ // load scripts from external data files
+ }
+ debug(0, "Setting up episode %d\n", num);
+ res_loadProgram(num);
+ _disabledInputCounter = 0;
+ }
+ res_decodeProgramData();
+ _roomAreaRect.setHeight(352);
+ _disableConversationScript = false;
+ _hideInventoryTexts = false;
+ _conversationEnded = false;
+ clearRoomArea();
+ drawInventory(_currentKeyCharNum, 1);
+}
+
+void ToucheEngine::setupNewEpisode() {
+ debugC(9, kDebugEngine, "ToucheEngine::setupNewEpisode() _newEpisodeNum=%d", _newEpisodeNum);
+ if (_newEpisodeNum) {
+ if (_newEpisodeNum == 91) {
+ _displayQuitDialog = true;
+ }
+// flushDigitalSounds();
+ setupEpisode(_newEpisodeNum);
+ runCurrentKeyCharScript(1);
+ _newEpisodeNum = 0;
+ resetSortedKeyCharsTable();
+ }
+}
+
+void ToucheEngine::drawKeyChar(KeyChar *key) {
+ debugC(9, kDebugEngine, "ToucheEngine::drawKeyChar()");
+ if (key->num != 0) {
+ Common::Rect r(key->prevBoundingRect);
+ r.extend(key->boundingRect);
+// r.clip(_roomAreaRect);
+// addToDirtyRect(r);
+ }
+}
+
+void ToucheEngine::sortKeyChars() {
+ debugC(9, kDebugEngine, "ToucheEngine::sortKeyChars()");
+ for (int i = 0; i < NUM_KEYCHARS; ++i) {
+ bool hasSwapped = false;
+ for (int j = 0; j < NUM_KEYCHARS - 1; ++j) {
+ KeyChar *key1 = _sortedKeyCharsTable[j];
+ KeyChar *key2 = _sortedKeyCharsTable[j + 1];
+ if (key1->num != 0 && key2->num != 0) {
+ if (key1->zPos > key2->zPos) {
+ SWAP(_sortedKeyCharsTable[j], _sortedKeyCharsTable[j + 1]);
+ hasSwapped = true;
+ } else if (key1->zPos == key2->zPos && key1->yPos > key2->yPos) {
+ SWAP(_sortedKeyCharsTable[j], _sortedKeyCharsTable[j + 1]);
+ hasSwapped = true;
+ }
+ } else if (key1->num != 0) {
+ SWAP(_sortedKeyCharsTable[j], _sortedKeyCharsTable[j + 1]);
+ hasSwapped = true;
+ }
+ }
+ if (!hasSwapped) {
+ break;
+ }
+ }
+}
+
+void ToucheEngine::runKeyCharScript(KeyChar *key) {
+ debugC(9, kDebugEngine, "ToucheEngine::runKeyCharScript() keyChar=%d", key - _keyCharsTable);
+ if (key->scriptDataOffset != 0 && (key->flags & (kScriptStopped | kScriptPaused)) == 0) {
+ int16 scriptParam = key->num - 1;
+ int16 *prevStackDataPtr = _script.stackDataPtr;
+ _script.stackDataPtr = key->scriptStackPtr;
+ uint16 prevDataOffset = _script.dataOffset;
+ _script.dataOffset = key->scriptDataOffset;
+ _script.quitFlag = 0;
+ while (_script.quitFlag == 0) {
+ executeScriptOpcode(scriptParam);
+ }
+ switch (_script.quitFlag) {
+ case 1: // restart
+ key->scriptDataOffset = key->scriptDataStartOffset;
+ key->scriptStackPtr = &key->scriptStackTable[39];
+ break;
+ case 3: // pause
+ key->flags |= kScriptPaused;
+ key->flags &= ~kScriptStopped;
+ key->scriptDataOffset = _script.dataOffset;
+ key->scriptStackPtr = _script.stackDataPtr;
+ break;
+ default: // stop
+ key->flags |= kScriptStopped;
+ key->flags &= ~kScriptPaused;
+ key->scriptDataOffset = 0;
+ break;
+ }
+ _script.dataOffset = prevDataOffset;
+ _script.stackDataPtr = prevStackDataPtr;
+ }
+}
+
+void ToucheEngine::runCurrentKeyCharScript(int mode) {
+ debugC(9, kDebugEngine, "ToucheEngine::runCurrentKeyCharScript() _currentKeyCharNum=%d mode=%d", _currentKeyCharNum, mode);
+ KeyChar *key = &_keyCharsTable[_currentKeyCharNum];
+ if (mode == 1) {
+ _script.dataOffset = 0;
+ _script.stackDataPtr = key->scriptStackPtr;
+ }
+ if (mode != 0) {
+ while (_script.quitFlag == 0) {
+ executeScriptOpcode(0);
+ }
+ if (mode == 1) {
+ centerScreenToKeyChar(_currentKeyCharNum);
+ }
+ if (_script.quitFlag == 3) {
+ key->flags |= kScriptPaused;
+ key->flags &= ~kScriptStopped;
+ key->scriptDataOffset = _script.dataOffset;
+ key->scriptStackPtr = _script.stackDataPtr;
+ }
+ }
+ handleMouseInput(1);
+}
+
+void ToucheEngine::executeScriptOpcode(int16 param) {
+ debugC(9, kDebugEngine, "executeScriptOpcode(%d) offset=%04X", param, _script.dataOffset);
+ _script.keyCharNum = param;
+ _script.opcodeNum = _script.readNextByte();
+ if (_script.opcodeNum < NUM_OPCODES) {
+ OpcodeProc op = _opcodesTable[_script.opcodeNum];
+ if (op) {
+ (this->*op)();
+ return;
+ }
+ }
+ error("Invalid opcode 0x%X", _script.opcodeNum);
+}
+
+void ToucheEngine::initKeyChars(int keyChar) {
+ debugC(9, kDebugEngine, "ToucheEngine::initKeyChars() keyChar=%d", keyChar);
+ int indexStart, indexEnd;
+ if (keyChar == -1) {
+ indexStart = 0;
+ indexEnd = NUM_KEYCHARS;
+ } else {
+ indexStart = keyChar;
+ indexEnd = keyChar + 1;
+ }
+ Common::Rect defaultKeyCharRect(10, 10, 11, 11);
+ for (int i = indexStart; i < indexEnd; ++i) {
+ KeyChar *key = &_keyCharsTable[i];
+ if (keyChar != -1 && key->num != 0) {
+ Area keyCharArea;
+ keyCharArea.r = key->prevBoundingRect;
+ keyCharArea.r.extend(key->boundingRect);
+ keyCharArea.srcX = _flagsTable[614] + keyCharArea.r.left;
+ keyCharArea.srcY = _flagsTable[615] + keyCharArea.r.top;
+ addToAreaTable(&keyCharArea);
+ }
+ key->num = 0;
+ key->strNum = 0;
+ key->textColor = 253;
+ key->currentAnimCounter = 0;
+ key->currentAnimSpeed = 0;
+ key->currentAnim = 0;
+ key->framesListCount = 0;
+ key->currentFrame = 0;
+ key->anim1Start = 0;
+ key->anim1Count = 1;
+ key->anim2Start = 0;
+ key->anim2Count = 1;
+ key->anim3Start = 0;
+ key->anim3Count = 1;
+ key->facingDirection = 0;
+ key->sequenceDataOffset = 0;
+ key->walkDataNum = 0;
+ key->walkPointsList[0] = -1;
+ key->walkPointsListCount = 0;
+ key->delay = 0;
+ key->waitingKeyChar = -1;
+ key->flags = 0;
+ key->scriptDataOffset = 0;
+ key->scriptStackPtr = &key->scriptStackTable[39];
+ key->xPos = 10;
+ // like the original interpreter, don't reset yPos here. Doing so causes
+ // glitches during the introduction for example (talk texts get displayed
+ // at the wrong coordinates).
+ key->boundingRect = defaultKeyCharRect;
+ key->prevBoundingRect = defaultKeyCharRect;
+ }
+}
+
+void ToucheEngine::setKeyCharTextColor(int keyChar, uint16 color) {
+ debugC(9, kDebugEngine, "ToucheEngine::setKeyCharTextColor(%d) color=%d", keyChar, color);
+ assert(keyChar >= 0 && keyChar < NUM_KEYCHARS);
+ _keyCharsTable[keyChar].textColor = color;
+}
+
+void ToucheEngine::waitForKeyCharPosition(int keyChar) {
+ debugC(9, kDebugEngine, "ToucheEngine::waitForKeyCharPosition(%d)", keyChar);
+ KeyChar *key = _sortedKeyCharsTable[keyChar];
+ if (key->num != 0) {
+ key->prevBoundingRect = key->boundingRect;
+ moveKeyChar(_offscreenBuffer, 640, key);
+ key->boundingRect = _moveKeyCharRect;
+ if (key->delay != 0) {
+ --key->delay;
+ if (key->delay == 0) {
+ key->flags &= ~kScriptPaused;
+ }
+ return;
+ }
+ if (key->waitingKeyChar == -1) {
+ return;
+ }
+ KeyChar *nextKey = &_keyCharsTable[key->waitingKeyChar];
+ if (nextKey->currentAnim != key->waitingKeyCharPosTable[0] &&
+ nextKey->pointsDataNum != key->waitingKeyCharPosTable[1] &&
+ nextKey->walkDataNum != key->waitingKeyCharPosTable[2]) {
+ return;
+ }
+ key->flags &= ~kScriptPaused;
+ key->waitingKeyChar = -1;
+ }
+}
+
+void ToucheEngine::setKeyCharBox(int keyChar, int value) {
+ debugC(9, kDebugEngine, "ToucheEngine::setKeyCharBox(%d) value=%d", keyChar, value);
+ assert(keyChar >= 0 && keyChar < NUM_KEYCHARS);
+ KeyChar *key = &_keyCharsTable[keyChar];
+ key->prevPointsDataNum = key->pointsDataNum = value;
+ key->xPosPrev = key->xPos = _programPointsTable[value].x;
+ key->yPosPrev = key->yPos = _programPointsTable[value].y;
+ key->zPosPrev = key->zPos = _programPointsTable[value].z;
+ key->prevWalkDataNum = key->walkDataNum = findWalkDataNum(value, 10000);
+}
+
+void ToucheEngine::setKeyCharFrame(int keyChar, int16 type, int16 value1, int16 value2) {
+ assert(keyChar >= 0 && keyChar < NUM_KEYCHARS);
+ KeyChar *key = &_keyCharsTable[keyChar];
+ switch (type) {
+ case 0:
+ key->anim2Start = value1;
+ key->anim2Count = value2;
+ key->anim3Start = value1;
+ key->anim3Count = value2;
+ break;
+ case 1:
+ if (value2 != 0) {
+ value2 = getRandomNumber(value2);
+ }
+ key->framesList[key->framesListCount] = value1 + value2;
+ ++key->framesListCount;
+ key->framesListCount &= 15;
+ break;
+ case 2:
+ key->anim1Start = value1;
+ key->anim1Count = value2;
+ break;
+ case 3:
+ key->currentAnim = value1;
+ key->currentAnimSpeed = 0;
+ key->currentAnimCounter = 0;
+ break;
+ case 4:
+ key->anim3Start = value1;
+ key->anim3Count = value2;
+ break;
+ }
+}
+
+void ToucheEngine::setKeyCharFacingDirection(int keyChar, int16 dir) {
+ assert(keyChar >= 0 && keyChar < NUM_KEYCHARS);
+ _keyCharsTable[keyChar].facingDirection = dir;
+}
+
+void ToucheEngine::initKeyCharScript(int keyChar, int16 spriteNum, int16 seqDataIndex, int16 seqDataOffs) {
+ assert(keyChar >= 0 && keyChar < NUM_KEYCHARS);
+ KeyChar *key = &_keyCharsTable[keyChar];
+ key->num = keyChar + 1;
+ key->spriteNum = spriteNum;
+ key->sequenceDataIndex = seqDataIndex;
+ key->sequenceDataOffset = seqDataOffs;
+ key->scriptDataStartOffset = findProgramKeyCharScriptOffset(keyChar);
+ key->scriptDataOffset = key->scriptDataStartOffset;
+}
+
+uint16 ToucheEngine::findProgramKeyCharScriptOffset(int keyChar) const {
+ for (uint i = 0; i < _programKeyCharScriptOffsetTable.size(); ++i) {
+ if (_programKeyCharScriptOffsetTable[i].keyChar == keyChar) {
+ return _programKeyCharScriptOffsetTable[i].offset;
+ }
+ }
+ return 0;
+}
+
+bool ToucheEngine::scrollRoom(int keyChar) {
+ if (_flagsTable[616] != 0) {
+ return 0;
+ }
+ KeyChar *key = &_keyCharsTable[keyChar];
+ bool needRedraw = false;
+
+ // vertical scrolling
+ int prevRoomDy = _flagsTable[615];
+ _flagsTable[615] = key->yPos + 32 - 400 / 2;
+ int roomHeight;
+ if (_hideInventoryTexts) {
+ roomHeight = 352;
+ } else {
+ roomHeight = (_flagsTable[606] != 0) ? 400 : 352;
+ _roomAreaRect.setHeight(roomHeight);
+ }
+ _flagsTable[615] = CLIP<int16>(_flagsTable[615], 0, _currentBitmapHeight - roomHeight);
+ if (_flagsTable[615] != prevRoomDy) {
+ needRedraw = true;
+ }
+
+ // horizontal scrolling
+ int prevRoomDx = _flagsTable[614];
+ if (key->xPos > prevRoomDx + 480) {
+ int dx = key->xPos - (prevRoomDx + 480);
+ prevRoomDx += dx;
+ } else if (key->xPos < prevRoomDx + 160) {
+ int dx = prevRoomDx + 160 - key->xPos;
+ prevRoomDx -= dx;
+ if (prevRoomDx < 0) {
+ prevRoomDx = 0;
+ }
+ }
+ prevRoomDx = CLIP<int16>(prevRoomDx, 0, _roomWidth - 640);
+ if (_flagsTable[614] != prevRoomDx) {
+ _flagsTable[614] = prevRoomDx;
+ return true;
+ }
+ if (_screenOffset.x == 0) {
+ return needRedraw;
+ }
+ int scrollDx = _screenOffset.x - _flagsTable[614];
+ if (scrollDx < -4) {
+ scrollDx = -4;
+ } else if (scrollDx > 4) {
+ scrollDx = 4;
+ }
+ _flagsTable[614] += scrollDx;
+
+ if (_screenOffset.x == _flagsTable[614]) {
+ _screenOffset.x = 0;
+ }
+ return true;
+}
+
+void ToucheEngine::drawIcon(int x, int y, int num) {
+ res_loadImage(num, _iconData);
+ Graphics::copyRect(_offscreenBuffer, 640, x, y,
+ _iconData, 58, 0, 0,
+ 58, 42,
+ Graphics::kTransparent);
+}
+
+void ToucheEngine::centerScreenToKeyChar(int keyChar) {
+ assert(keyChar >= 0 && keyChar < NUM_KEYCHARS);
+ KeyChar *key = &_keyCharsTable[keyChar];
+ _flagsTable[614] = key->xPos - 640 / 2;
+ _flagsTable[615] = key->yPos - 400 / 2;
+ _flagsTable[615] = CLIP<int16>(_flagsTable[615], 0, _currentBitmapHeight - 352);
+ scrollRoom(keyChar);
+}
+
+void ToucheEngine::waitForKeyCharsSet() {
+ if (_waitingSetKeyCharNum2 != -1) {
+ KeyChar *key = &_keyCharsTable[_waitingSetKeyCharNum2];
+ if (key->framesListCount == key->currentFrame && key->currentAnim == key->anim2Start) {
+ key = &_keyCharsTable[_waitingSetKeyCharNum1];
+ if (key->framesListCount == key->currentFrame && key->currentAnim == key->anim2Start) {
+ key = &_keyCharsTable[_waitingSetKeyCharNum3];
+ _waitingSetKeyCharNum2 = -1;
+ key->flags &= ~kScriptPaused;
+ }
+ }
+ }
+}
+
+void ToucheEngine::redrawRoom() {
+ if (_currentBitmapWidth == 0 || _currentBitmapHeight == 0) {
+ return;
+ }
+ int w = 640;
+ if (_flagsTable[614] < 0 || _flagsTable[614] > _currentBitmapWidth - w) {
+ error("Invalid room_x_offset = %d (w=%d, room_w=%d)", _flagsTable[614], w, _currentBitmapWidth);
+ }
+ int h = (_flagsTable[606] != 0) ? 400 : _roomAreaRect.height();
+ if (_flagsTable[615] < 0 || _flagsTable[615] > _currentBitmapHeight - h) {
+ error("Invalid room_y_offset = %d (h=%d, room_h=%d)", _flagsTable[615], h, _currentBitmapHeight);
+ }
+ uint8 *dst = _offscreenBuffer;
+ const uint8 *src = _backdropBuffer + _flagsTable[615] * _currentBitmapWidth + _flagsTable[614];
+ while (h--) {
+ memcpy(dst, src, w);
+ dst += w;
+ src += _currentBitmapWidth;
+ }
+}
+
+void ToucheEngine::fadePalette(int firstColor, int lastColor, int scale, int scaleInc, int fadingStepsCount) {
+ for (int i = 0; i < fadingStepsCount; ++i) {
+ scale += scaleInc;
+ if (scale > 255) {
+ scale = 0;
+ } else if (scale < 0) {
+ scale = 0;
+ }
+ setPalette(firstColor, lastColor, scale, scale, scale);
+ }
+}
+
+void ToucheEngine::fadePaletteFromFlags() {
+ if (_flagsTable[603]) {
+ setPalette(_flagsTable[607], _flagsTable[608], _flagsTable[605], _flagsTable[605], _flagsTable[605]);
+ if (_flagsTable[603] > 0) {
+ if (_flagsTable[605] >= _flagsTable[609]) {
+ _flagsTable[603] = 0;
+ }
+ } else {
+ if (_flagsTable[605] <= _flagsTable[610]) {
+ _flagsTable[603] = 0;
+ }
+ }
+ _flagsTable[605] += _flagsTable[603];
+ if (_flagsTable[605] < 0) {
+ _flagsTable[605] = 0;
+ } else if (_flagsTable[605] > 255) {
+ _flagsTable[605] = 255;
+ }
+ }
+}
+
+static uint8 *getKeyCharFrameData(uint8 *p, uint16 dir1, uint16 dir2, uint16 dir3, uint8 **dst, int16 sequence_num) {
+ uint8 *src;
+ uint16 offs, num1;
+
+ // spriteData
+ // LE16 offset to "sprite copy" data
+ // LE16 offset to 4 * 2 * 10 offsets : "sprite info" offset
+ // LE16 data offset
+ // LE16 ?
+ offs = READ_LE_UINT16(p + sequence_num * 8 + 2);
+ offs = READ_LE_UINT16(p + offs + dir1 * 4); // facing
+ offs = READ_LE_UINT16(p + offs + dir2 * 2); // top/bottom
+ src = p + offs + dir3 * 10; // current frame anim ?
+ *dst = src;
+ // LE16 : if 0x8000 -> offset "sprite copy" data num
+ // LE16 : dx
+ // LE16 : dy
+ // LE16 : dz
+
+ num1 = READ_LE_UINT16(src) & 0x7FFF;
+ offs = READ_LE_UINT16(p + sequence_num * 8 + 0);
+ offs = READ_LE_UINT16(p + offs + num1 * 2);
+ return p + offs;
+ // LE16 : srcX
+ // LE16 : srcY
+ // LE16 : flags (vflip, hflip)
+}
+
+void ToucheEngine::moveKeyChar(uint8 *dst, int dstPitch, KeyChar *key) {
+ int16 keyChar = key->num - 1;
+ int16 walkDataNum = key->walkDataNum;
+ int16 clippingRectNum = 0;
+ if (walkDataNum != -1) {
+ clippingRectNum = _programWalkTable[walkDataNum].clippingRect;
+ }
+ Common::Rect clippingRect(_programRectsTable[clippingRectNum]);
+ clippingRect.translate(-_flagsTable[614], -_flagsTable[615]);
+ if (key->flags & 0x8000) {
+ clippingRect.moveTo(clippingRect.left, 352);
+ }
+ clippingRect.clip(_roomAreaRect);
+ SpriteData *spr = &_spritesTable[key->spriteNum];
+ int x1 = 30000, y1 = 30000;
+ int x2 = -30000, y2 = -30000;
+ int16 keyCharDirection = _flagsTable[266];
+ if (keyCharDirection == 0) {
+ keyCharDirection = key->facingDirection;
+ }
+ int16 facingDirection = keyCharDirection;
+ uint8 *sequenceDataBase = _sequenceDataTable[key->sequenceDataIndex];
+ uint8 *sequenceData = sequenceDataBase;
+
+ uint16 frameDirFlag = READ_LE_UINT16(sequenceData + key->sequenceDataOffset * 8 + 4);
+ if (frameDirFlag) {
+ sequenceData += frameDirFlag & ~1;
+ }
+
+ uint8 *frameData;
+ uint8 *frameDataBase = getKeyCharFrameData(sequenceDataBase, key->currentAnim, facingDirection, key->currentAnimCounter, &frameData, key->sequenceDataOffset);
+ uint16 frameFlag = READ_LE_UINT16(frameData); frameData += 2;
+ uint16 walkDx = READ_LE_UINT16(frameData); frameData += 2;
+ uint16 walkDy = READ_LE_UINT16(frameData); frameData += 2;
+ uint16 walkDz = READ_LE_UINT16(frameData); frameData += 2;
+
+ if (key->currentAnimSpeed <= 0) {
+ key->currentAnimSpeed = READ_LE_UINT16(frameData);
+ }
+ --key->currentAnimSpeed;
+ if (key->currentAnimSpeed <= 0) {
+ ++key->currentAnimCounter;
+ }
+ if (_fastWalkMode) {
+ walkDx *= 2;
+ walkDy *= 2;
+ walkDz *= 2;
+ }
+ updateKeyCharWalkPath(key, walkDx, walkDy, walkDz);
+ int posX = key->xPos;
+ int posY = key->yPos;
+ int posZ = key->zPos;
+ if (frameFlag & 0x8000) {
+ changeKeyCharFrame(key, keyChar);
+ }
+ posX -= _flagsTable[614];
+ posY -= _flagsTable[615];
+ if (posZ == 160) { // draw sprite frames without rescaling
+ while (1) {
+ int dstX = (int16)READ_LE_UINT16(frameDataBase); frameDataBase += 2;
+ if (dstX == 10000) {
+ _moveKeyCharRect = Common::Rect(x1, y1, x2 + spr->w, y2 + spr->h);
+ break;
+ }
+ int dstY = (int16)READ_LE_UINT16(frameDataBase); frameDataBase += 2;
+
+ if (facingDirection == 3) {
+ dstX = -dstX - spr->w;
+ }
+ dstX += posX;
+ dstY += posY;
+ x1 = MIN(dstX, x1);
+ x2 = MAX(dstX, x2);
+ y1 = MIN(dstY, y1);
+ y2 = MAX(dstY, y2);
+
+ int frameDir = READ_LE_UINT16(frameDataBase); frameDataBase += 2;
+// assert((frameDir & 0x4000) == 0); // hflipped
+ bool vflipped = (frameDir & 0x8000) != 0;
+
+ frameDir &= 0xFFF;
+ if (frameDirFlag) {
+ frameDir = READ_LE_UINT16(sequenceData + frameDir * 2);
+ }
+ if (keyChar == 0) {
+ if (_directionsTable[frameDir] <= _flagsTable[176]) {
+ continue;
+ }
+ }
+ if (frameDir == 0x800) {
+ continue;
+ }
+
+ assert(spr->w != 0);
+ int framesPerLine = spr->bitmapWidth / spr->w;
+ assert(framesPerLine != 0);
+ const int srcOffsX = spr->w * (frameDir % framesPerLine);
+ const int srcOffsY = spr->h * (frameDir / framesPerLine);
+
+ Area copyRegion(dstX, dstY, spr->w, spr->h);
+ copyRegion.srcX = 0;
+ copyRegion.srcY = 0;
+ if (!copyRegion.clip(clippingRect)) {
+ continue;
+ }
+
+ if (facingDirection == 3) {
+ vflipped = !vflipped;
+ }
+
+ uint8 *dstCur = dst + copyRegion.r.top * dstPitch + copyRegion.r.left;
+ const int spr_y1 = srcOffsY + copyRegion.srcY;
+ const int spr_x1 = srcOffsX + copyRegion.srcX;
+ const uint8 *srcSpr = spr->ptr + spr_y1 * spr->bitmapWidth + spr_x1;
+ for (int h = 0; h < copyRegion.r.height(); ++h) {
+ for (int w = 0; w < copyRegion.r.width(); ++w) {
+ uint8 color = vflipped ? srcSpr[spr->w - 1 - w] : srcSpr[w];
+ if (color != 0) {
+ dstCur[w] = color;
+ }
+ }
+ srcSpr += spr->bitmapWidth;
+ dstCur += dstPitch;
+ }
+ }
+ } else { // draw sprite frames with rescaling
+ y2 = posY;
+ int clippingRect_x1 = clippingRect.left;
+ int clippingRect_y1 = clippingRect.top;
+ int clippingRect_x2 = clippingRect.right;
+ int clippingRect_y2 = clippingRect.bottom;
+ buildSpriteScalingTable(160, posZ);
+ while (1) {
+ int dstX = (int16)READ_LE_UINT16(frameDataBase); frameDataBase += 2;
+ if (dstX == 10000) {
+ _moveKeyCharRect = Common::Rect(x1, y1, x2 + 1, y2 + 1);
+ break;
+ }
+ int dstY = (int16)READ_LE_UINT16(frameDataBase); frameDataBase += 2;
+
+ int frameDir = READ_LE_UINT16(frameDataBase); frameDataBase += 2;
+// assert((frameDir & 0x4000) == 0); // hflipped
+ bool vflipped = (frameDir & 0x8000) != 0;
+
+ frameDir &= 0xFFF;
+ if (frameDirFlag) {
+ frameDir = READ_LE_UINT16(sequenceData + frameDir * 2);
+ }
+ if (keyChar == 0) {
+ if (_directionsTable[frameDir] <= _flagsTable[176]) {
+ continue;
+ }
+ }
+ if (frameDir == 0x800) {
+ continue;
+ }
+
+ assert(spr->w != 0);
+ int framesPerLine = spr->bitmapWidth / spr->w;
+ assert(framesPerLine != 0);
+ const int srcOffsX = spr->w * (frameDir % framesPerLine);
+ const int srcOffsY = spr->h * (frameDir / framesPerLine);
+ const uint8 *srcSpr = spr->ptr + srcOffsY * spr->bitmapWidth + srcOffsX;
+
+ assert(dstY >= -500 && dstY < 500);
+ int scalingIndex = _spriteScalingIndex[500 + dstY];
+ int16 *yScaledTable = &_spriteScalingTable[scalingIndex];
+ int sprScaledY = posY + scalingIndex - 500;
+ y1 = MIN(y1, sprScaledY);
+
+ if (facingDirection == 3) {
+ dstX = -dstX;
+ }
+ assert(dstX >= -500 && dstX < 500);
+ scalingIndex = _spriteScalingIndex[500 + dstX];
+ int sprScaledX = posX + scalingIndex - 500;
+ int16 *xScaledTable = &_spriteScalingTable[scalingIndex];
+ x1 = MIN(x1, sprScaledX);
+ x2 = MAX(x2, sprScaledX);
+
+ uint8 *dstCur = dst + sprScaledY * dstPitch + sprScaledX;
+
+ uint8 *dstStart = dstCur;
+ int sprStartY = 0;
+ while (1) {
+ int sprCurY = *yScaledTable - dstY; ++yScaledTable;
+ if (sprCurY >= spr->h) {
+ break;
+ }
+ sprStartY = sprCurY - sprStartY;
+ while (sprStartY != 0) {
+ srcSpr += spr->bitmapWidth;
+ --sprStartY;
+ }
+ sprStartY = sprCurY;
+
+ int16 *scalingTable = xScaledTable;
+ int spr_x2 = sprScaledX;
+ dstCur = dstStart;
+ if (sprScaledY < clippingRect_y1 || sprScaledY >= clippingRect_y2) {
+ continue;
+ }
+ if (facingDirection != 3) {
+ while (1) {
+ int spr_x1 = *scalingTable - dstX; ++scalingTable;
+ if (spr_x1 >= spr->w || spr_x2 >= clippingRect_x2) {
+ break;
+ }
+ if (spr_x2 >= clippingRect_x1) {
+ uint8 color = vflipped ? srcSpr[spr->w - 1 - spr_x1] : srcSpr[spr_x1];
+ if (color != 0) {
+ *dstCur = color;
+ }
+ }
+ ++spr_x2;
+ ++dstCur;
+ }
+ x2 = MAX(x2, spr_x2);
+ } else {
+ while (1) {
+ int spr_x1 = dstX - *scalingTable; --scalingTable;
+ if (spr_x1 >= spr->w || spr_x2 < clippingRect_x1) {
+ break;
+ }
+ if (spr_x2 < clippingRect_x2) {
+ uint8 color = vflipped ? srcSpr[spr->w - 1 - spr_x1] : srcSpr[spr_x1];
+ if (color != 0) {
+ *dstCur = color;
+ }
+ }
+ --spr_x2;
+ --dstCur;
+ }
+ x1 = MIN(x1, spr_x2);
+ }
+ ++sprScaledY;
+ dstStart += dstPitch;
+ }
+ }
+ }
+ if (walkDataNum != -1) {
+ if (_flagsTable[604] == 0) {
+ int area1 = _programWalkTable[walkDataNum].area1;
+ if (area1 != 0) {
+ findAndRedrawRoomRegion(area1);
+ }
+ int area2 = _programWalkTable[walkDataNum].area2;
+ if (area2 != 0) {
+ findAndRedrawRoomRegion(area2);
+ }
+ }
+ }
+}
+
+void ToucheEngine::changeKeyCharFrame(KeyChar *key, int keyChar) {
+ key->currentAnimSpeed = 0;
+ key->currentAnimCounter = 0;
+ if (key->currentAnim != 1) {
+ int16 animStart, animCount;
+ if (_currentObjectNum == keyChar && _flagsTable[901] == 1) {
+ animStart = key->anim1Start;
+ animCount = key->anim1Count;
+ } else if (key->framesListCount != key->currentFrame) {
+ animStart = key->framesList[key->currentFrame];
+ ++key->currentFrame;
+ key->currentFrame &= 15;
+ animCount = 0;
+ } else {
+ animStart = key->anim2Start;
+ animCount = key->anim2Count;
+ if (key->currentAnim >= animStart && key->currentAnim < animStart + animCount) {
+ int rnd = getRandomNumber(100);
+ if (key->flags & 0x10) {
+ if (rnd >= 50 && rnd <= 55) {
+ KeyChar *followingKey = &_keyCharsTable[key->followingKeyCharNum];
+ int16 num = followingKey->pointsDataNum;
+ if (num != 0 && followingKey->currentWalkBox != -1 && num != key->followingKeyCharPos) {
+ key->followingKeyCharPos = num;
+ sortPointsData(-1, num);
+ buildWalkPointsList(key->num - 1);
+ }
+ }
+ } else {
+ if (rnd >= 50 && rnd <= 51) {
+ animStart = key->anim3Start;
+ animCount = key->anim3Count;
+ }
+ }
+ }
+ }
+ if (animCount != 0) {
+ animCount = getRandomNumber(animCount);
+ }
+ key->currentAnim = animStart + animCount;
+ }
+}
+
+void ToucheEngine::setKeyCharRandomFrame(KeyChar *key) {
+ key->currentAnimSpeed = 0;
+ key->currentAnim = key->anim2Start + getRandomNumber(key->anim2Count);
+ key->currentAnimCounter = 0;
+}
+
+void ToucheEngine::setKeyCharMoney() {
+ _keyCharsTable[_currentKeyCharNum].money = _currentAmountOfMoney;
+ drawAmountOfMoneyInInventory();
+}
+
+const char *ToucheEngine::getString(int num) const {
+ if (num < 0) {
+ return (const char *)_textData + READ_LE_UINT32(_textData - num * 4);
+ } else {
+ return (const char *)_programTextDataPtr + READ_LE_UINT32(_programTextDataPtr + num * 4);
+ }
+}
+
+int ToucheEngine::getStringWidth(int m, int num) const {
+ int w = 0;
+ const char *str = getString(num);
+ switch (m) {
+ case 16:
+ w = Graphics::getStringWidth16(str);
+ break;
+ }
+ return w;
+}
+
+void ToucheEngine::drawString(uint8 *dst, int dstPitch, int m, uint16 color, int x, int y, int16 num) {
+ if (num) {
+ const char *str = getString(num);
+ switch (m) {
+ case 16:
+ Graphics::drawString16(dst, dstPitch, color, x, y, str);
+ break;
+ }
+ }
+}
+
+void ToucheEngine::drawGameString(int m, uint16 color, int x1, int y, const char *str) {
+ int x, w;
+ switch (m) {
+ case 16:
+ w = Graphics::getStringWidth16(str);
+ x = x1 - w / 2;
+ if (x + w >= 640) {
+ x = 640 - w - 1;
+ }
+ while (*str) {
+ char chr = *str++;
+ if (chr == '\\') {
+ y += 16;
+ w = Graphics::getStringWidth16(str);
+ x = x1 - w / 2;
+ } else {
+ if (x < 0) {
+ x = 0;
+ }
+ x += Graphics::drawChar16(_offscreenBuffer, 640, chr, x, y, color);
+ }
+ }
+ break;
+ }
+}
+
+int ToucheEngine::restartKeyCharScriptOnAction(int action, int obj1, int obj2) {
+ debugC(9, kDebugEngine, "ToucheEngine::restartKeyCharScriptOnAction(%d, %d, %d)", action, obj1, obj2);
+ for (uint i = 0; i < _programActionScriptOffsetTable.size(); ++i) {
+ const ProgramActionScriptOffsetData *pasod = &_programActionScriptOffsetTable[i];
+ if (pasod->object1 == obj1 && pasod->action == action && pasod->object2 == obj2) {
+ debug(0, "Found matching action i=%d %d,%d,%d\n", i, pasod->action, pasod->object1, pasod->object2);
+ KeyChar *key = &_keyCharsTable[_currentKeyCharNum];
+ key->scriptDataOffset = pasod->offset;
+ key->scriptStackPtr = &key->scriptStackTable[39];
+ key->flags &= ~(kScriptStopped | kScriptPaused);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void ToucheEngine::buildSpriteScalingTable(int z1, int z2) {
+ debugC(9, kDebugEngine, "ToucheEngine::buildSpriteScalingTable(%d, %d)", z1, z2);
+ if (z2 > 500) {
+ z2 = 500;
+ }
+ if (z2 == 0) {
+ z2 = 1;
+ }
+
+ const int scaleInc = z1 * 256 / z2;
+ int scaleSum = 0;
+ for (int i = 0; i < z2; ++i) {
+ int value = scaleSum >> 8;
+ assert(i < 500);
+ _spriteScalingTable[500 + i] = value;
+ _spriteScalingTable[500 - i] = -value;
+ scaleSum += scaleInc;
+ }
+
+ const int16 *p = &_spriteScalingTable[500];
+ int16 z1_s = *p++;
+ int16 z2_s = *p++;
+ for (int i = 0, j = 0; j < z1; ++i) {
+ while (z2_s != z1_s) {
+ ++z1_s;
+ assert(j < 500);
+ _spriteScalingIndex[500 + j] = i + 500;
+ _spriteScalingIndex[500 - j] = 500 - i;
+ if (j++ >= z1) {
+ break;
+ }
+ }
+ z1_s = z2_s;
+ z2_s = *p++;
+ }
+}
+
+void ToucheEngine::drawSpriteOnBackdrop(int num, int x, int y) {
+ assert(num >= 0 && num < NUM_SPRITES);
+ SpriteData *spr = &_spritesTable[num];
+ Graphics::copyRect(_backdropBuffer, _currentBitmapWidth, x, y,
+ spr->ptr, spr->bitmapWidth, 0, 0,
+ spr->bitmapWidth, spr->bitmapHeight);
+}
+
+void ToucheEngine::updateTalkFrames(int keyChar) {
+ assert(keyChar >= 0 && keyChar < NUM_KEYCHARS);
+ KeyChar *key = &_keyCharsTable[keyChar];
+ if (key->currentAnim >= key->anim1Start && key->currentAnim < key->anim1Start + key->anim1Count) {
+ key->currentAnim = key->anim2Start;
+ key->currentAnimCounter = 0;
+ key->currentAnimSpeed = 0;
+ }
+}
+
+void ToucheEngine::setKeyCharTalkingFrame(int keyChar) {
+ assert(keyChar >= 0 && keyChar < NUM_KEYCHARS);
+ KeyChar *key = &_keyCharsTable[keyChar];
+ if (key->currentAnim != 1) {
+ key->currentAnim = key->anim1Start;
+ key->currentAnimCounter = 0;
+ key->currentAnimSpeed = 0;
+ }
+}
+
+void ToucheEngine::lockUnlockHitBox(int num, int lock) {
+ for (uint i = 0; i < _programHitBoxTable.size(); ++i) {
+ if (_programHitBoxTable[i].item == num) {
+ if (lock) {
+ _programHitBoxTable[i].hitBoxes[0].top |= 0x4000;
+ } else {
+ _programHitBoxTable[i].hitBoxes[0].top &= ~0x4000;
+ }
+ }
+ }
+}
+
+void ToucheEngine::drawHitBoxes() {
+ for (uint i = 0; i < _programHitBoxTable.size(); ++i) {
+ uint16 state = _programHitBoxTable[i].state;
+ if (state & 0x8000) {
+ _programHitBoxTable[i].state = state & 0x7FFF;
+ addToDirtyRect(_programHitBoxTable[i].hitBoxes[1]);
+ }
+ }
+}
+
+void ToucheEngine::setCursor(int num) {
+ debugC(9, kDebugEngine, "ToucheEngine::setCursor(%d)", num);
+ _currentCursorObject = num;
+ const int cursorW = 58;
+ const int cursorH = 42;
+ res_loadImage(num, _mouseData);
+ _system->setMouseCursor(_mouseData, cursorW, cursorH, cursorW / 2, cursorH / 2, 0);
+ _system->showMouse(true);
+}
+
+void ToucheEngine::updateCursor(int num) {
+ debugC(9, kDebugEngine, "ToucheEngine::updateCursor(%d)", num);
+ if (_currentCursorObject != 0) {
+ if (_currentCursorObject != 1) {
+ addItemToInventory(num, _currentCursorObject);
+ drawInventory(num, 1);
+ }
+ setCursor(0);
+ }
+}
+
+void ToucheEngine::handleMouseButtonClicked() {
+ for (int i = 0; i < 13; ++i) {
+ if (_inventoryAreasTable[i].contains(_inp_mousePos)) {
+ switch (i) {
+ case 0:
+ _keyCharsTable[_currentKeyCharNum].money += _currentAmountOfMoney;
+ _currentAmountOfMoney = 0;
+ ui_handleOptions(0);
+ break;
+ case 1:
+ setKeyCharMoney();
+ if (_currentCursorObject == 1) {
+ setCursor(0);
+ }
+ break;
+ case 2:
+ if (_keyCharsTable[_currentKeyCharNum].money >= 10) {
+ _keyCharsTable[_currentKeyCharNum].money -= 10;
+ _currentAmountOfMoney += 10;
+ }
+ break;
+ case 3:
+ if (_keyCharsTable[_currentKeyCharNum].money != 0) {
+ --_keyCharsTable[_currentKeyCharNum].money;
+ ++_currentAmountOfMoney;
+ drawAmountOfMoneyInInventory();
+ }
+ break;
+ case 4:
+ if (_currentAmountOfMoney != 0) {
+ updateCursor(_objectDescriptionNum);
+ int money = _currentAmountOfMoney;
+ _currentAmountOfMoney = 0;
+ drawAmountOfMoneyInInventory();
+ setCursor(1);
+ _currentAmountOfMoney = money;
+ }
+ break;
+ case 5:
+ if (*_inventoryVar2 != 0) {
+ *_inventoryVar2 -= 6;
+ drawInventory(_objectDescriptionNum, 1);
+ }
+ break;
+ case 12:
+ if (_inventoryVar1[12 + *_inventoryVar2] != 0) {
+ *_inventoryVar2 += 6;
+ drawInventory(_objectDescriptionNum, 1);
+ }
+ break;
+ default:
+ if (i >= 6 && i <= 11) {
+ int item = _inventoryVar1[i - 6 + *_inventoryVar2];
+ _flagsTable[119] = _currentCursorObject;
+ if (_currentCursorObject == 1) {
+ setKeyCharMoney();
+ _flagsTable[118] = _currentAmountOfMoney;
+ _currentAmountOfMoney = 0;
+ }
+ if (item != 0 && _currentCursorObject != 0) {
+ if (restartKeyCharScriptOnAction(-53, item | 0x1000, 0)) {
+ updateCursor(_objectDescriptionNum);
+ drawInventory(_objectDescriptionNum, 1);
+ }
+ } else {
+ _inventoryVar1[i - 6 + *_inventoryVar2] = 0;
+ if (_currentCursorObject != 0) {
+ updateCursor(_objectDescriptionNum);
+ }
+ if (item != 0) {
+ setCursor(item);
+ packInventoryItems(0);
+ packInventoryItems(1);
+ }
+ drawInventory(_objectDescriptionNum, 1);
+ }
+ }
+ break;
+ }
+ break;
+ }
+ }
+}
+
+void ToucheEngine::handleMouseButtonPressed() {
+ for (int pos = 0; pos < 13; ++pos) {
+ const Common::Rect &r = _inventoryAreasTable[pos];
+ if (r.contains(_inp_mousePos)) {
+ if (pos >= 6 && pos <= 11) {
+ int item = _inventoryVar1[pos - 6 + *_inventoryVar2] | 0x1000;
+ for (uint i = 0; i < _programHitBoxTable.size(); ++i) {
+ const ProgramHitBoxData *hitBox = &_programHitBoxTable[i];
+ if (hitBox->item == item) {
+ const int menuX = r.left + r.width() / 2;
+ const int menuY = 352;
+ int act = handleActionMenuUnderCursor(hitBox->actions, menuX, menuY, hitBox->str);
+ if (act != 0) {
+ restartKeyCharScriptOnAction(act, hitBox->item, 0);
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+}
+
+void ToucheEngine::handleMouseInput(int flag) {
+ if (_disabledInputCounter != 0 || _flagsTable[618] != 0) {
+ _inp_mouseButtonPressed = false;
+ }
+ if (_inp_mousePos.y < _roomAreaRect.height()) {
+ handleMouseInputRoomArea(flag);
+ } else {
+ handleMouseInputInventoryArea(flag);
+ }
+}
+
+void ToucheEngine::handleMouseInputRoomArea(int flag) {
+ if (_hideInventoryTexts && _conversationReplyNum != -1 && !_conversationAreaCleared) {
+ drawConversationString(_conversationReplyNum, 0xD6);
+ }
+ if (_disabledInputCounter == 0 && !_hideInventoryTexts && _flagsTable[618] == 0) {
+ bool itemSelected = false;
+ bool stringDrawn = false;
+ if (_conversationReplyNum != -1 && !_conversationAreaCleared && _giveItemToCounter == 0) {
+ drawConversationString(_conversationReplyNum, 0xD6);
+ }
+ _conversationReplyNum = -1;
+ int keyCharNewPosX = _flagsTable[614] + _inp_mousePos.x;
+ int keyCharNewPosY = _flagsTable[615] + _inp_mousePos.y;
+ for (uint i = 0; i < _programHitBoxTable.size(); ++i) {
+ if (_programHitBoxTable[i].item & 0x1000) {
+ break;
+ }
+ bool itemDisabled = false;
+ Common::Rect *hitBox = &_programHitBoxTable[i].hitBoxes[0];
+ int hitPosX = keyCharNewPosX;
+ int hitPosY = keyCharNewPosY;
+ int16 str = _programHitBoxTable[i].str;
+ KeyChar *keyChar;
+ switch (_programHitBoxTable[i].item & 0xF000) {
+ case 0x1000:
+ if (_inventoryItemsInfoTable[_programHitBoxTable[i].item & ~0x1000] != 0x20) {
+ hitPosY = 10000;
+ }
+ break;
+ case 0x2000:
+ itemDisabled = true;
+ break;
+ case 0x4000:
+ keyChar = &_keyCharsTable[_programHitBoxTable[i].item & ~0x4000];
+ hitPosY = 10000;
+ if (keyChar->num != 0) {
+ if ((keyChar->flags & 0x4000) == 0) {
+ if (keyChar->strNum != 0) {
+ str = keyChar->strNum;
+ }
+ hitBox = &keyChar->prevBoundingRect;
+ hitPosX = _inp_mousePos.x;
+ hitPosY = _inp_mousePos.y;
+ }
+ }
+ break;
+ }
+ if (_giveItemToCounter == 0 && !_hideInventoryTexts) {
+ if (hitBox->contains(hitPosX, hitPosY)) {
+ if (!itemDisabled) {
+ if (_inp_mouseButtonClicked && _currentCursorObject != 0) {
+ _inp_mouseButtonClicked = false;
+ itemSelected = true;
+ _flagsTable[119] = _currentCursorObject;
+ if (_currentCursorObject == 1) {
+ _flagsTable[118] = _currentAmountOfMoney;
+ _currentAmountOfMoney = 0;
+ }
+ _inventoryItemsInfoTable[_currentCursorObject] = 0x20;
+ setCursor(0);
+ if (_giveItemToCounter == 0) {
+ if (!restartKeyCharScriptOnAction(-53, _programHitBoxTable[i].item, 0)) {
+ if (_flagsTable[119] == 1) {
+ _currentAmountOfMoney = _flagsTable[118];
+ } else {
+ addItemToInventory(_currentKeyCharNum, _flagsTable[119]);
+ drawInventory(_currentKeyCharNum, 1);
+ }
+ drawAmountOfMoneyInInventory();
+ }
+ } else {
+ _flagsTable[117] = _programHitBoxTable[i].item - 1;
+ _giveItemToCounter = -1;
+ }
+ }
+ const char *strData = getString(str);
+ int strPosY = _inp_mousePos.y - 22;
+ if (_currentCursorObject != 0) {
+ strPosY -= 8;
+ }
+ if (strPosY <= 0) {
+ strPosY = 1;
+ }
+ int strWidth = getStringWidth(16, str);
+ int strPosX = _inp_mousePos.x - strWidth / 2;
+ strPosX = CLIP<int>(strPosX, 0, 640 - strWidth - 1);
+ if (_talkTextSpeed != 0) {
+ --_talkTextSpeed;
+ }
+ if (!stringDrawn && _talkTextSpeed == 0) {
+ drawGameString(16, 0xFF, strPosX + strWidth / 2, strPosY, strData);
+ }
+ stringDrawn = true;
+ Common::Rect redrawRect(strPosX, strPosY, strPosX + strWidth, strPosY + 16);
+ if (_programHitBoxTable[i].state & 0x8000) {
+ redrawRect.extend(_programHitBoxTable[i].hitBoxes[1]);
+ }
+ addToDirtyRect(redrawRect);
+ _programHitBoxTable[i].hitBoxes[1] = Common::Rect(strPosX, strPosY, strPosX + strWidth, strPosY + 16);
+ _programHitBoxTable[i].state |= 0x8000;
+ }
+ if (_inp_mouseButtonClicked) {
+ _inp_mouseButtonClicked = false;
+ if (_currentCursorObject != 0) {
+ updateCursor(_currentKeyCharNum);
+ } else {
+ drawInventory(_currentKeyCharNum, 0);
+ if (restartKeyCharScriptOnAction(-49, _programHitBoxTable[i].item, 0) == 0) {
+ buildWalkPath(keyCharNewPosX, keyCharNewPosY, _currentKeyCharNum);
+ }
+ }
+ } else {
+ if (_inp_mouseButtonPressed && !itemDisabled && !itemSelected) {
+ int act = handleActionMenuUnderCursor(_programHitBoxTable[i].actions, _inp_mousePos.x, _inp_mousePos.y, str);
+ _inp_mouseButtonPressed = false;
+ int16 facing = (keyCharNewPosX <= _keyCharsTable[_currentKeyCharNum].xPos) ? 3 : 0;
+ _keyCharsTable[_currentKeyCharNum].facingDirection = facing;
+ if (act != 0) {
+ restartKeyCharScriptOnAction(act, _programHitBoxTable[i].item, 0);
+ } else {
+ act = _programHitBoxTable[i].talk;
+ if (act != 0) {
+ addToTalkTable(0, act, _currentKeyCharNum);
+ }
+ }
+ }
+ }
+ } else if (_programHitBoxTable[i].state & 0x8000) {
+ _programHitBoxTable[i].state &= 0x7FFF;
+ addToDirtyRect(_programHitBoxTable[i].hitBoxes[1]);
+ }
+ }
+ }
+ if (_inp_mouseButtonClicked) {
+ _inp_mouseButtonClicked = false;
+ if (_currentCursorObject != 0) {
+ if (_currentCursorObject != 1) {
+ addItemToInventory(_currentKeyCharNum, _currentCursorObject);
+ drawInventory(_objectDescriptionNum, 1);
+ }
+ setCursor(0);
+ } else {
+ drawInventory(_currentKeyCharNum, 0);
+ buildWalkPath(keyCharNewPosX, keyCharNewPosY, _currentKeyCharNum);
+ }
+ }
+ } else {
+ if (flag) {
+ drawHitBoxes();
+ }
+ }
+}
+
+void ToucheEngine::handleMouseInputInventoryArea(int flag) {
+ if (flag) {
+ drawHitBoxes();
+ }
+ if (_hideInventoryTexts && _giveItemToCounter == 0) {
+ if (!_conversationAreaCleared) {
+ if (_inp_mousePos.x >= 40) {
+ if (_inp_mousePos.y >= 328) {
+ int replyNum = (_inp_mousePos.y - 328) / 16;
+ if (replyNum >= 4) {
+ replyNum = 3;
+ }
+ if (replyNum != _conversationReplyNum) {
+ if (_conversationReplyNum != -1) {
+ drawConversationString(_conversationReplyNum, 0xD6);
+ }
+ drawConversationString(replyNum, 0xFF);
+ _conversationReplyNum = replyNum;
+ }
+ if (_inp_mouseButtonClicked) {
+ _inp_mouseButtonClicked = false;
+ setupConversationScript(replyNum);
+ _conversationReplyNum = -1;
+ }
+ }
+ } else {
+ if (_conversationReplyNum != -1 && !_conversationAreaCleared) {
+ drawConversationString(_conversationReplyNum, 0xD6);
+ }
+ _conversationReplyNum = -1;
+ if (_inp_mouseButtonClicked) {
+ int replyNum = _inp_mousePos.y - _roomAreaRect.height();
+ if (replyNum < 40) {
+ drawCharacterConversationRepeat();
+ } else {
+ drawCharacterConversationRepeat2();
+ }
+ _inp_mouseButtonClicked = false;
+ }
+ }
+ }
+ } else if (_disabledInputCounter == 0 && !_hideInventoryTexts) {
+ if (_inp_mouseButtonClicked) {
+ handleMouseButtonClicked();
+ _inp_mouseButtonClicked = false;
+ }
+ if (_inp_mouseButtonPressed) {
+ handleMouseButtonPressed();
+ _inp_mouseButtonPressed = false;
+ }
+ }
+}
+
+void ToucheEngine::scrollScreenToPos(int num) {
+ _screenOffset.x = _programPointsTable[num].x - 640 / 2;
+ _screenOffset.y = _programPointsTable[num].y - 400 / 2;
+}
+
+void ToucheEngine::clearRoomArea() {
+ int h = (_flagsTable[606] != 0) ? 400 : _roomAreaRect.height();
+ Graphics::fillRect(_offscreenBuffer, 640, 0, 0, 640, h, 0);
+ updateEntireScreen();
+}
+
+void ToucheEngine::startNewMusic() {
+ _snd_midiContext.unkA = _flagsTable[619] & 0xFF;
+ if (_newMusicNum != 0 && _newMusicNum != _currentMusicNum) {
+ _snd_midiContext.unkB = 3;
+ if (_snd_midiContext.unkF != 0 && _snd_midiContext.unk2 != 0) {
+ return;
+ }
+ _snd_midiContext.unkB = 0;
+ res_loadMusic(_newMusicNum);
+ _snd_midiContext.unk2 = 0;
+ _newMusicNum = 0;
+ }
+}
+
+void ToucheEngine::startNewSound() {
+ if (_newSoundNum != 0) {
+ if (_newSoundDelay == 0) {
+ res_loadSound(_newSoundPriority, _newSoundNum);
+ _newSoundNum = 0;
+ } else {
+ --_newSoundDelay;
+ }
+ }
+}
+
+void ToucheEngine::updateSpeech() {
+ if (_speechPlaying) {
+ if (!_mixer->isSoundHandleActive(_speechHandle)) {
+ _speechPlaying = false;
+ _defaultSoundPriority = 0;
+ }
+ }
+}
+
+int ToucheEngine::handleActionMenuUnderCursor(const int16 *actions, int offs, int y, int str) {
+ if (*actions == 0 || _redrawScreenCounter1 != 0) {
+ return -26;
+ }
+ int i;
+ int16 actionsTable[10];
+ int16 *currentAction = actionsTable;
+ int drawY = 0;
+ for (i = 0; i < 8; ++i) {
+ int act = *actions++;
+ if (act == 0) {
+ break;
+ }
+ if (act != -49 && act != -53) {
+ *currentAction++ = act;
+ drawY = 1;
+ }
+ }
+ if (drawY == 0) {
+ return -26;
+ }
+ *currentAction = 0;
+ int strW = getStringWidth(16, str);
+ int h = 0;
+ for (i = 0; i < 10; ++i) {
+ if (actionsTable[i] == 0) {
+ break;
+ }
+ ++h;
+ drawY = getStringWidth(16, actionsTable[i]);
+ if (drawY > strW) {
+ strW = drawY;
+ }
+ }
+ int cursorW = strW + 28;
+ int cursorPosX = CLIP<int16>(offs - cursorW / 2, 0, 640 - cursorW);
+ offs = cursorPosX + 14;
+ h *= 16;
+ int cursorH = h + 28;
+ int cursorPosY = CLIP<int16>(y - 24, 0, 352 - cursorH);
+ y = cursorPosY + 24;
+ _cursorObjectRect = Common::Rect(cursorPosX, cursorPosY, cursorPosX + cursorW, cursorPosY + cursorH);
+ addToDirtyRect(_cursorObjectRect);
+
+ Graphics::fillRect(_offscreenBuffer, 640, cursorPosX + 14, cursorPosY + 24, cursorW - 28, cursorH - 40, 0xF8);
+ ui_drawActionsPanel(cursorPosX, cursorPosY, cursorW, cursorH);
+
+ const char *strData = getString(str);
+ drawGameString(16, 0xF8FF, offs + strW / 2, cursorPosY + 4, strData);
+ for (i = 0; i < 10; ++i) {
+ if (actionsTable[i] == 0) {
+ break;
+ }
+ drawString(_offscreenBuffer, 640, 16, 0xF8F9, offs, y + i * 16, actionsTable[i]);
+ }
+ updateScreenArea(_offscreenBuffer, 640, cursorPosX, cursorPosY, cursorPosX, cursorPosY, cursorW, cursorH);
+
+ _redrawScreenCounter1 = 2;
+ Common::Rect rect(0, y, 640, y + h);
+ i = -1;
+ while (_inp_mouseButtonPressed) {
+ if (rect.contains(_inp_mousePos)) {
+ int c = (_inp_mousePos.y - y) / 16;
+ if (c != i) {
+ if (i >= 0) {
+ drawY = y + i * 16;
+ drawString(_offscreenBuffer, 640, 16, 0xF8F9, offs, drawY, actionsTable[i]);
+ updateScreenArea(_offscreenBuffer, 640, offs, drawY, offs, drawY, strW, 16);
+ }
+ i = c;
+ drawY = y + i * 16;
+ drawString(_offscreenBuffer, 640, 16, 0xF8FF, offs, drawY, actionsTable[i]);
+ updateScreenArea(_offscreenBuffer, 640, offs, drawY, offs, drawY, strW, 16);
+ }
+ } else if (i >= 0) {
+ drawY = y + i * 16;
+ drawString(_offscreenBuffer, 640, 16, 0xF8F9, offs, drawY, actionsTable[i]);
+ updateScreenArea(_offscreenBuffer, 640, offs, drawY, offs, drawY, strW, 16);
+ i = -1;
+ }
+
+ OSystem::Event event;
+ while (_system->pollEvent(event)) {
+ switch (event.type) {
+ case OSystem::EVENT_QUIT:
+ _flagsTable[611] = 1;
+ break;
+ case OSystem::EVENT_MOUSEMOVE:
+ _inp_mousePos.x = event.mouse.x;
+ _inp_mousePos.y = event.mouse.y;
+ break;
+ case OSystem::EVENT_RBUTTONDOWN:
+ _inp_mousePos.x = event.mouse.x;
+ _inp_mousePos.y = event.mouse.y;
+ _inp_mouseButtonPressed = true;
+ break;
+ case OSystem::EVENT_RBUTTONUP:
+ _inp_mousePos.x = event.mouse.x;
+ _inp_mousePos.y = event.mouse.y;
+ _inp_mouseButtonPressed = false;
+ break;
+ default:
+ break;
+ }
+ }
+ _system->delayMillis(50);
+ }
+
+ const int action = (i >= 0) ? actionsTable[i] : -26;
+ return action;
+}
+
+void ToucheEngine::redrawBackground() {
+ for (uint i = 0; i < _programBackgroundTable.size(); ++i) {
+ Area area = _programBackgroundTable[i].area;
+ if (area.r.top != 20000) {
+ area.r.translate(-_flagsTable[614], -_flagsTable[615]);
+ if (_programBackgroundTable[i].type == 4) {
+ int16 dx = _programBackgroundTable[i].offset - 640 / 2 - _flagsTable[614];
+ dx *= _programBackgroundTable[i].scaleMul;
+ dx /= _programBackgroundTable[i].scaleDiv;
+ area.r.translate(dx, 0);
+ }
+ if (area.clip(_roomAreaRect)) {
+ Graphics::copyRect(_offscreenBuffer, 640, area.r.left, area.r.top,
+ _backdropBuffer, _currentBitmapWidth, area.srcX, area.srcY,
+ area.r.width(), area.r.height(),
+ Graphics::kTransparent);
+ addToDirtyRect(area.r);
+ }
+ }
+ }
+}
+
+void ToucheEngine::processAreaTable() {
+ debugC(9, kDebugEngine, "ToucheEngine::processAreaTable()");
+// for (int i = 0; i < _areaTableCount; ++i) {
+// Rect r(_areaTable[i].r);
+// if (rectClip(&_roomAreaRect, &r)) {
+// addToDirtyRect(&r);
+// }
+// }
+}
+
+void ToucheEngine::clearAreaTable() {
+ debugC(9, kDebugEngine, "ToucheEngine::clearAreaTable()");
+ _areaTableCount = 0;
+}
+
+void ToucheEngine::addToAreaTable(const Area *area) {
+ debugC(9, kDebugEngine, "ToucheEngine::addToAreaTable()");
+ assert(_areaTableCount < NUM_AREAS);
+ _areaTable[_areaTableCount] = *area;
+ ++_areaTableCount;
+}
+
+void ToucheEngine::addRoomArea(int num, int flag) {
+ debugC(9, kDebugEngine, "ToucheEngine::addRoomArea(%d, %d)", num, flag);
+ if (_flagsTable[flag] == 20000) {
+ Area area = _programBackgroundTable[num].area;
+ area.r.translate(-_flagsTable[614], -_flagsTable[615]);
+ if (area.clip(_roomAreaRect)) {
+ addToAreaTable(&area);
+ }
+ }
+ _programBackgroundTable[num].area.r.moveTo(_flagsTable[flag], _flagsTable[flag + 1]);
+}
+
+void ToucheEngine::updateRoomAreas(int num, int flags) {
+ debugC(9, kDebugEngine, "ToucheEngine::updateRoomAreas(%d, %d)", num, flags);
+ if (flags != -1) {
+ int16 count = _updatedRoomAreasTable[0];
+ ++_updatedRoomAreasTable[0];
+ if (count == 199) {
+ _updatedRoomAreasTable[0] = 2;
+ count = 1;
+ }
+ _updatedRoomAreasTable[count] = (uint8)num;
+ }
+ for (uint i = 0; i < _programAreaTable.size(); ++i) {
+ if (_programAreaTable[i].id == num) {
+ Area area = _programAreaTable[i].area;
+ Graphics::copyRect(_backdropBuffer, _currentBitmapWidth, area.r.left, area.r.top,
+ _backdropBuffer, _currentBitmapWidth, area.srcX, area.srcY,
+ area.r.width(), area.r.height(),
+ Graphics::kTransparent);
+ if (flags != 0) {
+ area.r.translate(-_flagsTable[614], -_flagsTable[615]);
+ if (area.clip(_roomAreaRect)) {
+ addToAreaTable(&area);
+ }
+ }
+ }
+ }
+}
+
+void ToucheEngine::setRoomAreaState(int num, uint16 state) {
+ debugC(9, kDebugEngine, "ToucheEngine::setRoomAreaState(%d, %d)", num, state);
+ for (uint i = 0; i < _programAreaTable.size(); ++i) {
+ if (_programAreaTable[i].id == num) {
+ _programAreaTable[i].state = state;
+ }
+ }
+}
+
+void ToucheEngine::findAndRedrawRoomRegion(int num) {
+ debugC(9, kDebugEngine, "ToucheEngine::findAndRedrawRoomRegion(%d)", num);
+ for (uint i = 0; i < _programAreaTable.size(); ++i) {
+ if (_programAreaTable[i].id == num) {
+ redrawRoomRegion(i, 0);
+ break;
+ }
+ }
+}
+
+void ToucheEngine::updateRoomRegions() {
+ debugC(9, kDebugEngine, "ToucheEngine::updateRoomRegions()");
+ if (_flagsTable[269] == 0) {
+ uint i = 0;
+ while (i < _programAreaTable.size() && _programAreaTable[i].id != 0) {
+ switch (_programAreaTable[i].state) {
+ case 0:
+ ++i;
+ break;
+ case 1:
+ redrawRoomRegion(i + _programAreaTable[i].animNext, true);
+ ++_programAreaTable[i].animNext;
+ if (_programAreaTable[i].animNext >= _programAreaTable[i].animCount) {
+ _programAreaTable[i].animNext = 0;
+ }
+ i += _programAreaTable[i].animCount;
+ break;
+ case 3:
+ redrawRoomRegion(i + _programAreaTable[i].animNext, true);
+ ++_programAreaTable[i].animNext;
+ if (_programAreaTable[i].animNext >= _programAreaTable[i].animCount) {
+ _programAreaTable[i].animNext = 0;
+ }
+ i += _programAreaTable[i].animCount + 1;
+ break;
+ }
+ }
+ }
+}
+
+void ToucheEngine::redrawRoomRegion(int num, bool markForRedraw) {
+ debugC(9, kDebugEngine, "ToucheEngine::redrawRoomRegion(%d)", num);
+ Area area = _programAreaTable[num].area;
+ area.r.translate(-_flagsTable[614], -_flagsTable[615]);
+ if (area.clip(_roomAreaRect)) {
+ Graphics::copyRect(_offscreenBuffer, 640, area.r.left, area.r.top,
+ _backdropBuffer, _currentBitmapWidth, area.srcX, area.srcY,
+ area.r.width(), area.r.height(),
+ Graphics::kTransparent);
+ if (markForRedraw) {
+ addToDirtyRect(area.r);
+ }
+ }
+}
+
+void ToucheEngine::initInventoryObjectsTable() {
+ for (int i = 0; i < NUM_INVENTORY_ITEMS; ++i) {
+ _inventoryItemsInfoTable[i] = 0x20;
+ }
+}
+
+void ToucheEngine::initInventoryLists() {
+ memset(_inventoryList1, 0, sizeof(_inventoryList1));
+ _inventoryList1[100] = -1;
+ _inventoryListPtrs[0] = _inventoryList1;
+ _inventoryListCount[3 * 0 + 0] = 0; // start offset
+ _inventoryListCount[3 * 0 + 1] = 100; // max number of items
+ _inventoryListCount[3 * 0 + 2] = 6; // items per inventory line
+
+ memset(_inventoryList2, 0, sizeof(_inventoryList2));
+ _inventoryList2[100] = -1;
+ _inventoryListPtrs[1] = _inventoryList2;
+ _inventoryListCount[3 * 1 + 0] = 0;
+ _inventoryListCount[3 * 1 + 1] = 100;
+ _inventoryListCount[3 * 1 + 2] = 6;
+
+ memset(_inventoryList3, 0, sizeof(_inventoryList3));
+ _inventoryList3[6] = -1;
+ _inventoryListPtrs[2] = _inventoryList3;
+ _inventoryListCount[3 * 2 + 0] = 0;
+ _inventoryListCount[3 * 2 + 1] = 6;
+ _inventoryListCount[3 * 2 + 2] = 6;
+}
+
+void ToucheEngine::drawInventory(int index, int flag) {
+ if (_flagsTable[606] == 0) {
+ if (index > 1) {
+ index = 1;
+ }
+ if (_objectDescriptionNum == index && flag == 0) {
+ return;
+ }
+ _inventoryVar1 = _inventoryListPtrs[index];
+ _inventoryVar2 = &_inventoryListCount[index * 3];
+ _objectDescriptionNum = index;
+ uint8 *dst = _offscreenBuffer + 640 * 352;
+ res_loadSpriteImage(index + 12, dst);
+ res_loadImageHelper(dst, _currentImageWidth, _currentImageHeight);
+ int firstObjNum = _inventoryVar2[0];
+ for (int i = 0, x = 242; i < 6; ++i, x += 58) {
+ int num = _inventoryVar1[firstObjNum + i];
+ if (num == -1) {
+ break;
+ }
+ if (num != 0) {
+ drawIcon(x + 3, 353, num);
+ }
+ }
+ drawAmountOfMoneyInInventory();
+ updateScreenArea(_offscreenBuffer, 640, 0, 352, 0, 352, 640, 48);
+ }
+}
+
+void ToucheEngine::drawAmountOfMoneyInInventory() {
+ if (_flagsTable[606] == 0 && !_hideInventoryTexts) {
+ char text[4];
+ itoa(_keyCharsTable[0].money, text, 10);
+ Graphics::fillRect(_offscreenBuffer, 640, 74, 354, 40, 16, 0xD2);
+ drawGameString(16, 217, 94, 355, text);
+ updateScreenArea(_offscreenBuffer, 640, 74, 354, 74, 354, 40, 16);
+ Graphics::fillRect(_offscreenBuffer, 640, 150, 353, 40, 41, 0xD2);
+ if (_currentAmountOfMoney != 0) {
+ drawIcon(141, 348, 1);
+ itoa(_currentAmountOfMoney, text, 10);
+ drawGameString(16, 217, 170, 378, text);
+ }
+ updateScreenArea(_offscreenBuffer, 640, 150, 353, 150, 353, 40, 41);
+ }
+}
+
+void ToucheEngine::packInventoryItems(int index) {
+ int16 *p = _inventoryListPtrs[index];
+ for (int i = 0; *p != -1; ++i, ++p) {
+ if (p[0] == 0 && p[1] != -1) {
+ p[0] = p[1];
+ p[1] = 0;
+ }
+ }
+}
+
+void ToucheEngine::appendItemToInventoryList(int index) {
+ int last = _inventoryListCount[index * 3 + 1] - 1;
+ int16 *p = _inventoryListPtrs[index];
+ if (p[last] != 0) {
+ warning("Inventory %d Full", index);
+ } else {
+ for (int i = last; i > 0; --i) {
+ p[i] = p[i - 1];
+ }
+ *p = 0;
+ }
+}
+
+void ToucheEngine::addItemToInventory(int inventory, int16 item) {
+ if (item == 0) {
+ packInventoryItems(inventory);
+ } else if (item == 1) {
+ _currentAmountOfMoney += _flagsTable[118];
+ drawAmountOfMoneyInInventory();
+ } else {
+ appendItemToInventoryList(inventory);
+ assert(inventory >= 0 && inventory < 3);
+ int16 *p = _inventoryListPtrs[inventory];
+ for (int i = 0; *p != -1; ++i, ++p) {
+ if (*p == 0) {
+ *p = item;
+ _inventoryItemsInfoTable[item] = inventory | 0x10;
+ packInventoryItems(0);
+ packInventoryItems(1);
+ break;
+ }
+ }
+ }
+}
+
+void ToucheEngine::removeItemFromInventory(int inventory, int16 item) {
+ if (item == 1) {
+ _currentAmountOfMoney = 0;
+ drawAmountOfMoneyInInventory();
+ } else {
+ assert(inventory >= 0 && inventory < 3);
+ int16 *p = _inventoryListPtrs[inventory];
+ for (int i = 0; *p != -1; ++i, ++p) {
+ if (*p == item) {
+ *p = 0;
+ packInventoryItems(0);
+ packInventoryItems(1);
+ break;
+ }
+ }
+ }
+}
+
+void ToucheEngine::changeInventoryItemState(int flag, int itemNum, int itemRnd, int inventoryItem) {
+ const int rnd = getRandomNumber(100) + 1;
+ if (inventoryItem) {
+ itemNum = _keyCharsTable[_currentKeyCharNum].inventoryItems[itemNum];
+ }
+ if (_flagsTable[174]) {
+ itemNum /= 2;
+ _flagsTable[174] = 0;
+ }
+ int16 value;
+ if (itemNum > itemRnd) {
+ value = 1;
+ } else if (rnd < itemNum / 6) {
+ value = 0;
+ } else if (rnd <= itemNum) {
+ value = 1;
+ } else if (rnd >= itemNum * 2) {
+ value = 2;
+ } else {
+ value = 3;
+ }
+ _flagsTable[flag] = value;
+}
+
+void ToucheEngine::resetTalkingVars() {
+ _talkListCurrent = 0;
+ _talkListEnd = 0;
+ _keyCharTalkCounter = 0;
+ _talkTextRectDefined = false;
+ _talkTextDisplayed = false;
+ _skipTalkText = false;
+ _talkTextInitialized = false;
+ if (_speechPlaying) {
+ res_stopSpeech();
+ }
+}
+
+int ToucheEngine::updateKeyCharTalk(int skipFlag) {
+ if (skipFlag != 0) {
+ if (_speechPlaying) {
+ res_stopSpeech();
+ }
+ if (_talkListEnd != _talkListCurrent) {
+ _keyCharTalkCounter = 0;
+ _talkTextInitialized = false;
+ if (skipFlag == 2) {
+ _skipTalkText = true;
+ } else {
+ _skipTalkText = false;
+ }
+ }
+ return 0;
+ }
+ if (_talkListEnd == _talkListCurrent) {
+ return 0;
+ }
+ int talkingKeyChar = _talkTable[_talkListCurrent].talkingKeyChar;
+ int otherKeyChar = _talkTable[_talkListCurrent].otherKeyChar;
+ KeyChar *key = &_keyCharsTable[talkingKeyChar];
+ int x = key->xPos - _flagsTable[614];
+ int y = key->yPos - _flagsTable[615] - (key->zPos / 2 + 16);
+ int stringNum = _talkTable[_talkListCurrent].num;
+ const char *stringData = getString(stringNum);
+ int textWidth = getStringWidth(16, stringNum);
+ if (!_talkTextInitialized && !_skipTalkText) {
+ _keyCharTalkCounter = textWidth / 32 + 20;
+ setKeyCharTalkingFrame(talkingKeyChar);
+ res_loadSpeechSegment(stringNum);
+ _talkTextInitialized = true;
+ }
+ if (_keyCharTalkCounter) {
+ --_keyCharTalkCounter;
+ }
+ if (_speechPlaying) {
+ _flagsTable[297] = 0;
+ if (_talkTextMode == kTalkModeVoiceOnly) {
+ _keyCharTalkCounter = 0;
+ }
+ _currentObjectNum = talkingKeyChar;
+ if (_keyCharTalkCounter == 0) {
+ _keyCharTalkCounter = 1;
+ }
+ }
+ if (_talkTextMode == kTalkModeVoiceOnly) {
+ if (_speechPlaying) {
+ return 1;
+ }
+ }
+ if (_keyCharTalkCounter != 0) {
+ _currentObjectNum = talkingKeyChar;
+ _talkTextDisplayed = true;
+ int textHeight = 16;
+ y -= 16;
+ if (y < 0) {
+ y = 1;
+ } else if (y > 352) {
+ y = 336;
+ }
+ if (textWidth > 200) {
+ textWidth = 200;
+ stringData = formatTalkText(16, &y, &textHeight, stringData);
+ }
+ x -= textWidth / 2;
+ if (x < 0) {
+ x = 0;
+ }
+ if (x + textWidth >= 640) {
+ x = 640 - textWidth - 1;
+ }
+ drawGameString(16, key->textColor, x + textWidth / 2, y, stringData);
+ _talkTextSpeed = 6;
+ _talkTextRect = Common::Rect(x, y, x + textWidth, y + textHeight);
+ if (_talkTextRectDefined) {
+ _talkTextRect.extend(_talkTextRect2);
+ }
+ addToDirtyRect(_talkTextRect);
+ _talkTextRect2 = Common::Rect(x, y, x + textWidth, y + textHeight);
+ _talkTextRectDefined = true;
+ _flagsTable[297] = 0;
+ } else {
+ updateTalkFrames(_currentObjectNum);
+ _currentObjectNum = -1;
+ if (_talkTextDisplayed) {
+ addToDirtyRect(_talkTextRect2);
+ }
+ _talkTextInitialized = false;
+ _skipTalkText = false;
+ _talkTextRectDefined = false;
+ ++_talkListCurrent;
+ if (_talkListCurrent == 16) {
+ _talkListCurrent = 0;
+ }
+ if (otherKeyChar != -1) {
+ _keyCharsTable[otherKeyChar].flags &= ~kScriptPaused;
+ }
+ }
+ return 1;
+}
+
+const char *ToucheEngine::formatTalkText(int mode, int *y, int *h, const char *text) {
+ int newLineWidth = 0;
+ int lineWidth = 0;
+ char *textBuffer = _talkTextBuffer;
+ char *textLine = textBuffer;
+ if (mode != 16) {
+ return text;
+ } else {
+ while (*text) {
+ char chr = *text++;
+ int chrWidth = Graphics::getCharWidth16(chr);
+ lineWidth += chrWidth;
+ if (chr == ' ') {
+ if (lineWidth + newLineWidth >= 200) {
+ *textLine = '\\';
+ newLineWidth = lineWidth - chrWidth;
+ *y -= mode;
+ *h += mode;
+ lineWidth = chrWidth;
+ } else {
+ newLineWidth += lineWidth;
+ lineWidth = chrWidth;
+ }
+ *textBuffer = ' ';
+ textLine = textBuffer;
+ textBuffer++;
+ } else {
+ *textBuffer++ = chr;
+ }
+ }
+ if (newLineWidth + lineWidth >= 200) {
+ *textLine = '\\';
+ *y -= mode;
+ *h += mode;
+ }
+ *textBuffer = '\0';
+ if (*y < 0) {
+ *y = 1;
+ }
+ return _talkTextBuffer;
+ }
+}
+
+void ToucheEngine::addToTalkTable(int talkingKeyChar, int num, int otherKeyChar) {
+ if (_talkListEnd != _talkListCurrent) {
+ if (_talkTableLastTalkingKeyChar == talkingKeyChar &&
+ _talkTableLastOtherKeyChar == otherKeyChar &&
+ _talkTableLastStringNum == num) {
+ return;
+ }
+ }
+ _talkTableLastTalkingKeyChar = talkingKeyChar;
+ _talkTableLastOtherKeyChar = otherKeyChar;
+ _talkTableLastStringNum = num;
+
+ removeFromTalkTable(otherKeyChar);
+
+ assert(_talkListEnd < NUM_TALK_ENTRIES);
+ TalkEntry *talkEntry = &_talkTable[_talkListEnd];
+ talkEntry->talkingKeyChar = talkingKeyChar;
+ talkEntry->otherKeyChar = otherKeyChar;
+ talkEntry->num = num;
+
+ ++_talkListEnd;
+ if (_talkListEnd == NUM_TALK_ENTRIES) {
+ _talkListEnd = 0;
+ }
+}
+
+void ToucheEngine::removeFromTalkTable(int keyChar) {
+ debugC(9, kDebugEngine, "ToucheEngine::removeFromTalkTable(%d)", keyChar);
+ int i = _talkListCurrent;
+ while (i != _talkListEnd) {
+ if (_talkTable[i].otherKeyChar == keyChar) {
+ _talkTable[i].otherKeyChar = -1;
+ }
+ ++i;
+ i %= NUM_TALK_ENTRIES;
+ }
+}
+
+void ToucheEngine::addConversationChoice(int16 num) {
+ debugC(9, kDebugEngine, "ToucheEngine::addConversationChoice(%d)", num);
+ _conversationChoicesUpdated = true;
+ int16 msg = _programConversationTable[_currentConversation + num].msg;
+ for (int i = 0; i < NUM_CONVERSATION_CHOICES; ++i) {
+ if (_conversationChoicesTable[i].msg == msg) {
+ break;
+ }
+ if (_conversationChoicesTable[i].msg == 0) {
+ _conversationChoicesTable[i].msg = msg;
+ _conversationChoicesTable[i].num = num;
+ break;
+ }
+ }
+}
+
+void ToucheEngine::removeConversationChoice(int16 num) {
+ debugC(9, kDebugEngine, "ToucheEngine::removeConversationChoice(%d)", num);
+ for (int i = 0; i < NUM_CONVERSATION_CHOICES; ++i) {
+ if (_conversationChoicesTable[i].num == num) {
+ _conversationChoicesUpdated = true;
+ for(; i < NUM_CONVERSATION_CHOICES - 1; ++i) {
+ _conversationChoicesTable[i].num = _conversationChoicesTable[i + 1].num;
+ _conversationChoicesTable[i].msg = _conversationChoicesTable[i + 1].msg;
+ }
+ break;
+ }
+ }
+}
+
+void ToucheEngine::runConversationScript(uint16 offset) {
+ debugC(9, kDebugEngine, "ToucheEngine::runConversationScript() offset=0x%X", offset);
+ _script.dataOffset = offset;
+ _script.quitFlag = 0;
+ runCurrentKeyCharScript(2);
+}
+
+void ToucheEngine::findConversationByNum(int16 num) {
+ debugC(9, kDebugEngine, "ToucheEngine::findConversationByNum(%d)", num);
+ for (uint i = 0; i < _programConversationTable.size(); ++i) {
+ if (_programConversationTable[i].num == num) {
+ clearConversationChoices();
+ _currentConversation = i;
+ runConversationScript(_programConversationTable[i].offset);
+ break;
+ }
+ }
+}
+
+void ToucheEngine::clearConversationChoices() {
+ debugC(9, kDebugEngine, "ToucheEngine::clearConversationChoices()");
+ _conversationChoicesUpdated = true;
+ for (int i = 0; i < NUM_CONVERSATION_CHOICES; ++i) {
+ _conversationChoicesTable[i].num = 0;
+ _conversationChoicesTable[i].msg = 0;
+ }
+ _drawCharacterConversionRepeatCounter = 0;
+}
+
+void ToucheEngine::drawCharacterConversationRepeat2() {
+ if (_conversationChoicesTable[4 + _drawCharacterConversionRepeatCounter].msg != 0) {
+ ++_drawCharacterConversionRepeatCounter;
+ drawCharacterConversation();
+ }
+}
+
+void ToucheEngine::drawCharacterConversationRepeat() {
+ if (_drawCharacterConversionRepeatCounter != 0) {
+ --_drawCharacterConversionRepeatCounter;
+ drawCharacterConversation();
+ }
+}
+
+void ToucheEngine::drawCharacterConversation() {
+ _conversationChoicesUpdated = false;
+ if (!_disableConversationScript) {
+ if (_conversationChoicesTable[0].msg == 0) {
+ _conversationEnded = true;
+ return;
+ }
+ if (_conversationChoicesTable[1].msg == 0) {
+ setupConversationScript(0);
+ return;
+ }
+ }
+ ui_drawConversationPanel();
+ for (int i = 0; i < 4; ++i) {
+ drawString(_offscreenBuffer, 640, 16, 214, 42, 328 + i * 16, _conversationChoicesTable[_drawCharacterConversionRepeatCounter + i].msg);
+ }
+ updateScreenArea(_offscreenBuffer, 640, 0, 320, 0, 320, 640, 80);
+ _conversationAreaCleared = false;
+}
+
+void ToucheEngine::drawConversationString(int num, uint16 color) {
+ const int y = 328 + num * 16;
+ drawString(_offscreenBuffer, 640, 16, color, 42, y, _conversationChoicesTable[num + _drawCharacterConversionRepeatCounter].msg);
+ updateScreenArea(_offscreenBuffer, 640, 0, y, 0, y, 640, 16);
+}
+
+void ToucheEngine::clearConversationArea() {
+ ui_drawConversationPanel();
+ updateScreenArea(_offscreenBuffer, 640, 0, 320, 0, 320, 640, 80);
+ _conversationAreaCleared = true;
+}
+
+void ToucheEngine::setupConversationScript(int num) {
+ debugC(9, kDebugEngine, "ToucheEngine::setupConversationScript(%d)", num);
+ if (num < 5 && _conversationChoicesTable[num].msg != 0) {
+ num = _conversationChoicesTable[_drawCharacterConversionRepeatCounter + num].num;
+ KeyChar *key = &_keyCharsTable[_currentKeyCharNum];
+ key->scriptDataOffset = _programConversationTable[_currentConversation + num].offset;
+ key->scriptStackPtr = &key->scriptStackTable[39];
+ _drawCharacterConversionRepeatCounter = 0;
+ removeConversationChoice(num);
+ clearConversationArea();
+ }
+}
+
+void ToucheEngine::handleConversation() {
+ if (_conversationNum != 0) {
+ findConversationByNum(_conversationNum);
+ _conversationAreaCleared = false;
+ drawCharacterConversation();
+ _roomAreaRect.setHeight(320);
+ _hideInventoryTexts = true;
+ _conversationEnded = false;
+ _conversationNum = 0;
+ } else if (_hideInventoryTexts && _conversationAreaCleared) {
+ if (_keyCharsTable[_currentKeyCharNum].scriptDataOffset == 0) {
+ drawCharacterConversation();
+ }
+ } else if (!_conversationAreaCleared && _conversationChoicesUpdated) {
+ drawCharacterConversation();
+ }
+}
+
+static int getDirection(int x1, int y1, int z1, int x2, int y2, int z2) {
+ int ret = -1;
+ x2 -= x1;
+ y2 -= y1;
+ z2 -= z1;
+ if (x2 == 0 && y2 == 0 && z2 == 0) {
+ ret = -2;
+ } else {
+ if (ABS(x2) >= ABS(z2)) {
+ if (ABS(x2) > ABS(y2)) {
+ if (x2 > 0) {
+ ret = 0;
+ } else {
+ ret = 3;
+ }
+ } else {
+ if (y2 > 0) {
+ ret = 1;
+ } else {
+ ret = 2;
+ }
+ }
+ } else {
+ if (z2 != 0) {
+ if (z2 > 0) {
+ ret = 1;
+ } else {
+ ret = 2;
+ }
+ } else {
+ if (y2 > 0) {
+ ret = 1;
+ } else {
+ ret = 2;
+ }
+ }
+ }
+ }
+ return ret;
+}
+
+void ToucheEngine::buildWalkPointsList(int keyChar) {
+ debugC(9, kDebugEngine, "ToucheEngine::buildWalkPointsList(%d)", keyChar);
+ assert(keyChar >= 0 && keyChar < NUM_KEYCHARS);
+ KeyChar *key = &_keyCharsTable[keyChar];
+ uint16 curPos, pos1, pos2;
+ if (key->pointsDataNum & 0x8000) {
+ const ProgramWalkData *pwd = &_programWalkTable[(key->pointsDataNum & 0x7FFF)];
+ if (_programPointsTable[pwd->point1].priority < _programPointsTable[pwd->point2].priority) {
+ curPos = pwd->point1;
+ } else {
+ curPos = pwd->point2;
+ }
+ } else {
+ curPos = key->pointsDataNum;
+ }
+
+ int16 posNum = _programPointsTable[curPos].priority;
+ if (posNum == 32000) {
+ return;
+ }
+ key->walkPointsList[0] = curPos;
+ int16 walkPointsCount = 1;
+ do {
+ for (uint i = 0; i < _programWalkTable.size(); ++i) {
+ if ((_programWalkTable[i].point1 & 0x4000) == 0) {
+ pos1 = _programWalkTable[i].point1;
+ pos2 = _programWalkTable[i].point2;
+ if (pos1 == curPos && posNum > _programPointsTable[pos2].priority) {
+ curPos = pos2;
+ assert(walkPointsCount < 40);
+ key->walkPointsList[walkPointsCount] = curPos;
+ ++walkPointsCount;
+ posNum = _programPointsTable[pos2].priority;
+ break;
+ }
+ if (pos2 == curPos && posNum > _programPointsTable[pos1].priority) {
+ curPos = pos1;
+ assert(walkPointsCount < 40);
+ key->walkPointsList[walkPointsCount] = curPos;
+ ++walkPointsCount;
+ posNum = _programPointsTable[pos1].priority;
+ break;
+ }
+ }
+ }
+ } while (_programPointsTable[curPos].priority != 0);
+ assert(walkPointsCount < 40);
+ key->walkPointsList[walkPointsCount] = -1;
+
+ key->xPosPrev = _programPointsTable[curPos].x;
+ key->yPosPrev = _programPointsTable[curPos].y;
+ key->zPosPrev = _programPointsTable[curPos].z;
+ key->prevWalkDataNum = findWalkDataNum(curPos, -1);
+ key->walkPointsListCount = 0;
+ if (key->walkDataNum == -1) {
+ return;
+ }
+
+ pos1 = _programWalkTable[key->walkDataNum].point1;
+ pos2 = _programWalkTable[key->walkDataNum].point2;
+ if (key->pointsDataNum == pos1) {
+ if (key->walkPointsList[1] == pos2) {
+ ++key->walkPointsListCount;
+ }
+ return;
+ }
+ if (key->pointsDataNum == pos2) {
+ if (key->walkPointsList[1] == pos1) {
+ ++key->walkPointsListCount;
+ }
+ return;
+ }
+}
+
+int ToucheEngine::findWalkDataNum(int pointNum1, int pointNum2) {
+ debugC(9, kDebugEngine, "ToucheEngine::findWalkDataNum(%d, %d)", pointNum1, pointNum2);
+ if (pointNum1 != pointNum2) {
+ for (uint i = 0; i < _programWalkTable.size(); ++i) {
+ int p1 = _programWalkTable[i].point1 & 0xFFF;
+ int p2 = _programWalkTable[i].point2 & 0xFFF;
+ if (p1 == pointNum1) {
+ if (p2 == pointNum2 || pointNum2 == 10000) {
+ return i;
+ }
+ } else if (p2 == pointNum1) {
+ if (p1 == pointNum2 || pointNum2 == 10000) {
+ return i;
+ }
+ }
+ }
+ }
+ return -1;
+}
+
+void ToucheEngine::changeWalkPath(int num1, int num2, int16 val) {
+ debugC(9, kDebugEngine, "ToucheEngine::changeWalkPath(%d, %d)", num1, num2);
+ int num = findWalkDataNum(num1, num2);
+ if (num != -1) {
+ _programWalkTable[num].area1 = val;
+ }
+}
+
+void ToucheEngine::adjustKeyCharPosToWalkBox(KeyChar *key, int moveType) {
+ const ProgramWalkData *pwd = &_programWalkTable[key->walkDataNum];
+
+ const ProgramPointData *pts1 = &_programPointsTable[pwd->point1];
+ int16 x1 = pts1->x;
+ int16 y1 = pts1->y;
+ int16 z1 = pts1->z;
+
+ const ProgramPointData *pts2 = &_programPointsTable[pwd->point2];
+ int16 x2 = pts2->x;
+ int16 y2 = pts2->y;
+ int16 z2 = pts2->z;
+
+ int16 kx = key->xPos;
+ int16 ky = key->yPos;
+ int16 kz = key->zPos;
+
+ int16 dx = x2 - x1;
+ int16 dy = y2 - y1;
+ int16 dz = z2 - z1;
+
+ switch (moveType) {
+ case 0:
+ kx -= x1;
+ if (dx != 0) {
+ key->yPos = dy * kx / dx + y1;
+ key->zPos = dz * kx / dx + z1;
+ }
+ break;
+ case 1:
+ ky -= y1;
+ if (dy != 0) {
+ key->xPos = dx * ky / dy + x1;
+ key->zPos = dz * ky / dy + z1;
+ }
+ break;
+ case 2:
+ kz -= z1;
+ if (dz != 0) {
+ key->xPos = dx * kz / dz + x1;
+ key->yPos = dy * kz / dz + y1;
+ }
+ break;
+ }
+}
+
+void ToucheEngine::lockWalkPath(int num1, int num2) {
+ debugC(9, kDebugEngine, "ToucheEngine::lockWalkPath(%d, %d)", num1, num2);
+ const int num = findWalkDataNum(num1, num2);
+ if (num != -1) {
+ _programWalkTable[num].point1 |= 0x4000;
+ _programWalkTable[num].point2 |= 0x4000;
+ }
+}
+
+void ToucheEngine::unlockWalkPath(int num1, int num2) {
+ debugC(9, kDebugEngine, "ToucheEngine::unlockWalkPath(%d, %d)", num1, num2);
+ const int num = findWalkDataNum(num1, num2);
+ if (num != -1) {
+ _programWalkTable[num].point1 &= 0xFFF;
+ _programWalkTable[num].point2 &= 0xFFF;
+ }
+}
+
+void ToucheEngine::resetPointsData(int num) {
+ debugC(9, kDebugEngine, "ToucheEngine::resetPointsData(%d)", num);
+ for (uint i = 1; i < _programPointsTable.size(); ++i) {
+ _programPointsTable[i].priority = num;
+ }
+}
+
+bool ToucheEngine::sortPointsData(int num1, int num2) {
+ debugC(9, kDebugEngine, "ToucheEngine::sortPointsData(%d, %d)", num1, num2);
+ resetPointsData(32000);
+ if (num1 == -1) {
+ if (num2 == -1) {
+ return false;
+ }
+ _programPointsTable[num2].priority = 0;
+ } else {
+ const int md1 = _programWalkTable[num1].point1;
+ _programPointsTable[md1].priority = 0;
+ const int md2 = _programWalkTable[num1].point2;
+ _programPointsTable[md2].priority = 0;
+ }
+ bool quit = false;
+ int priority = 1;
+ while (!quit) {
+ quit = true;
+ for (uint i = 0; i < _programWalkTable.size(); ++i) {
+ const int md1 = _programWalkTable[i].point1;
+ const int md2 = _programWalkTable[i].point2;
+ if ((md1 & 0x4000) == 0) {
+ if (_programPointsTable[md1].priority == priority - 1 && _programPointsTable[md2].priority > priority) {
+ _programPointsTable[md2].priority = priority;
+ quit = false;
+ }
+ if (_programPointsTable[md2].priority == priority - 1 && _programPointsTable[md1].priority > priority) {
+ _programPointsTable[md1].priority = priority;
+ quit = false;
+ }
+ }
+ }
+ ++priority;
+ }
+ return true;
+}
+
+void ToucheEngine::updateKeyCharWalkPath(KeyChar *key, int16 dx, int16 dy, int16 dz) {
+ debugC(9, kDebugEngine, "ToucheEngine::updateKeyCharWalkPath(key=%d, dx=%d, dy=%d, dz=%d)", key - _keyCharsTable, dx, dy, dz);
+ if (key->walkDataNum == -1) {
+ return;
+ }
+ int16 kx = key->xPos;
+ int16 ky = key->yPos;
+ int16 kz = key->zPos;
+ if (kz != 160) {
+ if (dx != 0) {
+ dx = dx * kz / 160;
+ if (dx == 0) {
+ dx = 1;
+ }
+ }
+ if (dy != 0) {
+ dy = dy * kz / 160;
+ if (dy == 0) {
+ dy = 1;
+ }
+ }
+ if (dz != 0) {
+ dz = dz * kz / 160;
+ if (dz == 0) {
+ dz = 1;
+ }
+ }
+ }
+
+ int16 curDirection = key->facingDirection;
+ if (key->currentAnim > 1) {
+ if (dx != 0 || dy != 0 || dz != 0) {
+ if (curDirection == 3) {
+ key->xPos -= dx;
+ } else {
+ key->xPos += dx;
+ }
+ key->xPosPrev = key->xPos;
+ }
+ return;
+ }
+
+ int16 xpos, ypos, zpos, walkPoint1, walkPoint2, newDirection, incDx, incDy, incDz;
+ while (1) {
+ walkPoint1 = key->walkPointsList[key->walkPointsListCount];
+ walkPoint2 = key->walkPointsList[key->walkPointsListCount + 1];
+ key->currentWalkBox = walkPoint1;
+ if (walkPoint1 == -1) {
+ xpos = key->xPosPrev;
+ ypos = key->yPosPrev;
+ zpos = key->zPosPrev;
+ if (key->prevWalkDataNum != -1) {
+ key->walkDataNum = key->prevWalkDataNum;
+ key->prevWalkDataNum = -1;
+ }
+ } else {
+ xpos = _programPointsTable[walkPoint1].x;
+ ypos = _programPointsTable[walkPoint1].y;
+ zpos = _programPointsTable[walkPoint1].z;
+ }
+ newDirection = getDirection(kx, ky, kz, xpos, ypos, zpos);
+ if (newDirection < 0) {
+ newDirection = curDirection;
+ }
+ if (newDirection != curDirection) {
+ key->currentAnimCounter = 0;
+ key->facingDirection = newDirection;
+ return;
+ }
+ incDx = xpos - kx;
+ incDy = ypos - ky;
+ incDz = zpos - kz;
+ if (incDz != 0 || incDy != 0 || incDx != 0) {
+ break;
+ }
+ if (walkPoint1 == -1) {
+ if (key->currentAnim == 1) {
+ setKeyCharRandomFrame(key);
+ }
+ return;
+ }
+ key->prevPointsDataNum = key->pointsDataNum;
+ key->pointsDataNum = walkPoint1;
+ if (walkPoint2 == -1) {
+ key->walkPointsList[0] = -1;
+ key->walkPointsListCount = 0;
+ } else {
+ ++key->walkPointsListCount;
+ int16 walkDataNum = findWalkDataNum(walkPoint1, walkPoint2);
+ if (walkDataNum != -1) {
+ key->walkDataNum = walkDataNum;
+ }
+ }
+ }
+
+ if (key->currentAnim < 1) {
+ key->currentAnimCounter = 0;
+ key->currentAnim = 1;
+ if (dx == 0 && dy == 0 && dz == 0) {
+ return;
+ }
+ }
+
+ switch (newDirection) {
+ case 0:
+ case 3:
+ if (dx == 0) {
+ return;
+ }
+ if (newDirection == 3) {
+ dx = -dx;
+ }
+ if (ABS(dx) >= ABS(incDx)) {
+ if (walkPoint1 != -1) {
+ if (walkPoint2 == -1) {
+ newDirection = getDirection(xpos, ypos, zpos, key->xPosPrev, key->yPosPrev, key->zPosPrev);
+ if (key->prevWalkDataNum != -1) {
+ key->walkDataNum = key->prevWalkDataNum;
+ key->prevWalkDataNum = -1;
+ }
+ } else {
+ newDirection = getDirection(xpos, ypos, zpos, _programPointsTable[walkPoint2].x, _programPointsTable[walkPoint2].y, _programPointsTable[walkPoint2].z);
+ int16 walkDataNum = findWalkDataNum(walkPoint1, walkPoint2);
+ if (walkDataNum != -1) {
+ key->walkDataNum = walkDataNum;
+ }
+ }
+ if (newDirection == -2) {
+ key->xPos = xpos;
+ key->yPos = ypos;
+ key->zPos = zpos;
+ setKeyCharRandomFrame(key);
+ return;
+ }
+ if (newDirection < 0) {
+ newDirection = curDirection;
+ }
+ key->prevPointsDataNum = key->pointsDataNum;
+ key->pointsDataNum = walkPoint1;
+ ++key->walkPointsListCount;
+ if (newDirection != curDirection) {
+ key->facingDirection = newDirection;
+ key->currentAnimCounter = 0;
+ key->xPos = xpos;
+ key->yPos = ypos;
+ key->zPos = zpos;
+ return;
+ }
+ } else {
+ key->xPos = xpos;
+ key->yPos = ypos;
+ key->zPos = zpos;
+ return;
+ }
+ }
+ key->xPos += dx;
+ adjustKeyCharPosToWalkBox(key, 0);
+ break;
+ case 1:
+ case 2:
+ if (ABS(dz) >= ABS(incDz) && incDz != 0) {
+ if (walkPoint1 != -1) {
+ if (walkPoint2 == -1) {
+ newDirection = getDirection(xpos, ypos, zpos, key->xPosPrev, key->yPosPrev, key->zPosPrev);
+ } else {
+ newDirection = getDirection(xpos, ypos, zpos, _programPointsTable[walkPoint2].x, _programPointsTable[walkPoint2].y, _programPointsTable[walkPoint2].z);
+ int16 walkDataNum = findWalkDataNum(walkPoint1, walkPoint2);
+ if (walkDataNum != -1) {
+ key->walkDataNum = walkDataNum;
+ }
+ }
+ if (newDirection == -2) {
+ key->xPos = xpos;
+ key->yPos = ypos;
+ key->zPos = zpos;
+ setKeyCharRandomFrame(key);
+ return;
+ }
+ if (newDirection < 0) {
+ newDirection = curDirection;
+ }
+ key->prevPointsDataNum = key->pointsDataNum;
+ key->pointsDataNum = walkPoint1;
+ ++key->walkPointsListCount;
+ if (newDirection != curDirection) {
+ key->facingDirection = newDirection;
+ key->currentAnimCounter = 0;
+ key->xPos = xpos;
+ key->yPos = ypos;
+ key->zPos = zpos;
+ return;
+ }
+ } else {
+ key->xPos = xpos;
+ key->yPos = ypos;
+ key->zPos = zpos;
+ return;
+ }
+ }
+ if (incDz != 0) {
+ key->zPos += dz;
+ adjustKeyCharPosToWalkBox(key, 2);
+ } else {
+ if (ABS(dz) < ABS(incDy)) {
+ key->yPos += dz;
+ adjustKeyCharPosToWalkBox(key, 1);
+ } else {
+ key->xPos = xpos;
+ key->yPos = ypos;
+ key->zPos = zpos;
+ }
+ }
+ break;
+ }
+}
+
+void ToucheEngine::markWalkPoints(int keyChar) {
+ assert(keyChar >= 0 && keyChar < NUM_KEYCHARS);
+ KeyChar *key = &_keyCharsTable[keyChar];
+ int16 pointsDataNum = key->pointsDataNum;
+ resetPointsData(0);
+ if (pointsDataNum != -1) {
+ _programPointsTable[pointsDataNum].priority = 1;
+ bool quit = false;
+ while (!quit) {
+ quit = true;
+ for (uint i = 0; i < _programWalkTable.size(); ++i) {
+ int16 md1 = _programWalkTable[i].point1;
+ int16 md2 = _programWalkTable[i].point2;
+ if ((md1 & 0x4000) == 0) {
+ if (_programPointsTable[md1].priority != 0 && _programPointsTable[md2].priority == 0) {
+ _programPointsTable[md2].priority = 1;
+ quit = false;
+ }
+ if (_programPointsTable[md2].priority != 0 && _programPointsTable[md1].priority == 0) {
+ _programPointsTable[md1].priority = 1;
+ quit = false;
+ }
+ }
+ }
+ }
+ }
+}
+
+void ToucheEngine::buildWalkPath(int dstPosX, int dstPosY, int keyChar) {
+ debugC(9, kDebugEngine, "ToucheEngine::buildWalkPath(x=%d, y=%d, key=%d)", dstPosX, dstPosY, keyChar);
+ if (_currentEpisodeNum == 130) {
+ return;
+ }
+ markWalkPoints(keyChar);
+
+ int minDistance = 0x7D000000;
+ int minPointsDataNum = -1;
+ for (uint i = 1; i < _programPointsTable.size(); ++i) {
+ if (_programPointsTable[i].priority != 0) {
+ int dx = ABS<int>(_programPointsTable[i].x - dstPosX);
+ int dy = ABS<int>(_programPointsTable[i].y - dstPosY);
+ int distance = dx * dx + dy * dy;
+ if (distance < minDistance) {
+ minDistance = distance;
+ minPointsDataNum = i;
+ }
+ }
+ }
+
+ minDistance = 32000;
+ int minWalkDataNum = -1;
+ for (uint i = 0; i < _programWalkTable.size(); ++i) {
+ const ProgramWalkData *pwd = &_programWalkTable[i];
+ if ((pwd->point1 & 0x4000) == 0) {
+ int distance = 32000;
+ ProgramPointData *pts1 = &_programPointsTable[pwd->point1];
+ ProgramPointData *pts2 = &_programPointsTable[pwd->point2];
+ if (pts1->priority != 0) {
+ int dx = pts2->x - pts1->x;
+ int dy = pts2->y - pts1->y;
+ if (dx == 0) {
+ if (dstPosY > MIN(pts2->y, pts1->y) && dstPosY < MAX(pts2->y, pts1->y)) {
+ distance = ABS(dstPosX - pts1->x);
+ if (distance <= 100) {
+ distance *= distance;
+ }
+ }
+ } else if (dy == 0) {
+ if (dstPosX > MIN(pts2->x, pts1->x) && dstPosX < MAX(pts2->x, pts1->x)) {
+ distance = ABS(dstPosY - pts1->y);
+ if (distance <= 100) {
+ distance *= distance;
+ }
+ }
+ } else {
+ if (dstPosY > MIN(pts2->y, pts1->y) && dstPosY < MAX(pts2->y, pts1->y) &&
+ dstPosX > MIN(pts2->x, pts1->x) && dstPosX < MAX(pts2->x, pts1->x) ) {
+ distance = (dstPosY - pts1->y) * dx - (dstPosX - pts1->x) * dy;
+ distance = (dx * dx + dy * dy) / distance;
+ }
+ }
+ if (distance < minDistance) {
+ minDistance = distance;
+ minWalkDataNum = i;
+ }
+ }
+ }
+ }
+ if (!sortPointsData(minWalkDataNum, minPointsDataNum)) {
+ return;
+ }
+ int dstPosZ;
+ buildWalkPointsList(keyChar);
+ KeyChar *key = &_keyCharsTable[keyChar];
+ if (minWalkDataNum == -1) {
+ dstPosX = _programPointsTable[minPointsDataNum].x;
+ dstPosY = _programPointsTable[minPointsDataNum].y;
+ dstPosZ = _programPointsTable[minPointsDataNum].z;
+ } else {
+ ProgramWalkData *pwd = &_programWalkTable[minWalkDataNum];
+ ProgramPointData *pts1 = &_programPointsTable[pwd->point1];
+ ProgramPointData *pts2 = &_programPointsTable[pwd->point2];
+ int16 dx = pts2->x - pts1->x;
+ int16 dy = pts2->y - pts1->y;
+ int16 dz = pts2->z - pts1->z;
+ if (ABS(dy) > ABS(dx)) {
+ dstPosZ = pts2->z - (pts2->y - dstPosY) * dz / dy;
+ dstPosX = pts2->x - (pts2->y - dstPosY) * dx / dy;
+ } else {
+ dstPosZ = pts2->z - (pts2->x - dstPosX) * dz / dx;
+ dstPosY = pts2->y - (pts2->x - dstPosX) * dy / dx;
+ }
+ if (key->walkDataNum == key->prevWalkDataNum && key->walkPointsList[1] == -1) {
+ if (key->walkPointsList[0] == _programWalkTable[minWalkDataNum].point1 || key->walkPointsList[0] == _programWalkTable[minWalkDataNum].point2) {
+ ++key->walkPointsListCount;
+ }
+ }
+ }
+ key->prevWalkDataNum = minWalkDataNum;
+ key->xPosPrev = dstPosX;
+ key->yPosPrev = dstPosY;
+ key->zPosPrev = dstPosZ;
+ if (_flagsTable[902] != 0) {
+ Graphics::fillRect(_backdropBuffer, _currentBitmapWidth, dstPosX, dstPosY, 4, 4, 0xFC);
+ }
+}
+
+void ToucheEngine::addToAnimationTable(int num, int posNum, int keyChar, int delayCounter) {
+ for (int i = 0; i < NUM_ANIMATION_ENTRIES; ++i) {
+ AnimationEntry *anim = &_animationTable[i];
+ if (anim->num == 0) {
+ anim->num = num;
+ anim->delayCounter = delayCounter;
+ anim->posNum = posNum;
+ int16 xPos, yPos, x2Pos, y2Pos;
+ if (posNum >= 0) {
+ assert(posNum >= 0 && posNum < NUM_KEYCHARS);
+ xPos = _keyCharsTable[posNum].xPos;
+ yPos = _keyCharsTable[posNum].yPos - 50;
+ } else {
+ posNum = -posNum;
+ xPos = _programPointsTable[posNum].x;
+ yPos = _programPointsTable[posNum].y;
+ }
+ xPos -= _flagsTable[614];
+ yPos -= _flagsTable[615];
+ assert(keyChar >= 0 && keyChar < NUM_KEYCHARS);
+ x2Pos = _keyCharsTable[keyChar].xPos - _flagsTable[614];
+ y2Pos = _keyCharsTable[keyChar].yPos - _flagsTable[615] - 50;
+ xPos -= x2Pos;
+ yPos -= y2Pos;
+ xPos /= 8;
+ yPos /= 8;
+ anim->x = x2Pos;
+ anim->y = y2Pos;
+ anim->dx = xPos;
+ anim->dy = yPos;
+ anim->displayCounter = 8;
+ anim->displayRect.left = -1;
+ }
+ }
+}
+
+void ToucheEngine::copyAnimationImage(int dstX, int dstY, int w, int h, const uint8 *src, int srcX, int srcY, int fillColor) {
+ Area copyRegion(dstX, dstY, w, h);
+ copyRegion.srcX = srcX;
+ copyRegion.srcY = srcY;
+ if (copyRegion.clip(_screenRect)) {
+ if (fillColor != -1) {
+ Graphics::copyMask(_offscreenBuffer, 640, copyRegion.r.left, copyRegion.r.top,
+ src, 58, copyRegion.srcX, copyRegion.srcY,
+ copyRegion.r.width(), copyRegion.r.height(),
+ (uint8)fillColor);
+ } else {
+ Graphics::copyRect(_offscreenBuffer, 640, copyRegion.r.left, copyRegion.r.top,
+ src, 58, copyRegion.srcX, copyRegion.srcY,
+ copyRegion.r.width(), copyRegion.r.height(),
+ Graphics::kTransparent);
+ }
+ }
+}
+
+void ToucheEngine::drawAnimationImage(AnimationEntry *anim) {
+ if (anim->displayRect.left != -1) {
+ addToDirtyRect(anim->displayRect);
+ }
+ int x = anim->x;
+ int y = anim->y;
+ int dx = -anim->dx;
+ int dy = -anim->dy;
+
+ int displayRectX1 = 30000;
+ int displayRectY1 = 30000;
+ int displayRectX2 = -30000;
+ int displayRectY2 = -30000;
+
+ dx /= 3;
+ dy /= 3;
+
+ res_loadImage(anim->num, _iconData);
+ int color = 0xCF;
+
+ x += dx * 5 - 29;
+ y += dy * 5 - 21;
+ dx = -dx;
+ dy = -dy;
+ for (int i = 0; i < 6; ++i) {
+ if (i == 5) {
+ color = -1;
+ }
+ copyAnimationImage(x, y, 58, 42, _iconData, 0, 0, color);
+ --color;
+ displayRectX1 = MIN(x, displayRectX1);
+ displayRectX2 = MAX(x, displayRectX2);
+ displayRectY1 = MIN(y, displayRectY1);
+ displayRectY2 = MAX(y, displayRectY2);
+ x += dx;
+ y += dy;
+ }
+ anim->displayRect = Common::Rect(displayRectX1, displayRectY1, displayRectX2 + 58, displayRectY2 + 42);
+// if (rectClip(&_roomAreaRect, &anim->displayRect)) {
+// addToDirtyRect(&anim->displayRect);
+// }
+}
+
+void ToucheEngine::processAnimationTable() {
+ for (int i = 0; i < NUM_ANIMATION_ENTRIES; ++i) {
+ AnimationEntry *anim = &_animationTable[i];
+ if (anim->num != 0) {
+ if (anim->displayCounter == 0) {
+ anim->num = 0;
+ if (anim->displayRect.left != -1) {
+ addToDirtyRect(anim->displayRect);
+ }
+ } else {
+ if (anim->delayCounter != 0) {
+ --anim->delayCounter;
+ } else {
+ anim->x += anim->dx;
+ anim->y += anim->dy;
+ drawAnimationImage(anim);
+ --anim->displayCounter;
+ }
+ }
+ }
+ }
+}
+
+void ToucheEngine::clearAnimationTable() {
+ memset(_animationTable, 0, sizeof(_animationTable));
+}
+
+void ToucheEngine::addToDirtyRect(const Common::Rect &r) {
+ // XXX
+}
+
+void ToucheEngine::clearDirtyRects() {
+ // XXX
+}
+
+void ToucheEngine::setPalette(int firstColor, int colorCount, int rScale, int gScale, int bScale) {
+ uint8 pal[256 * 4];
+ for (int i = firstColor; i < firstColor + colorCount; ++i) {
+ int r = _paletteBuffer[i * 4 + 0];
+ r = (r * rScale) >> 8;
+ pal[i * 4 + 0] = (uint8)r;
+
+ int g = _paletteBuffer[i * 4 + 1];
+ g = (g * gScale) >> 8;
+ pal[i * 4 + 1] = (uint8)g;
+
+ int b = _paletteBuffer[i * 4 + 2];
+ b = (b * bScale) >> 8;
+ pal[i * 4 + 2] = (uint8)b;
+
+ pal[i * 4 + 3] = 0;
+ }
+ _system->setPalette(&pal[firstColor * 4], firstColor, colorCount);
+}
+
+void ToucheEngine::copyPaletteColor(int srcColorIndex, int dstColorIndex) {
+ memcpy(&_paletteBuffer[dstColorIndex * 4], &_paletteBuffer[srcColorIndex * 4], 4);
+}
+
+void ToucheEngine::updateScreenArea(const uint8 *src, int srcPitch, int srcX, int srcY, int dstX, int dstY, int w, int h) {
+ _system->copyRectToScreen(src + srcY * srcPitch + srcX, srcPitch, dstX, dstY, w, h);
+ _system->updateScreen();
+}
+
+void ToucheEngine::updateEntireScreen() {
+ int h = (_flagsTable[606] != 0) ? 400 : 352;
+ _system->copyRectToScreen(_offscreenBuffer, 640, 0, 0, 640, h);
+ _system->updateScreen();
+}
+
+void ToucheEngine::updateDirtyScreenAreas() {
+ // XXX
+ updateScreenArea(_offscreenBuffer, 640, 0, 0, 0, 0, 640, 400);
+ if (_fullRedrawCounter) {
+// updateEntireScreen();
+ --_fullRedrawCounter;
+ } else {
+// for (int i = 0; i < _dirtyRectsCount; ++i) {
+// Common::Rect *r = &_dirtyRects[i];
+// updateScreenArea(_offscreenBuffer, 640, r->x, r->y, r->x, r->y, r->w, r->h);
+// }
+ if (_redrawScreenCounter1) {
+ --_redrawScreenCounter1;
+// updateScreenArea(_offscreenBuffer, 640, _cursorObjectRect.x, _cursorObjectRect.y, _cursorObjectRect.x, _cursorObjectRect.y, _cursorObjectRect.w, _cursorObjectRect.h);
+ }
+ }
+}
+
+void ToucheEngine::updatePalette() {
+ _system->setPalette(_paletteBuffer, 0, 256);
+}
+
+} // namespace Touche
diff --git a/engines/touche/touche.h b/engines/touche/touche.h
new file mode 100644
index 0000000000..d7dd188ac7
--- /dev/null
+++ b/engines/touche/touche.h
@@ -0,0 +1,778 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id: $
+ *
+ */
+
+#ifndef TOUCHE_ENGINE_H
+#define TOUCHE_ENGINE_H
+
+#include "common/array.h"
+#include "common/endian.h"
+#include "common/file.h"
+#include "common/rect.h"
+#include "common/util.h"
+
+#include "sound/mixer.h"
+
+#include "engines/engine.h"
+
+namespace Touche {
+
+struct Area {
+ Common::Rect r;
+ int16 srcX, srcY;
+
+ Area() {
+ srcX = srcY = 0;
+ }
+
+ Area(int16 x, int16 y, int16 w, int16 h) {
+ r = Common::Rect(x, y, x + w, y + h);
+ srcX = srcY = 0;
+ }
+
+ bool clip(const Common::Rect &rect) {
+ const int dx = r.left - rect.left;
+ if (dx < 0) {
+ srcX -= dx;
+ }
+ const int dy = r.top - rect.top;
+ if (dy < 0) {
+ srcY -= dy;
+ }
+ if (rect.left > r.left) {
+ r.left = rect.left;
+ }
+ if (rect.top > r.top) {
+ r.top = rect.top;
+ }
+ if (rect.right < r.right) {
+ r.right = rect.right;
+ }
+ if (rect.bottom < r.bottom) {
+ r.bottom = rect.bottom;
+ }
+ return (r.right > r.left && r.bottom > r.top);
+ }
+};
+
+struct KeyChar {
+ uint16 num;
+ uint16 flags;
+ int16 currentAnimCounter;
+ int16 strNum;
+ int16 walkDataNum;
+ int16 spriteNum;
+ Common::Rect prevBoundingRect;
+ Common::Rect boundingRect;
+ int16 xPos;
+ int16 yPos;
+ int16 zPos;
+ int16 xPosPrev;
+ int16 yPosPrev;
+ int16 zPosPrev;
+ int16 prevWalkDataNum;
+ uint16 textColor;
+ int16 inventoryItems[4];
+ int16 money;
+ int16 pointsDataNum;
+ int16 currentWalkBox;
+ uint16 prevPointsDataNum;
+ int16 currentAnim;
+ int16 facingDirection;
+ int16 currentAnimSpeed;
+ int16 framesList[16];
+ int16 framesListCount;
+ int16 currentFrame;
+ int16 anim1Start;
+ int16 anim1Count;
+ int16 anim2Start;
+ int16 anim2Count;
+ int16 anim3Start;
+ int16 anim3Count;
+ int16 followingKeyCharNum;
+ int16 followingKeyCharPos;
+ uint16 sequenceDataIndex;
+ uint16 sequenceDataOffset;
+ int16 walkPointsListCount;
+ int16 walkPointsList[40];
+ uint16 scriptDataStartOffset;
+ uint16 scriptDataOffset;
+ int16 *scriptStackPtr;
+ int16 delay;
+ int16 waitingKeyChar;
+ int16 waitingKeyCharPosTable[3];
+ int16 scriptStackTable[40];
+};
+
+struct Script {
+ uint8 opcodeNum;
+ uint32 dataOffset;
+ int16 keyCharNum;
+ uint8 *dataPtr;
+ int16 *stackDataPtr;
+ int16 *stackDataBasePtr;
+ int16 quitFlag;
+ int16 stackDataTable[500];
+
+ void init(uint8 *data) {
+ dataPtr = data;
+ stackDataPtr = stackDataBasePtr = &stackDataTable[499];
+ dataOffset = 0;
+ quitFlag = 0;
+ }
+
+ uint8 readByte(uint32 offs) const {
+ return *(dataPtr + offs);
+ }
+
+ int16 readWord(uint32 offs) const {
+ return READ_LE_UINT16(dataPtr + offs);
+ }
+
+ uint8 readNextByte() {
+ uint8 val = readByte(dataOffset);
+ ++dataOffset;
+ return val;
+ }
+
+ int16 readNextWord() {
+ int16 val = readWord(dataOffset);
+ dataOffset += 2;
+ return val;
+ }
+};
+
+struct TalkEntry {
+ int16 otherKeyChar;
+ int16 talkingKeyChar;
+ int16 num;
+};
+
+struct ConversationChoice {
+ int16 num;
+ int16 msg;
+};
+
+struct AnimationEntry {
+ int16 num;
+ int16 x;
+ int16 y;
+ int16 dx;
+ int16 dy;
+ int16 posNum;
+ int16 delayCounter;
+ int16 displayCounter;
+ Common::Rect displayRect;
+};
+
+struct SequenceEntry {
+ int16 sprNum;
+ int16 seqNum;
+};
+
+struct SpriteData {
+ uint32 size;
+ uint8 *ptr;
+ uint16 bitmapWidth;
+ uint16 bitmapHeight;
+ uint16 w;
+ uint16 h;
+};
+
+struct MidiContext {
+ uint8 unk2;
+ uint8 unkA;
+ uint8 unkB;
+ uint16 volume;
+ uint8 unkF;
+ uint16 currentVolume;
+};
+
+struct ProgramPointData {
+ int16 x, y, z;
+ int16 priority;
+};
+
+struct ProgramWalkData {
+ int16 point1;
+ int16 point2;
+ int16 clippingRect;
+ int16 area1;
+ int16 area2;
+};
+
+struct ProgramAreaData {
+ Area area;
+ int16 id;
+ int16 state;
+ int16 animCount;
+ int16 animNext;
+};
+
+struct ProgramBackgroundData {
+ Area area;
+ int16 type;
+ int16 offset;
+ int16 scaleMul;
+ int16 scaleDiv;
+};
+
+struct ProgramHitBoxData {
+ int16 item;
+ int16 talk;
+ uint16 state;
+ int16 str;
+ int16 defaultStr;
+ int16 actions[8];
+ Common::Rect hitBoxes[2];
+};
+
+struct ProgramActionScriptOffsetData {
+ int16 object1;
+ int16 action;
+ int16 object2;
+ uint16 offset;
+};
+
+struct ProgramKeyCharScriptOffsetData {
+ int16 keyChar;
+ uint16 offset;
+};
+
+struct ProgramConversationData {
+ int16 num;
+ uint16 offset;
+ int16 msg;
+};
+
+enum {
+ kDebugEngine = 1 << 0,
+ kDebugGraphics = 1 << 1,
+ kDebugResource = 1 << 2,
+ kDebugOpcodes = 1 << 3,
+ kDebugUserIntf = 1 << 4
+};
+
+enum ResourceType {
+ kResourceTypeRoomImage = 0,
+ kResourceTypeSequence,
+ kResourceTypeSpriteImage,
+ kResourceTypeIconImage,
+ kResourceTypeRoomInfo,
+ kResourceTypeProgram,
+ kResourceTypeMusic,
+ kResourceTypeSound
+};
+
+enum TalkMode {
+ kTalkModeTextOnly = 0,
+ kTalkModeVoiceOnly,
+ kTalkModeVoiceAndText,
+ kTalkModeCount
+};
+
+enum ScriptFlag {
+ kScriptStopped = 1 << 0,
+ kScriptPaused = 1 << 1
+};
+
+class ToucheEngine: public Engine {
+public:
+
+ enum {
+ NUM_OPCODES = 135,
+ NUM_FLAGS = 2000,
+ NUM_KEYCHARS = 32,
+ NUM_AREAS = 10,
+ NUM_SPRITES = 5,
+ NUM_SEQUENCES = 7,
+ NUM_CONVERSATION_CHOICES = 40,
+ NUM_TALK_ENTRIES = 16,
+ NUM_ANIMATION_ENTRIES = 4,
+ NUM_INVENTORY_ITEMS = 100,
+ NUM_DIRTY_RECTS = 50,
+ NUM_GAMESTATE_FILES = 100
+ };
+
+ typedef void (ToucheEngine::*OpcodeProc)();
+
+ ToucheEngine(OSystem *system, Common::Language language);
+ virtual ~ToucheEngine();
+
+ virtual int init();
+ virtual int go();
+
+protected:
+
+ void restart();
+ void mainLoop();
+ void processEvents();
+ void runCycle();
+ int16 getRandomNumber(int max);
+ void changePaletteRange();
+ void playSoundInRange();
+ void resetSortedKeyCharsTable();
+ void setupEpisode(int num);
+ void setupNewEpisode();
+ void drawKeyChar(KeyChar *key);
+ void sortKeyChars();
+ void runKeyCharScript(KeyChar *key);
+ void runCurrentKeyCharScript(int mode);
+ void executeScriptOpcode(int16 param);
+ void initKeyChars(int keyChar);
+ void setKeyCharTextColor(int keyChar, uint16 color);
+ void waitForKeyCharPosition(int keyChar);
+ void setKeyCharBox(int keyChar, int value);
+ void setKeyCharFrame(int keyChar, int16 type, int16 value1, int16 value2);
+ void setKeyCharFacingDirection(int keyChar, int16 dir);
+ void initKeyCharScript(int keyChar, int16 spriteNum, int16 seqDataIndex, int16 seqDataOffs);
+ uint16 findProgramKeyCharScriptOffset(int keyChar) const;
+ bool scrollRoom(int keyChar);
+ void drawIcon(int x, int y, int num);
+ void centerScreenToKeyChar(int keyChar);
+ void waitForKeyCharsSet();
+ void redrawRoom();
+ void fadePalette(int firstColor, int lastColor, int scale, int scaleInc, int fadingStepsCount);
+ void fadePaletteFromFlags();
+ void moveKeyChar(uint8 *dst, int dstPitch, KeyChar *key);
+ void changeKeyCharFrame(KeyChar *key, int keyChar);
+ void setKeyCharRandomFrame(KeyChar *key);
+ void setKeyCharMoney();
+ const char *getString(int num) const;
+ int getStringWidth(int m, int num) const;
+ void drawString(uint8 *dst, int dstPitch, int m, uint16 color, int x, int y, int16 num);
+ void drawGameString(int m, uint16 color, int x1, int y, const char *str);
+ int restartKeyCharScriptOnAction(int action, int obj1, int obj2);
+ void buildSpriteScalingTable(int z1, int z2);
+ void drawSpriteOnBackdrop(int num, int x, int y);
+ void updateTalkFrames(int keyChar);
+ void setKeyCharTalkingFrame(int keyChar);
+ void lockUnlockHitBox(int num, int lock);
+ void drawHitBoxes();
+ void setCursor(int num);
+ void updateCursor(int num);
+ void handleMouseButtonClicked();
+ void handleMouseButtonPressed();
+ void handleMouseInput(int flag);
+ void handleMouseInputRoomArea(int flag);
+ void handleMouseInputInventoryArea(int flag);
+ void scrollScreenToPos(int num);
+ void clearRoomArea();
+ void startNewMusic();
+ void startNewSound();
+ void updateSpeech();
+ int handleActionMenuUnderCursor(const int16 *actions, int offs, int y, int str);
+
+ void redrawBackground();
+ void processAreaTable();
+ void clearAreaTable();
+ void addToAreaTable(const Area *area);
+ void addRoomArea(int num, int flag);
+ void updateRoomAreas(int num, int flags);
+ void setRoomAreaState(int num, uint16 state);
+ void findAndRedrawRoomRegion(int num);
+ void updateRoomRegions();
+ void redrawRoomRegion(int num, bool markForRedraw);
+
+ void initInventoryObjectsTable();
+ void initInventoryLists();
+ void drawInventory(int index, int flag);
+ void drawAmountOfMoneyInInventory();
+ void packInventoryItems(int index);
+ void appendItemToInventoryList(int index);
+ void addItemToInventory(int inventory, int16 item);
+ void removeItemFromInventory(int inventory, int16 item);
+ void changeInventoryItemState(int flag, int itemNum, int itemRnd, int inventoryItem);
+
+ void resetTalkingVars();
+ int updateKeyCharTalk(int pauseFlag);
+ const char *formatTalkText(int mode, int *y, int *h, const char *text);
+ void addToTalkTable(int talkingKeyChar, int num, int otherKeyChar);
+ void removeFromTalkTable(int keyChar);
+ void addConversationChoice(int16 num);
+ void removeConversationChoice(int16 num);
+ void runConversationScript(uint16 offset);
+ void findConversationByNum(int16 num);
+ void clearConversationChoices();
+ void drawCharacterConversationRepeat2();
+ void drawCharacterConversationRepeat();
+ void drawCharacterConversation();
+ void drawConversationString(int num, uint16 color);
+ void clearConversationArea();
+ void setupConversationScript(int num);
+ void handleConversation();
+
+ void buildWalkPointsList(int keyChar);
+ int findWalkDataNum(int pointNum1, int pointNum2);
+ void changeWalkPath(int num1, int num2, int16 val);
+ void adjustKeyCharPosToWalkBox(KeyChar *key, int moveType);
+ void lockWalkPath(int num1, int num2);
+ void unlockWalkPath(int num1, int num2);
+ void resetPointsData(int num);
+ bool sortPointsData(int num1, int num2);
+ void updateKeyCharWalkPath(KeyChar *key, int16 dx, int16 dy, int16 dz);
+ void markWalkPoints(int keyChar);
+ void buildWalkPath(int dstPosX, int dstPosY, int keyChar);
+
+ void addToAnimationTable(int num, int posNum, int keyChar, int delayCounter);
+ void copyAnimationImage(int dstX, int dstY, int w, int h, const uint8 *src, int srcX, int srcY, int fillColor);
+ void drawAnimationImage(AnimationEntry *anim);
+ void processAnimationTable();
+ void clearAnimationTable();
+
+ void addToDirtyRect(const Common::Rect &r);
+ void clearDirtyRects();
+ void setPalette(int firstColor, int colorCount, int redScale, int greenScale, int blueScale);
+ void copyPaletteColor(int srcColorIndex, int dstColorIndex);
+ void updateScreenArea(const uint8 *src, int srcPitch, int srcX, int srcY, int dstX, int dstY, int w, int h);
+ void updateEntireScreen();
+ void updateDirtyScreenAreas();
+ void updatePalette();
+
+ void saveGameStateData(Common::WriteStream *stream);
+ void loadGameStateData(Common::ReadStream *stream);
+ bool saveGameState(int num, const char *description);
+ bool loadGameState(int num, const char *description);
+ void readGameStateDescription(int num, char *description, int len);
+ void generateGameStateFileName(int num, char *dst, int len, bool prefixOnly = false) const;
+
+ void op_nop();
+ void op_jnz();
+ void op_jz();
+ void op_jmp();
+ void op_true();
+ void op_false();
+ void op_push();
+ void op_testFalse();
+ void op_add();
+ void op_sub();
+ void op_mul();
+ void op_div();
+ void op_mod();
+ void op_and();
+ void op_or();
+ void op_not();
+ void op_testGreater();
+ void op_testEquals();
+ void op_testLower();
+ void op_fetchScriptWord();
+ void op_testGreaterOrEquals();
+ void op_testLowerOrEquals();
+ void op_testNotEquals();
+ void op_endConversation();
+ void op_stopScript();
+ void op_getFlag();
+ void op_setFlag();
+ void op_fetchScriptByte();
+ void op_getScriptValue();
+ void op_setScriptValue();
+ void op_getKeyCharWalkBox();
+ void op_startSound();
+ void op_initKeyCharTalk();
+ void op_loadRoom();
+ void op_updateRoom();
+ void op_startTalk();
+ void op_loadSprite();
+ void op_loadSequence();
+ void op_setKeyCharBox();
+ void op_initKeyCharScript();
+ void op_setKeyCharFrame();
+ void op_setKeyCharDirection();
+ void op_clearConversationChoices();
+ void op_addConversationChoice();
+ void op_removeConversationChoice();
+ void op_getInventoryItem();
+ void op_setInventoryItem();
+ void op_startEpisode();
+ void op_setConversationNum();
+ void op_enableInventoryItem();
+ void op_enableInput();
+ void op_disableInput();
+ void op_faceKeyChar();
+ void op_getKeyCharCurrentAnim();
+ void op_getCurrentKeyChar();
+ void op_isKeyCharActive();
+ void op_setPalette();
+ void op_changeWalkPath();
+ void op_lockWalkPath();
+ void op_initializeKeyChar();
+ void op_setupWaitingKeyChars();
+ void op_updateRoomAreas();
+ void op_unlockWalkPath();
+ void op_addItemToInventoryAndRedraw();
+ void op_giveItemTo();
+ void op_resetHitBoxes();
+ void op_fadePalette();
+ void op_disableInventoryItem();
+ void op_getInventoryItemFlags();
+ void op_drawInventory();
+ void op_stopKeyCharScript();
+ void op_restartKeyCharScript();
+ void op_getKeyCharCurrentWalkBox();
+ void op_getKeyCharPointsDataNum();
+ void op_setupFollowingKeyChar();
+ void op_startAnimation();
+ void op_setKeyCharTextColor();
+ void op_startMusic();
+ void op_copyPaletteColor();
+ void op_delay();
+ void op_lockHitBox();
+ void op_removeItemFromInventory();
+ void op_unlockHitBox();
+ void op_addRoomArea();
+ void op_setKeyCharFlags();
+ void op_unsetKeyCharFlags();
+ void op_loadVoice();
+ void op_drawSpriteOnBackdrop();
+ void op_startPaletteFadeIn();
+ void op_startPaletteFadeOut();
+ void op_setRoomAreaState();
+
+ void res_openDataFile();
+ void res_closeDataFile();
+ void res_allocateTables();
+ void res_deallocateTables();
+ uint32 res_getDataOffset(ResourceType type, int num, uint32 *size = NULL);
+ void res_loadSpriteImage(int num, uint8 *dst);
+ void res_loadProgram(int num);
+ void res_decodeProgramData();
+ void res_loadRoom(int num);
+ void res_loadSprite(int num, int index);
+ void res_loadSequence(int num, int index);
+ void res_decodeScanLineImageRLE(uint8 *dst, int lineWidth);
+ void res_loadBackdrop();
+ void res_loadImage(int num, uint8 *dst);
+ void res_loadImageHelper(uint8 *imgData, int imgWidth, int imgHeight);
+ void res_loadSound(int flag, int num);
+ void res_loadMusic(int num);
+ void res_loadSpeech(int num);
+ void res_loadSpeechSegment(int num);
+ void res_stopSpeech();
+
+ bool ui_processEvents();
+ void ui_drawButtonBorders(const Common::Rect *r, int count);
+ void ui_drawMusicVolumeBar();
+ void ui_drawTalkMode();
+ void ui_drawAllBorders();
+ void ui_drawSaveGamesList(int page);
+ void ui_drawSaveLoadMenu(int page, int saveOrLoad);
+ int ui_getButtonPressed(const Common::Rect *r, int count) const;
+ void ui_drawButtonText(const int16 *texts, const Common::Rect *r, int count, bool centerTexts);
+ void ui_drawArrow(int x, int y, int dx, uint8 color);
+ void ui_drawOptionsMenu();
+ void ui_drawCurrentGameStateDescription();
+ int ui_handleSaveLoad(int saveOrLoad);
+ void ui_handleOptions(int forceDisplay);
+ void ui_drawActionsPanel(int dstX, int dstY, int deltaX, int deltaY);
+ void ui_drawConversationPanelBorder(int dstY, int srcX, int srcY);
+ void ui_drawConversationPanel();
+ void ui_printStatusString(const char *str);
+ void ui_clearStatusString();
+ int ui_displayQuitDialog();
+ void ui_displayTextMode(int str);
+
+
+ Common::Language _language;
+ Common::RandomSource _rnd;
+
+ Common::Point _inp_mousePos;
+ bool _inp_mouseButtonClicked;
+ bool _inp_mouseButtonPressed;
+ int _disabledInputCounter;
+ bool _hideInventoryTexts;
+
+ bool _displayQuitDialog;
+ int _saveLoadCurrentPage;
+ int _saveLoadCurrentSlot;
+ bool _saveLoadMarks[NUM_GAMESTATE_FILES];
+ char _saveLoadCurrentDescription[33];
+ int _saveLoadCurrentDescriptionLen;
+
+ int _defaultSoundPriority;
+ int _newMusicNum;
+ int _currentMusicNum;
+ int _newSoundNum;
+ int _newSoundDelay;
+ int _newSoundPriority;
+ int _playSoundCounter;
+ Audio::SoundHandle _sfxHandle;
+ Audio::SoundHandle _speechHandle;
+ MidiContext _snd_midiContext;
+
+ int16 _inventoryList1[101];
+ int16 _inventoryList2[101];
+ int16 _inventoryList3[7];
+ int16 *_inventoryListPtrs[3];
+ int16 _inventoryListCount[9];
+ int16 _inventoryItemsInfoTable[NUM_INVENTORY_ITEMS];
+ int16 *_inventoryVar1;
+ int16 *_inventoryVar2;
+ int _currentCursorObject;
+
+ int _talkTextMode;
+ int _talkListEnd;
+ int _talkListCurrent;
+ bool _talkTextRectDefined;
+ bool _talkTextDisplayed;
+ bool _talkTextInitialized;
+ bool _skipTalkText;
+ int _talkTextSpeed;
+ int _keyCharTalkCounter;
+ int _talkTableLastTalkingKeyChar;
+ int _talkTableLastOtherKeyChar;
+ int _talkTableLastStringNum;
+ int _objectDescriptionNum;
+ char _talkTextBuffer[200];
+ TalkEntry _talkTable[NUM_TALK_ENTRIES];
+
+ bool _conversationChoicesUpdated;
+ int _conversationReplyNum;
+ bool _conversationEnded;
+ int _conversationNum;
+ int _drawCharacterConversionRepeatCounter;
+ int _currentConversation;
+ bool _disableConversationScript;
+ bool _conversationAreaCleared;
+ ConversationChoice _conversationChoicesTable[NUM_CONVERSATION_CHOICES];
+
+ int16 _flagsTable[NUM_FLAGS];
+ KeyChar _keyCharsTable[NUM_KEYCHARS];
+ KeyChar *_sortedKeyCharsTable[NUM_KEYCHARS];
+ int _currentKeyCharNum;
+
+ int _newEpisodeNum;
+ int _currentEpisodeNum;
+
+ Area _areaTable[NUM_AREAS];
+ int _areaTableCount;
+
+ int _currentAmountOfMoney;
+ int _giveItemToKeyCharNum;
+ int _giveItemToObjectNum;
+ int _giveItemToCounter;
+ int _currentRoomNum;
+ int _waitingSetKeyCharNum1;
+ int _waitingSetKeyCharNum2;
+ int _waitingSetKeyCharNum3;
+ uint8 _updatedRoomAreasTable[200];
+ Common::Rect _moveKeyCharRect;
+ Common::Point _screenOffset;
+ int _currentObjectNum;
+ int _processRandomPaletteCounter;
+ int16 _spriteScalingIndex[1000];
+ int16 _spriteScalingTable[1000];
+
+ bool _fastWalkMode;
+
+ AnimationEntry _animationTable[NUM_ANIMATION_ENTRIES];
+
+ Script _script;
+
+ Common::File _fData;
+ Common::File _fSpeech[2];
+ int _compressedSpeechData;
+
+ uint8 *_textData;
+ uint8 *_backdropBuffer;
+ uint8 *_menuKitData;
+ uint8 *_convKitData;
+ uint8 *_sequenceDataTable[5];
+ uint8 *_programData;
+ uint32 _programDataSize;
+ uint8 *_mouseData;
+ uint8 *_iconData;
+
+ SequenceEntry _sequenceEntryTable[NUM_SEQUENCES];
+ int _currentBitmapWidth;
+ int _currentBitmapHeight;
+ int _currentImageWidth;
+ int _currentImageHeight;
+ bool _speechPlaying;
+ int _roomWidth;
+
+ uint8 *_programTextDataPtr;
+ Common::Array<Common::Rect> _programRectsTable;
+ Common::Array<ProgramPointData> _programPointsTable;
+ Common::Array<ProgramWalkData> _programWalkTable;
+ Common::Array<ProgramAreaData> _programAreaTable;
+ Common::Array<ProgramBackgroundData> _programBackgroundTable;
+ Common::Array<ProgramHitBoxData> _programHitBoxTable;
+ Common::Array<ProgramActionScriptOffsetData> _programActionScriptOffsetTable;
+ Common::Array<ProgramKeyCharScriptOffsetData> _programKeyCharScriptOffsetTable;
+ Common::Array<ProgramConversationData> _programConversationTable;
+ Common::Rect _cursorObjectRect;
+ Common::Rect _talkTextRect, _talkTextRect2;
+ Common::Rect _screenRect;
+ Common::Rect _roomAreaRect;
+
+ bool _roomNeedRedraw;
+ int _fullRedrawCounter;
+ int _redrawScreenCounter1;
+ uint8 *_offscreenBuffer;
+ uint8 _paletteBuffer[256 * 4];
+
+ static OpcodeProc _opcodesTable[NUM_OPCODES];
+ static SpriteData _spritesTable[NUM_SPRITES];
+ static const uint8 _directionsTable[];
+ static char _saveLoadDescriptionsTable[10][33];
+ static const Common::Rect _inventoryAreasTable[13];
+};
+
+/*
+ FLAGS LIST
+
+ 115 : don't set backdrop palette on room loading
+ 118 : current amount of money
+ 119 : current cursor object
+ 176 : keychar max direction
+ 266 : keychar direction override
+ 267 : don't decode picture/sprite images (in load_image_helper)
+ 268 : don't decode picture/sprite images
+ 270 : play random sound
+ 290 : process random palette
+ 295 : game cycle counter (incremented)
+ 296 : game cycle counter (incremented)
+ 297 : game cycle counter (incremented)
+ 298 : game cycle counter (decremented)
+ 299 : game cycle counter (decremented)
+ 600 : last ascii key press
+ 603 : fade palette "scale" increment (in vbl handler)
+ 605 : fade palette "scale"
+ 606 : inventory redraw disabled
+ 607 : first palette color to fade
+ 608 : last palette color to fade
+ 609 : max fade palette "scale"
+ 610 : min fade palette "scale"
+ 611 : quit game
+ 612 : random number modulo
+ 613 : last generated random number
+ 614 : room scroll x offset
+ 615 : room scroll y offset
+ 616 : disable room scrolling
+ 617 : current speech file number
+ 621 : enable french version "features"
+ 902 : debug/draw walk boxes
+ 911 : load scripts/programs from external files
+*/
+
+} // namespace Touche
+
+#endif
diff --git a/engines/touche/ui.cpp b/engines/touche/ui.cpp
new file mode 100644
index 0000000000..997420345d
--- /dev/null
+++ b/engines/touche/ui.cpp
@@ -0,0 +1,557 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id: $
+ *
+ */
+
+#include "common/stdafx.h"
+#include "common/system.h"
+#include "common/savefile.h"
+
+#include "touche/graphics.h"
+#include "touche/touche.h"
+
+namespace Touche {
+
+static const Common::Rect buttonsRectTable1[15] = {
+ Common::Rect(108, 120, 444, 135),
+ Common::Rect(108, 136, 444, 151),
+ Common::Rect(108, 152, 444, 167),
+ Common::Rect(108, 168, 444, 183),
+ Common::Rect(108, 184, 444, 199),
+ Common::Rect(108, 200, 444, 215),
+ Common::Rect(108, 216, 444, 231),
+ Common::Rect(108, 232, 444, 247),
+ Common::Rect(108, 248, 444, 263),
+ Common::Rect(108, 264, 444, 279),
+ Common::Rect(452, 120, 546, 144),
+ Common::Rect(452, 152, 546, 176),
+ Common::Rect(452, 216, 546, 240),
+ Common::Rect(452, 248, 546, 272),
+ Common::Rect(452, 184, 546, 208)
+};
+
+static const Common::Rect buttonsRectTable2[10] = {
+ Common::Rect(396, 130, 420, 154),
+ Common::Rect(396, 160, 420, 184),
+ Common::Rect(396, 190, 420, 214),
+ Common::Rect(126, 130, 380, 154),
+ Common::Rect(126, 160, 380, 184),
+ Common::Rect(126, 190, 380, 214),
+ Common::Rect(126, 250, 150, 274),
+ Common::Rect(396, 250, 420, 274),
+ Common::Rect(154, 256, 392, 268),
+ Common::Rect(126, 222, 420, 242)
+};
+
+static int16 settingsMenuTextsTable[] = { 0, 0, 0, -92, -93, -94, -87, -88, 0, -91 };
+
+static const int16 optionsMenuTextsTable[] = { -52, -53, -54, -55, -90 };
+
+static const int16 saveMenuTextsTable[] = { 2000, -56, -52, 2001, 0 };
+
+static const int16 loadMenuTextsTable[] = { 2000, -56, -53, 2001, 0 };
+
+bool ToucheEngine::ui_processEvents() {
+ bool quit = false;
+ OSystem::Event event;
+ while (_system->pollEvent(event)) {
+ switch (event.type) {
+ case OSystem::EVENT_QUIT:
+ quit = true;
+ break;
+ case OSystem::EVENT_KEYDOWN:
+ if (_saveLoadCurrentDescriptionLen != -1) {
+ if (event.kbd.keycode == 8) {
+ if (_saveLoadCurrentDescriptionLen > 0) {
+ --_saveLoadCurrentDescriptionLen;
+ _saveLoadCurrentDescription[_saveLoadCurrentDescriptionLen] = 0;
+ }
+ } else if (isprint((char)event.kbd.ascii)) {
+ if (_saveLoadCurrentDescriptionLen < 32) {
+ _saveLoadCurrentDescription[_saveLoadCurrentDescriptionLen] = (char)event.kbd.ascii;
+ ++_saveLoadCurrentDescriptionLen;
+ _saveLoadCurrentDescription[_saveLoadCurrentDescriptionLen] = 0;
+ }
+ }
+ }
+ break;
+ case OSystem::EVENT_MOUSEMOVE:
+ _inp_mousePos.x = event.mouse.x;
+ _inp_mousePos.y = event.mouse.y;
+ break;
+ case OSystem::EVENT_LBUTTONDOWN:
+ _inp_mousePos.x = event.mouse.x;
+ _inp_mousePos.y = event.mouse.y;
+ _inp_mouseButtonClicked = true;
+ break;
+ case OSystem::EVENT_LBUTTONUP:
+ _inp_mousePos.x = event.mouse.x;
+ _inp_mousePos.y = event.mouse.y;
+ break;
+ default:
+ break;
+ }
+ }
+ _system->updateScreen();
+ _system->delayMillis(50);
+ return quit;
+}
+
+void ToucheEngine::ui_drawButtonBorders(const Common::Rect *r, int count) {
+ while (count--) {
+ Graphics::drawRect(_offscreenBuffer, 640, r->left, r->top, r->width(), r->height(), 0xF7, 0xF9);
+ ++r;
+ }
+}
+
+void ToucheEngine::ui_drawMusicVolumeBar() {
+ int volume = _snd_midiContext.volume * 232 / 256;
+ if (volume != 0) {
+ Graphics::fillRect(_offscreenBuffer, 640, 157, 259, volume, 6, 0xF0);
+ }
+ if (volume <= 232) {
+ Graphics::fillRect(_offscreenBuffer, 640, 157 + volume, 259, 232 - volume, 6, 0xD2);
+ }
+}
+
+void ToucheEngine::ui_drawTalkMode() {
+ settingsMenuTextsTable[0] = 0;
+ settingsMenuTextsTable[1] = 0;
+ settingsMenuTextsTable[2] = 0;
+ settingsMenuTextsTable[_talkTextMode] = -86;
+}
+
+void ToucheEngine::ui_drawAllBorders() {
+ Graphics::fillRect(_offscreenBuffer, 640, 90, 102, 460, 196, 248);
+ Graphics::drawRect(_offscreenBuffer, 640, 90, 102, 460, 196, 0xF7, 0xF9);
+ Graphics::drawRect(_offscreenBuffer, 640, 106, 118, 340, 164, 0xF9, 0xF7);
+ ui_drawButtonBorders(&buttonsRectTable1[10], 5);
+}
+
+void ToucheEngine::ui_drawSaveGamesList(int page) {
+ ui_drawAllBorders();
+ for (int i = 0; i < 10; ++i) {
+ const Common::Rect *r = &buttonsRectTable1[i];
+ uint8 color = (_saveLoadCurrentSlot == i) ? 0xCB : 0xD9;
+ char num[10];
+ sprintf(num, "%d.", page + i);
+ Graphics::drawString16(_offscreenBuffer, 640, color, r->left, r->top, num);
+ Graphics::drawString16(_offscreenBuffer, 640, color, r->left + 30, r->top, _saveLoadDescriptionsTable[i]);
+ }
+}
+
+void ToucheEngine::ui_drawCurrentGameStateDescription() {
+ const Common::Rect *r = &buttonsRectTable1[_saveLoadCurrentSlot];
+ Graphics::fillRect(_offscreenBuffer, 640, r->left, r->top, r->width(), r->height(), 0xF8);
+
+ int y = r->top;
+ int x = r->left;
+ char num[10];
+ sprintf(num, "%d.", _saveLoadCurrentSlot);
+ Graphics::drawString16(_offscreenBuffer, 640, 0xCB, x, y, num);
+ x += 30;
+ Graphics::drawString16(_offscreenBuffer, 640, 0xCB, x, y, _saveLoadCurrentDescription);
+ x += Graphics::getStringWidth16(_saveLoadCurrentDescription);
+ Graphics::drawString16(_offscreenBuffer, 640, 0xCB, x, y, "_");
+
+ updateScreenArea(_offscreenBuffer, 640, r->left, r->top, r->left, r->top, r->width(), r->height());
+}
+
+void ToucheEngine::ui_drawSaveLoadMenu(int page, int saveOrLoad) {
+ for (int i = 0; i < 10; ++i) {
+ _saveLoadDescriptionsTable[i][0] = 0;
+ const int gameState = page + i;
+ if (_saveLoadMarks[gameState]) {
+ readGameStateDescription(gameState, _saveLoadDescriptionsTable[i], 32);
+ }
+ }
+ ui_drawSaveGamesList(page);
+ if (saveOrLoad == 0) {
+ ui_drawButtonText(loadMenuTextsTable, &buttonsRectTable1[10], 5, true);
+ } else {
+ ui_drawButtonText(saveMenuTextsTable, &buttonsRectTable1[10], 5, true);
+ }
+ updateScreenArea(_offscreenBuffer, 640, 90, 102, 90, 102, 460, 196);
+}
+
+int ToucheEngine::ui_getButtonPressed(const Common::Rect *r, int count) const {
+ for (int i = 0; i < count; ++i) {
+ if (r[i].contains(_inp_mousePos)) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+void ToucheEngine::ui_drawButtonText(const int16 *texts, const Common::Rect *r, int count, bool centerTexts) {
+ for (int i = 0; i < count; ++i, ++texts, ++r) {
+ int x, y;
+ if (*texts < 2000) {
+ const char *str = getString(*texts);
+ x = r->left;
+ y = r->top;
+ if (centerTexts) {
+ const int w = getStringWidth(16, *texts);
+ x += (r->width() - w) / 2;
+ y += (r->height() - 16) / 2;
+ }
+ Graphics::drawString16(_offscreenBuffer, 640, 0xFF, x, y, str);
+ } else {
+ x = r->left + r->width() / 2;
+ y = r->top + r->height() / 2;
+ int dx, dy;
+ switch (*texts) {
+ case 2000: // up arrow
+ dx = 1;
+ dy = 2;
+ break;
+ case 2001: // down arrow
+ dx = -1;
+ dy = -2;
+ break;
+ }
+ ui_drawArrow(x, y + dy + 1, dx, 0xD2);
+ ui_drawArrow(x, y + dy, dx, 0xFF);
+ }
+ }
+}
+
+void ToucheEngine::ui_drawArrow(int x, int y, int dx, uint8 color) {
+ static const int16 arrowCoordsTable[] = {
+ 5, 0, 9, 0,
+ 5, 0, 5, 4,
+ -5, 4, 5, 4,
+ -5, 0, -5, 4,
+ -9, 0, -5, 0,
+ -9, 0, 0, -9,
+ 0, -9, 9, 0
+ };
+ for (uint i = 0; i < ARRAYSIZE(arrowCoordsTable) / 4; ++i) {
+ const int x1 = x + arrowCoordsTable[i * 4 + 0];
+ const int y1 = y + arrowCoordsTable[i * 4 + 1] * dx;
+ const int x2 = x + arrowCoordsTable[i * 4 + 2];
+ const int y2 = y + arrowCoordsTable[i * 4 + 3] * dx;
+ Graphics::drawLine(_offscreenBuffer, 640, x1, y1, x2, y2, color);
+ }
+}
+
+void ToucheEngine::ui_drawOptionsMenu() {
+ ui_drawTalkMode();
+ ui_drawAllBorders();
+ ui_drawButtonText(optionsMenuTextsTable, &buttonsRectTable1[10], 5, true);
+ ui_drawButtonBorders(buttonsRectTable2, 10);
+ ui_drawButtonText(settingsMenuTextsTable, buttonsRectTable2, 10, true);
+ ui_drawMusicVolumeBar();
+ updateScreenArea(_offscreenBuffer, 640, 90, 102, 90, 102, 460, 196);
+}
+
+int ToucheEngine::ui_handleSaveLoad(int saveOrLoad) {
+ char gameStateFileName[16];
+ generateGameStateFileName(999, gameStateFileName, 15, true);
+ _saveFileMan->listSavefiles(gameStateFileName, _saveLoadMarks, NUM_GAMESTATE_FILES);
+ int ret = 0;
+ bool quitMenu = false;
+ while (!quitMenu) {
+ _saveLoadCurrentDescription[0] = 0;
+ _saveLoadCurrentDescriptionLen = 0;
+ ui_drawSaveLoadMenu(_saveLoadCurrentPage, saveOrLoad);
+ int descriptionLen = 0;
+ int button = -1;
+ while (button == -1 && !quitMenu) {
+ button = ui_getButtonPressed(buttonsRectTable1, 15);
+ if (!_inp_mouseButtonClicked) {
+ button = -1;
+ }
+ if (saveOrLoad == 0) {
+ _saveLoadCurrentPage = (_saveLoadCurrentSlot / 10) * 10;
+ if (_saveLoadCurrentDescriptionLen != descriptionLen) {
+ descriptionLen = _saveLoadCurrentDescriptionLen;
+ ui_drawCurrentGameStateDescription();
+ strcpy(_saveLoadDescriptionsTable[_saveLoadCurrentSlot % 10], _saveLoadCurrentDescription);
+ }
+ }
+ quitMenu = ui_processEvents();
+ }
+ _inp_mouseButtonClicked = false;
+ switch (button) {
+ case 10:
+ _saveLoadCurrentPage -= 10;
+ if (_saveLoadCurrentPage < 0) {
+ _saveLoadCurrentPage = 90;
+ }
+ break;
+ case 11:
+ quitMenu = true;
+ ret = 0;
+ break;
+ case 12:
+ quitMenu = true;
+ ret = 1;
+ if (saveOrLoad == 0) {
+ if (saveGameState(_saveLoadCurrentSlot, _saveLoadDescriptionsTable[_saveLoadCurrentSlot % 10])) {
+ ret = 2;
+ }
+ } else {
+ if (loadGameState(_saveLoadCurrentSlot, _saveLoadDescriptionsTable[_saveLoadCurrentSlot % 10])) {
+ ret = 2;
+ }
+ }
+ break;
+ case 13:
+ _saveLoadCurrentPage += 10;
+ if (_saveLoadCurrentPage > 90) {
+ _saveLoadCurrentPage = 0;
+ }
+ break;
+ default:
+ if (button >= 0 && button <= 9) {
+ _saveLoadCurrentSlot = _saveLoadCurrentPage + button;
+ }
+ break;
+ }
+ }
+ return ret;
+}
+
+void ToucheEngine::ui_handleOptions(int forceDisplay) {
+ if (_disabledInputCounter == 0 || forceDisplay != 0) {
+ _saveLoadCurrentDescriptionLen = -1;
+ updateCursor(_currentKeyCharNum);
+ int16 mode = _flagsTable[618];
+ _flagsTable[618] = 0;
+ updateEntireScreen();
+ bool quitMenu = false;
+ while (!quitMenu) {
+ ui_drawOptionsMenu();
+ int button = -1;
+ while (button == -1 && !quitMenu) {
+ if (_inp_mouseButtonClicked) {
+ button = ui_getButtonPressed(buttonsRectTable1, 15);
+ if (button < 10) {
+ button = ui_getButtonPressed(buttonsRectTable2, 10) + 20;
+ }
+ }
+ quitMenu = ui_processEvents();
+ }
+ _inp_mouseButtonClicked = false;
+ switch (button) {
+ case 10:
+ if (ui_handleSaveLoad(1) == 2) {
+ quitMenu = true;
+ }
+ break;
+ case 11:
+ if (ui_handleSaveLoad(0) == 2) {
+ quitMenu = true;
+ }
+ break;
+ case 12:
+ quitMenu = true;
+ break;
+ case 13:
+ quitMenu = true;
+ _flagsTable[611] = 1;
+ break;
+ case 14:
+ restart();
+ quitMenu = true;
+ break;
+ case 20:
+ _talkTextMode = kTalkModeTextOnly;
+ break;
+ case 21:
+ _talkTextMode = kTalkModeVoiceOnly;
+ break;
+ case 22:
+ _talkTextMode = kTalkModeVoiceAndText;
+ break;
+ case 26:
+ if (_snd_midiContext.volume > 0) {
+ _snd_midiContext.volume -= 16;
+ }
+ break;
+ case 27:
+ if (_snd_midiContext.volume < 256) {
+ _snd_midiContext.volume += 16;
+ }
+ break;
+ }
+ }
+ _fullRedrawCounter = 2;
+ _flagsTable[618] = mode;
+ if (_flagsTable[611] != 0) {
+ _flagsTable[611] = ui_displayQuitDialog();
+ }
+ _snd_midiContext.currentVolume = _snd_midiContext.volume;
+ }
+}
+
+void ToucheEngine::ui_drawActionsPanel(int dstX, int dstY, int deltaX, int deltaY) {
+ Graphics::copyRect(_offscreenBuffer, 640, dstX, dstY,
+ _menuKitData, 42, 0, 0,
+ 14, 24,
+ Graphics::kTransparent);
+ Graphics::copyRect(_offscreenBuffer, 640, deltaX - 14 + dstX, dstY,
+ _menuKitData, 42, 0, 40,
+ 14, 24,
+ Graphics::kTransparent);
+ Graphics::copyRect(_offscreenBuffer, 640, dstX, deltaY - 16 + dstY,
+ _menuKitData, 42, 0, 24,
+ 14, 16,
+ Graphics::kTransparent);
+ Graphics::copyRect(_offscreenBuffer, 640, deltaX - 14 + dstX, deltaY - 16 + dstY,
+ _menuKitData, 42, 0, 64,
+ 14, 16,
+ Graphics::kTransparent);
+ int x1 = deltaX - 28;
+ int x2 = dstX + 14;
+ while (x1 > 0) {
+ int w = (x1 > 14) ? 14 : x1;
+ Graphics::copyRect(_offscreenBuffer, 640, x2, dstY,
+ _menuKitData, 42, 0, 80,
+ w, 24,
+ Graphics::kTransparent);
+ Graphics::copyRect(_offscreenBuffer, 640, x2, deltaY - 16 + dstY,
+ _menuKitData, 42, 0, 104,
+ w, 16,
+ Graphics::kTransparent);
+ x1 -= 14;
+ x2 += 14;
+ }
+ x1 = deltaY - 40;
+ x2 = dstY + 24;
+ while (x1 > 0) {
+ int w = (x1 > 120) ? 120 : x1;
+ Graphics::copyRect(_offscreenBuffer, 640, dstX, x2,
+ _menuKitData, 42, 14, 0,
+ 14, w,
+ Graphics::kTransparent);
+ Graphics::copyRect(_offscreenBuffer, 640, deltaX - 14 + dstX, x2,
+ _menuKitData, 42, 28, 0,
+ 14, w,
+ Graphics::kTransparent);
+ x1 -= 120;
+ x2 += 120;
+ }
+}
+
+void ToucheEngine::ui_drawConversationPanelBorder(int dstY, int srcX, int srcY) {
+ int dstX = 24;
+ int w = 48;
+ for (int i = 0; i < 13; ++i) {
+ if (i == 12) {
+ w = 34;
+ }
+ Graphics::copyRect(_offscreenBuffer, 640, dstX, dstY, _convKitData, 152, srcX, srcY, w, 6);
+ dstX += w;
+ }
+}
+
+void ToucheEngine::ui_drawConversationPanel() {
+ Graphics::copyRect(_offscreenBuffer, 640, 0, 320, _convKitData, 152, 0, 0, 72, 80);
+ int dstX = 54;
+ int dstY = 326;
+ int w = 96;
+ for (int i = 0; i < 7; ++i) {
+ if (i == 5) {
+ w = 50;
+ }
+ Graphics::copyRect(_offscreenBuffer, 640, dstX, dstY, _convKitData, 152, 24, 6, w, 68);
+ dstX += w;
+ }
+ --dstX;
+ Graphics::copyRect(_offscreenBuffer, 640, dstX, 320, _convKitData, 152, 120, 0, 7, 80);
+ dstX -= 3;
+ if (_drawCharacterConversionRepeatCounter != 0) {
+ ui_drawConversationPanelBorder(320, 72, 0);
+ Graphics::copyRect(_offscreenBuffer, 640, 0, 320, _convKitData, 152, 128, 0, 24, 21);
+ Graphics::copyRect(_offscreenBuffer, 640, dstX, 320, _convKitData, 152, 128, 34, 10, 10);
+ } else {
+ ui_drawConversationPanelBorder(320, 24, 0);
+ }
+ if (_conversationChoicesTable[_drawCharacterConversionRepeatCounter + 4].msg != 0) {
+ ui_drawConversationPanelBorder(394, 72, 74);
+ Graphics::copyRect(_offscreenBuffer, 640, 0, 379, _convKitData, 152, 128, 59, 24, 21);
+ Graphics::copyRect(_offscreenBuffer, 640, dstX, 394, _convKitData, 152, 128, 46, 10, 6);
+ } else {
+ ui_drawConversationPanelBorder(394, 24, 74);
+ }
+}
+
+void ToucheEngine::ui_printStatusString(const char *str) {
+ Graphics::fillRect(_offscreenBuffer, 640, 0, 0, 640, 16, 0xD7);
+ Graphics::drawRect(_offscreenBuffer, 640, 0, 0, 640, 16, 0xD6, 0xD8);
+ Graphics::drawString16(_offscreenBuffer, 640, 0xFF, 0, 0, str);
+ updateScreenArea(_offscreenBuffer, 640, 0, 0, 0, 0, 640, 16);
+}
+
+void ToucheEngine::ui_clearStatusString() {
+ Graphics::copyRect(_offscreenBuffer, 640, 0, 0,
+ _backdropBuffer, _currentBitmapWidth, _flagsTable[614], _flagsTable[615],
+ 640, 16);
+ updateScreenArea(_offscreenBuffer, 640, 0, 0, 0, 0, 640, 16);
+}
+
+int ToucheEngine::ui_displayQuitDialog() {
+ debug(kDebugUserIntf, "ui_displayQuitDialog()");
+ ui_printStatusString(getString(-85));
+ int ret = 0;
+ bool quitLoop = false;
+ while (!quitLoop) {
+ OSystem::Event event;
+ while (_system->pollEvent(event)) {
+ switch (event.type) {
+ case OSystem::EVENT_QUIT:
+ quitLoop = true;
+ ret = 1;
+ break;
+ case OSystem::EVENT_KEYDOWN:
+ quitLoop = true;
+ switch (_language) {
+ case Common::FR_FRA:
+ if (event.kbd.ascii == 'o' || event.kbd.ascii == 'O') {
+ ret = 1;
+ }
+ break;
+ default:
+ if (event.kbd.ascii == 'y' || event.kbd.ascii == 'Y') {
+ ret = 1;
+ }
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ _system->delayMillis(50);
+ }
+ ui_clearStatusString();
+ return ret;
+}
+
+void ToucheEngine::ui_displayTextMode(int str) {
+ debug(kDebugUserIntf, "ui_displayTextMode(%d)", str);
+ ui_printStatusString(getString(str));
+ _system->delayMillis(1000);
+ ui_clearStatusString();
+}
+
+} // namespace Touche