aboutsummaryrefslogtreecommitdiff
path: root/engines/sky
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sky')
-rw-r--r--engines/sky/autoroute.cpp285
-rw-r--r--engines/sky/autoroute.h59
-rw-r--r--engines/sky/compact.cpp452
-rw-r--r--engines/sky/compact.h93
-rw-r--r--engines/sky/control.cpp1665
-rw-r--r--engines/sky/control.h293
-rw-r--r--engines/sky/debug.cpp1487
-rw-r--r--engines/sky/debug.h76
-rw-r--r--engines/sky/disk.cpp375
-rw-r--r--engines/sky/disk.h76
-rw-r--r--engines/sky/grid.cpp260
-rw-r--r--engines/sky/grid.h68
-rw-r--r--engines/sky/hufftext.cpp2046
-rw-r--r--engines/sky/intro.cpp926
-rw-r--r--engines/sky/intro.h74
-rw-r--r--engines/sky/logic.cpp2570
-rw-r--r--engines/sky/logic.h338
-rw-r--r--engines/sky/module.mk37
-rw-r--r--engines/sky/mouse.cpp323
-rw-r--r--engines/sky/mouse.h92
-rw-r--r--engines/sky/music/adlibchannel.cpp344
-rw-r--r--engines/sky/music/adlibchannel.h106
-rw-r--r--engines/sky/music/adlibmusic.cpp121
-rw-r--r--engines/sky/music/adlibmusic.h64
-rw-r--r--engines/sky/music/gmchannel.cpp217
-rw-r--r--engines/sky/music/gmchannel.h82
-rw-r--r--engines/sky/music/gmmusic.cpp118
-rw-r--r--engines/sky/music/gmmusic.h52
-rw-r--r--engines/sky/music/mt32music.cpp169
-rw-r--r--engines/sky/music/mt32music.h53
-rw-r--r--engines/sky/music/musicbase.cpp148
-rw-r--r--engines/sky/music/musicbase.h92
-rw-r--r--engines/sky/rnc_deco.cpp262
-rw-r--r--engines/sky/rnc_deco.h63
-rw-r--r--engines/sky/screen.cpp822
-rw-r--r--engines/sky/screen.h134
-rw-r--r--engines/sky/sky.cpp556
-rw-r--r--engines/sky/sky.h112
-rw-r--r--engines/sky/skydefs.h4314
-rw-r--r--engines/sky/sound.cpp1259
-rw-r--r--engines/sky/sound.h95
-rw-r--r--engines/sky/struc.h175
-rw-r--r--engines/sky/text.cpp703
-rw-r--r--engines/sky/text.h124
44 files changed, 21780 insertions, 0 deletions
diff --git a/engines/sky/autoroute.cpp b/engines/sky/autoroute.cpp
new file mode 100644
index 0000000000..15c00ff028
--- /dev/null
+++ b/engines/sky/autoroute.cpp
@@ -0,0 +1,285 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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/util.h"
+#include "sky/autoroute.h"
+#include "sky/compact.h"
+#include "sky/grid.h"
+#include "sky/skydefs.h"
+#include "sky/struc.h"
+
+namespace Sky {
+
+#define ROUTE_GRID_WIDTH ((GAME_SCREEN_WIDTH/8)+2)
+#define ROUTE_GRID_HEIGHT ((GAME_SCREEN_HEIGHT/8)+2)
+#define ROUTE_GRID_SIZE (ROUTE_GRID_WIDTH*ROUTE_GRID_HEIGHT*2)
+#define WALK_JUMP 8 // walk in blocks of 8
+
+const int16 AutoRoute::_routeDirections[4] = { -1, 1, -ROUTE_GRID_WIDTH, ROUTE_GRID_WIDTH };
+const uint16 AutoRoute::_logicCommands[4] = { RIGHTY, LEFTY, DOWNY, UPY };
+
+AutoRoute::AutoRoute(Grid *pGrid, SkyCompact *compact) {
+
+ _grid = pGrid;
+ _skyCompact = compact;
+ _routeGrid = (uint16 *)malloc(ROUTE_GRID_SIZE);
+ _routeBuf = (uint16 *)malloc(ROUTE_SPACE);
+}
+
+AutoRoute::~AutoRoute(void) {
+
+ free(_routeGrid);
+ free(_routeBuf);
+}
+
+uint16 AutoRoute::checkBlock(uint16 *blockPos) {
+
+ uint16 retVal = 0xFFFF;
+
+ for (uint8 cnt = 0; cnt < 4; cnt++) {
+ uint16 fieldVal = *(blockPos + _routeDirections[cnt]);
+ if (fieldVal && (fieldVal < retVal))
+ retVal = fieldVal;
+ }
+ return retVal;
+}
+
+void AutoRoute::clipCoordX(uint16 x, uint8 &blkX, int16 &initX) {
+ if (x < TOP_LEFT_X) {
+ blkX = 0;
+ initX = x - TOP_LEFT_X;
+ } else if (x >= TOP_LEFT_X + GAME_SCREEN_WIDTH) {
+ blkX = (GAME_SCREEN_WIDTH - 1) >> 3;
+ initX = x - (TOP_LEFT_X + GAME_SCREEN_WIDTH - 1);
+ } else {
+ blkX = (x - TOP_LEFT_X) >> 3;
+ initX = 0;
+ }
+}
+
+void AutoRoute::clipCoordY(uint16 y, uint8 &blkY, int16 &initY) {
+ if (y < TOP_LEFT_Y) {
+ blkY = 0;
+ initY = y - TOP_LEFT_Y;
+ } else if (y >= TOP_LEFT_Y + GAME_SCREEN_HEIGHT) {
+ blkY = (GAME_SCREEN_HEIGHT - 1) >> 3;
+ initY = y - (TOP_LEFT_Y + GAME_SCREEN_HEIGHT);
+ } else {
+ blkY = (y - TOP_LEFT_Y) >> 3;
+ initY = 0;
+ }
+}
+
+void AutoRoute::initWalkGrid(uint8 screen, uint8 width) {
+
+ uint16 *wGridPos;
+ uint8 stretch = 0;
+ uint8 *screenGrid = _grid->giveGrid(screen);
+ screenGrid += GRID_SIZE;
+ wGridPos = _routeGrid + (ROUTE_GRID_SIZE >> 1) - ROUTE_GRID_WIDTH - 2;
+
+ memset(_routeGrid, 0, ROUTE_GRID_SIZE);
+ uint8 bitsLeft = 0; uint32 gridData = 0;
+ for (uint8 gridCntY = 0; gridCntY < ROUTE_GRID_HEIGHT - 2; gridCntY++) {
+ for (uint8 gridCntX = 0; gridCntX < ROUTE_GRID_WIDTH - 2; gridCntX++) {
+ if (!bitsLeft) {
+ screenGrid -= 4;
+ gridData = READ_LE_UINT32(screenGrid);
+ bitsLeft = 32;
+ }
+ if (gridData & 1) {
+ *wGridPos = 0xFFFF; // block is not accessible
+ stretch = width;
+ } else if (stretch) {
+ *wGridPos = 0xFFFF;
+ stretch--;
+ }
+ wGridPos--;
+ bitsLeft--;
+ gridData >>= 1;
+ }
+ wGridPos -= 2;
+ stretch = 0;
+ }
+}
+
+bool AutoRoute::calcWalkGrid(uint8 startX, uint8 startY, uint8 destX, uint8 destY) {
+
+ int16 directionX, directionY;
+ uint8 roiX, roiY; // Rectangle Of Interest in the walk grid
+ if (startY > destY) {
+ directionY = -ROUTE_GRID_WIDTH;
+ roiY = startY;
+ } else {
+ directionY = ROUTE_GRID_WIDTH;
+ roiY = (ROUTE_GRID_HEIGHT-1) - startY;
+ }
+ if (startX > destX) {
+ directionX = -1;
+ roiX = startX + 2;
+ } else {
+ directionX = 1;
+ roiX = (ROUTE_GRID_WIDTH - 1) - startX;
+ }
+
+ uint16 *walkDest = _routeGrid + (destY + 1) * ROUTE_GRID_WIDTH + destX + 1;
+ uint16 *walkStart = _routeGrid + (startY + 1) * ROUTE_GRID_WIDTH + startX + 1;
+ *walkStart = 1;
+
+ // if we are on the edge, move diagonally from start
+ if (roiY < ROUTE_GRID_HEIGHT-3)
+ walkStart -= directionY;
+
+ if (roiX < ROUTE_GRID_WIDTH-2)
+ walkStart -= directionX;
+
+ bool gridChanged = true;
+ bool foundRoute = false;
+
+ while ((!foundRoute) && gridChanged) {
+ gridChanged = false;
+ uint16 *yWalkCalc = walkStart;
+ for (uint8 cnty = 0; cnty < roiY; cnty++) {
+ uint16 *xWalkCalc = yWalkCalc;
+ for (uint8 cntx = 0; cntx < roiX; cntx++) {
+ if (!*xWalkCalc) { // block wasn't done, yet
+ uint16 blockRet = checkBlock(xWalkCalc);
+ if (blockRet < 0xFFFF) {
+ *xWalkCalc = blockRet + 1;
+ gridChanged = true;
+ }
+ }
+ xWalkCalc += directionX;
+ }
+ yWalkCalc += directionY;
+ }
+ if (*walkDest) { // okay, finished
+ foundRoute = true;
+ } else { // we couldn't find the route, let's extend the ROI
+ if (roiY < ROUTE_GRID_HEIGHT - 4) {
+ walkStart -= directionY;
+ roiY++;
+ }
+ if (roiX < ROUTE_GRID_WIDTH - 4) {
+ walkStart -= directionX;
+ roiX++;
+ }
+ }
+ }
+ return foundRoute;
+}
+
+uint16 *AutoRoute::makeRouteData(uint8 startX, uint8 startY, uint8 destX, uint8 destY) {
+
+ memset(_routeBuf, 0, ROUTE_SPACE);
+
+ uint16 *routePos = _routeGrid + (destY + 1) * ROUTE_GRID_WIDTH + destX + 1;
+ uint16 *dataTrg = _routeBuf + (ROUTE_SPACE >> 1) - 2;
+
+ uint16 lastVal = (*routePos) - 1;
+ while (lastVal) { // lastVal == 0 means route is done.
+ dataTrg -= 2;
+
+ int16 walkDirection = 0;
+ for (uint8 cnt = 0; cnt < 4; cnt++)
+ if (lastVal == *(routePos + _routeDirections[cnt])) {
+ *(dataTrg + 1) = _logicCommands[cnt];
+ walkDirection = _routeDirections[cnt];
+ break;
+ }
+
+ if (!walkDirection)
+ error("makeRouteData:: can't find way through walkGrid (pos %d)", lastVal);
+ while (lastVal && (lastVal == *(routePos + walkDirection))) {
+ *dataTrg += WALK_JUMP;
+ lastVal--;
+ routePos += walkDirection;
+ }
+ }
+ return dataTrg;
+}
+
+uint16 *AutoRoute::checkInitMove(uint16 *data, int16 initStaX) {
+ if (initStaX < 0) {
+ data -= 2;
+ *(data + 1) = RIGHTY;
+ *data = ((-initStaX) + 7) & 0xFFF8;
+ } else if (initStaX > 0) {
+ data -= 2;
+ *(data + 1) = LEFTY;
+ *data = (initStaX + 7) & 0xFFF8;
+ }
+ return data;
+}
+
+uint16 AutoRoute::autoRoute(Compact *cpt) {
+
+ uint8 cptScreen = (uint8)cpt->screen;
+ uint8 cptWidth = (uint8)SkyCompact::getMegaSet(cpt)->gridWidth;
+ initWalkGrid(cptScreen, cptWidth);
+
+ uint8 startX, startY, destX, destY;
+ int16 initStaX, initStaY, initDestX, initDestY;
+
+ clipCoordX(cpt->xcood, startX, initStaX);
+ clipCoordY(cpt->ycood, startY, initStaY);
+ clipCoordX(cpt->arTargetX, destX, initDestX);
+ clipCoordY(cpt->arTargetY, destY, initDestY);
+
+ uint16 *routeDest = (uint16*)_skyCompact->fetchCpt(cpt->animScratchId);
+ memset(routeDest, 0, 64);
+ if ((startX == destX) && (startY == destY))
+ return 2;
+
+ if (_routeGrid[(destY + 1) * ROUTE_GRID_WIDTH + destX + 1]) {
+ //if ((cpt == &Sky::SkyCompact::foster) && (cptScreen == 12) && (destX == 2) && (destY == 14)) {
+ if (_skyCompact->cptIsId(cpt, CPT_FOSTER) && (cptScreen == 12) && (destX == 2) && (destY == 14)) {
+ /* workaround for Scriptbug #1043047
+ In screen 12 (the pipe factory) Joey can block Foster's target
+ coordinates (2/14). This is normally not too tragic, but in the
+ scene when foster gets thrown out by Lamb (first time you enter
+ the pipe factory), the game would enter an infinite loop. */
+ _routeGrid[(destY + 1) * ROUTE_GRID_WIDTH + destX + 1] = 0;
+ // hide this part joey from the grid
+ } else
+ return 1; // AR destination is an unaccessible block
+ }
+
+ if (!calcWalkGrid(startX, startY, destX, destY))
+ return 1; // can't find route to block
+
+ uint16 *routeData = makeRouteData(startX, startY, destX, destY);
+ // the route is done.
+ // if there was an initial x movement (due to clipping) tag it onto the start
+ routeData = checkInitMove(routeData, initStaX);
+
+ uint8 cnt = 0;
+ do {
+ routeDest[cnt] = routeData[cnt];
+ routeDest[cnt + 1] = routeData[cnt + 1];
+ cnt += 2;
+ } while (routeData[cnt - 2]);
+ return 0;
+}
+
+} // End of namespace Sky
diff --git a/engines/sky/autoroute.h b/engines/sky/autoroute.h
new file mode 100644
index 0000000000..060bc9acb1
--- /dev/null
+++ b/engines/sky/autoroute.h
@@ -0,0 +1,59 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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 AUTOROUTE_H
+#define AUTOROUTE_H
+
+#include "common/stdafx.h"
+#include "common/scummsys.h"
+
+namespace Sky {
+
+struct Compact;
+class Grid;
+class SkyCompact;
+
+class AutoRoute {
+public:
+ AutoRoute(Grid *pGrid, SkyCompact *compact);
+ ~AutoRoute(void);
+ uint16 autoRoute(Compact *cpt);
+private:
+ uint16 checkBlock(uint16 *blockPos);
+ void clipCoordX(uint16 x, uint8 &blkX, int16 &initX);
+ void clipCoordY(uint16 y, uint8 &blkY, int16 &initY);
+ void initWalkGrid(uint8 screen, uint8 width);
+ bool calcWalkGrid(uint8 startX, uint8 startY, uint8 destX, uint8 destY);
+ uint16 *makeRouteData(uint8 startX, uint8 startY, uint8 destX, uint8 destY);
+ uint16 *checkInitMove(uint16 *data, int16 initStaX);
+ Grid *_grid;
+ SkyCompact *_skyCompact;
+ uint16 *_routeGrid;
+ uint16 *_routeBuf;
+ static const int16 _routeDirections[4];
+ static const uint16 _logicCommands[4];
+};
+
+} // End of namespace Sky
+
+#endif // AUTOROUTE_H
+
diff --git a/engines/sky/compact.cpp b/engines/sky/compact.cpp
new file mode 100644
index 0000000000..a7d9ee69e6
--- /dev/null
+++ b/engines/sky/compact.cpp
@@ -0,0 +1,452 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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/util.h"
+#include "common/file.h"
+#include "sky/compact.h"
+#include "gui/message.h"
+
+namespace Sky {
+
+#define SKY_CPT_SIZE 419427
+
+#define OFFS(type,item) (((long)(&((type*)0)->item)))
+#define MK32(type,item) OFFS(type, item),0,0,0
+#define MK16(type,item) OFFS(type, item),0
+#define MK32_A5(type, item) MK32(type, item[0]), MK32(type, item[1]), \
+ MK32(type, item[2]), MK32(type, item[3]), MK32(type, item[4])
+
+static const uint32 compactOffsets[] = {
+ MK16(Compact, logic),
+ MK16(Compact, status),
+ MK16(Compact, sync),
+ MK16(Compact, screen),
+ MK16(Compact, place),
+ MK32(Compact, getToTableId),
+ MK16(Compact, xcood),
+ MK16(Compact, ycood),
+ MK16(Compact, frame),
+ MK16(Compact, cursorText),
+ MK16(Compact, mouseOn),
+ MK16(Compact, mouseOff),
+ MK16(Compact, mouseClick),
+ MK16(Compact, mouseRelX),
+ MK16(Compact, mouseRelY),
+ MK16(Compact, mouseSizeX),
+ MK16(Compact, mouseSizeY),
+ MK16(Compact, actionScript),
+ MK16(Compact, upFlag),
+ MK16(Compact, downFlag),
+ MK16(Compact, getToFlag),
+ MK16(Compact, flag),
+ MK16(Compact, mood),
+ MK32(Compact, grafixProgId),
+ MK16(Compact, offset),
+ MK16(Compact, mode),
+ MK16(Compact, baseSub),
+ MK16(Compact, baseSub_off),
+ MK16(Compact, actionSub),
+ MK16(Compact, actionSub_off),
+ MK16(Compact, getToSub),
+ MK16(Compact, getToSub_off),
+ MK16(Compact, extraSub),
+ MK16(Compact, extraSub_off),
+ MK16(Compact, dir),
+ MK16(Compact, stopScript),
+ MK16(Compact, miniBump),
+ MK16(Compact, leaving),
+ MK16(Compact, atWatch),
+ MK16(Compact, atWas),
+ MK16(Compact, alt),
+ MK16(Compact, request),
+ MK16(Compact, spWidth_xx),
+ MK16(Compact, spColour),
+ MK16(Compact, spTextId),
+ MK16(Compact, spTime),
+ MK16(Compact, arAnimIndex),
+ MK32(Compact, turnProgId),
+ MK16(Compact, waitingFor),
+ MK16(Compact, arTargetX),
+ MK16(Compact, arTargetY),
+ MK32(Compact, animScratchId),
+ MK16(Compact, megaSet),
+};
+
+static const uint32 megaSetOffsets[] = {
+ MK16(MegaSet, gridWidth),
+ MK16(MegaSet, colOffset),
+ MK16(MegaSet, colWidth),
+ MK16(MegaSet, lastChr),
+ MK32(MegaSet, animUpId),
+ MK32(MegaSet, animDownId),
+ MK32(MegaSet, animLeftId),
+ MK32(MegaSet, animRightId),
+ MK32(MegaSet, standUpId),
+ MK32(MegaSet, standDownId),
+ MK32(MegaSet, standLeftId),
+ MK32(MegaSet, standRightId),
+ MK32(MegaSet, standTalkId),
+};
+
+static const uint32 turnTableOffsets[] = {
+ MK32_A5(TurnTable, turnTableUp),
+ MK32_A5(TurnTable, turnTableDown),
+ MK32_A5(TurnTable, turnTableLeft),
+ MK32_A5(TurnTable, turnTableRight),
+ MK32_A5(TurnTable, turnTableTalk),
+};
+
+#define COMPACT_SIZE (sizeof(compactOffsets)/sizeof(uint32))
+#define MEGASET_SIZE (sizeof(megaSetOffsets)/sizeof(uint32))
+#define TURNTABLE_SIZE (sizeof(turnTableOffsets)/sizeof(uint32))
+
+SkyCompact::SkyCompact(void) {
+ _cptFile = new Common::File();
+ if (!_cptFile->open("sky.cpt")) {
+ GUI::MessageDialog dialog("Unable to find \"sky.cpt\" file!\n"
+ "Please download it from www.scummvm.org", "OK", NULL);
+ dialog.runModal();
+ error("Unable to find \"sky.cpt\" file\nPlease download it from www.scummvm.org");
+ }
+
+ uint16 fileVersion = _cptFile->readUint16LE();
+ if (fileVersion != 0)
+ error("unknown \"sky.cpt\" version");
+
+ if (SKY_CPT_SIZE != _cptFile->size()) {
+ GUI::MessageDialog dialog("The \"sky.cpt\" file has an incorrect size.\nPlease (re)download it from www.scummvm.org", "OK", NULL);
+ dialog.runModal();
+ error("Incorrect sky.cpt size (%d, expected: %d)", _cptFile->size(), SKY_CPT_SIZE);
+ }
+
+ // set the necessary data structs up...
+ _numDataLists = _cptFile->readUint16LE();
+ _cptNames = (char***)malloc(_numDataLists * sizeof(char**));
+ _dataListLen = (uint16 *)malloc(_numDataLists * sizeof(uint16));
+ _cptSizes = (uint16 **)malloc(_numDataLists * sizeof(uint16*));
+ _cptTypes = (uint16 **)malloc(_numDataLists * sizeof(uint16*));
+ _compacts = (Compact***)malloc(_numDataLists * sizeof(Compact**));
+
+ for (int i = 0; i < _numDataLists; i++) {
+ _dataListLen[i] = _cptFile->readUint16LE();
+ _cptNames[i] = (char**)malloc(_dataListLen[i] * sizeof(char*));
+ _cptSizes[i] = (uint16 *)malloc(_dataListLen[i] * sizeof(uint16));
+ _cptTypes[i] = (uint16 *)malloc(_dataListLen[i] * sizeof(uint16));
+ _compacts[i] = (Compact**)malloc(_dataListLen[i] * sizeof(Compact*));
+ }
+
+ uint32 rawSize = _cptFile->readUint32LE() * sizeof(uint16);
+ uint16 *rawPos = _rawBuf = (uint16*)malloc(rawSize);
+
+ uint32 srcSize = _cptFile->readUint32LE() * sizeof(uint16);
+ uint16 *srcBuf = (uint16*)malloc(srcSize);
+ uint16 *srcPos = srcBuf;
+ _cptFile->read(srcBuf, srcSize);
+
+ uint32 asciiSize = _cptFile->readUint32LE();
+ char *asciiPos = _asciiBuf = (char*)malloc(asciiSize);
+ _cptFile->read(_asciiBuf, asciiSize);
+
+ // and fill them with the compact data
+ for (uint32 lcnt = 0; lcnt < _numDataLists; lcnt++) {
+ for (uint32 ecnt = 0; ecnt < _dataListLen[lcnt]; ecnt++) {
+ _cptSizes[lcnt][ecnt] = READ_LE_UINT16(srcPos++);
+ if (_cptSizes[lcnt][ecnt]) {
+ _cptTypes[lcnt][ecnt] = READ_LE_UINT16(srcPos++);
+ _compacts[lcnt][ecnt] = (Compact*)rawPos;
+ _cptNames[lcnt][ecnt] = asciiPos;
+ asciiPos += strlen(asciiPos) + 1;
+
+ for (uint16 elemCnt = 0; elemCnt < _cptSizes[lcnt][ecnt]; elemCnt++)
+ *rawPos++ = READ_LE_UINT16(srcPos++);
+ } else {
+ _cptTypes[lcnt][ecnt] = 0;
+ _compacts[lcnt][ecnt] = NULL;
+ _cptNames[lcnt][ecnt] = NULL;
+ }
+ }
+ }
+ free(srcBuf);
+
+ uint16 numDlincs = _cptFile->readUint16LE();
+ uint16 *dlincBuf = (uint16*)malloc(numDlincs * 2 * sizeof(uint16));
+ uint16 *dlincPos = dlincBuf;
+ _cptFile->read(dlincBuf, numDlincs * 2 * sizeof(uint16));
+ // these compacts don't actually exist but only point to other ones...
+ uint16 cnt;
+ for (cnt = 0; cnt < numDlincs; cnt++) {
+ uint16 dlincId = READ_LE_UINT16(dlincPos++);
+ uint16 destId = READ_LE_UINT16(dlincPos++);
+ assert(((dlincId >> 12) < _numDataLists) && ((dlincId & 0xFFF) < _dataListLen[dlincId >> 12]) && (_compacts[dlincId >> 12][dlincId & 0xFFF] == NULL));
+ _compacts[dlincId >> 12][dlincId & 0xFFF] = _compacts[destId >> 12][destId & 0xFFF];
+
+ assert(_cptNames[dlincId >> 12][dlincId & 0xFFF] == NULL);
+ _cptNames[dlincId >> 12][dlincId & 0xFFF] = asciiPos;
+ asciiPos += strlen(asciiPos) + 1;
+ }
+ free(dlincBuf);
+
+ // if this is v0.0288, parse this diff data
+ uint16 numDiffs = _cptFile->readUint16LE();
+ uint16 diffSize = _cptFile->readUint16LE();
+ uint16 *diffBuf = (uint16*)malloc(diffSize * sizeof(uint16));
+ _cptFile->read(diffBuf, diffSize * sizeof(uint16));
+ if (SkyEngine::_systemVars.gameVersion == 288) {
+ uint16 *diffPos = diffBuf;
+ for (cnt = 0; cnt < numDiffs; cnt++) {
+ uint16 cptId = READ_LE_UINT16(diffPos++);
+ uint16 *rawCpt = (uint16*)fetchCpt(cptId);
+ rawCpt += READ_LE_UINT16(diffPos++);
+ uint16 len = READ_LE_UINT16(diffPos++);
+ for (uint16 elemCnt = 0; elemCnt < len; elemCnt++)
+ rawCpt[elemCnt] = READ_LE_UINT16(diffPos++);
+ }
+ assert(diffPos == (diffBuf + diffSize));
+ }
+ free(diffBuf);
+
+ // these are the IDs that have to be saved into savegame files.
+ _numSaveIds = _cptFile->readUint16LE();
+ _saveIds = (uint16*)malloc(_numSaveIds * sizeof(uint16));
+ _cptFile->read(_saveIds, _numSaveIds * sizeof(uint16));
+ for (cnt = 0; cnt < _numSaveIds; cnt++)
+ _saveIds[cnt] = FROM_LE_16(_saveIds[cnt]);
+ _resetDataPos = _cptFile->pos();
+}
+
+SkyCompact::~SkyCompact(void) {
+ free(_rawBuf);
+ free(_asciiBuf);
+ for (int i = 0; i < _numDataLists; i++) {
+ free(_compacts[i]);
+ free(_cptNames[i]);
+ free(_cptSizes[i]);
+ }
+ free(_compacts);
+ free(_cptNames);
+ free(_cptSizes);
+ _cptFile->close();
+ delete _cptFile;
+}
+
+// needed for some workaround where the engine has to check if it's currently processing joey, for example
+bool SkyCompact::cptIsId(Compact *cpt, uint16 id) {
+ return (cpt == fetchCpt(id));
+}
+
+Compact *SkyCompact::fetchCpt(uint16 cptId) {
+ if (cptId == 0xFFFF) // is this really still necessary?
+ return NULL;
+ assert(((cptId >> 12) < _numDataLists) && ((cptId & 0xFFF) < _dataListLen[cptId >> 12]));
+ return _compacts[cptId >> 12][cptId & 0xFFF];
+}
+
+Compact *SkyCompact::fetchCptInfo(uint16 cptId, uint16 *elems, uint16 *type, char *name) {
+ assert(((cptId >> 12) < _numDataLists) && ((cptId & 0xFFF) < _dataListLen[cptId >> 12]));
+ if (elems)
+ *elems = _cptSizes[cptId >> 12][cptId & 0xFFF];
+ if (type)
+ *type = _cptTypes[cptId >> 12][cptId & 0xFFF];
+ if (name)
+ strcpy(name, _cptNames[cptId >> 12][cptId & 0xFFF]);
+ return fetchCpt(cptId);
+}
+
+uint16 *SkyCompact::getSub(Compact *cpt, uint16 mode) {
+ switch (mode) {
+ case 0:
+ return &(cpt->baseSub);
+ case 2:
+ return &(cpt->baseSub_off);
+ case 4:
+ return &(cpt->actionSub);
+ case 6:
+ return &(cpt->actionSub_off);
+ case 8:
+ return &(cpt->getToSub);
+ case 10:
+ return &(cpt->getToSub_off);
+ case 12:
+ return &(cpt->extraSub);
+ case 14:
+ return &(cpt->extraSub_off);
+ default:
+ error("Invalid Mode (%d)", mode);
+ }
+}
+
+uint16 *SkyCompact::getGrafixPtr(Compact *cpt) {
+ uint16 *gfxBase = (uint16*)fetchCpt(cpt->grafixProgId);
+ if (gfxBase == NULL)
+ return NULL;
+
+ return gfxBase + cpt->grafixProgPos;
+}
+
+/**
+ * Returns the n'th mega set specified by \a megaSet from Compact \a cpt.
+ */
+MegaSet *SkyCompact::getMegaSet(Compact *cpt) {
+ switch (cpt->megaSet) {
+ case 0:
+ return &cpt->megaSet0;
+ case NEXT_MEGA_SET:
+ return &cpt->megaSet1;
+ case NEXT_MEGA_SET*2:
+ return &cpt->megaSet2;
+ case NEXT_MEGA_SET*3:
+ return &cpt->megaSet3;
+ default:
+ error("Invalid MegaSet (%d)", cpt->megaSet);
+ }
+}
+
+/**
+ \brief Returns the turn table for direction \a dir
+ from Compact \a cpt in \a megaSet.
+
+ Functionally equivalent to:
+ \verbatim
+ clear eax
+ mov al,20
+ mul (cpt[esi]).c_dir
+ add ax,(cpt[esi]).c_mega_set
+ lea eax,(cpt[esi+eax]).c_turn_table_up
+ \endverbatim
+*/
+uint16 *SkyCompact::getTurnTable(Compact *cpt, uint16 dir) {
+ MegaSet *m = getMegaSet(cpt);
+ TurnTable *turnTable = (TurnTable*)fetchCpt(m->turnTableId);
+ switch (dir) {
+ case 0:
+ return turnTable->turnTableUp;
+ case 1:
+ return turnTable->turnTableDown;
+ case 2:
+ return turnTable->turnTableLeft;
+ case 3:
+ return turnTable->turnTableRight;
+ case 4:
+ return turnTable->turnTableTalk;
+ default:
+ error("No TurnTable (%d) in MegaSet (%d)", dir, cpt->megaSet);
+ }
+}
+
+void *SkyCompact::getCompactElem(Compact *cpt, uint16 off) {
+ if (off < COMPACT_SIZE)
+ return((uint8 *)cpt + compactOffsets[off]);
+ off -= COMPACT_SIZE;
+
+ if (off < MEGASET_SIZE)
+ return((uint8 *)&(cpt->megaSet0) + megaSetOffsets[off]);
+
+ off -= MEGASET_SIZE;
+ if (off < TURNTABLE_SIZE)
+ return ((uint8 *)fetchCpt(cpt->megaSet0.turnTableId) + turnTableOffsets[off]);
+
+ off -= TURNTABLE_SIZE;
+ if (off < MEGASET_SIZE)
+ return((uint8 *)&(cpt->megaSet1) + megaSetOffsets[off]);
+
+ off -= MEGASET_SIZE;
+ if (off < TURNTABLE_SIZE)
+ return ((uint8 *)fetchCpt(cpt->megaSet1.turnTableId) + turnTableOffsets[off]);
+
+ off -= TURNTABLE_SIZE;
+ if (off < MEGASET_SIZE)
+ return((uint8 *)&(cpt->megaSet2) + megaSetOffsets[off]);
+
+ off -= MEGASET_SIZE;
+ if (off < TURNTABLE_SIZE)
+ return ((uint8 *)fetchCpt(cpt->megaSet2.turnTableId) + turnTableOffsets[off]);
+
+ off -= TURNTABLE_SIZE;
+ if (off < MEGASET_SIZE)
+ return((uint8 *)&(cpt->megaSet3) + megaSetOffsets[off]);
+
+ off -= MEGASET_SIZE;
+ if (off < TURNTABLE_SIZE)
+ return ((uint8 *)fetchCpt(cpt->megaSet3.turnTableId) + turnTableOffsets[off]);
+ off -= TURNTABLE_SIZE;
+
+ error("Offset %X out of bounds of compact", off + COMPACT_SIZE + 4 * MEGASET_SIZE + 4 * TURNTABLE_SIZE);
+}
+
+uint8 *SkyCompact::createResetData(uint16 gameVersion) {
+ _cptFile->seek(_resetDataPos);
+ uint32 dataSize = _cptFile->readUint16LE() * sizeof(uint16);
+ uint16 *resetBuf = (uint16*)malloc(dataSize);
+ _cptFile->read(resetBuf, dataSize);
+ uint16 numDiffs = _cptFile->readUint16LE();
+ for (uint16 cnt = 0; cnt < numDiffs; cnt++) {
+ uint16 version = _cptFile->readUint16LE();
+ uint16 diffFields = _cptFile->readUint16LE();
+ if (version == gameVersion) {
+ for (uint16 diffCnt = 0; diffCnt < diffFields; diffCnt++) {
+ uint16 pos = _cptFile->readUint16LE();
+ resetBuf[pos] = TO_LE_16(_cptFile->readUint16LE());
+ }
+ return (uint8*)resetBuf;
+ } else
+ _cptFile->seek(diffFields * 2 * sizeof(uint16), SEEK_CUR);
+ }
+ free(resetBuf);
+ error("Unable to find reset data for Beneath a Steel Sky Version 0.0%03d", gameVersion);
+}
+
+// - debugging functions
+
+uint16 SkyCompact::findCptId(void *cpt) {
+ for (uint16 listCnt = 0; listCnt < _numDataLists; listCnt++)
+ for (uint16 elemCnt = 0; elemCnt < _dataListLen[listCnt]; elemCnt++)
+ if (_compacts[listCnt][elemCnt] == cpt)
+ return (listCnt << 12) | elemCnt;
+ // not found
+ debug(1, "Id for Compact %p wasn't found!", cpt);
+ return 0;
+}
+
+uint16 SkyCompact::findCptId(const char *cptName) {
+ for (uint16 listCnt = 0; listCnt < _numDataLists; listCnt++)
+ for (uint16 elemCnt = 0; elemCnt < _dataListLen[listCnt]; elemCnt++)
+ if (_cptNames[listCnt][elemCnt] != 0)
+ if (scumm_stricmp(cptName, _cptNames[listCnt][elemCnt]) == 0)
+ return (listCnt << 12) | elemCnt;
+ // not found
+ debug(1, "Id for Compact %s wasn't found!", cptName);
+ return 0;
+}
+
+uint16 SkyCompact::giveNumDataLists(void) {
+ return _numDataLists;
+}
+
+uint16 SkyCompact::giveDataListLen(uint16 listNum) {
+ if (listNum >= _numDataLists) // list doesn't exist
+ return 0;
+ else
+ return _dataListLen[listNum];
+}
+
+} // End of namespace Sky
diff --git a/engines/sky/compact.h b/engines/sky/compact.h
new file mode 100644
index 0000000000..7f8abbd516
--- /dev/null
+++ b/engines/sky/compact.h
@@ -0,0 +1,93 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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 SKYCOMPACT_H
+#define SKYCOMPACT_H
+
+#include "sky/sky.h"
+#include "sky/struc.h"
+#include "sky/skydefs.h"
+
+namespace Common {
+ class File;
+}
+
+enum CptIds {
+ CPT_JOEY = 1,
+ CPT_FOSTER = 3,
+ CPT_TEXT_1 = 0x17,
+ CPT_TEXT_11 = 0x21,
+ CPT_MENU_BAR = 0x2E,
+ CPT_REICH_DOOR_20 = 0x30AB,
+ CPT_MOVE_LIST = 0xBD,
+ CPT_TALK_TABLE_LIST = 0xBC
+};
+
+enum CptTypeIds {
+ CPT_NULL = 0,
+ COMPACT,
+ TURNTAB,
+ ANIMSEQ,
+ MISCBIN,
+ GETTOTAB,
+ ROUTEBUF,
+ MAINLIST
+};
+
+namespace Sky {
+
+class SkyCompact {
+public:
+ SkyCompact(void);
+ ~SkyCompact(void);
+ Compact *fetchCpt(uint16 cptId);
+ Compact *fetchCptInfo(uint16 cptId, uint16 *elems = NULL, uint16 *type = NULL, char *name = NULL);
+ static uint16 *getSub(Compact *cpt, uint16 mode);
+ static MegaSet *getMegaSet(Compact *cpt);
+ uint16 *getGrafixPtr(Compact *cpt);
+ uint16 *getTurnTable(Compact *cpt, uint16 dir);
+ void *getCompactElem(Compact *cpt, uint16 off);
+ bool cptIsId(Compact *cpt, uint16 id);
+ uint8 *createResetData(uint16 gameVersion);
+ uint16 _numSaveIds;
+ uint16 *_saveIds;
+ // - debugging functions
+ uint16 findCptId(void *cpt);
+ uint16 findCptId(const char *cptName);
+ uint16 giveNumDataLists(void);
+ uint16 giveDataListLen(uint16 listNum);
+private:
+ uint16 _numDataLists;
+ uint16 *_dataListLen;
+ uint16 *_rawBuf;
+ char *_asciiBuf;
+ Compact ***_compacts;
+ char ***_cptNames;
+ uint16 **_cptSizes;
+ uint16 **_cptTypes;
+ Common::File *_cptFile;
+ uint32 _resetDataPos;
+};
+
+} // End of namespace Sky
+
+#endif
diff --git a/engines/sky/control.cpp b/engines/sky/control.cpp
new file mode 100644
index 0000000000..c2aa5ed02f
--- /dev/null
+++ b/engines/sky/control.cpp
@@ -0,0 +1,1665 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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/file.h"
+#include "common/system.h"
+#include "common/savefile.h"
+#include "common/util.h"
+#include "gui/message.h"
+#include "sky/compact.h"
+#include "sky/control.h"
+#include "sky/disk.h"
+#include "sky/logic.h"
+#include "sky/music/musicbase.h"
+#include "sky/mouse.h"
+#include "sky/screen.h"
+#include "sky/sky.h"
+#include "sky/skydefs.h"
+#include "sky/sound.h"
+#include "sky/struc.h"
+#include "sky/text.h"
+#include "sky/compact.h"
+
+namespace Sky {
+
+ConResource::ConResource(void *pSpData, uint32 pNSprites, uint32 pCurSprite, uint16 pX, uint16 pY, uint32 pText, uint8 pOnClick, OSystem *system, uint8 *screen) {
+
+ _spriteData = (dataFileHeader *)pSpData;
+ _numSprites = pNSprites;
+ _curSprite = pCurSprite;
+ _x = pX;
+ _y = pY;
+ _text = pText;
+ _onClick = pOnClick;
+ _system = system;
+ _screen = screen;
+}
+
+bool ConResource::isMouseOver(uint32 mouseX, uint32 mouseY) {
+
+ if ((mouseX >= _x) && (mouseY >= _y) && ((uint16)mouseX <= _x + _spriteData->s_width) && ((uint16)mouseY <= _y + _spriteData->s_height))
+ return true;
+ else
+ return false;
+}
+
+void ConResource::drawToScreen(bool doMask) {
+
+ uint8 *screenPos = _y * GAME_SCREEN_WIDTH + _x + _screen;
+ uint8 *updatePos = screenPos;
+
+ if (!_spriteData)
+ return;
+ uint8 *spriteData = ((uint8 *)_spriteData) + sizeof(dataFileHeader);
+ spriteData += _spriteData->s_sp_size * _curSprite;
+ if (doMask) {
+ for (uint16 cnty = 0; cnty < _spriteData->s_height; cnty++) {
+ for (uint16 cntx = 0; cntx < _spriteData->s_width; cntx++) {
+ if (spriteData[cntx]) screenPos[cntx] = spriteData[cntx];
+ }
+ screenPos += GAME_SCREEN_WIDTH;
+ spriteData += _spriteData->s_width;
+ }
+ } else {
+ for (uint16 cnty = 0; cnty < _spriteData->s_height; cnty++) {
+ memcpy(screenPos, spriteData, _spriteData->s_width);
+ screenPos += GAME_SCREEN_WIDTH;
+ spriteData += _spriteData->s_width;
+ }
+ }
+ _system->copyRectToScreen(updatePos, GAME_SCREEN_WIDTH, _x, _y, _spriteData->s_width, _spriteData->s_height);
+}
+
+TextResource::TextResource(void *pSpData, uint32 pNSprites, uint32 pCurSprite, uint16 pX, uint16 pY, uint32 pText, uint8 pOnClick, OSystem *system, uint8 *screen) :
+ ConResource(pSpData, pNSprites, pCurSprite, pX, pY, pText, pOnClick, system, screen) {
+ _oldScreen = (uint8 *)malloc(PAN_CHAR_HEIGHT * 3 * PAN_LINE_WIDTH);
+ _oldY = 0;
+ _oldX = GAME_SCREEN_WIDTH;
+}
+
+TextResource::~TextResource(void) {
+ free(_oldScreen);
+}
+
+void TextResource::flushForRedraw(void) {
+
+ if (_oldX < GAME_SCREEN_WIDTH) {
+ uint16 cpWidth = (PAN_LINE_WIDTH > (GAME_SCREEN_WIDTH - _oldX))?(GAME_SCREEN_WIDTH - _oldX):(PAN_LINE_WIDTH);
+ for (uint8 cnty = 0; cnty < PAN_CHAR_HEIGHT; cnty++)
+ memcpy(_screen + (cnty + _oldY) * GAME_SCREEN_WIDTH + _oldX, _oldScreen + cnty * PAN_LINE_WIDTH, cpWidth);
+ }
+ _oldX = GAME_SCREEN_WIDTH;
+}
+
+void TextResource::drawToScreen(bool doMask) {
+
+ doMask = true;
+ uint16 cnty, cntx, cpWidth, cpHeight;
+ if ((_oldX == _x) && (_oldY == _y) && (_spriteData))
+ return;
+ if (_oldX < GAME_SCREEN_WIDTH) {
+ cpWidth = (PAN_LINE_WIDTH > (GAME_SCREEN_WIDTH - _oldX))?(GAME_SCREEN_WIDTH - _oldX):(PAN_LINE_WIDTH);
+ if (_spriteData && (cpWidth > _spriteData->s_width))
+ cpWidth = _spriteData->s_width;
+ if (_spriteData)
+ cpHeight = (_spriteData->s_height > (GAME_SCREEN_HEIGHT - _oldY))?(GAME_SCREEN_HEIGHT - _oldY):(_spriteData->s_height);
+ else
+ cpHeight = PAN_CHAR_HEIGHT;
+ for (cnty = 0; cnty < cpHeight; cnty++)
+ memcpy(_screen + (cnty + _oldY) * GAME_SCREEN_WIDTH + _oldX, _oldScreen + cnty * PAN_LINE_WIDTH, cpWidth);
+ _system->copyRectToScreen(_screen + _oldY * GAME_SCREEN_WIDTH + _oldX, GAME_SCREEN_WIDTH, _oldX, _oldY, cpWidth, PAN_CHAR_HEIGHT);
+ }
+ if (!_spriteData) {
+ _oldX = GAME_SCREEN_WIDTH;
+ return;
+ }
+ _oldX = _x;
+ _oldY = _y;
+ cpWidth = (PAN_LINE_WIDTH > (GAME_SCREEN_WIDTH - _x))?(GAME_SCREEN_WIDTH - _x):(PAN_LINE_WIDTH);
+ if (cpWidth > _spriteData->s_width)
+ cpWidth = _spriteData->s_width;
+ cpHeight = (_spriteData->s_height > (GAME_SCREEN_HEIGHT - _y))?(GAME_SCREEN_HEIGHT - _y):(_spriteData->s_height);
+
+ uint8 *screenPos = _screen + _y * GAME_SCREEN_WIDTH + _x;
+ uint8 *copyDest = _oldScreen;
+ uint8 *copySrc = ((uint8 *)_spriteData) + sizeof(dataFileHeader);
+ for (cnty = 0; cnty < cpHeight; cnty++) {
+ memcpy(copyDest, screenPos, cpWidth);
+ for (cntx = 0; cntx < cpWidth; cntx++)
+ if (copySrc[cntx]) screenPos[cntx] = copySrc[cntx];
+ copySrc += _spriteData->s_width;
+ copyDest += PAN_LINE_WIDTH;
+ screenPos += GAME_SCREEN_WIDTH;
+ }
+ _system->copyRectToScreen(_screen + _y * GAME_SCREEN_WIDTH + _x, GAME_SCREEN_WIDTH, _x, _y, cpWidth, cpHeight);
+}
+
+ControlStatus::ControlStatus(Text *skyText, OSystem *system, uint8 *scrBuf) {
+ _skyText = skyText;
+ _system = system;
+ _screenBuf = scrBuf;
+ _textData = NULL;
+ _statusText = new TextResource(NULL, 2, 1, 64, 163, 0, DO_NOTHING, _system, _screenBuf);
+}
+
+ControlStatus::~ControlStatus(void) {
+ if (_textData)
+ free(_textData);
+ delete _statusText;
+}
+
+void ControlStatus::setToText(const char *newText) {
+ char tmpLine[256];
+ strcpy(tmpLine, newText);
+ if (_textData) {
+ _statusText->flushForRedraw();
+ free(_textData);
+ }
+ displayText_t disText = _skyText->displayText(tmpLine, NULL, true, STATUS_WIDTH, 255);
+ _textData = (dataFileHeader *)disText.textData;
+ _statusText->setSprite(_textData);
+ _statusText->drawToScreen(WITH_MASK);
+}
+
+void ControlStatus::setToText(uint16 textNum) {
+ if (_textData)
+ free(_textData);
+ displayText_t disText = _skyText->displayText(textNum, NULL, true, STATUS_WIDTH, 255);
+ _textData = (dataFileHeader *)disText.textData;
+ _statusText->setSprite(_textData);
+ _statusText->drawToScreen(WITH_MASK);
+}
+
+void ControlStatus::drawToScreen(void) {
+ _statusText->flushForRedraw();
+ _statusText->drawToScreen(WITH_MASK);
+}
+
+Control::Control(Common::SaveFileManager *saveFileMan, Screen *screen, Disk *disk, Mouse *mouse, Text *text, MusicBase *music, Logic *logic, Sound *sound, SkyCompact *skyCompact, OSystem *system) {
+ _saveFileMan = saveFileMan;
+
+ _skyScreen = screen;
+ _skyDisk = disk;
+ _skyMouse = mouse;
+ _skyText = text;
+ _skyMusic = music;
+ _skyLogic = logic;
+ _skySound = sound;
+ _skyCompact = skyCompact;
+ _system = system;
+}
+
+ConResource *Control::createResource(void *pSpData, uint32 pNSprites, uint32 pCurSprite, int16 pX, int16 pY, uint32 pText, uint8 pOnClick, uint8 panelType) {
+
+ if (pText) pText += 0x7000;
+ if (panelType == MAINPANEL) {
+ pX += MPNL_X;
+ pY += MPNL_Y;
+ } else {
+ pX += SPNL_X;
+ pY += SPNL_Y;
+ }
+ return new ConResource(pSpData, pNSprites, pCurSprite, pX, pY, pText, pOnClick, _system, _screenBuf);
+}
+
+void Control::removePanel(void) {
+
+ free(_screenBuf);
+ free(_sprites.controlPanel); free(_sprites.button);
+ free(_sprites.buttonDown); free(_sprites.savePanel);
+ free(_sprites.yesNo); free(_sprites.slide);
+ free(_sprites.slide2); free(_sprites.slode);
+ free(_sprites.slode2); free(_sprites.musicBodge);
+ delete _controlPanel; delete _exitButton;
+ delete _slide; delete _slide2;
+ delete _slode; delete _restorePanButton;
+ delete _savePanButton; delete _dosPanButton;
+ delete _restartPanButton; delete _fxPanButton;
+ delete _musicPanButton; delete _bodge;
+ delete _yesNo; delete _text;
+ delete _statusBar; delete _restoreButton;
+
+ if (_textSprite) {
+ free(_textSprite);
+ _textSprite = NULL;
+ }
+}
+
+void Control::initPanel(void) {
+
+ _screenBuf = (uint8 *)malloc(GAME_SCREEN_WIDTH * FULL_SCREEN_HEIGHT);
+ memset(_screenBuf, 0, GAME_SCREEN_WIDTH * FULL_SCREEN_HEIGHT);
+
+ uint16 volY = (127 - _skyMusic->giveVolume()) / 4 + 59 - MPNL_Y; // volume slider's Y coordinate
+ uint16 spdY = (SkyEngine::_systemVars.gameSpeed - 2) / SPEED_MULTIPLY;
+ spdY += MPNL_Y + 83; // speed slider's initial position
+
+ _sprites.controlPanel = _skyDisk->loadFile(60500);
+ _sprites.button = _skyDisk->loadFile(60501);
+ _sprites.buttonDown = _skyDisk->loadFile(60502);
+ _sprites.savePanel = _skyDisk->loadFile(60503);
+ _sprites.yesNo = _skyDisk->loadFile(60504);
+ _sprites.slide = _skyDisk->loadFile(60505);
+ _sprites.slode = _skyDisk->loadFile(60506);
+ _sprites.slode2 = _skyDisk->loadFile(60507);
+ _sprites.slide2 = _skyDisk->loadFile(60508);
+ if (SkyEngine::_systemVars.gameVersion < 368)
+ _sprites.musicBodge = NULL;
+ else
+ _sprites.musicBodge = _skyDisk->loadFile(60509);
+
+ //Main control panel: X Y Text OnClick
+ _controlPanel = createResource(_sprites.controlPanel, 1, 0, 0, 0, 0, DO_NOTHING, MAINPANEL);
+ _exitButton = createResource( _sprites.button, 3, 0, 16, 125, 50, EXIT, MAINPANEL);
+ _slide = createResource( _sprites.slide2, 1, 0, 19,spdY, 95, SPEED_SLIDE, MAINPANEL);
+ _slide2 = createResource( _sprites.slide2, 1, 0, 19,volY, 14, MUSIC_SLIDE, MAINPANEL);
+ _slode = createResource( _sprites.slode2, 1, 0, 9, 49, 0, DO_NOTHING, MAINPANEL);
+ _restorePanButton = createResource( _sprites.button, 3, 0, 58, 19, 51, REST_GAME_PANEL, MAINPANEL);
+ _savePanButton = createResource( _sprites.button, 3, 0, 58, 39, 48, SAVE_GAME_PANEL, MAINPANEL);
+ _dosPanButton = createResource( _sprites.button, 3, 0, 58, 59, 93, QUIT_TO_DOS, MAINPANEL);
+ _restartPanButton = createResource( _sprites.button, 3, 0, 58, 79, 94, RESTART, MAINPANEL);
+ if (SkyEngine::_systemVars.systemFlags & SF_FX_OFF)
+ _fxPanButton = createResource( _sprites.button, 3, 0, 58, 99, 87, TOGGLE_FX, MAINPANEL);
+ else
+ _fxPanButton = createResource( _sprites.button, 3, 2, 58, 99, 86, TOGGLE_FX, MAINPANEL);
+
+ if (SkyEngine::isCDVersion()) { // CD Version: Toggle text/speech
+ _musicPanButton = createResource( _sprites.button, 3, 0, 58, 119, 52, TOGGLE_TEXT, MAINPANEL);
+ } else { // disk version: toggle music on/off
+ _musicPanButton = createResource( _sprites.button, 3, 0, 58, 119, 91, TOGGLE_MS, MAINPANEL);
+ }
+ _bodge = createResource( _sprites.musicBodge, 2, 1, 98, 115, 0, DO_NOTHING, MAINPANEL);
+ _yesNo = createResource( _sprites.yesNo, 1, 0, -2, 40, 0, DO_NOTHING, MAINPANEL);
+
+ _text = new TextResource(NULL, 1, 0, 15, 137, 0, DO_NOTHING, _system, _screenBuf);
+ _controlPanLookList[0] = _exitButton;
+ _controlPanLookList[1] = _restorePanButton;
+ _controlPanLookList[2] = _savePanButton;
+ _controlPanLookList[3] = _dosPanButton;
+ _controlPanLookList[4] = _restartPanButton;
+ _controlPanLookList[5] = _fxPanButton;
+ _controlPanLookList[6] = _musicPanButton;
+ _controlPanLookList[7] = _slide;
+ _controlPanLookList[8] = _slide2;
+
+ // save/restore panel
+ _savePanel = createResource( _sprites.savePanel, 1, 0, 0, 0, 0, DO_NOTHING, SAVEPANEL);
+ _saveButton = createResource( _sprites.button, 3, 0, 29, 129, 48, SAVE_A_GAME, SAVEPANEL);
+ _downFastButton = createResource(_sprites.buttonDown, 1, 0, 212, 114, 0, SHIFT_DOWN_FAST, SAVEPANEL);
+ _downSlowButton = createResource(_sprites.buttonDown, 1, 0, 212, 104, 0, SHIFT_DOWN_SLOW, SAVEPANEL);
+ _upFastButton = createResource(_sprites.buttonDown, 1, 0, 212, 10, 0, SHIFT_UP_FAST, SAVEPANEL);
+ _upSlowButton = createResource(_sprites.buttonDown, 1, 0, 212, 21, 0, SHIFT_UP_SLOW, SAVEPANEL);
+ _quitButton = createResource( _sprites.button, 3, 0, 72, 129, 49, SP_CANCEL, SAVEPANEL);
+ _restoreButton = createResource( _sprites.button, 3, 0, 29, 129, 51, RESTORE_A_GAME, SAVEPANEL);
+ _autoSaveButton = createResource( _sprites.button, 3, 0, 115, 129, 0x8FFF, RESTORE_AUTO, SAVEPANEL);
+
+ _savePanLookList[0] = _saveButton;
+ _restorePanLookList[0] = _restoreButton;
+ _restorePanLookList[1] = _savePanLookList[1] = _downSlowButton;
+ _restorePanLookList[2] = _savePanLookList[2] = _downFastButton;
+ _restorePanLookList[3] = _savePanLookList[3] = _upFastButton;
+ _restorePanLookList[4] = _savePanLookList[4] = _upSlowButton;
+ _restorePanLookList[5] = _savePanLookList[5] = _quitButton;
+ _restorePanLookList[6] = _autoSaveButton;
+
+ _statusBar = new ControlStatus(_skyText, _system, _screenBuf);
+
+ _textSprite = NULL;
+}
+
+void Control::buttonControl(ConResource *pButton) {
+
+ char autoSave[] = "Restore Autosave";
+ if (pButton == NULL) {
+ if (_textSprite)
+ free(_textSprite);
+ _textSprite = NULL;
+ _curButtonText = 0;
+ _text->setSprite(NULL);
+ return;
+ }
+ if (_curButtonText != pButton->_text) {
+ if (_textSprite)
+ free(_textSprite);
+ _textSprite = NULL;
+ _curButtonText = pButton->_text;
+ if (pButton->_text) {
+ displayText_t textRes;
+ if (pButton->_text == 0xFFFF) // text for autosave button
+ textRes = _skyText->displayText(autoSave, NULL, false, PAN_LINE_WIDTH, 255);
+ else
+ textRes = _skyText->displayText(pButton->_text, NULL, false, PAN_LINE_WIDTH, 255);
+ _textSprite = (dataFileHeader *)textRes.textData;
+ _text->setSprite(_textSprite);
+ } else
+ _text->setSprite(NULL);
+ }
+ int destY = (_mouseY - 16 >= 0) ? _mouseY - 16 : 0;
+ _text->setXY(_mouseX + 12, destY);
+}
+
+void Control::drawTextCross(uint32 flags) {
+
+ _bodge->drawToScreen(NO_MASK);
+ if (!(flags & SF_ALLOW_SPEECH))
+ drawCross(151, 124);
+ if (!(flags & SF_ALLOW_TEXT))
+ drawCross(173, 124);
+}
+
+void Control::drawCross(uint16 x, uint16 y) {
+
+ _text->flushForRedraw();
+ uint8 *bufPos, *crossPos;
+ bufPos = _screenBuf + y * GAME_SCREEN_WIDTH + x;
+ crossPos = _crossImg;
+ for (uint16 cnty = 0; cnty < CROSS_SZ_Y; cnty++) {
+ for (uint16 cntx = 0; cntx < CROSS_SZ_X; cntx++)
+ if (crossPos[cntx] != 0xFF)
+ bufPos[cntx] = crossPos[cntx];
+ bufPos += GAME_SCREEN_WIDTH;
+ crossPos += CROSS_SZ_X;
+ }
+ bufPos = _screenBuf + y * GAME_SCREEN_WIDTH + x;
+ _system->copyRectToScreen(bufPos, GAME_SCREEN_WIDTH, x, y, CROSS_SZ_X, CROSS_SZ_Y);
+ _text->drawToScreen(WITH_MASK);
+}
+
+void Control::animClick(ConResource *pButton) {
+
+ if (pButton->_curSprite != pButton->_numSprites -1) {
+ pButton->_curSprite++;
+ _text->flushForRedraw();
+ pButton->drawToScreen(NO_MASK);
+ _text->drawToScreen(WITH_MASK);
+ _system->updateScreen();
+ delay(150);
+ pButton->_curSprite--;
+ _text->flushForRedraw();
+ pButton->drawToScreen(NO_MASK);
+ _text->drawToScreen(WITH_MASK);
+ _system->updateScreen();
+ }
+}
+
+void Control::drawMainPanel(void) {
+
+ memset(_screenBuf, 0, GAME_SCREEN_WIDTH * FULL_SCREEN_HEIGHT);
+ _system->copyRectToScreen(_screenBuf, GAME_SCREEN_WIDTH, 0, 0, GAME_SCREEN_WIDTH, FULL_SCREEN_HEIGHT);
+ _controlPanel->drawToScreen(NO_MASK);
+ _exitButton->drawToScreen(NO_MASK);
+ _savePanButton->drawToScreen(NO_MASK);
+ _restorePanButton->drawToScreen(NO_MASK);
+ _dosPanButton->drawToScreen(NO_MASK);
+ _restartPanButton->drawToScreen(NO_MASK);
+ _fxPanButton->drawToScreen(NO_MASK);
+ _musicPanButton->drawToScreen(NO_MASK);
+ _slode->drawToScreen(WITH_MASK);
+ _slide->drawToScreen(WITH_MASK);
+ _slide2->drawToScreen(WITH_MASK);
+ _bodge->drawToScreen(WITH_MASK);
+ if (SkyEngine::isCDVersion())
+ drawTextCross(SkyEngine::_systemVars.systemFlags & TEXT_FLAG_MASK);
+ _statusBar->drawToScreen();
+}
+
+void Control::doLoadSavePanel(void) {
+ if (SkyEngine::isDemo())
+ return; // I don't think this can even happen
+ initPanel();
+ _skyScreen->clearScreen();
+ if (SkyEngine::_systemVars.gameVersion < 331)
+ _skyScreen->setPalette(60509);
+ else
+ _skyScreen->setPalette(60510);
+
+ _savedMouse = _skyMouse->giveCurrentMouseType();
+ _savedCharSet = _skyText->giveCurrentCharSet();
+ _skyText->fnSetFont(0);
+ _skyMouse->spriteMouse(MOUSE_NORMAL, 0, 0);
+ _lastButton = -1;
+ _curButtonText = 0;
+
+ saveRestorePanel(false);
+
+ memset(_screenBuf, 0, GAME_SCREEN_WIDTH * FULL_SCREEN_HEIGHT);
+ _system->copyRectToScreen(_screenBuf, GAME_SCREEN_WIDTH, 0, 0, GAME_SCREEN_WIDTH, FULL_SCREEN_HEIGHT);
+ _system->updateScreen();
+ _skyScreen->forceRefresh();
+ _skyScreen->setPaletteEndian((uint8 *)_skyCompact->fetchCpt(SkyEngine::_systemVars.currentPalette));
+ removePanel();
+ _skyMouse->spriteMouse(_savedMouse, 0, 0);
+ _skyText->fnSetFont(_savedCharSet);
+}
+
+void Control::doControlPanel(void) {
+
+ if (SkyEngine::isDemo()) {
+ return;
+ }
+ initPanel();
+
+ _savedCharSet = _skyText->giveCurrentCharSet();
+ _skyText->fnSetFont(0);
+
+ _skyScreen->clearScreen();
+ if (SkyEngine::_systemVars.gameVersion < 331)
+ _skyScreen->setPalette(60509);
+ else
+ _skyScreen->setPalette(60510);
+
+ drawMainPanel();
+
+ _savedMouse = _skyMouse->giveCurrentMouseType();
+
+ _skyMouse->spriteMouse(MOUSE_NORMAL, 0, 0);
+ bool quitPanel = false;
+ _lastButton = -1;
+ _curButtonText = 0;
+ uint16 clickRes = 0;
+
+ while (!quitPanel && !SkyEngine::_systemVars.quitGame) {
+ _text->drawToScreen(WITH_MASK);
+ _system->updateScreen();
+ _mouseClicked = false;
+ delay(50);
+ if (_keyPressed == 27) { // escape pressed
+ _mouseClicked = false;
+ quitPanel = true;
+ }
+ bool haveButton = false;
+ for (uint8 lookCnt = 0; lookCnt < 9; lookCnt++) {
+ if (_controlPanLookList[lookCnt]->isMouseOver(_mouseX, _mouseY)) {
+ haveButton = true;
+ buttonControl(_controlPanLookList[lookCnt]);
+ if (_mouseClicked && _controlPanLookList[lookCnt]->_onClick) {
+ clickRes = handleClick(_controlPanLookList[lookCnt]);
+ _text->flushForRedraw();
+ drawMainPanel();
+ _text->drawToScreen(WITH_MASK);
+ if ((clickRes == QUIT_PANEL) || (clickRes == GAME_SAVED) ||
+ (clickRes == GAME_RESTORED))
+ quitPanel = true;
+ }
+ _mouseClicked = false;
+ }
+ }
+ if (!haveButton)
+ buttonControl(NULL);
+ }
+ memset(_screenBuf, 0, GAME_SCREEN_WIDTH * FULL_SCREEN_HEIGHT);
+ _system->copyRectToScreen(_screenBuf, GAME_SCREEN_WIDTH, 0, 0, GAME_SCREEN_WIDTH, FULL_SCREEN_HEIGHT);
+ if (!SkyEngine::_systemVars.quitGame)
+ _system->updateScreen();
+ _skyScreen->forceRefresh();
+ _skyScreen->setPaletteEndian((uint8 *)_skyCompact->fetchCpt(SkyEngine::_systemVars.currentPalette));
+ removePanel();
+ _skyMouse->spriteMouse(_savedMouse, 0, 0);
+ _skyText->fnSetFont(_savedCharSet);
+}
+
+uint16 Control::handleClick(ConResource *pButton) {
+
+ char quitDos[] = "Quit to DOS?";
+ char restart[] = "Restart?";
+
+ switch(pButton->_onClick) {
+ case DO_NOTHING:
+ return 0;
+ case REST_GAME_PANEL:
+ if (!loadSaveAllowed())
+ return CANCEL_PRESSED; // can't save/restore while choosing
+ animClick(pButton);
+ return saveRestorePanel(false); // texts can't be edited
+ case SAVE_GAME_PANEL:
+ if (!loadSaveAllowed())
+ return CANCEL_PRESSED; // can't save/restore while choosing
+ animClick(pButton);
+ return saveRestorePanel(true); // texts can be edited
+ case SAVE_A_GAME:
+ animClick(pButton);
+ return saveGameToFile();
+ case RESTORE_A_GAME:
+ animClick(pButton);
+ return restoreGameFromFile(false);
+ case RESTORE_AUTO:
+ animClick(pButton);
+ return restoreGameFromFile(true);
+ case SP_CANCEL:
+ animClick(pButton);
+ return CANCEL_PRESSED;
+ case SHIFT_DOWN_FAST:
+ animClick(pButton);
+ return shiftDown(FAST);
+ case SHIFT_DOWN_SLOW:
+ animClick(pButton);
+ return shiftDown(SLOW);
+ case SHIFT_UP_FAST:
+ animClick(pButton);
+ return shiftUp(FAST);
+ case SHIFT_UP_SLOW:
+ animClick(pButton);
+ return shiftUp(SLOW);
+ case SPEED_SLIDE:
+ _mouseClicked = true;
+ return doSpeedSlide();
+ case MUSIC_SLIDE:
+ _mouseClicked = true;
+ return doMusicSlide();
+ case TOGGLE_FX:
+ return toggleFx(pButton);
+ case TOGGLE_MS:
+ animClick(pButton);
+ toggleMusic();
+ return TOGGLED;
+ case TOGGLE_TEXT:
+ animClick(pButton);
+ return toggleText();
+ case EXIT:
+ animClick(pButton);
+ return QUIT_PANEL;
+ case RESTART:
+ animClick(pButton);
+ if (getYesNo(restart)) {
+ restartGame();
+ return GAME_RESTORED;
+ } else
+ return 0;
+ case QUIT_TO_DOS:
+ animClick(pButton);
+ if (getYesNo(quitDos))
+ SkyEngine::_systemVars.quitGame = true;
+ return 0;
+ default:
+ error("Control::handleClick: unknown routine: %X",pButton->_onClick);
+ }
+}
+
+bool Control::getYesNo(char *text) {
+
+ bool retVal = false;
+ bool quitPanel = false;
+ uint8 mouseType = MOUSE_NORMAL;
+ uint8 wantMouse = MOUSE_NORMAL;
+ dataFileHeader *dlgTextDat;
+ uint16 textY = MPNL_Y;
+
+ _yesNo->drawToScreen(WITH_MASK);
+ if (text) {
+ displayText_t dlgLtm = _skyText->displayText(text, NULL, true, _yesNo->_spriteData->s_width - 8, 37);
+ dlgTextDat = (dataFileHeader *)dlgLtm.textData;
+ textY = MPNL_Y + 44 + (28 - dlgTextDat->s_height) / 2;
+ } else
+ dlgTextDat = NULL;
+
+ TextResource *dlgText = new TextResource(dlgTextDat, 1, 0, MPNL_X+2, textY, 0, DO_NOTHING, _system, _screenBuf);
+ dlgText->drawToScreen(WITH_MASK);
+
+ while (!quitPanel) {
+ if (mouseType != wantMouse) {
+ mouseType = wantMouse;
+ _skyMouse->spriteMouse(mouseType, 0, 0);
+ }
+ _system->updateScreen();
+ delay(50);
+ if ((_mouseY >= 83) && (_mouseY <= 110)) {
+ if ((_mouseX >= 77) && (_mouseX <= 114)) { // over 'yes'
+ wantMouse = MOUSE_CROSS;
+ if (_mouseClicked) {
+ quitPanel = true;
+ retVal = true;
+ }
+ } else if ((_mouseX >= 156) && (_mouseX <= 193)) { // over 'no'
+ wantMouse = MOUSE_CROSS;
+ if (_mouseClicked) {
+ quitPanel = true;
+ retVal = false;
+ }
+ } else
+ wantMouse = MOUSE_NORMAL;
+ } else
+ wantMouse = MOUSE_NORMAL;
+ }
+ _mouseClicked = false;
+ if (dlgTextDat)
+ free(dlgTextDat);
+ delete dlgText;
+ return retVal;
+}
+
+uint16 Control::doMusicSlide(void) {
+
+ int ofsY = _slide2->_y - _mouseY;
+ uint8 volume;
+ while (_mouseClicked) {
+ delay(50);
+ int newY = ofsY + _mouseY;
+ if (newY < 59) newY = 59;
+ if (newY > 91) newY = 91;
+ if (newY != _slide2->_y) {
+ _slode->drawToScreen(NO_MASK);
+ _slide2->setXY(_slide2->_x, (uint16)newY);
+ _slide2->drawToScreen(WITH_MASK);
+ _slide->drawToScreen(WITH_MASK);
+ volume = (newY - 59) * 4;
+ if (volume >= 128) volume = 0;
+ else volume = 127 - volume;
+ _skyMusic->setVolume(volume);
+ }
+ buttonControl(_slide2);
+ _text->drawToScreen(WITH_MASK);
+ _system->updateScreen();
+ }
+ return 0;
+}
+
+uint16 Control::doSpeedSlide(void) {
+
+ int ofsY = _slide->_y - _mouseY;
+ uint16 speedDelay = _slide->_y - (MPNL_Y + 93);
+ speedDelay *= SPEED_MULTIPLY;
+ speedDelay += 2;
+ while (_mouseClicked) {
+ delay(50);
+ int newY = ofsY + _mouseY;
+ if (newY < MPNL_Y + 93) newY = MPNL_Y + 93;
+ if (newY > MPNL_Y + 104) newY = MPNL_Y + 104;
+ if ((newY == 110) || (newY == 108)) newY = 109;
+ if (newY != _slide->_y) {
+ _slode->drawToScreen(NO_MASK);
+ _slide->setXY(_slide->_x, (uint16)newY);
+ _slide->drawToScreen(WITH_MASK);
+ _slide2->drawToScreen(WITH_MASK);
+ speedDelay = newY - (MPNL_Y + 93);
+ speedDelay *= SPEED_MULTIPLY;
+ speedDelay += 2;
+ }
+ buttonControl(_slide);
+ _text->drawToScreen(WITH_MASK);
+ _system->updateScreen();
+ }
+ SkyEngine::_systemVars.gameSpeed = speedDelay;
+ return SPEED_CHANGED;
+}
+
+uint16 Control::toggleFx(ConResource *pButton) {
+
+ SkyEngine::_systemVars.systemFlags ^= SF_FX_OFF;
+ if (SkyEngine::_systemVars.systemFlags & SF_FX_OFF) {
+ pButton->_curSprite = 0;
+ pButton->_text = 0x7000 + 87;
+ _statusBar->setToText(0x7000 + 87);
+ } else {
+ pButton->_curSprite = 2;
+ pButton->_text = 0x7000 + 86;
+ _statusBar->setToText(0x7000 + 86);
+ }
+
+ ConfMan.set("sfx_mute", (SkyEngine::_systemVars.systemFlags & SF_FX_OFF) != 0);
+
+ pButton->drawToScreen(WITH_MASK);
+ buttonControl(pButton);
+ _system->updateScreen();
+ return TOGGLED;
+}
+
+uint16 Control::toggleText(void) {
+
+ uint32 flags = SkyEngine::_systemVars.systemFlags & TEXT_FLAG_MASK;
+ SkyEngine::_systemVars.systemFlags &= ~TEXT_FLAG_MASK;
+
+ if (flags == SF_ALLOW_TEXT) {
+ flags = SF_ALLOW_SPEECH;
+ _statusBar->setToText(0x7000 + 21); // speech only
+ } else if (flags == SF_ALLOW_SPEECH) {
+ flags = SF_ALLOW_SPEECH | SF_ALLOW_TEXT;
+ _statusBar->setToText(0x7000 + 52); // text and speech
+ } else {
+ flags = SF_ALLOW_TEXT;
+ _statusBar->setToText(0x7000 + 35); // text only
+ }
+
+ ConfMan.set("subtitles", (flags & SF_ALLOW_TEXT) != 0);
+ ConfMan.set("speech_mute", (flags & SF_ALLOW_SPEECH) == 0);
+
+ SkyEngine::_systemVars.systemFlags |= flags;
+
+ drawTextCross(flags);
+
+ _system->updateScreen();
+ return TOGGLED;
+}
+
+void Control::toggleMusic(void) {
+
+ if (SkyEngine::_systemVars.systemFlags & SF_MUS_OFF) {
+ SkyEngine::_systemVars.systemFlags &= ~SF_MUS_OFF;
+ _skyMusic->startMusic(SkyEngine::_systemVars.currentMusic);
+ _statusBar->setToText(0x7000 + 88);
+ } else {
+ SkyEngine::_systemVars.systemFlags |= SF_MUS_OFF;
+ _skyMusic->startMusic(0);
+ _statusBar->setToText(0x7000 + 89);
+ }
+}
+
+uint16 Control::shiftDown(uint8 speed) {
+
+ if (speed == SLOW) {
+ if (_firstText >= MAX_SAVE_GAMES - MAX_ON_SCREEN)
+ return 0;
+ _firstText++;
+ } else {
+ if (_firstText <= MAX_SAVE_GAMES - 2 * MAX_ON_SCREEN)
+ _firstText += MAX_ON_SCREEN;
+ else if (_firstText < MAX_SAVE_GAMES - MAX_ON_SCREEN)
+ _firstText = MAX_SAVE_GAMES - MAX_ON_SCREEN;
+ else
+ return 0;
+ }
+ return SHIFTED;
+}
+
+uint16 Control::shiftUp(uint8 speed) {
+
+ if (speed == SLOW) {
+ if (_firstText > 0)
+ _firstText--;
+ else
+ return 0;
+ } else {
+ if (_firstText >= MAX_ON_SCREEN)
+ _firstText -= MAX_ON_SCREEN;
+ else if (_firstText > 0)
+ _firstText = 0;
+ else
+ return 0;
+ }
+ return SHIFTED;
+}
+
+bool Control::autoSaveExists(void) {
+
+ bool test = false;
+ Common::InSaveFile *f;
+ char fName[20];
+ if (SkyEngine::isCDVersion())
+ strcpy(fName, "SKY-VM-CD.ASD");
+ else
+ sprintf(fName, "SKY-VM%03d.ASD", SkyEngine::_systemVars.gameVersion);
+
+ f = _saveFileMan->openForLoading(fName);
+ if (f != NULL) {
+ test = true;
+ delete f;
+ }
+ return test;
+}
+
+uint16 Control::saveRestorePanel(bool allowSave) {
+
+ _keyPressed = 0;
+ buttonControl(NULL);
+ _text->drawToScreen(WITH_MASK); // flush text restore buffer
+
+ ConResource **lookList;
+ uint16 cnt;
+ uint8 lookListLen;
+ if (allowSave) {
+ lookList = _savePanLookList;
+ lookListLen = 6;
+ _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true);
+ } else {
+ lookList = _restorePanLookList;
+ if (autoSaveExists())
+ lookListLen = 7;
+ else
+ lookListLen = 6;
+ }
+ bool withAutoSave = (lookListLen == 7);
+
+ uint8 *saveGameTexts = (uint8 *)malloc(MAX_SAVE_GAMES * MAX_TEXT_LEN);
+ dataFileHeader *textSprites[MAX_ON_SCREEN + 1];
+ for (cnt = 0; cnt < MAX_ON_SCREEN + 1; cnt++)
+ textSprites[cnt] = NULL;
+ _firstText = 0;
+
+ loadDescriptions(saveGameTexts);
+ _selectedGame = 0;
+
+ bool quitPanel = false;
+ bool refreshNames = true;
+ bool refreshAll = true;
+ uint16 clickRes = 0;
+ while (!quitPanel && !SkyEngine::_systemVars.quitGame) {
+ clickRes = 0;
+ if (refreshNames || refreshAll) {
+ if (refreshAll) {
+ _text->flushForRedraw();
+ _savePanel->drawToScreen(NO_MASK);
+ _quitButton->drawToScreen(NO_MASK);
+ if (withAutoSave)
+ _autoSaveButton->drawToScreen(NO_MASK);
+ refreshAll = false;
+ }
+ for (cnt = 0; cnt < MAX_ON_SCREEN; cnt++)
+ if (textSprites[cnt])
+ free(textSprites[cnt]);
+ setUpGameSprites(saveGameTexts, textSprites, _firstText, _selectedGame);
+ showSprites(textSprites, allowSave);
+ refreshNames = false;
+ }
+
+ _text->drawToScreen(WITH_MASK);
+ _system->updateScreen();
+ _mouseClicked = false;
+ delay(50);
+ if (_keyPressed == 27) { // escape pressed
+ _mouseClicked = false;
+ clickRes = CANCEL_PRESSED;
+ quitPanel = true;
+ } else if ((_keyPressed == 13) || (_keyPressed == 15)) {
+ clickRes = handleClick(lookList[0]);
+ if (clickRes == GAME_SAVED)
+ saveDescriptions(saveGameTexts);
+ quitPanel = true;
+ _mouseClicked = false;
+ _keyPressed = 0;
+ } if (allowSave && _keyPressed) {
+ handleKeyPress(_keyPressed, _selectedGame * MAX_TEXT_LEN + saveGameTexts);
+ refreshNames = true;
+ _keyPressed = 0;
+ }
+
+ bool haveButton = false;
+ for (cnt = 0; cnt < lookListLen; cnt++)
+ if (lookList[cnt]->isMouseOver(_mouseX, _mouseY)) {
+ buttonControl(lookList[cnt]);
+ haveButton = true;
+
+ if (_mouseClicked && lookList[cnt]->_onClick) {
+ _mouseClicked = false;
+
+ clickRes = handleClick(lookList[cnt]);
+
+ if (clickRes == SHIFTED) {
+ _selectedGame = _firstText;
+ refreshNames = true;
+ }
+ if (clickRes == NO_DISK_SPACE) {
+ displayMessage(0, "Could not save game in directory '%s'", _saveFileMan->getSavePath());
+ quitPanel = true;
+ }
+ if ((clickRes == CANCEL_PRESSED) || (clickRes == GAME_RESTORED))
+ quitPanel = true;
+
+ if (clickRes == GAME_SAVED) {
+ saveDescriptions(saveGameTexts);
+ quitPanel = true;
+ }
+ if (clickRes == RESTORE_FAILED)
+ refreshAll = true;
+ }
+ }
+
+ if (_mouseClicked) {
+ if ((_mouseX >= GAME_NAME_X) && (_mouseX <= GAME_NAME_X + PAN_LINE_WIDTH) &&
+ (_mouseY >= GAME_NAME_Y) && (_mouseY <= GAME_NAME_Y + PAN_CHAR_HEIGHT * MAX_ON_SCREEN)) {
+
+ _selectedGame = (_mouseY - GAME_NAME_Y) / PAN_CHAR_HEIGHT + _firstText;
+ refreshNames = true;
+ }
+ }
+ if (!haveButton)
+ buttonControl(NULL);
+ }
+
+ for (cnt = 0; cnt < MAX_ON_SCREEN + 1; cnt++)
+ free(textSprites[cnt]);
+
+ free(saveGameTexts);
+
+ if (allowSave) {
+ _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
+ }
+
+ return clickRes;
+}
+
+bool Control::checkKeyList(uint8 key) {
+ static const uint8 charList[14] = " ,().='-&+!?\"";
+ for (uint chCnt = 0; chCnt < ARRAYSIZE(charList); chCnt++)
+ if (charList[chCnt] == key)
+ return true;
+ return false;
+}
+
+void Control::handleKeyPress(uint8 key, uint8 *textBuf) {
+
+ if (key == 8) { // backspace
+ for (uint8 cnt = 0; cnt < 6; cnt++)
+ if (!textBuf[cnt])
+ return;
+
+ while (textBuf[1])
+ textBuf++;
+ textBuf[0] = 0;
+ } else {
+ if (_enteredTextWidth >= PAN_LINE_WIDTH - 10)
+ return;
+ if (((key >= 'A') && (key <= 'Z')) || ((key >= 'a') && (key <= 'z')) ||
+ ((key >= '0') && (key <= '9')) || checkKeyList(key)) {
+ uint8 strLen = 0;
+ while (textBuf[0]) {
+ textBuf++;
+ strLen++;
+ }
+ if (strLen < MAX_TEXT_LEN) {
+ textBuf[0] = key;
+ textBuf[1] = 0;
+ }
+ }
+ }
+}
+
+void Control::setUpGameSprites(uint8 *nameBuf, dataFileHeader **nameSprites, uint16 firstNum, uint16 selectedGame) {
+
+ char cursorChar[2] = "-";
+ nameBuf += firstNum * MAX_TEXT_LEN;
+ displayText_t textSpr;
+ if (!nameSprites[MAX_ON_SCREEN]) {
+ textSpr = _skyText->displayText(cursorChar, NULL, false, 15, 0);
+ nameSprites[MAX_ON_SCREEN] = (dataFileHeader *)textSpr.textData;
+ }
+ for (uint16 cnt = 0; cnt < MAX_ON_SCREEN; cnt++) {
+ if (firstNum + cnt == selectedGame)
+ textSpr = _skyText->displayText((char*)nameBuf, NULL, false, PAN_LINE_WIDTH, 0);
+ else
+ textSpr = _skyText->displayText((char*)nameBuf, NULL, false, PAN_LINE_WIDTH, 37);
+ nameBuf += MAX_TEXT_LEN;
+ nameSprites[cnt] = (dataFileHeader *)textSpr.textData;
+ if (firstNum + cnt == selectedGame) {
+ nameSprites[cnt]->flag = 1;
+ _enteredTextWidth = (uint16)textSpr.textWidth;
+ } else
+ nameSprites[cnt]->flag = 0;
+ }
+}
+
+void Control::showSprites(dataFileHeader **nameSprites, bool allowSave) {
+
+ ConResource *drawResource = new ConResource(NULL, 1, 0, 0, 0, 0, 0, _system, _screenBuf);
+ for (uint16 cnt = 0; cnt < MAX_ON_SCREEN; cnt++) {
+ drawResource->setSprite(nameSprites[cnt]);
+ drawResource->setXY(GAME_NAME_X, GAME_NAME_Y + cnt * PAN_CHAR_HEIGHT);
+ if (nameSprites[cnt]->flag) { // name is highlighted
+ for (uint16 cnty = GAME_NAME_Y + cnt * PAN_CHAR_HEIGHT; cnty < GAME_NAME_Y + (cnt + 1) * PAN_CHAR_HEIGHT - 1; cnty++)
+ memset(_screenBuf + cnty * GAME_SCREEN_WIDTH + GAME_NAME_X, 37, PAN_LINE_WIDTH);
+ drawResource->drawToScreen(WITH_MASK);
+ if (allowSave) {
+ drawResource->setSprite(nameSprites[MAX_ON_SCREEN]);
+ drawResource->setXY(GAME_NAME_X + _enteredTextWidth + 1, GAME_NAME_Y + cnt * PAN_CHAR_HEIGHT + 4);
+ drawResource->drawToScreen(WITH_MASK);
+ }
+ _system->copyRectToScreen(_screenBuf + (GAME_NAME_Y + cnt * PAN_CHAR_HEIGHT) * GAME_SCREEN_WIDTH + GAME_NAME_X, GAME_SCREEN_WIDTH, GAME_NAME_X, GAME_NAME_Y + cnt * PAN_CHAR_HEIGHT, PAN_LINE_WIDTH, PAN_CHAR_HEIGHT);
+ } else
+ drawResource->drawToScreen(NO_MASK);
+ }
+ delete drawResource;
+}
+
+void Control::loadDescriptions(uint8 *destBuf) {
+
+ memset(destBuf, 0, MAX_SAVE_GAMES * MAX_TEXT_LEN);
+
+ Common::InSaveFile *inf;
+ inf = _saveFileMan->openForLoading("SKY-VM.SAV");
+ if (inf != NULL) {
+ uint8 *tmpBuf = (uint8 *)malloc(MAX_SAVE_GAMES * MAX_TEXT_LEN);
+ inf->read(tmpBuf, MAX_SAVE_GAMES * MAX_TEXT_LEN);
+ uint8 *destPos = destBuf;
+ uint8 *inPos = tmpBuf;
+ for (uint16 cnt = 0; cnt < MAX_SAVE_GAMES; cnt++) {
+ sprintf((char*)destPos,"%3d: ", cnt + 1);
+ uint8 nameCnt = 0;
+ while ((destPos[nameCnt + 5] = inPos[nameCnt]))
+ nameCnt++;
+ destPos += MAX_TEXT_LEN;
+ inPos += nameCnt + 1;
+ }
+ free(tmpBuf);
+ delete inf;
+ } else {
+ uint8 *destPos = destBuf;
+ for (uint16 cnt = 0; cnt < MAX_SAVE_GAMES; cnt++) {
+ sprintf((char*)destPos,"%3d: ", cnt + 1);
+ destPos += MAX_TEXT_LEN;
+ }
+ }
+}
+
+bool Control::loadSaveAllowed(void) {
+
+ if (SkyEngine::_systemVars.systemFlags & SF_CHOOSING)
+ return false; // texts get lost during load/save, so don't allow it during choosing
+ if (Logic::_scriptVariables[SCREEN] >= 101)
+ return false; // same problem with LINC terminals
+ if ((Logic::_scriptVariables[SCREEN] >= 82) &&
+ (Logic::_scriptVariables[SCREEN] != 85) &&
+ (Logic::_scriptVariables[SCREEN] < 90))
+ return false; // don't allow saving in final rooms
+
+ return true;
+}
+
+int Control::displayMessage(const char *altButton, const char *message, ...) {
+ char buf[STRINGBUFLEN];
+ va_list va;
+
+ va_start(va, message);
+ vsnprintf(buf, STRINGBUFLEN, message, va);
+ va_end(va);
+
+ GUI::MessageDialog dialog(buf, "OK", altButton);
+ int result = dialog.runModal();
+ _skyMouse->spriteMouse(MOUSE_NORMAL, 0, 0);
+ return result;
+}
+
+void Control::saveDescriptions(uint8 *srcBuf) {
+
+ uint8 *tmpBuf = (uint8 *)malloc(MAX_SAVE_GAMES * MAX_TEXT_LEN);
+ uint8 *tmpPos = tmpBuf;
+ uint8 *srcPos = srcBuf;
+ for (uint16 cnt = 0; cnt < MAX_SAVE_GAMES; cnt++) {
+ uint8 namePos = 5;
+ while (srcPos[namePos]) {
+ if (srcPos[namePos] != '_') {
+ *tmpPos = srcPos[namePos];
+ tmpPos++;
+ }
+ namePos++;
+ }
+ *tmpPos = 0;
+ tmpPos++;
+ srcPos += MAX_TEXT_LEN;
+ }
+ Common::OutSaveFile *outf;
+
+ outf = _saveFileMan->openForSaving("SKY-VM.SAV");
+ bool ioFailed = true;
+ if (outf) {
+ outf->write(tmpBuf, tmpPos - tmpBuf);
+ outf->flush();
+ if (!outf->ioFailed())
+ ioFailed = false;
+ delete outf;
+ }
+ if (ioFailed)
+ displayMessage(NULL, "Unable to store Savegame names to file SKY-VM.SAV in directory %s", _saveFileMan->getSavePath());
+ free(tmpBuf);
+}
+
+void Control::doAutoSave(void) {
+ char fName[20];
+ if (SkyEngine::isCDVersion())
+ strcpy(fName, "SKY-VM-CD.ASD");
+ else
+ sprintf(fName, "SKY-VM%03d.ASD", SkyEngine::_systemVars.gameVersion);
+ Common::OutSaveFile *outf;
+
+ outf = _saveFileMan->openForSaving(fName);
+ if (outf == NULL) {
+ displayMessage(0, "Unable to create autosave file '%s' in directory '%s'", fName, _saveFileMan->getSavePath());
+ return;
+ }
+ uint8 *saveData = (uint8 *)malloc(0x20000);
+ uint32 fSize = prepareSaveData(saveData);
+
+ outf->write(saveData, fSize);
+ outf->flush();
+
+ if (outf->ioFailed())
+ displayMessage(0, "Unable to write autosave file '%s' in directory '%s'. Disk full?", fName, _saveFileMan->getSavePath());
+
+ delete outf;
+ free(saveData);
+}
+
+uint16 Control::saveGameToFile(void) {
+ char fName[20];
+ sprintf(fName,"SKY-VM.%03d", _selectedGame);
+
+ Common::OutSaveFile *outf;
+ outf = _saveFileMan->openForSaving(fName);
+ if (outf == NULL)
+ return NO_DISK_SPACE;
+
+ uint8 *saveData = (uint8 *)malloc(0x20000);
+ uint32 fSize = prepareSaveData(saveData);
+
+ uint32 writeRes = outf->write(saveData, fSize);
+ outf->flush();
+ if (outf->ioFailed())
+ writeRes = 0;
+ free(saveData);
+ delete outf;
+
+ return (writeRes == fSize) ? GAME_SAVED : NO_DISK_SPACE;
+}
+
+#define STOSD(ptr, val) { *(uint32 *)(ptr) = TO_LE_32(val); (ptr) += 4; }
+#define STOSW(ptr, val) { *(uint16 *)(ptr) = TO_LE_16(val); (ptr) += 2; }
+
+uint32 Control::prepareSaveData(uint8 *destBuf) {
+
+ uint32 cnt;
+ memset(destBuf, 0, 4); // space for data size
+ uint8 *destPos = destBuf + 4;
+ STOSD(destPos, SAVE_FILE_REVISION);
+ STOSD(destPos, SkyEngine::_systemVars.gameVersion);
+
+ STOSW(destPos, _skySound->_saveSounds[0]);
+ STOSW(destPos, _skySound->_saveSounds[1]);
+
+ STOSD(destPos, _skyMusic->giveCurrentMusic());
+ STOSD(destPos, _savedCharSet);
+ STOSD(destPos, _savedMouse);
+ STOSD(destPos, SkyEngine::_systemVars.currentPalette);
+ for (cnt = 0; cnt < 838; cnt++)
+ STOSD(destPos, Logic::_scriptVariables[cnt]);
+ uint32 *loadedFilesList = _skyDisk->giveLoadedFilesList();
+
+ for (cnt = 0; cnt < 60; cnt++)
+ STOSD(destPos, loadedFilesList[cnt]);
+
+ for (cnt = 0; cnt < _skyCompact->_numSaveIds; cnt++) {
+ uint16 numElems;
+ uint16 *rawCpt = (uint16*)_skyCompact->fetchCptInfo(_skyCompact->_saveIds[cnt], &numElems, NULL, NULL);
+ for (uint16 elemCnt = 0; elemCnt < numElems; elemCnt++)
+ STOSW(destPos, rawCpt[elemCnt]);
+ }
+
+ *(uint32 *)destBuf = TO_LE_32(destPos - destBuf); // save size
+ return destPos - destBuf;
+}
+
+#undef STOSD
+#undef STOSW
+
+#define LODSD(strPtr, val) { val = READ_LE_UINT32(strPtr); (strPtr) += 4; }
+#define LODSW(strPtr, val) { val = READ_LE_UINT16(strPtr); (strPtr) += 2; }
+
+void Control::importOldMegaSet(uint8 **srcPos, MegaSet *mega) {
+ LODSW(*srcPos, mega->gridWidth);
+ LODSW(*srcPos, mega->colOffset);
+ LODSW(*srcPos, mega->colWidth);
+ LODSW(*srcPos, mega->lastChr);
+}
+
+void Control::importOldCompact(Compact* destCpt, uint8 **srcPos, uint16 numElems, uint16 type, char *name) {
+ uint16 saveType;
+ LODSW(*srcPos, saveType);
+ if ((saveType & (SAVE_EXT | SAVE_TURNP)) && (numElems < 54))
+ error("Cpt %s: Savedata doesn't match cpt size (%d)!\n", name, numElems);
+ if ((saveType & SAVE_MEGA0) && (numElems < 54 + 13))
+ error("Cpt %s: Savedata doesn't match cpt size (%d)!\n", name, numElems);
+ if ((saveType & SAVE_MEGA1) && (numElems < 54 + 13 + 13))
+ error("Cpt %s: Savedata doesn't match cpt size (%d)!\n", name, numElems);
+ if ((saveType & SAVE_MEGA2) && (numElems < 54 + 13 + 13 + 13))
+ error("Cpt %s: Savedata doesn't match cpt size (%d)!\n", name, numElems);
+ if ((saveType & SAVE_MEGA3) && (numElems < 54 + 13 + 13 + 13))
+ error("Cpt %s: Savedata doesn't match cpt size (%d)!\n", name, numElems);
+ if (saveType & SAVE_GRAFX) {
+ uint16 graphType, target, pos;
+ LODSW(*srcPos, graphType);
+ LODSW(*srcPos, target);
+ LODSW(*srcPos, pos);
+ // convert to new compact system..
+ destCpt->grafixProgPos = pos;
+ if (graphType == OG_PTR_NULL)
+ destCpt->grafixProgId = 0;
+ else if (graphType == OG_AUTOROUTE)
+ destCpt->grafixProgId = destCpt->animScratchId;
+ else if (graphType == OG_COMPACT)
+ destCpt->grafixProgId = target;
+ else if (graphType == OG_TALKTABLE)
+ destCpt->grafixProgId = ((uint16*)_skyCompact->fetchCpt(CPT_TALK_TABLE_LIST))[target];
+ else if (graphType == OG_COMPACTELEM)
+ destCpt->grafixProgId = *(uint16*)_skyCompact->getCompactElem(destCpt, target);
+ else
+ error("Illegal GrafixProg type encountered for compact %s", name);
+ }
+ if (saveType & SAVE_TURNP) {
+ // basically impossible to import these. simply set it to end-of-turn and hope the script
+ // will take care of it.
+ destCpt->turnProgId = 0x13B;
+ destCpt->turnProgPos = 1;
+ uint16 turnSkipLen;
+ LODSW(*srcPos, turnSkipLen);
+ *srcPos += 2 * turnSkipLen;
+ } else if (numElems >= 49) {
+ destCpt->turnProgId = 0;
+ destCpt->turnProgPos = 0;
+ }
+ LODSW(*srcPos, destCpt->logic);
+ LODSW(*srcPos, destCpt->status);
+ LODSW(*srcPos, destCpt->sync);
+ LODSW(*srcPos, destCpt->screen);
+ LODSW(*srcPos, destCpt->place);
+ // getToTable
+ LODSW(*srcPos, destCpt->xcood);
+ LODSW(*srcPos, destCpt->ycood);
+ LODSW(*srcPos, destCpt->frame);
+ LODSW(*srcPos, destCpt->cursorText);
+ LODSW(*srcPos, destCpt->mouseOn);
+ LODSW(*srcPos, destCpt->mouseOff);
+ LODSW(*srcPos, destCpt->mouseClick);
+ LODSW(*srcPos, destCpt->mouseRelX);
+ LODSW(*srcPos, destCpt->mouseRelY);
+ LODSW(*srcPos, destCpt->mouseSizeX);
+ LODSW(*srcPos, destCpt->mouseSizeY);
+ LODSW(*srcPos, destCpt->actionScript);
+ LODSW(*srcPos, destCpt->upFlag);
+ LODSW(*srcPos, destCpt->downFlag);
+ LODSW(*srcPos, destCpt->getToFlag);
+ LODSW(*srcPos, destCpt->flag);
+ LODSW(*srcPos, destCpt->mood);
+ // grafixProg
+ LODSW(*srcPos, destCpt->offset);
+ LODSW(*srcPos, destCpt->mode);
+ LODSW(*srcPos, destCpt->baseSub);
+ LODSW(*srcPos, destCpt->baseSub_off);
+ if (saveType & SAVE_EXT) {
+ LODSW(*srcPos, destCpt->actionSub);
+ LODSW(*srcPos, destCpt->actionSub_off);
+ LODSW(*srcPos, destCpt->getToSub);
+ LODSW(*srcPos, destCpt->getToSub_off);
+ LODSW(*srcPos, destCpt->extraSub);
+ LODSW(*srcPos, destCpt->extraSub_off);
+ LODSW(*srcPos, destCpt->dir);
+ LODSW(*srcPos, destCpt->stopScript);
+ LODSW(*srcPos, destCpt->miniBump);
+ LODSW(*srcPos, destCpt->leaving);
+ LODSW(*srcPos, destCpt->atWatch);
+ LODSW(*srcPos, destCpt->atWas);
+ LODSW(*srcPos, destCpt->alt);
+ LODSW(*srcPos, destCpt->request);
+ LODSW(*srcPos, destCpt->spWidth_xx);
+ LODSW(*srcPos, destCpt->spColour);
+ LODSW(*srcPos, destCpt->spTextId);
+ LODSW(*srcPos, destCpt->spTime);
+ LODSW(*srcPos, destCpt->arAnimIndex);
+ // turnProg
+ LODSW(*srcPos, destCpt->waitingFor);
+ LODSW(*srcPos, destCpt->arTargetX);
+ LODSW(*srcPos, destCpt->arTargetY);
+ // animScratch
+ LODSW(*srcPos, destCpt->megaSet);
+ if (saveType & SAVE_MEGA0)
+ importOldMegaSet(srcPos, &(destCpt->megaSet0));
+ if (saveType & SAVE_MEGA1)
+ importOldMegaSet(srcPos, &(destCpt->megaSet1));
+ if (saveType & SAVE_MEGA2)
+ importOldMegaSet(srcPos, &(destCpt->megaSet2));
+ if (saveType & SAVE_MEGA3)
+ importOldMegaSet(srcPos, &(destCpt->megaSet3));
+ }
+}
+
+uint16 Control::parseSaveData(uint8 *srcBuf) {
+ uint32 reloadList[60];
+ uint32 cnt;
+ uint8 *srcPos = srcBuf;
+ uint32 size;
+ uint32 saveRev;
+ uint32 gameVersion;
+ LODSD(srcPos, size);
+ LODSD(srcPos, saveRev);
+ if (saveRev > SAVE_FILE_REVISION) {
+ displayMessage(0, "Unknown save file revision (%d)", saveRev);
+ return RESTORE_FAILED;
+ } else if (saveRev < OLD_SAVEGAME_TYPE) {
+ displayMessage(0, "This savegame version is unsupported.");
+ return RESTORE_FAILED;
+ }
+ LODSD(srcPos, gameVersion);
+ if (gameVersion != SkyEngine::_systemVars.gameVersion) {
+ if ((!SkyEngine::isCDVersion()) || (gameVersion < 365)) { // cd versions are compatible
+ displayMessage(NULL, "This savegame was created by\n"
+ "Beneath a Steel Sky v0.0%03d\n"
+ "It cannot be loaded by this version (v0.0%3d)",
+ gameVersion, SkyEngine::_systemVars.gameVersion);
+ return RESTORE_FAILED;
+ }
+ }
+ SkyEngine::_systemVars.systemFlags |= SF_GAME_RESTORED;
+
+ LODSW(srcPos, _skySound->_saveSounds[0]);
+ LODSW(srcPos, _skySound->_saveSounds[1]);
+ _skySound->restoreSfx();
+
+ uint32 music, mouseType, palette;
+ LODSD(srcPos, music);
+ LODSD(srcPos, _savedCharSet);
+ LODSD(srcPos, mouseType);
+ LODSD(srcPos, palette);
+
+ _skyLogic->parseSaveData((uint32*)srcPos);
+ srcPos += NUM_SKY_SCRIPTVARS * sizeof(uint32);
+
+ for (cnt = 0; cnt < 60; cnt++)
+ LODSD(srcPos, reloadList[cnt]);
+
+ if (saveRev == SAVE_FILE_REVISION) {
+ for (cnt = 0; cnt < _skyCompact->_numSaveIds; cnt++) {
+ uint16 numElems;
+ uint16 *rawCpt = (uint16*)_skyCompact->fetchCptInfo(_skyCompact->_saveIds[cnt], &numElems, NULL, NULL);
+ for (uint16 elemCnt = 0; elemCnt < numElems; elemCnt++)
+ LODSW(srcPos, rawCpt[elemCnt]);
+ }
+ } else { // import old savegame revision
+ for (cnt = 0; cnt < (uint32)(_skyCompact->_numSaveIds - 2); cnt++) {
+ uint16 numElems;
+ uint16 type;
+ char name[128];
+ uint16 *rawCpt = (uint16*)_skyCompact->fetchCptInfo(_skyCompact->_saveIds[cnt], &numElems, &type, name);
+ if (type == COMPACT) {
+ importOldCompact((Compact*)rawCpt, &srcPos, numElems, type, name);
+ } else if (type == ROUTEBUF) {
+ assert(numElems == 32);
+ for (uint32 elemCnt = 0; elemCnt < numElems; elemCnt++)
+ LODSW(srcPos, rawCpt[elemCnt]);
+ }
+ }
+ uint16 *rawCpt = (uint16*)_skyCompact->fetchCpt(0xBF);
+ for (cnt = 0; cnt < 3; cnt++)
+ LODSW(srcPos, rawCpt[cnt]);
+ rawCpt = (uint16*)_skyCompact->fetchCpt(0xC2);
+ for (cnt = 0; cnt < 13; cnt++)
+ LODSW(srcPos, rawCpt[cnt]);
+ }
+
+ // make sure all text compacts are off
+ for (cnt = CPT_TEXT_1; cnt <= CPT_TEXT_11; cnt++)
+ _skyCompact->fetchCpt(cnt)->status = 0;
+
+ if (srcPos - srcBuf != (int32)size)
+ error("Restore failed! Savegame data = %d bytes. Expected size: %d", srcPos-srcBuf, size);
+
+ _skyDisk->refreshFilesList(reloadList);
+ SkyEngine::_systemVars.currentMusic = (uint16)music;
+ if (!(SkyEngine::_systemVars.systemFlags & SF_MUS_OFF))
+ _skyMusic->startMusic((uint16)music);
+ _savedMouse = (uint16)mouseType;
+ SkyEngine::_systemVars.currentPalette = palette; // will be set when doControlPanel ends
+
+ return GAME_RESTORED;
+}
+
+
+uint16 Control::restoreGameFromFile(bool autoSave) {
+ char fName[20];
+ if (autoSave) {
+ if (SkyEngine::isCDVersion())
+ strcpy(fName, "SKY-VM-CD.ASD");
+ else
+ sprintf(fName, "SKY-VM%03d.ASD", SkyEngine::_systemVars.gameVersion);
+ } else
+ sprintf(fName,"SKY-VM.%03d", _selectedGame);
+
+ Common::InSaveFile *inf;
+ inf = _saveFileMan->openForLoading(fName);
+ if (inf == NULL) {
+ return RESTORE_FAILED;
+ }
+
+ uint32 infSize = inf->readUint32LE();
+ if (infSize < 4) infSize = 4;
+ uint8 *saveData = (uint8 *)malloc(infSize);
+ *(uint32 *)saveData = TO_LE_32(infSize);
+
+ if (inf->read(saveData+4, infSize-4) != infSize-4) {
+ displayMessage(NULL, "Can't read from file '%s'", fName);
+ free(saveData);
+ delete inf;
+ return RESTORE_FAILED;
+ }
+
+ uint16 res = parseSaveData(saveData);
+ SkyEngine::_systemVars.pastIntro = true;
+ delete inf;
+ free(saveData);
+ return res;
+}
+
+uint16 Control::quickXRestore(uint16 slot) {
+ uint16 result;
+ initPanel();
+ _mouseClicked = false;
+
+ _savedCharSet = _skyText->giveCurrentCharSet();
+ _skyText->fnSetFont(0);
+
+ _system->copyRectToScreen(_screenBuf, GAME_SCREEN_WIDTH, 0, 0, FULL_SCREEN_WIDTH, FULL_SCREEN_HEIGHT);
+ _system->updateScreen();
+
+ if (SkyEngine::_systemVars.gameVersion < 331)
+ _skyScreen->setPalette(60509);
+ else
+ _skyScreen->setPalette(60510);
+
+ _savedMouse = _skyMouse->giveCurrentMouseType();
+ _skyMouse->spriteMouse(MOUSE_NORMAL, 0, 0);
+
+ if (slot == 0)
+ result = restoreGameFromFile(true);
+ else {
+ _selectedGame = slot - 1;
+ result = restoreGameFromFile(false);
+ }
+ if (result == GAME_RESTORED) {
+ memset(_skyScreen->giveCurrent(), 0, GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT);
+ _skyScreen->showScreen(_skyScreen->giveCurrent());
+ _skyScreen->forceRefresh();
+ _skyScreen->setPaletteEndian((uint8 *)_skyCompact->fetchCpt(SkyEngine::_systemVars.currentPalette));
+ } else {
+ memset(_screenBuf, 0, FULL_SCREEN_WIDTH * FULL_SCREEN_HEIGHT);
+ _system->copyRectToScreen(_screenBuf, GAME_SCREEN_WIDTH, 0, 0, GAME_SCREEN_WIDTH, FULL_SCREEN_HEIGHT);
+ _system->updateScreen();
+ _skyScreen->showScreen(_skyScreen->giveCurrent());
+ _skyScreen->setPalette(60111);
+ }
+ _skyMouse->spriteMouse(_savedMouse, 0, 0);
+ _skyText->fnSetFont(_savedCharSet);
+
+ removePanel();
+ return result;
+}
+
+void Control::restartGame(void) {
+ if (SkyEngine::_systemVars.gameVersion <= 267)
+ return; // no restart for floppy demo
+
+ uint8 *resetData = _skyCompact->createResetData((uint16)SkyEngine::_systemVars.gameVersion);
+ parseSaveData((uint8*)resetData);
+ free(resetData);
+ _skyScreen->forceRefresh();
+
+ memset(_skyScreen->giveCurrent(), 0, GAME_SCREEN_WIDTH * FULL_SCREEN_HEIGHT);
+ _skyScreen->showScreen(_skyScreen->giveCurrent());
+ _skyScreen->setPaletteEndian((uint8 *)_skyCompact->fetchCpt(SkyEngine::_systemVars.currentPalette));
+ _skyMouse->spriteMouse(_savedMouse, 0, 0);
+ SkyEngine::_systemVars.pastIntro = true;
+}
+
+void Control::delay(unsigned int amount) {
+
+ OSystem::Event event;
+
+ uint32 start = _system->getMillis();
+ uint32 cur = start;
+ _keyPressed = 0; //reset
+
+ do {
+ while (_system->pollEvent(event)) {
+ switch (event.type) {
+ case OSystem::EVENT_KEYDOWN:
+ // Make sure backspace works right (this fixes a small issue on OS X)
+ if (event.kbd.keycode == 8)
+ _keyPressed = 8;
+ else
+ _keyPressed = (byte)event.kbd.ascii;
+ break;
+ case OSystem::EVENT_MOUSEMOVE:
+ _mouseX = event.mouse.x;
+ _mouseY = event.mouse.y;
+ break;
+ case OSystem::EVENT_LBUTTONDOWN:
+#ifdef PALMOS_MODE
+ _mouseX = event.mouse.x;
+ _mouseY = event.mouse.y;
+#endif
+ _mouseClicked = true;
+ break;
+ case OSystem::EVENT_LBUTTONUP:
+ _mouseClicked = false;
+ break;
+ case OSystem::EVENT_RBUTTONDOWN:
+ break;
+ case OSystem::EVENT_QUIT:
+ SkyEngine::_systemVars.quitGame = true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ uint this_delay = 20; // 1?
+#ifdef _WIN32_WCE
+ this_delay = 10;
+#endif
+ if (this_delay > amount)
+ this_delay = amount;
+
+ if (this_delay > 0) _system->delayMillis(this_delay);
+
+ cur = _system->getMillis();
+ } while (cur < start + amount);
+}
+
+void Control::showGameQuitMsg(void) {
+
+ _skyText->fnSetFont(0);
+ uint8 *textBuf1 = (uint8 *)malloc(GAME_SCREEN_WIDTH * 14 + sizeof(dataFileHeader));
+ uint8 *textBuf2 = (uint8 *)malloc(GAME_SCREEN_WIDTH * 14 + sizeof(dataFileHeader));
+ uint8 *screenData;
+ if (_skyScreen->sequenceRunning())
+ _skyScreen->stopSequence();
+
+ screenData = _skyScreen->giveCurrent();
+
+ _skyText->displayText(_quitTexts[SkyEngine::_systemVars.language * 2 + 0], textBuf1, true, 320, 255);
+ _skyText->displayText(_quitTexts[SkyEngine::_systemVars.language * 2 + 1], textBuf2, true, 320, 255);
+ uint8 *curLine1 = textBuf1 + sizeof(dataFileHeader);
+ uint8 *curLine2 = textBuf2 + sizeof(dataFileHeader);
+ uint8 *targetLine = screenData + GAME_SCREEN_WIDTH * 80;
+ for (uint8 cnty = 0; cnty < PAN_CHAR_HEIGHT; cnty++) {
+ for (uint16 cntx = 0; cntx < GAME_SCREEN_WIDTH; cntx++) {
+ if (curLine1[cntx])
+ targetLine[cntx] = curLine1[cntx];
+ if (curLine2[cntx])
+ (targetLine + 24 * GAME_SCREEN_WIDTH)[cntx] = curLine2[cntx];
+ }
+ curLine1 += GAME_SCREEN_WIDTH;
+ curLine2 += GAME_SCREEN_WIDTH;
+ targetLine += GAME_SCREEN_WIDTH;
+ }
+ _skyScreen->halvePalette();
+ _skyScreen->showScreen(screenData);
+ free(textBuf1);
+ free(textBuf2);
+}
+
+char Control::_quitTexts[16][35] = {
+ "Game over player one",
+ "BE VIGILANT",
+ "Das Spiel ist aus.",
+ "SEI WACHSAM",
+ "Game over joueur 1",
+ "SOYEZ VIGILANTS",
+ "Game over player one",
+ "BE VIGILANT",
+ "SPELET \x2Ar SLUT, Agent 1.",
+ "VAR VAKSAM",
+ "Game over giocatore 1",
+ "SIATE VIGILANTI",
+ "Fim de jogo para o jogador um",
+ "BE VIGILANT"
+ "Game over player one",
+ "BE VIGILANT",
+};
+
+uint8 Control::_crossImg[594] = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0B, 0x61, 0xFF, 0xFF, 0xFF, 0xFF, 0x4F, 0x4D, 0x61,
+ 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x08, 0x4E, 0x53, 0x50, 0x4F, 0x0C, 0x4D, 0x4E, 0x51, 0x58, 0x58, 0x54, 0x4E, 0x08, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x4E, 0x54, 0x58, 0x50, 0x4E, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x50, 0x4E, 0x54, 0x58, 0x58, 0x54, 0x4E, 0x0C, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x61, 0x53, 0x58, 0x54, 0x4E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x50, 0x4E, 0x55, 0x58, 0x58, 0x53, 0x4E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x05, 0x51, 0x58, 0x58,
+ 0x51, 0x50, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x4F, 0x51, 0x58,
+ 0x59, 0x58, 0x51, 0x61, 0xFF, 0xFF, 0x61, 0x54, 0x58, 0x58, 0x4F, 0x52, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x4E, 0x55, 0x58, 0x58, 0x57, 0x4E,
+ 0x4F, 0x56, 0x58, 0x57, 0x61, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x4F, 0x51, 0x58, 0x58, 0x58, 0x58, 0x58, 0x54, 0x4E, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0x6A, 0x4F, 0x58, 0x58, 0x58, 0x58, 0x52, 0x06, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x04, 0x54, 0x58,
+ 0x58, 0x58, 0x58, 0x57, 0x53, 0x61, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x04, 0x09, 0x58, 0x58, 0x58, 0x57, 0x56, 0x58, 0x58, 0x58,
+ 0x57, 0x4F, 0x0A, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x61, 0x55, 0x58, 0x58, 0x58, 0x58, 0x4E, 0x64, 0x57, 0x58, 0x58, 0x58, 0x58, 0x53, 0x61, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x61, 0x57, 0x58, 0x58, 0x58, 0x58,
+ 0x50, 0xFF, 0xFF, 0x4E, 0x57, 0x58, 0x58, 0x58, 0x58, 0x56, 0x61, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x61, 0x58, 0x58, 0x58, 0x58, 0x58, 0x53, 0x09, 0xFF, 0xFF, 0xFF, 0x4E,
+ 0x57, 0x58, 0x58, 0x58, 0x58, 0x58, 0x0B, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x61, 0x57,
+ 0x58, 0x58, 0x58, 0x58, 0x56, 0x4E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x61, 0x58, 0x58, 0x58, 0x58,
+ 0x58, 0x57, 0x61, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x04, 0x55, 0x58, 0x58, 0x58, 0x58, 0x58, 0x4E,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x4F, 0x58, 0x58, 0x58, 0x58, 0x4E, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x06, 0x58, 0x58, 0x58, 0x58, 0x58, 0x52, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0x0C, 0x52, 0x58, 0x58, 0x51, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x61, 0x56, 0x58,
+ 0x58, 0x58, 0x58, 0x56, 0x61, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x61, 0x56,
+ 0x58, 0x61, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x4D, 0x4D, 0x51, 0x56, 0x58, 0x58, 0x50, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x4F, 0x54, 0x09, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x4E, 0x50, 0x54, 0x61, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x06, 0x50, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0x61, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0x61, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x61, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x61, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF
+};
+
+} // End of namespace Sky
diff --git a/engines/sky/control.h b/engines/sky/control.h
new file mode 100644
index 0000000000..d219dab749
--- /dev/null
+++ b/engines/sky/control.h
@@ -0,0 +1,293 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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 CONTROL_H
+#define CONTROL_H
+
+#include "common/stdafx.h"
+#include "common/scummsys.h"
+
+class OSystem;
+namespace Common {
+ class SaveFileManager;
+}
+
+namespace Sky {
+
+class Disk;
+class Screen;
+class Logic;
+class Mouse;
+class Text;
+class MusicBase;
+class Sound;
+class SkyCompact;
+struct Compact;
+struct dataFileHeader;
+struct MegaSet;
+
+#define MAX_SAVE_GAMES 999
+#define MAX_TEXT_LEN 80
+#define PAN_LINE_WIDTH 184
+#define PAN_CHAR_HEIGHT 12
+#define STATUS_WIDTH 146
+#define MPNL_X 60 // Main Panel
+#define MPNL_Y 10
+
+#define SPNL_X 20 // Save Panel
+#define SPNL_Y 20
+#define SP_HEIGHT 149
+#define SP_TOP_GAP 12
+#define SP_BOT_GAP 27
+#define CROSS_SZ_X 27
+#define CROSS_SZ_Y 22
+
+#define TEXT_FLAG_MASK (SF_ALLOW_SPEECH | SF_ALLOW_TEXT)
+
+#define GAME_NAME_X (SPNL_X + 18) // x coordinate of game names
+#define GAME_NAME_Y (SPNL_Y + SP_TOP_GAP) // start y coord of game names
+#define MAX_ON_SCREEN ((SP_HEIGHT - SP_TOP_GAP - SP_BOT_GAP) / PAN_CHAR_HEIGHT) // no of save games on screen
+#define CP_PANEL 60400 // main panel sprite
+
+#define MAINPANEL 0
+#define SAVEPANEL 1
+
+#define NO_MASK false
+#define WITH_MASK true
+
+// resource's onClick routines
+#define DO_NOTHING 0
+#define REST_GAME_PANEL 1
+#define SAVE_GAME_PANEL 2
+#define SAVE_A_GAME 3
+#define RESTORE_A_GAME 4
+#define SP_CANCEL 5
+#define SHIFT_DOWN_FAST 6
+#define SHIFT_DOWN_SLOW 7
+#define SHIFT_UP_FAST 8
+#define SHIFT_UP_SLOW 9
+#define SPEED_SLIDE 10
+#define MUSIC_SLIDE 11
+#define TOGGLE_FX 12
+#define TOGGLE_MS 13
+#define TOGGLE_TEXT 14
+#define EXIT 15
+#define RESTART 16
+#define QUIT_TO_DOS 17
+#define RESTORE_AUTO 18
+
+// onClick return codes
+#define CANCEL_PRESSED 100
+#define NAME_TOO_SHORT 101
+#define GAME_SAVED 102
+#define SHIFTED 103
+#define TOGGLED 104
+#define RESTARTED 105
+#define GAME_RESTORED 106
+#define RESTORE_FAILED 107
+#define NO_DISK_SPACE 108
+#define SPEED_CHANGED 109
+#define QUIT_PANEL 110
+
+#define SLOW 0
+#define FAST 1
+
+#define SPEED_MULTIPLY 8
+
+//-
+#define SAVE_EXT 1
+#define SAVE_MEGA0 2
+#define SAVE_MEGA1 4
+#define SAVE_MEGA2 8
+#define SAVE_MEGA3 16
+#define SAVE_GRAFX 32
+#define SAVE_TURNP 64
+
+#define SAVE_FILE_REVISION 6
+#define OLD_SAVEGAME_TYPE 5
+
+struct AllocedMem {
+ uint16 *mem;
+ AllocedMem *next;
+};
+
+class ConResource {
+public:
+ ConResource(void *pSpData, uint32 pNSprites, uint32 pCurSprite, uint16 pX, uint16 pY, uint32 pText, uint8 pOnClick, OSystem *system, uint8 *screen);
+ virtual ~ConResource(void) {};
+ void setSprite(void *pSpData) { _spriteData = (dataFileHeader*)pSpData; };
+ void setText(uint32 pText) { if (pText) _text = pText + 0x7000; else _text = 0; };
+ void setXY(uint16 x, uint16 y) { _x = x; _y = y; };
+ bool isMouseOver(uint32 mouseX, uint32 mouseY);
+ virtual void drawToScreen(bool doMask);
+
+ dataFileHeader *_spriteData;
+ uint32 _numSprites, _curSprite;
+ uint16 _x, _y;
+ uint32 _text;
+ uint8 _onClick;
+ OSystem *_system;
+ uint8 *_screen;
+private:
+};
+
+class TextResource : public ConResource {
+public:
+ TextResource(void *pSpData, uint32 pNSprites, uint32 pCurSprite, uint16 pX, uint16 pY, uint32 pText, uint8 pOnClick, OSystem *system, uint8 *screen);
+ virtual ~TextResource(void);
+ virtual void drawToScreen(bool doMask);
+ void flushForRedraw(void);
+private:
+ uint16 _oldX, _oldY;
+ uint8 *_oldScreen;
+};
+
+class ControlStatus {
+public:
+ ControlStatus(Text *skyText, OSystem *system, uint8 *scrBuf);
+ ~ControlStatus(void);
+ void setToText(const char *newText);
+ void setToText(uint16 textNum);
+ void drawToScreen(void);
+private:
+ TextResource *_statusText;
+ dataFileHeader *_textData;
+ Text *_skyText;
+ OSystem *_system;
+ uint8 *_screenBuf;
+};
+
+class Control {
+public:
+ Control(Common::SaveFileManager *saveFileMan, Screen *screen, Disk *disk, Mouse *mouse, Text *text, MusicBase *music, Logic *logic, Sound *sound, SkyCompact *skyCompact, OSystem *system);
+ void doControlPanel(void);
+ void doLoadSavePanel(void);
+ void restartGame(void);
+ void showGameQuitMsg(void);
+ void doAutoSave(void);
+ uint16 quickXRestore(uint16 slot);
+ bool loadSaveAllowed(void);
+
+private:
+ int displayMessage(const char *altButton, const char *message, ...);
+
+ void initPanel(void);
+ void removePanel(void);
+
+ void drawMainPanel(void);
+
+ void delay(unsigned int amount);
+
+ void animClick(ConResource *pButton);
+ bool getYesNo(char *text);
+ void buttonControl(ConResource *pButton);
+ uint16 handleClick(ConResource *pButton);
+ uint16 doMusicSlide(void);
+ uint16 doSpeedSlide(void);
+ uint16 toggleFx(ConResource *pButton);
+ uint16 toggleText(void);
+ void toggleMusic(void);
+ uint16 shiftDown(uint8 speed);
+ uint16 shiftUp(uint8 speed);
+ void drawTextCross(uint32 flags);
+ void drawCross(uint16 x, uint16 y);
+
+ uint16 saveRestorePanel(bool allowSave);
+ void loadDescriptions(uint8 *destBuf);
+ void saveDescriptions(uint8 *srcBuf);
+ void setUpGameSprites(uint8 *nameBuf, dataFileHeader **nameSprites, uint16 firstNum, uint16 selectedGame);
+ void showSprites(dataFileHeader **nameSprites, bool allowSave);
+ bool checkKeyList(uint8 key);
+ void handleKeyPress(uint8 key, uint8 *textBuf);
+
+ uint16 _selectedGame;
+ uint16 saveGameToFile(void);
+ uint32 prepareSaveData(uint8 *destBuf);
+
+ bool autoSaveExists(void);
+ uint16 restoreGameFromFile(bool autoSave);
+ void importOldMegaSet(uint8 **srcPos, MegaSet *mega);
+ void importOldCompact(Compact* destCpt, uint8 **srcPos, uint16 numElems, uint16 type, char *name);
+ uint16 parseSaveData(uint8 *srcBuf);
+
+ Common::SaveFileManager *_saveFileMan;
+ SkyCompact *_skyCompact;
+ Screen *_skyScreen;
+ Disk *_skyDisk;
+ Mouse *_skyMouse;
+ Text *_skyText;
+ MusicBase *_skyMusic;
+ Logic *_skyLogic;
+ Sound *_skySound;
+ OSystem *_system;
+ int _mouseX, _mouseY;
+ bool _mouseClicked;
+ byte _keyPressed;
+
+ struct {
+ uint8 *controlPanel;
+ uint8 *button;
+ uint8 *buttonDown;
+ uint8 *savePanel;
+ uint8 *yesNo;
+ uint8 *slide;
+ uint8 *slode;
+ uint8 *slode2;
+ uint8 *slide2;
+ uint8 *musicBodge;
+ } _sprites;
+
+ uint8 *_screenBuf;
+ int _lastButton;
+ uint32 _curButtonText;
+ uint16 _firstText;
+ uint16 _savedMouse;
+ uint32 _savedCharSet;
+ uint16 _enteredTextWidth;
+
+ ConResource *createResource(void *pSpData, uint32 pNSprites, uint32 pCurSprite, int16 pX, int16 pY, uint32 pText, uint8 pOnClick, uint8 panelType);
+
+ dataFileHeader *_textSprite;
+ TextResource *_text;
+
+ ConResource *_controlPanel, *_exitButton, *_slide, *_slide2, *_slode;
+ ConResource *_restorePanButton, *_savePanButton, *_dosPanButton, *_restartPanButton, *_fxPanButton, *_musicPanButton;
+ ConResource *_bodge, *_yesNo;
+ ConResource *_controlPanLookList[9];
+
+ //- Save/restore panel
+ ConResource *_savePanel;
+ ConResource *_saveButton, *_downFastButton, *_downSlowButton;
+ ConResource *_upFastButton, *_upSlowButton, *_quitButton, *_restoreButton;
+ ConResource *_autoSaveButton;
+
+ ConResource *_savePanLookList[6], *_restorePanLookList[7];
+
+ ControlStatus *_statusBar;
+
+ static char _quitTexts[16][35];
+ static uint8 _crossImg[594];
+};
+
+} // End of namespace Sky
+
+#endif // CONTROL_H
diff --git a/engines/sky/debug.cpp b/engines/sky/debug.cpp
new file mode 100644
index 0000000000..05aec03db5
--- /dev/null
+++ b/engines/sky/debug.cpp
@@ -0,0 +1,1487 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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/util.h"
+#include "common/debugger.cpp"
+
+#include "sky/debug.h"
+#include "sky/grid.h"
+#include "sky/logic.h"
+#include "sky/mouse.h"
+#include "sky/screen.h"
+#include "sky/sky.h"
+#include "sky/struc.h"
+#include "sky/compact.h"
+
+namespace Sky {
+
+static const char *section_0_compacts[] = {
+ "UNDEFINED",
+ "joey",
+ "joey_park",
+ "foster",
+ "std_menu_logic",
+ "text_mouse",
+ "gallcard_menu",
+ "rs_mega_alive",
+ "citycard_menu",
+ "shades_menu",
+ "putty_menu",
+ "lightbulb_menu",
+ "low_get_seq",
+ "mini_shrug_seq",
+ "sml_up_mid_get_seq",
+ "new_grid",
+ "lamb",
+ "floor",
+ "coordinate_test",
+ "save_restore_mouse",
+ "whole_screen",
+ "l_talk_s2",
+ "r_talk_s2",
+ "text_1",
+ "text_2",
+ "text_3",
+ "text_4",
+ "text_5",
+ "text_6",
+ "text_7",
+ "text_8",
+ "text_9",
+ "text_10",
+ "text_11",
+ "wd40_menu",
+ "skey_menu",
+ "secateurs_menu",
+ "rope_menu",
+ "plaster_menu",
+ "new_cable_menu",
+ "shrug_seq",
+ "rad_shrug_seq",
+ "brick_menu",
+ "tongs_menu",
+ "talk1",
+ "talk2",
+ "menu_bar",
+ "left_arrow",
+ "right_arrow",
+ "dog_food_menu",
+ "UNDEFINED",
+ "blank1",
+ "blank2",
+ "blank3",
+ "blank4",
+ "blank5",
+ "blank6",
+ "blank7",
+ "blank8",
+ "blank9",
+ "blank10",
+ "blank11",
+ "UNDEFINED",
+ "crow_bar_menu",
+ "sarnie_menu",
+ "spanner_menu",
+ "joeyb_menu",
+ "low_floor",
+ "UNDEFINED",
+ "stairs",
+ "upstairs",
+ "anita_card_menu",
+ "rs_lamb_to_three",
+ "rs_lamb_start_2",
+ "anchor_menu",
+ "magazine_menu",
+ "tape_menu",
+ "glass_menu",
+ "rs_lamb_start_3",
+ "ticket_menu",
+ "s29_fast_list",
+ "s6_fast_list",
+ "fast_list_sc3",
+ "s9_fast_list",
+ "s10_fast_list",
+ "bar",
+ "s11_fast_list",
+ "fast_list_0",
+ "s0_fast_list",
+ "s7_fast_list",
+ "door",
+ "s28_fast_list",
+ "swing_list",
+ "UNDEFINED",
+ "UNDEFINED",
+ "outside_ledge",
+ "UNDEFINED",
+ "r1_door",
+ "UNDEFINED",
+ "UNDEFINED",
+ "UNDEFINED",
+ "UNDEFINED",
+ "fast_list_sc90",
+ "UNDEFINED",
+ "UNDEFINED",
+ "small_door",
+ "sc85_fast_list",
+ "sc85_chip_list",
+ "sc85_logic_list",
+ "sc85_mouse_list",
+ "sc85_palette",
+ "right_exit0",
+ "UNDEFINED",
+ "UNDEFINED",
+ "UNDEFINED",
+ "s2_floor",
+ "UNDEFINED",
+ "s101_chip_list",
+ "s101_pal",
+ "s101_mouse",
+ "s101_logic",
+ "full_screen",
+ "cancel_button",
+ "button_0",
+ "button_1",
+ "button_2",
+ "button_3",
+ "button_4",
+ "button_5",
+ "button_6",
+ "button_7",
+ "button_8",
+ "button_9",
+ "rs_left_arrow",
+ "rs_right_arrow",
+ "rs_blank",
+ "monitor",
+ "anita",
+ "UNDEFINED",
+ "UNDEFINED",
+ "UNDEFINED",
+ "baby_logic_list",
+ "rs_l_arr_linc",
+ "rs_r_arr_linc",
+ "rs_blanks_linc",
+ "s5_fast_list",
+ "but_e",
+ "but_0",
+ "but_1",
+ "but_2",
+ "but_3",
+ "but_4",
+ "but_5",
+ "but_6",
+ "but_7",
+ "but_8",
+ "but_9",
+ "UNDEFINED",
+ "s102_chip_list",
+ "s102_pal",
+ "s102_logic",
+ "s102_mouse",
+ "restart_butt",
+ "restart_seq",
+ "restore_butt",
+ "restore_seq",
+ "seq1_pal",
+ "seq2_pal",
+ "seq3_pal",
+ "fast_intro",
+ "chip_intro",
+ "fast_intro_2",
+ "fast_intro_3",
+ "retina_scan",
+ "retina_scan_cdt",
+ "exit_butt",
+ "exit_seq",
+ "forklift_cpt",
+ "forklift1_cdt",
+ "forklift2_cdt"
+};
+
+static const char *logic_table_names[] = {
+ "return",
+ "Logic::script",
+ "Logic::auto_route",
+ "Logic::ar_anim",
+ "Logic::ar_turn",
+ "Logic::alt",
+ "Logic::anim",
+ "Logic::turn",
+ "Logic::cursor",
+ "Logic::talk",
+ "Logic::listen",
+ "Logic::stopped",
+ "Logic::choose",
+ "Logic::frames",
+ "Logic::pause",
+ "Logic::wait_sync",
+ "Logic::simple_anim"
+};
+
+static const char opcode_par[] = {
+ 1,
+ 0,
+ 1,
+ 0,
+ 0,
+ 1,
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 2,
+ 0,
+ 0,
+ 1,
+ 1,
+ 1,
+ 0,
+ 1,
+ 0,
+ 0
+};
+
+static const char *opcodes[] = {
+ "push_variable",
+ "less_than",
+ "push_number",
+ "not_equal",
+ "if_and",
+ "skip_zero",
+ "pop_var",
+ "minus",
+ "plus",
+ "skip_always",
+ "if_or",
+ "call_mcode",
+ "more_than",
+ "script_exit",
+ "switch",
+ "push_offset",
+ "pop_offset",
+ "is_equal",
+ "skip_nz",
+ "script_exit",
+ "restart_script"
+};
+
+static const char *mcodes[] = {
+ "fn_cache_chip",
+ "fn_cache_fast",
+ "fn_draw_screen",
+ "fn_ar",
+ "fn_ar_animate",
+ "fn_idle",
+ "fn_interact",
+ "fn_start_sub",
+ "fn_they_start_sub",
+ "fn_assign_base",
+ "fn_disk_mouse",
+ "fn_normal_mouse",
+ "fn_blank_mouse",
+ "fn_cross_mouse",
+ "fn_cursor_right",
+ "fn_cursor_left",
+ "fn_cursor_down",
+ "fn_open_hand",
+ "fn_close_hand",
+ "fn_get_to",
+ "fn_set_to_stand",
+ "fn_turn_to",
+ "fn_arrived",
+ "fn_leaving",
+ "fn_set_alternate",
+ "fn_alt_set_alternate",
+ "fn_kill_id",
+ "fn_no_human",
+ "fn_add_human",
+ "fn_add_buttons",
+ "fn_no_buttons",
+ "fn_set_stop",
+ "fn_clear_stop",
+ "fn_pointer_text",
+ "fn_quit",
+ "fn_speak_me",
+ "fn_speak_me_dir",
+ "fn_speak_wait",
+ "fn_speak_wait_dir",
+ "fn_chooser",
+ "fn_highlight",
+ "fn_text_kill",
+ "fn_stop_mode",
+ "fn_we_wait",
+ "fn_send_sync",
+ "fn_send_fast_sync",
+ "fn_send_request",
+ "fn_clear_request",
+ "fn_check_request",
+ "fn_start_menu",
+ "fn_unhighlight",
+ "fn_face_id",
+ "fn_foreground",
+ "fn_background",
+ "fn_new_background",
+ "fn_sort",
+ "fn_no_sprite_engine",
+ "fn_no_sprites_a6",
+ "fn_reset_id",
+ "fn_toggle_grid",
+ "fn_pause",
+ "fn_run_anim_mod",
+ "fn_simple_mod",
+ "fn_run_frames",
+ "fn_await_sync",
+ "fn_inc_mega_set",
+ "fn_dec_mega_set",
+ "fn_set_mega_set",
+ "fn_move_items",
+ "fn_new_list",
+ "fn_ask_this",
+ "fn_random",
+ "fn_person_here",
+ "fn_toggle_mouse",
+ "fn_mouse_on",
+ "fn_mouse_off",
+ "fn_fetch_x",
+ "fn_fetch_y",
+ "fn_test_list",
+ "fn_fetch_place",
+ "fn_custom_joey",
+ "fn_set_palette",
+ "fn_text_module",
+ "fn_change_name",
+ "fn_mini_load",
+ "fn_flush_buffers",
+ "fn_flush_chip",
+ "fn_save_coods",
+ "fn_plot_grid",
+ "fn_remove_grid",
+ "fn_eyeball",
+ "fn_cursor_up",
+ "fn_leave_section",
+ "fn_enter_section",
+ "fn_restore_game",
+ "fn_restart_game",
+ "fn_new_swing_seq",
+ "fn_wait_swing_end",
+ "fn_skip_intro_code",
+ "fn_blank_screen",
+ "fn_print_credit",
+ "fn_look_at",
+ "fn_linc_text_module",
+ "fn_text_kill2",
+ "fn_set_font",
+ "fn_start_fx",
+ "fn_stop_fx",
+ "fn_start_music",
+ "fn_stop_music",
+ "fn_fade_down",
+ "fn_fade_up",
+ "fn_quit_to_dos",
+ "fn_pause_fx",
+ "fn_un_pause_fx",
+ "fn_printf"
+};
+
+static const char *scriptVars[] = {
+ "result",
+ "screen",
+ "logic_list_no",
+ "safe_logic_list",
+ "low_list_no",
+ "high_list_no",
+ "mouse_list_no",
+ "safe_mouse_list",
+ "draw_list_no",
+ "second_draw_list",
+ "do_not_use",
+ "music_module",
+ "cur_id",
+ "mouse_status",
+ "mouse_stop",
+ "button",
+ "but_repeat",
+ "special_item",
+ "get_off",
+ "safe_click",
+ "click_id",
+ "player_id",
+ "cursor_id",
+ "pointer_pen",
+ "last_pal",
+ "safex",
+ "safey",
+ "player_x",
+ "player_y",
+ "player_mood",
+ "player_screen",
+ "old_x",
+ "old_y",
+ "joey_x",
+ "joey_y",
+ "joey_list",
+ "flag",
+ "hit_id",
+ "player_target",
+ "joey_target",
+ "mega_target",
+ "layer_0_id",
+ "layer_1_id",
+ "layer_2_id",
+ "layer_3_id",
+ "grid_1_id",
+ "grid_2_id",
+ "grid_3_id",
+ "stop_grid",
+ "text_rate",
+ "text_speed",
+ "the_chosen_one",
+ "chosen_anim",
+ "text1",
+ "anim1",
+ "text2",
+ "anim2",
+ "text3",
+ "anim3",
+ "text4",
+ "anim4",
+ "text5",
+ "anim5",
+ "text6",
+ "anim6",
+ "text7",
+ "anim7",
+ "text8",
+ "anim8",
+ "o0",
+ "o1",
+ "o2",
+ "o3",
+ "o4",
+ "o5",
+ "o6",
+ "o7",
+ "o8",
+ "o9",
+ "o10",
+ "o11",
+ "o12",
+ "o13",
+ "o14",
+ "o15",
+ "o16",
+ "o17",
+ "o18",
+ "o19",
+ "o20",
+ "o21",
+ "o22",
+ "o23",
+ "o24",
+ "o25",
+ "o26",
+ "o27",
+ "o28",
+ "o29",
+ "first_icon",
+ "menu_length",
+ "scroll_offset",
+ "menu",
+ "object_held",
+ "icon_lit",
+ "at_sign",
+ "fire_exit_flag",
+ "small_door_flag",
+ "jobs_greet",
+ "lamb_greet",
+ "knob_flag",
+ "lazer_flag",
+ "cupb_flag",
+ "jobs_loop",
+ "done_something",
+ "rnd",
+ "jobs_text",
+ "jobs_loc1",
+ "jobs_loc2",
+ "jobs_loc3",
+ "id_talking",
+ "alarm",
+ "alarm_count",
+ "clearing_alarm",
+ "jobs_friend",
+ "joey_born",
+ "joey_text",
+ "joey_peeved",
+ "knows_linc",
+ "linc_overmann",
+ "reich_entry",
+ "seen_lock",
+ "wshop_text",
+ "knows_firedoor",
+ "knows_furnace",
+ "jobs_got_spanner",
+ "jobs_got_sandwich",
+ "jobs_firedoor",
+ "knows_transporter",
+ "joey_loc1",
+ "joey_loc2",
+ "joey_loc3",
+ "joey_screen",
+ "cur_section",
+ "old_section",
+ "joey_section",
+ "lamb_section",
+ "knows_overmann",
+ "jobs_overmann",
+ "jobs_seen_joey",
+ "anita_text",
+ "anit_loc1",
+ "anit_loc2",
+ "anit_loc3",
+ "lamb_friend",
+ "lamb_sick",
+ "lamb_crawly",
+ "lamb_loc1",
+ "lamb_loc2",
+ "lamb_loc3",
+ "lamb_got_spanner",
+ "lamb_text",
+ "knows_auditor",
+ "lamb_security",
+ "lamb_auditor",
+ "fore_text",
+ "transporter_alive",
+ "anita_friend",
+ "anita_stop",
+ "anita_count",
+ "knows_security",
+ "fore_loc1",
+ "fore_loc2",
+ "fore_loc3",
+ "fore_friend",
+ "knows_dlinc",
+ "seen_lift",
+ "player_sound",
+ "guard_linc",
+ "guard_text",
+ "guar_loc1",
+ "guar_loc2",
+ "guar_loc3",
+ "guard_talk",
+ "lamb_out",
+ "guard_warning",
+ "wshp_loc1",
+ "wshp_loc2",
+ "wshp_loc3",
+ "jobs_linc",
+ "knows_port",
+ "jobs_port",
+ "joey_overmann",
+ "joey_count",
+ "knows_pipes",
+ "knows_hobart",
+ "fore_hobart",
+ "fore_overmann",
+ "anit_text",
+ "seen_eye",
+ "anita_dlinc",
+ "seen_dis_lift",
+ "lamb_move_anita",
+ "lamb_stat",
+ "machine_stops",
+ "guard_stat",
+ "guard_hobart",
+ "gordon_text",
+ "gord_loc1",
+ "gord_loc2",
+ "gord_loc3",
+ "lamb_hobart",
+ "anita_loc1",
+ "anita_loc2",
+ "anita_loc3",
+ "knows_elders",
+ "anita_elders",
+ "anita_overmann",
+ "stay_here",
+ "joey_pause",
+ "knows_break_in",
+ "joey_break_in",
+ "joey_lift",
+ "stair_talk",
+ "blown_top",
+ "tamper_flag",
+ "knows_reich",
+ "gordon_reich",
+ "open_panel",
+ "panel_count",
+ "wreck_text",
+ "press_button",
+ "touch_count",
+ "gordon_overmann",
+ "lamb_reich",
+ "exit_stores",
+ "henri_text",
+ "henr_loc1",
+ "henr_loc2",
+ "henr_loc3",
+ "got_sponsor",
+ "used_deodorant",
+ "lob_dad_text",
+ "lob_son_text",
+ "scan_talk",
+ "dady_loc1",
+ "dady_loc2",
+ "dady_loc3",
+ "samm_loc1",
+ "samm_loc2",
+ "samm_loc3",
+ "dirty_card",
+ "wrek_loc1",
+ "wrek_loc2",
+ "wrek_loc3",
+ "crushed_nuts",
+ "got_port",
+ "anita_port",
+ "got_jammer",
+ "knows_anita",
+ "anita_hobart",
+ "local_count",
+ "lamb_joey",
+ "stop_store",
+ "knows_suit",
+ "joey_box",
+ "asked_box",
+ "shell_count",
+ "got_cable",
+ "local_flag",
+ "search_flag",
+ "rad_count",
+ "rad_text",
+ "radm_loc1",
+ "radm_loc2",
+ "radm_loc3",
+ "gordon_off",
+ "knows_jobsworth",
+ "rad_back_flag",
+ "lamb_lift",
+ "knows_cat",
+ "lamb_screwed",
+ "tour_flag",
+ "foreman_reactor",
+ "foreman_anita",
+ "burke_text",
+ "burk_loc1",
+ "burk_loc2",
+ "burk_loc3",
+ "burke_anchor",
+ "jason_text",
+ "jaso_loc1",
+ "jaso_loc2",
+ "helg_loc2",
+ "say_to_helga",
+ "interest_count",
+ "anchor_text",
+ "anchor_overmann",
+ "anch_loc1",
+ "anch_loc2",
+ "anch_loc3",
+ "anchor_count",
+ "lamb_anchor",
+ "anchor_port",
+ "knows_stephen",
+ "knows_ghoul",
+ "anchor_talk",
+ "joey_hook",
+ "joey_done_dir",
+ "bios_loc1",
+ "bios_loc2",
+ "bios_loc3",
+ "got_hook",
+ "anchor_anita",
+ "trev_loc1",
+ "trev_loc2",
+ "trev_loc3",
+ "trevor_text",
+ "trev_text",
+ "trev_overmann",
+ "lamb_smell",
+ "art_flag",
+ "trev_computer",
+ "helga_text",
+ "helg_loc1",
+ "helg_loc3",
+ "bios_loc4",
+ "gallagher_text",
+ "gall_loc1",
+ "gall_loc2",
+ "gall_loc3",
+ "warn_lamb",
+ "open_apts",
+ "store_count",
+ "foreman_auditor",
+ "frozen_assets",
+ "read_report",
+ "seen_holo",
+ "knows_subway",
+ "exit_flag",
+ "father_text",
+ "lamb_fix",
+ "read_briefing",
+ "seen_shaft",
+ "knows_mother",
+ "console_type",
+ "hatch_selected",
+ "seen_walters",
+ "joey_fallen",
+ "jbel_loc1",
+ "lbel_loc1",
+ "lbel_loc2",
+ "jobsworth_speech",
+ "jobs_alert",
+ "jobs_alarmed_ref",
+ "safe_joey_recycle",
+ "safe_joey_sss",
+ "safe_joey_mission",
+ "safe_trans_mission",
+ "safe_slot_mission",
+ "safe_corner_mission",
+ "safe_joey_logic",
+ "safe_gordon_speech",
+ "safe_button_mission",
+ "safe_dad_speech",
+ "safe_son_speech",
+ "safe_skorl_speech",
+ "safe_uchar_speech",
+ "safe_wreck_speech",
+ "safe_anita_speech",
+ "safe_lamb_speech",
+ "safe_foreman_speech",
+ "joey_42_mission",
+ "joey_junction_mission",
+ "safe_welder_mission",
+ "safe_joey_weld",
+ "safe_radman_speech",
+ "safe_link_7_29",
+ "safe_link_29_7",
+ "safe_lamb_to_3",
+ "safe_lamb_to_2",
+ "safe_burke_speech",
+ "safe_burke_1",
+ "safe_burke_2",
+ "safe_dr_1",
+ "safe_body_speech",
+ "joey_bell",
+ "safe_anchor_speech",
+ "safe_anchor",
+ "safe_pc_mission",
+ "safe_hook_mission",
+ "safe_trevor_speech",
+ "joey_fact",
+ "safe_helga_speech",
+ "helga_mission",
+ "gal_bel_speech",
+ "safe_glass_mission",
+ "safe_lamb_fact_return",
+ "lamb_part_2",
+ "safe_lamb_bell_return",
+ "safe_lamb_bell",
+ "safe_cable_mission",
+ "safe_foster_tour",
+ "safe_lamb_tour",
+ "safe_foreman_logic",
+ "safe_lamb_leave",
+ "safe_lamb_3",
+ "safe_lamb_2",
+ "into_linc",
+ "out_10",
+ "out_74",
+ "safe_link_28_31",
+ "safe_link_31_28",
+ "safe_exit_linc",
+ "safe_end_game",
+ "which_linc",
+ "lift_moving",
+ "lift_on_screen",
+ "barrel_on_screen",
+ "convey_on_screen",
+ "shades_searched",
+ "joey_wiz",
+ "slot_slotted",
+ "motor_flag",
+ "panel_flag",
+ "switch_flag",
+ "steam_flag",
+ "steam_fx_no",
+ "factory_flag",
+ "power_door_open",
+ "left_skull_flag",
+ "right_skull_flag",
+ "monitor_watching",
+ "left_lever_flag",
+ "right_lever_flag",
+ "lobby_door_flag",
+ "weld_stop",
+ "cog_flag",
+ "sensor_flag",
+ "look_through",
+ "welder_nut_flag",
+ "s7_lift_flag",
+ "s29_lift_flag",
+ "whos_at_lift_7",
+ "whos_at_lift_29",
+ "lift_power",
+ "whats_joey",
+ "seen_box",
+ "seen_welder",
+ "flap_flag",
+ "s15_floor",
+ "foreman_friend",
+ "locker1_flag",
+ "locker2_flag",
+ "locker3_flag",
+ "whats_in_locker",
+ "knows_radsuit",
+ "radman_anita",
+ "at_anita",
+ "coat_flag",
+ "dressed_as",
+ "s14_take",
+ "reactor_door_flag",
+ "joey_in_lift",
+ "chair_27_flag",
+ "at_body_flag",
+ "at_gas_flag",
+ "anchor_seated",
+ "door_23_jam",
+ "door_20_jam",
+ "reich_door_flag",
+ "reich_door_jam",
+ "lamb_door_flag",
+ "lamb_door_jam",
+ "pillow_flag",
+ "cat_food_flag",
+ "helga_up",
+ "got_magazine",
+ "trevs_doing",
+ "card_status",
+ "card_fix",
+ "lamb_gallager",
+ "locker_11_flag",
+ "ever_opened",
+ "linc_10_flag",
+ "chair_10_flag",
+ "skorl_flag",
+ "lift_pause",
+ "lift_in_use",
+ "gordon_back",
+ "furnace_door_flag",
+ "whos_with_gall",
+ "read_news",
+ "whos_at_lift_28",
+ "s28_lift_flag",
+ "mission_state",
+ "anita_flag",
+ "card_used",
+ "gordon_catch",
+ "car_flag",
+ "first_jobs",
+ "jobs_removed",
+ "menu_id",
+ "tonys_tour_flag",
+ "joey_foster_phase",
+ "start_info_window",
+ "ref_slab_on",
+ "ref_up_mouse",
+ "ref_down_mouse",
+ "ref_left_mouse",
+ "ref_right_mouse",
+ "ref_disconnect_foster",
+ "k0",
+ "k1",
+ "k2",
+ "k3",
+ "k4",
+ "k5",
+ "k6",
+ "k7",
+ "k8",
+ "k9",
+ "k10",
+ "k11",
+ "k12",
+ "k13",
+ "k14",
+ "k15",
+ "k16",
+ "k17",
+ "k18",
+ "k19",
+ "k20",
+ "k21",
+ "k22",
+ "k23",
+ "k24",
+ "k25",
+ "k26",
+ "k27",
+ "k28",
+ "k29",
+ "a0",
+ "a1",
+ "a2",
+ "a3",
+ "a4",
+ "a5",
+ "a6",
+ "a7",
+ "a8",
+ "a9",
+ "a10",
+ "a11",
+ "a12",
+ "a13",
+ "a14",
+ "a15",
+ "a16",
+ "a17",
+ "a18",
+ "a19",
+ "a20",
+ "a21",
+ "a22",
+ "a23",
+ "a24",
+ "a25",
+ "a26",
+ "a27",
+ "a28",
+ "a29",
+ "g0",
+ "g1",
+ "g2",
+ "g3",
+ "g4",
+ "g5",
+ "g6",
+ "g7",
+ "g8",
+ "g9",
+ "g10",
+ "g11",
+ "g12",
+ "g13",
+ "g14",
+ "g15",
+ "g16",
+ "g17",
+ "g18",
+ "g19",
+ "g20",
+ "g21",
+ "g22",
+ "g23",
+ "g24",
+ "g25",
+ "g26",
+ "g27",
+ "g28",
+ "g29",
+ "window_subject",
+ "file_text",
+ "size_text",
+ "auth_text",
+ "note_text",
+ "id_head_compact",
+ "id_file_compact",
+ "id_size_compact",
+ "id_auth_compact",
+ "id_note_compact",
+ "pal_no",
+ "strikes",
+ "char_set_number",
+ "eye90_blinded",
+ "zap90",
+ "eye90_frame",
+ "eye91_blinded",
+ "zap91",
+ "eye91_frame",
+ "bag_open",
+ "bridge_a_on",
+ "bridge_b_on",
+ "bridge_c_on",
+ "bridge_d_on",
+ "bridge_e_on",
+ "bridge_f_on",
+ "bridge_g_on",
+ "bridge_h_on",
+ "green_slab",
+ "red_slab",
+ "foster_slab",
+ "circle_slab",
+ "slab1_mouse",
+ "slab2_mouse",
+ "slab3_mouse",
+ "slab4_mouse",
+ "slab5_mouse",
+ "at_guardian",
+ "guardian_there",
+ "crystal_shattered",
+ "virus_taken",
+ "fs_command",
+ "enter_digits",
+ "next_page",
+ "linc_digit_0",
+ "linc_digit_1",
+ "linc_digit_2",
+ "linc_digit_3",
+ "linc_digit_4",
+ "linc_digit_5",
+ "linc_digit_6",
+ "linc_digit_7",
+ "linc_digit_8",
+ "linc_digit_9",
+ "ref_std_on",
+ "ref_std_exit_left_on",
+ "ref_std_exit_right_on",
+ "ref_advisor_188",
+ "ref_shout_action",
+ "ref_mega_click",
+ "ref_mega_action",
+ "ref_walter_speech",
+ "ref_joey_medic",
+ "ref_joey_med_logic",
+ "ref_joey_med_mission72",
+ "ref_ken_logic",
+ "ref_ken_speech",
+ "ref_ken_mission_hand",
+ "ref_sc70_iris_opened",
+ "ref_sc70_iris_closed",
+ "ref_foster_enter_boardroom",
+ "ref_father_speech",
+ "ref_foster_enter_new_boardroom",
+ "ref_hobbins_speech",
+ "ref_sc82_jobs_sss",
+ "brickwork",
+ "door_67_68_flag",
+ "crowbar_in_clot",
+ "clot_ruptured",
+ "clot_repaired",
+ "walt_text",
+ "walt_loc1",
+ "walt_loc2",
+ "walt_loc3",
+ "walt_count",
+ "medic_text",
+ "seen_room_72",
+ "seen_tap",
+ "joey_med_seen72",
+ "seen_secure_door",
+ "ask_secure_door",
+ "sc70_iris_flag",
+ "sc70_iris_frame",
+ "foster_on_sc70_iris",
+ "sc70_grill_flag",
+ "sc71_charging_flag",
+ "sc72_slime_flag",
+ "sc72_witness_sees_foster",
+ "sc72_witness_killed",
+ "sc73_gallagher_killed",
+ "sc73_removed_board",
+ "sc73_searched_corpse",
+ "door_73_75_flag",
+ "sc74_sitting_flag",
+ "sc75_crashed_flag",
+ "sc75_tissue_infected",
+ "sc75_tongs_flag",
+ "sc76_cabinet1_flag",
+ "sc76_cabinet2_flag",
+ "sc76_cabinet3_flag",
+ "sc76_board_flag",
+ "sc76_ken_prog_flag",
+ "sc76_and2_up_flag",
+ "ken_text",
+ "ken_door_flag",
+ "sc77_foster_hand_flag",
+ "sc77_ken_hand_flag",
+ "door_77_78_flag",
+ "sc80_exit_flag",
+ "ref_danielle_speech",
+ "ref_danielle_go_home",
+ "ref_spunky_go_home",
+ "ref_henri_speech",
+ "ref_buzzer_speech",
+ "ref_foster_visit_dani",
+ "ref_danielle_logic",
+ "ref_jukebox_speech",
+ "ref_vincent_speech",
+ "ref_eddie_speech",
+ "ref_blunt_speech",
+ "ref_dani_answer_phone",
+ "ref_spunky_see_video",
+ "ref_spunky_bark_at_foster",
+ "ref_spunky_smells_food",
+ "ref_barry_speech",
+ "ref_colston_speech",
+ "ref_gallagher_speech",
+ "ref_babs_speech",
+ "ref_chutney_speech",
+ "ref_foster_enter_court",
+ "dani_text",
+ "dani_loc1",
+ "dani_loc2",
+ "dani_loc3",
+ "dani_buff",
+ "dani_huff",
+ "mother_hobart",
+ "foster_id_flag",
+ "knows_spunky",
+ "dog_fleas",
+ "op_flag",
+ "chat_up",
+ "buzz_loc1",
+ "buzz_loc2",
+ "blunt_text",
+ "blun_loc1",
+ "blun_loc2",
+ "blun_loc3",
+ "blunt_dan_info",
+ "vincent_text",
+ "vinc_loc1",
+ "vinc_loc2",
+ "vinc_loc3",
+ "eddie_text",
+ "eddi_loc1",
+ "eddi_loc2",
+ "eddi_loc3",
+ "knows_dandelions",
+ "barry_text",
+ "bazz_loc1",
+ "bazz_loc2",
+ "bazz_loc3",
+ "seen_cellar_door",
+ "babs_text",
+ "babs_loc1",
+ "babs_loc2",
+ "babs_loc3",
+ "colston_text",
+ "cols_loc1",
+ "cols_loc2",
+ "cols_loc3",
+ "jukebox",
+ "knows_soaking",
+ "knows_complaint",
+ "dog_bite",
+ "new_prints",
+ "knows_virus",
+ "been_to_court",
+ "danielle_target",
+ "spunky_target",
+ "henri_forward",
+ "sc31_lift_flag",
+ "sc31_food_on_plank",
+ "sc31_spunky_at_plank",
+ "dog_in_lake",
+ "sc32_lift_flag",
+ "sc33_shed_door_flag",
+ "gardener_up",
+ "babs_x",
+ "babs_y",
+ "foster_caching",
+ "colston_caching",
+ "band_playing",
+ "colston_at_table",
+ "sc36_next_dealer",
+ "sc36_door_flag",
+ "sc37_door_flag",
+ "sc37_lid_loosened",
+ "sc37_lid_used",
+ "sc37_standing_on_box",
+ "sc37_box_broken",
+ "sc37_grill_state",
+ "got_dog_biscuits",
+ "sc38_video_playing",
+ "dani_on_phone",
+ "sc40_locker_1_flag",
+ "sc40_locker_2_flag",
+ "sc40_locker_3_flag",
+ "sc40_locker_4_flag",
+ "sc40_locker_5_flag",
+ "seen_anita_corpse",
+ "spunky_at_lift",
+ "court_text",
+ "blunt_knew_jobs",
+ "credit_1_text",
+ "credit_2_text",
+ "id_credit_1",
+ "id_credit_2",
+ "glass_stolen",
+ "foster_at_plank",
+ "foster_at_guard",
+ "man_talk",
+ "man_loc1",
+ "man_loc2",
+ "man_loc3"
+};
+
+void Debug::fetchCompact(uint32 a) {
+ uint32 sectionNum = (a & 0xf000) >> 12;
+ uint32 compactNum = (a & 0x0fff);
+
+ if (sectionNum == 0)
+ debug(8, "Loading Compact %d (%s) from section %d", compactNum, section_0_compacts[compactNum], sectionNum);
+ else
+ debug(8, "Loading Compact %d from section %d", compactNum, sectionNum);
+}
+
+void Debug::logic(uint32 logic) {
+ debug(6, "LOGIC: %s", logic_table_names[logic]);
+}
+
+void Debug::script(uint32 command, uint16 *scriptData) {
+ debug(6, "SCRIPT: %s", opcodes[command]);
+ if (command == 0 || command == 6)
+ debug(6, " %s", scriptVars[READ_LE_UINT16(scriptData)/4]);
+ else {
+ int i;
+ for (i = 0; i < opcode_par[command]; i++) {
+ debug(6, " %d", READ_LE_UINT16(scriptData + i));
+ }
+ }
+ debug(6, "");
+}
+
+void Debug::mcode(uint32 mcode, uint32 a, uint32 b, uint32 c) {
+ debug(6, "MCODE: %s(%d, %d, %d)", mcodes[mcode], a, b, c);
+}
+
+
+
+
+Debugger::Debugger(Logic *logic, Mouse *mouse, Screen *screen, SkyCompact *skyCompact)
+: Common::Debugger<Debugger>(), _logic(logic), _mouse(mouse), _screen(screen), _skyCompact(skyCompact), _showGrid(false) {
+ DCmd_Register("exit", &Debugger::Cmd_Exit);
+ DCmd_Register("help", &Debugger::Cmd_Help);
+ DCmd_Register("info", &Debugger::Cmd_Info);
+ DCmd_Register("showgrid", &Debugger::Cmd_ShowGrid);
+ DCmd_Register("reloadgrid", &Debugger::Cmd_ReloadGrid);
+ DCmd_Register("compact", &Debugger::Cmd_ShowCompact);
+ DCmd_Register("logiccmd", &Debugger::Cmd_LogicCommand);
+ DCmd_Register("scriptvar", &Debugger::Cmd_ScriptVar);
+ DCmd_Register("section", &Debugger::Cmd_Section);
+}
+
+Debugger::~Debugger() {} // we need this here for __SYMBIAN32__
+
+void Debugger::preEnter() {
+
+}
+
+void Debugger::postEnter() {
+ _mouse->resetCursor();
+}
+
+bool Debugger::Cmd_Exit(int argc, const char **argv) {
+ _detach_now = true;
+ return false;
+}
+
+bool Debugger::Cmd_Help(int argc, const char **argv) {
+ // console normally has 39 line width
+ // wrap around nicely
+ int width = 0, size;
+
+ DebugPrintf("Commands are:\n");
+ for (int i = 0; i < _dcmd_count; ++i) {
+ size = strlen(_dcmds[i].name) + 1;
+
+ if ((width + size) >= 39) {
+ DebugPrintf("\n");
+ width = size;
+ } else {
+ width += size;
+ }
+
+ DebugPrintf("%s ", _dcmds[i].name);
+ }
+ DebugPrintf("\n");
+ return true;
+}
+
+bool Debugger::Cmd_ShowGrid(int argc, const char **argv) {
+ _showGrid = !_showGrid;
+ DebugPrintf("Show grid: %s\n", _showGrid ? "On" : "Off");
+ if (!_showGrid) _screen->forceRefresh();
+ return true;
+}
+
+bool Debugger::Cmd_ReloadGrid(int argc, const char **argv) {
+ _logic->_skyGrid->loadGrids();
+ DebugPrintf("Grid reloaded\n");
+ return true;
+}
+
+bool Debugger::Cmd_ShowCompact(int argc, const char **argv) {
+ if (argc < 2) {
+ DebugPrintf("Example: %s foster\n", argv[0]);
+ return true;
+ }
+
+ int i;
+ int numCompacts = ARRAYSIZE(section_0_compacts);
+
+ if (0 == strcmp(argv[1], "list")) {
+ for (i = 0; i < numCompacts; ++i) {
+ DebugPrintf("%s\n", section_0_compacts[i]);
+ }
+ return true;
+ }
+
+ Compact *cpt = 0;
+
+ for (i = 0; i < numCompacts; ++i) {
+ if (0 == strcmp(section_0_compacts[i], argv[1])) {
+ cpt = _skyCompact->fetchCpt(i);
+ break;
+ }
+ }
+
+ if (cpt) {
+ DebugPrintf("------Compact %d ('%s')------\n", i, section_0_compacts[i]);
+ DebugPrintf("logic : %d\n", cpt->logic);
+ DebugPrintf("status : %d\n", cpt->status);
+ DebugPrintf("sync : %d\n", cpt->sync);
+ DebugPrintf("screen : %d\n", cpt->screen);
+ DebugPrintf("x/y : %d/%d\n", cpt->xcood, cpt->ycood);
+ DebugPrintf("place cpt : %d\n", cpt->place);
+ DebugPrintf("getToFlag : %d\n", cpt->getToFlag);
+ DebugPrintf("mode : %d\n", cpt->mode);
+ // Mega / extCompact info
+ /*if (cpt->extCompact) {
+ DebugPrintf("waitingFor : %d\n", cpt->extCompact->waitingFor);
+ DebugPrintf("arTargetX/Y: %d/%d\n", cpt->extCompact->arTargetX, cpt->extCompact->arTargetY);
+ }*/
+ } else {
+ DebugPrintf("Unknown compact: '%s'\n", argv[1]);
+ }
+
+ return true;
+}
+
+bool Debugger::Cmd_LogicCommand(int argc, const char **argv) {
+ if (argc < 2) {
+ DebugPrintf("Example: %s fn_printf 42\n", argv[0]);
+ return true;
+ }
+
+ int numMCodes = ARRAYSIZE(mcodes);
+
+ if (0 == strcmp(argv[1], "list")) {
+ for (int i = 0; i < numMCodes; ++i) {
+ DebugPrintf("%s\n", mcodes[i]);
+ }
+ return true;
+ }
+
+ uint32 arg1 = 0, arg2 = 0, arg3 = 0;
+
+ switch (argc) {
+ case 5:
+ arg3 = atoi(argv[4]);
+ case 4:
+ arg2 = atoi(argv[3]);
+ case 3:
+ arg1 = atoi(argv[2]);
+ }
+
+ for (int i = 0; i < numMCodes; ++i) {
+ if (0 == strcmp(mcodes[i], argv[1])) {
+ _logic->fnExec(i, arg1, arg2, arg3);
+ return true;
+ }
+ }
+
+ DebugPrintf("Unknown function: '%s'\n", argv[1]);
+
+ return true;
+}
+
+bool Debugger::Cmd_Info(int argc, const char **argv) {
+ DebugPrintf("Beneath a Steel Sky version: 0.0%d\n", SkyEngine::_systemVars.gameVersion);
+ DebugPrintf("Speech: %s\n", (SkyEngine::_systemVars.systemFlags & SF_ALLOW_SPEECH) ? "on" : "off");
+ DebugPrintf("Text : %s\n", (SkyEngine::_systemVars.systemFlags & SF_ALLOW_TEXT) ? "on" : "off");
+ return true;
+}
+
+bool Debugger::Cmd_ScriptVar(int argc, const char **argv) {
+ if (argc < 2) {
+ DebugPrintf("Example: %s lamb_friend <value>\n", argv[0]);
+ return true;
+ }
+
+ int numScriptVars = ARRAYSIZE(scriptVars);
+
+ if (0 == strcmp(argv[1], "list")) {
+ for (int i = 0; i < numScriptVars; ++i) {
+ DebugPrintf("%s\n", scriptVars[i]);
+ }
+ return true;
+ }
+
+ for (int i = 0; i < numScriptVars; ++i) {
+ if (0 == strcmp(scriptVars[i], argv[1])) {
+ if (argc == 3) {
+ Logic::_scriptVariables[i] = atoi(argv[2]);
+ }
+ DebugPrintf("%s = %d\n", argv[1], Logic::_scriptVariables[i]);
+
+ return true;
+ }
+ }
+
+ DebugPrintf("Unknown ScriptVar: '%s'\n", argv[1]);
+
+ return true;
+}
+
+bool Debugger::Cmd_Section(int argc, const char **argv) {
+ if (argc < 2) {
+ DebugPrintf("Example: %s 4\n", argv[0]);
+ return true;
+ }
+
+ const int baseId[] = { START_ONE, START_S6, START_29, START_SC31, START_SC66, START_SC90, START_SC81 };
+ int section = atoi(argv[1]);
+
+ if (section >= 0 && section <= 6) {
+ _logic->fnEnterSection(section == 6 ? 4 : section, 0, 0);
+ _logic->fnAssignBase(ID_FOSTER, baseId[section], 0);
+ _skyCompact->fetchCpt(ID_FOSTER)->megaSet = 0;
+ } else {
+ DebugPrintf("Unknown section '%s'\n", argv[1]);
+ }
+
+ return true;
+}
+
+} // End of namespace Sky
diff --git a/engines/sky/debug.h b/engines/sky/debug.h
new file mode 100644
index 0000000000..8fdb46d2e1
--- /dev/null
+++ b/engines/sky/debug.h
@@ -0,0 +1,76 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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 SKY_DEBUG_H
+#define SKY_DEBUG_H
+
+#include "common/stdafx.h"
+#include "common/scummsys.h"
+#include "common/debugger.h"
+
+namespace Sky {
+
+class Logic;
+class Mouse;
+class Screen;
+class SkyCompact;
+
+class Debugger : public Common::Debugger<Debugger> {
+public:
+ Debugger(Logic *logic, Mouse *mouse, Screen *screen, SkyCompact *skyCompact);
+ virtual ~Debugger(); // we need this here for __SYMBIAN32__ archaic gcc/UIQ
+ bool showGrid() { return _showGrid; }
+
+protected:
+ virtual void preEnter();
+ virtual void postEnter();
+
+ bool Cmd_Exit(int argc, const char **argv);
+ bool Cmd_Help(int argc, const char **argv);
+ bool Cmd_ShowGrid(int argc, const char **argv);
+ bool Cmd_ReloadGrid(int argc, const char **argv);
+ bool Cmd_ShowCompact(int argc, const char **argv);
+ bool Cmd_LogicCommand(int argc, const char **argv);
+ bool Cmd_Info(int argc, const char **argv);
+ bool Cmd_ScriptVar(int argc, const char **argv);
+ bool Cmd_Section(int argc, const char **argv);
+
+ Logic *_logic;
+ Mouse *_mouse;
+ Screen *_screen;
+ SkyCompact *_skyCompact;
+
+ bool _showGrid;
+};
+
+
+class Debug {
+public:
+ static void fetchCompact(uint32 a);
+ static void logic(uint32 logic);
+ static void script(uint32 command, uint16 *scriptData);
+ static void mcode(uint32 mcode, uint32 a, uint32 b, uint32 c);
+};
+
+} // End of namespace Sky
+
+#endif
diff --git a/engines/sky/disk.cpp b/engines/sky/disk.cpp
new file mode 100644
index 0000000000..3c39a287d0
--- /dev/null
+++ b/engines/sky/disk.cpp
@@ -0,0 +1,375 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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/file.h"
+#include "common/util.h"
+#include "common/scummsys.h"
+#include "sky/disk.h"
+#include "sky/rnc_deco.h"
+#include "sky/sky.h"
+#include "sky/struc.h"
+
+namespace Sky {
+
+static const char *dataFilename = "sky.dsk";
+static const char *dinnerFilename = "sky.dnr";
+
+Disk::Disk(const Common::String &gameDataPath) {
+ _dataDiskHandle = new Common::File();
+ _dnrHandle = new Common::File();
+
+ _dnrHandle->open(dinnerFilename);
+ if (!_dnrHandle->isOpen())
+ error("Could not open %s%s", gameDataPath.c_str(), dinnerFilename);
+
+ if (!(_dinnerTableEntries = _dnrHandle->readUint32LE()))
+ error("Error reading from sky.dnr"); //even though it was opened correctly?!
+
+ _dinnerTableArea = (uint8 *)malloc(_dinnerTableEntries * 8);
+ uint32 entriesRead = _dnrHandle->read(_dinnerTableArea, 8 * _dinnerTableEntries) / 8;
+
+ if (entriesRead != _dinnerTableEntries)
+ error("entriesRead != dinnerTableEntries. [%d/%d]", entriesRead, _dinnerTableEntries);
+
+ _dataDiskHandle->open(dataFilename);
+ if (!_dataDiskHandle->isOpen())
+ error("Error opening %s%s", gameDataPath.c_str(), dataFilename);
+
+ printf("Found BASS version v0.0%d (%d dnr entries)\n", determineGameVersion(), _dinnerTableEntries);
+
+ memset(_buildList, 0, 60 * 2);
+ memset(_loadedFilesList, 0, 60 * 4);
+}
+
+Disk::~Disk(void) {
+ if (_dnrHandle->isOpen())
+ _dnrHandle->close();
+ if (_dataDiskHandle->isOpen())
+ _dataDiskHandle->close();
+ fnFlushBuffers();
+ free(_dinnerTableArea);
+ delete _dnrHandle;
+ delete _dataDiskHandle;
+}
+
+bool Disk::fileExists(uint16 fileNr) {
+ return (getFileInfo(fileNr) != NULL);
+}
+
+// allocate memory, load the file and return a pointer
+uint8 *Disk::loadFile(uint16 fileNr) {
+
+ uint8 cflag;
+
+ debug(2, "load file %d,%d (%d)", (fileNr >> 11), (fileNr & 2047), fileNr);
+
+ uint8 *fileInfoPtr = getFileInfo(fileNr);
+ if (fileInfoPtr == NULL) {
+ debug(1, "File %d not found", fileNr);
+ return NULL;
+ }
+
+ uint32 fileFlags = READ_LE_UINT24(fileInfoPtr + 5);
+ uint32 fileSize = fileFlags & 0x03fffff;
+ uint32 fileOffset = READ_LE_UINT32(fileInfoPtr + 2) & 0x0ffffff;
+
+ _lastLoadedFileSize = fileSize;
+ cflag = (uint8)((fileOffset >> 23) & 0x1);
+ fileOffset &= 0x7FFFFF;
+
+ if (cflag) {
+ if (SkyEngine::_systemVars.gameVersion == 331)
+ fileOffset <<= 3;
+ else
+ fileOffset <<= 4;
+ }
+
+ uint8 *fileDest = (uint8 *)malloc(fileSize + 4); // allocate memory for file
+
+ _dataDiskHandle->seek(fileOffset, SEEK_SET);
+
+ //now read in the data
+ int32 bytesRead = _dataDiskHandle->read(fileDest, fileSize);
+
+ if (bytesRead != (int32)fileSize)
+ warning("Unable to read %d bytes from datadisk (%d bytes read)", fileSize, bytesRead);
+
+ cflag = (uint8)((fileFlags >> 23) & 0x1);
+ //if cflag == 0 then file is compressed, 1 == uncompressed
+
+ dataFileHeader *fileHeader = (dataFileHeader*)fileDest;
+
+ if ((!cflag) && ((FROM_LE_16(fileHeader->flag) >> 7) & 1)) {
+ debug(2, "File is RNC compressed.");
+
+ uint32 decompSize = (FROM_LE_16(fileHeader->flag) & ~0xFF) << 8;
+ decompSize |= FROM_LE_16(fileHeader->s_tot_size);
+
+ uint8 *uncompDest = (uint8 *)malloc(decompSize);
+
+ int32 unpackLen;
+ void *output, *input = fileDest + sizeof(dataFileHeader);
+
+ if ((fileFlags >> 22) & 0x1) { //do we include the header?
+ // don't return the file's header
+ output = uncompDest;
+ unpackLen = _rncDecoder.unpackM1(input, output, 0);
+ } else {
+#ifdef SCUMM_BIG_ENDIAN
+ // Convert dataFileHeader to BE (it only consists of 16 bit words)
+ uint16 *headPtr = (uint16 *)fileDest;
+ for (uint i = 0; i < sizeof(struct dataFileHeader) / 2; i++)
+ *(headPtr + i) = READ_LE_UINT16(headPtr + i);
+#endif
+
+ memcpy(uncompDest, fileDest, sizeof(dataFileHeader));
+ output = uncompDest + sizeof(dataFileHeader);
+ unpackLen = _rncDecoder.unpackM1(input, output, 0);
+ if (unpackLen)
+ unpackLen += sizeof(dataFileHeader);
+ }
+
+ debug(3, "UnpackM1 returned: %d", unpackLen);
+
+ if (unpackLen == 0) { //Unpack returned 0: file was probably not packed.
+ free(uncompDest);
+ return fileDest;
+ } else {
+ if (unpackLen != (int32)decompSize)
+ debug(1, "ERROR: File %d: invalid decomp size! (was: %d, should be: %d)", fileNr, unpackLen, decompSize);
+ _lastLoadedFileSize = decompSize;
+
+ free(fileDest);
+ return uncompDest;
+ }
+ } else {
+#ifdef SCUMM_BIG_ENDIAN
+ if (!cflag) {
+ uint16 *headPtr = (uint16 *)fileDest;
+ for (uint i = 0; i < sizeof(struct dataFileHeader) / 2; i++)
+ *(headPtr + i) = READ_LE_UINT16(headPtr + i);
+ }
+#endif
+ return fileDest;
+ }
+}
+
+uint16 *Disk::loadScriptFile(uint16 fileNr) {
+ uint16 *buf = (uint16*)loadFile(fileNr);
+#ifdef SCUMM_BIG_ENDIAN
+ for (uint i = 0; i < _lastLoadedFileSize / 2; i++)
+ buf[i] = FROM_LE_16(buf[i]);
+#endif
+ return buf;
+}
+
+uint8 *Disk::getFileInfo(uint16 fileNr) {
+
+ uint16 i;
+ uint16 *dnrTbl16Ptr = (uint16 *)_dinnerTableArea;
+
+ for (i = 0; i < _dinnerTableEntries; i++) {
+ if (READ_LE_UINT16(dnrTbl16Ptr) == fileNr) {
+ debug(2, "file %d found!", fileNr);
+ return (uint8 *)dnrTbl16Ptr;
+ }
+ dnrTbl16Ptr += 4;
+ }
+
+ return 0; //not found
+}
+
+void Disk::fnCacheChip(uint16 *fList) {
+
+ // fnCacheChip is called after fnCacheFast
+ uint16 cnt = 0;
+ while (_buildList[cnt])
+ cnt++;
+ uint16 fCnt = 0;
+ do {
+ _buildList[cnt + fCnt] = fList[fCnt] & 0x7FFFU;
+ fCnt++;
+ } while (fList[fCnt-1]);
+ fnCacheFiles();
+}
+
+void Disk::fnCacheFast(uint16 *fList) {
+ if (fList != NULL) {
+ uint8 cnt = 0;
+ do {
+ _buildList[cnt] = fList[cnt] & 0x7FFFU;
+ cnt++;
+ } while (fList[cnt-1]);
+ }
+}
+
+void Disk::fnCacheFiles(void) {
+
+ uint16 lCnt, bCnt, targCnt;
+ targCnt = lCnt = 0;
+ bool found;
+ while (_loadedFilesList[lCnt]) {
+ bCnt = 0;
+ found = false;
+ while (_buildList[bCnt] && (!found)) {
+ if ((_buildList[bCnt] & 0x7FFFU) == _loadedFilesList[lCnt])
+ found = true;
+ else
+ bCnt++;
+ }
+ if (found) {
+ _loadedFilesList[targCnt] = _loadedFilesList[lCnt];
+ targCnt++;
+ } else {
+ free(SkyEngine::_itemList[_loadedFilesList[lCnt] & 2047]);
+ SkyEngine::_itemList[_loadedFilesList[lCnt] & 2047] = NULL;
+ }
+ lCnt++;
+ }
+ _loadedFilesList[targCnt] = 0; // mark end of list
+ bCnt = 0;
+ while (_buildList[bCnt]) {
+ if ((_buildList[bCnt] & 0x7FF) == 0x7FF) {
+ // amiga dummy files
+ bCnt++;
+ continue;
+ }
+ lCnt = 0;
+ found = false;
+ while (_loadedFilesList[lCnt] && (!found)) {
+ if (_loadedFilesList[lCnt] == (_buildList[bCnt] & 0x7FFFU))
+ found = true;
+ lCnt++;
+ }
+ if (found) {
+ bCnt++;
+ continue;
+ }
+ // ok, we really have to load the file.
+ _loadedFilesList[targCnt] = _buildList[bCnt] & 0x7FFFU;
+ targCnt++;
+ _loadedFilesList[targCnt] = 0;
+ SkyEngine::_itemList[_buildList[bCnt] & 2047] = (void**)loadFile(_buildList[bCnt] & 0x7FFF);
+ if (!SkyEngine::_itemList[_buildList[bCnt] & 2047])
+ warning("fnCacheFiles: Disk::loadFile() returned NULL for file %d",_buildList[bCnt] & 0x7FFF);
+ bCnt++;
+ }
+ _buildList[0] = 0;
+}
+
+void Disk::refreshFilesList(uint32 *list) {
+
+ uint8 cnt = 0;
+ while (_loadedFilesList[cnt]) {
+ if (SkyEngine::_itemList[_loadedFilesList[cnt] & 2047])
+ free(SkyEngine::_itemList[_loadedFilesList[cnt] & 2047]);
+ SkyEngine::_itemList[_loadedFilesList[cnt] & 2047] = NULL;
+ cnt++;
+ }
+ cnt = 0;
+ while (list[cnt]) {
+ _loadedFilesList[cnt] = list[cnt];
+ SkyEngine::_itemList[_loadedFilesList[cnt] & 2047] = (void**)loadFile((uint16)(_loadedFilesList[cnt] & 0x7FFF));
+ cnt++;
+ }
+ _loadedFilesList[cnt] = 0;
+}
+
+void Disk::fnMiniLoad(uint16 fileNum) {
+
+ uint16 cnt = 0;
+ while (_loadedFilesList[cnt]) {
+ if (_loadedFilesList[cnt] == fileNum)
+ return;
+ cnt++;
+ }
+ _loadedFilesList[cnt] = fileNum & 0x7FFFU;
+ _loadedFilesList[cnt + 1] = 0;
+ SkyEngine::_itemList[fileNum & 2047] = (void**)loadFile(fileNum);
+}
+
+void Disk::fnFlushBuffers(void) {
+
+ // dump all loaded sprites
+ uint8 lCnt = 0;
+ while (_loadedFilesList[lCnt]) {
+ free(SkyEngine::_itemList[_loadedFilesList[lCnt] & 2047]);
+ SkyEngine::_itemList[_loadedFilesList[lCnt] & 2047] = NULL;
+ lCnt++;
+ }
+ _loadedFilesList[0] = 0;
+}
+
+void Disk::dumpFile(uint16 fileNr) {
+ char buf[128];
+ Common::File out;
+ byte* filePtr;
+
+ filePtr = loadFile(fileNr);
+ sprintf(buf, "dumps/file-%d.dmp", fileNr);
+
+ if (!out.exists(buf, "")) {
+ if (out.open(buf, Common::File::kFileWriteMode, ""))
+ out.write(filePtr, _lastLoadedFileSize);
+ }
+ free(filePtr);
+}
+
+uint32 Disk::determineGameVersion() {
+ //determine game version based on number of entries in dinner table
+ switch (_dinnerTableEntries) {
+ case 243:
+ // pc gamer demo (v0.0109)
+ return 109;
+ case 247:
+ //floppy demo (v0.0267)
+ return 267;
+ case 1404:
+ //floppy (v0.0288)
+ return 288;
+ case 1413:
+ //floppy (v0.0303)
+ return 303;
+ case 1445:
+ //floppy (v0.0331 or v0.0348)
+ if (_dataDiskHandle->size() == 8830435)
+ return 348;
+ else
+ return 331;
+ case 1711:
+ //cd demo (v0.0365)
+ return 365;
+ case 5099:
+ //cd (v0.0368)
+ return 368;
+ case 5097:
+ //cd (v0.0372)
+ return 372;
+ default:
+ //unknown version
+ error("Unknown game version! %d dinner table entries", _dinnerTableEntries);
+ break;
+ }
+}
+
+} // End of namespace Sky
diff --git a/engines/sky/disk.h b/engines/sky/disk.h
new file mode 100644
index 0000000000..4d2fe4c294
--- /dev/null
+++ b/engines/sky/disk.h
@@ -0,0 +1,76 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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 SKYDISK_H
+#define SKYDISK_H
+
+#include "common/stdafx.h"
+#include "common/scummsys.h"
+#include "common/str.h"
+#include "sky/rnc_deco.h"
+
+#define MAX_FILES_IN_LIST 60
+
+namespace Common {
+ class File;
+}
+
+namespace Sky {
+
+class Disk {
+public:
+ Disk(const Common::String &gameDataPath);
+ ~Disk(void);
+
+ uint8 *loadFile(uint16 fileNr);
+ uint16 *loadScriptFile(uint16 fileNr);
+ bool fileExists(uint16 fileNr);
+
+ uint32 determineGameVersion();
+
+ uint32 _lastLoadedFileSize;
+
+ void fnMiniLoad(uint16 fileNum);
+ void fnCacheFast(uint16 *fList);
+ void fnCacheChip(uint16 *fList);
+ void fnCacheFiles(void);
+ void fnFlushBuffers(void);
+ uint32 *giveLoadedFilesList(void) { return _loadedFilesList; };
+ void refreshFilesList(uint32 *list);
+
+protected:
+ uint8 *getFileInfo(uint16 fileNr);
+ void dumpFile(uint16 fileNr);
+
+ uint32 _dinnerTableEntries;
+ uint8 *_dinnerTableArea;
+ Common::File *_dataDiskHandle;
+ Common::File *_dnrHandle;
+ RncDecoder _rncDecoder;
+
+ uint16 _buildList[MAX_FILES_IN_LIST];
+ uint32 _loadedFilesList[MAX_FILES_IN_LIST];
+};
+
+} // End of namespace Sky
+
+#endif
diff --git a/engines/sky/grid.cpp b/engines/sky/grid.cpp
new file mode 100644
index 0000000000..7becff74d5
--- /dev/null
+++ b/engines/sky/grid.cpp
@@ -0,0 +1,260 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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 "sky/compact.h"
+#include "sky/disk.h"
+#include "sky/grid.h"
+#include "sky/logic.h"
+#include "sky/compact.h"
+
+namespace Sky {
+
+#define GRID_FILE_START 60000
+
+int8 Grid::_gridConvertTable[] = {
+
+ 0, //0
+ 1, //1
+ 2, //2
+ 3, //3
+ 4, //4
+ 5, //5
+ 6, //6
+ 7, //7
+ 8, //8
+ 9, //9
+ 10, //10
+ 11, //11
+ 12, //12
+ 13, //13
+ 14, //14
+ 15, //15
+ 16, //16
+ 17, //17
+ 18, //18
+ 19, //19
+ 20, //20
+ 21, //21
+ 22, //22
+ 23, //23
+ 24, //24
+ 25, //25
+ 26, //26
+ 27, //27
+ 28, //28
+ 29, //29
+ 30, //30
+ 31, //31
+ 32, //32
+ 33, //33
+ 34, //34
+ -1, //35
+ 35, //36
+ 36, //37
+ 37, //38
+ 38, //39
+ 39, //40
+ 40, //41
+ 41, //42
+ -1, //43
+ 42, //44
+ 43, //45
+ 44, //46
+ 45, //47
+ 46, //48
+ -1, //49
+ -1, //50
+ -1, //51
+ -1, //52
+ -1, //53
+ -1, //54
+ -1, //55
+ -1, //56
+ -1, //57
+ -1, //58
+ -1, //59
+ -1, //60
+ -1, //61
+ -1, //62
+ -1, //63
+ -1, //64
+ 47, //65
+ TOT_NO_GRIDS, //66
+ 48, //67
+ 49, //68
+ 50, //69
+ 51, //70
+ 52, //71
+ 53, //72
+ 54, //73
+ 55, //74
+ 56, //75
+ 57, //76
+ 58, //77
+ 59, //78
+ 60, //79
+ -1, //80
+ 61, //81
+ 62, //82
+ -1, //83
+ -1, //84
+ -1, //85
+ -1, //86
+ -1, //87
+ -1, //88
+ TOT_NO_GRIDS, //89
+ 63, //90
+ 64, //91
+ 65, //92
+ 66, //93
+ 67, //94
+ 68, //95
+ 69, //96
+};
+
+Grid::Grid(Disk *pDisk, SkyCompact *skyCompact) {
+ for (int cnt = 0; cnt < TOT_NO_GRIDS; cnt++)
+ _gameGrids[cnt] = NULL;
+ _skyDisk = pDisk;
+ _skyCompact = skyCompact;
+}
+
+Grid::~Grid(void) {
+ for (uint8 cnt = 0; cnt < TOT_NO_GRIDS; cnt++)
+ if (_gameGrids[cnt])
+ free(_gameGrids[cnt]);
+}
+
+void Grid::loadGrids(void) {
+ // no endian conversion necessary as I'm using uint8* instead of uint32*
+ for (uint8 cnt = 0; cnt < TOT_NO_GRIDS; cnt++) {
+ if (_gameGrids[cnt])
+ free(_gameGrids[cnt]);
+ _gameGrids[cnt] = _skyDisk->loadFile(GRID_FILE_START + cnt);
+ }
+ if (!SkyEngine::isDemo()) { // single disk demos never get that far
+ // Reloading the grids can sometimes cause problems eg when reichs door is
+ // open the door grid bit gets replaced so you can't get back in (or out)
+ if (Logic::_scriptVariables[REICH_DOOR_FLAG])
+ removeGrid(256, 280, 1, _skyCompact->fetchCpt(CPT_REICH_DOOR_20));
+ //removeGrid(256, 280, 1, &SkyCompact::reich_door_20);
+ }
+}
+
+bool Grid::getGridValues(Compact *cpt, uint8 *resGrid, uint32 *resBitNum, uint32 *resWidth) {
+ uint16 width = SkyCompact::getMegaSet(cpt)->gridWidth;
+ return getGridValues(cpt->xcood, cpt->ycood, width, cpt, resGrid, resBitNum, resWidth);
+}
+
+bool Grid::getGridValues(uint32 x, uint32 y, uint32 width, Compact *cpt, uint8 *resGrid, uint32 *resBitNum, uint32 *resWidth) {
+ uint32 bitPos;
+ if (y < TOP_LEFT_Y)
+ return false; // off screen
+ y -= TOP_LEFT_Y;
+ y >>= 3; // convert to blocks
+ if (y >= GAME_SCREEN_HEIGHT >> 3)
+ return false; // off screen
+ bitPos = y * 40;
+ width++;
+ x >>= 3; // convert to blocks
+
+ if (x < (TOP_LEFT_X >> 3)) { // at least partially off screen
+ if (x + width < (TOP_LEFT_X >> 3))
+ return false; // completely off screen
+ else {
+ width -= (TOP_LEFT_X >> 3) - x;
+ x = 0;
+ }
+ } else
+ x -= TOP_LEFT_X >> 3;
+
+ if ((GAME_SCREEN_WIDTH >> 3) <= x)
+ return false; // off screen
+ if ((GAME_SCREEN_WIDTH >> 3) < x + width) // partially off screen
+ width = (GAME_SCREEN_WIDTH >> 3) - x;
+
+ bitPos += x;
+ assert((_gridConvertTable[cpt->screen] >= 0) && (_gridConvertTable[cpt->screen] < TOT_NO_GRIDS));
+ *resGrid = (uint8)_gridConvertTable[cpt->screen];
+
+ uint32 tmpBits = 0x1F - (bitPos&0x1F);
+ bitPos &= ~0x1F; // divide into dword address and bit number
+ bitPos += tmpBits;
+ *resBitNum = bitPos;
+ *resWidth = width;
+ return true;
+}
+
+void Grid::removeObjectFromWalk(Compact *cpt) {
+ uint32 bitNum, width;
+ uint8 gridIdx;
+ if (getGridValues(cpt, &gridIdx, &bitNum, &width))
+ removeObjectFromWalk(gridIdx, bitNum, width);
+}
+
+void Grid::removeObjectFromWalk(uint8 gridIdx, uint32 bitNum, uint32 width) {
+ for (uint32 cnt = 0; cnt < width; cnt++) {
+ _gameGrids[gridIdx][bitNum >> 3] &= ~(1 << (bitNum & 0x7));
+ if ((bitNum & 0x1F) == 0)
+ bitNum += 0x3F;
+ else
+ bitNum--;
+ }
+}
+
+void Grid::objectToWalk(Compact *cpt) {
+ uint32 bitNum, width;
+ uint8 gridIdx;
+ if (getGridValues(cpt, &gridIdx, &bitNum, &width))
+ objectToWalk(gridIdx, bitNum, width);
+}
+
+void Grid::objectToWalk(uint8 gridIdx, uint32 bitNum, uint32 width) {
+ for (uint32 cnt = 0; cnt < width; cnt++) {
+ _gameGrids[gridIdx][bitNum >> 3] |= (1 << (bitNum & 0x7));
+ if ((bitNum & 0x1F) == 0)
+ bitNum += 0x3F;
+ else
+ bitNum--;
+ }
+}
+
+void Grid::plotGrid(uint32 x, uint32 y, uint32 width, Compact *cpt) {
+ uint32 resBitPos, resWidth;
+ uint8 resGridIdx;
+ if (getGridValues(x, y, width-1, cpt, &resGridIdx, &resBitPos, &resWidth))
+ objectToWalk(resGridIdx, resBitPos, resWidth);
+}
+
+void Grid::removeGrid(uint32 x, uint32 y, uint32 width, Compact *cpt) {
+ uint32 resBitPos, resWidth;
+ uint8 resGridIdx;
+ if (getGridValues(x, y, width, cpt, &resGridIdx, &resBitPos, &resWidth))
+ removeObjectFromWalk(resGridIdx, resBitPos, resWidth);
+}
+
+uint8 *Grid::giveGrid(uint32 pScreen) {
+ assert((_gridConvertTable[pScreen] >= 0) && (_gridConvertTable[pScreen] < TOT_NO_GRIDS));
+ return _gameGrids[_gridConvertTable[pScreen]];
+}
+
+} // End of namespace Sky
diff --git a/engines/sky/grid.h b/engines/sky/grid.h
new file mode 100644
index 0000000000..7c2ba557c0
--- /dev/null
+++ b/engines/sky/grid.h
@@ -0,0 +1,68 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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 SKYGRID_H
+#define SKYGRID_H
+
+#include "common/stdafx.h"
+#include "common/scummsys.h"
+#include "skydefs.h"
+
+namespace Sky {
+
+struct Compact;
+class Disk;
+class SkyCompact;
+
+class Grid {
+public:
+ Grid(Disk *pDisk, SkyCompact *skyCompact);
+ ~Grid(void);
+
+ // grid.asm routines
+ void loadGrids(void);
+ void removeObjectFromWalk(Compact *cpt);
+ void objectToWalk(Compact *cpt);
+
+ // function.asm
+ // note that this routine does the same as objectToWalk, it just doesn't get
+ // its x, y, width parameters from cpt.
+ void plotGrid(uint32 x, uint32 y, uint32 width, Compact *cpt);
+ // same here, it's basically the same as removeObjectFromWalk
+ void removeGrid(uint32 x, uint32 y, uint32 width, Compact *cpt);
+ uint8 *giveGrid(uint32 pScreen);
+
+private:
+ void objectToWalk(uint8 gridIdx, uint32 bitNum, uint32 width);
+ void removeObjectFromWalk(uint8 gridIdx, uint32 bitNum, uint32 width);
+ bool getGridValues(Compact *cpt, uint8 *resGrid, uint32 *resBitNum, uint32 *resWidth);
+ bool getGridValues(uint32 x, uint32 y, uint32 width, Compact *cpt, uint8 *resGrid, uint32 *resBitNum, uint32 *resWidth);
+
+ static int8 _gridConvertTable[];
+ uint8 *_gameGrids[TOT_NO_GRIDS];
+ Disk *_skyDisk;
+ SkyCompact *_skyCompact;
+};
+
+} // End of namespace Sky
+
+#endif //SKYGRID_H
diff --git a/engines/sky/hufftext.cpp b/engines/sky/hufftext.cpp
new file mode 100644
index 0000000000..01b0d4a679
--- /dev/null
+++ b/engines/sky/hufftext.cpp
@@ -0,0 +1,2046 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2002-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 "sky/text.h"
+
+namespace Sky {
+
+#ifdef PALMOS_68K
+const HuffTree *Text::_huffTree_00109;
+const HuffTree *Text::_huffTree_00267;
+const HuffTree *Text::_huffTree_00288;
+const HuffTree *Text::_huffTree_00303;
+const HuffTree *Text::_huffTree_00331;
+const HuffTree *Text::_huffTree_00348;
+const HuffTree *Text::_huffTree_00365;
+const HuffTree *Text::_huffTree_00368;
+const HuffTree *Text::_huffTree_00372;
+#else
+const HuffTree Text::_huffTree_00109[] = {
+ { 1, 22, 0 },
+ { 2, 9, 0 },
+ { 3, 6, 0 },
+ { 4, 5, 0 },
+ { 0, 0, 0x20 },
+ { 0, 0, 0x65 },
+ { 7, 8, 0 },
+ { 0, 0, 0x74 },
+ { 0, 0, 0x6F },
+ { 10, 17, 0 },
+ { 11, 14, 0 },
+ { 12, 13, 0 },
+ { 0, 0, 0x2E },
+ { 0, 0, 0x61 },
+ { 15, 16, 0 },
+ { 0, 0, 0x00 },
+ { 0, 0, 0x73 },
+ { 18, 21, 0 },
+ { 19, 20, 0 },
+ { 0, 0, 0x6E },
+ { 0, 0, 0x68 },
+ { 0, 0, 0x69 },
+ { 23, 46, 0 },
+ { 24, 35, 0 },
+ { 25, 30, 0 },
+ { 26, 29, 0 },
+ { 27, 28, 0 },
+ { 0, 0, 0x45 },
+ { 0, 0, 0x49 },
+ { 0, 0, 0x72 },
+ { 31, 34, 0 },
+ { 32, 33, 0 },
+ { 0, 0, 0x54 },
+ { 0, 0, 0x75 },
+ { 0, 0, 0x6D },
+ { 36, 41, 0 },
+ { 37, 40, 0 },
+ { 38, 39, 0 },
+ { 0, 0, 0x6C },
+ { 0, 0, 0x79 },
+ { 0, 0, 0x4F },
+ { 42, 45, 0 },
+ { 43, 44, 0 },
+ { 0, 0, 0x41 },
+ { 0, 0, 0x53 },
+ { 0, 0, 0x4E },
+ { 47, 66, 0 },
+ { 48, 57, 0 },
+ { 49, 54, 0 },
+ { 50, 53, 0 },
+ { 51, 52, 0 },
+ { 0, 0, 0x52 },
+ { 0, 0, 0x64 },
+ { 0, 0, 0x27 },
+ { 55, 56, 0 },
+ { 0, 0, 0x44 },
+ { 0, 0, 0x4C },
+ { 58, 63, 0 },
+ { 59, 62, 0 },
+ { 60, 61, 0 },
+ { 0, 0, 0x67 },
+ { 0, 0, 0x43 },
+ { 0, 0, 0x63 },
+ { 64, 65, 0 },
+ { 0, 0, 0x48 },
+ { 0, 0, 0x21 },
+ { 67, 84, 0 },
+ { 68, 77, 0 },
+ { 69, 74, 0 },
+ { 70, 73, 0 },
+ { 71, 72, 0 },
+ { 0, 0, 0x55 },
+ { 0, 0, 0x77 },
+ { 0, 0, 0x66 },
+ { 75, 76, 0 },
+ { 0, 0, 0x50 },
+ { 0, 0, 0x4D },
+ { 78, 81, 0 },
+ { 79, 80, 0 },
+ { 0, 0, 0x62 },
+ { 0, 0, 0x57 },
+ { 82, 83, 0 },
+ { 0, 0, 0x3F },
+ { 0, 0, 0x47 },
+ { 85, 94, 0 },
+ { 86, 91, 0 },
+ { 87, 90, 0 },
+ { 88, 89, 0 },
+ { 0, 0, 0x59 },
+ { 0, 0, 0x2C },
+ { 0, 0, 0x70 },
+ { 92, 93, 0 },
+ { 0, 0, 0x42 },
+ { 0, 0, 0x6B },
+ { 95, 100, 0 },
+ { 96, 99, 0 },
+ { 97, 98, 0 },
+ { 0, 0, 0x76 },
+ { 0, 0, 0x46 },
+ { 0, 0, 0x4B },
+ { 101, 106, 0 },
+ { 102, 105, 0 },
+ { 103, 104, 0 },
+ { 0, 0, 0x2D },
+ { 0, 0, 0x56 },
+ { 0, 0, 0x4A },
+ { 107, 120, 0 },
+ { 108, 113, 0 },
+ { 109, 112, 0 },
+ { 110, 111, 0 },
+ { 0, 0, 0x3A },
+ { 0, 0, 0x58 },
+ { 0, 0, 0x6A },
+ { 114, 117, 0 },
+ { 115, 116, 0 },
+ { 0, 0, 0x60 },
+ { 0, 0, 0x5A },
+ { 118, 119, 0 },
+ { 0, 0, 0x78 },
+ { 0, 0, 0x30 },
+ { 121, 132, 0 },
+ { 122, 127, 0 },
+ { 123, 126, 0 },
+ { 124, 125, 0 },
+ { 0, 0, 0x32 },
+ { 0, 0, 0x31 },
+ { 0, 0, 0x51 },
+ { 128, 131, 0 },
+ { 129, 130, 0 },
+ { 0, 0, 0x33 },
+ { 0, 0, 0x39 },
+ { 0, 0, 0x71 },
+ { 133, 142, 0 },
+ { 134, 137, 0 },
+ { 135, 136, 0 },
+ { 0, 0, 0x34 },
+ { 0, 0, 0x38 },
+ { 138, 141, 0 },
+ { 139, 140, 0 },
+ { 0, 0, 0x35 },
+ { 0, 0, 0x7A },
+ { 0, 0, 0x26 },
+ { 143, 150, 0 },
+ { 144, 147, 0 },
+ { 145, 146, 0 },
+ { 0, 0, 0x36 },
+ { 0, 0, 0x29 },
+ { 148, 149, 0 },
+ { 0, 0, 0x28 },
+ { 0, 0, 0x37 },
+ { 151, 158, 0 },
+ { 152, 155, 0 },
+ { 153, 154, 0 },
+ { 0, 0, 0x24 },
+ { 0, 0, 0x22 },
+ { 156, 157, 0 },
+ { 0, 0, 0x2F },
+ { 0, 0, 0x3C },
+ { 159, 162, 0 },
+ { 160, 161, 0 },
+ { 0, 0, 0x3E },
+ { 0, 0, 0x25 },
+ { 163, 164, 0 },
+ { 0, 0, 0x23 },
+ { 165, 166, 0 },
+ { 0, 0, 0x5F },
+ { 0, 0, 0x7C }
+};
+
+const HuffTree Text::_huffTree_00267[] = {
+ { 1, 20, 0 },
+ { 2, 7, 0 },
+ { 3, 6, 0 },
+ { 4, 5, 0 },
+ { 0, 0, 0x20 },
+ { 0, 0, 0x65 },
+ { 0, 0, 0x73 },
+ { 8, 15, 0 },
+ { 9, 12, 0 },
+ { 10, 11, 0 },
+ { 0, 0, 0x6d },
+ { 0, 0, 0x61 },
+ { 13, 14, 0 },
+ { 0, 0, 0x0 },
+ { 0, 0, 0x6e },
+ { 16, 19, 0 },
+ { 17, 18, 0 },
+ { 0, 0, 0x69 },
+ { 0, 0, 0x74 },
+ { 0, 0, 0x75 },
+ { 21, 44, 0 },
+ { 22, 31, 0 },
+ { 23, 28, 0 },
+ { 24, 27, 0 },
+ { 25, 26, 0 },
+ { 0, 0, 0x2e },
+ { 0, 0, 0x72 },
+ { 0, 0, 0x45 },
+ { 29, 30, 0 },
+ { 0, 0, 0x6f },
+ { 0, 0, 0x68 },
+ { 32, 39, 0 },
+ { 33, 36, 0 },
+ { 34, 35, 0 },
+ { 0, 0, 0x44 },
+ { 0, 0, 0x67 },
+ { 37, 38, 0 },
+ { 0, 0, 0x49 },
+ { 0, 0, 0x79 },
+ { 40, 43, 0 },
+ { 41, 42, 0 },
+ { 0, 0, 0x53 },
+ { 0, 0, 0x64 },
+ { 0, 0, 0x6c },
+ { 45, 64, 0 },
+ { 46, 53, 0 },
+ { 47, 50, 0 },
+ { 48, 49, 0 },
+ { 0, 0, 0x54 },
+ { 0, 0, 0x4e },
+ { 51, 52, 0 },
+ { 0, 0, 0x63 },
+ { 0, 0, 0x52 },
+ { 54, 59, 0 },
+ { 55, 58, 0 },
+ { 56, 57, 0 },
+ { 0, 0, 0x41 },
+ { 0, 0, 0x4f },
+ { 0, 0, 0x4c },
+ { 60, 63, 0 },
+ { 61, 62, 0 },
+ { 0, 0, 0x48 },
+ { 0, 0, 0x43 },
+ { 0, 0, 0x55 },
+ { 65, 84, 0 },
+ { 66, 75, 0 },
+ { 67, 72, 0 },
+ { 68, 71, 0 },
+ { 69, 70, 0 },
+ { 0, 0, 0x62 },
+ { 0, 0, 0x21 },
+ { 0, 0, 0x27 },
+ { 73, 74, 0 },
+ { 0, 0, 0x77 },
+ { 0, 0, 0x66 },
+ { 76, 81, 0 },
+ { 77, 80, 0 },
+ { 78, 79, 0 },
+ { 0, 0, 0x47 },
+ { 0, 0, 0x4d },
+ { 0, 0, 0x2c },
+ { 82, 83, 0 },
+ { 0, 0, 0x57 },
+ { 0, 0, 0x42 },
+ { 85, 98, 0 },
+ { 86, 93, 0 },
+ { 87, 90, 0 },
+ { 88, 89, 0 },
+ { 0, 0, 0x3f },
+ { 0, 0, 0x50 },
+ { 91, 92, 0 },
+ { 0, 0, 0x6b },
+ { 0, 0, 0x70 },
+ { 94, 97, 0 },
+ { 95, 96, 0 },
+ { 0, 0, 0x76 },
+ { 0, 0, 0x46 },
+ { 0, 0, 0x4b },
+ { 99, 110, 0 },
+ { 100, 105, 0 },
+ { 101, 104, 0 },
+ { 102, 103, 0 },
+ { 0, 0, 0x56 },
+ { 0, 0, 0x59 },
+ { 0, 0, 0x7a },
+ { 106, 109, 0 },
+ { 107, 108, 0 },
+ { 0, 0, 0x2d },
+ { 0, 0, 0x23 },
+ { 0, 0, 0x4a },
+ { 111, 124, 0 },
+ { 112, 117, 0 },
+ { 113, 116, 0 },
+ { 114, 115, 0 },
+ { 0, 0, 0x5a },
+ { 0, 0, 0x28 },
+ { 0, 0, 0x29 },
+ { 118, 121, 0 },
+ { 119, 120, 0 },
+ { 0, 0, 0x6a },
+ { 0, 0, 0x2b },
+ { 122, 123, 0 },
+ { 0, 0, 0x2a },
+ { 0, 0, 0x71 },
+ { 125, 138, 0 },
+ { 126, 131, 0 },
+ { 127, 130, 0 },
+ { 128, 129, 0 },
+ { 0, 0, 0x7d },
+ { 0, 0, 0x3a },
+ { 0, 0, 0x60 },
+ { 132, 135, 0 },
+ { 133, 134, 0 },
+ { 0, 0, 0x30 },
+ { 0, 0, 0x32 },
+ { 136, 137, 0 },
+ { 0, 0, 0x31 },
+ { 0, 0, 0x51 },
+ { 139, 150, 0 },
+ { 140, 145, 0 },
+ { 141, 144, 0 },
+ { 142, 143, 0 },
+ { 0, 0, 0x58 },
+ { 0, 0, 0x78 },
+ { 0, 0, 0x33 },
+ { 146, 149, 0 },
+ { 147, 148, 0 },
+ { 0, 0, 0x39 },
+ { 0, 0, 0x34 },
+ { 0, 0, 0x3c },
+ { 151, 160, 0 },
+ { 152, 157, 0 },
+ { 153, 156, 0 },
+ { 154, 155, 0 },
+ { 0, 0, 0x38 },
+ { 0, 0, 0x5d },
+ { 0, 0, 0x3d },
+ { 158, 159, 0 },
+ { 0, 0, 0x26 },
+ { 0, 0, 0x35 },
+ { 161, 168, 0 },
+ { 162, 165, 0 },
+ { 163, 164, 0 },
+ { 0, 0, 0x36 },
+ { 0, 0, 0x2f },
+ { 166, 167, 0 },
+ { 0, 0, 0x37 },
+ { 0, 0, 0x24 },
+ { 169, 174, 0 },
+ { 170, 173, 0 },
+ { 171, 172, 0 },
+ { 0, 0, 0x3e },
+ { 0, 0, 0x25 },
+ { 0, 0, 0x5e },
+ { 175, 180, 0 },
+ { 176, 179, 0 },
+ { 177, 178, 0 },
+ { 0, 0, 0x22 },
+ { 0, 0, 0x40 },
+ { 0, 0, 0x5b },
+ { 181, 184, 0 },
+ { 182, 183, 0 },
+ { 0, 0, 0x5f },
+ { 0, 0, 0x7b },
+ { 185, 186, 0 },
+ { 0, 0, 0x5c },
+ { 0, 0, 0x7c },
+};
+
+const HuffTree Text::_huffTree_00288[] = {
+ { 1, 20, 0 },
+ { 2, 7, 0 },
+ { 3, 4, 0 },
+ { 0, 0, 0x20 },
+ { 5, 6, 0 },
+ { 0, 0, 0x65 },
+ { 0, 0, 0x73 },
+ { 8, 15, 0 },
+ { 9, 12, 0 },
+ { 10, 11, 0 },
+ { 0, 0, 0x6e },
+ { 0, 0, 0x69 },
+ { 13, 14, 0 },
+ { 0, 0, 0x74 },
+ { 0, 0, 0x61 },
+ { 16, 19, 0 },
+ { 17, 18, 0 },
+ { 0, 0, 0x2e },
+ { 0, 0, 0x0 },
+ { 0, 0, 0x45 },
+ { 21, 44, 0 },
+ { 22, 31, 0 },
+ { 23, 28, 0 },
+ { 24, 27, 0 },
+ { 25, 26, 0 },
+ { 0, 0, 0x72 },
+ { 0, 0, 0x6f },
+ { 0, 0, 0x75 },
+ { 29, 30, 0 },
+ { 0, 0, 0x6d },
+ { 0, 0, 0x68 },
+ { 32, 39, 0 },
+ { 33, 36, 0 },
+ { 34, 35, 0 },
+ { 0, 0, 0x49 },
+ { 0, 0, 0x6c },
+ { 37, 38, 0 },
+ { 0, 0, 0x53 },
+ { 0, 0, 0x52 },
+ { 40, 43, 0 },
+ { 41, 42, 0 },
+ { 0, 0, 0x64 },
+ { 0, 0, 0x4e },
+ { 0, 0, 0x54 },
+ { 45, 68, 0 },
+ { 46, 55, 0 },
+ { 47, 52, 0 },
+ { 48, 51, 0 },
+ { 49, 50, 0 },
+ { 0, 0, 0x63 },
+ { 0, 0, 0x41 },
+ { 0, 0, 0x4f },
+ { 53, 54, 0 },
+ { 0, 0, 0x44 },
+ { 0, 0, 0x4c },
+ { 56, 63, 0 },
+ { 57, 60, 0 },
+ { 58, 59, 0 },
+ { 0, 0, 0x43 },
+ { 0, 0, 0x67 },
+ { 61, 62, 0 },
+ { 0, 0, 0x55 },
+ { 0, 0, 0x27 },
+ { 64, 67, 0 },
+ { 65, 66, 0 },
+ { 0, 0, 0x79 },
+ { 0, 0, 0x48 },
+ { 0, 0, 0x70 },
+ { 69, 88, 0 },
+ { 70, 79, 0 },
+ { 71, 76, 0 },
+ { 72, 75, 0 },
+ { 73, 74, 0 },
+ { 0, 0, 0x21 },
+ { 0, 0, 0x4d },
+ { 0, 0, 0x62 },
+ { 77, 78, 0 },
+ { 0, 0, 0x76 },
+ { 0, 0, 0x2c },
+ { 80, 85, 0 },
+ { 81, 84, 0 },
+ { 82, 83, 0 },
+ { 0, 0, 0x50 },
+ { 0, 0, 0x66 },
+ { 0, 0, 0x3f },
+ { 86, 87, 0 },
+ { 0, 0, 0x47 },
+ { 0, 0, 0x42 },
+ { 89, 104, 0 },
+ { 90, 97, 0 },
+ { 91, 94, 0 },
+ { 92, 93, 0 },
+ { 0, 0, 0x77 },
+ { 0, 0, 0x57 },
+ { 95, 96, 0 },
+ { 0, 0, 0x46 },
+ { 0, 0, 0x56 },
+ { 98, 101, 0 },
+ { 99, 100, 0 },
+ { 0, 0, 0x6b },
+ { 0, 0, 0x7a },
+ { 102, 103, 0 },
+ { 0, 0, 0x4b },
+ { 0, 0, 0x2d },
+ { 105, 116, 0 },
+ { 106, 111, 0 },
+ { 107, 110, 0 },
+ { 108, 109, 0 },
+ { 0, 0, 0x4a },
+ { 0, 0, 0x2b },
+ { 0, 0, 0x71 },
+ { 112, 115, 0 },
+ { 113, 114, 0 },
+ { 0, 0, 0x59 },
+ { 0, 0, 0x6a },
+ { 0, 0, 0x5a },
+ { 117, 132, 0 },
+ { 118, 125, 0 },
+ { 119, 122, 0 },
+ { 120, 121, 0 },
+ { 0, 0, 0x23 },
+ { 0, 0, 0x51 },
+ { 123, 124, 0 },
+ { 0, 0, 0x28 },
+ { 0, 0, 0x29 },
+ { 126, 129, 0 },
+ { 127, 128, 0 },
+ { 0, 0, 0x3c },
+ { 0, 0, 0x78 },
+ { 130, 131, 0 },
+ { 0, 0, 0x3a },
+ { 0, 0, 0x2a },
+ { 133, 146, 0 },
+ { 134, 141, 0 },
+ { 135, 138, 0 },
+ { 136, 137, 0 },
+ { 0, 0, 0x58 },
+ { 0, 0, 0x7d },
+ { 139, 140, 0 },
+ { 0, 0, 0x3d },
+ { 0, 0, 0x60 },
+ { 142, 145, 0 },
+ { 143, 144, 0 },
+ { 0, 0, 0x5d },
+ { 0, 0, 0x30 },
+ { 0, 0, 0x32 },
+ { 147, 158, 0 },
+ { 148, 153, 0 },
+ { 149, 152, 0 },
+ { 150, 151, 0 },
+ { 0, 0, 0x31 },
+ { 0, 0, 0x33 },
+ { 0, 0, 0x39 },
+ { 154, 157, 0 },
+ { 155, 156, 0 },
+ { 0, 0, 0x2f },
+ { 0, 0, 0x34 },
+ { 0, 0, 0x5e },
+ { 159, 168, 0 },
+ { 160, 165, 0 },
+ { 161, 164, 0 },
+ { 162, 163, 0 },
+ { 0, 0, 0x38 },
+ { 0, 0, 0x3e },
+ { 0, 0, 0x26 },
+ { 166, 167, 0 },
+ { 0, 0, 0x35 },
+ { 0, 0, 0x40 },
+ { 169, 176, 0 },
+ { 170, 173, 0 },
+ { 171, 172, 0 },
+ { 0, 0, 0x36 },
+ { 0, 0, 0x5f },
+ { 174, 175, 0 },
+ { 0, 0, 0x5c },
+ { 0, 0, 0x37 },
+ { 177, 182, 0 },
+ { 178, 181, 0 },
+ { 179, 180, 0 },
+ { 0, 0, 0x5b },
+ { 0, 0, 0x24 },
+ { 0, 0, 0x7b },
+ { 183, 186, 0 },
+ { 184, 185, 0 },
+ { 0, 0, 0x25 },
+ { 0, 0, 0x9 },
+ { 187, 188, 0 },
+ { 0, 0, 0x22 },
+ { 0, 0, 0x7c },
+};
+
+const HuffTree Text::_huffTree_00303[] = {
+ { 1, 22, 0 },
+ { 2, 9, 0 },
+ { 3, 6, 0 },
+ { 4, 5, 0 },
+ { 0, 0, 0x20 },
+ { 0, 0, 0x65 },
+ { 7, 8, 0 },
+ { 0, 0, 0x74 },
+ { 0, 0, 0x73 },
+ { 10, 17, 0 },
+ { 11, 14, 0 },
+ { 12, 13, 0 },
+ { 0, 0, 0x6e },
+ { 0, 0, 0x61 },
+ { 15, 16, 0 },
+ { 0, 0, 0x69 },
+ { 0, 0, 0x2e },
+ { 18, 21, 0 },
+ { 19, 20, 0 },
+ { 0, 0, 0x6f },
+ { 0, 0, 0x0 },
+ { 0, 0, 0x45 },
+ { 23, 46, 0 },
+ { 24, 35, 0 },
+ { 25, 30, 0 },
+ { 26, 29, 0 },
+ { 27, 28, 0 },
+ { 0, 0, 0x72 },
+ { 0, 0, 0x75 },
+ { 0, 0, 0x68 },
+ { 31, 34, 0 },
+ { 32, 33, 0 },
+ { 0, 0, 0x49 },
+ { 0, 0, 0x6d },
+ { 0, 0, 0x6c },
+ { 36, 41, 0 },
+ { 37, 40, 0 },
+ { 38, 39, 0 },
+ { 0, 0, 0x54 },
+ { 0, 0, 0x53 },
+ { 0, 0, 0x52 },
+ { 42, 45, 0 },
+ { 43, 44, 0 },
+ { 0, 0, 0x64 },
+ { 0, 0, 0x4e },
+ { 0, 0, 0x41 },
+ { 47, 70, 0 },
+ { 48, 59, 0 },
+ { 49, 54, 0 },
+ { 50, 53, 0 },
+ { 51, 52, 0 },
+ { 0, 0, 0x63 },
+ { 0, 0, 0x4f },
+ { 0, 0, 0x44 },
+ { 55, 58, 0 },
+ { 56, 57, 0 },
+ { 0, 0, 0x4c },
+ { 0, 0, 0x43 },
+ { 0, 0, 0x79 },
+ { 60, 65, 0 },
+ { 61, 64, 0 },
+ { 62, 63, 0 },
+ { 0, 0, 0x67 },
+ { 0, 0, 0x27 },
+ { 0, 0, 0x55 },
+ { 66, 69, 0 },
+ { 67, 68, 0 },
+ { 0, 0, 0x48 },
+ { 0, 0, 0x21 },
+ { 0, 0, 0x70 },
+ { 71, 88, 0 },
+ { 72, 81, 0 },
+ { 73, 78, 0 },
+ { 74, 77, 0 },
+ { 75, 76, 0 },
+ { 0, 0, 0x4d },
+ { 0, 0, 0x62 },
+ { 0, 0, 0x3f },
+ { 79, 80, 0 },
+ { 0, 0, 0x76 },
+ { 0, 0, 0x66 },
+ { 82, 85, 0 },
+ { 83, 84, 0 },
+ { 0, 0, 0x50 },
+ { 0, 0, 0x2c },
+ { 86, 87, 0 },
+ { 0, 0, 0x77 },
+ { 0, 0, 0x47 },
+ { 89, 102, 0 },
+ { 90, 95, 0 },
+ { 91, 94, 0 },
+ { 92, 93, 0 },
+ { 0, 0, 0x42 },
+ { 0, 0, 0x57 },
+ { 0, 0, 0x6b },
+ { 96, 99, 0 },
+ { 97, 98, 0 },
+ { 0, 0, 0x46 },
+ { 0, 0, 0x56 },
+ { 100, 101, 0 },
+ { 0, 0, 0x59 },
+ { 0, 0, 0x4b },
+ { 103, 114, 0 },
+ { 104, 109, 0 },
+ { 105, 108, 0 },
+ { 106, 107, 0 },
+ { 0, 0, 0x2d },
+ { 0, 0, 0x7a },
+ { 0, 0, 0x4a },
+ { 110, 113, 0 },
+ { 111, 112, 0 },
+ { 0, 0, 0x71 },
+ { 0, 0, 0x2b },
+ { 0, 0, 0x6a },
+ { 115, 132, 0 },
+ { 116, 123, 0 },
+ { 117, 120, 0 },
+ { 118, 119, 0 },
+ { 0, 0, 0x5a },
+ { 0, 0, 0x23 },
+ { 121, 122, 0 },
+ { 0, 0, 0x51 },
+ { 0, 0, 0x78 },
+ { 124, 129, 0 },
+ { 125, 128, 0 },
+ { 126, 127, 0 },
+ { 0, 0, 0x3a },
+ { 0, 0, 0x29 },
+ { 0, 0, 0x28 },
+ { 130, 131, 0 },
+ { 0, 0, 0x3c },
+ { 0, 0, 0x58 },
+ { 133, 148, 0 },
+ { 134, 141, 0 },
+ { 135, 138, 0 },
+ { 136, 137, 0 },
+ { 0, 0, 0x2a },
+ { 0, 0, 0x60 },
+ { 139, 140, 0 },
+ { 0, 0, 0x7d },
+ { 0, 0, 0x3d },
+ { 142, 145, 0 },
+ { 143, 144, 0 },
+ { 0, 0, 0x32 },
+ { 0, 0, 0x30 },
+ { 146, 147, 0 },
+ { 0, 0, 0x5d },
+ { 0, 0, 0x31 },
+ { 149, 160, 0 },
+ { 150, 155, 0 },
+ { 151, 154, 0 },
+ { 152, 153, 0 },
+ { 0, 0, 0x7e },
+ { 0, 0, 0x33 },
+ { 0, 0, 0x7f },
+ { 156, 159, 0 },
+ { 157, 158, 0 },
+ { 0, 0, 0x39 },
+ { 0, 0, 0x34 },
+ { 0, 0, 0x2f },
+ { 161, 172, 0 },
+ { 162, 167, 0 },
+ { 163, 166, 0 },
+ { 164, 165, 0 },
+ { 0, 0, 0x38 },
+ { 0, 0, 0x5e },
+ { 0, 0, 0x26 },
+ { 168, 171, 0 },
+ { 169, 170, 0 },
+ { 0, 0, 0x35 },
+ { 0, 0, 0x36 },
+ { 0, 0, 0x3e },
+ { 173, 182, 0 },
+ { 174, 179, 0 },
+ { 175, 178, 0 },
+ { 176, 177, 0 },
+ { 0, 0, 0x40 },
+ { 0, 0, 0x37 },
+ { 0, 0, 0x5f },
+ { 180, 181, 0 },
+ { 0, 0, 0x5c },
+ { 0, 0, 0x24 },
+ { 183, 190, 0 },
+ { 184, 187, 0 },
+ { 185, 186, 0 },
+ { 0, 0, 0x5b },
+ { 0, 0, 0x80 },
+ { 188, 189, 0 },
+ { 0, 0, 0x81 },
+ { 0, 0, 0x22 },
+ { 191, 194, 0 },
+ { 192, 193, 0 },
+ { 0, 0, 0x25 },
+ { 0, 0, 0x82 },
+ { 195, 196, 0 },
+ { 0, 0, 0x7b },
+ { 197, 198, 0 },
+ { 0, 0, 0x9 },
+ { 0, 0, 0x7c },
+};
+
+const HuffTree Text::_huffTree_00331[] = {
+ { 1, 20, 0 },
+ { 2, 7, 0 },
+ { 3, 4, 0 },
+ { 0, 0, 0x20 },
+ { 5, 6, 0 },
+ { 0, 0, 0x65 },
+ { 0, 0, 0x61 },
+ { 8, 15, 0 },
+ { 9, 12, 0 },
+ { 10, 11, 0 },
+ { 0, 0, 0x6f },
+ { 0, 0, 0x73 },
+ { 13, 14, 0 },
+ { 0, 0, 0x74 },
+ { 0, 0, 0x6e },
+ { 16, 19, 0 },
+ { 17, 18, 0 },
+ { 0, 0, 0x2e },
+ { 0, 0, 0x69 },
+ { 0, 0, 0x72 },
+ { 21, 44, 0 },
+ { 22, 31, 0 },
+ { 23, 28, 0 },
+ { 24, 27, 0 },
+ { 25, 26, 0 },
+ { 0, 0, 0x0 },
+ { 0, 0, 0x45 },
+ { 0, 0, 0x75 },
+ { 29, 30, 0 },
+ { 0, 0, 0x6d },
+ { 0, 0, 0x41 },
+ { 32, 39, 0 },
+ { 33, 36, 0 },
+ { 34, 35, 0 },
+ { 0, 0, 0x6c },
+ { 0, 0, 0x49 },
+ { 37, 38, 0 },
+ { 0, 0, 0x64 },
+ { 0, 0, 0x52 },
+ { 40, 43, 0 },
+ { 41, 42, 0 },
+ { 0, 0, 0x4e },
+ { 0, 0, 0x53 },
+ { 0, 0, 0x54 },
+ { 45, 68, 0 },
+ { 46, 55, 0 },
+ { 47, 52, 0 },
+ { 48, 51, 0 },
+ { 49, 50, 0 },
+ { 0, 0, 0x4f },
+ { 0, 0, 0x68 },
+ { 0, 0, 0x63 },
+ { 53, 54, 0 },
+ { 0, 0, 0x44 },
+ { 0, 0, 0x67 },
+ { 56, 63, 0 },
+ { 57, 60, 0 },
+ { 58, 59, 0 },
+ { 0, 0, 0x4c },
+ { 0, 0, 0x43 },
+ { 61, 62, 0 },
+ { 0, 0, 0x70 },
+ { 0, 0, 0x55 },
+ { 64, 67, 0 },
+ { 65, 66, 0 },
+ { 0, 0, 0x21 },
+ { 0, 0, 0x79 },
+ { 0, 0, 0x4d },
+ { 69, 88, 0 },
+ { 70, 79, 0 },
+ { 71, 76, 0 },
+ { 72, 75, 0 },
+ { 73, 74, 0 },
+ { 0, 0, 0x50 },
+ { 0, 0, 0x76 },
+ { 0, 0, 0x48 },
+ { 77, 78, 0 },
+ { 0, 0, 0x3f },
+ { 0, 0, 0x62 },
+ { 80, 85, 0 },
+ { 81, 84, 0 },
+ { 82, 83, 0 },
+ { 0, 0, 0x27 },
+ { 0, 0, 0x66 },
+ { 0, 0, 0x2c },
+ { 86, 87, 0 },
+ { 0, 0, 0x47 },
+ { 0, 0, 0x42 },
+ { 89, 108, 0 },
+ { 90, 99, 0 },
+ { 91, 96, 0 },
+ { 92, 95, 0 },
+ { 93, 94, 0 },
+ { 0, 0, 0x56 },
+ { 0, 0, 0x6b },
+ { 0, 0, 0x46 },
+ { 97, 98, 0 },
+ { 0, 0, 0x71 },
+ { 0, 0, 0x2a },
+ { 100, 105, 0 },
+ { 101, 104, 0 },
+ { 102, 103, 0 },
+ { 0, 0, 0x77 },
+ { 0, 0, 0x4b },
+ { 0, 0, 0x2d },
+ { 106, 107, 0 },
+ { 0, 0, 0x57 },
+ { 0, 0, 0x4a },
+ { 109, 126, 0 },
+ { 110, 117, 0 },
+ { 111, 114, 0 },
+ { 112, 113, 0 },
+ { 0, 0, 0x7a },
+ { 0, 0, 0x2b },
+ { 115, 116, 0 },
+ { 0, 0, 0x59 },
+ { 0, 0, 0x6a },
+ { 118, 123, 0 },
+ { 119, 122, 0 },
+ { 120, 121, 0 },
+ { 0, 0, 0x85 },
+ { 0, 0, 0x29 },
+ { 0, 0, 0x51 },
+ { 124, 125, 0 },
+ { 0, 0, 0x5a },
+ { 0, 0, 0x7e },
+ { 127, 148, 0 },
+ { 128, 137, 0 },
+ { 129, 134, 0 },
+ { 130, 133, 0 },
+ { 131, 132, 0 },
+ { 0, 0, 0x8b },
+ { 0, 0, 0x3c },
+ { 0, 0, 0x8a },
+ { 135, 136, 0 },
+ { 0, 0, 0x7f },
+ { 0, 0, 0x3a },
+ { 138, 143, 0 },
+ { 139, 142, 0 },
+ { 140, 141, 0 },
+ { 0, 0, 0x87 },
+ { 0, 0, 0x23 },
+ { 0, 0, 0x78 },
+ { 144, 147, 0 },
+ { 145, 146, 0 },
+ { 0, 0, 0x58 },
+ { 0, 0, 0x91 },
+ { 0, 0, 0x83 },
+ { 149, 168, 0 },
+ { 150, 159, 0 },
+ { 151, 156, 0 },
+ { 152, 155, 0 },
+ { 153, 154, 0 },
+ { 0, 0, 0x88 },
+ { 0, 0, 0x60 },
+ { 0, 0, 0x32 },
+ { 157, 158, 0 },
+ { 0, 0, 0x30 },
+ { 0, 0, 0x31 },
+ { 160, 165, 0 },
+ { 161, 164, 0 },
+ { 162, 163, 0 },
+ { 0, 0, 0x28 },
+ { 0, 0, 0x2f },
+ { 0, 0, 0x5d },
+ { 166, 167, 0 },
+ { 0, 0, 0x3d },
+ { 0, 0, 0x86 },
+ { 169, 184, 0 },
+ { 170, 177, 0 },
+ { 171, 174, 0 },
+ { 172, 173, 0 },
+ { 0, 0, 0x5e },
+ { 0, 0, 0x33 },
+ { 175, 176, 0 },
+ { 0, 0, 0x39 },
+ { 0, 0, 0x34 },
+ { 178, 181, 0 },
+ { 179, 180, 0 },
+ { 0, 0, 0x7d },
+ { 0, 0, 0x38 },
+ { 182, 183, 0 },
+ { 0, 0, 0x5c },
+ { 0, 0, 0x22 },
+ { 185, 198, 0 },
+ { 186, 193, 0 },
+ { 187, 190, 0 },
+ { 188, 189, 0 },
+ { 0, 0, 0x3e },
+ { 0, 0, 0x26 },
+ { 191, 192, 0 },
+ { 0, 0, 0x8d },
+ { 0, 0, 0x7b },
+ { 194, 197, 0 },
+ { 195, 196, 0 },
+ { 0, 0, 0x35 },
+ { 0, 0, 0x36 },
+ { 0, 0, 0x8f },
+ { 199, 210, 0 },
+ { 200, 205, 0 },
+ { 201, 204, 0 },
+ { 202, 203, 0 },
+ { 0, 0, 0x8e },
+ { 0, 0, 0x8c },
+ { 0, 0, 0x37 },
+ { 206, 209, 0 },
+ { 207, 208, 0 },
+ { 0, 0, 0x89 },
+ { 0, 0, 0x24 },
+ { 0, 0, 0x92 },
+ { 211, 218, 0 },
+ { 212, 215, 0 },
+ { 213, 214, 0 },
+ { 0, 0, 0x5b },
+ { 0, 0, 0x80 },
+ { 216, 217, 0 },
+ { 0, 0, 0x81 },
+ { 0, 0, 0x40 },
+ { 219, 222, 0 },
+ { 220, 221, 0 },
+ { 0, 0, 0x5f },
+ { 0, 0, 0x82 },
+ { 223, 224, 0 },
+ { 0, 0, 0x25 },
+ { 225, 226, 0 },
+ { 0, 0, 0x9 },
+ { 227, 228, 0 },
+ { 0, 0, 0x3b },
+ { 0, 0, 0x7c },
+};
+
+const HuffTree Text::_huffTree_00348[] = {
+ { 1, 20, 0 },
+ { 2, 7, 0 },
+ { 3, 4, 0 },
+ { 0, 0, 0x20 },
+ { 5, 6, 0 },
+ { 0, 0, 0x65 },
+ { 0, 0, 0x61 },
+ { 8, 15, 0 },
+ { 9, 12, 0 },
+ { 10, 11, 0 },
+ { 0, 0, 0x6F },
+ { 0, 0, 0x73 },
+ { 13, 14, 0 },
+ { 0, 0, 0x74 },
+ { 0, 0, 0x6E },
+ { 16, 19, 0 },
+ { 17, 18, 0 },
+ { 0, 0, 0x2E },
+ { 0, 0, 0x69 },
+ { 0, 0, 0x72 },
+ { 21, 44, 0 },
+ { 22, 31, 0 },
+ { 23, 28, 0 },
+ { 24, 27, 0 },
+ { 25, 26, 0 },
+ { 0, 0, 0x00 },
+ { 0, 0, 0x45 },
+ { 0, 0, 0x75 },
+ { 29, 30, 0 },
+ { 0, 0, 0x6D },
+ { 0, 0, 0x41 },
+ { 32, 39, 0 },
+ { 33, 36, 0 },
+ { 34, 35, 0 },
+ { 0, 0, 0x6C },
+ { 0, 0, 0x49 },
+ { 37, 38, 0 },
+ { 0, 0, 0x64 },
+ { 0, 0, 0x52 },
+ { 40, 43, 0 },
+ { 41, 42, 0 },
+ { 0, 0, 0x4E },
+ { 0, 0, 0x53 },
+ { 0, 0, 0x54 },
+ { 45, 68, 0 },
+ { 46, 55, 0 },
+ { 47, 52, 0 },
+ { 48, 51, 0 },
+ { 49, 50, 0 },
+ { 0, 0, 0x4F },
+ { 0, 0, 0x68 },
+ { 0, 0, 0x63 },
+ { 53, 54, 0 },
+ { 0, 0, 0x44 },
+ { 0, 0, 0x67 },
+ { 56, 63, 0 },
+ { 57, 60, 0 },
+ { 58, 59, 0 },
+ { 0, 0, 0x4C },
+ { 0, 0, 0x43 },
+ { 61, 62, 0 },
+ { 0, 0, 0x70 },
+ { 0, 0, 0x55 },
+ { 64, 67, 0 },
+ { 65, 66, 0 },
+ { 0, 0, 0x21 },
+ { 0, 0, 0x79 },
+ { 0, 0, 0x4D },
+ { 69, 88, 0 },
+ { 70, 79, 0 },
+ { 71, 76, 0 },
+ { 72, 75, 0 },
+ { 73, 74, 0 },
+ { 0, 0, 0x50 },
+ { 0, 0, 0x76 },
+ { 0, 0, 0x48 },
+ { 77, 78, 0 },
+ { 0, 0, 0x3F },
+ { 0, 0, 0x62 },
+ { 80, 85, 0 },
+ { 81, 84, 0 },
+ { 82, 83, 0 },
+ { 0, 0, 0x27 },
+ { 0, 0, 0x66 },
+ { 0, 0, 0x2C },
+ { 86, 87, 0 },
+ { 0, 0, 0x47 },
+ { 0, 0, 0x42 },
+ { 89, 108, 0 },
+ { 90, 99, 0 },
+ { 91, 96, 0 },
+ { 92, 95, 0 },
+ { 93, 94, 0 },
+ { 0, 0, 0x56 },
+ { 0, 0, 0x6B },
+ { 0, 0, 0x46 },
+ { 97, 98, 0 },
+ { 0, 0, 0x71 },
+ { 0, 0, 0x77 },
+ { 100, 105, 0 },
+ { 101, 104, 0 },
+ { 102, 103, 0 },
+ { 0, 0, 0x4B },
+ { 0, 0, 0x2D },
+ { 0, 0, 0x57 },
+ { 106, 107, 0 },
+ { 0, 0, 0x4A },
+ { 0, 0, 0x2A },
+ { 109, 128, 0 },
+ { 110, 117, 0 },
+ { 111, 114, 0 },
+ { 112, 113, 0 },
+ { 0, 0, 0x7A },
+ { 0, 0, 0x59 },
+ { 115, 116, 0 },
+ { 0, 0, 0x6A },
+ { 0, 0, 0x2B },
+ { 118, 123, 0 },
+ { 119, 122, 0 },
+ { 120, 121, 0 },
+ { 0, 0, 0x51 },
+ { 0, 0, 0x29 },
+ { 0, 0, 0x85 },
+ { 124, 127, 0 },
+ { 125, 126, 0 },
+ { 0, 0, 0x5A },
+ { 0, 0, 0x8B },
+ { 0, 0, 0x3C },
+ { 129, 150, 0 },
+ { 130, 139, 0 },
+ { 131, 136, 0 },
+ { 132, 135, 0 },
+ { 133, 134, 0 },
+ { 0, 0, 0x95 },
+ { 0, 0, 0x7E },
+ { 0, 0, 0x8A },
+ { 137, 138, 0 },
+ { 0, 0, 0x87 },
+ { 0, 0, 0x3A },
+ { 140, 145, 0 },
+ { 141, 144, 0 },
+ { 142, 143, 0 },
+ { 0, 0, 0x7F },
+ { 0, 0, 0x5D },
+ { 0, 0, 0x23 },
+ { 146, 149, 0 },
+ { 147, 148, 0 },
+ { 0, 0, 0x78 },
+ { 0, 0, 0x58 },
+ { 0, 0, 0x91 },
+ { 151, 172, 0 },
+ { 152, 163, 0 },
+ { 153, 158, 0 },
+ { 154, 157, 0 },
+ { 155, 156, 0 },
+ { 0, 0, 0x88 },
+ { 0, 0, 0x60 },
+ { 0, 0, 0x32 },
+ { 159, 162, 0 },
+ { 160, 161, 0 },
+ { 0, 0, 0x30 },
+ { 0, 0, 0x83 },
+ { 0, 0, 0x31 },
+ { 164, 169, 0 },
+ { 165, 168, 0 },
+ { 166, 167, 0 },
+ { 0, 0, 0x2F },
+ { 0, 0, 0x28 },
+ { 0, 0, 0x3D },
+ { 170, 171, 0 },
+ { 0, 0, 0x86 },
+ { 0, 0, 0x5E },
+ { 173, 190, 0 },
+ { 174, 181, 0 },
+ { 175, 178, 0 },
+ { 176, 177, 0 },
+ { 0, 0, 0x33 },
+ { 0, 0, 0x39 },
+ { 179, 180, 0 },
+ { 0, 0, 0x98 },
+ { 0, 0, 0x34 },
+ { 182, 187, 0 },
+ { 183, 186, 0 },
+ { 184, 185, 0 },
+ { 0, 0, 0x7D },
+ { 0, 0, 0x38 },
+ { 0, 0, 0x5C },
+ { 188, 189, 0 },
+ { 0, 0, 0x22 },
+ { 0, 0, 0x9B },
+ { 191, 206, 0 },
+ { 192, 199, 0 },
+ { 193, 196, 0 },
+ { 194, 195, 0 },
+ { 0, 0, 0x26 },
+ { 0, 0, 0x8D },
+ { 197, 198, 0 },
+ { 0, 0, 0x35 },
+ { 0, 0, 0x36 },
+ { 200, 203, 0 },
+ { 201, 202, 0 },
+ { 0, 0, 0x92 },
+ { 0, 0, 0x8F },
+ { 204, 205, 0 },
+ { 0, 0, 0x8E },
+ { 0, 0, 0x93 },
+ { 207, 222, 0 },
+ { 208, 215, 0 },
+ { 209, 212, 0 },
+ { 210, 211, 0 },
+ { 0, 0, 0x8C },
+ { 0, 0, 0x37 },
+ { 213, 214, 0 },
+ { 0, 0, 0x99 },
+ { 0, 0, 0x24 },
+ { 216, 219, 0 },
+ { 217, 218, 0 },
+ { 0, 0, 0x80 },
+ { 0, 0, 0x81 },
+ { 220, 221, 0 },
+ { 0, 0, 0x40 },
+ { 0, 0, 0x5B },
+ { 223, 232, 0 },
+ { 224, 229, 0 },
+ { 225, 228, 0 },
+ { 226, 227, 0 },
+ { 0, 0, 0x9A },
+ { 0, 0, 0x5F },
+ { 0, 0, 0x3E },
+ { 230, 231, 0 },
+ { 0, 0, 0x96 },
+ { 0, 0, 0x82 },
+ { 233, 238, 0 },
+ { 234, 237, 0 },
+ { 235, 236, 0 },
+ { 0, 0, 0x25 },
+ { 0, 0, 0x09 },
+ { 0, 0, 0x9C },
+ { 239, 240, 0 },
+ { 0, 0, 0x97 },
+ { 241, 242, 0 },
+ { 0, 0, 0x7B },
+ { 243, 244, 0 },
+ { 0, 0, 0x94 },
+ { 0, 0, 0x7C },
+};
+
+const HuffTree Text::_huffTree_00365[] = {
+ { 1, 20, 0 },
+ { 2, 7, 0 },
+ { 3, 4, 0 },
+ { 0, 0, 0x20 },
+ { 5, 6, 0 },
+ { 0, 0, 0x65 },
+ { 0, 0, 0x61 },
+ { 8, 15, 0 },
+ { 9, 12, 0 },
+ { 10, 11, 0 },
+ { 0, 0, 0x6F },
+ { 0, 0, 0x73 },
+ { 13, 14, 0 },
+ { 0, 0, 0x74 },
+ { 0, 0, 0x6E },
+ { 16, 19, 0 },
+ { 17, 18, 0 },
+ { 0, 0, 0x2E },
+ { 0, 0, 0x69 },
+ { 0, 0, 0x72 },
+ { 21, 44, 0 },
+ { 22, 31, 0 },
+ { 23, 28, 0 },
+ { 24, 27, 0 },
+ { 25, 26, 0 },
+ { 0, 0, 0x00 },
+ { 0, 0, 0x45 },
+ { 0, 0, 0x75 },
+ { 29, 30, 0 },
+ { 0, 0, 0x6D },
+ { 0, 0, 0x41 },
+ { 32, 39, 0 },
+ { 33, 36, 0 },
+ { 34, 35, 0 },
+ { 0, 0, 0x6C },
+ { 0, 0, 0x49 },
+ { 37, 38, 0 },
+ { 0, 0, 0x64 },
+ { 0, 0, 0x52 },
+ { 40, 43, 0 },
+ { 41, 42, 0 },
+ { 0, 0, 0x4E },
+ { 0, 0, 0x53 },
+ { 0, 0, 0x54 },
+ { 45, 68, 0 },
+ { 46, 55, 0 },
+ { 47, 52, 0 },
+ { 48, 51, 0 },
+ { 49, 50, 0 },
+ { 0, 0, 0x4F },
+ { 0, 0, 0x68 },
+ { 0, 0, 0x63 },
+ { 53, 54, 0 },
+ { 0, 0, 0x44 },
+ { 0, 0, 0x67 },
+ { 56, 63, 0 },
+ { 57, 60, 0 },
+ { 58, 59, 0 },
+ { 0, 0, 0x4C },
+ { 0, 0, 0x43 },
+ { 61, 62, 0 },
+ { 0, 0, 0x70 },
+ { 0, 0, 0x55 },
+ { 64, 67, 0 },
+ { 65, 66, 0 },
+ { 0, 0, 0x21 },
+ { 0, 0, 0x79 },
+ { 0, 0, 0x4D },
+ { 69, 88, 0 },
+ { 70, 79, 0 },
+ { 71, 76, 0 },
+ { 72, 75, 0 },
+ { 73, 74, 0 },
+ { 0, 0, 0x50 },
+ { 0, 0, 0x76 },
+ { 0, 0, 0x48 },
+ { 77, 78, 0 },
+ { 0, 0, 0x3F },
+ { 0, 0, 0x62 },
+ { 80, 85, 0 },
+ { 81, 84, 0 },
+ { 82, 83, 0 },
+ { 0, 0, 0x27 },
+ { 0, 0, 0x66 },
+ { 0, 0, 0x2C },
+ { 86, 87, 0 },
+ { 0, 0, 0x47 },
+ { 0, 0, 0x42 },
+ { 89, 108, 0 },
+ { 90, 99, 0 },
+ { 91, 96, 0 },
+ { 92, 95, 0 },
+ { 93, 94, 0 },
+ { 0, 0, 0x56 },
+ { 0, 0, 0x6B },
+ { 0, 0, 0x46 },
+ { 97, 98, 0 },
+ { 0, 0, 0x71 },
+ { 0, 0, 0x77 },
+ { 100, 105, 0 },
+ { 101, 104, 0 },
+ { 102, 103, 0 },
+ { 0, 0, 0x4B },
+ { 0, 0, 0x2D },
+ { 0, 0, 0x57 },
+ { 106, 107, 0 },
+ { 0, 0, 0x4A },
+ { 0, 0, 0x2A },
+ { 109, 128, 0 },
+ { 110, 117, 0 },
+ { 111, 114, 0 },
+ { 112, 113, 0 },
+ { 0, 0, 0x7A },
+ { 0, 0, 0x59 },
+ { 115, 116, 0 },
+ { 0, 0, 0x6A },
+ { 0, 0, 0x2B },
+ { 118, 123, 0 },
+ { 119, 122, 0 },
+ { 120, 121, 0 },
+ { 0, 0, 0x51 },
+ { 0, 0, 0x85 },
+ { 0, 0, 0x29 },
+ { 124, 127, 0 },
+ { 125, 126, 0 },
+ { 0, 0, 0x5A },
+ { 0, 0, 0x8B },
+ { 0, 0, 0x3C },
+ { 129, 150, 0 },
+ { 130, 139, 0 },
+ { 131, 136, 0 },
+ { 132, 135, 0 },
+ { 133, 134, 0 },
+ { 0, 0, 0x95 },
+ { 0, 0, 0x7E },
+ { 0, 0, 0x8A },
+ { 137, 138, 0 },
+ { 0, 0, 0x87 },
+ { 0, 0, 0x3A },
+ { 140, 145, 0 },
+ { 141, 144, 0 },
+ { 142, 143, 0 },
+ { 0, 0, 0x7F },
+ { 0, 0, 0x5D },
+ { 0, 0, 0x23 },
+ { 146, 149, 0 },
+ { 147, 148, 0 },
+ { 0, 0, 0x78 },
+ { 0, 0, 0x58 },
+ { 0, 0, 0x91 },
+ { 151, 172, 0 },
+ { 152, 163, 0 },
+ { 153, 158, 0 },
+ { 154, 157, 0 },
+ { 155, 156, 0 },
+ { 0, 0, 0x88 },
+ { 0, 0, 0x60 },
+ { 0, 0, 0x32 },
+ { 159, 162, 0 },
+ { 160, 161, 0 },
+ { 0, 0, 0x30 },
+ { 0, 0, 0x83 },
+ { 0, 0, 0x31 },
+ { 164, 169, 0 },
+ { 165, 168, 0 },
+ { 166, 167, 0 },
+ { 0, 0, 0x2F },
+ { 0, 0, 0x28 },
+ { 0, 0, 0x3D },
+ { 170, 171, 0 },
+ { 0, 0, 0x86 },
+ { 0, 0, 0x5E },
+ { 173, 190, 0 },
+ { 174, 181, 0 },
+ { 175, 178, 0 },
+ { 176, 177, 0 },
+ { 0, 0, 0x33 },
+ { 0, 0, 0x39 },
+ { 179, 180, 0 },
+ { 0, 0, 0x98 },
+ { 0, 0, 0x34 },
+ { 182, 187, 0 },
+ { 183, 186, 0 },
+ { 184, 185, 0 },
+ { 0, 0, 0x7D },
+ { 0, 0, 0x38 },
+ { 0, 0, 0x5C },
+ { 188, 189, 0 },
+ { 0, 0, 0x22 },
+ { 0, 0, 0x90 },
+ { 191, 206, 0 },
+ { 192, 199, 0 },
+ { 193, 196, 0 },
+ { 194, 195, 0 },
+ { 0, 0, 0x26 },
+ { 0, 0, 0x8D },
+ { 197, 198, 0 },
+ { 0, 0, 0x35 },
+ { 0, 0, 0x36 },
+ { 200, 203, 0 },
+ { 201, 202, 0 },
+ { 0, 0, 0x92 },
+ { 0, 0, 0x8F },
+ { 204, 205, 0 },
+ { 0, 0, 0x8E },
+ { 0, 0, 0x93 },
+ { 207, 220, 0 },
+ { 208, 213, 0 },
+ { 209, 212, 0 },
+ { 210, 211, 0 },
+ { 0, 0, 0x8C },
+ { 0, 0, 0x37 },
+ { 0, 0, 0x80 },
+ { 214, 217, 0 },
+ { 215, 216, 0 },
+ { 0, 0, 0x81 },
+ { 0, 0, 0x99 },
+ { 218, 219, 0 },
+ { 0, 0, 0x24 },
+ { 0, 0, 0x40 },
+ { 221, 230, 0 },
+ { 222, 227, 0 },
+ { 223, 226, 0 },
+ { 224, 225, 0 },
+ { 0, 0, 0x5B },
+ { 0, 0, 0x9A },
+ { 0, 0, 0x5F },
+ { 228, 229, 0 },
+ { 0, 0, 0x3E },
+ { 0, 0, 0x96 },
+ { 231, 236, 0 },
+ { 232, 235, 0 },
+ { 233, 234, 0 },
+ { 0, 0, 0x82 },
+ { 0, 0, 0x25 },
+ { 0, 0, 0x09 },
+ { 237, 240, 0 },
+ { 238, 239, 0 },
+ { 0, 0, 0x9C },
+ { 0, 0, 0x97 },
+ { 241, 242, 0 },
+ { 0, 0, 0x7B },
+ { 243, 244, 0 },
+ { 0, 0, 0x94 },
+ { 0, 0, 0x7C },
+};
+
+const HuffTree Text::_huffTree_00368[] = {
+ { 1, 20, 0 },
+ { 2, 7, 0 },
+ { 3, 4, 0 },
+ { 0, 0, 0x20 },
+ { 5, 6, 0 },
+ { 0, 0, 0x65 },
+ { 0, 0, 0x61 },
+ { 8, 15, 0 },
+ { 9, 12, 0 },
+ { 10, 11, 0 },
+ { 0, 0, 0x6F },
+ { 0, 0, 0x73 },
+ { 13, 14, 0 },
+ { 0, 0, 0x74 },
+ { 0, 0, 0x6E },
+ { 16, 19, 0 },
+ { 17, 18, 0 },
+ { 0, 0, 0x2E },
+ { 0, 0, 0x69 },
+ { 0, 0, 0x72 },
+ { 21, 44, 0 },
+ { 22, 31, 0 },
+ { 23, 28, 0 },
+ { 24, 27, 0 },
+ { 25, 26, 0 },
+ { 0, 0, 0x00 },
+ { 0, 0, 0x45 },
+ { 0, 0, 0x75 },
+ { 29, 30, 0 },
+ { 0, 0, 0x6D },
+ { 0, 0, 0x41 },
+ { 32, 39, 0 },
+ { 33, 36, 0 },
+ { 34, 35, 0 },
+ { 0, 0, 0x6C },
+ { 0, 0, 0x49 },
+ { 37, 38, 0 },
+ { 0, 0, 0x64 },
+ { 0, 0, 0x52 },
+ { 40, 43, 0 },
+ { 41, 42, 0 },
+ { 0, 0, 0x4E },
+ { 0, 0, 0x53 },
+ { 0, 0, 0x54 },
+ { 45, 68, 0 },
+ { 46, 55, 0 },
+ { 47, 52, 0 },
+ { 48, 51, 0 },
+ { 49, 50, 0 },
+ { 0, 0, 0x4F },
+ { 0, 0, 0x68 },
+ { 0, 0, 0x63 },
+ { 53, 54, 0 },
+ { 0, 0, 0x44 },
+ { 0, 0, 0x67 },
+ { 56, 63, 0 },
+ { 57, 60, 0 },
+ { 58, 59, 0 },
+ { 0, 0, 0x4C },
+ { 0, 0, 0x43 },
+ { 61, 62, 0 },
+ { 0, 0, 0x70 },
+ { 0, 0, 0x55 },
+ { 64, 67, 0 },
+ { 65, 66, 0 },
+ { 0, 0, 0x21 },
+ { 0, 0, 0x79 },
+ { 0, 0, 0x4D },
+ { 69, 88, 0 },
+ { 70, 79, 0 },
+ { 71, 76, 0 },
+ { 72, 75, 0 },
+ { 73, 74, 0 },
+ { 0, 0, 0x50 },
+ { 0, 0, 0x76 },
+ { 0, 0, 0x48 },
+ { 77, 78, 0 },
+ { 0, 0, 0x3F },
+ { 0, 0, 0x62 },
+ { 80, 85, 0 },
+ { 81, 84, 0 },
+ { 82, 83, 0 },
+ { 0, 0, 0x27 },
+ { 0, 0, 0x66 },
+ { 0, 0, 0x2C },
+ { 86, 87, 0 },
+ { 0, 0, 0x47 },
+ { 0, 0, 0x42 },
+ { 89, 108, 0 },
+ { 90, 99, 0 },
+ { 91, 96, 0 },
+ { 92, 95, 0 },
+ { 93, 94, 0 },
+ { 0, 0, 0x56 },
+ { 0, 0, 0x6B },
+ { 0, 0, 0x46 },
+ { 97, 98, 0 },
+ { 0, 0, 0x71 },
+ { 0, 0, 0x77 },
+ { 100, 105, 0 },
+ { 101, 104, 0 },
+ { 102, 103, 0 },
+ { 0, 0, 0x4B },
+ { 0, 0, 0x2D },
+ { 0, 0, 0x57 },
+ { 106, 107, 0 },
+ { 0, 0, 0x4A },
+ { 0, 0, 0x2A },
+ { 109, 128, 0 },
+ { 110, 117, 0 },
+ { 111, 114, 0 },
+ { 112, 113, 0 },
+ { 0, 0, 0x7A },
+ { 0, 0, 0x59 },
+ { 115, 116, 0 },
+ { 0, 0, 0x6A },
+ { 0, 0, 0x2B },
+ { 118, 123, 0 },
+ { 119, 122, 0 },
+ { 120, 121, 0 },
+ { 0, 0, 0x51 },
+ { 0, 0, 0x85 },
+ { 0, 0, 0x29 },
+ { 124, 127, 0 },
+ { 125, 126, 0 },
+ { 0, 0, 0x5A },
+ { 0, 0, 0x8B },
+ { 0, 0, 0x3C },
+ { 129, 152, 0 },
+ { 130, 139, 0 },
+ { 131, 136, 0 },
+ { 132, 135, 0 },
+ { 133, 134, 0 },
+ { 0, 0, 0x95 },
+ { 0, 0, 0x7E },
+ { 0, 0, 0x8A },
+ { 137, 138, 0 },
+ { 0, 0, 0x87 },
+ { 0, 0, 0x3A },
+ { 140, 145, 0 },
+ { 141, 144, 0 },
+ { 142, 143, 0 },
+ { 0, 0, 0x7F },
+ { 0, 0, 0x23 },
+ { 0, 0, 0x78 },
+ { 146, 149, 0 },
+ { 147, 148, 0 },
+ { 0, 0, 0x58 },
+ { 0, 0, 0x5D },
+ { 150, 151, 0 },
+ { 0, 0, 0x91 },
+ { 0, 0, 0x88 },
+ { 153, 174, 0 },
+ { 154, 165, 0 },
+ { 155, 160, 0 },
+ { 156, 159, 0 },
+ { 157, 158, 0 },
+ { 0, 0, 0x5F },
+ { 0, 0, 0x60 },
+ { 0, 0, 0x32 },
+ { 161, 164, 0 },
+ { 162, 163, 0 },
+ { 0, 0, 0x30 },
+ { 0, 0, 0x83 },
+ { 0, 0, 0x31 },
+ { 166, 171, 0 },
+ { 167, 170, 0 },
+ { 168, 169, 0 },
+ { 0, 0, 0x2F },
+ { 0, 0, 0x28 },
+ { 0, 0, 0x3D },
+ { 172, 173, 0 },
+ { 0, 0, 0x86 },
+ { 0, 0, 0x5E },
+ { 175, 190, 0 },
+ { 176, 183, 0 },
+ { 177, 180, 0 },
+ { 178, 179, 0 },
+ { 0, 0, 0x33 },
+ { 0, 0, 0x39 },
+ { 181, 182, 0 },
+ { 0, 0, 0x98 },
+ { 0, 0, 0x34 },
+ { 184, 187, 0 },
+ { 185, 186, 0 },
+ { 0, 0, 0x7D },
+ { 0, 0, 0x38 },
+ { 188, 189, 0 },
+ { 0, 0, 0x5C },
+ { 0, 0, 0x22 },
+ { 191, 206, 0 },
+ { 192, 199, 0 },
+ { 193, 196, 0 },
+ { 194, 195, 0 },
+ { 0, 0, 0x90 },
+ { 0, 0, 0x26 },
+ { 197, 198, 0 },
+ { 0, 0, 0x8D },
+ { 0, 0, 0x35 },
+ { 200, 203, 0 },
+ { 201, 202, 0 },
+ { 0, 0, 0x36 },
+ { 0, 0, 0x3E },
+ { 204, 205, 0 },
+ { 0, 0, 0x93 },
+ { 0, 0, 0x8C },
+ { 207, 220, 0 },
+ { 208, 215, 0 },
+ { 209, 212, 0 },
+ { 210, 211, 0 },
+ { 0, 0, 0x37 },
+ { 0, 0, 0x80 },
+ { 213, 214, 0 },
+ { 0, 0, 0x81 },
+ { 0, 0, 0x8E },
+ { 216, 219, 0 },
+ { 217, 218, 0 },
+ { 0, 0, 0x8F },
+ { 0, 0, 0x99 },
+ { 0, 0, 0x24 },
+ { 221, 230, 0 },
+ { 222, 227, 0 },
+ { 223, 226, 0 },
+ { 224, 225, 0 },
+ { 0, 0, 0x92 },
+ { 0, 0, 0x40 },
+ { 0, 0, 0x5B },
+ { 228, 229, 0 },
+ { 0, 0, 0x9A },
+ { 0, 0, 0x96 },
+ { 231, 236, 0 },
+ { 232, 235, 0 },
+ { 233, 234, 0 },
+ { 0, 0, 0x82 },
+ { 0, 0, 0x25 },
+ { 0, 0, 0x09 },
+ { 237, 240, 0 },
+ { 238, 239, 0 },
+ { 0, 0, 0x9C },
+ { 0, 0, 0x97 },
+ { 241, 242, 0 },
+ { 0, 0, 0x7B },
+ { 243, 244, 0 },
+ { 0, 0, 0x94 },
+ { 0, 0, 0x7C },
+};
+
+const HuffTree Text::_huffTree_00372[] = {
+ { 1, 20, 0 },
+ { 2, 7, 0 },
+ { 3, 4, 0 },
+ { 0, 0, ' ' },
+ { 5, 6, 0 },
+ { 0, 0, 'e' },
+ { 0, 0, 'a' },
+ { 8, 15, 0 },
+ { 9, 12, 0 },
+ { 10, 11, 0 },
+ { 0, 0, 'o' },
+ { 0, 0, 's' },
+ { 13, 14, 0 },
+ { 0, 0, 't' },
+ { 0, 0, 'n' },
+ { 16, 19, 0 },
+ { 17, 18, 0 },
+ { 0, 0, '.' },
+ { 0, 0, 'i' },
+ { 0, 0, 'r' },
+ { 21, 44, 0 },
+ { 22, 31, 0 },
+ { 23, 28, 0 },
+ { 24, 27, 0 },
+ { 25, 26, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 'E' },
+ { 0, 0, 'u' },
+ { 29, 30, 0 },
+ { 0, 0, 'm' },
+ { 0, 0, 'A' },
+ { 32, 39, 0 },
+ { 33, 36, 0 },
+ { 34, 35, 0 },
+ { 0, 0, 'l' },
+ { 0, 0, 'I' },
+ { 37, 38, 0 },
+ { 0, 0, 'd' },
+ { 0, 0, 'R' },
+ { 40, 43, 0 },
+ { 41, 42, 0 },
+ { 0, 0, 'N' },
+ { 0, 0, 'S' },
+ { 0, 0, 'T' },
+ { 45, 68, 0 },
+ { 46, 55, 0 },
+ { 47, 52, 0 },
+ { 48, 51, 0 },
+ { 49, 50, 0 },
+ { 0, 0, 'O' },
+ { 0, 0, 'h' },
+ { 0, 0, 'c' },
+ { 53, 54, 0 },
+ { 0, 0, 'D' },
+ { 0, 0, 'g' },
+ { 56, 63, 0 },
+ { 57, 60, 0 },
+ { 58, 59, 0 },
+ { 0, 0, 'L' },
+ { 0, 0, 'C' },
+ { 61, 62, 0 },
+ { 0, 0, 'p' },
+ { 0, 0, 'U' },
+ { 64, 67, 0 },
+ { 65, 66, 0 },
+ { 0, 0, '!' },
+ { 0, 0, 'y' },
+ { 0, 0, 'M' },
+ { 69, 88, 0 },
+ { 70, 79, 0 },
+ { 71, 76, 0 },
+ { 72, 75, 0 },
+ { 73, 74, 0 },
+ { 0, 0, 'P' },
+ { 0, 0, 'v' },
+ { 0, 0, 'H' },
+ { 77, 78, 0 },
+ { 0, 0, '?' },
+ { 0, 0, 'b' },
+ { 80, 85, 0 },
+ { 81, 84, 0 },
+ { 82, 83, 0 },
+ { 0, 0, 39 },
+ { 0, 0, 'f' },
+ { 0, 0, ',' },
+ { 86, 87, 0 },
+ { 0, 0, 'G' },
+ { 0, 0, 'B' },
+ { 89, 108, 0 },
+ { 90, 99, 0 },
+ { 91, 96, 0 },
+ { 92, 95, 0 },
+ { 93, 94, 0 },
+ { 0, 0, 'V' },
+ { 0, 0, 'k' },
+ { 0, 0, 'F' },
+ { 97, 98, 0 },
+ { 0, 0, 'q' },
+ { 0, 0, 'w' },
+ { 100, 105, 0 },
+ { 101, 104, 0 },
+ { 102, 103, 0 },
+ { 0, 0, 'K' },
+ { 0, 0, '-' },
+ { 0, 0, 'W' },
+ { 106, 107, 0 },
+ { 0, 0, 'J' },
+ { 0, 0, '*' },
+ { 109, 128, 0 },
+ { 110, 117, 0 },
+ { 111, 114, 0 },
+ { 112, 113, 0 },
+ { 0, 0, 'z' },
+ { 0, 0, 'Y' },
+ { 115, 116, 0 },
+ { 0, 0, 'j' },
+ { 0, 0, '+' },
+ { 118, 123, 0 },
+ { 119, 122, 0 },
+ { 120, 121, 0 },
+ { 0, 0, 'Q' },
+ { 0, 0, 133 },
+ { 0, 0, ')' },
+ { 124, 127, 0 },
+ { 125, 126, 0 },
+ { 0, 0, 'Z' },
+ { 0, 0, 139 },
+ { 0, 0, '<' },
+ { 129, 150, 0 },
+ { 130, 139, 0 },
+ { 131, 136, 0 },
+ { 132, 135, 0 },
+ { 133, 134, 0 },
+ { 0, 0, 149 },
+ { 0, 0, 126 },
+ { 0, 0, 138 },
+ { 137, 138, 0 },
+ { 0, 0, 135 },
+ { 0, 0, ':' },
+ { 140, 145, 0 },
+ { 141, 144, 0 },
+ { 142, 143, 0 },
+ { 0, 0, 127 },
+ { 0, 0, ']' },
+ { 0, 0, '#' },
+ { 146, 149, 0 },
+ { 147, 148, 0 },
+ { 0, 0, 'x' },
+ { 0, 0, 'X' },
+ { 0, 0, 145 },
+ { 151, 172, 0 },
+ { 152, 163, 0 },
+ { 153, 158, 0 },
+ { 154, 157, 0 },
+ { 155, 156, 0 },
+ { 0, 0, 136 },
+ { 0, 0, '`' },
+ { 0, 0, '2' },
+ { 159, 162, 0 },
+ { 160, 161, 0 },
+ { 0, 0, '0' },
+ { 0, 0, 131 },
+ { 0, 0, '1' },
+ { 164, 169, 0 },
+ { 165, 168, 0 },
+ { 166, 167, 0 },
+ { 0, 0, '/' },
+ { 0, 0, '(' },
+ { 0, 0, '=' },
+ { 170, 171, 0 },
+ { 0, 0, 134 },
+ { 0, 0, '^' },
+ { 173, 190, 0 },
+ { 174, 181, 0 },
+ { 175, 178, 0 },
+ { 176, 177, 0 },
+ { 0, 0, '3' },
+ { 0, 0, '9' },
+ { 179, 180, 0 },
+ { 0, 0, 152 },
+ { 0, 0, '4' },
+ { 182, 187, 0 },
+ { 183, 186, 0 },
+ { 184, 185, 0 },
+ { 0, 0, '}' },
+ { 0, 0, '8' },
+ { 0, 0, '\\' },
+ { 188, 189, 0 },
+ { 0, 0, '"' },
+ { 0, 0, 144 },
+ { 191, 206, 0 },
+ { 192, 199, 0 },
+ { 193, 196, 0 },
+ { 194, 195, 0 },
+ { 0, 0, '&' },
+ { 0, 0, 141 },
+ { 197, 198, 0 },
+ { 0, 0, '5' },
+ { 0, 0, '6' },
+ { 200, 203, 0 },
+ { 201, 202, 0 },
+ { 0, 0, 146 },
+ { 0, 0, 143 },
+ { 204, 205, 0 },
+ { 0, 0, 142 },
+ { 0, 0, 147 },
+ { 207, 220, 0 },
+ { 208, 213, 0 },
+ { 209, 212, 0 },
+ { 210, 211, 0 },
+ { 0, 0, 140 },
+ { 0, 0, '7' },
+ { 0, 0, 128 },
+ { 214, 217, 0 },
+ { 215, 216, 0 },
+ { 0, 0, 129 },
+ { 0, 0, 153 },
+ { 218, 219, 0 },
+ { 0, 0, '$' },
+ { 0, 0, '@' },
+ { 221, 230, 0 },
+ { 222, 227, 0 },
+ { 223, 226, 0 },
+ { 224, 225, 0 },
+ { 0, 0, '[' },
+ { 0, 0, 154 },
+ { 0, 0, '_' },
+ { 228, 229, 0 },
+ { 0, 0, '>' },
+ { 0, 0, 150 },
+ { 231, 236, 0 },
+ { 232, 235, 0 },
+ { 233, 234, 0 },
+ { 0, 0, 130 },
+ { 0, 0, '%' },
+ { 0, 0, 9 },
+ { 237, 240, 0 },
+ { 238, 239, 0 },
+ { 0, 0, 156 },
+ { 0, 0, 151 },
+ { 241, 242, 0 },
+ { 0, 0, '{' },
+ { 243, 244, 0 },
+ { 0, 0, 148 },
+ { 0, 0, '!' },
+};
+#endif
+
+} // End of namespace Sky
+
+#ifdef PALMOS_68K
+#include "scumm_globals.h"
+
+_GINIT(Sky_Hufftext)
+_GSETPTR(Sky::Text::_huffTree_00109, GBVARS_HUFFTREE_00109_INDEX, const Sky::HuffTree, GBVARS_QUEEN)
+_GSETPTR(Sky::Text::_huffTree_00267, GBVARS_HUFFTREE_00267_INDEX, const Sky::HuffTree, GBVARS_QUEEN)
+_GSETPTR(Sky::Text::_huffTree_00288, GBVARS_HUFFTREE_00288_INDEX, const Sky::HuffTree, GBVARS_QUEEN)
+_GSETPTR(Sky::Text::_huffTree_00303, GBVARS_HUFFTREE_00303_INDEX, const Sky::HuffTree, GBVARS_QUEEN)
+_GSETPTR(Sky::Text::_huffTree_00331, GBVARS_HUFFTREE_00331_INDEX, const Sky::HuffTree, GBVARS_QUEEN)
+_GSETPTR(Sky::Text::_huffTree_00348, GBVARS_HUFFTREE_00348_INDEX, const Sky::HuffTree, GBVARS_QUEEN)
+_GSETPTR(Sky::Text::_huffTree_00365, GBVARS_HUFFTREE_00365_INDEX, const Sky::HuffTree, GBVARS_QUEEN)
+_GSETPTR(Sky::Text::_huffTree_00368, GBVARS_HUFFTREE_00368_INDEX, const Sky::HuffTree, GBVARS_QUEEN)
+_GSETPTR(Sky::Text::_huffTree_00372, GBVARS_HUFFTREE_00372_INDEX, const Sky::HuffTree, GBVARS_QUEEN)
+_GEND
+
+_GRELEASE(Sky_Hufftext)
+_GRELEASEPTR(GBVARS_HUFFTREE_00109_INDEX, GBVARS_QUEEN)
+_GRELEASEPTR(GBVARS_HUFFTREE_00267_INDEX, GBVARS_QUEEN)
+_GRELEASEPTR(GBVARS_HUFFTREE_00288_INDEX, GBVARS_QUEEN)
+_GRELEASEPTR(GBVARS_HUFFTREE_00303_INDEX, GBVARS_QUEEN)
+_GRELEASEPTR(GBVARS_HUFFTREE_00331_INDEX, GBVARS_QUEEN)
+_GRELEASEPTR(GBVARS_HUFFTREE_00348_INDEX, GBVARS_QUEEN)
+_GRELEASEPTR(GBVARS_HUFFTREE_00365_INDEX, GBVARS_QUEEN)
+_GRELEASEPTR(GBVARS_HUFFTREE_00368_INDEX, GBVARS_QUEEN)
+_GRELEASEPTR(GBVARS_HUFFTREE_00372_INDEX, GBVARS_QUEEN)
+_GEND
+
+#endif
diff --git a/engines/sky/intro.cpp b/engines/sky/intro.cpp
new file mode 100644
index 0000000000..ce6849fbd0
--- /dev/null
+++ b/engines/sky/intro.cpp
@@ -0,0 +1,926 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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/util.h"
+#include "common/system.h"
+#include "sky/disk.h"
+#include "sky/intro.h"
+#include "sky/music/musicbase.h"
+#include "sky/screen.h"
+#include "sky/sky.h"
+#include "sky/sound.h"
+#include "sky/struc.h"
+#include "sky/text.h"
+
+namespace Sky {
+
+#ifdef MACOSX
+// FIXME: DELAY is already defined in sys/param.h !
+// Better fix would be to remove sys/param.h froms stdafx.h, or
+// to change the name DELAY here to something else.
+#undef DELAY
+#endif
+
+#define SHOWSCREEN 0
+#define COMMANDEND 0 // end of COMMANDFLIRT block
+#define FADEUP 1 // fade up palette
+#define FADEDOWN 2
+#define DELAY 3
+#define DOFLIRT 4 // start flirt sequence (and wait for it to finish)
+#define SCROLLFLIRT 5 // start special floppy intro flirt sequence (and wait for it)
+#define COMMANDFLIRT 6 // start flirt sequence and wait for it, while processing command block
+#define BGFLIRT 7 // start flirt sequence without waiting for it
+#define WAITFLIRT 8 // wait for sequence started by BGFLIRT
+#define STOPFLIRT 9
+#define STARTMUSIC 10
+#define WAITMUSIC 11
+#define PLAYVOICE 12
+#define WAITVOICE 13
+#define LOADBG 14 // load new background sound
+#define PLAYBG 15 // play background sound
+#define LOOPBG 16 // loop background sound
+#define STOPBG 17 // stop background sound
+#define SEQEND 65535 // end of intro sequence
+
+#define IC_PREPARE_TEXT 20 // commands used in COMMANDFLIRT block
+#define IC_SHOW_TEXT 21
+#define IC_REMOVE_TEXT 22
+#define IC_MAKE_SOUND 23
+#define IC_FX_VOLUME 24
+
+#define FRAME_SIZE (GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT)
+#define INTRO_TEXT_WIDTH 128
+//CD intro file defines
+#define CDV_00 59500
+#define CD_PAL 59501
+#define CD_1_LOG 59502
+#define CD_1 59503
+#define CDV_01 59504
+#define CDV_02 59505
+#define CD_2 59506
+#define CDV_03 59507
+#define CDV_04 59508
+#define CD_3 59509
+#define CDV_05 59510
+#define CDV_06 59511
+#define CD_5 59512
+#define CDV_07 59513
+#define CDV_08 59514
+#define CDV_09 59515
+#define CD_7 59516
+#define CDV_10 59518
+#define CD_11 59519
+#define CDV_11 59520
+#define CD_11_PAL 59521
+#define CD_11_LOG 59522
+#define CDV_12 59523
+#define CD_13 59524
+#define CDV_13 59525
+#define CDV_14 59527
+#define CDV_15 59528
+#define CD_15_PAL 59529
+#define CD_15_LOG 59530
+#define CDV_16 59531
+#define CD_17_LOG 59532
+#define CD_17 59533
+#define CDV_17 59534
+#define CDV_18 59535
+#define CDV_19 59536
+#define CD_19_PAL 59537
+#define CD_19_LOG 59538
+#define CDV_20 59539
+#define CD_20_LOG 59540
+#define CDV_21 59541
+#define CD_21_LOG 59542
+#define CDV_22 59545
+#define CDV_23 59546
+#define CD_23_PAL 59547
+#define CD_24_LOG 59550
+#define CDV_24 59551
+#define CDV_25 59554
+#define CDV_26 59556
+#define CD_27 59557
+#define CDV_27 59558
+#define CD_27_PAL 59559
+#define CD_27_LOG 59560
+#define CDV_28 59561
+#define CDV_29 59562
+#define CDV_30 59563
+#define CDV_31 59565
+#define CDV_32 59566
+#define CDV_33 59567
+#define CDV_34 59568
+#define CD_35 59569
+#define CDV_35 59570
+#define CD_35_PAL 59571
+#define CD_35_LOG 59572
+#define CDV_36 59574
+#define CD_37 59575
+#define CDV_37 59576
+#define CD_37_PAL 59577
+#define CD_37_LOG 59578
+#define CDV_38 59579
+#define CDV_39 59581
+#define CDV_40 59583
+#define CD_40_PAL 59584
+#define CD_40_LOG 59585
+#define CDV_41 59587
+#define CDV_42 59588
+#define CD_43 59589
+#define CDV_43 59590
+#define CD_43_PAL 59591
+#define CD_43_LOG 59592
+#define CDV_44 59594
+#define CD_45 59595
+#define CDV_45 59596
+#define CD_45_PAL 59597
+#define CD_45_LOG 59598
+#define CDV_46 59600
+#define CDV_47 59602
+#define CD_47_PAL 59603
+#define CD_47_LOG 59604
+#define CD_48 59605
+#define CDV_48 59606
+#define CD_48_PAL 59607
+#define CD_48_LOG 59608
+#define CD_49 59609
+#define CDV_49 59610
+#define CD_50 59611
+#define CDV_50 59612
+#define CDV_51 59613
+#define CDV_52 59614
+#define CDV_53 59615
+#define CDV_54 59616
+#define CDV_55 59618
+#define CD_55_PAL 59619
+#define CD_55_LOG 59620
+#define CDV_56 59621
+#define CDV_57 59622
+#define CD_58 59623
+#define CDV_58 59624
+#define CD_58_PAL 59625
+#define CD_58_LOG 59626
+#define CDV_59 59627
+#define CDV_60 59628
+#define CDV_61 59629
+#define CDV_62 59630
+#define CDV_63 59631
+#define CDV_64 59632
+#define CDV_65 59633
+#define CDV_66 59635
+#define CD_66_PAL 59636
+#define CD_66_LOG 59637
+#define CDV_67 59639
+#define CD_67_PAL 59640
+#define CD_67_LOG 59641
+#define CDV_68 59642
+#define CD_69 59643
+#define CDV_69 59644
+#define CD_69_PAL 59645
+#define CD_69_LOG 59646
+#define CDV_70 59647
+#define CDV_71 59648
+#define CDV_72 59649
+#define CD_72_PAL 59650
+#define CD_72_LOG 59651
+#define CD_73_PAL 59652
+#define CD_73_LOG 59653
+#define CDV_73 59654
+#define CDV_74 59655
+#define CDV_75 59656
+#define CD_76_PAL 59657
+#define CD_76_LOG 59658
+#define CDV_76 59659
+#define CDV_77 59660
+#define CD_78_PAL 59661
+#define CD_78_LOG 59662
+#define CDV_78 59663
+#define CDV_79 59664
+#define CDV_80 59665
+#define CDV_81 59666
+#define CDV_82 59667
+#define CDV_83 59668
+#define CDV_84 59669
+#define CDV_85 59670
+#define CDV_86 59671
+#define CDV_87 59672
+#define CD_100 60087
+#define CD_101_LOG 60088
+#define CD_101 60099
+#define CD_102_LOG 60090
+#define CD_102 60091
+#define CD_103_PAL 60092
+#define CD_103_LOG 60093
+#define CD_103 60094
+#define CD_104_PAL 60095
+#define CD_104_LOG 60096
+#define CD_104 60097
+#define CD_105 60098
+
+
+uint16 Intro::_mainIntroSeq[] = {
+ DELAY, 3000, // keep virgin screen up
+ FADEDOWN,
+ SHOWSCREEN, 60112, // revo screen + palette
+ FADEUP, 60113,
+ DELAY, 8000,
+ FADEDOWN,
+ SHOWSCREEN, 60114, // gibbo screen + palette
+ FADEUP, 60115,
+ DELAY, 2000,
+ FADEDOWN,
+ SEQEND
+};
+
+uint16 Intro::_cdIntroSeq[] = {
+ PLAYVOICE, 59500,
+ LOADBG, 59499,
+ LOOPBG,
+ WAITVOICE,
+ PLAYVOICE, 59504,
+ SHOWSCREEN, CD_1_LOG,
+ FADEUP, CD_PAL,
+ BGFLIRT, CD_1,
+ WAITVOICE,
+ PLAYVOICE, CDV_02,
+ WAITVOICE,
+ STOPFLIRT,
+ BGFLIRT, CD_2,
+ PLAYVOICE, CDV_03,
+ WAITVOICE,
+ PLAYVOICE, CDV_04,
+ WAITFLIRT,
+ WAITVOICE,
+ PLAYVOICE, CDV_05,
+ DELAY, 2000,
+ BGFLIRT, CD_3,
+ WAITVOICE,
+ PLAYVOICE, CDV_06,
+ WAITFLIRT,
+ WAITVOICE,
+ PLAYVOICE, CDV_07,
+ BGFLIRT, CD_5,
+ WAITVOICE,
+ PLAYVOICE, CDV_08,
+ WAITVOICE,
+ PLAYVOICE, CDV_09,
+ WAITFLIRT,
+ WAITVOICE,
+ PLAYVOICE, CDV_10,
+ BGFLIRT, CD_7,
+ WAITVOICE,
+ PLAYVOICE, CDV_11,
+ WAITFLIRT,
+ FADEDOWN,
+ SHOWSCREEN, CD_11_LOG,
+ FADEUP, CD_11_PAL,
+ WAITVOICE,
+ PLAYVOICE, CDV_12,
+ DELAY, 1600,
+ BGFLIRT, CD_11,
+ WAITVOICE,
+ PLAYVOICE, CDV_13,
+ WAITVOICE,
+ WAITFLIRT,
+ WAITVOICE,
+ PLAYVOICE, CDV_14,
+ LOADBG, 59498, // fade-in heli
+ PLAYBG,
+ DOFLIRT, CD_13,
+ WAITVOICE,
+ PLAYVOICE, CDV_15,
+ FADEDOWN,
+ SHOWSCREEN, CD_15_LOG,
+ FADEUP, CD_15_PAL,
+ WAITVOICE,
+ LOADBG, 59496, // quiet heli
+ LOOPBG,
+ PLAYVOICE, CDV_16,
+ WAITVOICE,
+ PLAYVOICE, CDV_17,
+ DELAY, 2000,
+ SHOWSCREEN, CD_17_LOG,
+ WAITVOICE,
+ BGFLIRT, CD_17,
+ PLAYVOICE, CDV_18,
+ LOADBG, 59497, // loud heli
+ LOOPBG,
+ WAITFLIRT,
+ WAITVOICE,
+ FADEDOWN,
+ SHOWSCREEN, CD_19_LOG,
+ FADEUP, CD_19_PAL,
+ PLAYVOICE, CDV_19,
+ WAITVOICE,
+ PLAYVOICE, CDV_20,
+ FADEDOWN,
+ SHOWSCREEN, CD_20_LOG,
+ FADEUP, CD_19_PAL,
+ WAITVOICE,
+ LOADBG, 59496, // quiet heli
+ LOOPBG,
+ PLAYVOICE, CDV_21,
+ FADEDOWN,
+ SHOWSCREEN, CD_21_LOG,
+ FADEUP, CD_19_PAL,
+ WAITVOICE,
+ PLAYVOICE, CDV_22,
+ LOADBG, 59494, // heli whine
+ PLAYBG,
+ WAITVOICE,
+ PLAYVOICE, CDV_23,
+ FADEDOWN,
+ WAITVOICE,
+ SHOWSCREEN, CD_24_LOG,
+ FADEUP, CD_23_PAL,
+ PLAYVOICE, CDV_24,
+ WAITVOICE,
+ PLAYVOICE, CDV_25,
+ WAITVOICE,
+ PLAYVOICE, CDV_26,
+ WAITVOICE,
+ FADEDOWN,
+ SHOWSCREEN, CD_27_LOG,
+ FADEUP, CD_27_PAL,
+ PLAYVOICE, CDV_27,
+ WAITVOICE,
+ PLAYVOICE, CDV_29,
+ WAITVOICE,
+ PLAYVOICE, CDV_30,
+ WAITVOICE,
+ BGFLIRT, CD_27,
+ PLAYVOICE, CDV_31,
+ WAITVOICE,
+ PLAYVOICE, CDV_32,
+ WAITVOICE,
+ PLAYVOICE, CDV_33,
+ WAITVOICE,
+ PLAYVOICE, CDV_34,
+ WAITFLIRT,
+ WAITVOICE,
+ PLAYVOICE, CDV_35,
+ WAITVOICE,
+ PLAYVOICE, CDV_36,
+ FADEDOWN,
+ SHOWSCREEN, CD_35_LOG,
+ FADEUP, CD_35_PAL,
+ WAITVOICE,
+ PLAYVOICE, CDV_37,
+ DOFLIRT, CD_35,
+ WAITVOICE,
+ PLAYVOICE, CDV_38,
+ DOFLIRT, CD_37,
+ WAITVOICE,
+ PLAYVOICE, CDV_39,
+ WAITVOICE,
+ FADEDOWN,
+ SHOWSCREEN, CD_40_LOG,
+ FADEUP, CD_40_PAL,
+ PLAYVOICE, CDV_40,
+ WAITVOICE,
+ PLAYVOICE, CDV_41,
+ WAITVOICE,
+ PLAYVOICE, CDV_42,
+ WAITVOICE,
+ FADEDOWN,
+ SHOWSCREEN, CD_43_LOG,
+ FADEUP, CD_43_PAL,
+ PLAYVOICE, CDV_43,
+ WAITVOICE,
+ DOFLIRT, CD_43,
+ PLAYVOICE, CDV_45,
+ FADEDOWN,
+ SHOWSCREEN, CD_45_LOG,
+ FADEUP, CD_45_PAL,
+ WAITVOICE,
+ PLAYVOICE, CDV_46,
+ DOFLIRT, CD_45,
+ WAITVOICE,
+ FADEDOWN,
+ SHOWSCREEN, CD_47_LOG,
+ FADEUP, CD_47_PAL,
+ PLAYVOICE, CDV_47,
+ WAITVOICE,
+ PLAYVOICE, CDV_48,
+ FADEDOWN,
+ SHOWSCREEN, CD_48_LOG,
+ FADEUP, CD_48_PAL,
+ WAITVOICE,
+ BGFLIRT, CD_48,
+ PLAYVOICE, CDV_49,
+ WAITVOICE,
+ PLAYVOICE, CDV_50,
+ WAITFLIRT,
+ WAITVOICE,
+ PLAYVOICE, CDV_51,
+ BGFLIRT, CD_49,
+ WAITVOICE,
+ PLAYVOICE, CDV_52,
+ WAITVOICE,
+ PLAYVOICE, CDV_53,
+ WAITVOICE,
+ WAITFLIRT,
+ PLAYVOICE, CDV_54,
+ DOFLIRT, CD_50,
+ WAITVOICE,
+ PLAYVOICE, CDV_55,
+ WAITVOICE,
+ PLAYVOICE, CDV_56,
+ FADEDOWN,
+ SHOWSCREEN, CD_55_LOG,
+ FADEUP, CD_55_PAL,
+ WAITVOICE,
+ PLAYVOICE, CDV_57,
+ WAITVOICE,
+ FADEDOWN,
+ SHOWSCREEN, CD_58_LOG,
+ FADEUP, CD_58_PAL,
+ PLAYVOICE, CDV_58,
+ WAITVOICE,
+ PLAYVOICE, CDV_59,
+ WAITVOICE,
+ PLAYVOICE, CDV_60,
+ WAITVOICE,
+ PLAYVOICE, CDV_61,
+ WAITVOICE,
+ PLAYVOICE, CDV_62,
+ BGFLIRT, CD_58,
+ WAITVOICE,
+ PLAYVOICE, CDV_63,
+ WAITVOICE,
+ PLAYVOICE, CDV_64,
+ WAITFLIRT,
+ WAITVOICE,
+ PLAYVOICE, CDV_65,
+ FADEDOWN,
+ WAITVOICE,
+ SHOWSCREEN, CD_66_LOG,
+ FADEUP, CD_66_PAL,
+ PLAYVOICE, CDV_66,
+ WAITVOICE,
+ PLAYVOICE, CDV_67,
+ FADEDOWN,
+ SHOWSCREEN, CD_67_LOG,
+ FADEUP, CD_67_PAL,
+ WAITVOICE,
+ PLAYVOICE, CDV_68,
+ WAITVOICE,
+ PLAYVOICE, CDV_69,
+ FADEDOWN,
+ SHOWSCREEN, CD_69_LOG,
+ FADEUP, CD_69_PAL,
+ WAITVOICE,
+ PLAYVOICE, CDV_70,
+ DOFLIRT, CD_69,
+ WAITVOICE,
+ FADEDOWN,
+ PLAYVOICE, CDV_71,
+ WAITVOICE,
+ SHOWSCREEN, CD_72_LOG,
+ FADEUP, CD_72_PAL,
+ PLAYVOICE, CDV_72,
+ WAITVOICE,
+ FADEDOWN,
+ SHOWSCREEN, CD_73_LOG,
+ FADEUP, CD_73_PAL,
+ PLAYVOICE, CDV_73,
+ WAITVOICE,
+ PLAYVOICE, CDV_74,
+ WAITVOICE,
+ PLAYVOICE, CDV_75,
+ FADEDOWN,
+ SHOWSCREEN, CD_76_LOG,
+ FADEUP, CD_76_PAL,
+ WAITVOICE,
+ PLAYVOICE, CDV_76,
+ WAITVOICE,
+ PLAYVOICE, CDV_77,
+ WAITVOICE,
+ FADEDOWN,
+ SHOWSCREEN, CD_78_LOG,
+ FADEUP, CD_78_PAL,
+ PLAYVOICE, CDV_78,
+ WAITVOICE,
+ PLAYVOICE, CDV_79,
+ WAITVOICE,
+ PLAYVOICE, CDV_80,
+ BGFLIRT, CD_100,
+ WAITVOICE,
+ PLAYVOICE, CDV_81,
+ WAITVOICE,
+ PLAYVOICE, CDV_82,
+ WAITVOICE,
+ WAITFLIRT,
+ SHOWSCREEN, CD_101_LOG,
+ BGFLIRT, CD_101,
+ PLAYVOICE, CDV_83,
+ WAITVOICE,
+ PLAYVOICE, CDV_84,
+ WAITVOICE,
+ PLAYVOICE, CDV_85,
+ WAITVOICE,
+ WAITFLIRT,
+ SHOWSCREEN, CD_102_LOG,
+ PLAYVOICE, CDV_86,
+ DOFLIRT, CD_102,
+ FADEDOWN,
+ SHOWSCREEN, CD_103_LOG,
+ FADEUP, CD_103_PAL,
+ BGFLIRT, CD_103,
+ WAITVOICE,
+ PLAYVOICE, CDV_87,
+ WAITFLIRT,
+ WAITVOICE,
+ STARTMUSIC, 2,
+ FADEDOWN,
+ SHOWSCREEN, CD_104_LOG,
+ FADEUP, CD_104_PAL,
+ DOFLIRT, CD_104,
+ DOFLIRT, CD_105,
+ SEQEND
+};
+
+uint16 Intro::_floppyIntroSeq[] = {
+ SHOWSCREEN, 60081,
+ FADEUP, 60080,
+ DOFLIRT, 60082,
+ DOFLIRT, 60083,
+ DOFLIRT, 60084, // Beneath a Steel Sky
+ DOFLIRT, 60085,
+ DOFLIRT, 60086,
+ SCROLLFLIRT,
+ COMMANDFLIRT, 60087, // => command list 4a
+ 136, IC_MAKE_SOUND, 1, 70,
+ 90, IC_FX_VOLUME, 80,
+ 50, IC_FX_VOLUME, 90,
+ 5, IC_FX_VOLUME, 100,
+ COMMANDEND,
+ SHOWSCREEN, 60088,
+ COMMANDFLIRT, 60089, // => command list 4b (cockpit)
+ 1000, IC_PREPARE_TEXT, 77,
+ 220, IC_SHOW_TEXT, 20, 160, // radar detects jamming signal
+ 105, IC_REMOVE_TEXT,
+ 105, IC_PREPARE_TEXT, 81,
+ 105, IC_SHOW_TEXT, 170, 86, // well switch to override you fool
+ 35, IC_REMOVE_TEXT,
+ 35, IC_PREPARE_TEXT, 477,
+ 35, IC_SHOW_TEXT, 30, 160,
+ 3, IC_REMOVE_TEXT,
+ COMMANDEND,
+ SHOWSCREEN, 60090,
+ COMMANDFLIRT, 60091, // => command list 4c
+ 1000, IC_FX_VOLUME, 100,
+ 25, IC_FX_VOLUME, 110,
+ 15, IC_FX_VOLUME, 120,
+ 4, IC_FX_VOLUME, 127,
+ COMMANDEND,
+ FADEDOWN,
+ SHOWSCREEN, 60093,
+ FADEUP, 60092,
+ COMMANDFLIRT, 60094, // => command list 5
+ 31, IC_MAKE_SOUND, 2, 127,
+ COMMANDEND,
+ WAITMUSIC,
+ FADEDOWN,
+ SHOWSCREEN, 60096,
+ STARTMUSIC, 2,
+ FADEUP, 60095,
+ COMMANDFLIRT, 60097, // => command list 6a
+ 1000, IC_PREPARE_TEXT, 478,
+ 13, IC_SHOW_TEXT, 175, 155,
+ COMMANDEND,
+ COMMANDFLIRT, 60098, // => command list 6b
+ 131, IC_REMOVE_TEXT,
+ 131, IC_PREPARE_TEXT, 479,
+ 74, IC_SHOW_TEXT, 175, 155,
+ 45, IC_REMOVE_TEXT,
+ 45, IC_PREPARE_TEXT, 162,
+ 44, IC_SHOW_TEXT, 175, 155,
+ 4, IC_REMOVE_TEXT,
+ COMMANDEND,
+ SEQEND
+};
+
+Intro::Intro(Disk *disk, Screen *screen, MusicBase *music, Sound *sound, Text *text, Audio::Mixer *mixer, OSystem *system) {
+
+ _skyDisk = disk;
+ _skyScreen = screen;
+ _skyMusic = music;
+ _skySound = sound;
+ _skyText = text;
+ _mixer = mixer;
+ _system = system;
+ _textBuf = (uint8*)malloc(10000);
+ _saveBuf = (uint8*)malloc(10000);
+ _bgBuf = NULL;
+ _quitProg = false;
+ _relDelay = 0;
+}
+
+Intro::~Intro(void) {
+
+ _mixer->stopAll();
+ _skyScreen->stopSequence();
+ if (_textBuf)
+ free(_textBuf);
+ if (_saveBuf)
+ free(_saveBuf);
+ if (_bgBuf)
+ free(_bgBuf);
+}
+
+bool Intro::doIntro(bool floppyIntro) {
+
+ if (!SkyEngine::isCDVersion())
+ floppyIntro = true;
+
+ _skyMusic->loadSection(0);
+ _skySound->loadSection(0);
+
+ if (!escDelay(3000))
+ return false;
+ if (floppyIntro)
+ _skyMusic->startMusic(1);
+
+ uint16 *seqData = _mainIntroSeq;
+ while (*seqData != SEQEND) {
+ if (!nextPart(seqData))
+ return false;
+ }
+ if (floppyIntro)
+ seqData = _floppyIntroSeq;
+ else
+ seqData = _cdIntroSeq;
+
+ while (*seqData != SEQEND) {
+ if (!nextPart(seqData))
+ return false;
+ }
+ return true;
+}
+
+bool Intro::nextPart(uint16 *&data) {
+
+ uint8 *vData = NULL;
+ // return false means cancel intro
+ uint16 command = *data++;
+ switch (command) {
+ case SHOWSCREEN:
+ _skyScreen->showScreen(*data++);
+ return true;
+ case FADEUP:
+ _skyScreen->paletteFadeUp(*data++);
+ _relDelay += 32 * 20; // hack: the screen uses a seperate delay function for the
+ // blocking fadeups. So add 32*20 msecs to out delay counter.
+ return true;
+ case FADEDOWN:
+ _skyScreen->fnFadeDown(0);
+ _relDelay += 32 * 20; // hack: see above.
+ return true;
+ case DELAY:
+ if (!escDelay(*data++))
+ return false;
+ return true;
+ case DOFLIRT:
+ _skyScreen->startSequence(*data++);
+ while (_skyScreen->sequenceRunning())
+ if (!escDelay(50))
+ return false;
+ return true;
+ case SCROLLFLIRT:
+ return floppyScrollFlirt();
+ case COMMANDFLIRT:
+ return commandFlirt(data);
+ case STOPFLIRT:
+ _skyScreen->stopSequence();
+ return true;
+ case STARTMUSIC:
+ _skyMusic->startMusic(*data++);
+ return true;
+ case WAITMUSIC:
+ while (_skyMusic->musicIsPlaying())
+ if (!escDelay(50))
+ return false;
+ return true;
+ case BGFLIRT:
+ _skyScreen->startSequence(*data++);
+ return true;
+ case WAITFLIRT:
+ while (_skyScreen->sequenceRunning())
+ if (!escDelay(50))
+ return false;
+ return true;
+ case PLAYVOICE:
+ if (!escDelay(200))
+ return false;
+ vData = _skyDisk->loadFile(*data++);
+ // HACK: Fill the header with silence. We should
+ // probably use _skySound instead of calling playRaw()
+ // directly, but this will have to do for now.
+ memset(vData, 127, sizeof(struct dataFileHeader));
+ _mixer->playRaw(&_voice, vData, _skyDisk->_lastLoadedFileSize, 11025,
+ Audio::Mixer::FLAG_AUTOFREE | Audio::Mixer::FLAG_UNSIGNED, SOUND_VOICE);
+ return true;
+ case WAITVOICE:
+ while (_mixer->isSoundHandleActive(_voice))
+ if (!escDelay(50))
+ return false;
+ return true;
+ case LOADBG:
+ _mixer->stopID(SOUND_BG);
+ if (_bgBuf)
+ free(_bgBuf);
+ _bgBuf = _skyDisk->loadFile(*data++);
+ _bgSize = _skyDisk->_lastLoadedFileSize;
+ return true;
+ case LOOPBG:
+ _mixer->stopID(SOUND_BG);
+ _mixer->playRaw(&_bgSfx, _bgBuf + 256, _bgSize - 768, 11025,
+ Audio::Mixer::FLAG_UNSIGNED | Audio::Mixer::FLAG_LOOP, SOUND_BG);
+ return true;
+ case PLAYBG:
+ _mixer->stopID(SOUND_BG);
+ _mixer->playRaw(&_bgSfx, _bgBuf + 256, _bgSize - 768, 11025,
+ Audio::Mixer::FLAG_UNSIGNED, SOUND_BG);
+ return true;
+ case STOPBG:
+ _mixer->stopID(SOUND_BG);
+ return true;
+ default:
+ error("Unknown intro command %X", command);
+ }
+ return true;
+}
+
+bool Intro::floppyScrollFlirt(void) {
+
+ uint8 *scrollScreen = (uint8*)malloc(FRAME_SIZE * 2);
+ memset(scrollScreen, 0, FRAME_SIZE);
+ memcpy(scrollScreen + FRAME_SIZE, _skyScreen->giveCurrent(), FRAME_SIZE);
+ uint8 *scrollPos = scrollScreen + FRAME_SIZE;
+ uint8 *vgaData = _skyDisk->loadFile(60100);
+ uint8 *diffData = _skyDisk->loadFile(60101);
+ uint16 frameNum = READ_LE_UINT16(diffData);
+ uint8 *diffPtr = diffData + 2;
+ uint8 *vgaPtr = vgaData;
+ bool doContinue = true;
+
+ for (uint16 frameCnt = 1; (frameCnt < frameNum) && doContinue; frameCnt++) {
+ uint8 scrollVal = *diffPtr++;
+ if (scrollVal)
+ scrollPos -= scrollVal * GAME_SCREEN_WIDTH;
+
+ uint16 scrPos = 0;
+ while (scrPos < FRAME_SIZE) {
+ uint8 nrToDo, nrToSkip;
+ do {
+ nrToSkip = *diffPtr++;
+ scrPos += nrToSkip;
+ } while (nrToSkip == 255);
+ do {
+ nrToDo = *diffPtr++;
+ memcpy(scrollPos + scrPos, vgaPtr, nrToDo);
+ scrPos += nrToDo;
+ vgaPtr += nrToDo;
+ } while (nrToDo == 255);
+ }
+ _system->copyRectToScreen(scrollPos, GAME_SCREEN_WIDTH, 0, 0, GAME_SCREEN_WIDTH, GAME_SCREEN_HEIGHT);
+ _system->updateScreen();
+ if (!escDelay(60))
+ doContinue = false;
+ }
+ memcpy(_skyScreen->giveCurrent(), scrollPos, FRAME_SIZE);
+ free(diffData);
+ free(vgaData);
+ free(scrollScreen);
+ return doContinue;
+}
+
+bool Intro::commandFlirt(uint16 *&data) {
+
+ _skyScreen->startSequence(*data++);
+ while ((*data != COMMANDEND) || _skyScreen->sequenceRunning()) {
+ while ((_skyScreen->seqFramesLeft() < *data)) {
+ data++;
+ uint16 command = *data++;
+ switch(command) {
+ case IC_PREPARE_TEXT:
+ _skyText->displayText(*data++, _textBuf, true, INTRO_TEXT_WIDTH, 255);
+ break;
+ case IC_SHOW_TEXT:
+ ((dataFileHeader*)_textBuf)->s_x = *data++;
+ ((dataFileHeader*)_textBuf)->s_y = *data++;
+ showTextBuf();
+ break;
+ case IC_REMOVE_TEXT:
+ restoreScreen();
+ break;
+ case IC_MAKE_SOUND:
+ _skySound->playSound(data[0], data[1], 0);
+ data += 2;
+ break;
+ case IC_FX_VOLUME:
+ _skySound->playSound(1, *data++, 0);
+ break;
+ default:
+ error("Unknown FLIRT command %X\n", command);
+ }
+ }
+ if (!escDelay(50)) {
+ _skyScreen->stopSequence();
+ return false;
+ }
+ }
+ data++; // move pointer over "COMMANDEND"
+ return true;
+}
+
+void Intro::showTextBuf(void) {
+
+ uint16 x = ((dataFileHeader*)_textBuf)->s_x;
+ uint16 y = ((dataFileHeader*)_textBuf)->s_y;
+ uint16 width = ((dataFileHeader*)_textBuf)->s_width;
+ uint16 height = ((dataFileHeader*)_textBuf)->s_height;
+ uint8 *screenBuf = _skyScreen->giveCurrent() + y * GAME_SCREEN_WIDTH + x;
+ memcpy(_saveBuf, _textBuf, sizeof(dataFileHeader));
+ uint8 *saveBuf = _saveBuf + sizeof(dataFileHeader);
+ uint8 *textBuf = _textBuf + sizeof(dataFileHeader);
+ for (uint16 cnty = 0; cnty < height; cnty++) {
+ memcpy(saveBuf, screenBuf, width);
+ for (uint16 cntx = 0; cntx < width; cntx++)
+ if (textBuf[cntx])
+ screenBuf[cntx] = textBuf[cntx];
+ screenBuf += GAME_SCREEN_WIDTH;
+ textBuf += width;
+ saveBuf += width;
+ }
+ screenBuf = _skyScreen->giveCurrent() + y * GAME_SCREEN_WIDTH + x;
+ _system->copyRectToScreen(screenBuf, GAME_SCREEN_WIDTH, x, y, width, height);
+}
+
+void Intro::restoreScreen(void) {
+
+ uint16 x = ((dataFileHeader*)_saveBuf)->s_x;
+ uint16 y = ((dataFileHeader*)_saveBuf)->s_y;
+ uint16 width = ((dataFileHeader*)_saveBuf)->s_width;
+ uint16 height = ((dataFileHeader*)_saveBuf)->s_height;
+ uint8 *screenBuf = _skyScreen->giveCurrent() + y * GAME_SCREEN_WIDTH + x;
+ uint8 *saveBuf = _saveBuf + sizeof(dataFileHeader);
+ for (uint16 cnt = 0; cnt < height; cnt++) {
+ memcpy(screenBuf, saveBuf, width);
+ screenBuf += GAME_SCREEN_WIDTH;
+ saveBuf += width;
+ }
+ _system->copyRectToScreen(_saveBuf + sizeof(dataFileHeader), width, x, y, width, height);
+}
+
+bool Intro::escDelay(uint32 msecs) {
+
+ OSystem::Event event;
+ if (_relDelay == 0) // first call, init with system time
+ _relDelay = (int32)_system->getMillis();
+
+ _relDelay += msecs; // now wait until _system->getMillis() >= _relDelay
+
+ int32 nDelay = 0;
+ do {
+ while (_system->pollEvent(event)) {
+ if (event.type == OSystem::EVENT_KEYDOWN) {
+ if (event.kbd.keycode == 27)
+ return false;
+ } else if (event.type == OSystem::EVENT_QUIT) {
+ _quitProg = true;
+ return false;
+ }
+ }
+ nDelay = _relDelay - _system->getMillis();
+ if (nDelay < 0)
+ nDelay = 0;
+ else if (nDelay > 15)
+ nDelay = 15;
+ _system->delayMillis(nDelay);
+ } while (nDelay == 15);
+ return true;
+}
+
+} // End of namespace Sky
diff --git a/engines/sky/intro.h b/engines/sky/intro.h
new file mode 100644
index 0000000000..294c907887
--- /dev/null
+++ b/engines/sky/intro.h
@@ -0,0 +1,74 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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 INTRO_H
+#define INTRO_H
+
+#include "common/stdafx.h"
+#include "common/scummsys.h"
+#include "sound/mixer.h"
+
+namespace Sky {
+
+class Disk;
+class Screen;
+class MusicBase;
+class Sound;
+class Text;
+
+class Intro {
+public:
+ Intro(Disk *disk, Screen *screen, MusicBase *music, Sound *sound, Text *text, Audio::Mixer *mixer, OSystem *system);
+ ~Intro(void);
+ bool doIntro(bool floppyIntro);
+ bool _quitProg;
+private:
+ static uint16 _mainIntroSeq[];
+ static uint16 _floppyIntroSeq[];
+ static uint16 _cdIntroSeq[];
+
+ Disk *_skyDisk;
+ Screen *_skyScreen;
+ MusicBase *_skyMusic;
+ Sound *_skySound;
+ Text *_skyText;
+ OSystem *_system;
+ Audio::Mixer *_mixer;
+
+ uint8 *_textBuf, *_saveBuf;
+ uint8 *_bgBuf;
+ uint32 _bgSize;
+ Audio::SoundHandle _voice, _bgSfx;
+
+ int32 _relDelay;
+
+ bool escDelay(uint32 msecs);
+ bool nextPart(uint16 *&data);
+ bool floppyScrollFlirt(void);
+ bool commandFlirt(uint16 *&data);
+ void showTextBuf(void);
+ void restoreScreen(void);
+};
+
+} // End of namespace Sky
+
+#endif // INTRO_H
diff --git a/engines/sky/logic.cpp b/engines/sky/logic.cpp
new file mode 100644
index 0000000000..9ea560a5bf
--- /dev/null
+++ b/engines/sky/logic.cpp
@@ -0,0 +1,2570 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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 "sky/autoroute.h"
+#include "sky/compact.h"
+#include "sky/control.h"
+#include "sky/debug.h"
+#include "sky/disk.h"
+#include "sky/grid.h"
+#include "sky/logic.h"
+#include "sky/mouse.h"
+#include "sky/music/musicbase.h"
+#include "sky/text.h"
+#include "sky/screen.h"
+#include "sky/sky.h"
+#include "sky/sound.h"
+#include "sky/struc.h"
+
+namespace Sky {
+
+uint32 Logic::_scriptVariables[NUM_SKY_SCRIPTVARS];
+
+void Logic::setupLogicTable() {
+ static const LogicTable logicTable[] = {
+ &Logic::nop,
+ &Logic::logicScript, // 1 script processor
+ &Logic::autoRoute, // 2 Make a route
+ &Logic::arAnim, // 3 Follow a route
+ &Logic::arTurn, // 4 Mega turns araound
+ &Logic::alt, // 5 Set up new get-to script
+ &Logic::anim, // 6 Follow a sequence
+ &Logic::turn, // 7 Mega turning
+ &Logic::cursor, // 8 id tracks the pointer
+ &Logic::talk, // 9 count down and animate
+ &Logic::listen, // 10 player waits for talking id
+ &Logic::stopped, // 11 wait for id to move
+ &Logic::choose, // 12 wait for player to click
+ &Logic::frames, // 13 animate just frames
+ &Logic::pause, // 14 Count down to 0 and go
+ &Logic::waitSync, // 15 Set to l_script when sync!=0
+ &Logic::simpleAnim, // 16 Module anim without x,y's
+ };
+
+ _logicTable = logicTable;
+}
+
+Logic::Logic(SkyCompact *skyCompact, Screen *skyScreen, Disk *skyDisk, Text *skyText, MusicBase *skyMusic, Mouse *skyMouse, Sound *skySound) {
+ _skyCompact = skyCompact;
+ _skyScreen = skyScreen;
+ _skyDisk = skyDisk;
+ _skyText = skyText;
+ _skyMusic = skyMusic;
+ _skySound = skySound;
+ _skyMouse = skyMouse;
+ _skyGrid = new Grid(_skyDisk, _skyCompact);
+ _skyAutoRoute = new AutoRoute(_skyGrid, _skyCompact);
+
+ setupLogicTable();
+ setupMcodeTable();
+
+ memset(_objectList, 0, 30 * sizeof(uint32));
+
+ for (int i = 0; i < ARRAYSIZE(_moduleList); i++)
+ _moduleList[i] = 0;
+ _stackPtr = 0;
+
+ _currentSection = 0xFF; //force music & sound reload
+ initScriptVariables();
+}
+
+Logic::~Logic(void) {
+ delete _skyGrid;
+ delete _skyAutoRoute;
+
+ for (int i = 0; i < ARRAYSIZE(_moduleList); i++)
+ if (_moduleList[i])
+ free(_moduleList[i]);
+}
+
+void Logic::initScreen0(void) {
+ fnEnterSection(0, 0, 0);
+ _skyMusic->startMusic(2);
+ SkyEngine::_systemVars.currentMusic = 2;
+}
+
+void Logic::parseSaveData(uint32 *data) {
+ if (!SkyEngine::isDemo())
+ fnLeaveSection(_scriptVariables[CUR_SECTION], 0, 0);
+ for (uint16 cnt = 0; cnt < NUM_SKY_SCRIPTVARS; cnt++)
+ _scriptVariables[cnt] = READ_LE_UINT32(data++);
+ fnEnterSection(_scriptVariables[CUR_SECTION], 0, 0);
+}
+
+bool Logic::checkProtection(void) {
+ if (_scriptVariables[ENTER_DIGITS]) {
+ if (_scriptVariables[CONSOLE_TYPE] == 5) // reactor code
+ _scriptVariables[FS_COMMAND] = 240;
+ else // copy protection
+ _scriptVariables[FS_COMMAND] = 337;
+ _scriptVariables[ENTER_DIGITS] = 0;
+ return true;
+ } else
+ return false;
+}
+
+void Logic::engine() {
+ do {
+ uint16 *logicList = (uint16 *)_skyCompact->fetchCpt(_scriptVariables[LOGIC_LIST_NO]);
+
+ while (uint16 id = *logicList++) { // 0 means end of list
+ if (id == 0xffff) {
+ // Change logic data address
+ logicList = (uint16 *)_skyCompact->fetchCpt(*logicList);
+ continue;
+ }
+
+ _scriptVariables[CUR_ID] = id;
+ _compact = _skyCompact->fetchCpt(id);
+
+ // check the id actually wishes to be processed
+ if (!(_compact->status & (1 << 6)))
+ continue;
+
+ // ok, here we process the logic bit system
+
+ if (_compact->status & (1 << 7))
+ _skyGrid->removeObjectFromWalk(_compact);
+
+ Debug::logic(_compact->logic);
+ (this->*_logicTable[_compact->logic]) ();
+
+ if (_compact->status & (1 << 7))
+ _skyGrid->objectToWalk(_compact);
+
+ // a sync sent to the compact is available for one cycle
+ // only. that cycle has just ended so remove the sync.
+ // presumably the mega has just reacted to it.
+ _compact->sync = 0;
+ }
+ // usually this loop is run only once, it'll only be run a second time if the game
+ // script just asked the user to enter a copy protection code.
+ // this is done to prevent the copy protection screen from flashing up.
+ // (otherwise it would be visible for 1/50 second)
+ } while (checkProtection());
+}
+
+void Logic::nop() {}
+
+/**
+ * This function is basicly a wrapper around the real script engine. It runs
+ * the script engine until a script has finished.
+ * @see script()
+ */
+void Logic::logicScript() {
+ /// Process the current mega's script
+ /// If the script finishes then drop back a level
+
+ for (;;) {
+ uint16 mode = _compact->mode; // get pointer to current script
+ uint16 *scriptNo = SkyCompact::getSub(_compact, mode);
+ uint16 *offset = SkyCompact::getSub(_compact, mode + 2);
+
+ *offset = script(*scriptNo, *offset);
+
+ if (!*offset) // script finished
+ _compact->mode -= 4;
+ else if (_compact->mode == mode)
+ return;
+ }
+}
+
+void Logic::autoRoute() {
+
+ _compact->downFlag = _skyAutoRoute->autoRoute(_compact);
+ if ((_compact->downFlag == 2) && _skyCompact->cptIsId(_compact, CPT_JOEY) &&
+ (_compact->mode == 0) && (_compact->baseSub == JOEY_OUT_OF_LIFT)) {
+ // workaround for script bug #1064113. Details unclear...
+ _compact->downFlag = 0;
+ }
+ if (_compact->downFlag != 1) { // route ok
+ _compact->grafixProgId = _compact->animScratchId;
+ _compact->grafixProgPos = 0;
+ }
+
+ _compact->logic = L_SCRIPT; // continue the script
+
+ logicScript();
+ return;
+}
+
+void Logic::arAnim() {
+ /// Follow a route
+ /// Mega should be in getToMode
+
+ // only check collisions on character boundaries
+ if ((_compact->xcood & 7) || (_compact->ycood & 7)) {
+ mainAnim();
+ return;
+ }
+
+ // On character boundary. Have we been told to wait?
+ // if not - are WE colliding?
+
+ if (_compact->waitingFor == 0xffff) { // 1st cycle of re-route does
+ mainAnim();
+ return;
+ }
+
+ if (_compact->waitingFor) {
+ // ok, we've been told we've hit someone
+ // we will wait until we are no longer colliding
+ // with them. here we check to see if we are (still) colliding.
+ // if we are then run the stop script. if not clear the flag
+ // and continue.
+
+ // remember - this could be the first ar cycle for some time,
+ // we might have been told to wait months ago. if we are
+ // waiting for one person then another hits us then
+ // c_waiting_for will be replaced by the new mega - this is
+ // fine because the later collision will almost certainly
+ // take longer to clear than the earlier one.
+
+ if (collide(_skyCompact->fetchCpt(_compact->waitingFor))) {
+ stopAndWait();
+ return;
+ }
+
+ // we are not in fact hitting this person so clr & continue
+ // it must have registered some time ago
+
+ _compact->waitingFor = 0; // clear id flag
+ }
+
+ // ok, our turn to check for collisions
+
+ uint16 *logicList = (uint16 *)_skyCompact->fetchCpt(_scriptVariables[LOGIC_LIST_NO]);
+ Compact *cpt = 0;
+
+ while (uint16 id = *logicList++) { // get an id
+
+ if (id == 0xffff) { // address change?
+ logicList = (uint16 *)_skyCompact->fetchCpt(*logicList); // get new logic list
+ continue;
+ }
+
+ if (id == (uint16)(_scriptVariables[CUR_ID] & 0xffff)) // is it us?
+ continue;
+
+ _scriptVariables[HIT_ID] = id; // save target id for any possible c_mini_bump
+ cpt = _skyCompact->fetchCpt(id); // let's have a closer look
+
+ if (!(cpt->status & (1 << ST_COLLISION_BIT))) // can it collide?
+ continue;
+
+ if (cpt->screen != _compact->screen) // is it on our screen?
+ continue;
+
+ if (collide(cpt)) { // check for a hit
+ // ok, we've hit a mega
+ // is it moving... or something else?
+
+ if (cpt->logic != L_AR_ANIM) { // check for following route
+ // it is doing something else
+ // we restart our get-to script
+ // first tell it to wait for us - in case it starts moving
+ // ( *it may have already hit us and stopped to wait )
+
+ _compact->waitingFor = 0xffff; // effect 1 cycle collision skip
+ // tell it it is waiting for us
+ cpt->waitingFor = (uint16)(_scriptVariables[CUR_ID] & 0xffff);
+ // restart current script
+ *SkyCompact::getSub(_compact, _compact->mode + 2) = 0;
+ _compact->logic = L_SCRIPT;
+ logicScript();
+ return;
+ }
+
+ script(_compact->miniBump, 0);
+ return;
+ }
+ }
+
+ // ok, there was no collisions
+ // now check for interaction request
+ // *note: the interaction is always set up as an action script
+
+ if (_compact->request) {
+ _compact->mode = C_ACTION_MODE; // put into action mode
+ _compact->actionSub = _compact->request;
+ _compact->actionSub_off = 0;
+ _compact->request = 0; // trash request
+ _compact->logic = L_SCRIPT;
+ logicScript();
+ return;
+ }
+
+ // any flag? - or any change?
+ // if change then re-run the current script, which must be
+ // a position independent get-to ----
+
+ if (!_compact->atWatch) { // any flag set?
+ mainAnim();
+ return;
+ }
+
+ // ok, there is an at watch - see if it's changed
+
+ if (_compact->atWas == _scriptVariables[_compact->atWatch/4]) { // still the same?
+ mainAnim();
+ return;
+ }
+
+ // changed so restart the current script
+ // *not suitable for base initiated ARing
+ *SkyCompact::getSub(_compact, _compact->mode + 2) = 0;
+
+ _compact->logic = L_SCRIPT;
+ logicScript();
+}
+
+void Logic::mainAnim() {
+ /// Extension of arAnim()
+ _compact->waitingFor = 0; // clear possible zero-zero skip
+
+ uint16 *sequence = _skyCompact->getGrafixPtr(_compact);
+ if (!*sequence) {
+ // ok, move to new anim segment
+ sequence += 2;
+ _compact->grafixProgPos += 2;
+ if (!*sequence) { // end of route?
+ // ok, sequence has finished
+
+ // will start afresh if new sequence continues in last direction
+ _compact->arAnimIndex = 0;
+
+ _compact->downFlag = 0; // pass back ok to script
+ _compact->logic = L_SCRIPT;
+ logicScript();
+ return;
+ }
+
+ _compact->arAnimIndex = 0; // reset position
+ }
+
+ uint16 dir;
+ while ((dir = _compact->dir) != *(sequence + 1)) {
+ // ok, setup turning
+ _compact->dir = *(sequence + 1);
+
+ uint16 *tt = _skyCompact->getTurnTable(_compact, dir);
+ if (tt[_compact->dir]) {
+ _compact->turnProgId = tt[_compact->dir];
+ _compact->turnProgPos = 0;
+ _compact->logic = L_AR_TURNING;
+ arTurn();
+ return;
+ }
+ };
+
+ uint16 animId = *(uint16*)_skyCompact->getCompactElem(_compact, C_ANIM_UP + _compact->megaSet + dir * 4);
+ uint16 *animList = (uint16*)_skyCompact->fetchCpt(animId);
+
+ uint16 arAnimIndex = _compact->arAnimIndex;
+ if (!animList[arAnimIndex / 2]) {
+ arAnimIndex = 0;
+ _compact->arAnimIndex = 0; // reset
+ }
+
+ _compact->arAnimIndex += S_LENGTH;
+
+ *sequence -= animList[(S_COUNT + arAnimIndex)/2]; // reduce the distance to travel
+ _compact->frame = animList[(S_FRAME + arAnimIndex)/2]; // new graphic frame
+ _compact->xcood += animList[(S_AR_X + arAnimIndex)/2]; // update x coordinate
+ _compact->ycood += animList[(S_AR_Y + arAnimIndex)/2]; // update y coordinate
+}
+
+void Logic::arTurn() {
+ uint16 *turnData = (uint16*)_skyCompact->fetchCpt(_compact->turnProgId) + _compact->turnProgPos;
+ _compact->frame = *turnData++;
+ _compact->turnProgPos++;
+
+ if (!*turnData) { // turn done?
+ // Back to ar mode
+ _compact->arAnimIndex = 0;
+ _compact->logic = L_AR_ANIM;
+ }
+}
+
+void Logic::alt() {
+ /// change the current script
+ _compact->logic = L_SCRIPT;
+ *SkyCompact::getSub(_compact, _compact->mode) = _compact->alt;
+ *SkyCompact::getSub(_compact, _compact->mode + 2) = 0;
+ logicScript();
+}
+
+void Logic::anim() {
+ /// Follow an animation sequence
+ uint16 *grafixProg = _skyCompact->getGrafixPtr(_compact);
+
+ while (*grafixProg) {
+ _compact->grafixProgPos += 3; // all types are 3 words.
+ if (*grafixProg == LF_START_FX) { // do fx
+ grafixProg++;
+ uint16 sound = *grafixProg++;
+ uint16 volume = *grafixProg++;
+
+ // channel 0
+ fnStartFx(sound, 0, volume);
+ } else if (*grafixProg >= LF_START_FX) { // do sync
+ grafixProg++;
+
+ Compact *cpt = _skyCompact->fetchCpt(*grafixProg++);
+
+ cpt->sync = *grafixProg++;
+ } else { // put coordinates and frame in
+ _compact->xcood = *grafixProg++;
+ _compact->ycood = *grafixProg++;
+
+ _compact->frame = *grafixProg++ | _compact->offset;
+ return;
+ }
+ }
+
+ _compact->downFlag = 0;
+ _compact->logic = L_SCRIPT;
+ logicScript();
+}
+
+void Logic::turn() {
+ uint16 *turnData = (uint16*)_skyCompact->fetchCpt(_compact->turnProgId) + _compact->turnProgPos;
+ if (*turnData) {
+ _compact->frame = *turnData;
+ _compact->turnProgPos++;
+ return;
+ }
+
+ // turn_to_script:
+ _compact->arAnimIndex = 0;
+ _compact->logic = L_SCRIPT;
+
+ logicScript();
+}
+
+void Logic::cursor() {
+ _skyText->logicCursor(_compact, _skyMouse->giveMouseX(), _skyMouse->giveMouseY());
+}
+
+static uint16 clickTable[46] = {
+ ID_FOSTER,
+ ID_JOEY,
+ ID_JOBS,
+ ID_LAMB,
+ ID_ANITA,
+ ID_SON,
+ ID_DAD,
+ ID_MONITOR,
+ ID_SHADES,
+ MINI_SS,
+ FULL_SS,
+ ID_FOREMAN,
+ ID_RADMAN,
+ ID_GALLAGER_BEL,
+ ID_BURKE,
+ ID_BODY,
+ ID_HOLO,
+ ID_TREVOR,
+ ID_ANCHOR,
+ ID_WRECK_GUARD,
+ ID_SKORL_GUARD,
+
+ // BASE LEVEL
+ ID_SC30_HENRI,
+ ID_SC31_GUARD,
+ ID_SC32_VINCENT,
+ ID_SC32_GARDENER,
+ ID_SC32_BUZZER,
+ ID_SC36_BABS,
+ ID_SC36_BARMAN,
+ ID_SC36_COLSTON,
+ ID_SC36_GALLAGHER,
+ ID_SC36_JUKEBOX,
+ ID_DANIELLE,
+ ID_SC42_JUDGE,
+ ID_SC42_CLERK,
+ ID_SC42_PROSECUTION,
+ ID_SC42_JOBSWORTH,
+
+ // UNDERWORLD
+ ID_MEDI,
+ ID_WITNESS,
+ ID_GALLAGHER,
+ ID_KEN,
+ ID_SC76_ANDROID_2,
+ ID_SC76_ANDROID_3,
+ ID_SC81_FATHER,
+ ID_SC82_JOBSWORTH,
+
+ // LINC WORLD
+ ID_HOLOGRAM_B,
+ 12289
+};
+
+void Logic::talk() {
+ // first count through the frames
+ // just frames - nothing tweeky
+ // the speech finishes when the timer runs out &
+ // not when the animation finishes
+ // this routine is very task specific
+
+ // TODO: Check for mouse clicking
+
+ // Are we allowed to click
+
+ if (_skyMouse->wasClicked())
+ for (int i = 0; i < ARRAYSIZE(clickTable); i++)
+ if (clickTable[i] == (uint16)_scriptVariables[CUR_ID]) {
+ if ((SkyEngine::_systemVars.systemFlags & SF_ALLOW_SPEECH) && (!_skySound->speechFinished()))
+ _skySound->stopSpeech();
+ if ((_compact->spTextId > 0) &&
+ (_compact->spTextId < 0xFFFF)) {
+
+ _skyCompact->fetchCpt(_compact->spTextId)->status = 0;
+ }
+ if (_skyCompact->getGrafixPtr(_compact)) {
+ _compact->frame = _compact->getToFlag; // set character to stand
+ _compact->grafixProgId = 0;
+ }
+
+ _compact->logic = L_SCRIPT;
+ logicScript();
+ return;
+ }
+
+ // If speech is allowed then check for it to finish before finishing animations
+
+ if ((_compact->spTextId == 0xFFFF) && // is this a voc file?
+ (_skySound->speechFinished())) { // finished?
+
+ _compact->logic = L_SCRIPT; // restart character control
+
+ if (_skyCompact->getGrafixPtr(_compact)) {
+ _compact->frame = _compact->getToFlag; // set character to stand
+ _compact->grafixProgId = 0;
+ }
+
+ logicScript();
+ return;
+ }
+
+ uint16 *graphixProg = _skyCompact->getGrafixPtr(_compact);
+ if (graphixProg) {
+ if ((*graphixProg) && ((_compact->spTime != 3) || (!_skySound->speechFinished()))) {
+ // we will force the animation to finish 3 game cycles
+ // before the speech actually finishes - because it looks good.
+
+ _compact->frame = *(graphixProg + 2) + _compact->offset;
+ graphixProg += 3;
+ _compact->grafixProgPos += 3;
+ } else {
+ // we ran out of frames or finished speech, let actor stand still.
+ _compact->frame = _compact->getToFlag;
+ _compact->grafixProgId = 0;
+ }
+ }
+
+ if (_skySound->speechFinished()) _compact->spTime--;
+
+ if (_compact->spTime == 0) {
+
+ // ok, speech has finished
+
+ if (_compact->spTextId) {
+ Compact *cpt = _skyCompact->fetchCpt(_compact->spTextId); // get text id to kill
+ cpt->status = 0; // kill the text
+ }
+
+ _compact->logic = L_SCRIPT;
+ logicScript();
+ }
+}
+
+void Logic::listen() {
+ /// Stay in this mode until id in getToFlag leaves L_TALK mode
+
+ Compact *cpt = _skyCompact->fetchCpt(_compact->flag);
+
+ if (cpt->logic == L_TALK)
+ return;
+
+ _compact->logic = L_SCRIPT;
+ logicScript();
+}
+
+void Logic::stopped() {
+ /// waiting for another mega to move or give-up trying
+ ///
+ /// this mode will always be set up from a special script
+ /// that will be one level higher than the script we
+ /// would wish to restart from
+
+ Compact *cpt = _skyCompact->fetchCpt(_compact->waitingFor);
+
+ if (cpt)
+ if (!cpt->mood && collide(cpt))
+ return;
+
+ // we are free, continue processing the script
+
+ // restart script one level below
+ *SkyCompact::getSub(_compact, _compact->mode - 2) = 0;
+ _compact->waitingFor = 0xffff;
+
+ _compact->logic = L_SCRIPT;
+ logicScript();
+}
+
+void Logic::choose() {
+ // Remain in this mode until player selects some text
+ if (!_scriptVariables[THE_CHOSEN_ONE])
+ return;
+
+ fnNoHuman(0, 0, 0); // kill mouse again
+
+ SkyEngine::_systemVars.systemFlags &= ~SF_CHOOSING; // restore save/restore
+
+ _compact->logic = L_SCRIPT; // and continue script
+ logicScript();
+}
+
+void Logic::frames() {
+ if (!_compact->sync)
+ simpleAnim();
+ else {
+ _compact->downFlag = 0; // return 'ok' to script
+ _compact->logic = L_SCRIPT;
+ logicScript();
+ }
+}
+
+void Logic::pause() {
+ if (--_compact->flag)
+ return;
+
+ _compact->logic = L_SCRIPT;
+ logicScript();
+ return;
+}
+
+void Logic::waitSync() {
+ /// checks c_sync, when its non 0
+ /// the id is put back into script mode
+ // use this instead of loops in the script
+
+ if (!_compact->sync)
+ return;
+
+ _compact->logic = L_SCRIPT;
+ logicScript();
+}
+
+void Logic::simpleAnim() {
+ /// follow an animation sequence module whilst ignoring the coordinate data
+
+ uint16 *grafixProg = _skyCompact->getGrafixPtr(_compact);
+
+ // *grafix_prog: command
+ while (*grafixProg) {
+ _compact->grafixProgPos += 3;
+ if (*grafixProg != SEND_SYNC) {
+ grafixProg++;
+ grafixProg++; // skip coordinates
+
+ // *grafix_prog: frame
+ if (*grafixProg >= 64)
+ _compact->frame = *grafixProg;
+ else
+ _compact->frame = *grafixProg + _compact->offset;
+
+ return;
+ }
+
+ grafixProg++;
+ // *grafix_prog: id to sync
+ Compact *compact2 = _skyCompact->fetchCpt(*grafixProg);
+ grafixProg++;
+
+ // *grafix_prog: sync
+ compact2->sync = *grafixProg;
+ grafixProg++;
+ }
+
+ _compact->downFlag = 0; // return 'ok' to script
+ _compact->logic = L_SCRIPT;
+ logicScript();
+}
+
+bool Logic::collide(Compact *cpt) {
+ MegaSet *m1 = SkyCompact::getMegaSet(_compact);
+ MegaSet *m2 = SkyCompact::getMegaSet(cpt);
+
+ // target's base coordinates
+ uint16 x = cpt->xcood & 0xfff8;
+ uint16 y = cpt->ycood & 0xfff8;
+
+ // The collision is direction dependent
+ switch (_compact->dir) {
+ case 0: // looking up
+ x -= m1->colOffset; // compensate for inner x offsets
+ x += m2->colOffset;
+
+ if ((x + m2->colWidth) < _compact->xcood) // their rightmost
+ return false;
+
+ x -= m1->colWidth; // our left, their right
+ if (x >= _compact->xcood)
+ return false;
+
+ y += 8; // bring them down a line
+ if (y == _compact->ycood)
+ return true;
+
+ y += 8; // bring them down a line
+ if (y == _compact->ycood)
+ return true;
+
+ return false;
+ case 1: // looking down
+ x -= m1->colOffset; // compensate for inner x offsets
+ x += m2->colOffset;
+
+ if ((x + m2->colWidth) < _compact->xcood) // their rightmoast
+ return false;
+
+ x -= m1->colWidth; // our left, their right
+ if (x >= _compact->xcood)
+ return false;
+
+ y -= 8; // bring them up a line
+ if (y == _compact->ycood)
+ return true;
+
+ y -= 8; // bring them up a line
+ if (y == _compact->ycood)
+ return true;
+
+ return false;
+ case 2: // looking left
+
+ if (y != _compact->ycood)
+ return false;
+
+ x += m2->lastChr;
+ if (x == _compact->xcood)
+ return true;
+
+ x -= 8; // out another one
+ if (x == _compact->xcood)
+ return true;
+
+ return false;
+ case 3: // looking right
+ case 4: // talking (not sure if this makes sense...)
+
+ if (y != _compact->ycood)
+ return false;
+
+ x -= m1->lastChr; // last block
+ if (x == _compact->xcood)
+ return true;
+
+ x -= 8; // out another block
+ if (x != _compact->xcood)
+ return false;
+
+ return true;
+ default:
+ error("Unknown Direction: %d", _compact->dir);
+ }
+}
+
+void Logic::runGetOff() {
+ uint32 getOff = _scriptVariables[GET_OFF];
+ _scriptVariables[GET_OFF] = 0;
+ if (getOff)
+ script((uint16)(getOff & 0xffff), (uint16)(getOff >> 16));
+}
+
+void Logic::stopAndWait() {
+ _compact->mode += 4;
+
+ uint16 *scriptNo = SkyCompact::getSub(_compact, _compact->mode);
+ uint16 *offset = SkyCompact::getSub(_compact, _compact->mode + 2);
+
+ *scriptNo = _compact->stopScript;
+ *offset = 0;
+
+ _compact->logic = L_SCRIPT;
+ logicScript();
+}
+
+void Logic::checkModuleLoaded(uint16 moduleNo) {
+ if (!_moduleList[moduleNo])
+ _moduleList[moduleNo] = (uint16 *)_skyDisk->loadFile((uint16)moduleNo + F_MODULE_0);
+}
+
+void Logic::push(uint32 a) {
+ if (_stackPtr > ARRAYSIZE(_stack) - 2)
+ error("Stack overflow");
+ _stack[_stackPtr++] = a;
+}
+
+uint32 Logic::pop() {
+ if (_stackPtr < 1 || _stackPtr > ARRAYSIZE(_stack) - 1)
+ error("No items on Stack to pop");
+ return _stack[--_stackPtr];
+}
+
+void Logic::setupMcodeTable() {
+ static const McodeTable mcodeTable[] = {
+ &Logic::fnCacheChip,
+ &Logic::fnCacheFast,
+ &Logic::fnDrawScreen,
+ &Logic::fnAr,
+ &Logic::fnArAnimate,
+ &Logic::fnIdle,
+ &Logic::fnInteract,
+ &Logic::fnStartSub,
+ &Logic::fnTheyStartSub,
+ &Logic::fnAssignBase,
+ &Logic::fnDiskMouse,
+ &Logic::fnNormalMouse,
+ &Logic::fnBlankMouse,
+ &Logic::fnCrossMouse,
+ &Logic::fnCursorRight,
+ &Logic::fnCursorLeft,
+ &Logic::fnCursorDown,
+ &Logic::fnOpenHand,
+ &Logic::fnCloseHand,
+ &Logic::fnGetTo,
+ &Logic::fnSetToStand,
+ &Logic::fnTurnTo,
+ &Logic::fnArrived,
+ &Logic::fnLeaving,
+ &Logic::fnSetAlternate,
+ &Logic::fnAltSetAlternate,
+ &Logic::fnKillId,
+ &Logic::fnNoHuman,
+ &Logic::fnAddHuman,
+ &Logic::fnAddButtons,
+ &Logic::fnNoButtons,
+ &Logic::fnSetStop,
+ &Logic::fnClearStop,
+ &Logic::fnPointerText,
+ &Logic::fnQuit,
+ &Logic::fnSpeakMe,
+ &Logic::fnSpeakMeDir,
+ &Logic::fnSpeakWait,
+ &Logic::fnSpeakWaitDir,
+ &Logic::fnChooser,
+ &Logic::fnHighlight,
+ &Logic::fnTextKill,
+ &Logic::fnStopMode,
+ &Logic::fnWeWait,
+ &Logic::fnSendSync,
+ &Logic::fnSendFastSync,
+ &Logic::fnSendRequest,
+ &Logic::fnClearRequest,
+ &Logic::fnCheckRequest,
+ &Logic::fnStartMenu,
+ &Logic::fnUnhighlight,
+ &Logic::fnFaceId,
+ &Logic::fnForeground,
+ &Logic::fnBackground,
+ &Logic::fnNewBackground,
+ &Logic::fnSort,
+ &Logic::fnNoSpriteEngine,
+ &Logic::fnNoSpritesA6,
+ &Logic::fnResetId,
+ &Logic::fnToggleGrid,
+ &Logic::fnPause,
+ &Logic::fnRunAnimMod,
+ &Logic::fnSimpleMod,
+ &Logic::fnRunFrames,
+ &Logic::fnAwaitSync,
+ &Logic::fnIncMegaSet,
+ &Logic::fnDecMegaSet,
+ &Logic::fnSetMegaSet,
+ &Logic::fnMoveItems,
+ &Logic::fnNewList,
+ &Logic::fnAskThis,
+ &Logic::fnRandom,
+ &Logic::fnPersonHere,
+ &Logic::fnToggleMouse,
+ &Logic::fnMouseOn,
+ &Logic::fnMouseOff,
+ &Logic::fnFetchX,
+ &Logic::fnFetchY,
+ &Logic::fnTestList,
+ &Logic::fnFetchPlace,
+ &Logic::fnCustomJoey,
+ &Logic::fnSetPalette,
+ &Logic::fnTextModule,
+ &Logic::fnChangeName,
+ &Logic::fnMiniLoad,
+ &Logic::fnFlushBuffers,
+ &Logic::fnFlushChip,
+ &Logic::fnSaveCoods,
+ &Logic::fnPlotGrid,
+ &Logic::fnRemoveGrid,
+ &Logic::fnEyeball,
+ &Logic::fnCursorUp,
+ &Logic::fnLeaveSection,
+ &Logic::fnEnterSection,
+ &Logic::fnRestoreGame,
+ &Logic::fnRestartGame,
+ &Logic::fnNewSwingSeq,
+ &Logic::fnWaitSwingEnd,
+ &Logic::fnSkipIntroCode,
+ &Logic::fnBlankScreen,
+ &Logic::fnPrintCredit,
+ &Logic::fnLookAt,
+ &Logic::fnLincTextModule,
+ &Logic::fnTextKill2,
+ &Logic::fnSetFont,
+ &Logic::fnStartFx,
+ &Logic::fnStopFx,
+ &Logic::fnStartMusic,
+ &Logic::fnStopMusic,
+ &Logic::fnFadeDown,
+ &Logic::fnFadeUp,
+ &Logic::fnQuitToDos,
+ &Logic::fnPauseFx,
+ &Logic::fnUnPauseFx,
+ &Logic::fnPrintf
+ };
+
+ _mcodeTable = mcodeTable;
+}
+
+static const uint32 forwardList1b[] = {
+ JOBS_SPEECH,
+ JOBS_S4,
+ JOBS_ALARMED,
+ JOEY_RECYCLE,
+ SHOUT_SSS,
+ JOEY_MISSION,
+ TRANS_MISSION,
+ SLOT_MISSION,
+ CORNER_MISSION,
+ JOEY_LOGIC,
+ GORDON_SPEECH,
+ JOEY_BUTTON_MISSION,
+ LOB_DAD_SPEECH,
+ LOB_SON_SPEECH,
+ GUARD_SPEECH,
+ MANTRACH_SPEECH,
+ WRECK_SPEECH,
+ ANITA_SPEECH,
+ LAMB_FACTORY,
+ FORE_SPEECH,
+ JOEY_42_MISS,
+ JOEY_JUNCTION_MISS,
+ WELDER_MISSION,
+ JOEY_WELD_MISSION,
+ RADMAN_SPEECH,
+ LINK_7_29,
+ LINK_29_7,
+ LAMB_TO_3,
+ LAMB_TO_2,
+ BURKE_SPEECH,
+ BURKE_1,
+ BURKE_2,
+ DR_BURKE_1,
+ JASON_SPEECH,
+ JOEY_BELLEVUE,
+ ANCHOR_SPEECH,
+ ANCHOR_MISSION,
+ JOEY_PC_MISSION,
+ HOOK_MISSION,
+ TREVOR_SPEECH,
+ JOEY_FACTORY,
+ HELGA_SPEECH,
+ JOEY_HELGA_MISSION,
+ GALL_BELLEVUE,
+ GLASS_MISSION,
+ LAMB_FACT_RETURN,
+ LAMB_LEAVE_GARDEN,
+ LAMB_START_29,
+ LAMB_BELLEVUE,
+ CABLE_MISSION,
+ FOSTER_TOUR,
+ LAMB_TOUR,
+ FOREMAN_LOGIC,
+ LAMB_LEAVE_FACTORY,
+ LAMB_BELL_LOGIC,
+ LAMB_FACT_2,
+ START90,
+ 0,
+ 0,
+ LINK_28_31,
+ LINK_31_28,
+ EXIT_LINC,
+ DEATH_SCRIPT
+};
+
+static uint32 forwardList1b288[] = {
+ JOBS_SPEECH,
+ JOBS_S4,
+ JOBS_ALARMED,
+ JOEY_RECYCLE,
+ SHOUT_SSS,
+ JOEY_MISSION,
+ TRANS_MISSION,
+ SLOT_MISSION,
+ CORNER_MISSION,
+ JOEY_LOGIC,
+ GORDON_SPEECH,
+ JOEY_BUTTON_MISSION,
+ LOB_DAD_SPEECH,
+ LOB_SON_SPEECH,
+ GUARD_SPEECH,
+ 0x68,
+ WRECK_SPEECH,
+ ANITA_SPEECH,
+ LAMB_FACTORY,
+ FORE_SPEECH,
+ JOEY_42_MISS,
+ JOEY_JUNCTION_MISS,
+ WELDER_MISSION,
+ JOEY_WELD_MISSION,
+ RADMAN_SPEECH,
+ LINK_7_29,
+ LINK_29_7,
+ LAMB_TO_3,
+ LAMB_TO_2,
+ 0x3147,
+ 0x3100,
+ 0x3101,
+ 0x3102,
+ 0x3148,
+ 0x3149,
+ 0x314A,
+ 0x30C5,
+ 0x30C6,
+ 0x30CB,
+ 0x314B,
+ JOEY_FACTORY,
+ 0x314C,
+ 0x30E2,
+ 0x314D,
+ 0x310C,
+ LAMB_FACT_RETURN,
+ 0x3139,
+ 0x313A,
+ 0x004F,
+ CABLE_MISSION,
+ FOSTER_TOUR,
+ LAMB_TOUR,
+ FOREMAN_LOGIC,
+ LAMB_LEAVE_FACTORY,
+ 0x3138,
+ LAMB_FACT_2,
+ 0x004D,
+ 0,
+ 0,
+ LINK_28_31,
+ LINK_31_28,
+ 0x004E,
+ DEATH_SCRIPT
+};
+
+static const uint32 forwardList2b[] = {
+ STD_ON,
+ STD_EXIT_LEFT_ON,
+ STD_EXIT_RIGHT_ON,
+ ADVISOR_188,
+ SHOUT_ACTION,
+ MEGA_CLICK,
+ MEGA_ACTION
+};
+
+static const uint32 forwardList3b[] = {
+ DANI_SPEECH,
+ DANIELLE_GO_HOME,
+ SPUNKY_GO_HOME,
+ HENRI_SPEECH,
+ BUZZER_SPEECH,
+ FOSTER_VISIT_DANI,
+ DANIELLE_LOGIC,
+ JUKEBOX_SPEECH,
+ VINCENT_SPEECH,
+ EDDIE_SPEECH,
+ BLUNT_SPEECH,
+ DANI_ANSWER_PHONE,
+ SPUNKY_SEE_VIDEO,
+ SPUNKY_BARK_AT_FOSTER,
+ SPUNKY_SMELLS_FOOD,
+ BARRY_SPEECH,
+ COLSTON_SPEECH,
+ GALL_SPEECH,
+ BABS_SPEECH,
+ CHUTNEY_SPEECH,
+ FOSTER_ENTER_COURT
+};
+
+static const uint32 forwardList4b[] = {
+ WALTER_SPEECH,
+ JOEY_MEDIC,
+ JOEY_MED_LOGIC,
+ JOEY_MED_MISSION72,
+ KEN_LOGIC,
+ KEN_SPEECH,
+ KEN_MISSION_HAND,
+ SC70_IRIS_OPENED,
+ SC70_IRIS_CLOSED,
+ FOSTER_ENTER_BOARDROOM,
+ BORED_ROOM,
+ FOSTER_ENTER_NEW_BOARDROOM,
+ HOBS_END,
+ SC82_JOBS_SSS
+};
+
+static const uint32 forwardList5b[] = {
+ SET_UP_INFO_WINDOW,
+ SLAB_ON,
+ UP_MOUSE,
+ DOWN_MOUSE,
+ LEFT_MOUSE,
+ RIGHT_MOUSE,
+ DISCONNECT_FOSTER
+};
+
+void Logic::fnExec(uint16 num, uint32 a, uint32 b, uint32 c) {
+ (this->*_mcodeTable[num])(a, b, c);
+}
+
+void Logic::initScriptVariables() {
+ for (int i = 0; i < ARRAYSIZE(_scriptVariables); i++)
+ _scriptVariables[i] = 0;
+
+ _scriptVariables[LOGIC_LIST_NO] = 141;
+ _scriptVariables[LAMB_GREET] = 62;
+ _scriptVariables[JOEY_SECTION] = 1;
+ _scriptVariables[LAMB_SECTION] = 2;
+ _scriptVariables[S15_FLOOR] = 8371;
+ _scriptVariables[GUARDIAN_THERE] = 1;
+ _scriptVariables[DOOR_67_68_FLAG] = 1;
+ _scriptVariables[SC70_IRIS_FLAG] = 3;
+ _scriptVariables[DOOR_73_75_FLAG] = 1;
+ _scriptVariables[SC76_CABINET1_FLAG] = 1;
+ _scriptVariables[SC76_CABINET2_FLAG] = 1;
+ _scriptVariables[SC76_CABINET3_FLAG] = 1;
+ _scriptVariables[DOOR_77_78_FLAG] = 1;
+ _scriptVariables[SC80_EXIT_FLAG] = 1;
+ _scriptVariables[SC31_LIFT_FLAG] = 1;
+ _scriptVariables[SC32_LIFT_FLAG] = 1;
+ _scriptVariables[SC33_SHED_DOOR_FLAG] = 1;
+ _scriptVariables[BAND_PLAYING] = 1;
+ _scriptVariables[COLSTON_AT_TABLE] = 1;
+ _scriptVariables[SC36_NEXT_DEALER] = 16731;
+ _scriptVariables[SC36_DOOR_FLAG] = 1;
+ _scriptVariables[SC37_DOOR_FLAG] = 2;
+ _scriptVariables[SC40_LOCKER_1_FLAG] = 1;
+ _scriptVariables[SC40_LOCKER_2_FLAG] = 1;
+ _scriptVariables[SC40_LOCKER_3_FLAG] = 1;
+ _scriptVariables[SC40_LOCKER_4_FLAG] = 1;
+ _scriptVariables[SC40_LOCKER_5_FLAG] = 1;
+
+ if (SkyEngine::_systemVars.gameVersion == 288)
+ memcpy(_scriptVariables + 352, forwardList1b288, sizeof(forwardList1b288));
+ else
+ memcpy(_scriptVariables + 352, forwardList1b, sizeof(forwardList1b));
+
+ memcpy(_scriptVariables + 656, forwardList2b, sizeof(forwardList2b));
+ memcpy(_scriptVariables + 721, forwardList3b, sizeof(forwardList3b));
+ memcpy(_scriptVariables + 663, forwardList4b, sizeof(forwardList4b));
+ memcpy(_scriptVariables + 505, forwardList5b, sizeof(forwardList5b));
+}
+
+uint16 Logic::mouseScript(uint32 scrNum, Compact *scriptComp) {
+
+ Compact *tmpComp = _compact;
+ _compact = scriptComp;
+ uint16 retVal = script((uint16)(scrNum & 0xFFFF), (uint16)(scrNum >> 16));
+ _compact = tmpComp;
+ return retVal;
+}
+
+/**
+ * This is the actual script engine. It interprets script \a scriptNo starting at \a offset
+ *
+ * @param scriptNo The script to interpret.
+ * @arg Bits 0-11 - Script number
+ * @arg Bits 12-15 - Module number
+ * @param offset At which offset to start interpreting the script.
+ *
+ * @return 0 if script finished. Else offset where to continue.
+ */
+uint16 Logic::script(uint16 scriptNo, uint16 offset) {
+script:
+ /// process a script
+ /// low level interface to interpreter
+
+ uint16 moduleNo = scriptNo >> 12;
+ debug(3, "Doing Script %x", (offset << 16) | scriptNo);
+ uint16 *scriptData = _moduleList[moduleNo]; // get module address
+
+ if (!scriptData) { // We need to load the script module
+ _moduleList[moduleNo] = _skyDisk->loadScriptFile(moduleNo + F_MODULE_0);
+ scriptData = _moduleList[moduleNo]; // module has been loaded
+ }
+
+ uint16 *moduleStart = scriptData;
+
+ // Check whether we have an offset or what
+ if (offset)
+ scriptData = moduleStart + offset;
+ else
+ scriptData += scriptData[scriptNo & 0x0fff];
+
+ uint32 a = 0, b = 0, c = 0;
+ uint16 command, s;
+
+ for (;;) {
+ command = *scriptData++; // get a command
+ Debug::script(command, scriptData);
+
+ switch (command) {
+ case 0: // push_variable
+ push( _scriptVariables[*scriptData++ / 4] );
+ break;
+ case 1: // less_than
+ a = pop();
+ b = pop();
+ if (a > b)
+ push(1);
+ else
+ push(0);
+ break;
+ case 2: // push_number
+ push(*scriptData++);
+ break;
+ case 3: // not_equal
+ a = pop();
+ b = pop();
+ if (a != b)
+ push(1);
+ else
+ push(0);
+ break;
+ case 4: // if_and
+ a = pop();
+ b = pop();
+ if (a && b)
+ push(1);
+ else
+ push(0);
+ break;
+ case 5: // skip_zero
+ s = *scriptData++;
+
+ a = pop();
+ if (!a)
+ scriptData += s / 2;
+ break;
+ case 6: // pop_var
+ b = _scriptVariables[*scriptData++ / 4] = pop();
+ break;
+ case 7: // minus
+ a = pop();
+ b = pop();
+ push(b-a);
+ break;
+ case 8: // plus
+ a = pop();
+ b = pop();
+ push(b+a);
+ break;
+ case 9: // skip_always
+ s = *scriptData++;
+ scriptData += s / 2;
+ break;
+ case 10: // if_or
+ a = pop();
+ b = pop();
+ if (a || b)
+ push(1);
+ else
+ push(0);
+ break;
+ case 11: // call_mcode
+ {
+ a = *scriptData++;
+ assert(a <= 3);
+ // No, I did not forget the "break"s
+ switch (a) {
+ case 3:
+ c = pop();
+ case 2:
+ b = pop();
+ case 1:
+ a = pop();
+ }
+
+ uint16 mcode = *scriptData++ / 4; // get mcode number
+ Debug::mcode(mcode, a, b, c);
+
+ Compact *saveCpt = _compact;
+ bool ret = (this->*_mcodeTable[mcode]) (a, b, c);
+ _compact = saveCpt;
+
+ if (!ret)
+ return (scriptData - moduleStart);
+ }
+ break;
+ case 12: // more_than
+ a = pop();
+ b = pop();
+ if (a < b)
+ push(1);
+ else
+ push(0);
+ break;
+ case 14: // switch
+ c = s = *scriptData++; // get number of cases
+
+ a = pop(); // and value to switch on
+
+ do {
+ if (a == *scriptData) {
+ scriptData += scriptData[1] / 2;
+ scriptData++;
+ break;
+ }
+ scriptData += 2;
+ } while (--s);
+
+ if (s == 0)
+ scriptData += *scriptData / 2; // use the default
+ break;
+ case 15: // push_offset
+ push( *(uint16 *)_skyCompact->getCompactElem(_compact, *scriptData++) );
+ break;
+ case 16: // pop_offset
+ // pop a value into a compact
+ *(uint16 *)_skyCompact->getCompactElem(_compact, *scriptData++) = (uint16)pop();
+ break;
+ case 17: // is_equal
+ a = pop();
+ b = pop();
+ if (a == b)
+ push(1);
+ else
+ push(0);
+ break;
+ case 18: { // skip_nz
+ int16 t = *scriptData++;
+ a = pop();
+ if (a)
+ scriptData += t / 2;
+ break;
+ }
+ case 13:
+ case 19: // script_exit
+ return 0;
+ case 20: // restart_script
+ offset = 0;
+ goto script;
+ default:
+ error("Unknown script command: %d", command);
+ }
+ }
+}
+
+bool Logic::fnCacheChip(uint32 a, uint32 b, uint32 c) {
+ _skySound->fnStopFx();
+ _skyDisk->fnCacheChip((uint16*)_skyCompact->fetchCpt((uint16)a));
+ return true;
+}
+
+bool Logic::fnCacheFast(uint32 a, uint32 b, uint32 c) {
+ _skyDisk->fnCacheFast((uint16*)_skyCompact->fetchCpt((uint16)a));
+ return true;
+}
+
+bool Logic::fnDrawScreen(uint32 a, uint32 b, uint32 c) {
+ debug(5, "Call: fnDrawScreen(%X, %X)",a,b);
+ SkyEngine::_systemVars.currentPalette = a;
+ _skyScreen->fnDrawScreen(a, b);
+
+ if (Logic::_scriptVariables[SCREEN] == 32) {
+ /* workaround for script bug #786482
+ Under certain circumstances, which never got completely cleared,
+ the gardener can get stuck in an animation, waiting for a sync
+ signal from foster.
+ This is most probably caused by foster leaving the screen before
+ sending the sync.
+ To work around that, we simply send a sync to the gardener every time
+ we enter the screen. If he isn't stuck (and thus not waiting for sync)
+ it will be ignored anyways */
+
+ debug(1, "sending gardener sync");
+ fnSendSync(ID_SC32_GARDENER, 1, 0);
+ }
+ return true;
+}
+
+bool Logic::fnAr(uint32 x, uint32 y, uint32 c) {
+ _compact->downFlag = 1; // assume failure in-case logic is interupted by speech (esp Joey)
+
+ _compact->arTargetX = (uint16)x;
+ _compact->arTargetY = (uint16)y;
+ _compact->logic = L_AR; // Set to AR mode
+
+ _compact->xcood &= 0xfff8;
+ _compact->ycood &= 0xfff8;
+
+ return false; // drop out of script
+}
+
+bool Logic::fnArAnimate(uint32 a, uint32 b, uint32 c) {
+ _compact->mood = 0; // high level 'not stood still'
+ _compact->logic = L_AR_ANIM;
+ return false; // drop out of script
+}
+
+bool Logic::fnIdle(uint32 a, uint32 b, uint32 c) {
+ // set the player idling
+ _compact->logic = 0;
+ return true;
+}
+
+bool Logic::fnInteract(uint32 targetId, uint32 b, uint32 c) {
+ _compact->mode += 4; // next level up
+ _compact->logic = L_SCRIPT;
+ Compact *cpt = _skyCompact->fetchCpt(targetId);
+
+ *SkyCompact::getSub(_compact, _compact->mode) = cpt->actionScript;
+ *SkyCompact::getSub(_compact, _compact->mode + 2) = 0;
+
+ return false;
+}
+
+bool Logic::fnStartSub(uint32 scr, uint32 b, uint32 c) {
+ _compact->mode += 4;
+ *SkyCompact::getSub(_compact, _compact->mode) = (uint16)(scr & 0xffff);
+ *SkyCompact::getSub(_compact, _compact->mode + 2) = (uint16)(scr >> 16);
+ return false;
+}
+
+bool Logic::fnTheyStartSub(uint32 mega, uint32 scr, uint32 c) {
+ Compact *cpt = _skyCompact->fetchCpt(mega);
+ cpt->mode += 4;
+ *SkyCompact::getSub(cpt, cpt->mode) = (uint16)(scr & 0xffff);
+ *SkyCompact::getSub(cpt, cpt->mode + 2) = (uint16)(scr >> 16);
+ return true;
+}
+
+bool Logic::fnAssignBase(uint32 id, uint32 scr, uint32 c) {
+ Compact *cpt = _skyCompact->fetchCpt(id);
+ cpt->mode = C_BASE_MODE;
+ cpt->logic = L_SCRIPT;
+ cpt->baseSub = (uint16)(scr & 0xffff);
+ cpt->baseSub_off = (uint16)(scr >> 16);
+ return true;
+}
+
+bool Logic::fnDiskMouse(uint32 a, uint32 b, uint32 c) {
+ _skyMouse->spriteMouse(MOUSE_DISK, 11, 11);
+ return true;
+}
+
+bool Logic::fnNormalMouse(uint32 a, uint32 b, uint32 c) {
+ _skyMouse->spriteMouse(MOUSE_NORMAL, 0, 0);
+ return true;
+}
+
+bool Logic::fnBlankMouse(uint32 a, uint32 b, uint32 c) {
+ _skyMouse->spriteMouse(MOUSE_BLANK, 0, 0);
+ return true;
+}
+
+bool Logic::fnCrossMouse(uint32 a, uint32 b, uint32 c) {
+ if (_scriptVariables[OBJECT_HELD])
+ _skyMouse->fnOpenCloseHand(false);
+ else
+ _skyMouse->spriteMouse(MOUSE_CROSS, 4, 4);
+ return true;
+}
+
+bool Logic::fnCursorRight(uint32 a, uint32 b, uint32 c) {
+ _skyMouse->spriteMouse(MOUSE_RIGHT, 9, 4);
+ return true;
+}
+
+bool Logic::fnCursorLeft(uint32 a, uint32 b, uint32 c) {
+ _skyMouse->spriteMouse(MOUSE_LEFT, 0, 5);
+ return true;
+}
+
+bool Logic::fnCursorDown(uint32 a, uint32 b, uint32 c) {
+ _skyMouse->spriteMouse(MOUSE_DOWN, 9, 4);
+ return true;
+}
+
+bool Logic::fnCursorUp(uint32 a, uint32 b, uint32 c) {
+ _skyMouse->spriteMouse(MOUSE_UP, 9, 4);
+ return true;
+}
+
+bool Logic::fnOpenHand(uint32 a, uint32 b, uint32 c) {
+ _skyMouse->fnOpenCloseHand(true);
+ return true;
+}
+
+bool Logic::fnCloseHand(uint32 a, uint32 b, uint32 c) {
+ _skyMouse->fnOpenCloseHand(false);
+ return true;
+}
+
+bool Logic::fnGetTo(uint32 targetPlaceId, uint32 mode, uint32 c) {
+ _compact->upFlag = (uint16)mode; // save mode for action script
+ _compact->mode += 4; // next level up
+ Compact *cpt = _skyCompact->fetchCpt(_compact->place);
+ if (!cpt) {
+ warning("can't find _compact's getToTable. Place compact is NULL");
+ return false;
+ }
+ uint16 *getToTable = (uint16*)_skyCompact->fetchCpt(cpt->getToTableId);
+ if (!getToTable) {
+ warning("Place compact's getToTable is NULL!");
+ return false;
+ }
+
+ while (*getToTable != targetPlaceId)
+ getToTable += 2;
+
+ // get new script
+ *SkyCompact::getSub(_compact, _compact->mode) = *(getToTable + 1);
+ *SkyCompact::getSub(_compact, _compact->mode + 2) = 0;
+
+ return false; // drop out of script
+}
+
+bool Logic::fnSetToStand(uint32 a, uint32 b, uint32 c) {
+ _compact->mood = 1; // high level stood still
+
+ _compact->grafixProgId = *(uint16*)_skyCompact->getCompactElem(_compact, C_STAND_UP + _compact->megaSet + _compact->dir * 4);
+ _compact->grafixProgPos = 0;
+
+ uint16 *standList = _skyCompact->getGrafixPtr(_compact);
+
+ _compact->offset = *standList; // get frames offset
+ _compact->logic = L_SIMPLE_MOD;
+ _compact->grafixProgPos++;
+ simpleAnim();
+ return false; // drop out of script
+}
+
+bool Logic::fnTurnTo(uint32 dir, uint32 b, uint32 c) {
+ /// turn compact to direction dir
+
+ uint16 curDir = _compact->dir; // get current direction
+ _compact->dir = (uint16)(dir & 0xffff); // set new direction
+
+ uint16 *tt = _skyCompact->getTurnTable(_compact, curDir);
+
+ if (!tt[dir])
+ return true; // keep going
+
+ _compact->turnProgId = tt[dir]; // put turn program in
+ _compact->turnProgPos = 0;
+ _compact->logic = L_TURNING;
+
+ turn();
+
+ return false; // drop out of script
+}
+
+bool Logic::fnArrived(uint32 scriptVar, uint32 b, uint32 c) {
+ _compact->leaving = (uint16)(scriptVar & 0xffff);
+ _scriptVariables[scriptVar/4]++;
+ return true;
+}
+
+bool Logic::fnLeaving(uint32 a, uint32 b, uint32 c) {
+ _compact->atWatch = 0;
+
+ if (_compact->leaving) {
+ _scriptVariables[_compact->leaving/4]--;
+ _compact->leaving = 0; // I shall do this only once
+ }
+
+ return true; // keep going
+}
+
+bool Logic::fnSetAlternate(uint32 scr, uint32 b, uint32 c) {
+ _compact->alt = (uint16)(scr & 0xffff);
+ _compact->logic = L_ALT;
+ return false;
+}
+
+bool Logic::fnAltSetAlternate(uint32 target, uint32 scr, uint32 c) {
+ Compact *cpt = _skyCompact->fetchCpt(target);
+ cpt->alt = (uint16)(scr & 0xffff);
+ cpt->logic = L_ALT;
+ return false;
+}
+
+bool Logic::fnKillId(uint32 id, uint32 b, uint32 c) {
+ if (id) {
+ Compact *cpt = _skyCompact->fetchCpt(id);
+ if (cpt->status & (1 << 7))
+ _skyGrid->removeObjectFromWalk(cpt);
+ cpt->status = 0;
+ }
+ return true;
+}
+
+bool Logic::fnNoHuman(uint32 a, uint32 b, uint32 c) {
+ if (!_scriptVariables[MOUSE_STOP]) {
+ _scriptVariables[MOUSE_STATUS] &= 1;
+ runGetOff();
+ fnBlankMouse(0, 0, 0);
+ }
+ return true;
+}
+
+bool Logic::fnAddHuman(uint32 a, uint32 b, uint32 c) {
+ return _skyMouse->fnAddHuman();
+}
+
+bool Logic::fnAddButtons(uint32 a, uint32 b, uint32 c) {
+ _scriptVariables[MOUSE_STATUS] |= 4;
+ return true;
+}
+
+bool Logic::fnNoButtons(uint32 a, uint32 b, uint32 c) {
+ //remove the mouse buttons
+ _scriptVariables[MOUSE_STATUS] &= 0xFFFFFFFB;
+ return true;
+}
+
+bool Logic::fnSetStop(uint32 a, uint32 b, uint32 c) {
+ _scriptVariables[MOUSE_STOP] |= 1;
+ return true;
+}
+
+bool Logic::fnClearStop(uint32 a, uint32 b, uint32 c) {
+ _scriptVariables[MOUSE_STOP] = 0;
+ return true;
+}
+
+bool Logic::fnPointerText(uint32 a, uint32 b, uint32 c) {
+ _skyText->fnPointerText(a, _skyMouse->giveMouseX(), _skyMouse->giveMouseY());
+ return true;
+}
+
+bool Logic::fnQuit(uint32 a, uint32 b, uint32 c) {
+ return false;
+}
+
+bool Logic::fnSpeakMe(uint32 targetId, uint32 mesgNum, uint32 animNum) {
+ stdSpeak(_skyCompact->fetchCpt(targetId), mesgNum, animNum, 0);
+ return false; //drop out of script
+}
+
+bool Logic::fnSpeakMeDir(uint32 targetId, uint32 mesgNum, uint32 animNum) {
+ //must be player so don't cause script to drop out
+ //this function sets the directional option whereby
+ //the anim chosen is linked to c_dir
+ animNum += _compact->dir << 1; //2 sizes (large and small)
+ return fnSpeakMe(targetId, mesgNum, animNum);
+}
+
+bool Logic::fnSpeakWait(uint32 id, uint32 message, uint32 animation) {
+ // non player mega char speaks
+ // player will wait for it to finish before continuing script processing
+ _compact->flag = (uint16)(id & 0xffff);
+ _compact->logic = L_LISTEN;
+ return fnSpeakMe(id, message, animation);
+}
+
+bool Logic::fnSpeakWaitDir(uint32 a, uint32 b, uint32 c) {
+ /* non player mega chr$ speaks S2(20Jan93tw)
+ the player will wait for it to finish
+ before continuing script processing
+ this function sets the directional option whereby
+ the anim chosen is linked to c_dir -
+
+ _compact is player
+ a is ID to speak (not us)
+ b is text message number
+ c is base of mini table within anim_talk_table */
+
+#ifdef __DC__
+ __builtin_alloca(4); // Works around a gcc bug (wrong-code/11736)
+#endif
+
+ _compact->flag = (uint16)a;
+ _compact->logic = L_LISTEN;
+
+ Compact *speaker = _skyCompact->fetchCpt(a);
+ if (c) {
+ c += speaker->dir << 1;
+ stdSpeak(speaker, b, c, speaker->dir << 1);
+ } else
+ stdSpeak(speaker, b, c, 0);
+
+ return false;
+}
+
+bool Logic::fnChooser(uint32 a, uint32 b, uint32 c) {
+
+ // setup the text questions to be clicked on
+ // read from TEXT1 until 0
+
+ SkyEngine::_systemVars.systemFlags |= SF_CHOOSING; // can't save/restore while choosing
+
+ _scriptVariables[THE_CHOSEN_ONE] = 0; // clear result
+
+ uint32 *p = _scriptVariables + TEXT1;
+ uint16 ycood = TOP_LEFT_Y; // rolling coordinate
+
+ while (*p) {
+ uint32 textNum = *p++;
+
+ struct lowTextManager_t lowText = _skyText->lowTextManager(textNum, GAME_SCREEN_WIDTH, 0, 241, 0);
+
+ uint8 *data = lowText.textData;
+
+ // stipple the text
+
+ uint32 size = ((dataFileHeader *)data)->s_height * ((dataFileHeader *)data)->s_width;
+ uint32 index = 0;
+ uint32 width = ((dataFileHeader *)data)->s_width;
+
+ data += sizeof(dataFileHeader);
+
+ while (index < size) {
+ if (index % width <= 1)
+ index ^= 1; //index++;
+ if (!data[index])
+ data[index] = 1;
+ index += 2;
+ }
+
+ Compact *textCompact = _skyCompact->fetchCpt(lowText.compactNum);
+
+ textCompact->getToFlag = (uint16)textNum;
+ textCompact->downFlag = (uint16)*p++; // get animation number
+
+ textCompact->status |= ST_MOUSE; // mouse detects
+
+ textCompact->xcood = TOP_LEFT_X; // set coordinates
+ textCompact->ycood = ycood;
+ ycood += 12;
+ }
+
+ if (p == _scriptVariables + TEXT1)
+ return true;
+
+ _compact->logic = L_CHOOSE; // player frozen until choice made
+ fnAddHuman(0, 0, 0); // bring back mouse
+
+ return false;
+}
+
+bool Logic::fnHighlight(uint32 itemNo, uint32 pen, uint32 c) {
+ pen -= 11;
+ pen ^= 1;
+ pen += 241;
+ Compact *textCompact = _skyCompact->fetchCpt(itemNo);
+ uint8 *sprData = (uint8 *)SkyEngine::fetchItem(textCompact->flag);
+ _skyText->changeTextSpriteColour(sprData, (uint8)pen);
+ return true;
+}
+
+bool Logic::fnTextKill(uint32 a, uint32 b, uint32 c) {
+ /// Kill of text items that are mouse detectable
+
+ uint32 id = FIRST_TEXT_COMPACT;
+
+ for (int i = 10; i > 0; i--) {
+ Compact *cpt = _skyCompact->fetchCpt(id);
+ if (cpt->status & (1 << 4))
+ cpt->status = 0;
+ id++;
+ }
+ return true;
+}
+
+bool Logic::fnStopMode(uint32 a, uint32 b, uint32 c) {
+ _compact->logic = L_STOPPED;
+ return false;
+}
+
+bool Logic::fnWeWait(uint32 id, uint32 b, uint32 c) {
+ /// We have hit another mega
+ /// we are going to wait for it to move
+
+ _compact->waitingFor = (uint16) id;
+ stopAndWait();
+ return true; // not sure about this
+}
+
+bool Logic::fnSendSync(uint32 mega, uint32 sync, uint32 c) {
+ Compact *cpt = _skyCompact->fetchCpt(mega);
+ cpt->sync = (uint16)(sync & 0xffff);
+ return false;
+}
+
+bool Logic::fnSendFastSync(uint32 mega, uint32 sync, uint32 c) {
+ Compact *cpt = _skyCompact->fetchCpt(mega);
+ cpt->sync = (uint16)(sync & 0xffff);
+ return true;
+}
+
+bool Logic::fnSendRequest(uint32 target, uint32 scr, uint32 c) {
+ Compact *cpt = _skyCompact->fetchCpt(target);
+ cpt->request = (uint16)(scr & 0xffff);
+ return false;
+}
+
+bool Logic::fnClearRequest(uint32 target, uint32 b, uint32 c) {
+ Compact *cpt = _skyCompact->fetchCpt(target);
+ cpt->request = 0;
+ return true;
+}
+
+bool Logic::fnCheckRequest(uint32 a, uint32 b, uint32 c) {
+ /// check for interaction request
+
+ if (!_compact->request)
+ return true;
+
+ _compact->mode = C_ACTION_MODE; // into action mode
+
+ _compact->actionSub = _compact->request;
+ _compact->actionSub_off = 0;
+
+ _compact->request = 0; // trash request
+ return false; // drop from script
+}
+
+bool Logic::fnStartMenu(uint32 firstObject, uint32 b, uint32 c) {
+ /// initialise the top menu bar
+ // firstObject is o0 for game menu, k0 for linc
+
+ uint i;
+ firstObject /= 4;
+
+ // (1) FIRST, SET UP THE 2 ARROWS SO THEY APPEAR ON SCREEN
+
+ Compact *cpt = _skyCompact->fetchCpt(47);
+ cpt->status = ST_MOUSE + ST_FOREGROUND + ST_LOGIC + ST_RECREATE;
+ cpt->screen = (uint16)(_scriptVariables[SCREEN] & 0xffff);
+
+ cpt = _skyCompact->fetchCpt(48);
+ cpt->status = ST_MOUSE + ST_FOREGROUND + ST_LOGIC + ST_RECREATE;
+ cpt->screen = (uint16)(_scriptVariables[SCREEN] & 0xffff);
+
+ // (2) COPY OBJECTS FROM NON-ZERO INVENTORY VARIABLES INTO OBJECT DISPLAY LIST (& COUNT THEM)
+
+ // sort the objects and pad with blanks
+
+ uint32 menuLength = 0;
+ for (i = firstObject; i < firstObject + ARRAYSIZE(_objectList); i++) {
+ if ( _scriptVariables[i] )
+ _objectList[menuLength++] = _scriptVariables[i];
+ }
+ _scriptVariables[MENU_LENGTH] = menuLength;
+
+ // (3) OK, NOW TOP UP THE LIST WITH THE REQUIRED NO. OF BLANK OBJECTS (for min display length 11)
+
+ uint32 blankID = 51;
+ for (i = menuLength; i < 11; i++)
+ _objectList[i] = blankID++;
+
+ // (4) KILL ID's OF ALL 20 OBJECTS SO UNWANTED ICONS (SCROLLED OFF) DON'T REMAIN ON SCREEN
+ // (There should be a better way of doing this - only kill id of 12th item when menu has scrolled right)
+
+ for (i = 0; i < ARRAYSIZE(_objectList); i++) {
+ if (_objectList[i])
+ (_skyCompact->fetchCpt(_objectList[i]))->status = ST_LOGIC;
+ else break;
+ }
+
+ // (5) NOW FIND OUT WHICH OBJECT TO START THE DISPLAY FROM (depending on scroll offset)
+
+ if (menuLength < 11) // check we can scroll
+ _scriptVariables[SCROLL_OFFSET] = 0;
+ else if (menuLength < _scriptVariables[SCROLL_OFFSET] + 11)
+ _scriptVariables[SCROLL_OFFSET] = menuLength - 11;
+
+ // (6) AND FINALLY, INITIALISE THE 11 OBJECTS SO THEY APPEAR ON SCREEEN
+
+ uint16 rollingX = TOP_LEFT_X + 28;
+ for (i = 0; i < 11; i++) {
+ cpt = _skyCompact->fetchCpt(
+ _objectList[_scriptVariables[SCROLL_OFFSET] + i]);
+
+ cpt->status = ST_MOUSE + ST_FOREGROUND + ST_LOGIC + ST_RECREATE;
+ cpt->screen = (uint16)(_scriptVariables[SCREEN] & 0xffff);
+
+ cpt->xcood = rollingX;
+ rollingX += 24;
+
+ if (_scriptVariables[MENU] == 2)
+ cpt->ycood = 136;
+ else
+ cpt->ycood = 112;
+ }
+
+ return true;
+}
+
+bool Logic::fnUnhighlight(uint32 item, uint32 b, uint32 c) {
+ Compact *cpt = _skyCompact->fetchCpt(item);
+ cpt->frame--;
+ cpt->getToFlag = 0;
+ return true;
+}
+
+bool Logic::fnFaceId(uint32 otherId, uint32 b, uint32 c) {
+ /// return the direction to turn to face another id
+ /// pass back result in c_just_flag
+
+ Compact *cpt = _skyCompact->fetchCpt(otherId);
+
+ int16 x = _compact->xcood - cpt->xcood;
+
+ if (x < 0) { // we're to the left
+ x = -x;
+ _compact->getToFlag = 3;
+ } else { // it's to the left
+ _compact->getToFlag = 2;
+ }
+
+ // now check y
+
+ // we must find the true bottom of the sprite
+ // it is not enough to use y coord because changing
+ // sprite offsets can ruin the formula - instead we
+ // will use the bottom of the mouse collision area
+
+ int16 y = _compact->ycood - (cpt->ycood + cpt->mouseRelY + cpt->mouseSizeY);
+
+ if (y < 0) { // it's below
+ y = -y;
+ if (y >= x)
+ _compact->getToFlag = 1;
+ } else { // it's above
+ if (y >= x)
+ _compact->getToFlag = 0;
+ }
+ return true;
+}
+
+bool Logic::fnForeground(uint32 sprite, uint32 b, uint32 c) {
+ /// Make sprite a foreground sprite
+ Compact *cpt = _skyCompact->fetchCpt(sprite);
+ cpt->status &= 0xfff8;
+ cpt->status |= ST_FOREGROUND;
+ return true;
+}
+
+bool Logic::fnBackground(uint32 a, uint32 b, uint32 c) {
+ /// Make us a background sprite
+ _compact->status &= 0xfff8;
+ _compact->status |= ST_BACKGROUND;
+ return true;
+}
+
+bool Logic::fnNewBackground(uint32 sprite, uint32 b, uint32 c) {
+ /// Make sprite a background sprite
+ Compact *cpt = _skyCompact->fetchCpt(sprite);
+ cpt->status &= 0xfff8;
+ cpt->status |= ST_BACKGROUND;
+ return true;
+}
+
+bool Logic::fnSort(uint32 mega, uint32 b, uint32 c) {
+ Compact *cpt = _skyCompact->fetchCpt(mega);
+ cpt->status &= 0xfff8;
+ cpt->status |= ST_SORT;
+ return true;
+}
+
+bool Logic::fnNoSpriteEngine(uint32 a, uint32 b, uint32 c) {
+ /// stop the compact printing
+ /// remove foreground, background & sort
+ _compact->status &= 0xfff8;
+ return true;
+}
+
+bool Logic::fnNoSpritesA6(uint32 us, uint32 b, uint32 c) {
+ /// stop the compact printing
+ /// remove foreground, background & sort
+ Compact *cpt = _skyCompact->fetchCpt(us);
+ cpt->status &= 0xfff8;
+ return true;
+}
+
+bool Logic::fnResetId(uint32 id, uint32 resetBlock, uint32 c) {
+ /// used when a mega is to be restarted
+ /// eg - when a smaller mega turn to larger
+ /// - a mega changes rooms...
+
+ Compact *cpt = _skyCompact->fetchCpt(id);
+ uint16 *rst = (uint16 *)_skyCompact->fetchCpt(resetBlock);
+
+ if (!cpt) {
+ warning("fnResetId(): Compact %d (id) == NULL", id);
+ return true;
+ }
+ if (!rst) {
+ warning("fnResetId(): Compact %d (resetBlock) == NULL", resetBlock);
+ return true;
+ }
+
+ uint16 off;
+ while ((off = *rst++) != 0xffff)
+ *(uint16 *)_skyCompact->getCompactElem(cpt, off) = *rst++;
+ return true;
+}
+
+bool Logic::fnToggleGrid(uint32 a, uint32 b, uint32 c) {
+ /// Toggle a mega's grid plotting
+ _compact->status ^= ST_GRID_PLOT;
+ return true;
+}
+
+bool Logic::fnPause(uint32 cycles, uint32 b, uint32 c) {
+ /// Set mega to L_PAUSE
+ _compact->flag = (uint16)(cycles & 0xffff);
+ _compact->logic = L_PAUSE;
+ return false; // drop out of script
+}
+
+bool Logic::fnRunAnimMod(uint32 animNo, uint32 b, uint32 c) {
+ _compact->grafixProgId = animNo;
+ _compact->grafixProgPos = 0;
+
+ _compact->offset = *_skyCompact->getGrafixPtr(_compact);
+ _compact->grafixProgPos++;
+ _compact->logic = L_MOD_ANIMATE;
+ anim();
+ return false; // drop from script
+}
+
+bool Logic::fnSimpleMod(uint32 animSeqNo, uint32 b, uint32 c) {
+ _compact->grafixProgId = animSeqNo;
+ _compact->grafixProgPos = 0;
+
+ _compact->logic = L_SIMPLE_MOD;
+ _compact->offset = *_skyCompact->getGrafixPtr(_compact);
+ _compact->grafixProgPos++;
+ simpleAnim();
+ return false;
+}
+
+bool Logic::fnRunFrames(uint32 sequenceNo, uint32 b, uint32 c) {
+ _compact->grafixProgId = sequenceNo;
+ _compact->grafixProgPos = 0;
+
+ _compact->logic = L_FRAMES;
+ _compact->offset = *_skyCompact->getGrafixPtr(_compact);
+ _compact->grafixProgPos++;
+ simpleAnim();
+ return false;
+}
+
+bool Logic::fnAwaitSync(uint32 a, uint32 b, uint32 c) {
+ if (_compact->sync)
+ return true;
+
+ _compact->logic = L_WAIT_SYNC;
+ return false;
+}
+
+bool Logic::fnIncMegaSet(uint32 a, uint32 b, uint32 c) {
+ _compact->megaSet += NEXT_MEGA_SET;
+ return true;
+}
+
+bool Logic::fnDecMegaSet(uint32 a, uint32 b, uint32 c) {
+ _compact->megaSet -= NEXT_MEGA_SET;
+ return true;
+}
+
+bool Logic::fnSetMegaSet(uint32 mega, uint32 setNo, uint32 c) {
+ Compact *cpt = _skyCompact->fetchCpt(mega);
+ cpt->megaSet = (uint16) (setNo * NEXT_MEGA_SET);
+ return true;
+}
+
+bool Logic::fnMoveItems(uint32 listNo, uint32 screenNo, uint32 c) {
+ // Move a list of id's to another screen
+ uint16 *p = (uint16*)_skyCompact->fetchCpt(CPT_MOVE_LIST);
+ p = (uint16*)_skyCompact->fetchCpt(p[listNo]);
+ for (int i = 0; i < 2; i++) {
+ if (!*p)
+ return true;
+ Compact *cpt = _skyCompact->fetchCpt(*p++);
+ cpt->screen = (uint16)(screenNo & 0xffff);
+ }
+ return true;
+}
+
+bool Logic::fnNewList(uint32 a, uint32 b, uint32 c) {
+ /// Reset the chooser list
+ for (int i = 0; i < 16; i++)
+ _scriptVariables[TEXT1 + i] = 0;
+ return true;
+}
+
+bool Logic::fnAskThis(uint32 textNo, uint32 animNo, uint32 c) {
+ // find first free position
+ uint32 *p = _scriptVariables + TEXT1;
+ while (*p)
+ p += 2;
+ *p++ = textNo;
+ *p = animNo;
+ return true;
+}
+
+bool Logic::fnRandom(uint32 a, uint32 b, uint32 c) {
+ _scriptVariables[RND] = _rnd.getRandomNumber(65536) & a;
+ return true;
+}
+
+bool Logic::fnPersonHere(uint32 id, uint32 room, uint32 c) {
+ Compact *cpt = _skyCompact->fetchCpt(id);
+ _scriptVariables[RESULT] = cpt->screen == room ? 1 : 0;
+ return true;
+}
+
+bool Logic::fnToggleMouse(uint32 a, uint32 b, uint32 c) {
+
+ _skyCompact->fetchCpt(a)->status ^= ST_MOUSE;
+ return true;
+}
+
+bool Logic::fnMouseOn(uint32 a, uint32 b, uint32 c) {
+ //switch on the mouse highlight
+ Compact *cpt = _skyCompact->fetchCpt(a);
+ cpt->status |= ST_MOUSE;
+ return true;
+}
+
+bool Logic::fnMouseOff(uint32 a, uint32 b, uint32 c) {
+ //switch off the mouse highlight
+ Compact *cpt = _skyCompact->fetchCpt(a);
+ cpt->status &= ~ST_MOUSE;
+ return true;
+}
+
+bool Logic::fnFetchX(uint32 id, uint32 b, uint32 c) {
+ Compact *cpt = _skyCompact->fetchCpt(id);
+ _scriptVariables[RESULT] = cpt->xcood;
+ return true;
+}
+
+bool Logic::fnFetchY(uint32 id, uint32 b, uint32 c) {
+ Compact *cpt = _skyCompact->fetchCpt(id);
+ _scriptVariables[RESULT] = cpt->ycood;
+ return true;
+}
+
+bool Logic::fnTestList(uint32 id, uint32 x, uint32 y) {
+ _scriptVariables[RESULT] = 0; // assume fail
+ uint16 *list = (uint16 *)_skyCompact->fetchCpt(id);
+
+ while (*list) {
+ if ((x >= list[0]) && (x < list[1]) && (y >= list[2]) && (y < list[3]))
+ _scriptVariables[RESULT] = list[4];
+ list += 5;
+ }
+ return true;
+}
+
+bool Logic::fnFetchPlace(uint32 id, uint32 b, uint32 c) {
+ Compact *cpt = _skyCompact->fetchCpt(id);
+ _scriptVariables[RESULT] = cpt->place;
+ return true;
+}
+
+bool Logic::fnCustomJoey(uint32 id, uint32 b, uint32 c) {
+ /// return id's x & y coordinate & c_mood (i.e. stood still yes/no)
+ /// used by Joey-Logic - done in code like this because scripts can't
+ /// get access to another megas compact as easily
+
+ Compact *cpt = _skyCompact->fetchCpt(id);
+
+ _scriptVariables[PLAYER_X] = cpt->xcood;
+ _scriptVariables[PLAYER_Y] = cpt->ycood;
+ _scriptVariables[PLAYER_MOOD] = cpt->mood;
+ _scriptVariables[PLAYER_SCREEN] = cpt->screen;
+ return true;
+}
+
+bool Logic::fnSetPalette(uint32 a, uint32 b, uint32 c) {
+ _skyScreen->setPaletteEndian((uint8 *)_skyCompact->fetchCpt(a));
+ SkyEngine::_systemVars.currentPalette = a;
+ return true;
+}
+
+bool Logic::fnTextModule(uint32 a, uint32 b, uint32 c) {
+ _skyText->fnTextModule(a, b);
+ return true;
+}
+
+bool Logic::fnChangeName(uint32 id, uint32 textNo, uint32 c) {
+ Compact *cpt = _skyCompact->fetchCpt(id);
+ cpt->cursorText = (uint16) textNo;
+ return true;
+}
+
+bool Logic::fnMiniLoad(uint32 a, uint32 b, uint32 c) {
+ _skyDisk->fnMiniLoad((uint16)a);
+ return true;
+}
+
+bool Logic::fnFlushBuffers(uint32 a, uint32 b, uint32 c) {
+ _skyDisk->fnFlushBuffers();
+ return true;
+}
+
+bool Logic::fnFlushChip(uint32 a, uint32 b, uint32 c) {
+ // this should be done automatically
+ return true;
+}
+
+bool Logic::fnSaveCoods(uint32 a, uint32 b, uint32 c) {
+ _skyMouse->fnSaveCoods();
+ return true;
+}
+
+bool Logic::fnPlotGrid(uint32 x, uint32 y, uint32 width) {
+ _skyGrid->plotGrid(x, y, width, _compact);
+ return true;
+}
+
+bool Logic::fnRemoveGrid(uint32 x, uint32 y, uint32 width) {
+ _skyGrid->removeGrid(x, y, width, _compact);
+ return true;
+}
+
+bool Logic::fnEyeball(uint32 id, uint32 b, uint32 c) {
+ // set 'result' to frame no. pointing to foster, according to table used
+ // eg. FN_eyeball (id_eye_90_table);
+
+ uint16 *eyeTable = (uint16 *)_skyCompact->fetchCpt(id);
+ Compact *cpt = _skyCompact->fetchCpt(ID_BLUE_FOSTER);
+
+ uint32 x = cpt->xcood; // 168 < x < 416
+ x -= 168;
+ x >>= 3;
+
+ uint32 y = cpt->ycood; // 256 < y < 296
+ y -= 256;
+ y <<= 2;
+
+ _scriptVariables[RESULT] = eyeTable[x + y] + S91;
+ return true;
+}
+
+bool Logic::fnLeaveSection(uint32 sectionNo, uint32 b, uint32 c) {
+ if (SkyEngine::isDemo())
+ _skyControl->showGameQuitMsg();
+
+ if (sectionNo == 5) //linc section - has different mouse icons
+ _skyMouse->replaceMouseCursors(60301);
+
+ return true;
+}
+
+bool Logic::fnEnterSection(uint32 sectionNo, uint32 b, uint32 c) {
+
+ if (SkyEngine::isDemo() && (sectionNo > 2))
+ _skyControl->showGameQuitMsg();
+
+ _scriptVariables[CUR_SECTION] = sectionNo;
+ SkyEngine::_systemVars.currentMusic = 0;
+
+ if (sectionNo == 5) //linc section - has different mouse icons
+ _skyMouse->replaceMouseCursors(60302);
+
+ if ((sectionNo != _currentSection) || (SkyEngine::_systemVars.systemFlags & SF_GAME_RESTORED)) {
+ _currentSection = sectionNo;
+
+ sectionNo++;
+ _skyMusic->loadSection((byte)sectionNo);
+ _skySound->loadSection((byte)sectionNo);
+ _skyGrid->loadGrids();
+ SkyEngine::_systemVars.systemFlags &= ~SF_GAME_RESTORED;
+ }
+
+ return true;
+}
+
+bool Logic::fnRestoreGame(uint32 a, uint32 b, uint32 c) {
+ _skyControl->doLoadSavePanel();
+ return false;
+}
+
+bool Logic::fnRestartGame(uint32 a, uint32 b, uint32 c) {
+ _skyControl->restartGame();
+ return false;
+}
+
+bool Logic::fnNewSwingSeq(uint32 a, uint32 b, uint32 c) {
+ // only certain files work on pc. (huh?! something we should take care of?)
+ if ((a == 85) || (a == 106) || (a == 75) || (a == 15)) {
+ _skyScreen->startSequenceItem((uint16)a);
+ } else {
+ debug(1,"Logic::fnNewSwingSeq: ignored seq %d",a);
+ }
+ return true;
+}
+
+bool Logic::fnWaitSwingEnd(uint32 a, uint32 b, uint32 c) {
+ _skyScreen->waitForSequence();
+ return true;
+}
+
+bool Logic::fnSkipIntroCode(uint32 a, uint32 b, uint32 c) {
+ SkyEngine::_systemVars.pastIntro = true;
+ return true;
+}
+
+bool Logic::fnBlankScreen(uint32 a, uint32 b, uint32 c) {
+ _skyScreen->clearScreen();
+ return true;
+}
+
+bool Logic::fnPrintCredit(uint32 a, uint32 b, uint32 c) {
+
+ lowTextManager_t creditText = _skyText->lowTextManager(a, 240, 0, 248, true);
+ Compact *credCompact = _skyCompact->fetchCpt(creditText.compactNum);
+ credCompact->xcood = 168;
+ if ((a == 558) && (c == 215))
+ credCompact->ycood = 211;
+ else
+ credCompact->ycood = (uint16)c;
+ _scriptVariables[RESULT] = creditText.compactNum;
+ return true;
+}
+
+bool Logic::fnLookAt(uint32 a, uint32 b, uint32 c) {
+
+ struct lowTextManager_t textInfo = _skyText->lowTextManager(a, 240, 0, 248, true);
+ Compact *textCpt = _skyCompact->fetchCpt(textInfo.compactNum);
+ textCpt->xcood = 168;
+ textCpt->ycood = (uint16)c;
+
+ _skyScreen->recreate();
+ _skyScreen->spriteEngine();
+ _skyScreen->flip();
+
+ fnNoHuman(0, 0, 0);
+ _skyMouse->lockMouse();
+
+ _skyMouse->waitMouseNotPressed();
+
+ _skyMouse->unlockMouse();
+ fnAddHuman(0, 0, 0);
+ textCpt->status = 0;
+
+ return true;
+}
+
+bool Logic::fnLincTextModule(uint32 textPos, uint32 textNo, uint32 buttonAction) {
+
+ uint16 cnt;
+ if (buttonAction & 0x8000)
+ for (cnt = LINC_DIGIT_0; cnt <= LINC_DIGIT_9; cnt++)
+ _scriptVariables[cnt] = 0;
+ buttonAction &= 0x7FFF;
+ if (buttonAction < 10)
+ _scriptVariables[LINC_DIGIT_0 + buttonAction] = textNo;
+
+ lowTextManager_t text = _skyText->lowTextManager(textNo, 220, 0, 215, false);
+
+ Compact *textCpt = _skyCompact->fetchCpt(text.compactNum);
+
+ if (textPos < 20) { // line number (for text)
+ textCpt->xcood = 152;
+ textCpt->ycood = (uint16)textPos * 13 + 170;
+ } else if (textPos > 20) { // x coordinate (for numbers)
+ textCpt->xcood = (uint16)textPos;
+ textCpt->ycood = 214;
+ } else warning("::fnLincTextModule: textPos == 20");
+ textCpt->getToFlag = (uint16)textNo;
+ return true;
+}
+
+bool Logic::fnTextKill2(uint32 a, uint32 b, uint32 c) {
+ /// Kill all text items
+
+ uint32 id = FIRST_TEXT_COMPACT;
+
+ for (int i = 10; i > 0; i--) {
+ Compact *cpt = _skyCompact->fetchCpt(id);
+ cpt->status = 0;
+ id++;
+ }
+ return true;
+}
+
+bool Logic::fnSetFont(uint32 font, uint32 b, uint32 c) {
+ _skyText->fnSetFont(font);
+ return true;
+}
+
+bool Logic::fnStartFx(uint32 sound, uint32 b, uint32 c) {
+ _skySound->fnStartFx(sound, (uint8)(b & 1));
+ return true;
+}
+
+bool Logic::fnStopFx(uint32 a, uint32 b, uint32 c) {
+ _skySound->fnStopFx();
+ return true;
+}
+
+bool Logic::fnStartMusic(uint32 a, uint32 b, uint32 c) {
+ if (!(SkyEngine::_systemVars.systemFlags & SF_MUS_OFF))
+ _skyMusic->startMusic((uint16)a);
+ SkyEngine::_systemVars.currentMusic = (uint16)a;
+ return true;
+}
+
+bool Logic::fnStopMusic(uint32 a, uint32 b, uint32 c) {
+ _skyMusic->startMusic(0);
+ SkyEngine::_systemVars.currentMusic = 0;
+ return true;
+}
+
+bool Logic::fnFadeDown(uint32 a, uint32 b, uint32 c) {
+ _skyScreen->fnFadeDown(a);
+ return true;
+}
+
+bool Logic::fnFadeUp(uint32 a, uint32 b, uint32 c) {
+ SkyEngine::_systemVars.currentPalette = a;
+ _skyScreen->fnFadeUp(a,b);
+ return true;
+}
+
+bool Logic::fnQuitToDos(uint32 a, uint32 b, uint32 c) {
+ SkyEngine::_systemVars.quitGame = true;
+ return false;
+}
+
+bool Logic::fnPauseFx(uint32 a, uint32 b, uint32 c) {
+ _skySound->fnPauseFx();
+ return true;
+}
+
+bool Logic::fnUnPauseFx(uint32 a, uint32 b, uint32 c) {
+ _skySound->fnUnPauseFx();
+ return true;
+}
+
+bool Logic::fnPrintf(uint32 a, uint32 b, uint32 c) {
+ printf("fnPrintf: %d\n", a);
+ return true;
+}
+
+void Logic::stdSpeak(Compact *target, uint32 textNum, uint32 animNum, uint32 base) {
+
+ animNum += target->megaSet / NEXT_MEGA_SET;
+ animNum &= 0xFF;
+
+ uint16 *talkTable = (uint16*)_skyCompact->fetchCpt(CPT_TALK_TABLE_LIST);
+ target->grafixProgId = talkTable[animNum];
+ target->grafixProgPos = 0;
+ uint16 *animPtr = _skyCompact->getGrafixPtr(target);
+
+ if (animPtr) {
+ target->offset = *animPtr++;
+ target->getToFlag = *animPtr++;
+ target->grafixProgPos += 2;
+ } else
+ target->grafixProgId = 0;
+
+ bool speechFileFound = false;
+ if (SkyEngine::isCDVersion())
+ speechFileFound = _skySound->startSpeech((uint16)textNum);
+
+ if ((SkyEngine::_systemVars.systemFlags & SF_ALLOW_TEXT) || !speechFileFound) {
+ // form the text sprite, if player wants subtitles or
+ // if we couldn't find the speech file
+ struct lowTextManager_t textInfo;
+ textInfo = _skyText->lowTextManager(textNum, FIXED_TEXT_WIDTH, 0, (uint8)target->spColour, true);
+ Compact *textCompact = _skyCompact->fetchCpt(textInfo.compactNum);
+ target->spTextId = textInfo.compactNum; //So we know what text to kill
+ byte *textGfx = textInfo.textData;
+
+ textCompact->screen = target->screen; //put it on our screen
+
+ if (_scriptVariables[SCREEN] == target->screen) { // Only use coordinates if we are on the current screen
+ //talking on-screen
+ //create the x coordinate for the speech text
+ //we need the talkers sprite information
+ byte *targetGfx = (byte *)SkyEngine::fetchItem(target->frame >> 6);
+ uint16 xPos = target->xcood + ((struct dataFileHeader *)targetGfx)->s_offset_x;
+ uint16 width = (((struct dataFileHeader *)targetGfx)->s_width >> 1);
+
+ xPos += width - (FIXED_TEXT_WIDTH / 2); //middle of talker
+
+ if (xPos < TOP_LEFT_X)
+ xPos = TOP_LEFT_X;
+
+ width = xPos + FIXED_TEXT_WIDTH;
+ if ((TOP_LEFT_X + FULL_SCREEN_WIDTH) <= width) {
+ xPos = TOP_LEFT_X + FULL_SCREEN_WIDTH;
+ xPos -= FIXED_TEXT_WIDTH;
+ }
+
+ textCompact->xcood = xPos;
+ uint16 yPos = target->ycood + ((struct dataFileHeader *)targetGfx)->s_offset_y - 6 - ((struct dataFileHeader *)textGfx)->s_height;
+
+ if (yPos < TOP_LEFT_Y)
+ yPos = TOP_LEFT_Y;
+
+ textCompact->ycood = yPos;
+
+ } else {
+ //talking off-screen
+ target->spTextId = 0; //don't kill any text 'cos none was made
+ textCompact->status = 0; //don't display text
+ }
+ // In CD version, we're doing the timing by checking when the VOC has stopped playing.
+ // Setting spTime to 10 thus means that we're doing a pause of 10 gamecycles between
+ // each sentence.
+ if (speechFileFound)
+ target->spTime = 10;
+ else
+ target->spTime = (uint16)_skyText->_numLetters + 5;
+ } else {
+ target->spTime = 10;
+ target->spTextId = 0;
+ }
+ target->logic = L_TALK;
+}
+
+} // End of namespace Sky
diff --git a/engines/sky/logic.h b/engines/sky/logic.h
new file mode 100644
index 0000000000..7d10be6d8c
--- /dev/null
+++ b/engines/sky/logic.h
@@ -0,0 +1,338 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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 SKYLOGIC_H
+#define SKYLOGIC_H
+
+#include "common/stdafx.h"
+#include "common/util.h"
+
+namespace Sky {
+
+struct Compact;
+
+enum scriptVariableOffsets {
+ RESULT = 0,
+ SCREEN = 1,
+ LOGIC_LIST_NO = 2,
+ MOUSE_LIST_NO = 6,
+ DRAW_LIST_NO = 8,
+ CUR_ID = 12,
+ MOUSE_STATUS = 13,
+ MOUSE_STOP = 14,
+ BUTTON = 15,
+ SPECIAL_ITEM = 17,
+ GET_OFF = 18,
+ CURSOR_ID = 22,
+ SAFEX = 25,
+ SAFEY = 26,
+ PLAYER_X = 27,
+ PLAYER_Y = 28,
+ PLAYER_MOOD = 29,
+ PLAYER_SCREEN = 30,
+ HIT_ID = 37,
+ LAYER_0_ID = 41,
+ LAYER_1_ID = 42,
+ LAYER_2_ID = 43,
+ LAYER_3_ID = 44,
+ GRID_1_ID = 45,
+ GRID_2_ID = 46,
+ GRID_3_ID = 47,
+ THE_CHOSEN_ONE = 51,
+ TEXT1 = 53,
+ MENU_LENGTH = 100,
+ SCROLL_OFFSET = 101,
+ MENU = 102,
+ OBJECT_HELD = 103,
+ LAMB_GREET = 109,
+ RND = 115,
+ CUR_SECTION = 143,
+ JOEY_SECTION = 145,
+ LAMB_SECTION = 146,
+ KNOWS_PORT = 190,
+ GOT_SPONSOR = 240,
+ GOT_JAMMER = 258,
+ CONSOLE_TYPE = 345,
+ S15_FLOOR = 450,
+ FOREMAN_FRIEND = 451,
+ REICH_DOOR_FLAG = 470,
+ CARD_STATUS = 479,
+ CARD_FIX = 480,
+ GUARDIAN_THERE = 640,
+ FS_COMMAND = 643,
+ ENTER_DIGITS = 644,
+ LINC_DIGIT_0 = 646,
+ LINC_DIGIT_1 = 647,
+ LINC_DIGIT_2 = 648,
+ LINC_DIGIT_3 = 649,
+ LINC_DIGIT_4 = 650,
+ LINC_DIGIT_5 = 651,
+ LINC_DIGIT_6 = 651,
+ LINC_DIGIT_7 = 653,
+ LINC_DIGIT_8 = 654,
+ LINC_DIGIT_9 = 655,
+ DOOR_67_68_FLAG = 678,
+ SC70_IRIS_FLAG = 693,
+ DOOR_73_75_FLAG = 704,
+ SC76_CABINET1_FLAG = 709,
+ SC76_CABINET2_FLAG = 710,
+ SC76_CABINET3_FLAG = 711,
+ DOOR_77_78_FLAG = 719,
+ SC80_EXIT_FLAG = 720,
+ SC31_LIFT_FLAG = 793,
+ SC32_LIFT_FLAG = 797,
+ SC33_SHED_DOOR_FLAG = 798,
+ BAND_PLAYING = 804,
+ COLSTON_AT_TABLE = 805,
+ SC36_NEXT_DEALER = 806,
+ SC36_DOOR_FLAG = 807,
+ SC37_DOOR_FLAG = 808,
+ SC40_LOCKER_1_FLAG = 817,
+ SC40_LOCKER_2_FLAG = 818,
+ SC40_LOCKER_3_FLAG = 819,
+ SC40_LOCKER_4_FLAG = 820,
+ SC40_LOCKER_5_FLAG = 821
+};
+
+#define NUM_SKY_SCRIPTVARS 838
+
+class AutoRoute;
+class Control;
+class Disk;
+class Grid;
+class Mouse;
+class MusicBase;
+class Screen;
+class Sound;
+class Text;
+class SkyCompact;
+
+class Logic;
+
+typedef void (Logic::*LogicTable) ();
+typedef bool (Logic::*McodeTable) (uint32, uint32, uint32);
+
+class Logic {
+public:
+ Logic(
+ SkyCompact *skyCompact,
+ Screen *skyScreen,
+ Disk *skyDisk,
+ Text *skyText,
+ MusicBase *skyMusic,
+ Mouse *skyMouse,
+ Sound *skySound);
+ ~Logic(void);
+ void engine();
+ void useControlInstance(Control *control) { _skyControl = control; };
+
+ uint16 mouseScript(uint32 scrNum, Compact *scriptComp);
+
+ static uint32 _scriptVariables[NUM_SKY_SCRIPTVARS];
+ Grid *_skyGrid;
+
+ uint16 script(uint16 scriptNo, uint16 offset);
+ void initScreen0(void);
+ void parseSaveData(uint32 *data);
+
+private:
+ void setupLogicTable();
+ void setupMcodeTable();
+ const LogicTable *_logicTable;
+ const McodeTable *_mcodeTable;
+
+protected:
+ void push(uint32);
+ uint32 pop();
+ void checkModuleLoaded(uint16 moduleNo);
+ bool collide(Compact *cpt);
+ void initScriptVariables();
+ void mainAnim();
+ void runGetOff();
+ void stopAndWait();
+ bool checkProtection(void);
+
+ void nop();
+ void logicScript();
+ void autoRoute();
+ void arAnim();
+ void arTurn();
+ void alt();
+ void anim();
+ void turn();
+ void cursor();
+ void talk();
+ void listen();
+ void stopped();
+ void choose();
+ void frames();
+ void pause();
+ void waitSync();
+ void simpleAnim();
+
+ bool fnCacheChip(uint32 a, uint32 b, uint32 c);
+ bool fnCacheFast(uint32 a, uint32 b, uint32 c);
+ bool fnDrawScreen(uint32 a, uint32 b, uint32 c);
+ bool fnAr(uint32 a, uint32 b, uint32 c);
+ bool fnArAnimate(uint32 a, uint32 b, uint32 c);
+ bool fnIdle(uint32 a, uint32 b, uint32 c);
+ bool fnInteract(uint32 a, uint32 b, uint32 c);
+ bool fnStartSub(uint32 a, uint32 b, uint32 c);
+ bool fnTheyStartSub(uint32 a, uint32 b, uint32 c);
+ bool fnAssignBase(uint32 a, uint32 b, uint32 c);
+ bool fnDiskMouse(uint32 a, uint32 b, uint32 c);
+ bool fnNormalMouse(uint32 a, uint32 b, uint32 c);
+ bool fnBlankMouse(uint32 a, uint32 b, uint32 c);
+ bool fnCrossMouse(uint32 a, uint32 b, uint32 c);
+ bool fnCursorRight(uint32 a, uint32 b, uint32 c);
+ bool fnCursorLeft(uint32 a, uint32 b, uint32 c);
+ bool fnCursorDown(uint32 a, uint32 b, uint32 c);
+ bool fnOpenHand(uint32 a, uint32 b, uint32 c);
+ bool fnCloseHand(uint32 a, uint32 b, uint32 c);
+ bool fnGetTo(uint32 a, uint32 b, uint32 c);
+ bool fnSetToStand(uint32 a, uint32 b, uint32 c);
+ bool fnTurnTo(uint32 a, uint32 b, uint32 c);
+ bool fnArrived(uint32 a, uint32 b, uint32 c);
+ bool fnLeaving(uint32 a, uint32 b, uint32 c);
+ bool fnSetAlternate(uint32 a, uint32 b, uint32 c);
+ bool fnAltSetAlternate(uint32 a, uint32 b, uint32 c);
+ bool fnKillId(uint32 a, uint32 b, uint32 c);
+ bool fnNoHuman(uint32 a, uint32 b, uint32 c);
+ bool fnAddHuman(uint32 a, uint32 b, uint32 c);
+ bool fnAddButtons(uint32 a, uint32 b, uint32 c);
+ bool fnNoButtons(uint32 a, uint32 b, uint32 c);
+ bool fnSetStop(uint32 a, uint32 b, uint32 c);
+ bool fnClearStop(uint32 a, uint32 b, uint32 c);
+ bool fnPointerText(uint32 a, uint32 b, uint32 c);
+ bool fnQuit(uint32 a, uint32 b, uint32 c);
+ bool fnSpeakMe(uint32 targetId, uint32 mesgNum, uint32 animNum);
+ bool fnSpeakMeDir(uint32 targetId, uint32 mesgNum, uint32 animNum);
+ bool fnSpeakWait(uint32 a, uint32 b, uint32 c);
+ bool fnSpeakWaitDir(uint32 a, uint32 b, uint32 c);
+ bool fnChooser(uint32 a, uint32 b, uint32 c);
+ bool fnHighlight(uint32 a, uint32 b, uint32 c);
+ bool fnTextKill(uint32 a, uint32 b, uint32 c);
+ bool fnStopMode(uint32 a, uint32 b, uint32 c);
+ bool fnWeWait(uint32 a, uint32 b, uint32 c);
+ bool fnSendSync(uint32 a, uint32 b, uint32 c);
+ bool fnSendFastSync(uint32 a, uint32 b, uint32 c);
+ bool fnSendRequest(uint32 a, uint32 b, uint32 c);
+ bool fnClearRequest(uint32 a, uint32 b, uint32 c);
+ bool fnCheckRequest(uint32 a, uint32 b, uint32 c);
+ bool fnStartMenu(uint32 a, uint32 b, uint32 c);
+ bool fnUnhighlight(uint32 a, uint32 b, uint32 c);
+ bool fnFaceId(uint32 a, uint32 b, uint32 c);
+ bool fnForeground(uint32 a, uint32 b, uint32 c);
+ bool fnBackground(uint32 a, uint32 b, uint32 c);
+ bool fnNewBackground(uint32 a, uint32 b, uint32 c);
+ bool fnSort(uint32 a, uint32 b, uint32 c);
+ bool fnNoSpriteEngine(uint32 a, uint32 b, uint32 c);
+ bool fnNoSpritesA6(uint32 a, uint32 b, uint32 c);
+ bool fnResetId(uint32 a, uint32 b, uint32 c);
+ bool fnToggleGrid(uint32 a, uint32 b, uint32 c);
+ bool fnPause(uint32 a, uint32 b, uint32 c);
+ bool fnRunAnimMod(uint32 a, uint32 b, uint32 c);
+ bool fnSimpleMod(uint32 a, uint32 b, uint32 c);
+ bool fnRunFrames(uint32 a, uint32 b, uint32 c);
+ bool fnAwaitSync(uint32 a, uint32 b, uint32 c);
+ bool fnIncMegaSet(uint32 a, uint32 b, uint32 c);
+ bool fnDecMegaSet(uint32 a, uint32 b, uint32 c);
+ bool fnSetMegaSet(uint32 a, uint32 b, uint32 c);
+ bool fnMoveItems(uint32 a, uint32 b, uint32 c);
+ bool fnNewList(uint32 a, uint32 b, uint32 c);
+ bool fnAskThis(uint32 a, uint32 b, uint32 c);
+ bool fnRandom(uint32 a, uint32 b, uint32 c);
+ bool fnPersonHere(uint32 a, uint32 b, uint32 c);
+ bool fnToggleMouse(uint32 a, uint32 b, uint32 c);
+ bool fnMouseOn(uint32 a, uint32 b, uint32 c);
+ bool fnMouseOff(uint32 a, uint32 b, uint32 c);
+ bool fnFetchX(uint32 a, uint32 b, uint32 c);
+ bool fnFetchY(uint32 a, uint32 b, uint32 c);
+ bool fnTestList(uint32 a, uint32 b, uint32 c);
+ bool fnFetchPlace(uint32 a, uint32 b, uint32 c);
+ bool fnCustomJoey(uint32 a, uint32 b, uint32 c);
+ bool fnSetPalette(uint32 a, uint32 b, uint32 c);
+ bool fnTextModule(uint32 a, uint32 b, uint32 c);
+ bool fnChangeName(uint32 a, uint32 b, uint32 c);
+ bool fnMiniLoad(uint32 a, uint32 b, uint32 c);
+ bool fnFlushBuffers(uint32 a, uint32 b, uint32 c);
+ bool fnFlushChip(uint32 a, uint32 b, uint32 c);
+ bool fnSaveCoods(uint32 a, uint32 b, uint32 c);
+ bool fnPlotGrid(uint32 a, uint32 b, uint32 c);
+ bool fnRemoveGrid(uint32 a, uint32 b, uint32 c);
+ bool fnEyeball(uint32 a, uint32 b, uint32 c);
+ bool fnCursorUp(uint32 a, uint32 b, uint32 c);
+ bool fnLeaveSection(uint32 a, uint32 b, uint32 c);
+ bool fnEnterSection(uint32 sectionNo, uint32 b, uint32 c);
+ bool fnRestoreGame(uint32 a, uint32 b, uint32 c);
+ bool fnRestartGame(uint32 a, uint32 b, uint32 c);
+ bool fnNewSwingSeq(uint32 a, uint32 b, uint32 c);
+ bool fnWaitSwingEnd(uint32 a, uint32 b, uint32 c);
+ bool fnSkipIntroCode(uint32 a, uint32 b, uint32 c);
+ bool fnBlankScreen(uint32 a, uint32 b, uint32 c);
+ bool fnPrintCredit(uint32 a, uint32 b, uint32 c);
+ bool fnLookAt(uint32 a, uint32 b, uint32 c);
+ bool fnLincTextModule(uint32 a, uint32 b, uint32 c);
+ bool fnTextKill2(uint32 a, uint32 b, uint32 c);
+ bool fnSetFont(uint32 a, uint32 b, uint32 c);
+ bool fnStartFx(uint32 a, uint32 b, uint32 c);
+ bool fnStopFx(uint32 a, uint32 b, uint32 c);
+ bool fnStartMusic(uint32 a, uint32 b, uint32 c);
+ bool fnStopMusic(uint32 a, uint32 b, uint32 c);
+ bool fnFadeDown(uint32 a, uint32 b, uint32 c);
+ bool fnFadeUp(uint32 a, uint32 b, uint32 c);
+ bool fnQuitToDos(uint32 a, uint32 b, uint32 c);
+ bool fnPauseFx(uint32 a, uint32 b, uint32 c);
+ bool fnUnPauseFx(uint32 a, uint32 b, uint32 c);
+ bool fnPrintf(uint32 a, uint32 b, uint32 c);
+
+ void stdSpeak(Compact *target, uint32 textNum, uint32 animNum, uint32 base);
+ void fnExec(uint16 num, uint32 a, uint32 b, uint32 c);
+
+ uint16 *_moduleList[16];
+ uint32 _stack[20];
+ byte _stackPtr;
+
+ Compact *_compact;
+
+ uint32 _objectList[30];
+
+ uint32 _currentSection;
+
+ Common::RandomSource _rnd;
+
+ SkyCompact *_skyCompact;
+ Screen *_skyScreen;
+ Disk *_skyDisk;
+ Text *_skyText;
+ MusicBase *_skyMusic;
+ Sound *_skySound;
+ AutoRoute *_skyAutoRoute;
+ Mouse *_skyMouse;
+ Control *_skyControl;
+
+ friend class Debugger;
+};
+
+} // End of namespace Sky
+
+#endif
diff --git a/engines/sky/module.mk b/engines/sky/module.mk
new file mode 100644
index 0000000000..875cf65e47
--- /dev/null
+++ b/engines/sky/module.mk
@@ -0,0 +1,37 @@
+MODULE := engines/sky
+
+MODULE_OBJS := \
+ engines/sky/autoroute.o \
+ engines/sky/compact.o \
+ engines/sky/control.o \
+ engines/sky/debug.o \
+ engines/sky/disk.o \
+ engines/sky/grid.o \
+ engines/sky/hufftext.o \
+ engines/sky/intro.o \
+ engines/sky/logic.o \
+ engines/sky/mouse.o \
+ engines/sky/rnc_deco.o \
+ engines/sky/screen.o \
+ engines/sky/sky.o \
+ engines/sky/sound.o \
+ engines/sky/text.o \
+ engines/sky/music/adlibchannel.o \
+ engines/sky/music/adlibmusic.o \
+ engines/sky/music/gmchannel.o \
+ engines/sky/music/gmmusic.o \
+ engines/sky/music/mt32music.o \
+ engines/sky/music/musicbase.o
+
+MODULE_DIRS += \
+ engines/sky \
+ engines/sky/music \
+ engines/sky/compacts
+
+# This module can be built as a plugin
+ifdef BUILD_PLUGINS
+PLUGIN := 1
+endif
+
+# Include common rules
+include $(srcdir)/common.rules
diff --git a/engines/sky/mouse.cpp b/engines/sky/mouse.cpp
new file mode 100644
index 0000000000..dd906b5b2d
--- /dev/null
+++ b/engines/sky/mouse.cpp
@@ -0,0 +1,323 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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 "sky/disk.h"
+#include "sky/logic.h"
+#include "sky/mouse.h"
+#include "sky/sky.h"
+#include "sky/skydefs.h"
+#include "sky/struc.h"
+#include "sky/compact.h"
+
+namespace Sky {
+
+#define MICE_FILE 60300
+#define NO_MAIN_OBJECTS 24
+#define NO_LINC_OBJECTS 21
+
+uint32 Mouse::_mouseMainObjects[24] = {
+ 65,
+ 9,
+ 66,
+ 64,
+ 8,
+ 63,
+ 10,
+ 11,
+ 71,
+ 76,
+ 37,
+ 36,
+ 42,
+ 75,
+ 79,
+ 6,
+ 74,
+ 39,
+ 49,
+ 43,
+ 34,
+ 35,
+ 77,
+ 38
+};
+
+uint32 Mouse::_mouseLincObjects[21] = {
+ 24625,
+ 24649,
+ 24827,
+ 24651,
+ 24583,
+ 24581,
+ 24582,
+ 24628,
+ 24650,
+ 24629,
+ 24732,
+ 24631,
+ 24584,
+ 24630,
+ 24626,
+ 24627,
+ 24632,
+ 24643,
+ 24828,
+ 24830,
+ 24829
+};
+
+Mouse::Mouse(OSystem *system, Disk *skyDisk, SkyCompact *skyCompact) {
+
+ _skyDisk = skyDisk;
+ _skyCompact = skyCompact;
+ _system = system;
+ _mouseB = 0;
+ _currentCursor = 6;
+ _mouseX = GAME_SCREEN_WIDTH / 2;
+ _mouseY = GAME_SCREEN_HEIGHT / 2;
+
+ _miceData = _skyDisk->loadFile(MICE_FILE);
+
+ //load in the object mouse file
+ _objectMouseData = _skyDisk->loadFile(MICE_FILE + 1);
+}
+
+Mouse::~Mouse( ){
+ free (_miceData);
+ free (_objectMouseData);
+}
+
+void Mouse::replaceMouseCursors(uint16 fileNo) {
+ free(_objectMouseData);
+ _objectMouseData = _skyDisk->loadFile(fileNo);
+}
+
+bool Mouse::fnAddHuman(void) {
+ //reintroduce the mouse so that the human can control the player
+ //could still be switched out at high-level
+
+ if (!Logic::_scriptVariables[MOUSE_STOP]) {
+ Logic::_scriptVariables[MOUSE_STATUS] |= 6; //cursor & mouse
+
+ if (_mouseY < 2) //stop mouse activating top line
+ _mouseY = 2;
+
+ _system->warpMouse(_mouseX, _mouseY);
+
+ //force the pointer engine into running a get-off
+ //even if it's over nothing
+
+ //KWIK-FIX
+ //get off may contain script to remove mouse pointer text
+ //surely this script should be run just in case
+ //I am going to try it anyway
+ if (Logic::_scriptVariables[GET_OFF])
+ _skyLogic->script((uint16)Logic::_scriptVariables[GET_OFF],(uint16)(Logic::_scriptVariables[GET_OFF] >> 16));
+
+ Logic::_scriptVariables[SPECIAL_ITEM] = 0xFFFFFFFF;
+ Logic::_scriptVariables[GET_OFF] = RESET_MOUSE;
+ }
+
+ return true;
+}
+
+void Mouse::fnSaveCoods(void) {
+ Logic::_scriptVariables[SAFEX] = _mouseX + TOP_LEFT_X;
+ Logic::_scriptVariables[SAFEY] = _mouseY + TOP_LEFT_Y;
+}
+
+void Mouse::lockMouse(void) {
+ SkyEngine::_systemVars.systemFlags |= SF_MOUSE_LOCKED;
+}
+
+void Mouse::unlockMouse(void) {
+ SkyEngine::_systemVars.systemFlags &= ~SF_MOUSE_LOCKED;
+}
+
+void Mouse::restoreMouseData(uint16 frameNum) {
+ warning("Stub: Mouse::restoreMouseData");
+}
+
+void Mouse::drawNewMouse() {
+ warning("Stub: Mouse::drawNewMouse");
+ //calculateMouseValues();
+ //saveMouseData();
+ //drawMouse();
+}
+
+void Mouse::waitMouseNotPressed(void) {
+
+ bool mousePressed = true;
+ OSystem::Event event;
+ while (mousePressed) {
+ _system->delayMillis(20);
+ while (_system->pollEvent(event)) {
+ if ((event.type == OSystem::EVENT_LBUTTONUP) ||
+ (event.type == OSystem::EVENT_QUIT))
+ mousePressed = false;
+ }
+ }
+}
+
+void Mouse::spriteMouse(uint16 frameNum, uint8 mouseX, uint8 mouseY) {
+
+ _currentCursor = frameNum;
+
+ byte *newCursor = _miceData;
+ newCursor += ((struct dataFileHeader *)_miceData)->s_sp_size * frameNum;
+ newCursor += sizeof(struct dataFileHeader);
+
+ uint16 mouseWidth = ((struct dataFileHeader *)_miceData)->s_width;
+ uint16 mouseHeight = ((struct dataFileHeader *)_miceData)->s_height;
+
+ _system->setMouseCursor(newCursor, mouseWidth, mouseHeight, mouseX, mouseY, 0);
+ if (frameNum == MOUSE_BLANK)
+ _system->showMouse(false);
+ else
+ _system->showMouse(true);
+}
+
+void Mouse::mouseEngine(uint16 mouseX, uint16 mouseY) {
+ _mouseX = mouseX;
+ _mouseY = mouseY;
+
+ _logicClick = (_mouseB > 0); // click signal is available for Logic for one gamecycle
+
+ if (!Logic::_scriptVariables[MOUSE_STOP]) {
+ if (Logic::_scriptVariables[MOUSE_STATUS] & (1 << 1)) {
+ pointerEngine(mouseX + TOP_LEFT_X, mouseY + TOP_LEFT_Y);
+ if (Logic::_scriptVariables[MOUSE_STATUS] & (1 << 2)) //buttons enabled?
+ buttonEngine1();
+ }
+ }
+ _mouseB = 0; //don't save up buttons
+}
+
+void Mouse::pointerEngine(uint16 xPos, uint16 yPos) {
+ uint32 currentListNum = Logic::_scriptVariables[MOUSE_LIST_NO];
+ uint16 *currentList;
+ do {
+ currentList = (uint16 *)_skyCompact->fetchCpt(currentListNum);
+ while ((*currentList != 0) && (*currentList != 0xFFFF)) {
+ uint16 itemNum = *currentList;
+ Compact *itemData = _skyCompact->fetchCpt(itemNum);
+ currentList++;
+ if ((itemData->screen == Logic::_scriptVariables[SCREEN]) && (itemData->status & 16)) {
+ if (itemData->xcood + ((int16)itemData->mouseRelX) > xPos) continue;
+ if (itemData->xcood + ((int16)itemData->mouseRelX) + itemData->mouseSizeX < xPos) continue;
+ if (itemData->ycood + ((int16)itemData->mouseRelY) > yPos) continue;
+ if (itemData->ycood + ((int16)itemData->mouseRelY) + itemData->mouseSizeY < yPos) continue;
+ // we've hit the item
+ if (Logic::_scriptVariables[SPECIAL_ITEM] == itemNum)
+ return;
+ Logic::_scriptVariables[SPECIAL_ITEM] = itemNum;
+ if (Logic::_scriptVariables[GET_OFF])
+ _skyLogic->mouseScript(Logic::_scriptVariables[GET_OFF], itemData);
+ Logic::_scriptVariables[GET_OFF] = itemData->mouseOff;
+ if (itemData->mouseOn)
+ _skyLogic->mouseScript(itemData->mouseOn, itemData);
+ return;
+ }
+ }
+ if (*currentList == 0xFFFF)
+ currentListNum = currentList[1];
+ } while (*currentList != 0);
+ if (Logic::_scriptVariables[SPECIAL_ITEM] != 0) {
+ Logic::_scriptVariables[SPECIAL_ITEM] = 0;
+
+ if (Logic::_scriptVariables[GET_OFF])
+ _skyLogic->script((uint16)Logic::_scriptVariables[GET_OFF],(uint16)(Logic::_scriptVariables[GET_OFF] >> 16));
+ Logic::_scriptVariables[GET_OFF] = 0;
+ }
+}
+
+void Mouse::buttonPressed(uint8 button) {
+
+ _mouseB = button;
+}
+
+void Mouse::buttonEngine1(void) {
+ //checks for clicking on special item
+ //"compare the size of this routine to S1 mouse_button"
+
+ if (_mouseB) { //anything pressed?
+ Logic::_scriptVariables[BUTTON] = _mouseB;
+ if (Logic::_scriptVariables[SPECIAL_ITEM]) { //over anything?
+ Compact *item = _skyCompact->fetchCpt(Logic::_scriptVariables[SPECIAL_ITEM]);
+ if (item->mouseClick)
+ _skyLogic->mouseScript(item->mouseClick, item);
+ }
+ }
+}
+
+void Mouse::resetCursor() {
+ spriteMouse(_currentCursor, 0, 0);
+}
+
+uint16 Mouse::findMouseCursor(uint32 itemNum) {
+
+ uint8 cnt;
+ for (cnt = 0; cnt < NO_MAIN_OBJECTS; cnt++) {
+ if (itemNum == _mouseMainObjects[cnt]) {
+ return cnt;
+ }
+ }
+ for (cnt = 0; cnt < NO_LINC_OBJECTS; cnt++) {
+ if (itemNum == _mouseLincObjects[cnt]) {
+ return cnt;
+ }
+ }
+ return 0;
+}
+
+void Mouse::fnOpenCloseHand(bool open) {
+
+ if ((!open) && (!Logic::_scriptVariables[OBJECT_HELD])) {
+ spriteMouse(1, 0, 0);
+ return;
+ }
+ uint16 cursor = findMouseCursor(Logic::_scriptVariables[OBJECT_HELD]) << 1;
+ if (open)
+ cursor++;
+
+ uint32 size = ((dataFileHeader*)_objectMouseData)->s_sp_size;
+ uint8 *srcData;
+ uint8 *destData;
+
+ srcData = (uint8 *)_objectMouseData + size * cursor + sizeof(dataFileHeader);
+ destData = (uint8 *)_miceData + sizeof(dataFileHeader);
+ memcpy(destData, srcData, size);
+ spriteMouse(0, 5, 5);
+}
+
+bool Mouse::wasClicked(void) {
+
+ if (_logicClick) {
+ _logicClick = false;
+ return true;
+ } else
+ return false;
+}
+
+} // End of namespace Sky
diff --git a/engines/sky/mouse.h b/engines/sky/mouse.h
new file mode 100644
index 0000000000..9e713cce03
--- /dev/null
+++ b/engines/sky/mouse.h
@@ -0,0 +1,92 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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 SKYMOUSE_H
+#define SKYMOUSE_H
+
+#include "common/stdafx.h"
+#include "common/scummsys.h"
+
+class OSystem;
+
+namespace Sky {
+
+class Disk;
+class Logic;
+class SkyCompact;
+
+class Mouse {
+
+public:
+
+ Mouse(OSystem *system, Disk *skyDisk, SkyCompact *skyCompact);
+ ~Mouse(void);
+
+ void mouseEngine(uint16 mouseX, uint16 mouseY);
+ void replaceMouseCursors(uint16 fileNo);
+ bool fnAddHuman(void);
+ void fnSaveCoods(void);
+ void fnOpenCloseHand(bool open);
+ uint16 findMouseCursor(uint32 itemNum);
+ void lockMouse(void);
+ void unlockMouse(void);
+ void restoreMouseData(uint16 frameNum);
+ void drawNewMouse(void);
+ void spriteMouse(uint16 frameNum, uint8 mouseX, uint8 mouseY);
+ void useLogicInstance(Logic *skyLogic) { _skyLogic = skyLogic; };
+ void buttonPressed(uint8 button);
+ void waitMouseNotPressed(void);
+ uint16 giveMouseX(void) { return _mouseX; };
+ uint16 giveMouseY(void) { return _mouseY; };
+ uint16 giveCurrentMouseType(void) { return _currentCursor; };
+ bool wasClicked(void);
+ void logicClick(void) { _logicClick = true; };
+ void resetCursor();
+
+protected:
+
+ void pointerEngine(uint16 xPos, uint16 yPos);
+ void buttonEngine1(void);
+
+ bool _logicClick;
+
+ uint16 _mouseB; //mouse button
+ uint16 _mouseX; //actual mouse coordinates
+ uint16 _mouseY;
+
+ uint16 _currentCursor;
+
+ byte *_miceData; //address of mouse sprites
+ byte *_objectMouseData; //address of object mouse sprites
+
+ static uint32 _mouseMainObjects[24];
+ static uint32 _mouseLincObjects[21];
+
+ OSystem *_system;
+ Disk *_skyDisk;
+ Logic *_skyLogic;
+ SkyCompact *_skyCompact;
+};
+
+} // End of namespace Sky
+
+#endif //SKYMOUSE_H
diff --git a/engines/sky/music/adlibchannel.cpp b/engines/sky/music/adlibchannel.cpp
new file mode 100644
index 0000000000..9b28f832bb
--- /dev/null
+++ b/engines/sky/music/adlibchannel.cpp
@@ -0,0 +1,344 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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/util.h"
+#include "sky/music/adlibchannel.h"
+#include "sky/sky.h"
+
+namespace Sky {
+
+AdlibChannel::AdlibChannel(FM_OPL *opl, uint8 *pMusicData, uint16 startOfData) {
+ _opl = opl;
+ _musicData = pMusicData;
+ _channelData.startOfData = startOfData;
+ _channelData.eventDataPtr = startOfData;
+ _channelData.channelActive = 1;
+ _channelData.freqDataSize = 2;
+ _channelData.tremoVibro = 0;
+ _channelData.assignedInstrument = 0xFF;
+ _channelData.channelVolume = 0x7F;
+ _channelData.nextEventTime = getNextEventTime();
+
+ _channelData.adlibChannelNumber = _channelData.lastCommand = _channelData.note =
+ _channelData.adlibReg1 = _channelData.adlibReg2 = _channelData.freqOffset = 0;
+ _channelData.frequency = 0;
+ _channelData.instrumentData = NULL;
+
+ uint16 instrumentDataLoc;
+
+ if (SkyEngine::_systemVars.gameVersion == 109) {
+ //instrumentDataLoc = (_musicData[0x11D0] << 8) | _musicData[0x11CF];
+ //_frequenceTable = (uint16*)(_musicData + 0x835);
+ //_registerTable = _musicData + 0xE35;
+ //_opOutputTable = _musicData + 0xE47;
+ //_adlibRegMirror = _musicData + 0xF4A;
+
+ instrumentDataLoc = READ_LE_UINT16(_musicData + 0x1204);
+ _frequenceTable = (uint16*)(_musicData + 0x868);
+ _registerTable = _musicData + 0xE68;
+ _opOutputTable = _musicData + 0xE7A;
+ _adlibRegMirror = _musicData + 0xF7D;
+ } else if (SkyEngine::_systemVars.gameVersion == 267) {
+ instrumentDataLoc = READ_LE_UINT16(_musicData + 0x11FB);
+ _frequenceTable = (uint16*)(_musicData + 0x7F4);
+ _registerTable = _musicData + 0xDF4;
+ _opOutputTable = _musicData + 0xE06;
+ _adlibRegMirror = _musicData + 0xF55;
+ } else {
+ instrumentDataLoc = READ_LE_UINT16(_musicData + 0x1205);
+ _frequenceTable = (uint16*)(_musicData + 0x7FE);
+ _registerTable = _musicData + 0xDFE;
+ _opOutputTable = _musicData + 0xE10;
+ _adlibRegMirror = _musicData + 0xF5F;
+ }
+
+ _instrumentMap = _musicData+instrumentDataLoc;
+ _instruments = (InstrumentStruct*)(_instrumentMap+0x80);
+
+ _musicVolume = 0x100;
+}
+
+bool AdlibChannel::isActive(void) {
+
+ return _channelData.channelActive != 0;
+}
+
+void AdlibChannel::updateVolume(uint16 pVolume) {
+
+ _musicVolume = pVolume * 3;
+}
+
+/* This class uses the same area for the register mirror as the original
+ asm driver did (_musicData[0xF5F..0x105E]), so the cache is indeed shared
+ by all instances of the class.
+*/
+void AdlibChannel::setRegister(uint8 regNum, uint8 value) {
+
+ if (_adlibRegMirror[regNum] != value) {
+ OPLWriteReg (_opl, regNum, value);
+ _adlibRegMirror[regNum] = value;
+ }
+}
+
+void AdlibChannel::stopNote(void) {
+
+ if (_channelData.note & 0x20) {
+ _channelData.note &= ~0x20;
+ setRegister(0xB0 | _channelData.adlibChannelNumber, _channelData.note);
+ }
+}
+
+int32 AdlibChannel::getNextEventTime(void) {
+ int32 retV = 0;
+ uint8 cnt, lVal = 0;
+ for (cnt = 0; cnt < 4; cnt++) {
+ lVal = _musicData[_channelData.eventDataPtr];
+ _channelData.eventDataPtr++;
+ retV = (retV << 7) | (lVal & 0x7F);
+ if (!(lVal & 0x80)) break;
+ }
+ if (lVal & 0x80) { // should never happen
+ return -1;
+ } else return retV;
+
+}
+
+uint8 AdlibChannel::process(uint16 aktTime) {
+
+ if (!_channelData.channelActive) {
+ return 0;
+ }
+
+ uint8 returnVal = 0;
+
+ _channelData.nextEventTime -= aktTime;
+ uint8 opcode;
+ while ((_channelData.nextEventTime < 0) && (_channelData.channelActive)) {
+ opcode = _musicData[_channelData.eventDataPtr];
+ _channelData.eventDataPtr++;
+ if (opcode & 0x80) {
+ if (opcode == 0xFF) {
+ // dummy opcode
+ } else if (opcode >= 0x90) {
+ switch (opcode&0xF) {
+ case 0: com90_caseNoteOff(); break;
+ case 1: com90_stopChannel(); break;
+ case 2: com90_setupInstrument(); break;
+ case 3:
+ returnVal = com90_updateTempo();
+ break;
+ case 5: com90_getFreqOffset(); break;
+ case 6: com90_getChannelVolume(); break;
+ case 7: com90_getTremoVibro(); break;
+ case 8: com90_rewindMusic(); break;
+ case 9: com90_keyOff(); break;
+ case 12: com90_setStartOfData(); break;
+ case 4: //com90_dummy();
+ case 10: //com90_error();
+ case 11: //com90_doLodsb();
+ case 13: //com90_do_two_Lodsb();
+ error("Channel: dummy music routine 0x%02X was called",opcode);
+ _channelData.channelActive = 0;
+ break;
+ default:
+ // these opcodes aren't implemented in original music driver
+ error("Channel: Not existent routine 0x%02X was called",opcode);
+ _channelData.channelActive = 0;
+ break;
+ }
+ } else {
+ // new adlib channel assignment
+ _channelData.adlibChannelNumber = opcode&0xF;
+ _channelData.adlibReg1 = _registerTable[(opcode&0xF)<<1];
+ _channelData.adlibReg2 = _registerTable[((opcode&0xF)<<1)|1];
+ }
+ } else {
+ _channelData.lastCommand = opcode;
+ stopNote();
+ // not sure why this "if" is necessary...either a bug in my
+ // code or a bug in the music data (section 1, music 2)
+ if (_channelData.instrumentData || _channelData.tremoVibro) {
+ setupInstrument(opcode);
+
+ opcode = _musicData[_channelData.eventDataPtr];
+ _channelData.eventDataPtr++;
+ setupChannelVolume(opcode);
+ } else _channelData.eventDataPtr++;
+ }
+ if (_channelData.channelActive)
+ _channelData.nextEventTime += getNextEventTime();
+ }
+ return returnVal;
+}
+
+void AdlibChannel::setupInstrument(uint8 opcode) {
+
+ uint16 nextNote;
+ if (_channelData.tremoVibro) {
+ uint8 newInstrument = _instrumentMap[opcode];
+ if (newInstrument != _channelData.assignedInstrument) {
+ _channelData.assignedInstrument = newInstrument;
+ _channelData.instrumentData = _instruments + newInstrument;
+ adlibSetupInstrument();
+ }
+ _channelData.lastCommand = _channelData.instrumentData->bindedEffect;
+ nextNote = getNextNote(_channelData.lastCommand);
+ } else {
+ nextNote = getNextNote(opcode - 0x18 + _channelData.instrumentData->bindedEffect);
+ }
+ _channelData.frequency = nextNote;
+ setRegister(0xA0 | _channelData.adlibChannelNumber, (uint8)nextNote);
+ setRegister(0xB0 | _channelData.adlibChannelNumber, (uint8)((nextNote >> 8) | 0x20));
+ _channelData.note = (uint8)((nextNote >> 8) | 0x20);
+}
+
+void AdlibChannel::setupChannelVolume(uint8 volume) {
+
+ uint8 resultOp;
+ uint32 resVol = ((volume + 1) * (_channelData.instrumentData->totOutLev_Op2 + 1)) << 1;
+ resVol &= 0xFFFF;
+ resVol *= (_channelData.channelVolume+1)<<1;
+ resVol >>= 8;
+ resVol *= _musicVolume;
+ resVol >>= 16;
+ resultOp = ((_channelData.instrumentData->scalingLevel << 6) & 0xC0) | _opOutputTable[resVol];
+ setRegister(0x40 | _channelData.adlibReg2, resultOp);
+ if (_channelData.instrumentData->feedBack & 1) {
+ resVol = ((volume + 1) * (_channelData.instrumentData->totOutLev_Op1 + 1)) << 1;
+ resVol &= 0xFFFF;
+ resVol *= (_channelData.channelVolume + 1)<<1;
+ resVol >>= 8;
+ resVol *= (_musicVolume & 0xFF);
+ resVol >>= 16;
+ } else resVol = _channelData.instrumentData->totOutLev_Op1;
+ resultOp = ((_channelData.instrumentData->scalingLevel << 2) & 0xC0) | _opOutputTable[resVol];
+ setRegister(0x40 | _channelData.adlibReg1, resultOp);
+}
+
+void AdlibChannel::adlibSetupInstrument(void) {
+
+ setRegister(0x60 | _channelData.adlibReg1, _channelData.instrumentData->ad_Op1);
+ setRegister(0x60 | _channelData.adlibReg2, _channelData.instrumentData->ad_Op2);
+ setRegister(0x80 | _channelData.adlibReg1, _channelData.instrumentData->sr_Op1);
+ setRegister(0x80 | _channelData.adlibReg2, _channelData.instrumentData->sr_Op2);
+ setRegister(0xE0 | _channelData.adlibReg1, _channelData.instrumentData->waveSelect_Op1);
+ setRegister(0xE0 | _channelData.adlibReg2, _channelData.instrumentData->waveSelect_Op2);
+ setRegister(0xC0 | _channelData.adlibChannelNumber, _channelData.instrumentData->feedBack);
+ setRegister(0x20 | _channelData.adlibReg1, _channelData.instrumentData->ampMod_Op1);
+ setRegister(0x20 | _channelData.adlibReg2, _channelData.instrumentData->ampMod_Op2);
+}
+
+#ifdef SCUMM_BIG_ENDIAN
+#define ENDIAN16(x) ((x >> 8) | ((x & 0xFF) << 8))
+#else
+#define ENDIAN16(x) (x)
+#endif
+
+uint16 AdlibChannel::getNextNote(uint8 param) {
+
+ int16 freqIndex = ((int16)_channelData.freqOffset) - 0x40;
+ if (freqIndex >= 0x3F) freqIndex++;
+ freqIndex *= _channelData.freqDataSize;
+ freqIndex += param<<6;
+ uint16 freqData = ENDIAN16(_frequenceTable[freqIndex % 0x300]);
+ if ((freqIndex%0x300 >= 0x1C0) || (freqIndex/0x300 > 0)) {
+ return (((freqIndex / 0x300) - 1) << 10) + (freqData & 0x7FF);
+ } else {
+ // looks like a bug. dunno why. It's what the ASM code says.
+ return (uint16)(((int16)freqData) >> 1);
+ }
+}
+
+//- command 90h routines
+
+void AdlibChannel::com90_caseNoteOff(void) {
+
+ if (_musicData[_channelData.eventDataPtr] == _channelData.lastCommand)
+ stopNote();
+ _channelData.eventDataPtr++;
+}
+
+void AdlibChannel::com90_stopChannel(void) {
+
+ stopNote();
+ _channelData.channelActive = 0;
+}
+
+void AdlibChannel::com90_setupInstrument(void) {
+
+ _channelData.channelVolume = 0x7F;
+ _channelData.freqOffset = 0x40;
+ _channelData.assignedInstrument = _musicData[_channelData.eventDataPtr];
+ _channelData.eventDataPtr++;
+ _channelData.instrumentData = _instruments + _channelData.assignedInstrument;
+ adlibSetupInstrument();
+}
+
+uint8 AdlibChannel::com90_updateTempo(void) {
+
+ uint8 retV = _musicData[_channelData.eventDataPtr];
+ _channelData.eventDataPtr++;
+ return retV;
+}
+
+void AdlibChannel::com90_getFreqOffset(void) {
+
+ _channelData.freqOffset = _musicData[_channelData.eventDataPtr];
+ _channelData.eventDataPtr++;
+ if (_channelData.note & 0x20) {
+ uint16 nextNote = getNextNote(
+ _channelData.lastCommand - 0x18 + _channelData.instrumentData->bindedEffect);
+ setRegister(0xA0 | _channelData.adlibChannelNumber, (uint8)nextNote);
+ setRegister(0xB0 | _channelData.adlibChannelNumber, (uint8)((nextNote >> 8) | 0x20));
+ _channelData.note = (uint8)(nextNote >> 8) | 0x20;
+ }
+}
+
+void AdlibChannel::com90_getChannelVolume(void) {
+
+ _channelData.channelVolume = _musicData[_channelData.eventDataPtr];
+ _channelData.eventDataPtr++;
+}
+
+void AdlibChannel::com90_getTremoVibro(void) {
+
+ _channelData.tremoVibro = _musicData[_channelData.eventDataPtr];
+ _channelData.eventDataPtr++;
+}
+
+void AdlibChannel::com90_rewindMusic(void) {
+
+ _channelData.eventDataPtr = _channelData.startOfData;
+}
+
+void AdlibChannel::com90_keyOff(void) {
+
+ stopNote();
+}
+
+void AdlibChannel::com90_setStartOfData(void) {
+
+ _channelData.startOfData = _channelData.eventDataPtr;
+}
+
+} // End of namespace Sky
diff --git a/engines/sky/music/adlibchannel.h b/engines/sky/music/adlibchannel.h
new file mode 100644
index 0000000000..661f3a20dc
--- /dev/null
+++ b/engines/sky/music/adlibchannel.h
@@ -0,0 +1,106 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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 ADLIBCHANNEL_H
+#define ADLIBCHANNEL_H
+
+#include "sky/music/musicbase.h"
+#include "sound/fmopl.h"
+
+namespace Sky {
+
+typedef struct {
+ uint8 ad_Op1, ad_Op2;
+ uint8 sr_Op1, sr_Op2;
+ uint8 ampMod_Op1, ampMod_Op2;
+ uint8 waveSelect_Op1, waveSelect_Op2;
+ uint8 bindedEffect;
+ uint8 feedBack;
+ uint8 totOutLev_Op1, totOutLev_Op2;
+ uint8 scalingLevel;
+ uint8 pad1, pad2, pad3;
+} InstrumentStruct;
+
+typedef struct {
+ uint16 eventDataPtr;
+ int32 nextEventTime;
+ uint16 startOfData;
+ uint8 adlibChannelNumber;
+ uint8 lastCommand;
+ uint8 channelActive;
+ uint8 note;
+ uint8 adlibReg1, adlibReg2;
+ InstrumentStruct *instrumentData;
+ uint8 assignedInstrument;
+ uint8 channelVolume;
+ uint8 padding; // field_12 / not used by original driver
+ uint8 tremoVibro;
+ uint8 freqDataSize;
+ uint8 freqOffset;
+ uint16 frequency;
+} AdlibChannelType;
+
+class AdlibChannel : public ChannelBase {
+public:
+ AdlibChannel (FM_OPL *opl, uint8 *pMusicData, uint16 startOfData);
+ virtual void stopNote(void);
+ virtual uint8 process(uint16 aktTime);
+ virtual void updateVolume(uint16 pVolume);
+ virtual bool isActive(void);
+private:
+ FM_OPL *_opl;
+ uint8 *_musicData;
+ uint16 _musicVolume;
+ AdlibChannelType _channelData;
+ //-
+ InstrumentStruct *_instruments;
+ uint16 *_frequenceTable;
+ uint8 *_instrumentMap;
+ uint8 *_registerTable, *_opOutputTable;
+ uint8 *_adlibRegMirror;
+ //- normal subs
+ void setRegister(uint8 regNum, uint8 value);
+ int32 getNextEventTime(void);
+ uint16 getNextNote(uint8 param);
+ void adlibSetupInstrument(void);
+ void setupInstrument(uint8 opcode);
+ void setupChannelVolume(uint8 volume);
+ //- Streamfunctions from Command90hTable
+ void com90_caseNoteOff(void); // 0
+ void com90_stopChannel(void); // 1
+ void com90_setupInstrument(void); // 2
+ uint8 com90_updateTempo(void); // 3
+ //void com90_dummy(void); // 4
+ void com90_getFreqOffset(void); // 5
+ void com90_getChannelVolume(void); // 6
+ void com90_getTremoVibro(void); // 7
+ void com90_rewindMusic(void); // 8
+ void com90_keyOff(void); // 9
+ //void com90_error(void); // 10
+ //void com90_doLodsb(void); // 11
+ void com90_setStartOfData(void); // 12
+ //void com90_do_two_Lodsb(void); // 13
+};
+
+} // End of namespace Sky
+
+#endif //ADLIBCHANNEL_H
diff --git a/engines/sky/music/adlibmusic.cpp b/engines/sky/music/adlibmusic.cpp
new file mode 100644
index 0000000000..e7ee4ecb6d
--- /dev/null
+++ b/engines/sky/music/adlibmusic.cpp
@@ -0,0 +1,121 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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 "sky/music/adlibmusic.h"
+#include "sky/music/adlibchannel.h"
+#include "sound/mixer.h"
+#include "sky/sky.h"
+
+namespace Sky {
+
+AdlibMusic::AdlibMusic(Audio::Mixer *pMixer, Disk *pDisk)
+ : MusicBase(pDisk) {
+
+ _driverFileBase = 60202;
+ _mixer = pMixer;
+ _sampleRate = pMixer->getOutputRate();
+
+ _opl = makeAdlibOPL(_sampleRate);
+
+ _mixer->setupPremix(this);
+}
+
+AdlibMusic::~AdlibMusic(void) {
+
+ _mixer->setupPremix(0);
+}
+
+void AdlibMusic::premixerCall(int16 *data, uint len) {
+
+ if (_musicData == NULL) {
+ // no music loaded
+ memset(data, 0, 2 * len * sizeof(int16));
+ } else if ((_currentMusic == 0) || (_numberOfChannels == 0)) {
+ // music loaded but not played as of yet
+ memset(data, 0, 2 * len * sizeof(int16));
+ // poll anyways as pollMusic() can activate the music
+ pollMusic();
+ _nextMusicPoll = _sampleRate/50;
+ } else {
+ uint32 render;
+ int16 *origData = data;
+ uint origLen = len;
+ while (len) {
+ render = (len > _nextMusicPoll) ? (_nextMusicPoll) : (len);
+ len -= render;
+ _nextMusicPoll -= render;
+ YM3812UpdateOne(_opl, data, render);
+ data += render;
+ if (_nextMusicPoll == 0) {
+ pollMusic();
+ _nextMusicPoll = _sampleRate/50;
+ }
+ }
+
+ // Convert mono data to stereo
+ for (int i = (origLen - 1); i >= 0; i--) {
+ origData[2 * i] = origData[2 * i + 1] = origData[i];
+ }
+ }
+}
+
+void AdlibMusic::setupPointers(void) {
+
+ if (SkyEngine::_systemVars.gameVersion == 109) {
+ // disk demo uses a different adlib driver version, some offsets have changed
+ //_musicDataLoc = (_musicData[0x11CC] << 8) | _musicData[0x11CB];
+ //_initSequence = _musicData + 0xEC8;
+
+ _musicDataLoc = READ_LE_UINT16(_musicData + 0x1200);
+ _initSequence = _musicData + 0xEFB;
+ } else if (SkyEngine::_systemVars.gameVersion == 267) {
+ _musicDataLoc = READ_LE_UINT16(_musicData + 0x11F7);
+ _initSequence = _musicData + 0xE87;
+ } else {
+ _musicDataLoc = READ_LE_UINT16(_musicData + 0x1201);
+ _initSequence = _musicData + 0xE91;
+ }
+ _nextMusicPoll = 0;
+}
+
+void AdlibMusic::setupChannels(uint8 *channelData) {
+
+ _numberOfChannels = channelData[0];
+ channelData++;
+ for (uint8 cnt = 0; cnt < _numberOfChannels; cnt++) {
+ uint16 chDataStart = ((channelData[(cnt << 1) | 1] << 8) | channelData[cnt << 1]) + _musicDataLoc;
+ _channels[cnt] = new AdlibChannel(_opl, _musicData, chDataStart);
+ _channels[cnt]->updateVolume(_musicVolume);
+ }
+}
+
+void AdlibMusic::startDriver(void) {
+
+ uint16 cnt = 0;
+ while (_initSequence[cnt] || _initSequence[cnt+1]) {
+ OPLWriteReg (_opl, _initSequence[cnt], _initSequence[cnt+1]);
+ cnt += 2;
+ }
+ _allowedCommands = 0xD;
+}
+
+} // End of namespace Sky
diff --git a/engines/sky/music/adlibmusic.h b/engines/sky/music/adlibmusic.h
new file mode 100644
index 0000000000..effa19dc51
--- /dev/null
+++ b/engines/sky/music/adlibmusic.h
@@ -0,0 +1,64 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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 ADLIBMUSIC_H
+#define ADLIBMUSIC_H
+
+#include "sky/music/musicbase.h"
+#include "sound/audiostream.h"
+#include "sound/fmopl.h"
+
+namespace Audio {
+ class Mixer;
+}
+
+namespace Sky {
+
+class AdlibMusic : public AudioStream, public MusicBase {
+public:
+ AdlibMusic(Audio::Mixer *pMixer, Disk *pDisk);
+ ~AdlibMusic(void);
+
+ // AudioStream API
+ int readBuffer(int16 *buffer, const int numSamples) {
+ premixerCall(buffer, numSamples / 2);
+ return numSamples;
+ }
+ bool isStereo() const { return true; }
+ bool endOfData() const { return false; }
+ int getRate() const { return _sampleRate; }
+
+private:
+ FM_OPL *_opl;
+ Audio::Mixer *_mixer;
+ uint8 *_initSequence;
+ uint32 _sampleRate, _nextMusicPoll;
+ virtual void setupPointers(void);
+ virtual void setupChannels(uint8 *channelData);
+ virtual void startDriver(void);
+
+ void premixerCall(int16 *buf, uint len);
+};
+
+} // End of namespace Sky
+
+#endif //ADLIBMUSIC_H
diff --git a/engines/sky/music/gmchannel.cpp b/engines/sky/music/gmchannel.cpp
new file mode 100644
index 0000000000..66fbdfb69f
--- /dev/null
+++ b/engines/sky/music/gmchannel.cpp
@@ -0,0 +1,217 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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 "gmchannel.h"
+#include "common/util.h"
+#include "sound/mididrv.h"
+
+namespace Sky {
+
+GmChannel::GmChannel(uint8 *pMusicData, uint16 startOfData, MidiDriver *pMidiDrv, const byte *pInstMap, const byte *veloTab) {
+
+ _musicData = pMusicData;
+ _midiDrv = pMidiDrv;
+ _channelData.midiChannelNumber = 0;
+ _channelData.startOfData = startOfData;
+ _channelData.eventDataPtr = startOfData;
+ _channelData.channelActive = 1;
+ _channelData.nextEventTime = getNextEventTime();
+ _instMap = pInstMap;
+ _veloTab = veloTab;
+
+ _musicVolume = 0x7F;
+ _lastVolume = 0xFF;
+}
+
+bool GmChannel::isActive(void) {
+
+ return _channelData.channelActive != 0;
+}
+
+void GmChannel::updateVolume(uint16 pVolume) {
+
+ _musicVolume = pVolume;
+ if (_musicVolume > 0)
+ _musicVolume = (_musicVolume * 2) / 3 + 43;
+ if (_lastVolume < 0xFF) {
+ uint8 newVol = (_lastVolume * _musicVolume) >> 7;
+ _midiDrv->send((0xB0 | _channelData.midiChannelNumber) | 0x700 | (newVol << 16));
+ }
+}
+
+void GmChannel::stopNote(void) {
+
+ // All Notes Off
+ _midiDrv->send((0xB0 | _channelData.midiChannelNumber) | 0x7B00 | 0 | 0x79000000);
+ // Reset the Pitch Wheel. See bug #1016556.
+ _midiDrv->send((0xE0 | _channelData.midiChannelNumber) | 0x400000);
+}
+
+int32 GmChannel::getNextEventTime(void) {
+
+ int32 retV = 0;
+ uint8 cnt, lVal = 0;
+ for (cnt = 0; cnt < 4; cnt++) {
+ lVal = _musicData[_channelData.eventDataPtr];
+ _channelData.eventDataPtr++;
+ retV = (retV << 7) | (lVal & 0x7F);
+ if (!(lVal & 0x80)) break;
+ }
+ if (lVal & 0x80) { // should never happen
+ return -1;
+ } else return retV;
+
+}
+
+uint8 GmChannel::process(uint16 aktTime) {
+
+ if (!_channelData.channelActive)
+ return 0;
+
+ uint8 returnVal = 0;
+
+ _channelData.nextEventTime -= aktTime;
+ uint8 opcode;
+
+ while ((_channelData.nextEventTime < 0) && (_channelData.channelActive)) {
+ opcode = _musicData[_channelData.eventDataPtr];
+ _channelData.eventDataPtr++;
+ if (opcode&0x80) {
+ if (opcode == 0xFF) {
+ // dummy opcode
+ } else if (opcode >= 0x90) {
+ switch (opcode&0xF) {
+ case 0: com90_caseNoteOff(); break;
+ case 1: com90_stopChannel(); break;
+ case 2: com90_setupInstrument(); break;
+ case 3:
+ returnVal = com90_updateTempo();
+ break;
+ case 5: com90_getPitch(); break;
+ case 6: com90_getChannelVolume(); break;
+ case 8: com90_rewindMusic(); break;
+ case 9: com90_keyOff(); break;
+ case 11: com90_getChannelPanValue(); break;
+ case 12: com90_setStartOfData(); break;
+ case 13: com90_getChannelControl(); break;
+ case 4: //com90_dummy();
+ case 7: //com90_skipTremoVibro();
+ case 10: //com90_error();
+ error("Channel: dummy music routine 0x%02X was called",opcode);
+ _channelData.channelActive = 0;
+ break;
+ default:
+ // these opcodes aren't implemented in original music driver
+ error("Channel: Not existent routine 0x%02X was called",opcode);
+ _channelData.channelActive = 0;
+ break;
+ }
+ } else {
+ // new midi channel assignment
+ _channelData.midiChannelNumber = opcode&0xF;
+ }
+ } else {
+ _channelData.note = opcode;
+ byte velocity = _musicData[_channelData.eventDataPtr];
+ if (_veloTab)
+ velocity = _veloTab[velocity];
+ _channelData.eventDataPtr++;
+ _midiDrv->send((0x90 | _channelData.midiChannelNumber) | (opcode << 8) | (velocity << 16));
+ }
+ if (_channelData.channelActive)
+ _channelData.nextEventTime += getNextEventTime();
+ }
+ return returnVal;
+}
+
+//- command 90h routines
+
+void GmChannel::com90_caseNoteOff(void) {
+
+ _midiDrv->send((0x90 | _channelData.midiChannelNumber) | (_musicData[_channelData.eventDataPtr] << 8));
+ _channelData.eventDataPtr++;
+}
+
+void GmChannel::com90_stopChannel(void) {
+
+ stopNote();
+ _channelData.channelActive = 0;
+}
+
+void GmChannel::com90_setupInstrument(void) {
+ byte instrument = _musicData[_channelData.eventDataPtr];
+ if (_instMap)
+ instrument = _instMap[instrument];
+ _midiDrv->send((0xC0 | _channelData.midiChannelNumber) | (instrument << 8));
+ _channelData.eventDataPtr++;
+}
+
+uint8 GmChannel::com90_updateTempo(void) {
+
+ uint8 retV = _musicData[_channelData.eventDataPtr];
+ _channelData.eventDataPtr++;
+ return retV;
+}
+
+void GmChannel::com90_getPitch(void) {
+
+ _midiDrv->send((0xE0 | _channelData.midiChannelNumber) | 0 | (_musicData[_channelData.eventDataPtr] << 16));
+ _channelData.eventDataPtr++;
+}
+
+void GmChannel::com90_getChannelVolume(void) {
+
+ _lastVolume = _musicData[_channelData.eventDataPtr];
+ uint8 newVol = (uint8)((_musicData[_channelData.eventDataPtr++] * _musicVolume) >> 7);
+ _midiDrv->send((0xB0 | _channelData.midiChannelNumber) | 0x700 | (newVol << 16));
+}
+
+void GmChannel::com90_rewindMusic(void) {
+
+ _channelData.eventDataPtr = _channelData.startOfData;
+}
+
+void GmChannel::com90_keyOff(void) {
+
+ _midiDrv->send((0x90 | _channelData.midiChannelNumber) | (_channelData.note << 8) | 0);
+}
+
+void GmChannel::com90_setStartOfData(void) {
+
+ _channelData.startOfData = _channelData.eventDataPtr;
+}
+
+void GmChannel::com90_getChannelPanValue(void) {
+
+ _midiDrv->send((0xB0 | _channelData.midiChannelNumber) | 0x0A00 | (_musicData[_channelData.eventDataPtr] << 16));
+ _channelData.eventDataPtr++;
+}
+
+void GmChannel::com90_getChannelControl(void) {
+
+ uint8 conNum = _musicData[_channelData.eventDataPtr];
+ uint8 conDat = _musicData[_channelData.eventDataPtr + 1];
+ _channelData.eventDataPtr += 2;
+ _midiDrv->send((0xB0 | _channelData.midiChannelNumber) | (conNum << 8) | (conDat << 16));
+}
+
+} // End of namespace Sky
diff --git a/engines/sky/music/gmchannel.h b/engines/sky/music/gmchannel.h
new file mode 100644
index 0000000000..051b5d0648
--- /dev/null
+++ b/engines/sky/music/gmchannel.h
@@ -0,0 +1,82 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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 SKYGMCHANNEL_H
+#define SKYGMCHANNEL_H
+
+#include "sky/music/musicbase.h"
+
+class MidiDriver;
+
+namespace Sky {
+
+typedef struct {
+ uint16 eventDataPtr;
+ int32 nextEventTime;
+ uint16 startOfData;
+ uint8 midiChannelNumber;
+ uint8 note;
+ uint8 channelActive;
+} MidiChannelType;
+
+class GmChannel : public ChannelBase {
+public:
+ GmChannel(uint8 *pMusicData, uint16 startOfData, MidiDriver *pMidiDrv, const byte *pInstMap, const byte *veloTab);
+ virtual void stopNote(void);
+ virtual uint8 process(uint16 aktTime);
+ virtual void updateVolume(uint16 pVolume);
+ virtual bool isActive(void);
+private:
+ const byte *_instMap;
+ const byte *_veloTab;
+ MidiDriver *_midiDrv;
+ uint8 *_musicData;
+ uint16 _musicVolume;
+ MidiChannelType _channelData;
+ uint8 _lastVolume;
+ //- normal subs
+ void setRegister(uint8 regNum, uint8 value);
+ int32 getNextEventTime(void);
+ uint16 getNextNote(uint8 param);
+ void adlibSetupInstrument(void);
+ void setupInstrument(uint8 opcode);
+ void setupChannelVolume(uint8 volume);
+ //- Streamfunctions from Command90hTable
+ void com90_caseNoteOff(void); // 0
+ void com90_stopChannel(void); // 1
+ void com90_setupInstrument(void); // 2
+ uint8 com90_updateTempo(void); // 3
+ //void com90_dummy(void); // 4
+ void com90_getPitch(void); // 5
+ void com90_getChannelVolume(void); // 6
+ //void com90_skipTremoVibro(void); // 7
+ void com90_rewindMusic(void); // 8
+ void com90_keyOff(void); // 9
+ //void com90_error(void); // 10
+ void com90_getChannelPanValue(void); // 11
+ void com90_setStartOfData(void); // 12
+ void com90_getChannelControl(void); // 13
+};
+
+} // End of namespace Sky
+
+#endif //SKYGMCHANNEL_H
diff --git a/engines/sky/music/gmmusic.cpp b/engines/sky/music/gmmusic.cpp
new file mode 100644
index 0000000000..bedb8acc7c
--- /dev/null
+++ b/engines/sky/music/gmmusic.cpp
@@ -0,0 +1,118 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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 "sky/music/gmmusic.h"
+#include "sky/music/gmchannel.h"
+#include "sky/sky.h"
+#include "common/util.h"
+#include "sound/mididrv.h"
+
+namespace Sky {
+
+void GmMusic::passTimerFunc(void *param) {
+
+ ((GmMusic*)param)->timerCall();
+}
+
+GmMusic::GmMusic(MidiDriver *pMidiDrv, Disk *pDisk)
+ : MusicBase(pDisk) {
+
+ _driverFileBase = 60200;
+ _midiDrv = pMidiDrv;
+ int midiRes = _midiDrv->open();
+ if (midiRes != 0)
+ error("Can't open midi device. Errorcode: %d", midiRes);
+ _timerCount = 0;
+ _midiDrv->setTimerCallback(this, passTimerFunc);
+}
+
+GmMusic::~GmMusic(void) {
+
+ _midiDrv->setTimerCallback(NULL, NULL);
+ if (_currentMusic)
+ stopMusic();
+ // Send All Sound Off and All Notes Off (for external synths)
+ for (int i = 0; i < 16; ++i) {
+ _midiDrv->send ((120 << 8) | 0xB0 | i);
+ _midiDrv->send ((123 << 8) | 0xB0 | i);
+ }
+ _midiDrv->close();
+ delete _midiDrv;
+}
+
+void GmMusic::timerCall(void) {
+ _timerCount += _midiDrv->getBaseTempo();
+ if (_timerCount > (1000000 / 50)) {
+ // call pollMusic() 50 times per second
+ _timerCount -= 1000000 / 50;
+ if (_musicData != NULL)
+ pollMusic();
+ }
+}
+
+void GmMusic::setupPointers(void) {
+
+ if (SkyEngine::_systemVars.gameVersion == 109) {
+ _musicDataLoc = (_musicData[0x79C] << 8) | _musicData[0x79B];
+ _sysExSequence = _musicData + 0x1EF2;
+ } else {
+ _musicDataLoc = (_musicData[0x7DD] << 8) | _musicData[0x7DC];
+ _sysExSequence = ((_musicData[0x7E1] << 8) | _musicData[0x7E0]) + _musicData;
+ }
+}
+
+void GmMusic::setupChannels(uint8 *channelData) {
+
+ _numberOfChannels = channelData[0];
+ channelData++;
+ for (uint8 cnt = 0; cnt < _numberOfChannels; cnt++) {
+ uint16 chDataStart = ((channelData[(cnt << 1) | 1] << 8) | channelData[cnt << 1]) + _musicDataLoc;
+ _channels[cnt] = new GmChannel(_musicData, chDataStart, _midiDrv, MidiDriver::_mt32ToGm, _veloTab);
+ _channels[cnt]->updateVolume(_musicVolume);
+ }
+}
+
+void GmMusic::startDriver(void) {
+ // Send GM System On to reset channel parameters on external and capa$
+ uint8 sysEx[] = "\xf0\x7e\x7f\x09\x01\xf7";
+ _midiDrv->sysEx(sysEx, 6);
+ //_midiDrv->send(0xFF); //ALSA can't handle this.
+ // skip all sysEx as it can't be handled anyways.
+}
+
+const byte GmMusic::_veloTab[128] = {
+ 0x00, 0x40, 0x41, 0x41, 0x42, 0x42, 0x43, 0x43, 0x44, 0x44,
+ 0x45, 0x45, 0x46, 0x46, 0x47, 0x47, 0x48, 0x48, 0x49, 0x49,
+ 0x4A, 0x4A, 0x4B, 0x4B, 0x4C, 0x4C, 0x4D, 0x4D, 0x4E, 0x4E,
+ 0x4F, 0x4F, 0x50, 0x50, 0x51, 0x51, 0x52, 0x52, 0x53, 0x53,
+ 0x54, 0x54, 0x55, 0x55, 0x56, 0x56, 0x57, 0x57, 0x58, 0x58,
+ 0x59, 0x59, 0x5A, 0x5A, 0x5B, 0x5B, 0x5C, 0x5C, 0x5D, 0x5D,
+ 0x5E, 0x5E, 0x5F, 0x5F, 0x60, 0x60, 0x61, 0x61, 0x62, 0x62,
+ 0x63, 0x63, 0x64, 0x64, 0x65, 0x65, 0x66, 0x66, 0x67, 0x67,
+ 0x68, 0x68, 0x69, 0x69, 0x6A, 0x6A, 0x6B, 0x6B, 0x6C, 0x6C,
+ 0x6D, 0x6D, 0x6E, 0x6E, 0x6F, 0x6F, 0x70, 0x70, 0x71, 0x71,
+ 0x72, 0x72, 0x73, 0x73, 0x74, 0x74, 0x75, 0x75, 0x76, 0x76,
+ 0x77, 0x77, 0x78, 0x78, 0x79, 0x79, 0x7A, 0x7A, 0x7B, 0x7B,
+ 0x7C, 0x7C, 0x7D, 0x7D, 0x7E, 0x7E, 0x7F, 0x7F
+};
+
+} // End of namespace Sky
diff --git a/engines/sky/music/gmmusic.h b/engines/sky/music/gmmusic.h
new file mode 100644
index 0000000000..2623c6b5cd
--- /dev/null
+++ b/engines/sky/music/gmmusic.h
@@ -0,0 +1,52 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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 GMMUSIC_H
+#define GMMUSIC_H
+
+#include "sky/music/musicbase.h"
+
+class MidiDriver;
+
+namespace Sky {
+
+class GmMusic : public MusicBase {
+public:
+ GmMusic(MidiDriver *pMidiDrv, Disk *pDisk);
+ ~GmMusic(void);
+private:
+ static void passTimerFunc(void *param);
+ void timerCall(void);
+
+ uint32 _timerCount;
+ uint8 *_sysExSequence;
+ MidiDriver *_midiDrv;
+ static const byte _veloTab[128];
+
+ virtual void setupPointers(void);
+ virtual void setupChannels(uint8 *channelData);
+ virtual void startDriver(void);
+};
+
+} // End of namespace Sky
+
+#endif //GMMUSIC_H
diff --git a/engines/sky/music/mt32music.cpp b/engines/sky/music/mt32music.cpp
new file mode 100644
index 0000000000..a6bcbf4d05
--- /dev/null
+++ b/engines/sky/music/mt32music.cpp
@@ -0,0 +1,169 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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 "sky/music/mt32music.h"
+#include "sky/music/gmchannel.h"
+#include "common/util.h"
+#include "common/system.h"
+#include "sound/mididrv.h"
+
+namespace Sky {
+
+void MT32Music::passTimerFunc(void *param) {
+
+ ((MT32Music*)param)->timerCall();
+}
+
+MT32Music::MT32Music(MidiDriver *pMidiDrv, Disk *pDisk)
+ : MusicBase(pDisk) {
+
+ _driverFileBase = 60200;
+ _midiDrv = pMidiDrv;
+ int midiRes = _midiDrv->open();
+ if (midiRes != 0)
+ error("Can't open midi device. Errorcode: %d",midiRes);
+ _timerCount = 0;
+ _midiDrv->setTimerCallback(this, passTimerFunc);
+}
+
+MT32Music::~MT32Music(void) {
+
+ _midiDrv->close();
+ _midiDrv->setTimerCallback(NULL, NULL);
+ delete _midiDrv;
+}
+
+void MT32Music::timerCall(void) {
+ _timerCount += _midiDrv->getBaseTempo();
+ if (_timerCount > (1000000 / 50)) {
+ // call pollMusic() 50 times per second
+ _timerCount -= 1000000 / 50;
+ if (_musicData != NULL)
+ pollMusic();
+ }
+}
+
+void MT32Music::setVolume(uint8 volume) {
+ uint8 sysEx[10] = "\x41\x10\x16\x12\x10\x00\x16\x00\x00";
+ _musicVolume = volume;
+ sysEx[7] = (volume > 100) ? 100 : volume;
+ sysEx[8] = 0x00;
+ for (uint8 cnt = 4; cnt < 8; cnt++)
+ sysEx[8] -= sysEx[cnt];
+ sysEx[8] &= 0x7F;
+ _midiDrv->sysEx(sysEx, 9);
+}
+
+void MT32Music::setupPointers(void) {
+
+ _musicDataLoc = (_musicData[0x7DD] << 8) | _musicData[0x7DC];
+ _sysExSequence = ((_musicData[0x7E1] << 8) | _musicData[0x7E0]) + _musicData;
+}
+
+void MT32Music::setupChannels(uint8 *channelData) {
+
+ _numberOfChannels = channelData[0];
+ channelData++;
+ for (uint8 cnt = 0; cnt < _numberOfChannels; cnt++) {
+ uint16 chDataStart = ((channelData[(cnt << 1) | 1] << 8) | channelData[cnt << 1]) + _musicDataLoc;
+ _channels[cnt] = new GmChannel(_musicData, chDataStart, _midiDrv, NULL, NULL);
+ _channels[cnt]->updateVolume(_musicVolume);
+ }
+}
+
+bool MT32Music::processPatchSysEx(uint8 *sysExData) {
+
+ uint8 sysExBuf[15];
+ uint8 crc = 0;
+ if (sysExData[0] & 0x80)
+ return false;
+
+ // decompress data from stream
+ sysExBuf[0] = 0x41; sysExBuf[1] = 0x10; sysExBuf[2] = 0x16; sysExBuf[3] = 0x12; sysExBuf[4] = 0x5;
+ sysExBuf[5] = sysExData[0] >> 4; // patch offset part 1
+ sysExBuf[6] = (sysExData[0] & 0xF) << 3; // patch offset part 2
+ sysExBuf[7] = sysExData[1] >> 6; // timbre group
+ sysExBuf[8] = sysExData[1] & 0x3F; // timbre num
+ sysExBuf[9] = sysExData[2] & 0x3F; // key shift
+ sysExBuf[10] = sysExData[3] & 0x7F; // fine tune
+ sysExBuf[11] = sysExData[4] & 0x7F; // bender range
+ sysExBuf[12] = sysExData[2] >> 6; // assign mode
+ sysExBuf[13] = sysExData[3] >> 7; // reverb switch
+ for (uint8 cnt = 4; cnt < 14; cnt++)
+ crc -= sysExBuf[cnt];
+ sysExBuf[14] = crc & 0x7F; // crc
+ _midiDrv->sysEx(sysExBuf, 15);
+ g_system->delayMillis(5);
+ return true;
+}
+
+void MT32Music::startDriver(void) {
+
+ // setup timbres and patches using SysEx data
+ uint8* sysExData = _sysExSequence;
+ uint8 timbreNum = sysExData[0];
+ uint8 cnt, crc;
+ sysExData++;
+ uint8 sendBuf[256];
+ uint8 len;
+ sendBuf[0] = 0x41; sendBuf[1] = 0x10; sendBuf[2] = 0x16; sendBuf[3] = 0x12;
+ for (cnt = 0; cnt < timbreNum; cnt++) {
+ len = 7;
+ crc = 0;
+ // Timbre address
+ sendBuf[4] = 0x8 | (sysExData[0] >> 6);
+ sendBuf[5] = (sysExData[0] & 0x3F) << 1;
+ sendBuf[6] = 0xA;
+ sysExData++;
+ crc -= sendBuf[4] + sendBuf[5] + sendBuf[6];
+ uint8 dataLen = sysExData[0];
+ sysExData++;
+ // Timbre data:
+ do {
+ uint8 rlVal = 1;
+ uint8 codeVal = sysExData[0];
+ sysExData++;
+
+ if (codeVal & 0x80) {
+ codeVal &= 0x7F;
+ rlVal = sysExData[0];
+ sysExData++;
+ dataLen--;
+ }
+ for (uint8 cnt2 = 0; cnt2 < rlVal; cnt2++) {
+ sendBuf[len] = codeVal;
+ len++;
+ crc -= codeVal;
+ }
+ dataLen--;
+ } while (dataLen > 0);
+ sendBuf[len] = crc & 0x7F;
+ len++;
+ _midiDrv->sysEx(sendBuf, len);
+ g_system->delayMillis (5);
+ }
+
+ while (processPatchSysEx(sysExData))
+ sysExData += 5;
+}
+
+} // End of namespace Sky
diff --git a/engines/sky/music/mt32music.h b/engines/sky/music/mt32music.h
new file mode 100644
index 0000000000..a64663a15f
--- /dev/null
+++ b/engines/sky/music/mt32music.h
@@ -0,0 +1,53 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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 MT32MUSIC_H
+#define MT32MUSIC_H
+
+#include "sky/music/musicbase.h"
+
+class MidiDriver;
+
+namespace Sky {
+
+class MT32Music : public MusicBase {
+public:
+ MT32Music(MidiDriver *pMidiDrv, Disk *pDisk);
+ ~MT32Music(void);
+private:
+ static void passTimerFunc(void *param);
+ void timerCall(void);
+ bool processPatchSysEx(uint8 *sysExData);
+ virtual void setVolume(uint8 volume);
+
+ uint32 _timerCount;
+ uint8 *_sysExSequence;
+ MidiDriver *_midiDrv;
+
+ virtual void setupPointers(void);
+ virtual void setupChannels(uint8 *channelData);
+ virtual void startDriver(void);
+};
+
+} // End of namespace Sky
+
+#endif //MT32MUSIC_H
diff --git a/engines/sky/music/musicbase.cpp b/engines/sky/music/musicbase.cpp
new file mode 100644
index 0000000000..9d308ebc7f
--- /dev/null
+++ b/engines/sky/music/musicbase.cpp
@@ -0,0 +1,148 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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 "sky/music/musicbase.h"
+#include "sky/disk.h"
+#include "common/util.h"
+
+namespace Sky {
+
+MusicBase::MusicBase(Disk *pDisk) {
+
+ _musicData = NULL;
+ _allowedCommands = 0;
+ _skyDisk = pDisk;
+ _currentMusic = 0;
+ _musicVolume = 127;
+ _numberOfChannels = _currentMusic = 0;
+}
+
+MusicBase::~MusicBase(void) {
+
+ stopMusic();
+ if (_musicData)
+ free(_musicData);
+}
+
+void MusicBase::loadSection(uint8 pSection) {
+
+ _mutex.lock();
+ if (_currentMusic)
+ stopMusic();
+ if (_musicData)
+ free(_musicData);
+ _currentSection = pSection;
+ _musicData = _skyDisk->loadFile(_driverFileBase + FILES_PER_SECTION * pSection);
+ _allowedCommands = 0;
+ _musicTempo0 = 0x78; // init constants taken from idb file, area ~0x1060
+ _musicTempo1 = 0xC0;
+ _onNextPoll.doReInit = false;
+ _onNextPoll.doStopMusic = false;
+ _onNextPoll.musicToProcess = 0;
+ _tempo = _aktTime = 0x10001;
+ _numberOfChannels = _currentMusic = 0;
+ setupPointers();
+ startDriver();
+ _mutex.unlock();
+}
+
+bool MusicBase::musicIsPlaying(void) {
+
+ for (uint8 cnt = 0; cnt < _numberOfChannels; cnt++)
+ if (_channels[cnt]->isActive())
+ return true;
+ return false;
+}
+
+void MusicBase::setVolume(uint16 param) {
+
+ _musicVolume = param;
+ for (uint8 cnt = 0; cnt < _numberOfChannels; cnt++)
+ _channels[cnt]->updateVolume(_musicVolume);
+}
+
+void MusicBase::stopMusic(void) {
+
+ for (uint8 cnt = 0; cnt < _numberOfChannels; cnt++) {
+ _channels[cnt]->stopNote();
+ delete _channels[cnt];
+ }
+ _numberOfChannels = 0;
+}
+
+void MusicBase::updateTempo(void) {
+
+ uint16 tempoMul = _musicTempo0 * _musicTempo1;
+ uint16 divisor = 0x4446390/ 23864;
+ _tempo = (tempoMul / divisor) << 16;
+ _tempo |= (((tempoMul%divisor) << 16) | (tempoMul / divisor)) / divisor;
+}
+
+void MusicBase::loadNewMusic(void) {
+
+ uint16 musicPos;
+ if (_onNextPoll.musicToProcess > _musicData[_musicDataLoc]) {
+ error("Music %d requested but doesn't exist in file.", _onNextPoll.musicToProcess);
+ return;
+ }
+ if (_currentMusic != 0)
+ stopMusic();
+
+ _currentMusic = _onNextPoll.musicToProcess;
+
+ if (_currentMusic != 0) {
+ musicPos = (_musicData[_musicDataLoc + 2] << 8) | _musicData[_musicDataLoc+1];
+ musicPos += _musicDataLoc+((_currentMusic-1) << 1);
+ musicPos = ((_musicData[musicPos+1] << 8) | _musicData[musicPos]) + _musicDataLoc;
+
+ _musicTempo0 = _musicData[musicPos];
+ _musicTempo1 = _musicData[musicPos+1];
+
+ setupChannels(_musicData + musicPos + 2);
+
+ updateTempo();
+ }
+}
+
+void MusicBase::pollMusic(void) {
+
+ _mutex.lock();
+ uint8 newTempo;
+ if (_onNextPoll.doReInit) startDriver();
+ if (_onNextPoll.doStopMusic) stopMusic();
+ if (_onNextPoll.musicToProcess != _currentMusic)
+ loadNewMusic();
+
+ _aktTime += _tempo;
+
+ for (uint8 cnt = 0; cnt < _numberOfChannels; cnt++) {
+ newTempo = _channels[cnt]->process((uint16)(_aktTime >> 16));
+ if (newTempo) {
+ _musicTempo1 = newTempo;
+ updateTempo();
+ }
+ }
+ _mutex.unlock();
+ _aktTime &= 0xFFFF;
+}
+
+} // End of namespace Sky
diff --git a/engines/sky/music/musicbase.h b/engines/sky/music/musicbase.h
new file mode 100644
index 0000000000..d9f3e22beb
--- /dev/null
+++ b/engines/sky/music/musicbase.h
@@ -0,0 +1,92 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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 MUSICBASE_H
+#define MUSICBASE_H
+
+#include "common/stdafx.h"
+#include "common/scummsys.h"
+#include "common/mutex.h"
+
+namespace Sky {
+
+class Disk;
+
+#define FILES_PER_SECTION 4
+
+typedef struct {
+ bool doReInit, doStopMusic;
+ uint8 musicToProcess;
+} Actions;
+
+class ChannelBase {
+public:
+ virtual ~ChannelBase() {};
+ virtual void stopNote(void) = 0;
+ virtual uint8 process(uint16 aktTime) = 0;
+ virtual void updateVolume(uint16 pVolume) = 0;
+ virtual bool isActive(void) = 0;
+private:
+};
+
+class MusicBase {
+public:
+ MusicBase(Disk *pDisk);
+ virtual ~MusicBase(void);
+ void loadSection(uint8 pSection);
+ void startMusic(uint16 param) { _onNextPoll.musicToProcess = param & 0xF; }; // 4
+ void stopMusic(); // 7
+ bool musicIsPlaying(void);
+ uint8 giveVolume(void) { return (uint8)_musicVolume; };
+ uint8 giveCurrentMusic(void) { return _currentMusic; };
+ void setVolume(uint16 param);
+
+protected:
+
+ Disk *_skyDisk;
+ uint8 *_musicData;
+ uint8 _allowedCommands;
+ uint16 _musicDataLoc;
+ uint16 _driverFileBase;
+
+ uint16 _musicVolume, _numberOfChannels;
+ uint8 _currentMusic, _currentSection;
+ uint8 _musicTempo0; // can be changed by music stream
+ uint8 _musicTempo1; // given once per music
+ uint32 _tempo; // calculated from musicTempo0 and musicTempo1
+ uint32 _aktTime;
+ Actions _onNextPoll;
+ ChannelBase *_channels[10];
+ Common::Mutex _mutex;
+
+ virtual void setupPointers(void) = 0;
+ virtual void setupChannels(uint8 *channelData) = 0;
+ virtual void startDriver(void) = 0;
+
+ void updateTempo(void);
+ void loadNewMusic(void);
+ void pollMusic(void);
+};
+
+} // End of namespace Sky
+
+#endif //MUSICBASE_H
diff --git a/engines/sky/rnc_deco.cpp b/engines/sky/rnc_deco.cpp
new file mode 100644
index 0000000000..06b7721d74
--- /dev/null
+++ b/engines/sky/rnc_deco.cpp
@@ -0,0 +1,262 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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/scummsys.h"
+#include "sky/rnc_deco.h"
+
+namespace Sky {
+
+//return codes
+#define NOT_PACKED 0
+#define PACKED_CRC -1
+#define UNPACKED_CRC -2
+
+//other defines
+#define TABLE_SIZE (16 * 8)
+#define MIN_LENGTH 2
+#define HEADER_LEN 18
+
+RncDecoder::RncDecoder() {
+ initCrc();
+}
+
+RncDecoder::~RncDecoder() { }
+
+void RncDecoder::initCrc() {
+ uint16 cnt = 0;
+ uint16 tmp1 = 0;
+ uint16 tmp2 = 0;
+
+ for (tmp2 = 0; tmp2 < 0x100; tmp2++) {
+ tmp1 = tmp2;
+ for (cnt = 8; cnt > 0; cnt--) {
+ if (tmp1 % 2) {
+ tmp1 >>= 1;
+ tmp1 ^= 0x0a001;
+ } else
+ tmp1 >>= 1;
+ }
+ _crcTable[tmp2] = tmp1;
+ }
+}
+
+//calculate 16 bit crc of a block of memory
+uint16 RncDecoder::crcBlock(const uint8 *block, uint32 size) {
+ uint16 crc = 0;
+ uint8 *crcTable8 = (uint8 *)_crcTable; //make a uint8* to crc_table
+ uint8 tmp;
+ uint32 i;
+
+ for (i = 0; i < size; i++) {
+ tmp = *block++;
+ crc ^= tmp;
+ tmp = (uint8)((crc >> 8) & 0x00FF);
+ crc &= 0x00FF;
+ crc = *(uint16 *)&crcTable8[crc << 1];
+ crc ^= tmp;
+ }
+
+ return crc;
+}
+
+uint16 RncDecoder::inputBits(uint8 amount) {
+ uint16 newBitBuffh = _bitBuffh;
+ uint16 newBitBuffl = _bitBuffl;
+ int16 newBitCount = _bitCount;
+ uint16 remBits, returnVal;
+
+ returnVal = ((1 << amount) - 1) & newBitBuffl;
+ newBitCount -= amount;
+
+ if (newBitCount < 0) {
+ newBitCount += amount;
+ remBits = (newBitBuffh << (16 - newBitCount));
+ newBitBuffh >>= newBitCount;
+ newBitBuffl >>= newBitCount;
+ newBitBuffl |= remBits;
+ _srcPtr += 2;
+ newBitBuffh = READ_LE_UINT16(_srcPtr);
+ amount -= newBitCount;
+ newBitCount = 16 - amount;
+ }
+ remBits = (newBitBuffh << (16 - amount));
+ _bitBuffh = newBitBuffh >> amount;
+ _bitBuffl = (newBitBuffl >> amount) | remBits;
+ _bitCount = (uint8)newBitCount;
+
+ return returnVal;
+}
+
+void RncDecoder::makeHufftable(uint16 *table) {
+ uint16 bitLength, i, j;
+ uint16 numCodes = inputBits(5);
+
+ if (!numCodes)
+ return;
+
+ uint8 huffLength[16];
+ for (i = 0; i < numCodes; i++)
+ huffLength[i] = (uint8)(inputBits(4) & 0x00FF);
+
+ uint16 huffCode = 0;
+
+ for (bitLength = 1; bitLength < 17; bitLength++) {
+ for (i = 0; i < numCodes; i++) {
+ if (huffLength[i] == bitLength) {
+ *table++ = (1 << bitLength) - 1;
+
+ uint16 b = huffCode >> (16 - bitLength);
+ uint16 a = 0;
+
+ for (j = 0; j < bitLength; j++)
+ a |= ((b >> j) & 1) << (bitLength - j - 1);
+ *table++ = a;
+
+ *(table + 0x1e) = (huffLength[i] << 8) | (i & 0x00FF);
+ huffCode += 1 << (16 - bitLength);
+ }
+ }
+ }
+}
+
+uint16 RncDecoder::inputValue(uint16 *table) {
+ uint16 valOne, valTwo, value = _bitBuffl;
+
+ do {
+ valTwo = (*table++) & value;
+ valOne = *table++;
+
+ } while (valOne != valTwo);
+
+ value = *(table + 0x1e);
+ inputBits((uint8)((value>>8) & 0x00FF));
+ value &= 0x00FF;
+
+ if (value >= 2) {
+ value--;
+ valOne = inputBits((uint8)value & 0x00FF);
+ valOne |= (1 << value);
+ value = valOne;
+ }
+
+ return value;
+}
+
+int32 RncDecoder::unpackM1(const void *input, void *output, uint16 key) {
+ uint8 *outputLow, *outputHigh;
+ const uint8 *inputHigh, *inputptr = (const uint8 *)input;
+
+ uint32 unpackLen = 0;
+ uint32 packLen = 0;
+ uint16 counts = 0;
+ uint16 crcUnpacked = 0;
+ uint16 crcPacked = 0;
+
+
+ _bitBuffl = 0;
+ _bitBuffh = 0;
+ _bitCount = 0;
+
+ //Check for "RNC "
+ if (READ_BE_UINT32(inputptr) != RNC_SIGNATURE)
+ return NOT_PACKED;
+
+ inputptr += 4;
+
+ // read unpacked/packed file length
+ unpackLen = READ_BE_UINT32(inputptr); inputptr += 4;
+ packLen = READ_BE_UINT32(inputptr); inputptr += 4;
+
+ uint8 blocks = *(inputptr + 5);
+
+ //read CRC's
+ crcUnpacked = READ_BE_UINT16(inputptr); inputptr += 2;
+ crcPacked = READ_BE_UINT16(inputptr); inputptr += 2;
+ inputptr = (inputptr + HEADER_LEN - 16);
+
+ if (crcBlock(inputptr, packLen) != crcPacked)
+ return PACKED_CRC;
+
+ inputptr = (((const uint8 *)input) + HEADER_LEN);
+ _srcPtr = inputptr;
+
+ inputHigh = ((const uint8 *)input) + packLen + HEADER_LEN;;
+ outputLow = (uint8 *)output;
+ outputHigh = *(((const uint8 *)input) + 16) + unpackLen + outputLow;
+
+ if (! ((inputHigh <= outputLow) || (outputHigh <= inputHigh)) ) {
+ _srcPtr = inputHigh;
+ _dstPtr = outputHigh;
+ memcpy((_dstPtr-packLen), (_srcPtr-packLen), packLen);
+ _srcPtr = (_dstPtr-packLen);
+ }
+
+ _dstPtr = (uint8 *)output;
+ _bitCount = 0;
+
+ _bitBuffl = READ_LE_UINT16(_srcPtr);
+ inputBits(2);
+
+ do {
+ makeHufftable(_rawTable);
+ makeHufftable(_posTable);
+ makeHufftable(_lenTable);
+
+ counts = inputBits(16);
+
+ do {
+ uint32 inputLength = inputValue(_rawTable);
+ uint32 inputOffset;
+
+ if (inputLength) {
+ memcpy(_dstPtr, _srcPtr, inputLength); //memcpy is allowed here
+ _dstPtr += inputLength;
+ _srcPtr += inputLength;
+ uint16 a = READ_LE_UINT16(_srcPtr);
+ uint16 b = READ_LE_UINT16(_srcPtr + 2);
+
+ _bitBuffl &= ((1 << _bitCount) - 1);
+ _bitBuffl |= (a << _bitCount);
+ _bitBuffh = (a >> (16 - _bitCount)) | (b << _bitCount);
+ }
+
+ if (counts > 1) {
+ inputOffset = inputValue(_posTable) + 1;
+ inputLength = inputValue(_lenTable) + MIN_LENGTH;
+
+ // Don't use memcpy here! because input and output overlap.
+ uint8 *tmpPtr = (_dstPtr-inputOffset);
+ while (inputLength--)
+ *_dstPtr++ = *tmpPtr++;
+ }
+ } while (--counts);
+ } while (--blocks);
+
+ if (crcBlock((uint8 *)output, unpackLen) != crcUnpacked)
+ return UNPACKED_CRC;
+
+ // all is done..return the amount of unpacked bytes
+ return unpackLen;
+}
+
+} // End of namespace Sky
diff --git a/engines/sky/rnc_deco.h b/engines/sky/rnc_deco.h
new file mode 100644
index 0000000000..1a05d95531
--- /dev/null
+++ b/engines/sky/rnc_deco.h
@@ -0,0 +1,63 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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 RNC_DECO_H
+#define RNC_DECO_H
+
+#include "common/stdafx.h"
+
+#define RNC_SIGNATURE 0x524E4301 // "RNC\001"
+
+namespace Sky {
+
+class RncDecoder {
+
+protected:
+ uint16 _rawTable[64];
+ uint16 _posTable[64];
+ uint16 _lenTable[64];
+ uint16 _crcTable[256];
+
+ uint16 _bitBuffl;
+ uint16 _bitBuffh;
+ uint8 _bitCount;
+
+ const uint8 *_srcPtr;
+ uint8 *_dstPtr;
+
+public:
+ RncDecoder();
+ ~RncDecoder();
+ int32 unpackM1(const void *input, void *output, uint16 key);
+
+protected:
+ void initCrc();
+ uint16 crcBlock(const uint8 *block, uint32 size);
+ uint16 inputBits(uint8 amount);
+ void makeHufftable(uint16 *table);
+ uint16 inputValue(uint16 *table);
+
+};
+
+} // End of namespace Sky
+
+#endif
diff --git a/engines/sky/screen.cpp b/engines/sky/screen.cpp
new file mode 100644
index 0000000000..8688969de5
--- /dev/null
+++ b/engines/sky/screen.cpp
@@ -0,0 +1,822 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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 "sky/disk.h"
+#include "sky/logic.h"
+#include "sky/screen.h"
+#include "sky/compact.h"
+#include "sky/sky.h"
+#include "sky/skydefs.h"
+#include "sky/struc.h"
+
+namespace Sky {
+
+uint8 Screen::_top16Colours[16*3] = {
+ 0, 0, 0,
+ 38, 38, 38,
+ 63, 63, 63,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 0, 0, 0,
+ 54, 54, 54,
+ 45, 47, 49,
+ 32, 31, 41,
+ 29, 23, 37,
+ 23, 18, 30,
+ 49, 11, 11,
+ 39, 5, 5,
+ 29, 1, 1,
+ 63, 63, 63
+};
+
+Screen::Screen(OSystem *pSystem, Disk *pDisk, SkyCompact *skyCompact) {
+
+ _system = pSystem;
+ _skyDisk = pDisk;
+ _skyCompact = skyCompact;
+
+ int i;
+ uint8 tmpPal[1024];
+
+ _system->initSize(FULL_SCREEN_WIDTH, FULL_SCREEN_HEIGHT);
+ _gameGrid = (uint8 *)malloc(GRID_X * GRID_Y * 2);
+ forceRefresh();
+
+ _currentScreen = NULL;
+ _scrollScreen = NULL;
+
+ //blank the first 240 colors of the palette
+ memset(tmpPal, 0, GAME_COLOURS * 4);
+
+ //set the remaining colors
+ for (i = 0; i < (VGA_COLOURS-GAME_COLOURS); i++) {
+ tmpPal[4 * GAME_COLOURS + i * 4] = (_top16Colours[i * 3] << 2) + (_top16Colours[i * 3] >> 4);
+ tmpPal[4 * GAME_COLOURS + i * 4 + 1] = (_top16Colours[i * 3 + 1] << 2) + (_top16Colours[i * 3 + 1] >> 4);
+ tmpPal[4 * GAME_COLOURS + i * 4 + 2] = (_top16Colours[i * 3 + 2] << 2) + (_top16Colours[i * 3 + 2] >> 4);
+ tmpPal[4 * GAME_COLOURS + i * 4 + 3] = 0x00;
+ }
+
+ //set the palette
+ _system->setPalette(tmpPal, 0, VGA_COLOURS);
+ _currentPalette = 0;
+
+ _seqInfo.framesLeft = 0;
+ _seqInfo.seqData = _seqInfo.seqDataPos = NULL;
+ _seqInfo.running = false;
+}
+
+Screen::~Screen(void) {
+
+ free(_gameGrid);
+ if (_currentScreen)
+ free(_currentScreen);
+ if (_scrollScreen)
+ free(_scrollScreen);
+}
+
+void Screen::clearScreen(void) {
+
+ memset(_currentScreen, 0, FULL_SCREEN_WIDTH * FULL_SCREEN_HEIGHT);
+ _system->copyRectToScreen(_currentScreen, GAME_SCREEN_WIDTH, 0, 0, GAME_SCREEN_WIDTH, GAME_SCREEN_HEIGHT);
+ _system->updateScreen();
+}
+
+//set a new palette, pal is a pointer to dos vga rgb components 0..63
+void Screen::setPalette(uint8 *pal) {
+
+ convertPalette(pal, _palette);
+ _system->setPalette(_palette, 0, GAME_COLOURS);
+ _system->updateScreen();
+}
+
+void Screen::setPaletteEndian(uint8 *pal) {
+
+#ifdef SCUMM_BIG_ENDIAN
+ uint8 endPalette[256 * 3];
+ for (uint16 cnt = 0; cnt < 256 * 3; cnt++)
+ endPalette[cnt] = pal[cnt ^ 1];
+ convertPalette(endPalette, _palette);
+#else
+ convertPalette(pal, _palette);
+#endif
+ _system->setPalette(_palette, 0, GAME_COLOURS);
+ _system->updateScreen();
+}
+
+void Screen::halvePalette(void) {
+
+ uint8 halfPalette[1024];
+ for (uint8 cnt = 0; cnt < GAME_COLOURS; cnt++) {
+ halfPalette[(cnt << 2) | 0] = _palette[(cnt << 2) | 0] >> 1;
+ halfPalette[(cnt << 2) | 1] = _palette[(cnt << 2) | 1] >> 1;
+ halfPalette[(cnt << 2) | 2] = _palette[(cnt << 2) | 2] >> 1;
+ halfPalette[(cnt << 2) | 3] = 0;
+ }
+ _system->setPalette(halfPalette, 0, GAME_COLOURS);
+}
+
+void Screen::setPalette(uint16 fileNum) {
+
+ uint8 *tmpPal = _skyDisk->loadFile(fileNum);
+ if (tmpPal) {
+ setPalette(tmpPal);
+ free(tmpPal);
+ } else
+ warning("Screen::setPalette: can't load file nr. %d",fileNum);
+}
+
+void Screen::showScreen(uint16 fileNum) {
+
+ if (_currentScreen)
+ free(_currentScreen);
+ _currentScreen = _skyDisk->loadFile(fileNum);
+
+ if (_currentScreen)
+ showScreen(_currentScreen);
+ else
+ warning("Screen::showScreen: can't load file nr. %d",fileNum);
+}
+
+void Screen::showScreen(uint8 *pScreen) {
+
+ _system->copyRectToScreen(pScreen, 320, 0, 0, GAME_SCREEN_WIDTH, GAME_SCREEN_HEIGHT);
+ _system->updateScreen();
+}
+
+void Screen::convertPalette(uint8 *inPal, uint8* outPal) { //convert 3 byte 0..63 rgb to 4byte 0..255 rgbx
+
+ int i;
+
+ for (i = 0; i < VGA_COLOURS; i++) {
+ outPal[4 * i] = (inPal[3 * i] << 2) + (inPal[3 * i] >> 4);
+ outPal[4 * i + 1] = (inPal[3 * i + 1] << 2) + (inPal[3 * i + 1] >> 4);
+ outPal[4 * i + 2] = (inPal[3 * i + 2] << 2) + (inPal[3 * i + 2] >> 4);
+ outPal[4 * i + 3] = 0x00;
+ }
+}
+
+void Screen::recreate(void) {
+
+ // check the game grid for changed blocks
+ if (!Logic::_scriptVariables[LAYER_0_ID])
+ return;
+ uint8 *gridPos = _gameGrid;
+ uint8 *screenData = (uint8 *)SkyEngine::fetchItem(Logic::_scriptVariables[LAYER_0_ID]);
+ if (!screenData) {
+ error("Screen::recreate():\nSkyEngine::fetchItem(Logic::_scriptVariables[LAYER_0_ID](%X)) returned NULL", Logic::_scriptVariables[LAYER_0_ID]);
+ }
+ uint8 *screenPos = _currentScreen;
+
+ for (uint8 cnty = 0; cnty < GRID_Y; cnty++) {
+ for (uint8 cntx = 0; cntx < GRID_X; cntx++) {
+ if (gridPos[0] & 0x80) {
+ gridPos[0] &= 0x7F; // reset recreate flag
+ gridPos[0] |= 1; // set bit for flip routine
+ uint8 *savedScreenY = screenPos;
+ for (uint8 gridCntY = 0; gridCntY < GRID_H; gridCntY++) {
+ memcpy(screenPos, screenData, GRID_W);
+ screenPos += GAME_SCREEN_WIDTH;
+ screenData += GRID_W;
+ }
+ screenPos = savedScreenY + GRID_W;
+ } else {
+ screenPos += GRID_W;
+ screenData += GRID_W * GRID_H;
+ }
+ gridPos++;
+ }
+ screenPos += (GRID_H - 1) * GAME_SCREEN_WIDTH;
+ }
+}
+
+void Screen::flip(bool doUpdate) {
+
+ uint32 copyX, copyWidth;
+ copyX = copyWidth = 0;
+ for (uint8 cnty = 0; cnty < GRID_Y; cnty++) {
+ for (uint8 cntx = 0; cntx < GRID_X; cntx++) {
+ if (_gameGrid[cnty * GRID_X + cntx] & 1) {
+ _gameGrid[cnty * GRID_X + cntx] &= ~1;
+ if (!copyWidth)
+ copyX = cntx * GRID_W;
+ copyWidth += GRID_W;
+ } else if (copyWidth) {
+ _system->copyRectToScreen(_currentScreen + cnty * GRID_H * GAME_SCREEN_WIDTH + copyX, GAME_SCREEN_WIDTH, copyX, cnty * GRID_H, copyWidth, GRID_H);
+ copyWidth = 0;
+ }
+ }
+ if (copyWidth) {
+ _system->copyRectToScreen(_currentScreen + cnty * GRID_H * GAME_SCREEN_WIDTH + copyX, GAME_SCREEN_WIDTH, copyX, cnty * GRID_H, copyWidth, GRID_H);
+ copyWidth = 0;
+ }
+ }
+ if (doUpdate)
+ _system->updateScreen();
+}
+
+void Screen::fnDrawScreen(uint32 palette, uint32 scroll) {
+
+ // set up the new screen
+ fnFadeDown(scroll);
+ forceRefresh();
+ recreate();
+ spriteEngine();
+ flip(false);
+ fnFadeUp(palette, scroll);
+}
+
+void Screen::fnFadeDown(uint32 scroll) {
+
+ if (((scroll != 123) && (scroll != 321)) || (SkyEngine::_systemVars.systemFlags & SF_NO_SCROLL)) {
+ uint32 delayTime = _system->getMillis();
+ for (uint8 cnt = 0; cnt < 32; cnt++) {
+ delayTime += 20;
+ palette_fadedown_helper((uint32 *)_palette, GAME_COLOURS);
+ _system->setPalette(_palette, 0, GAME_COLOURS);
+ _system->updateScreen();
+ int32 waitTime = (int32)delayTime - _system->getMillis();
+ if (waitTime < 0)
+ waitTime = 0;
+ _system->delayMillis((uint)waitTime);
+ }
+ } else {
+ // scrolling is performed by fnFadeUp. It's just prepared here
+ _scrollScreen = _currentScreen;
+ _currentScreen = (uint8 *)malloc(FULL_SCREEN_WIDTH * FULL_SCREEN_HEIGHT);
+ // the game will draw the new room into _currentScreen which
+ // will be scrolled into the visible screen by fnFadeUp
+ // fnFadeUp also frees the _scrollScreen
+ }
+}
+
+void Screen::palette_fadedown_helper(uint32 *pal, uint num) {
+ byte *p = (byte *)pal;
+
+ do {
+ if (p[0] >= 8)
+ p[0] -= 8;
+ else
+ p[0] = 0;
+ if (p[1] >= 8)
+ p[1] -= 8;
+ else
+ p[1] = 0;
+ if (p[2] >= 8)
+ p[2] -= 8;
+ else
+ p[2] = 0;
+ p += sizeof(uint32);
+ } while (--num);
+}
+
+void Screen::paletteFadeUp(uint16 fileNr) {
+
+ uint8 *pal = _skyDisk->loadFile(fileNr);
+ if (pal) {
+ paletteFadeUp(pal);
+ free(pal);
+ } else
+ warning("Screen::paletteFadeUp: Can't load palette #%d",fileNr);
+}
+
+void Screen::paletteFadeUp(uint8 *pal) {
+
+ byte tmpPal[1024];
+
+ convertPalette(pal, tmpPal);
+
+ uint32 delayTime = _system->getMillis();
+ for (uint8 cnt = 1; cnt <= 32; cnt++) {
+ delayTime += 20;
+ for (uint8 colCnt = 0; colCnt < GAME_COLOURS; colCnt++) {
+ _palette[(colCnt << 2) | 0] = (tmpPal[(colCnt << 2) | 0] * cnt) >> 5;
+ _palette[(colCnt << 2) | 1] = (tmpPal[(colCnt << 2) | 1] * cnt) >> 5;
+ _palette[(colCnt << 2) | 2] = (tmpPal[(colCnt << 2) | 2] * cnt) >> 5;
+ }
+ _system->setPalette(_palette, 0, GAME_COLOURS);
+ _system->updateScreen();
+ int32 waitTime = (int32)delayTime - _system->getMillis();
+ if (waitTime < 0)
+ waitTime = 0;
+ _system->delayMillis((uint)waitTime);
+ }
+}
+
+void Screen::fnFadeUp(uint32 palNum, uint32 scroll) {
+
+ //_currentScreen points to new screen,
+ //_scrollScreen points to graphic showing old room
+ if ((scroll != 123) && (scroll != 321))
+ scroll = 0;
+
+ if ((scroll == 0) || (SkyEngine::_systemVars.systemFlags & SF_NO_SCROLL)) {
+ uint8 *palette = (uint8 *)_skyCompact->fetchCpt(palNum);
+ if (palette == NULL)
+ error("Screen::fnFadeUp: can't fetch compact %X", palNum);
+#ifdef SCUMM_BIG_ENDIAN
+ byte tmpPal[256 * 3];
+ for (uint16 cnt = 0; cnt < 256*3; cnt++)
+ tmpPal[cnt] = palette[cnt ^ 1];
+ paletteFadeUp(tmpPal);
+#else
+ paletteFadeUp(palette);
+#endif
+ } else if (scroll == 123) { // scroll left (going right)
+ assert(_currentScreen && _scrollScreen);
+ uint8 *scrNewPtr, *scrOldPtr;
+ for (uint8 scrollCnt = 0; scrollCnt < (GAME_SCREEN_WIDTH / SCROLL_JUMP) - 1; scrollCnt++) {
+ scrNewPtr = _currentScreen + scrollCnt * SCROLL_JUMP;
+ scrOldPtr = _scrollScreen;
+ for (uint8 lineCnt = 0; lineCnt < GAME_SCREEN_HEIGHT; lineCnt++) {
+ memmove(scrOldPtr, scrOldPtr + SCROLL_JUMP, GAME_SCREEN_WIDTH - SCROLL_JUMP);
+ memcpy(scrOldPtr + GAME_SCREEN_WIDTH - SCROLL_JUMP, scrNewPtr, SCROLL_JUMP);
+ scrNewPtr += GAME_SCREEN_WIDTH;
+ scrOldPtr += GAME_SCREEN_WIDTH;
+ }
+ showScreen(_scrollScreen);
+ waitForTimer();
+ }
+ showScreen(_currentScreen);
+ } else if (scroll == 321) { // scroll right (going left)
+ assert(_currentScreen && _scrollScreen);
+ uint8 *scrNewPtr, *scrOldPtr;
+ for (uint8 scrollCnt = 0; scrollCnt < (GAME_SCREEN_WIDTH / SCROLL_JUMP) - 1; scrollCnt++) {
+ scrNewPtr = _currentScreen + GAME_SCREEN_WIDTH - (scrollCnt + 1) * SCROLL_JUMP;
+ scrOldPtr = _scrollScreen;
+ for (uint8 lineCnt = 0; lineCnt < GAME_SCREEN_HEIGHT; lineCnt++) {
+ memmove(scrOldPtr + SCROLL_JUMP, scrOldPtr, GAME_SCREEN_WIDTH - SCROLL_JUMP);
+ memcpy(scrOldPtr, scrNewPtr, SCROLL_JUMP);
+ scrNewPtr += GAME_SCREEN_WIDTH;
+ scrOldPtr += GAME_SCREEN_WIDTH;
+ }
+ showScreen(_scrollScreen);
+ waitForTimer();
+ }
+ showScreen(_currentScreen);
+ }
+ if (_scrollScreen) {
+ free(_scrollScreen);
+ _scrollScreen = NULL;
+ }
+}
+
+void Screen::waitForTimer(void) {
+
+ _gotTick = false;
+ while (!_gotTick) {
+ OSystem::Event event;
+
+ _system->delayMillis(10);
+ while (_system->pollEvent(event));
+ }
+}
+
+void Screen::waitForSequence(void) {
+ while (_seqInfo.running) {
+ OSystem::Event event;
+
+ _system->delayMillis(20);
+ while (_system->pollEvent(event));
+ }
+}
+
+void Screen::handleTimer(void) {
+
+ _gotTick = true;
+ if (_seqInfo.running)
+ processSequence();
+}
+
+void Screen::startSequence(uint16 fileNum) {
+
+ _seqInfo.seqData = _skyDisk->loadFile(fileNum);
+ _seqInfo.framesLeft = _seqInfo.seqData[0];
+ _seqInfo.seqDataPos = _seqInfo.seqData + 1;
+ _seqInfo.delay = SEQ_DELAY;
+ _seqInfo.running = true;
+ _seqInfo.runningItem = false;
+}
+
+void Screen::startSequenceItem(uint16 itemNum) {
+
+ _seqInfo.seqData = (uint8 *)SkyEngine::fetchItem(itemNum);
+ _seqInfo.framesLeft = _seqInfo.seqData[0] - 1;
+ _seqInfo.seqDataPos = _seqInfo.seqData + 1;
+ _seqInfo.delay = SEQ_DELAY;
+ _seqInfo.running = true;
+ _seqInfo.runningItem = true;
+}
+
+void Screen::stopSequence() {
+
+ _seqInfo.running = false;
+ waitForTimer();
+ waitForTimer();
+ _seqInfo.framesLeft = 0;
+ free(_seqInfo.seqData);
+ _seqInfo.seqData = _seqInfo.seqDataPos = NULL;
+}
+
+void Screen::processSequence(void) {
+
+ uint32 screenPos = 0;
+
+ _seqInfo.delay--;
+ if (_seqInfo.delay == 0) {
+ _seqInfo.delay = SEQ_DELAY;
+ memset(_seqGrid, 0, 12 * 20);
+
+ uint8 nrToSkip, nrToDo, cnt;
+ do {
+ do {
+ nrToSkip = _seqInfo.seqDataPos[0];
+ _seqInfo.seqDataPos++;
+ screenPos += nrToSkip;
+ } while (nrToSkip == 0xFF);
+ do {
+ nrToDo = _seqInfo.seqDataPos[0];
+ _seqInfo.seqDataPos++;
+
+ uint8 gridSta = (uint8)((screenPos / (GAME_SCREEN_WIDTH * 16))*20 + ((screenPos % GAME_SCREEN_WIDTH) >> 4));
+ uint8 gridEnd = (uint8)(((screenPos+nrToDo) / (GAME_SCREEN_WIDTH * 16))*20 + (((screenPos+nrToDo) % GAME_SCREEN_WIDTH) >> 4));
+ gridSta = MIN(gridSta, (uint8)(12 * 20 - 1));
+ gridEnd = MIN(gridEnd, (uint8)(12 * 20 - 1));
+ if (gridEnd >= gridSta)
+ for (cnt = gridSta; cnt <= gridEnd; cnt++)
+ _seqGrid[cnt] = 1;
+ else {
+ for (cnt = gridSta; cnt < (gridSta / 20 + 1) * 20; cnt++)
+ _seqGrid[cnt] = 1;
+ for (cnt = (gridEnd / 20) * 20; cnt <= gridEnd; cnt++)
+ _seqGrid[cnt] = 1;
+ }
+
+ for (cnt = 0; cnt < nrToDo; cnt++) {
+ _currentScreen[screenPos] = _seqInfo.seqDataPos[0];
+ _seqInfo.seqDataPos++;
+ screenPos++;
+ }
+ } while (nrToDo == 0xFF);
+ } while (screenPos < (GAME_SCREEN_WIDTH * GAME_SCREEN_HEIGHT));
+ uint8 *gridPtr = _seqGrid; uint8 *scrPtr = _currentScreen; uint8 *rectPtr = NULL;
+ uint8 rectWid = 0, rectX = 0, rectY = 0;
+ for (uint8 cnty = 0; cnty < 12; cnty++) {
+ for (uint8 cntx = 0; cntx < 20; cntx++) {
+ if (*gridPtr) {
+ if (!rectWid) {
+ rectX = cntx;
+ rectY = cnty;
+ rectPtr = scrPtr;
+ }
+ rectWid++;
+ } else if (rectWid) {
+ _system->copyRectToScreen(rectPtr, GAME_SCREEN_WIDTH, rectX << 4, rectY << 4, rectWid << 4, 16);
+ rectWid = 0;
+ }
+ scrPtr += 16;
+ gridPtr++;
+ }
+ if (rectWid) {
+ _system->copyRectToScreen(rectPtr, GAME_SCREEN_WIDTH, rectX << 4, rectY << 4, rectWid << 4, 16);
+ rectWid = 0;
+ }
+ scrPtr += 15 * GAME_SCREEN_WIDTH;
+ }
+ _system->updateScreen();
+ _seqInfo.framesLeft--;
+ }
+ if (_seqInfo.framesLeft == 0) {
+ _seqInfo.running = false;
+ if (!_seqInfo.runningItem)
+ free(_seqInfo.seqData);
+ _seqInfo.seqData = _seqInfo.seqDataPos = NULL;
+ }
+}
+
+//- sprites.asm routines
+
+void Screen::spriteEngine(void) {
+
+ doSprites(BACK);
+ sortSprites();
+ doSprites(FORE);
+}
+
+void Screen::sortSprites(void) {
+
+ StSortList sortList[30];
+ uint32 currDrawList = DRAW_LIST_NO;
+ uint32 loadDrawList;
+
+ bool nextDrawList = false;
+ while (Logic::_scriptVariables[currDrawList]) {
+ // big_sort_loop
+ uint32 spriteCnt = 0;
+ loadDrawList = Logic::_scriptVariables[currDrawList];
+ currDrawList++;
+
+ do { // a_new_draw_list:
+ uint16 *drawListData = (uint16 *)_skyCompact->fetchCpt(loadDrawList);
+ nextDrawList = false;
+ while ((!nextDrawList) && (drawListData[0])) {
+ if (drawListData[0] == 0xFFFF) {
+ loadDrawList = drawListData[1];
+ nextDrawList = true;
+ } else {
+ // process_this_id:
+ Compact *spriteComp = _skyCompact->fetchCpt(drawListData[0]);
+ if ((spriteComp->status & 4) && // is it sortable playfield?(!?!)
+ (spriteComp->screen == Logic::_scriptVariables[SCREEN])) { // on current screen
+ dataFileHeader *spriteData =
+ (dataFileHeader *)SkyEngine::fetchItem(spriteComp->frame >> 6);
+ if (!spriteData) {
+ debug(9,"Missing file %d", spriteComp->frame >> 6);
+ spriteComp->status = 0;
+ } else {
+ sortList[spriteCnt].yCood = spriteComp->ycood + spriteData->s_offset_y + spriteData->s_height;
+ sortList[spriteCnt].compact = spriteComp;
+ sortList[spriteCnt].sprite = spriteData;
+ spriteCnt++;
+ }
+ }
+ drawListData++;
+ }
+ }
+ } while (nextDrawList);
+ // made_list:
+ if (spriteCnt > 1) { // bubble sort
+ for (uint32 cnt1 = 0; cnt1 < spriteCnt - 1; cnt1++)
+ for (uint32 cnt2 = cnt1 + 1; cnt2 < spriteCnt; cnt2++)
+ if (sortList[cnt1].yCood > sortList[cnt2].yCood) {
+ StSortList tmp;
+ tmp.yCood = sortList[cnt1].yCood;
+ tmp.sprite = sortList[cnt1].sprite;
+ tmp.compact = sortList[cnt1].compact;
+ sortList[cnt1].yCood = sortList[cnt2].yCood;
+ sortList[cnt1].sprite = sortList[cnt2].sprite;
+ sortList[cnt1].compact = sortList[cnt2].compact;
+ sortList[cnt2].yCood = tmp.yCood;
+ sortList[cnt2].sprite = tmp.sprite;
+ sortList[cnt2].compact = tmp.compact;
+ }
+ }
+ for (uint32 cnt = 0; cnt < spriteCnt; cnt++) {
+ drawSprite((uint8 *)sortList[cnt].sprite, sortList[cnt].compact);
+ if (sortList[cnt].compact->status & 8)
+ vectorToGame(0x81);
+ else
+ vectorToGame(1);
+ if (!(sortList[cnt].compact->status & 0x200))
+ verticalMask();
+ }
+ }
+}
+
+void Screen::doSprites(uint8 layer) {
+
+ uint16 drawListNum = DRAW_LIST_NO;
+ uint32 idNum;
+ uint16* drawList;
+ while (Logic::_scriptVariables[drawListNum]) { // std sp loop
+ idNum = Logic::_scriptVariables[drawListNum];
+ drawListNum++;
+
+ drawList = (uint16 *)_skyCompact->fetchCpt(idNum);
+ while (drawList[0]) {
+ // new_draw_list:
+ while ((drawList[0] != 0) && (drawList[0] != 0xFFFF)) {
+ // back_loop:
+ // not_new_list
+ Compact *spriteData = _skyCompact->fetchCpt(drawList[0]);
+ drawList++;
+ if ((spriteData->status & (1 << layer)) &&
+ (spriteData->screen == Logic::_scriptVariables[SCREEN])) {
+ uint8 *toBeDrawn = (uint8 *)SkyEngine::fetchItem(spriteData->frame >> 6);
+ if (!toBeDrawn) {
+ debug(9, "Spritedata %d not loaded", spriteData->frame >> 6);
+ spriteData->status = 0;
+ } else {
+ drawSprite(toBeDrawn, spriteData);
+ if (layer == BACK)
+ verticalMask();
+ if (spriteData->status & 8)
+ vectorToGame(0x81);
+ else
+ vectorToGame(1);
+ }
+ }
+ }
+ while (drawList[0] == 0xFFFF)
+ drawList = (uint16 *)_skyCompact->fetchCpt(drawList[1]);
+ }
+ }
+}
+
+void Screen::drawSprite(uint8 *spriteInfo, Compact *sprCompact) {
+
+ if (spriteInfo == NULL) {
+ warning("Screen::drawSprite Can't draw sprite. Data %d was not loaded", sprCompact->frame >> 6);
+ sprCompact->status = 0;
+ return;
+ }
+ dataFileHeader *sprDataFile = (dataFileHeader *)spriteInfo;
+ _sprWidth = sprDataFile->s_width;
+ _sprHeight = sprDataFile->s_height;
+ _maskX1 = _maskX2 = 0;
+ uint8 *spriteData = spriteInfo + (sprCompact->frame & 0x3F) * sprDataFile->s_sp_size;
+ spriteData += sizeof(dataFileHeader);
+ int32 spriteY = sprCompact->ycood + sprDataFile->s_offset_y - TOP_LEFT_Y;
+ if (spriteY < 0) {
+ spriteY = -spriteY;
+ if (_sprHeight <= (uint32)spriteY) {
+ _sprWidth = 0;
+ return;
+ }
+ _sprHeight -= spriteY;
+ spriteData += sprDataFile->s_width * spriteY;
+ spriteY = 0;
+ } else {
+ int32 botClip = GAME_SCREEN_HEIGHT - sprDataFile->s_height - spriteY;
+ if (botClip < 0) {
+ botClip = -botClip;
+ if (_sprHeight <= (uint32)botClip) {
+ _sprWidth = 0;
+ return;
+ }
+ _sprHeight -= botClip;
+ }
+ }
+ _sprY = (uint32)spriteY;
+ int32 spriteX = sprCompact->xcood + sprDataFile->s_offset_x - TOP_LEFT_X;
+ if (spriteX < 0) {
+ spriteX = -spriteX;
+ if (_sprWidth <= (uint32)spriteX) {
+ _sprWidth = 0;
+ return;
+ }
+ _sprWidth -= spriteX;
+ _maskX1 = spriteX;
+ spriteX = 0;
+ } else {
+ int32 rightClip = GAME_SCREEN_WIDTH - (sprDataFile->s_width + spriteX);
+ if (rightClip < 0) {
+ rightClip = (-rightClip) + 1;
+ if (_sprWidth <= (uint32)rightClip) {
+ _sprWidth = 0;
+ return;
+ }
+ _sprWidth -= rightClip;
+ _maskX2 = rightClip;
+ }
+ }
+ _sprX = (uint32)spriteX;
+ uint8 *screenPtr = _currentScreen + _sprY * GAME_SCREEN_WIDTH + _sprX;
+ if ((_sprHeight > 192) || (_sprY > 192)) {
+ _sprWidth = 0;
+ return;
+ }
+ if ((_sprX + _sprWidth > 320) || (_sprY + _sprHeight > 192)) {
+ warning("Screen::drawSprite fatal error: got x = %d, y = %d, w = %d, h = %d",_sprX, _sprY, _sprWidth, _sprHeight);
+ _sprWidth = 0;
+ return;
+ }
+
+ for (uint16 cnty = 0; cnty < _sprHeight; cnty++) {
+ for (uint16 cntx = 0; cntx < _sprWidth; cntx++)
+ if (spriteData[cntx + _maskX1])
+ screenPtr[cntx] = spriteData[cntx + _maskX1];
+ spriteData += _sprWidth + _maskX2 + _maskX1;
+ screenPtr += GAME_SCREEN_WIDTH;
+ }
+ // Convert the sprite coordinate/size values to blocks for vertical mask and/or vector to game
+ _sprWidth += _sprX + GRID_W-1;
+ _sprHeight += _sprY + GRID_H-1;
+
+ _sprX >>= GRID_W_SHIFT;
+ _sprWidth >>= GRID_W_SHIFT;
+ _sprY >>= GRID_H_SHIFT;
+ _sprHeight >>= GRID_H_SHIFT;
+
+ _sprWidth -= _sprX;
+ _sprHeight -= _sprY;
+}
+
+void Screen::vectorToGame(uint8 gridVal) {
+
+ if (_sprWidth == 0)
+ return;
+ uint8 *trgGrid = _gameGrid + _sprY * GRID_X +_sprX;
+ for (uint32 cnty = 0; cnty < _sprHeight; cnty++) {
+ for (uint32 cntx = 0; cntx < _sprWidth; cntx++)
+ trgGrid[cntx] |= gridVal;
+ trgGrid += GRID_X;
+ }
+}
+
+void Screen::vertMaskSub(uint16 *grid, uint32 gridOfs, uint8 *screenPtr, uint32 layerId) {
+
+ for (uint32 cntx = 0; cntx < _sprHeight; cntx++) { // start_x | block_loop
+ if (grid[gridOfs]) {
+ if (!(FROM_LE_16(grid[gridOfs]) & 0x8000)) {
+ uint32 gridVal = FROM_LE_16(grid[gridOfs]) - 1;
+ gridVal *= GRID_W * GRID_H;
+ uint8 *dataSrc = (uint8 *)SkyEngine::fetchItem(Logic::_scriptVariables[layerId]) + gridVal;
+ uint8 *dataTrg = screenPtr;
+ for (uint32 grdCntY = 0; grdCntY < GRID_H; grdCntY++) {
+ for (uint32 grdCntX = 0; grdCntX < GRID_W; grdCntX++)
+ if (dataSrc[grdCntX])
+ dataTrg[grdCntX] = dataSrc[grdCntX];
+ dataSrc += GRID_W;
+ dataTrg += GAME_SCREEN_WIDTH;
+ }
+ } // dummy_end:
+ screenPtr -= GRID_H * GAME_SCREEN_WIDTH;
+ gridOfs -= GRID_X;
+ } else
+ return;
+ } // next_x
+}
+
+void Screen::verticalMask(void) {
+
+ if (_sprWidth == 0)
+ return;
+ uint32 startGridOfs = (_sprY + _sprHeight - 1) * GRID_X + _sprX;
+ uint8 *startScreenPtr = (_sprY + _sprHeight - 1) * GRID_H * GAME_SCREEN_WIDTH + _sprX * GRID_W + _currentScreen;
+
+ for (uint32 layerCnt = LAYER_1_ID; layerCnt <= LAYER_3_ID; layerCnt++) {
+ uint32 gridOfs = startGridOfs;
+ uint8 *screenPtr = startScreenPtr;
+ for (uint32 widCnt = 0; widCnt < _sprWidth; widCnt++) { // x_loop
+ uint32 nLayerCnt = layerCnt;
+ while (Logic::_scriptVariables[nLayerCnt + 3]) {
+ uint16 *scrGrid;
+ scrGrid = (uint16 *)SkyEngine::fetchItem(Logic::_scriptVariables[layerCnt + 3]);
+ if (scrGrid[gridOfs]) {
+ vertMaskSub(scrGrid, gridOfs, screenPtr, layerCnt);
+ break;
+ } else
+ nLayerCnt++;
+ }
+ // next_x:
+ screenPtr += GRID_W;
+ gridOfs++;
+ }
+ }
+}
+
+void Screen::paintBox(uint16 x, uint16 y) {
+
+ uint8 *screenPos = _currentScreen + y * GAME_SCREEN_WIDTH + x;
+ memset(screenPos, 255, 8);
+ for (uint8 cnt = 1; cnt < 8; cnt++) {
+ *(screenPos + cnt * GAME_SCREEN_WIDTH) = 255;
+ *(screenPos + cnt * GAME_SCREEN_WIDTH + 7) = 255;
+ }
+ memset(screenPos + 7 * GAME_SCREEN_WIDTH, 255, 7);
+}
+
+void Screen::showGrid(uint8 *gridBuf) {
+
+ uint32 gridData = 0;
+ uint8 bitsLeft = 0;
+ for (uint16 cnty = 0; cnty < GAME_SCREEN_HEIGHT >> 3; cnty++) {
+ for (uint16 cntx = 0; cntx < GAME_SCREEN_WIDTH >> 3; cntx++) {
+ if (!bitsLeft) {
+ bitsLeft = 32;
+ gridData = *(uint32 *)gridBuf;
+ gridBuf += 4;
+ }
+ if (gridData & 0x80000000)
+ paintBox(cntx << 3, cnty << 3);
+ bitsLeft--;
+ gridData <<= 1;
+ }
+ }
+ _system->copyRectToScreen(_currentScreen, GAME_SCREEN_WIDTH, 0, 0, GAME_SCREEN_WIDTH, GAME_SCREEN_HEIGHT);
+
+}
+
+} // End of namespace Sky
diff --git a/engines/sky/screen.h b/engines/sky/screen.h
new file mode 100644
index 0000000000..c1e504a87f
--- /dev/null
+++ b/engines/sky/screen.h
@@ -0,0 +1,134 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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 SKYSCREEN_H
+#define SKYSCREEN_H
+
+#include "common/stdafx.h"
+#include "common/scummsys.h"
+#include "sky/skydefs.h"
+
+class OSystem;
+
+namespace Sky {
+
+class Disk;
+class SkyEngine;
+class SkyCompact;
+struct Compact;
+struct dataFileHeader;
+
+#define SCROLL_JUMP 16
+#define VGA_COLOURS 256
+#define GAME_COLOURS 240
+#define SEQ_DELAY 3
+
+#define FORE 1
+#define BACK 0
+
+typedef struct {
+ uint16 yCood;
+ Compact *compact;
+ dataFileHeader *sprite;
+} StSortList;
+
+class Screen {
+public:
+ Screen(OSystem *pSystem, Disk *pDisk, SkyCompact *skyCompact);
+ ~Screen(void);
+ void setPalette(uint8 *pal);
+ void setPaletteEndian(uint8 *pal);
+ void setPalette(uint16 fileNum);
+ void paletteFadeUp(uint8 *pal);
+ void paletteFadeUp(uint16 fileNr);
+
+ void showScreen(uint16 fileNum);
+ void showScreen(uint8 *pScreen);
+
+ void handleTimer(void);
+ void startSequence(uint16 fileNum);
+ void startSequenceItem(uint16 itemNum);
+ void stopSequence(void);
+ bool sequenceRunning(void) { return _seqInfo.running; };
+ void waitForSequence(void);
+ uint32 seqFramesLeft(void) { return _seqInfo.framesLeft; };
+ uint8 *giveCurrent(void) { return _currentScreen; };
+ void halvePalette(void);
+
+ //- regular screen.asm routines
+ void forceRefresh(void) { memset(_gameGrid, 0x80, GRID_X * GRID_Y); };
+ void fnFadeUp(uint32 palNum, uint32 scroll);
+ void fnFadeDown(uint32 scroll);
+ void fnDrawScreen(uint32 palette, uint32 scroll);
+ void clearScreen(void);
+
+ void recreate(void);
+ void flip(bool doUpdate = true);
+
+ void spriteEngine(void);
+
+ void paintBox(uint16 x, uint16 y);
+ void showGrid(uint8 *gridBuf);
+
+private:
+ OSystem *_system;
+ Disk *_skyDisk;
+ SkyCompact *_skyCompact;
+ static uint8 _top16Colours[16*3];
+ uint8 _palette[1024];
+ uint32 _currentPalette;
+ uint8 _seqGrid[20 * 12];
+
+ bool volatile _gotTick;
+ void waitForTimer(void);
+ void processSequence(void);
+
+ uint8 *_gameGrid;
+ uint8 *_currentScreen;
+ uint8 *_scrollScreen;
+ struct {
+ uint32 framesLeft;
+ uint32 delay;
+ uint8 *seqData;
+ uint8 *seqDataPos;
+ volatile bool running;
+ bool runningItem; // when playing an item, don't free it afterwards.
+ } _seqInfo;
+
+ //- more regular screen.asm + layer.asm routines
+ void convertPalette(uint8 *inPal, uint8* outPal);
+ void palette_fadedown_helper(uint32 *pal, uint num);
+
+ //- sprite.asm routines
+ // fixme: get rid of these globals
+ uint32 _sprWidth, _sprHeight, _sprX, _sprY, _maskX1, _maskX2;
+ void doSprites(uint8 layer);
+ void sortSprites(void);
+ void drawSprite(uint8 *spriteData, Compact *sprCompact);
+ void verticalMask(void);
+ void vertMaskSub(uint16 *grid, uint32 gridOfs, uint8 *screenPtr, uint32 layerId);
+ void vectorToGame(uint8 gridVal);
+};
+
+} // End of namespace Sky
+
+#endif //SKYSCREEN_H
diff --git a/engines/sky/sky.cpp b/engines/sky/sky.cpp
new file mode 100644
index 0000000000..af904097ed
--- /dev/null
+++ b/engines/sky/sky.cpp
@@ -0,0 +1,556 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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 "backends/fs/fs.h"
+
+#include "base/gameDetector.h"
+#include "base/plugins.h"
+
+#include "common/config-manager.h"
+#include "common/file.h"
+#include "common/system.h"
+#include "common/timer.h"
+
+#include "sky/control.h"
+#include "sky/debug.h"
+#include "sky/disk.h"
+#include "sky/grid.h"
+#include "sky/intro.h"
+#include "sky/logic.h"
+#include "sky/mouse.h"
+#include "sky/music/adlibmusic.h"
+#include "sky/music/gmmusic.h"
+#include "sky/music/mt32music.h"
+#include "sky/music/musicbase.h"
+#include "sky/screen.h"
+#include "sky/sky.h"
+#include "sky/skydefs.h"
+#include "sky/sound.h"
+#include "sky/text.h"
+#include "sky/compact.h"
+
+#include "sound/mididrv.h"
+#include "sound/mixer.h"
+
+#ifdef _WIN32_WCE
+
+extern bool toolbar_drawn;
+extern bool draw_keyboard;
+extern bool isSmartphone(void);
+#endif
+
+/*
+ At the beginning the reverse engineers were happy, and did rejoice at
+ their task, for the engine before them did shineth and was full of
+ promise. But then they did look closer and see'th the aweful truth;
+ it's code was assembly and messy (rareth was its comments). And so large
+ were it's includes that did at first seem small; queereth also was its
+ compact(s). Then they did findeth another version, and this was slightly
+ different from the first. Then a third, and this was different again.
+ All different, but not really better, for all were not really compatible.
+ But, eventually, it did come to pass that Steel Sky was implemented on
+ a modern platform. And the programmers looked and saw that it was indeed a
+ miracle. But they were not joyous and instead did weep for nobody knew
+ just what had been done. Except people who read the source. Hello.
+
+ With apologies to the CD32 SteelSky file.
+*/
+
+static const GameSettings skySetting =
+ {"sky", "Beneath a Steel Sky", 0 };
+
+GameList Engine_SKY_gameList() {
+ GameList games;
+ games.push_back(skySetting);
+ return games;
+}
+
+DetectedGameList Engine_SKY_detectGames(const FSList &fslist) {
+ DetectedGameList detectedGames;
+ // Iterate over all files in the given directory
+ for (FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
+ if (!file->isDirectory()) {
+ const char *fileName = file->displayName().c_str();
+
+ if (0 == scumm_stricmp("sky.dsk", fileName)) {
+ // Match found, add to list of candidates, then abort inner loop.
+ // The game detector uses US English by default. We want British
+ // English to match the recorded voices better.
+ detectedGames.push_back(DetectedGame(skySetting, Common::EN_GRB, Common::kPlatformUnknown));
+ break;
+ }
+ }
+ }
+ return detectedGames;
+}
+
+Engine *Engine_SKY_create(GameDetector *detector, OSystem *syst) {
+ return new Sky::SkyEngine(detector, syst);
+}
+
+REGISTER_PLUGIN(SKY, "Beneath a Steel Sky")
+
+
+namespace Sky {
+
+void *SkyEngine::_itemList[300];
+
+SystemVars SkyEngine::_systemVars = {0, 0, 0, 0, 4316, 0, 0, false, false, false };
+
+SkyEngine::SkyEngine(GameDetector *detector, OSystem *syst)
+ : Engine(syst), _fastMode(0), _debugger(0) {
+}
+
+SkyEngine::~SkyEngine() {
+
+ _timer->removeTimerProc(&timerHandler);
+
+ delete _skyLogic;
+ delete _skySound;
+ delete _skyMusic;
+ delete _skyText;
+ delete _skyMouse;
+ delete _skyScreen;
+ delete _debugger;
+ delete _skyDisk;
+ delete _skyControl;
+ delete _skyCompact;
+
+ for (int i = 0; i < 300; i++)
+ if (_itemList[i])
+ free(_itemList[i]);
+}
+
+void SkyEngine::errorString(const char *buf1, char *buf2) {
+ strcpy(buf2, buf1);
+
+#ifdef _WIN32_WCE
+ if (isSmartphone())
+ return;
+#endif
+
+ // Unless an error -originated- within the debugger, spawn the
+ // debugger. Otherwise exit out normally.
+ if (_debugger && !_debugger->isAttached()) {
+ // (Print it again in case debugger segfaults)
+ printf("%s\n", buf2);
+ _debugger->attach(buf2);
+ _debugger->onFrame();
+ }
+}
+
+void SkyEngine::initVirgin() {
+
+ _skyScreen->setPalette(60111);
+ _skyScreen->showScreen(60110);
+}
+
+void SkyEngine::handleKey(void) {
+
+ if (_keyPressed && _systemVars.paused) {
+ _skySound->fnUnPauseFx();
+ _systemVars.paused = false;
+ _skyScreen->setPaletteEndian((uint8 *)_skyCompact->fetchCpt(SkyEngine::_systemVars.currentPalette));
+ _keyFlags = _keyPressed = 0;
+ return;
+ }
+
+ if (_keyFlags == OSystem::KBD_CTRL) {
+ if (_keyPressed == 'f')
+ _fastMode ^= 1;
+ else if (_keyPressed == 'g')
+ _fastMode ^= 2;
+ else if (_keyPressed == 'd')
+ _debugger->attach();
+ } else {
+ switch (_keyPressed) {
+ case '`':
+ case '~':
+ case '#':
+ _debugger->attach();
+ break;
+ case 63:
+ _skyControl->doControlPanel();
+ break;
+
+ case 27:
+ if (!_systemVars.pastIntro)
+ _skyControl->restartGame();
+ break;
+
+ case '.':
+ _skyMouse->logicClick();
+ break;
+
+ case 'p':
+ _skyScreen->halvePalette();
+ _skySound->fnPauseFx();
+ _systemVars.paused = true;
+ break;
+
+ }
+ }
+ _keyFlags = _keyPressed = 0;
+}
+
+int SkyEngine::go() {
+
+ _systemVars.quitGame = false;
+
+ _mouseX = GAME_SCREEN_WIDTH / 2;
+ _mouseY = GAME_SCREEN_HEIGHT / 2;
+ _keyFlags = _keyPressed = 0;
+
+ uint16 result = 0;
+ if (ConfMan.hasKey("save_slot") && ConfMan.getInt("save_slot") >= 0)
+ result = _skyControl->quickXRestore(ConfMan.getInt("save_slot"));
+
+ if (result != GAME_RESTORED) {
+ bool introSkipped = false;
+ if (_systemVars.gameVersion > 267) { // don't do intro for floppydemos
+ _skyIntro = new Intro(_skyDisk, _skyScreen, _skyMusic, _skySound, _skyText, _mixer, _system);
+ introSkipped = !_skyIntro->doIntro(_floppyIntro);
+ _systemVars.quitGame = _skyIntro->_quitProg;
+
+ delete _skyIntro;
+ }
+
+ if (!_systemVars.quitGame) {
+ _skyLogic->initScreen0();
+ if (introSkipped)
+ _skyControl->restartGame();
+ }
+ }
+
+ _lastSaveTime = _system->getMillis();
+
+ uint32 delayCount = _system->getMillis();
+ while (!_systemVars.quitGame) {
+ if (_debugger->isAttached())
+ _debugger->onFrame();
+
+ if (shouldPerformAutoSave(_lastSaveTime)) {
+ if (_skyControl->loadSaveAllowed()) {
+ _lastSaveTime = _system->getMillis();
+ _skyControl->doAutoSave();
+ } else
+ _lastSaveTime += 30 * 1000; // try again in 30 secs
+ }
+ _skySound->checkFxQueue();
+ _skyMouse->mouseEngine((uint16)_mouseX, (uint16)_mouseY);
+ handleKey();
+ if (_systemVars.paused) {
+ do {
+ _system->updateScreen();
+ delay(50);
+ handleKey();
+ } while (_systemVars.paused);
+ delayCount = _system->getMillis();
+ }
+
+ _skyLogic->engine();
+ _skyScreen->recreate();
+ _skyScreen->spriteEngine();
+ if (_debugger->showGrid()) {
+ _skyScreen->showGrid(_skyLogic->_skyGrid->giveGrid(Logic::_scriptVariables[SCREEN]));
+ _skyScreen->forceRefresh();
+ }
+ _skyScreen->flip();
+
+ if (_fastMode & 2)
+ delay(0);
+ else if (_fastMode & 1)
+ delay(10);
+ else {
+ delayCount += _systemVars.gameSpeed;
+ int needDelay = delayCount - (int)_system->getMillis();
+ if ((needDelay < 0) || (needDelay > 4 * _systemVars.gameSpeed)) {
+ needDelay = 0;
+ delayCount = _system->getMillis();
+ }
+ delay(needDelay);
+ }
+ }
+
+ _skyControl->showGameQuitMsg();
+ _skyMusic->stopMusic();
+ ConfMan.flushToDisk();
+ delay(1500);
+ return 0;
+}
+
+int SkyEngine::init(GameDetector &detector) {
+ _system->beginGFXTransaction();
+ initCommonGFX(detector);
+ _system->initSize(320, 200);
+ _system->endGFXTransaction();
+
+ if (!_mixer->isReady())
+ warning("Sound initialisation failed");
+
+ if (ConfMan.getBool("sfx_mute")) {
+ SkyEngine::_systemVars.systemFlags |= SF_FX_OFF;
+ }
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume"));
+ _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume"));
+ _floppyIntro = ConfMan.getBool("alt_intro");
+
+ _skyDisk = new Disk(_gameDataPath);
+ _skySound = new Sound(_mixer, _skyDisk, ConfMan.getInt("sfx_volume"));
+
+ _systemVars.gameVersion = _skyDisk->determineGameVersion();
+
+ int midiDriver = MidiDriver::detectMusicDriver(MDT_ADLIB | MDT_MIDI | MDT_PREFER_MIDI);
+ if (midiDriver == MD_ADLIB) {
+ _systemVars.systemFlags |= SF_SBLASTER;
+ _skyMusic = new AdlibMusic(_mixer, _skyDisk);
+ } else {
+ _systemVars.systemFlags |= SF_ROLAND;
+ if ((midiDriver == MD_MT32) || ConfMan.getBool("native_mt32"))
+ _skyMusic = new MT32Music(MidiDriver::createMidi(midiDriver), _skyDisk);
+ else
+ _skyMusic = new GmMusic(MidiDriver::createMidi(midiDriver), _skyDisk);
+ }
+
+ if (isCDVersion()) {
+ if (ConfMan.hasKey("nosubtitles")) {
+ warning("Configuration key 'nosubtitles' is deprecated. Use 'subtitles' instead");
+ if (!ConfMan.getBool("nosubtitles"))
+ _systemVars.systemFlags |= SF_ALLOW_TEXT;
+ }
+
+ if (ConfMan.getBool("subtitles"))
+ _systemVars.systemFlags |= SF_ALLOW_TEXT;
+
+ if (!ConfMan.getBool("speech_mute"))
+ _systemVars.systemFlags |= SF_ALLOW_SPEECH;
+
+ } else
+ _systemVars.systemFlags |= SF_ALLOW_TEXT;
+
+ _systemVars.systemFlags |= SF_PLAY_VOCS;
+ _systemVars.gameSpeed = 50;
+
+ _skyCompact = new SkyCompact();
+ _skyText = new Text(_skyDisk, _skyCompact);
+ _skyMouse = new Mouse(_system, _skyDisk, _skyCompact);
+ _skyScreen = new Screen(_system, _skyDisk, _skyCompact);
+
+ initVirgin();
+ initItemList();
+ loadFixedItems();
+ _skyLogic = new Logic(_skyCompact, _skyScreen, _skyDisk, _skyText, _skyMusic, _skyMouse, _skySound);
+ _skyMouse->useLogicInstance(_skyLogic);
+
+ // initialize timer *after* _skyScreen has been initialized.
+ _timer->installTimerProc(&timerHandler, 1000000 / 50, this); //call 50 times per second
+
+ _skyControl = new Control(_saveFileMan, _skyScreen, _skyDisk, _skyMouse, _skyText, _skyMusic, _skyLogic, _skySound, _skyCompact, _system);
+ _skyLogic->useControlInstance(_skyControl);
+
+ switch (Common::parseLanguage(ConfMan.get("language"))) {
+ case Common::EN_USA:
+ _systemVars.language = SKY_USA;
+ break;
+ case Common::DE_DEU:
+ _systemVars.language = SKY_GERMAN;
+ break;
+ case Common::FR_FRA:
+ _systemVars.language = SKY_FRENCH;
+ break;
+ case Common::IT_ITA:
+ _systemVars.language = SKY_ITALIAN;
+ break;
+ case Common::PT_BRA:
+ _systemVars.language = SKY_PORTUGUESE;
+ break;
+ case Common::ES_ESP:
+ _systemVars.language = SKY_SPANISH;
+ break;
+ case Common::SE_SWE:
+ _systemVars.language = SKY_SWEDISH;
+ break;
+ case Common::EN_GRB:
+ _systemVars.language = SKY_ENGLISH;
+ break;
+ default:
+ _systemVars.language = SKY_ENGLISH;
+ break;
+ }
+
+ if (!_skyDisk->fileExists(60600 + SkyEngine::_systemVars.language * 8)) {
+ warning("The language you selected does not exist in your BASS version.");
+ if (_skyDisk->fileExists(60600))
+ SkyEngine::_systemVars.language = SKY_ENGLISH; // default to GB english if it exists..
+ else if (_skyDisk->fileExists(60600 + SKY_USA * 8))
+ SkyEngine::_systemVars.language = SKY_USA; // try US english...
+ else
+ for (uint8 cnt = SKY_ENGLISH; cnt <= SKY_SPANISH; cnt++)
+ if (_skyDisk->fileExists(60600 + cnt * 8)) { // pick the first language we can find
+ SkyEngine::_systemVars.language = cnt;
+ break;
+ }
+ }
+
+ _skyMusic->setVolume(ConfMan.getInt("music_volume") >> 1);
+
+ _debugger = new Debugger(_skyLogic, _skyMouse, _skyScreen, _skyCompact);
+ return 0;
+}
+
+void SkyEngine::initItemList() {
+
+ //See List.asm for (cryptic) item # descriptions
+
+ for (int i = 0; i < 300; i++)
+ _itemList[i] = NULL;
+}
+
+void SkyEngine::loadFixedItems(void) {
+
+ _itemList[49] = _skyDisk->loadFile(49);
+ _itemList[50] = _skyDisk->loadFile(50);
+ _itemList[73] = _skyDisk->loadFile(73);
+ _itemList[262] = _skyDisk->loadFile(262);
+
+ if (!isDemo()) {
+ _itemList[36] = _skyDisk->loadFile(36);
+ _itemList[263] = _skyDisk->loadFile(263);
+ _itemList[264] = _skyDisk->loadFile(264);
+ _itemList[265] = _skyDisk->loadFile(265);
+ _itemList[266] = _skyDisk->loadFile(266);
+ _itemList[267] = _skyDisk->loadFile(267);
+ _itemList[269] = _skyDisk->loadFile(269);
+ _itemList[271] = _skyDisk->loadFile(271);
+ _itemList[272] = _skyDisk->loadFile(272);
+ }
+}
+
+void *SkyEngine::fetchItem(uint32 num) {
+
+ return _itemList[num];
+}
+
+void SkyEngine::timerHandler(void *refCon) {
+
+ ((SkyEngine *)refCon)->gotTimerTick();
+}
+
+void SkyEngine::gotTimerTick(void) {
+
+ _skyScreen->handleTimer();
+}
+
+void SkyEngine::delay(int32 amount) {
+
+ OSystem::Event event;
+
+ uint32 start = _system->getMillis();
+ _keyFlags = _keyPressed = 0; //reset
+
+ if (amount < 0)
+ amount = 0;
+
+ do {
+ while (_system->pollEvent(event)) {
+ switch (event.type) {
+ case OSystem::EVENT_KEYDOWN:
+ _keyFlags = event.kbd.flags;
+ if (_keyFlags == OSystem::KBD_CTRL)
+ _keyPressed = event.kbd.keycode;
+ else
+ _keyPressed = (byte)event.kbd.ascii;
+ break;
+ case OSystem::EVENT_MOUSEMOVE:
+ if (!(_systemVars.systemFlags & SF_MOUSE_LOCKED)) {
+ _mouseX = event.mouse.x;
+ _mouseY = event.mouse.y;
+ }
+ break;
+ case OSystem::EVENT_LBUTTONDOWN:
+#ifdef PALMOS_MODE
+ _mouseX = event.mouse.x;
+ _mouseY = event.mouse.y;
+#endif
+ _skyMouse->buttonPressed(2);
+ break;
+ case OSystem::EVENT_RBUTTONDOWN:
+#ifdef PALMOS_MODE
+ _mouseX = event.mouse.x;
+ _mouseY = event.mouse.y;
+#endif
+ _skyMouse->buttonPressed(1);
+ break;
+ case OSystem::EVENT_QUIT:
+ _systemVars.quitGame = true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (amount > 0)
+ _system->delayMillis((amount > 10) ? 10 : amount);
+
+ } while (_system->getMillis() < start + amount);
+}
+
+bool SkyEngine::isDemo(void) {
+ switch (_systemVars.gameVersion) {
+ case 109: // pc gamer demo
+ case 267: // floppy demo
+ case 365: // cd demo
+ return true;
+ case 288:
+ case 303:
+ case 331:
+ case 348:
+ case 368:
+ case 372:
+ return false;
+ default:
+ error("Unknown game version %d", _systemVars.gameVersion);
+ }
+}
+
+bool SkyEngine::isCDVersion(void) {
+
+ switch (_systemVars.gameVersion) {
+ case 109:
+ case 267:
+ case 288:
+ case 303:
+ case 331:
+ case 348:
+ return false;
+ case 365:
+ case 368:
+ case 372:
+ return true;
+ default:
+ error("Unknown game version %d", _systemVars.gameVersion);
+ }
+}
+
+} // End of namespace Sky
diff --git a/engines/sky/sky.h b/engines/sky/sky.h
new file mode 100644
index 0000000000..71dcfa533c
--- /dev/null
+++ b/engines/sky/sky.h
@@ -0,0 +1,112 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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 SKYMAIN_H
+#define SKYMAIN_H
+
+#include "common/stdafx.h"
+#include "base/engine.h"
+
+class GameDetector;
+
+namespace Sky {
+
+struct SystemVars {
+ uint32 systemFlags;
+ uint32 gameVersion;
+ uint32 mouseFlag;
+ uint16 language;
+ uint32 currentPalette;
+ uint16 gameSpeed;
+ uint16 currentMusic;
+ bool pastIntro;
+ bool quitGame;
+ bool paused;
+};
+
+struct Compact;
+class Sound;
+class Disk;
+class Text;
+class Logic;
+class Mouse;
+class Screen;
+class Control;
+class MusicBase;
+class Intro;
+class Debugger;
+class SkyCompact;
+
+class SkyEngine : public Engine {
+ void errorString(const char *buf_input, char *buf_output);
+protected:
+ byte _keyPressed, _keyFlags;
+ bool _floppyIntro;
+
+ int _mouseX, _mouseY;
+
+ Sound *_skySound;
+ Disk *_skyDisk;
+ Text *_skyText;
+ Logic *_skyLogic;
+ Mouse *_skyMouse;
+ Screen *_skyScreen;
+ Control *_skyControl;
+ SkyCompact *_skyCompact;
+ Debugger *_debugger;
+
+ MusicBase *_skyMusic;
+ Intro *_skyIntro;
+
+public:
+ SkyEngine(GameDetector *detector, OSystem *syst);
+ virtual ~SkyEngine();
+
+ static bool isDemo(void);
+ static bool isCDVersion(void);
+
+ static void *fetchItem(uint32 num);
+ static void *_itemList[300];
+
+ static SystemVars _systemVars;
+
+protected:
+ byte _fastMode;
+
+ void delay(int32 amount);
+ int go();
+ void handleKey(void);
+
+ uint32 _lastSaveTime;
+
+ int init(GameDetector &detector);
+ void initItemList();
+
+ void initVirgin();
+ static void timerHandler(void *ptr);
+ void gotTimerTick();
+ void loadFixedItems();
+};
+
+} // End of namespace Sky
+
+#endif
diff --git a/engines/sky/skydefs.h b/engines/sky/skydefs.h
new file mode 100644
index 0000000000..4d56999f95
--- /dev/null
+++ b/engines/sky/skydefs.h
@@ -0,0 +1,4314 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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 SKYDEFS_H
+#define SKYDEFS_H
+
+#include "common/stdafx.h"
+
+namespace Sky {
+
+//This file is incomplete, several flags still missing.
+
+// grafixProg pointer types:
+#define OG_PTR_NULL 0
+#define OG_AUTOROUTE 1
+#define OG_COMPACT 2
+#define OG_COMPACTELEM 3 // needed by fnSetToStand
+#define OG_TALKTABLE 4
+
+// language codes:
+#define SKY_ENGLISH 0
+#define SKY_GERMAN 1
+#define SKY_FRENCH 2
+#define SKY_USA 3
+#define SKY_SWEDISH 4
+#define SKY_ITALIAN 5
+#define SKY_PORTUGUESE 6
+#define SKY_SPANISH 7
+
+#define ST_COLLISION_BIT 5
+
+#define S_COUNT 0
+#define S_FRAME 2
+#define S_AR_X 4
+#define S_AR_Y 6
+#define S_LENGTH 8
+
+#define KEY_BUFFER_SIZE 80
+#define SEQUENCE_COUNT 3
+
+#define FIRST_TEXT_COMPACT 23
+#define LAST_TEXT_COMPACT 33
+#define FIXED_TEXT_WIDTH 128
+
+//screen/grid defines
+#define GAME_SCREEN_WIDTH 320
+#define GAME_SCREEN_HEIGHT 192
+#define FULL_SCREEN_WIDTH 320
+#define FULL_SCREEN_HEIGHT 200
+
+#define TOT_NO_GRIDS 70 //total no. of grids supported
+#define GRID_SIZE 120 //grid size in bytes
+
+#define GRID_X 20
+#define GRID_Y 24
+#define GRID_W 16
+#define GRID_H 8
+
+#define GRID_W_SHIFT 4
+#define GRID_H_SHIFT 3
+
+#define TOP_LEFT_X 128
+#define TOP_LEFT_Y 136
+
+//item list defines
+#define section_0_item 119
+
+#define MAIN_CHAR_HEIGHT 12
+
+#define C_BASE_MODE 0
+#define C_BASE_MODE56 56
+#define C_ACTION_MODE 4
+#define C_SP_COLOUR 90
+#define C_MEGA_SET 112
+#define C_GRID_WIDTH 114
+#define C_ANIM_UP 122
+#define C_STAND_UP 138
+#define C_TURN_TABLE 158
+
+#define SECTION_0_ITEM 119 //item number of first item section
+#define NEXT_MEGA_SET (258 - C_GRID_WIDTH)
+
+#define SEND_SYNC 0xFFFF
+#define LF_START_FX 0xFFFE
+#define SAFE_START_SCREEN 0
+
+//autoroute defines
+#define UPY 0
+#define DOWNY 1
+#define LEFTY 2
+#define RIGHTY 3
+
+#define ROUTE_SPACE 64
+
+#define PCONLY_F_R3_1 0
+#define PCONLY_F_R3_2 0
+
+#define RESTART_BUTT_X 147
+#define RESTART_BUTT_Y 309
+#define RESTORE_BUTT_X 246
+#define RESTORE_BUTT_Y 309
+#define EXIT_BUTT_X 345
+#define EXIT_BUTT_Y 309
+
+#define L_SCRIPT 1
+#define L_AR 2
+#define L_AR_ANIM 3
+#define L_AR_TURNING 4
+#define L_ALT 5
+#define L_MOD_ANIMATE 6
+#define L_TURNING 7
+#define L_CURSOR 8
+#define L_TALK 9
+#define L_LISTEN 10
+#define L_STOPPED 11
+#define L_CHOOSE 12
+#define L_FRAMES 13
+#define L_PAUSE 14
+#define L_WAIT_SYNC 15
+#define L_SIMPLE_MOD 16
+
+// characters with own colour set
+#define SP_COL_FOSTER 194
+#define SP_COL_JOEY 216
+#define SP_COL_JOBS 209
+#define SP_COL_SO 218
+#define SP_COL_HOLO 234
+#define SP_COL_LAMB 203
+#define SP_COL_FOREMAN 205
+#define SP_COL_SHADES 217
+#define SP_COL_MONITOR 224
+#define SP_COL_WRECK 219 //wreck guard
+#define SP_COL_ANITA 73
+#define SP_COL_DAD 224
+#define SP_COL_SON 223
+#define SP_COL_GALAG 194
+#define SP_COL_ANCHOR 85 //194
+#define SP_COL_BURKE 192
+#define SP_COL_BODY 234
+#define SP_COL_MEDI 235
+#define SP_COL_SKORL 241 //skorl guard will probably go
+#define SP_COL_ANDROID2 222
+#define SP_COL_ANDROID3 222
+#define SP_COL_KEN 222
+#define SP_COL_HENRI30 128 //207
+#define SP_COL_GUARD31 216
+#define SP_DAN_COL 228
+#define SP_COL_BUZZER32 228 //124
+#define SP_COL_VINCENT32 193
+#define SP_COL_GARDENER32 145
+#define SP_COL_WITNESS 195
+#define SP_COL_JOBS82 209
+#define SP_COL_KEN81 224
+#define SP_COL_FATHER81 177
+#define SP_COL_TREVOR 216
+#define SP_COL_RADMAN 193
+#define SP_COL_BARMAN36 144
+#define SP_COL_BABS36 202
+#define SP_COL_GALLAGHER36 145
+#define SP_COL_COLSTON36 146
+#define SP_COL_JUKEBOX36 176
+#define SP_COL_JUDGE42 193
+#define SP_COL_CLERK42 195
+#define SP_COL_PROS42 217
+#define SP_COL_JOBS42 209
+
+#define SP_COL_HOLOGRAM_B 255
+#define SP_COL_BLUE 255
+#define SP_COL_LOADER 255
+
+#define SP_COL_UCHAR 255
+
+#define ST_NO_VMASK 0x200
+
+// Files.asm
+#define DISK_1 (2048)
+#define DISK_2 (2048*2)
+#define DISK_3 (2048*3)
+#define DISK_4 (2048*4)
+#define DISK_5 (2048*5)
+#define DISK_6 (2048*6)
+#define DISK_7 (2048*7)
+#define DISK_8 (2048*8)
+#define DISK_9 (2048*9)
+#define DISK_10 (2048*10)
+#define DISK_12 (2048*12)
+#define DISK_13 (2048*13)
+#define DISK_14 (2048*14)
+#define DISK_15 (2048*15)
+#define F_MODULE_0 60400
+#define F_MODULE_1 60401
+#define CHAR_SET_FILE 60150
+
+// Script.equ
+#define STD_BASE (0x0000+0x1)
+#define ADVISOR_188 (0x0000+0x2)
+#define JUST_INTERACT (0x0000+0x3)
+#define MEGA_CLICK (0x0000+0x4)
+#define STD_EXIT_RIGHT_ON (0x0000+0x5)
+#define STD_EXIT_LEFT_ON (0x0000+0x6)
+#define STD_EXIT_DOWN_ON (0x0000+0x7)
+#define STD_EXIT_UP_ON (0x0000+0x8)
+#define STD_ON (0x0000+0x9)
+#define STD_OFF (0x0000+0xa)
+#define TEXT_ON (0x0000+0xb)
+#define TEXT_OFF (0x0000+0xc)
+#define START_MENU (0x0000+0xd)
+#define MENU_SELECT (0x0000+0xe)
+#define CLICK_LEFT_ARROW (0x0000+0xf)
+#define CLICK_RIGHT_ARROW (0x0000+0x10)
+#define TOUCH_MENU (0x0000+0x11)
+#define UNTOUCH_MENU (0x0000+0x12)
+#define TOUCH_ARROW (0x0000+0x13)
+#define UNTOUCH_ARROW (0x0000+0x14)
+#define MENU_SCRIPT (0x0000+0x15)
+#define TEXT_CLICK (0x0000+0x16)
+#define RESET_MOUSE (0x0000+0x17)
+#define CLICK_DEBUG (0x0000+0x18)
+#define STD_MEGA_STOP (0x0000+0x19)
+#define STD_PLAYER_STOP (0x0000+0x1a)
+#define STD_MINI_BUMP (0x0000+0x1b)
+#define RET_OK (0x0000+0x1c)
+#define RET_FAIL (0x0000+0x1d)
+#define STD_ADJOIN_FLOOR (0x0000+0x1e)
+#define FLOOR_ACTION (0x0000+0x1f)
+#define ANIMATE_LOGIC (0x0000+0x20)
+#define STORE_188 (0x0000+0x21)
+#define TEXT_EDIT (0x0000+0x22)
+#define SHOUT_SSS (0x0000+0x23)
+#define SHOUT_ACTION (0x0000+0x24)
+#define MEGA_SSS (0x0000+0x25)
+#define MEGA_ACTION (0x0000+0x26)
+#define BASE_INTRO (0x0000+0x27)
+#define FURNACE_D_ACTION (0x0000+0x28)
+#define STAIR6_ACTION (0x0000+0x29)
+#define GET_TO_JP2 (0x0000+0x2a)
+#define JOEY_EXTRA (0x0000+0x2b)
+#define JOEY_LOGIC (0x0000+0x2c)
+#define SECURITY_EXIT_ACTION (0x0000+0x2d)
+#define SMALL_DOOR_ACTION (0x0000+0x2e)
+#define LINK_7_29 (0x0000+0x2f)
+#define LINK_29_7 (0x0000+0x30)
+#define LAMB_TO_3 (0x0000+0x31)
+#define LAMB_TO_2 (0x0000+0x32)
+#define SS_SIGN_ACTION (0x0000+0x33)
+#define SCANNER_10_LOGIC (0x0000+0x34)
+#define SLOT_10_ACTION (0x0000+0x35)
+#define DAD_SCAN_SSS (0x0000+0x36)
+#define LOBBY_SLOT_ACTION (0x0000+0x37)
+#define LINK_28_31 (0x0000+0x38)
+#define LINK_31_28 (0x0000+0x39)
+#define LINK_65_66 (0x0000+0x3a)
+#define DEATH_SCRIPT (0x0000+0x3b)
+#define RESTART_BUTTON_LOGIC (0x0000+0x3c)
+#define RESTORE_BUTTON_LOGIC (0x0000+0x3d)
+#define EXIT_BUTTON_LOGIC (0x0000+0x3e)
+#define DEATH_CLICK (0x0000+0x3f)
+#define STD_GIVE_UP (0x1000+0x1)
+#define GET_TO_TALK1 (0x1000+0x2)
+#define GET_TO_TALK2 (0x1000+0x3)
+#define STAIRS_FROM_LOW (0x1000+0x4)
+#define STAIRS_FROM_HIGH (0x1000+0x5)
+#define STAIR_ACTION (0x1000+0x6)
+#define CLIMB_STAIRS (0x1000+0x7)
+#define SS_SHOOTS (0x1000+0x8)
+#define UPSTAIR_ACTION (0x1000+0x9)
+#define DECEND (0x1000+0xa)
+#define START_MINI_SS (0x1000+0xb)
+#define ALERT_SS (0x1000+0xc)
+#define MORE_SS (0x1000+0xd)
+#define BAR_ACTION (0x1000+0xe)
+#define GET_TO_BAR (0x1000+0xf)
+#define FULL_SS_CUT (0x1000+0x10)
+#define CUT_SEQ (0x1000+0x11)
+#define FIRE_EXIT_ACTION (0x1000+0x12)
+#define GET_TO_FEXIT (0x1000+0x13)
+#define FEXIT_DOOR (0x1000+0x14)
+#define FEXIT_ON (0x1000+0x15)
+#define SMALL_DOOR_LOGIC (0x1000+0x16)
+#define GET_TO_SMALL_DOOR (0x1000+0x17)
+#define ER0_ACTION (0x1000+0x18)
+#define ER0_ALT (0x1000+0x19)
+#define GET_TO_ER0 (0x1000+0x1a)
+#define FAN1_LOGIC (0x1000+0x1b)
+#define FAN2_LOGIC (0x1000+0x1c)
+#define FAN3_LOGIC (0x1000+0x1d)
+#define FAN4_LOGIC (0x1000+0x1e)
+#define FAN5_LOGIC (0x1000+0x1f)
+#define FAN6_LOGIC (0x1000+0x20)
+#define FAN7_LOGIC (0x1000+0x21)
+#define UPLOAD_WAIT (0x1000+0x22)
+#define GET_TO_UPLOAD (0x1000+0x23)
+#define LAZER_GUN_LOGIC (0x1000+0x24)
+#define LOAD_POINT_LOGIC (0x1000+0x25)
+#define NOTICE_LOGIC (0x1000+0x26)
+#define NOTICE_ACTION (0x1000+0x27)
+#define GET_TO_NOTICE (0x1000+0x28)
+#define PRESS_LOGIC (0x1000+0x29)
+#define PRESS_ACTION (0x1000+0x2a)
+#define GET_TO_PRESS (0x1000+0x2b)
+#define LOAD_POINT_ACTION (0x1000+0x2c)
+#define SMALL_DOOR_ON (0x1000+0x2d)
+#define OUT_EXIT_ON (0x1000+0x2e)
+#define R1EXIT_DOOR (0x1000+0x2f)
+#define GET_TO_R1_DOOR (0x1000+0x30)
+#define S1_DOOR_ACTION (0x1000+0x31)
+#define GET_TO_NOTICE2 (0x1000+0x32)
+#define NOTICE2_ACTION (0x1000+0x33)
+#define GET_TO_SS_SIGN (0x1000+0x34)
+#define LFAN1_LOGIC (0x1000+0x35)
+#define LFAN2_LOGIC (0x1000+0x36)
+#define SMOKE1_LOGIC (0x1000+0x37)
+#define SMOKE2_LOGIC (0x1000+0x38)
+#define FIRE1_LOGIC (0x1000+0x39)
+#define FIRE2_LOGIC (0x1000+0x3a)
+#define CAR_LOGIC (0x1000+0x3b)
+#define ER0_WALK_ON (0x1000+0x3c)
+#define S2_WALK_ON (0x1000+0x3d)
+#define EL2_ACTION (0x1000+0x3e)
+#define GET_TO_EL2 (0x1000+0x3f)
+#define GET_TO_TALK21 (0x1000+0x40)
+#define MEGA_FAILED_S2 (0x1000+0x41)
+#define GET_TO_TALK22 (0x1000+0x42)
+#define GET_TO_ER2 (0x1000+0x43)
+#define FIRST_INTERACT (0x1000+0x44)
+#define ER2_ACTION (0x1000+0x45)
+#define TOP_LIFT_ACTION (0x1000+0x46)
+#define LIFT_WAIT (0x1000+0x47)
+#define GET_TO_LIFTER (0x1000+0x48)
+#define LIFT_TO_FLOOR (0x1000+0x49)
+#define TOP_BARREL_LOGIC (0x1000+0x4a)
+#define LIGHT_LOGIC (0x1000+0x4b)
+#define GET_TO_LIGHT1 (0x1000+0x4c)
+#define PANEL_LOGIC (0x1000+0x4d)
+#define ALARM_LOGIC (0x1000+0x4e)
+#define GET_TO_HOLE (0x1000+0x4f)
+#define HOLE_ACTION (0x1000+0x50)
+#define DEAD_LOSS (0x1000+0x51)
+#define GET_TO_TRANSPORTER (0x1000+0x52)
+#define TRANSPORTER_ACTION (0x1000+0x53)
+#define TRANS_ALIVE_ACTION (0x1000+0x54)
+#define JOEY_START (0x1000+0x55)
+#define JOEY_MISSION (0x1000+0x56)
+#define TRANS_MISSION (0x1000+0x57)
+#define SHELL_ACTION (0x1000+0x58)
+#define GET_TO_SHELL (0x1000+0x59)
+#define LIGHT1_ACTION (0x1000+0x5a)
+#define GET_TO_LEDS (0x1000+0x5b)
+#define GT_PANEL2 (0x1000+0x5c)
+#define PANEL2_ACTION (0x1000+0x5d)
+#define GT_JUNK1 (0x1000+0x5e)
+#define JUNK1_ACTION (0x1000+0x5f)
+#define GT_JUNK2 (0x1000+0x60)
+#define JUNK2_ACTION (0x1000+0x61)
+#define TOP_LIFT_LOGIC (0x1000+0x62)
+#define TOP_LIFT_2_LOGIC (0x1000+0x63)
+#define LOW_LIFT_LOGIC (0x1000+0x64)
+#define LOW_LIFT2_LOGIC (0x1000+0x65)
+#define LOW_LIFT3_LOGIC (0x1000+0x66)
+#define STEVE_SPY_LOGIC (0x1000+0x67)
+#define LOW_BARREL_LOGIC (0x1000+0x68)
+#define CONVEY_LOGIC (0x1000+0x69)
+#define FLY_LOGIC (0x1000+0x6a)
+#define FURNACE_LOGIC (0x1000+0x6b)
+#define LIGHTS1_LOGIC (0x1000+0x6c)
+#define EYE_BALL_LOGIC (0x1000+0x6d)
+#define NEW_EYE_BALL (0x1000+0x6e)
+#define FURNACE_DOOR_LOGIC (0x1000+0x6f)
+#define GET_TO_FURNACE_DOOR (0x1000+0x70)
+#define GET_TO_SLOT (0x1000+0x71)
+#define SLOT_ACTION (0x1000+0x72)
+#define SLOT_MISSION (0x1000+0x73)
+#define SHADES_LOGIC (0x1000+0x74)
+#define CORNER_MISSION (0x1000+0x75)
+#define EYE_BOLT_LOGIC (0x1000+0x76)
+#define SMOULDER_LOGIC (0x1000+0x77)
+#define GET_TO_BODY (0x1000+0x78)
+#define SMOULDER_ACTION (0x1000+0x79)
+#define GET_TO_EYE (0x1000+0x7a)
+#define EYE_ACTION (0x1000+0x7b)
+#define GET_TO_FURNACE (0x1000+0x7c)
+#define FURNACE_ACTION (0x1000+0x7d)
+#define FURNACE_EXIT_ON (0x1000+0x7e)
+#define GET_TO_EL4 (0x1000+0x7f)
+#define S4_WALK_ON (0x1000+0x80)
+#define EL4_ACTION (0x1000+0x81)
+#define PLAYER_FAIL_S4 (0x1000+0x82)
+#define GET_TO_TALK41 (0x1000+0x83)
+#define MEGA_FAILED_S4 (0x1000+0x84)
+#define GET_TO_TALK42 (0x1000+0x85)
+#define TV_LOGIC (0x1000+0x86)
+#define KNOB_ACTION (0x1000+0x87)
+#define KNOB_LOGIC (0x1000+0x88)
+#define CHUCK_LOGIC (0x1000+0x89)
+#define LAZER_LOGIC (0x1000+0x8a)
+#define GT_LAZER (0x1000+0x8b)
+#define LAZER_ACTION (0x1000+0x8c)
+#define CUPBOARD_LOGIC (0x1000+0x8d)
+#define CUPBOARD_ALERT (0x1000+0x8e)
+#define CUPBOARD_ACTION (0x1000+0x8f)
+#define GET_TO_CUPBOARD (0x1000+0x90)
+#define GET_TO_SHELVES (0x1000+0x91)
+#define GET_TO_KNOB (0x1000+0x92)
+#define GET_TO_CHUCK (0x1000+0x93)
+#define GET_TO_SCREENS (0x1000+0x94)
+#define SPANNER_ACTION (0x1000+0x95)
+#define SARNIE_ACTION (0x1000+0x96)
+#define GET_TO_BUTTONS (0x1000+0x97)
+#define MONITOR_LOGIC (0x1000+0x98)
+#define BUTTON_ACTION (0x1000+0x99)
+#define POSTCARD_ACTION (0x1000+0x9a)
+#define GET_TO_POSTCARD (0x1000+0x9b)
+#define NOTICE4_ACTION (0x1000+0x9c)
+#define CHUCK_ACTION (0x1000+0x9d)
+#define TV_1_ACTION (0x1000+0x9e)
+#define TV_2_ACTION (0x1000+0x9f)
+#define GET_TO_MONITOR (0x1000+0xa0)
+#define JOBS_ALARMED (0x1000+0xa1)
+#define JOBS_S4 (0x1000+0xa2)
+#define MORE_JOBS (0x1000+0xa3)
+#define BASIC_JOBS (0x1000+0xa4)
+#define START_JOBS (0x1000+0xa5)
+#define DEAD_LOGIC (0x1000+0xa6)
+#define LOADER_LOGIC (0x1000+0xa7)
+#define LOADER_START (0x1000+0xa8)
+#define JOBS_SPEECH (0x1000+0xa9)
+#define UNUSED (0x1000+0xaa)
+#define GET_TO_STAIRS6 (0x2000+0x1)
+#define GET_SECURITY_S6 (0x2000+0x2)
+#define JOEY_FLY_TO_6 (0x2000+0x3)
+#define GET_TO_L_EXIT_S6 (0x2000+0x4)
+#define EL6_ACTION (0x2000+0x5)
+#define S5_WALK_ON (0x2000+0x6)
+#define S5_STROLL_ON (0x2000+0x7)
+#define GET_TO_R_EXIT_S5 (0x2000+0x8)
+#define ER5_ACTION (0x2000+0x9)
+#define S6_WALK_ON (0x2000+0xa)
+#define GET_TO_R_EXIT_S6 (0x2000+0xb)
+#define S6_RWALK_ON (0x2000+0xc)
+#define INTO_18_FAIL (0x2000+0xd)
+#define GET_TO_L_EXIT_S5 (0x2000+0xe)
+#define LDOOR_5_ACTION (0x2000+0xf)
+#define S6_DOOR_ACTION (0x2000+0x10)
+#define S6_SEC_WALK_ON (0x2000+0x11)
+#define SKORL_LOGIC (0x2000+0x12)
+#define SKORL_SSS (0x2000+0x13)
+#define SKORL_ACTION (0x2000+0x14)
+#define GET_TO_SKORL (0x2000+0x15)
+#define GET_TO_SECURITY_EXIT (0x2000+0x16)
+#define ER6_ACTION (0x2000+0x17)
+#define EL7_ACTION (0x2000+0x18)
+#define GET_TO_L_EXIT_S7 (0x2000+0x19)
+#define S7_WALK_ON (0x2000+0x1a)
+#define GET_TO_R_EXIT_S7 (0x2000+0x1b)
+#define ER7_ACTION (0x2000+0x1c)
+#define S8_WALK_ON (0x2000+0x1d)
+#define ED8_ACTION (0x2000+0x1e)
+#define GET_TO_EXIT_S8 (0x2000+0x1f)
+#define S7_RIGHT_ON (0x2000+0x20)
+#define GET_TO_WRECK (0x2000+0x21)
+#define WRECK_ACTION (0x2000+0x22)
+#define WRECK_LOGIC (0x2000+0x23)
+#define FACT_FAIL (0x2000+0x24)
+#define GET_TO_FACTORY (0x2000+0x25)
+#define FACTORY_ENTRY_ACTION (0x2000+0x26)
+#define S12_WALK_ON (0x2000+0x27)
+#define GT_S7_LINC (0x2000+0x28)
+#define GT_S7_SLOT (0x2000+0x29)
+#define GT_LIFT_NOTICE (0x2000+0x2a)
+#define LIFT_NOTICE_ACTION (0x2000+0x2b)
+#define S7_SLOT_ACTION (0x2000+0x2c)
+#define LINC_S7_ACTION (0x2000+0x2d)
+#define LEFT_FAIL_7 (0x2000+0x2e)
+#define GT_L_TALK_7 (0x2000+0x2f)
+#define RIGHT_FAIL_7 (0x2000+0x30)
+#define GT_R_TALK_7 (0x2000+0x31)
+#define JOEY_OUT_OF_LIFT7 (0x2000+0x32)
+#define CABLE_7_LOGIC (0x2000+0x33)
+#define GT_CABLE_7 (0x2000+0x34)
+#define CABLE_7_ACTION (0x2000+0x35)
+#define CABLE_MISSION (0x2000+0x36)
+#define GT_S7_LIFT (0x2000+0x37)
+#define S7_LIFT_LOGIC (0x2000+0x38)
+#define JOEY_TO_LIFT (0x2000+0x39)
+#define LIFT_S7_ACTION (0x2000+0x3a)
+#define COPTER_ACTION (0x2000+0x3b)
+#define S9_WALK_ON (0x2000+0x3c)
+#define FANS_LOGIC (0x2000+0x3d)
+#define GET_TO_L_EXIT_S9 (0x2000+0x3e)
+#define EL9_ACTION (0x2000+0x3f)
+#define LOBBY_DOOR_LOGIC (0x2000+0x40)
+#define LOBBY_DOOR_ON (0x2000+0x41)
+#define GET_TO_LOBBY_DOOR (0x2000+0x42)
+#define LOBBY_DOOR_ACTION (0x2000+0x43)
+#define SCANNER_LOGIC (0x2000+0x44)
+#define GET_TO_SCANNER (0x2000+0x45)
+#define SCANNER_ACTION (0x2000+0x46)
+#define DAD_LOGIC (0x2000+0x47)
+#define DAD_SSS (0x2000+0x48)
+#define DAD_ACTION (0x2000+0x49)
+#define GET_TO_DAD (0x2000+0x4a)
+#define GET_TO_SON (0x2000+0x4b)
+#define SON_LOGIC (0x2000+0x4c)
+#define SON_ACTION (0x2000+0x4d)
+#define GT_LINC_S9 (0x2000+0x4e)
+#define LINC_S9_ACTION (0x2000+0x4f)
+#define GET_TO_R_EXIT_S18 (0x2000+0x50)
+#define S18_WALK_ON (0x2000+0x51)
+#define ER18_ACTION (0x2000+0x52)
+#define MONITOR_SLEEP (0x2000+0x53)
+#define SON_SSS (0x2000+0x54)
+#define STEAM_FRIGHT (0x2000+0x55)
+#define MONITOR_ALERT (0x2000+0x56)
+#define STEAM_LOGIC (0x2000+0x57)
+#define POWER_DOOR_LOGIC (0x2000+0x58)
+#define POWER_MOTOR_LOGIC (0x2000+0x59)
+#define POWER_PANEL_LOGIC (0x2000+0x5a)
+#define GET_TO_POWER_PANEL (0x2000+0x5b)
+#define SOCKET_ACTION (0x2000+0x5c)
+#define POWER_SWITCH_LOGIC (0x2000+0x5d)
+#define GET_TO_POWER_SWITCH (0x2000+0x5e)
+#define SWITCH_ACTION (0x2000+0x5f)
+#define CHAIR_FAIL (0x2000+0x60)
+#define GET_TO_POWER_CHAIR (0x2000+0x61)
+#define GET_TO_LEFT_SKULL (0x2000+0x62)
+#define GET_TO_RIGHT_SKULL (0x2000+0x63)
+#define LEFT_SKULL_ACTION (0x2000+0x64)
+#define POWER_BANG_LOGIC (0x2000+0x65)
+#define RIGHT_SKULL_ACTION (0x2000+0x66)
+#define GET_TO_TALK (0x2000+0x67)
+#define GORDON_SSS (0x2000+0x68)
+#define SAT_GORDON_ACTION (0x2000+0x69)
+#define GET_TO_POWER_DOOR (0x2000+0x6a)
+#define POWER_DOOR_ACTION (0x2000+0x6b)
+#define JOEY_BUTTON_MISSION (0x2000+0x6c)
+#define LEFT_LEVER_LOGIC (0x2000+0x6d)
+#define RIGHT_LEVER_LOGIC (0x2000+0x6e)
+#define LEFT_LEVER_ACTION (0x2000+0x6f)
+#define RIGHT_LEVER_ACTION (0x2000+0x70)
+#define GET_TO_RIGHT_LEVER (0x2000+0x71)
+#define GET_TO_LEFT_LEVER (0x2000+0x72)
+#define CHAIR_ACTION (0x2000+0x73)
+#define S12_LEFT_ON (0x2000+0x74)
+#define GET_TO_FACTORY_EXIT (0x2000+0x75)
+#define FACTORY_EXIT_ACTION (0x2000+0x76)
+#define LAMB_LEAVE_FACTORY (0x2000+0x77)
+#define LAMB_FACT_2 (0x2000+0x78)
+#define LAMB_FACT_RETURN (0x2000+0x79)
+#define LAMB_FACTORY_START (0x2000+0x7a)
+#define LAMB_FORCE_START (0x2000+0x7b)
+#define GT_FACT1_EXIT (0x2000+0x7c)
+#define FACT1_EXIT_ACTION (0x2000+0x7d)
+#define S12_RIGHT_ON (0x2000+0x7e)
+#define ANITA_WORK (0x2000+0x7f)
+#define ANITA_SSS (0x2000+0x80)
+#define ANITA_ACTION (0x2000+0x81)
+#define GT_ANITA (0x2000+0x82)
+#define BOTBELT_LOGIC (0x2000+0x83)
+#define STD_FACT_LOGIC (0x2000+0x84)
+#define ANITA_ALERT (0x2000+0x85)
+#define ANITA_SPY_ACTION (0x2000+0x86)
+#define ANITA_SPY_LOGIC (0x2000+0x87)
+#define TICK_OFF_II (0x2000+0x88)
+#define GT_TICK_OFF (0x2000+0x89)
+#define WELDER_LOGIC (0x2000+0x8a)
+#define GT_WELDER (0x2000+0x8b)
+#define WELDER_ACTION (0x2000+0x8c)
+#define LEFT_FAIL_12 (0x2000+0x8d)
+#define GT_L_TALK_12 (0x2000+0x8e)
+#define RIGHT_FAIL_12 (0x2000+0x8f)
+#define GT_R_TALK_12 (0x2000+0x90)
+#define WELDER_MISSION (0x2000+0x91)
+#define JOEY_WELD_MISSION (0x2000+0x92)
+#define GT_STUMP (0x2000+0x93)
+#define STUMP_ACTION (0x2000+0x94)
+#define GT_CONSOLE_12 (0x2000+0x95)
+#define CONSOLE_12_ACTION (0x2000+0x96)
+#define GT_TOUR_1 (0x2000+0x97)
+#define GT_TOUR_2 (0x2000+0x98)
+#define FOREMAN_LAMB (0x2000+0x99)
+#define FOSTER_TOUR (0x2000+0x9a)
+#define LAMB_TOUR (0x2000+0x9b)
+#define ON_FROM_S15 (0x2000+0x9c)
+#define S13_LEFT_ON (0x2000+0x9d)
+#define GT_FACT2_L_EXIT (0x2000+0x9e)
+#define FACT2_ACTION (0x2000+0x9f)
+#define FACT2_RIGHT_ACTION (0x2000+0xa0)
+#define GT_FACT2_R_EXIT (0x2000+0xa1)
+#define S13_RIGHT_ON (0x2000+0xa2)
+#define GT_FACT2_STORE_EXIT (0x2000+0xa3)
+#define FACT2_STORE_ACTION (0x2000+0xa4)
+#define GT_COGS (0x2000+0xa5)
+#define FOREMAN_LOGIC (0x2000+0xa6)
+#define FOREMAN_ALERT (0x2000+0xa7)
+#define COGS_ACTION (0x2000+0xa8)
+#define GT_LITE1 (0x2000+0xa9)
+#define STORE_ROOM_STOP (0x2000+0xaa)
+#define SENSOR_LOGIC (0x2000+0xab)
+#define RIGHT_FAIL_13 (0x2000+0xac)
+#define GT_R_TALK_13 (0x2000+0xad)
+#define LEFT_FAIL_13 (0x2000+0xae)
+#define GT_L_TALK_13 (0x2000+0xaf)
+#define GT_STORE_STOP (0x2000+0xb0)
+#define FACT2_FOREMAN_ALERT (0x2000+0xb1)
+#define FACT2_STOP (0x2000+0xb2)
+#define FACT2_SPY_LOGIC (0x2000+0xb3)
+#define GT_WINDOW (0x2000+0xb4)
+#define WINDOW_ACTION (0x2000+0xb5)
+#define FACT_CONSOLE_LOGIC (0x2000+0xb6)
+#define FOREMAN_STORE_CHECK (0x2000+0xb7)
+#define GT_SENSORS (0x2000+0xb8)
+#define SENSORS_ACTION (0x2000+0xb9)
+#define GT_FACT_CONSOLE (0x2000+0xba)
+#define CONSOLE_13_ACTION (0x2000+0xbb)
+#define RAD_BACK (0x2000+0xbc)
+#define FACT3_ACTION (0x2000+0xbd)
+#define S14_LEFT_ON (0x2000+0xbe)
+#define GT_FACT3_L_EXIT (0x2000+0xbf)
+#define ALT_NU_ANITA (0x2000+0xc0)
+#define GT_NU_ANITA (0x2000+0xc1)
+#define GT_FACT3_R_EXIT (0x2000+0xc2)
+#define LOCKER3_LOGIC (0x2000+0xc3)
+#define LOCKER2_LOGIC (0x2000+0xc4)
+#define LOCKER1_LOGIC (0x2000+0xc5)
+#define LOCKER3_ACTION (0x2000+0xc6)
+#define GT_LOCKER3 (0x2000+0xc7)
+#define LOCKER2_ACTION (0x2000+0xc8)
+#define GT_LOCKER2 (0x2000+0xc9)
+#define GT_LOCKER1 (0x2000+0xca)
+#define LOCKER1_ACTION (0x2000+0xcb)
+#define GT_MACHINE (0x2000+0xcc)
+#define MACHINE_ACTION (0x2000+0xcd)
+#define FACT3_R_ACTION (0x2000+0xce)
+#define S14_RIGHT_ON (0x2000+0xcf)
+#define NU_ANITA_SSS (0x2000+0xd0)
+#define RADMAN_LOGIC (0x2000+0xd1)
+#define LEFT_FAIL_14 (0x2000+0xd2)
+#define GT_L_TALK_14 (0x2000+0xd3)
+#define RIGHT_FAIL_14 (0x2000+0xd4)
+#define GT_R_TALK_14 (0x2000+0xd5)
+#define RAD_SCREEN_ACTION (0x2000+0xd6)
+#define GT_RAD_SCREEN (0x2000+0xd7)
+#define GT_14_CONSOLE (0x2000+0xd8)
+#define CONSOLE_14_ACTION (0x2000+0xd9)
+#define COAT_LOGIC (0x2000+0xda)
+#define GT_COAT (0x2000+0xdb)
+#define COAT_ACTION (0x2000+0xdc)
+#define S15_WALK_ON (0x2000+0xdd)
+#define GT_STORE_EXIT (0x2000+0xde)
+#define STORE_EXIT_ACTION (0x2000+0xdf)
+#define JOEY_42_MISS (0x2000+0xe0)
+#define JOEY_JUNCTION_MISS (0x2000+0xe1)
+#define GT_JUNCTION_BOX (0x2000+0xe2)
+#define JUNCTION_ACTION (0x2000+0xe3)
+#define FLAP_LOGIC (0x2000+0xe4)
+#define GT_FLAP (0x2000+0xe5)
+#define FLAP_ACTION (0x2000+0xe6)
+#define GT_SKEY (0x2000+0xe7)
+#define GT_WD40 (0x2000+0xe8)
+#define SKEY_ACTION (0x2000+0xe9)
+#define WD40_ACTION (0x2000+0xea)
+#define SHELF_OBJECT_LOGIC (0x2000+0xeb)
+#define FLOOR_PUTTY_ACTION (0x2000+0xec)
+#define GT_PUTTY (0x2000+0xed)
+#define FORKLIFT_LOGIC (0x2000+0xee)
+#define S16_LEFT_ON (0x2000+0xef)
+#define ENTRANCE_EXIT_ACTION (0x2000+0xf0)
+#define GT_ENTRANCE_EXIT (0x2000+0xf1)
+#define GT_ALT_CONSOLE (0x2000+0xf2)
+#define GT_REACTOR_CONSOLE (0x2000+0xf3)
+#define REACTOR_PC_ACTION (0x2000+0xf4)
+#define REACTOR_DOOR_ACTION (0x2000+0xf5)
+#define GT_REACTOR_DOOR (0x2000+0xf6)
+#define LEFT_FAIL_16 (0x2000+0xf7)
+#define GT_L_TALK_16 (0x2000+0xf8)
+#define RIGHT_FAIL_16 (0x2000+0xf9)
+#define GT_R_TALK_16 (0x2000+0xfa)
+#define REACTOR_ON (0x2000+0xfb)
+#define S17_LEFT_ON (0x2000+0xfc)
+#define GT_CORE_EXIT (0x2000+0xfd)
+#define CORE_EXIT_ACTION (0x2000+0xfe)
+#define S16_CORE_ON (0x2000+0xff)
+#define GT_ANITA_CARD (0x2000+0x100)
+#define ANITA_CARD_ACTION (0x2000+0x101)
+#define GT_RODS (0x2000+0x102)
+#define RODS_ACTION (0x2000+0x103)
+#define CONSOLE_16_LOGIC (0x2000+0x104)
+#define S10_RIGHT_ON (0x3000+0x1)
+#define GT_LEFT_EXIT_10 (0x3000+0x2)
+#define EL10_ACTION (0x3000+0x3)
+#define LIFT_10_LOGIC (0x3000+0x4)
+#define GT_SLOT_10 (0x3000+0x5)
+#define POD_LOGIC (0x3000+0x6)
+#define POD_LIGHT_LOGIC (0x3000+0x7)
+#define POD_LIGHT_ACTION (0x3000+0x8)
+#define GT_POD_LIGHT (0x3000+0x9)
+#define GT_LINC_10 (0x3000+0xa)
+#define LINC_10_ACTION (0x3000+0xb)
+#define GT_FLOOR_FROM_CHAIR10 (0x3000+0xc)
+#define GT_TERMINAL_10 (0x3000+0xd)
+#define TERMINAL_10_ACTION (0x3000+0xe)
+#define GT_SCANNER_10 (0x3000+0xf)
+#define SCANNER_10_ACTION (0x3000+0x10)
+#define GT_DOOR_10 (0x3000+0x11)
+#define DOOR_10_ACTION (0x3000+0x12)
+#define GT_SLOT_11 (0x3000+0x13)
+#define SLOT_11_ACTION (0x3000+0x14)
+#define GT_SOCCER_1 (0x3000+0x15)
+#define SOCCER_1_ACTION (0x3000+0x16)
+#define GT_SOCCER_2 (0x3000+0x17)
+#define GT_SOCCER_3 (0x3000+0x18)
+#define GT_SOCCER_4 (0x3000+0x19)
+#define GT_SOCCER_5 (0x3000+0x1a)
+#define SLAT_ACTION (0x3000+0x1b)
+#define GT_RIGHT_EXIT_11 (0x3000+0x1c)
+#define ER11_ACTION (0x3000+0x1d)
+#define S11_LEFT_ON (0x3000+0x1e)
+#define GT_LEFT_EXIT_19 (0x3000+0x1f)
+#define EL19_ACTION (0x3000+0x20)
+#define GT_TOP_RIGHT_19 (0x3000+0x21)
+#define TOP_R19_ACTION (0x3000+0x22)
+#define UCHAR_SSS (0x3000+0x23)
+#define UCHAR_ACTION (0x3000+0x24)
+#define GET_TO_UCHAR (0x3000+0x25)
+#define UCHAR_LOGIC (0x3000+0x26)
+#define S20_START_ON (0x3000+0x27)
+#define DOWN_20_FAIL (0x3000+0x28)
+#define GT_DOWN_EXIT_20 (0x3000+0x29)
+#define ED20_ACTION (0x3000+0x2a)
+#define REICH_20_ON (0x3000+0x2b)
+#define REICH_DOOR_FAIL (0x3000+0x2c)
+#define GT_REICH_DOOR_20 (0x3000+0x2d)
+#define REICH_DOOR_20_ACTION (0x3000+0x2e)
+#define GT_REICH_SLOT (0x3000+0x2f)
+#define REICH_SLOT_ACTION (0x3000+0x30)
+#define S20_REICH_ON (0x3000+0x31)
+#define REICH_DOOR_20_LOGIC (0x3000+0x32)
+#define LAMB_DOOR_20_LOGIC (0x3000+0x33)
+#define LAMB_SLOT_FAIL (0x3000+0x34)
+#define GT_LAMB_SLOT (0x3000+0x35)
+#define LAMB_SLOT_ACTION (0x3000+0x36)
+#define LAMB_20_ON (0x3000+0x37)
+#define LAMB_DOOR_FAIL (0x3000+0x38)
+#define GT_LAMB_DOOR_20 (0x3000+0x39)
+#define LAMB_DOOR_20_ACTION (0x3000+0x3a)
+#define S20_LAMB_ON (0x3000+0x3b)
+#define GT_SHRUB_1 (0x3000+0x3c)
+#define SHRUB_1_ACTION (0x3000+0x3d)
+#define GT_SHRUB_2 (0x3000+0x3e)
+#define SHRUB_2_ACTION (0x3000+0x3f)
+#define GT_SHRUB_3 (0x3000+0x40)
+#define SHRUB_3_ACTION (0x3000+0x41)
+#define START_20 (0x3000+0x42)
+#define GAL_LOGIC (0x3000+0x43)
+#define GT_GALLAGER_BEL (0x3000+0x44)
+#define GAL_BEL_ACTION (0x3000+0x45)
+#define GT_REICH_WINDOW (0x3000+0x46)
+#define REICH_WINDOW_ACTION (0x3000+0x47)
+#define GT_LAMB_WINDOW (0x3000+0x48)
+#define LAMB_WINDOW_ACTION (0x3000+0x49)
+#define LEFT_FAIL_20 (0x3000+0x4a)
+#define GT_L_TALK_20 (0x3000+0x4b)
+#define RIGHT_FAIL_20 (0x3000+0x4c)
+#define GT_R_TALK_20 (0x3000+0x4d)
+#define S21_START_ON (0x3000+0x4e)
+#define GT_LEFT_EXIT_21 (0x3000+0x4f)
+#define EL21_ACTION (0x3000+0x50)
+#define GT_LAMBS_BOOKS (0x3000+0x51)
+#define LAMBS_BOOKS_ACTION (0x3000+0x52)
+#define GT_LAMBS_CHAIR (0x3000+0x53)
+#define LAMBS_CHAIR_ACTION (0x3000+0x54)
+#define GT_DISPENSOR (0x3000+0x55)
+#define DISPENSOR_ACTION (0x3000+0x56)
+#define CAT_FOOD_LOGIC (0x3000+0x57)
+#define GT_CAT_FOOD (0x3000+0x58)
+#define CAT_FOOD_ACTION (0x3000+0x59)
+#define VIDEO_LOGIC (0x3000+0x5a)
+#define GT_VIDEO (0x3000+0x5b)
+#define VIDEO_ACTION (0x3000+0x5c)
+#define GT_CASSETTE (0x3000+0x5d)
+#define CASSETTE_ACTION (0x3000+0x5e)
+#define GT_BIG_PICT1 (0x3000+0x5f)
+#define BIG_PICT1_ACTION (0x3000+0x60)
+#define GT_VIDEO_SCREEN (0x3000+0x61)
+#define VIDEO_SCREEN_ACTION (0x3000+0x62)
+#define VIDEO_SCREEN_LOGIC (0x3000+0x63)
+#define GT_BIG_PICT2 (0x3000+0x64)
+#define BIG_PICT2_ACTION (0x3000+0x65)
+#define GT_BIG_PICT3 (0x3000+0x66)
+#define BIG_PICT3_ACTION (0x3000+0x67)
+#define CAT_LOGIC (0x3000+0x68)
+#define GT_CAT (0x3000+0x69)
+#define CAT_ACTION (0x3000+0x6a)
+#define INNER_LAMB_DOOR_LOGIC (0x3000+0x6b)
+#define S22_START_ON (0x3000+0x6c)
+#define GT_RIGHT_EXIT_22 (0x3000+0x6d)
+#define ER22_ACTION (0x3000+0x6e)
+#define GT_LAMB_BED (0x3000+0x6f)
+#define BED_ACTION (0x3000+0x70)
+#define GT_LAMB_TV (0x3000+0x71)
+#define LAMB_TV_ACTION (0x3000+0x72)
+#define GT_FISH_TANK (0x3000+0x73)
+#define FISH_TANK_ACTION (0x3000+0x74)
+#define FISH_POSTER_ACTION (0x3000+0x75)
+#define PILLOW_LOGIC (0x3000+0x76)
+#define GT_PILLOW (0x3000+0x77)
+#define PILLOW_ACTION (0x3000+0x78)
+#define GT_MAGAZINE (0x3000+0x79)
+#define MAGAZINE_ACTION (0x3000+0x7a)
+#define FISH_LOGIC (0x3000+0x7b)
+#define GT_REICH_CHAIR (0x3000+0x7c)
+#define REICH_CHAIR_ACTION (0x3000+0x7d)
+#define GT_CABINET (0x3000+0x7e)
+#define CABINET_ACTION (0x3000+0x7f)
+#define GT_CERT (0x3000+0x80)
+#define CERT_ACTION (0x3000+0x81)
+#define GT_REICH_PICTURE (0x3000+0x82)
+#define REICH_PICTURE_ACTION (0x3000+0x83)
+#define GT_FISH_FOOD (0x3000+0x84)
+#define FISH_FOOD_ACTION (0x3000+0x85)
+#define INNER_R_DOOR_LOGIC (0x3000+0x86)
+#define S23_LEFT_ON (0x3000+0x87)
+#define S23_ANCHOR_ON (0x3000+0x88)
+#define S23_TRAVEL_ON (0x3000+0x89)
+#define GT_LEFT_EXIT_23 (0x3000+0x8a)
+#define EL23_ACTION (0x3000+0x8b)
+#define GT_ANCHOR_EXIT_23 (0x3000+0x8c)
+#define ANCHOR23_ACTION (0x3000+0x8d)
+#define GT_TRAVEL_FAIL (0x3000+0x8e)
+#define GT_TRAVEL_EXIT_23 (0x3000+0x8f)
+#define TRAVEL_23_ACTION (0x3000+0x90)
+#define GT_BIN_23 (0x3000+0x91)
+#define BIN_23_ACTION (0x3000+0x92)
+#define GT_SCULPTURE (0x3000+0x93)
+#define SCULPTURE_ACTION (0x3000+0x94)
+#define GT_LINK_23 (0x3000+0x95)
+#define LINK_23_ACTION (0x3000+0x96)
+#define GT_WRECK_23 (0x3000+0x97)
+#define WRECK_23_ACTION (0x3000+0x98)
+#define GT_SMALL_23 (0x3000+0x99)
+#define SML_EXIT_S23_ACTION (0x3000+0x9a)
+#define S24_LEFT_ON (0x3000+0x9b)
+#define GT_LEFT_EXIT_24 (0x3000+0x9c)
+#define EL24_ACTION (0x3000+0x9d)
+#define GT_LONDON_POSTER (0x3000+0x9e)
+#define LONDON_ACTION (0x3000+0x9f)
+#define GT_NEW_YORK (0x3000+0xa0)
+#define NEW_YORK_ACTION (0x3000+0xa1)
+#define GT_MURAL (0x3000+0xa2)
+#define MURAL_ACTION (0x3000+0xa3)
+#define GT_PIDGEONS (0x3000+0xa4)
+#define PIDGEONS_ACTION (0x3000+0xa5)
+#define TREVOR_LOGIC (0x3000+0xa6)
+#define TREVOR_SSS (0x3000+0xa7)
+#define TREVOR_ACTION (0x3000+0xa8)
+#define GT_TREVOR (0x3000+0xa9)
+#define TICKET_LOGIC (0x3000+0xaa)
+#define TICKET_ACTION (0x3000+0xab)
+#define GT_TICKET (0x3000+0xac)
+#define GT_GLOBE (0x3000+0xad)
+#define GLOBE_ACTION (0x3000+0xae)
+#define GLOBE_LOGIC (0x3000+0xaf)
+#define S25_LEFT_ON (0x3000+0xb0)
+#define GT_ANCHOR_EXIT_25 (0x3000+0xb1)
+#define ANCHOR25_ACTION (0x3000+0xb2)
+#define ANCHOR_LOGIC (0x3000+0xb3)
+#define ANCHOR_SSS (0x3000+0xb4)
+#define ANCHOR_ACTION (0x3000+0xb5)
+#define GT_ANCHOR (0x3000+0xb6)
+#define ANCHOR_MISSION (0x3000+0xb7)
+#define JOEY_PC_MISSION (0x3000+0xb8)
+#define GT_ANCHOR_PC (0x3000+0xb9)
+#define HOOK_LOGIC (0x3000+0xba)
+#define GT_STATUE_25 (0x3000+0xbb)
+#define STATUE_25_ACTION (0x3000+0xbc)
+#define HOOK_MISSION (0x3000+0xbd)
+#define LAZER_25_LOGIC (0x3000+0xbe)
+#define SPARK_25_LOGIC (0x3000+0xbf)
+#define GT_HOOK (0x3000+0xc0)
+#define HOOK_ACTION (0x3000+0xc1)
+#define GT_SALES_CHART (0x3000+0xc2)
+#define SALES_CHART_ACTION (0x3000+0xc3)
+#define S26_LEFT_ON (0x3000+0xc4)
+#define S26_RIGHT_ON (0x3000+0xc5)
+#define GT_RIGHT_EXIT_26 (0x3000+0xc6)
+#define ER26_ACTION (0x3000+0xc7)
+#define START_26 (0x3000+0xc8)
+#define GT_POSTER (0x3000+0xc9)
+#define POSTER1_ACTION (0x3000+0xca)
+#define POSTER2_ACTION (0x3000+0xcb)
+#define POSTER3_ACTION (0x3000+0xcc)
+#define POSTER4_ACTION (0x3000+0xcd)
+#define GT_PLANT (0x3000+0xce)
+#define PLANT_26_ACTION (0x3000+0xcf)
+#define NU_GT_HOLO (0x3000+0xd0)
+#define GT_HOLO (0x3000+0xd1)
+#define HOLO_ACTION (0x3000+0xd2)
+#define HELGA_LOGIC (0x3000+0xd3)
+#define JOEY_HELGA_MISSION (0x3000+0xd4)
+#define GT_LEFT_EXIT_26 (0x3000+0xd5)
+#define EL26_ACTION (0x3000+0xd6)
+#define HELGA_ACTION (0x3000+0xd7)
+#define BIO_DOOR_LOGIC (0x3000+0xd8)
+#define GT_BIO_DOOR (0x3000+0xd9)
+#define BIO_DOOR_ACTION (0x3000+0xda)
+#define GT_LEAFLET (0x3000+0xdb)
+#define LEAFLET_LOGIC (0x3000+0xdc)
+#define LEAFLET_ACTION (0x3000+0xdd)
+#define S27_RIGHT_ON (0x3000+0xde)
+#define GT_RIGHT_EXIT_27 (0x3000+0xdf)
+#define ER27_ACTION (0x3000+0xe0)
+#define GT_CHART1 (0x3000+0xe1)
+#define CHART1_ACTION (0x3000+0xe2)
+#define GT_CHART2 (0x3000+0xe3)
+#define CHART2_ACTION (0x3000+0xe4)
+#define GT_GAS (0x3000+0xe5)
+#define GAS_ACTION (0x3000+0xe6)
+#define GT_CHAIR_27 (0x3000+0xe7)
+#define CHAIR_27_ACTION (0x3000+0xe8)
+#define GT_FLOOR_FROM_CHAIR (0x3000+0xe9)
+#define GT_SCANNER_27 (0x3000+0xea)
+#define SCANNER_27_ACTION (0x3000+0xeb)
+#define GT_L_TALK_27 (0x3000+0xec)
+#define RIGHT_FAIL_27 (0x3000+0xed)
+#define GT_R_TALK_27 (0x3000+0xee)
+#define BURKE_LOGIC (0x3000+0xef)
+#define GT_MEDI_COMP (0x3000+0xf0)
+#define MEDI_COMP_ACTION (0x3000+0xf1)
+#define BURKE_1 (0x3000+0xf2)
+#define BURKE_2 (0x3000+0xf3)
+#define DR_BURKE_1 (0x3000+0xf4)
+#define SCANNER_27_LOGIC (0x3000+0xf5)
+#define HELMET_LOGIC (0x3000+0xf6)
+#define BODY_SSS (0x3000+0xf7)
+#define BODY_ACTION (0x3000+0xf8)
+#define BUSY_BODY (0x3000+0xf9)
+#define GT_BODY (0x3000+0xfa)
+#define GT_HELMET (0x3000+0xfb)
+#define HELMET_ACTION (0x3000+0xfc)
+#define GLASS_SLOT_LOGIC (0x3000+0xfd)
+#define GLASS_MISSION (0x3000+0xfe)
+#define MEDIC_LOGIC (0x3000+0xff)
+#define S28_RIGHT_ON (0x3000+0x100)
+#define GT_RIGHT_EXIT_28 (0x3000+0x101)
+#define ER28_ACTION (0x3000+0x102)
+#define GT_LEFT_EXIT_28 (0x3000+0x103)
+#define EL28_ACTION (0x3000+0x104)
+#define S28_LEFT_ON (0x3000+0x105)
+#define GT_DUSTBIN_28 (0x3000+0x106)
+#define DUSTBIN_ACTION (0x3000+0x107)
+#define UP_28_FAIL (0x3000+0x108)
+#define GT_UP_EXIT_28 (0x3000+0x109)
+#define EU28_ACTION (0x3000+0x10a)
+#define S28_UP_ON (0x3000+0x10b)
+#define LEFT_FAIL_28 (0x3000+0x10c)
+#define GT_L_TALK_28 (0x3000+0x10d)
+#define RIGHT_FAIL_28 (0x3000+0x10e)
+#define GT_R_TALK_28 (0x3000+0x10f)
+#define GT_SML_R_28 (0x3000+0x110)
+#define R_28_SML_ACTION (0x3000+0x111)
+#define GT_SML_L_28 (0x3000+0x112)
+#define L_28_SML_ACTION (0x3000+0x113)
+#define SML_RIGHT_28 (0x3000+0x114)
+#define SML_LEFT_28 (0x3000+0x115)
+#define LIFT_28_LOGIC (0x3000+0x116)
+#define GT_LIFT_28 (0x3000+0x117)
+#define LIFT_28_ACTION (0x3000+0x118)
+#define S28_SLOT_ACTION (0x3000+0x119)
+#define GT_SLOT_28 (0x3000+0x11a)
+#define S29_LIFT_LOGIC (0x3000+0x11b)
+#define JOEY_TO_LIFT29 (0x3000+0x11c)
+#define LIFT_29_ACTION (0x3000+0x11d)
+#define GT_29_LIFT (0x3000+0x11e)
+#define S29_SLOT_ACTION (0x3000+0x11f)
+#define GT_29_CARD_SLOT (0x3000+0x120)
+#define JOEY_OUT_OF_LIFT (0x3000+0x121)
+#define GT_RIGHT_EXIT_29 (0x3000+0x122)
+#define ER29_ACTION (0x3000+0x123)
+#define S29_RIGHT_ON (0x3000+0x124)
+#define GT_LEFT_EXIT_29 (0x3000+0x125)
+#define EL29_ACTION (0x3000+0x126)
+#define S29_LEFT_ON (0x3000+0x127)
+#define OTHER_LIFT_WAIT (0x3000+0x128)
+#define GT_LIFT_WAIT (0x3000+0x129)
+#define LAMB_BELL_LOGIC (0x3000+0x12a)
+#define LAMB_LEAVE_GARDEN (0x3000+0x12b)
+#define LAMB_START_29 (0x3000+0x12c)
+#define LEFT_FAIL_29 (0x3000+0x12d)
+#define GT_L_TALK_29 (0x3000+0x12e)
+#define RIGHT_FAIL_29 (0x3000+0x12f)
+#define GT_R_TALK_29 (0x3000+0x130)
+#define GT_CABLE_29 (0x3000+0x131)
+#define CABLE_29_ACTION (0x3000+0x132)
+#define GT_SML_R_29 (0x3000+0x133)
+#define R_29_SML_ACTION (0x3000+0x134)
+#define GT_SML_L_29 (0x3000+0x135)
+#define L_29_SML_ACTION (0x3000+0x136)
+#define SML_RIGHT_29 (0x3000+0x137)
+#define SML_LEFT_29 (0x3000+0x138)
+#define DANI_SPEECH (0x4000+0x1)
+#define HENRI_SPEECH (0x4000+0x2)
+#define BUZZER_SPEECH (0x4000+0x3)
+#define JUKEBOX_SPEECH (0x4000+0x4)
+#define VINCENT_SPEECH (0x0000+0x40)
+#define EDDIE_SPEECH (0x0000+0x41)
+#define BLUNT_SPEECH (0x0000+0x42)
+#define BARRY_SPEECH (0x4000+0x5)
+#define COLSTON_SPEECH (0x0000+0x43)
+#define GALL_SPEECH (0x0000+0x44)
+#define BABS_SPEECH (0x4000+0x6)
+#define CHUTNEY_SPEECH (0x0000+0x45)
+#define DOG_BARK_LOGIC (0x4000+0x7)
+#define SPUNKY_SMELLS_FOOD (0x4000+0x8)
+#define SPUNKY_EXTRA (0x4000+0x9)
+#define SPUNKY_LOGIC (0x4000+0xa)
+#define SPUNKY_EAT_FOOD (0x4000+0xb)
+#define SPUNKY_BARK_AT_FOSTER (0x4000+0xc)
+#define SPUNKY_GO_HOME (0x4000+0xd)
+#define SPUNKY_SEE_VIDEO (0x4000+0xe)
+#define DANIELLE_SSS (0x4000+0xf)
+#define GT_SC31_DANIELLE (0x4000+0x10)
+#define SC31_DANI_ACTION (0x4000+0x11)
+#define DANI_CHAT_TO_GUARD (0x4000+0x12)
+#define GT_DANI_WAIT (0x4000+0x13)
+#define DANIELLE_EXTRA (0x4000+0x14)
+#define DANIELLE_LOGIC (0x4000+0x15)
+#define GT_SC32_DANIELLE_AT_LIFT (0x4000+0x16)
+#define SC32_DANIELLE_AT_LIFT_ACTION (0x4000+0x17)
+#define DANIELLE_GO_HOME (0x4000+0x18)
+#define GT_SC38_DANIELLE (0x4000+0x19)
+#define SC38_DANIELLE_ACTION (0x4000+0x1a)
+#define GT_SC38_HAND_SET (0x4000+0x1b)
+#define DANI_ANSWER_PHONE (0x4000+0x1c)
+#define FOSTER_VISIT_DANI (0x4000+0x1d)
+#define GN_SC30_LEFT_TALK (0x4000+0x1e)
+#define GT_SC30_LEFT_TALK (0x4000+0x1f)
+#define GN_SC30_RIGHT_TALK (0x4000+0x20)
+#define GT_SC30_RIGHT_TALK (0x4000+0x21)
+#define SC30_EXIT_31_WALK_ON (0x4000+0x22)
+#define GT_SC30_EXIT_31 (0x4000+0x23)
+#define SC30_EXIT_31_ACTION (0x4000+0x24)
+#define SC30_EXIT_33_WALK_ON (0x4000+0x25)
+#define GT_SC30_EXIT_33 (0x4000+0x26)
+#define SC30_EXIT_33_ACTION (0x4000+0x27)
+#define SC30_COURT_DOOR_MOUSE_ON (0x4000+0x28)
+#define SC30_COURT_DOOR_WALK_ON (0x4000+0x29)
+#define GT_SC30_COURT_DOOR (0x4000+0x2a)
+#define SC30_COURT_DOOR_ACTION (0x4000+0x2b)
+#define SC30_COURT_DOOR_LOGIC (0x4000+0x2c)
+#define GT_SC30_NOTICE (0x4000+0x2d)
+#define SC30_NOTICE_ACTION (0x4000+0x2e)
+#define GT_SC30_STATUE_1 (0x4000+0x2f)
+#define SC30_STATUE_1_ACTION (0x4000+0x30)
+#define GT_SC30_STATUE_2 (0x4000+0x31)
+#define SC30_STATUE_2_ACTION (0x4000+0x32)
+#define SC30_HENRI_LOGIC (0x4000+0x33)
+#define SC30_HENRI_SSS (0x4000+0x34)
+#define GT_SC30_HENRI (0x4000+0x35)
+#define SC30_HENRI_ACTION (0x4000+0x36)
+#define SC30_EXIT_36_WALK_ON (0x4000+0x37)
+#define GT_SC30_EXIT_36 (0x4000+0x38)
+#define SC30_EXIT_36_ACTION (0x4000+0x39)
+#define GN_SC31_LEFT_TALK (0x4000+0x3a)
+#define GT_SC31_LEFT_TALK (0x4000+0x3b)
+#define GN_SC31_RIGHT_TALK (0x4000+0x3c)
+#define GT_SC31_RIGHT_TALK (0x4000+0x3d)
+#define SC31_EXIT_30_WALK_ON (0x4000+0x3e)
+#define GT_SC31_EXIT_30 (0x4000+0x3f)
+#define SC31_EXIT_30_ACTION (0x4000+0x40)
+#define SC31_EXIT_32_WALK_ON (0x4000+0x41)
+#define GT_SC31_EXIT_32 (0x4000+0x42)
+#define SC31_EXIT_32_ACTION (0x4000+0x43)
+#define GT_SC31_LIFT_SLOT (0x4000+0x44)
+#define SC31_LIFT_SLOT_ACTION (0x4000+0x45)
+#define GT_SC31_LIFT (0x4000+0x46)
+#define SC31_LIFT_ACTION (0x4000+0x47)
+#define SC31_LIFT_LOGIC (0x4000+0x48)
+#define SC31_GUARD_RESCUE_DOG (0x4000+0x49)
+#define GT_SC31_END_OF_ROPE (0x4000+0x4a)
+#define SC31_END_OF_ROPE_ACTION (0x4000+0x4b)
+#define SC31_ROPE_LOGIC (0x4000+0x4c)
+#define SC31_BRICKS_LOGIC (0x4000+0x4d)
+#define SC31_PLANK_LOGIC (0x4000+0x4e)
+#define SC31_BISCUITS_LOGIC (0x4000+0x4f)
+#define GT_SC31_BRICKS (0x4000+0x50)
+#define SC31_BRICKS_ACTION (0x4000+0x51)
+#define GN_SC31_PLANK (0x4000+0x52)
+#define GT_SC31_PLANK (0x4000+0x53)
+#define SC31_PLANK_ACTION (0x4000+0x54)
+#define SC31_GUARD_LOGIC (0x4000+0x55)
+#define SC31_GUARD_CHATTING_LOGIC (0x4000+0x56)
+#define SC31_GUARD_SSS (0x4000+0x57)
+#define GN_SC31_GUARD (0x4000+0x58)
+#define GT_SC31_GUARD (0x4000+0x59)
+#define SC31_GUARD_ACTION (0x4000+0x5a)
+#define SC31_GUARD_CHATTING_ACTION (0x4000+0x5b)
+#define SC31_EXIT_39_WALK_ON (0x4000+0x5c)
+#define GT_SC31_EXIT_39 (0x4000+0x5d)
+#define SC31_EXIT_39_ACTION (0x4000+0x5e)
+#define SC31_JOEY_LOGIC (0x4000+0x5f)
+#define GT_SC31_JOEY (0x4000+0x60)
+#define SC31_JOEY_ACTION (0x4000+0x61)
+#define SC31_AT_WATCHER_LOGIC (0x4000+0x62)
+#define GN_SC32_LEFT_TALK (0x4000+0x63)
+#define GT_SC32_LEFT_TALK (0x4000+0x64)
+#define GN_SC32_RIGHT_TALK (0x4000+0x65)
+#define GT_SC32_RIGHT_TALK (0x4000+0x66)
+#define SC32_EXIT_31_WALK_ON (0x4000+0x67)
+#define GT_SC32_EXIT_31 (0x4000+0x68)
+#define SC32_EXIT_31_ACTION (0x4000+0x69)
+#define SC32_EXIT_33_WALK_ON (0x4000+0x6a)
+#define GT_SC32_EXIT_33 (0x4000+0x6b)
+#define SC32_EXIT_33_ACTION (0x4000+0x6c)
+#define GT_SC32_TERMINAL (0x4000+0x6d)
+#define SC32_TERMINAL_ACTION (0x4000+0x6e)
+#define GT_SC32_PLANT_1 (0x4000+0x6f)
+#define SC32_PLANT_1_ACTION (0x4000+0x70)
+#define GT_SC32_PLANT_2 (0x4000+0x71)
+#define SC32_PLANT_2_ACTION (0x4000+0x72)
+#define GT_SC32_PLANT_3 (0x4000+0x73)
+#define SC32_PLANT_3_ACTION (0x4000+0x74)
+#define SC32_BUZZER_LOGIC (0x4000+0x75)
+#define GT_SC32_BUZZER (0x4000+0x76)
+#define SC32_BUZZER_ACTION (0x4000+0x77)
+#define GT_SC32_LIFT (0x4000+0x78)
+#define SC32_LIFT_ACTION (0x4000+0x79)
+#define SC32_LIFT_LOGIC (0x4000+0x7a)
+#define SC32_VINCENT_LOGIC (0x4000+0x7b)
+#define SC32_VINCENT_SSS (0x4000+0x7c)
+#define GT_SC32_VINCENT (0x4000+0x7d)
+#define SC32_VINCENT_ACTION (0x4000+0x7e)
+#define SC32_GARDENER_LOGIC (0x4000+0x7f)
+#define SC32_GARDENER_SSS (0x4000+0x80)
+#define GT_SC32_GARDENER (0x4000+0x81)
+#define SC32_GARDENER_ACTION (0x4000+0x82)
+#define GN_SC33_LEFT_TALK (0x4000+0x83)
+#define GT_SC33_LEFT_TALK (0x4000+0x84)
+#define GN_SC33_RIGHT_TALK (0x4000+0x85)
+#define GT_SC33_RIGHT_TALK (0x4000+0x86)
+#define SC33_EXIT_30_WALK_ON (0x4000+0x87)
+#define GT_SC33_EXIT_30 (0x4000+0x88)
+#define SC33_EXIT_30_ACTION (0x4000+0x89)
+#define SC33_EXIT_32_WALK_ON (0x4000+0x8a)
+#define GT_SC33_EXIT_32 (0x4000+0x8b)
+#define SC33_EXIT_32_ACTION (0x4000+0x8c)
+#define SC33_SHED_DOOR_LOGIC (0x4000+0x8d)
+#define SC33_SHED_DOOR_MOUSE_ON (0x4000+0x8e)
+#define SC33_SHED_DOOR_WALK_ON (0x4000+0x8f)
+#define GT_SC33_SHED_DOOR (0x4000+0x90)
+#define SC33_SHED_DOOR_ACTION (0x4000+0x91)
+#define GT_SC33_LOCK (0x4000+0x92)
+#define SC33_LOCK_ACTION (0x4000+0x93)
+#define SC34_DOOR_WALK_ON (0x4000+0x94)
+#define GT_SC34_DOOR (0x4000+0x95)
+#define SC34_DOOR_ACTION (0x4000+0x96)
+#define GT_SC34_SECATEURS (0x4000+0x97)
+#define SC34_SECATEURS_ACTION (0x4000+0x98)
+#define SC34_SECATEURS_LOGIC (0x4000+0x99)
+#define GT_SC34_TKT_MACHINE (0x4000+0x9a)
+#define SC34_TKT_MACHINE_ACTION (0x4000+0x9b)
+#define GT_SC34_MAP (0x4000+0x9c)
+#define SC34_MAP_ACTION (0x4000+0x9d)
+#define GT_SC34_BRICKS (0x4000+0x9e)
+#define SC34_BRICKS_ACTION (0x4000+0x9f)
+#define GN_SC36_LEFT_TALK (0x4000+0xa0)
+#define GT_SC36_LEFT_TALK (0x4000+0xa1)
+#define GN_SC36_RIGHT_TALK (0x4000+0xa2)
+#define GT_SC36_RIGHT_TALK (0x4000+0xa3)
+#define GT_SC36_LOW_FLOOR (0x4000+0xa4)
+#define GT_SC36_FLOOR (0x4000+0xa5)
+#define SC36_EXIT_30_WALK_ON (0x4000+0xa6)
+#define GT_SC36_EXIT_30 (0x4000+0xa7)
+#define SC36_EXIT_30_ACTION (0x4000+0xa8)
+#define GT_SC36_SENSOR (0x4000+0xa9)
+#define SC36_SENSOR_ACTION (0x4000+0xaa)
+#define SC36_DOOR_WALK_ON (0x4000+0xab)
+#define GT_SC36_DOOR (0x4000+0xac)
+#define SC36_DOOR_ACTION (0x4000+0xad)
+#define SC36_DOOR_LOGIC (0x4000+0xae)
+#define SC36_BAND_LOGIC (0x4000+0xaf)
+#define GT_SC36_BAND (0x4000+0xb0)
+#define SC36_BAND_ACTION (0x4000+0xb1)
+#define SC36_JUKE_LIGHT_LOGIC (0x4000+0xb2)
+#define SC36_COLSTON_FIX_JUKEBOX (0x4000+0xb3)
+#define PLAY_TUNE_1 (0x4000+0xb4)
+#define PLAY_TUNE_2 (0x4000+0xb5)
+#define PLAY_TUNE_3 (0x4000+0xb6)
+#define SC36_JUKEBOX_SSS (0x4000+0xb7)
+#define SC36_JUKEBOX_LOGIC (0x4000+0xb8)
+#define GT_SC36_JUKEBOX (0x4000+0xb9)
+#define SC36_JUKEBOX_ACTION (0x4000+0xba)
+#define SC36_BARMAN_LOGIC (0x4000+0xbb)
+#define SC36_BARMAN_SSS (0x4000+0xbc)
+#define GT_SC36_BARMAN (0x4000+0xbd)
+#define SC36_BARMAN_ACTION (0x4000+0xbe)
+#define SC36_COLSTON_LOGIC (0x4000+0xbf)
+#define SC36_COLSTON_SSS (0x4000+0xc0)
+#define GT_SC36_COLSTON (0x4000+0xc1)
+#define SC36_COLSTON_ACTION (0x4000+0xc2)
+#define SC36_GALLAGHER_LOGIC (0x4000+0xc3)
+#define SC36_GALLAGHER_SSS (0x4000+0xc4)
+#define GT_SC36_GALLAGHER (0x4000+0xc5)
+#define SC36_GALLAGHER_ACTION (0x4000+0xc6)
+#define SC36_CARDS_LOGIC (0x4000+0xc7)
+#define GT_SC36_GLASS (0x4000+0xc8)
+#define SC36_COLSTON_PROTEST (0x4000+0xc9)
+#define SC36_GLASS_ACTION (0x4000+0xca)
+#define MOVE_BABS (0x4000+0xcb)
+#define SC36_BABS_LOGIC (0x4000+0xcc)
+#define BABS_LOGIC_AMIGA (0x4000+0xcd)
+#define GT_BABS_AMIGA (0x4000+0xce)
+#define BABS_SSS_AMIGA (0x4000+0xcf)
+#define BABS_ACTION_AMIGA (0x4000+0xd0)
+#define GT_SC37_SENSOR (0x4000+0xd1)
+#define SC37_SENSOR_ACTION (0x4000+0xd2)
+#define SC37_DOOR_WALK_ON (0x4000+0xd3)
+#define GT_SC37_DOOR (0x4000+0xd4)
+#define SC37_DOOR_ACTION (0x4000+0xd5)
+#define SC37_DOOR_LOGIC (0x4000+0xd6)
+#define GT_SC37_GRILL (0x4000+0xd7)
+#define SC37_GRILL_ACTION (0x4000+0xd8)
+#define SC37_GRILL_LOGIC (0x4000+0xd9)
+#define GT_SC37_FLIMSY_BOX (0x4000+0xda)
+#define SC37_FLIMSY_BOX_ACTION (0x4000+0xdb)
+#define STEP_OFF_BOX (0x4000+0xdc)
+#define GT_SC37_BIG_BOX (0x4000+0xdd)
+#define SC37_BIG_BOX_ACTION (0x4000+0xde)
+#define GT_SC37_LID (0x4000+0xdf)
+#define SC37_LID_ACTION (0x4000+0xe0)
+#define PUT_LID_BACK (0x4000+0xe1)
+#define USE_LID_ON_FLIMSY_BOX (0x4000+0xe2)
+#define SC37_LID_LOGIC (0x4000+0xe3)
+#define GT_SC37_WINE_RACK (0x4000+0xe4)
+#define SC37_WINE_RACK_ACTION (0x4000+0xe5)
+#define GN_SC38_LEFT_TALK (0x4000+0xe6)
+#define GT_SC38_LEFT_TALK (0x4000+0xe7)
+#define GN_SC38_RIGHT_TALK (0x4000+0xe8)
+#define GT_SC38_RIGHT_TALK (0x4000+0xe9)
+#define GT_SC38_LIFT (0x4000+0xea)
+#define SC38_LIFT_ACTION (0x4000+0xeb)
+#define SC38_LIFT_LOGIC (0x4000+0xec)
+#define GT_SC38_STATUE (0x4000+0xed)
+#define SC38_STATUE_ACTION (0x4000+0xee)
+#define GT_SC38_VIDEO (0x4000+0xef)
+#define SC38_VIDEO_ACTION (0x4000+0xf0)
+#define SC38_VIDEO_LOGIC (0x4000+0xf1)
+#define GT_SC38_MONITOR (0x4000+0xf2)
+#define SC38_MONITOR_ACTION (0x4000+0xf3)
+#define SC38_MONITOR_LOGIC (0x4000+0xf4)
+#define GT_SC38_SOFA (0x4000+0xf5)
+#define SC38_SOFA_ACTION (0x4000+0xf6)
+#define GT_SC38_DOG_TRAY (0x4000+0xf7)
+#define SC38_DOG_TRAY_ACTION (0x4000+0xf8)
+#define GT_SC38_BISCUITS (0x4000+0xf9)
+#define SC38_BISCUITS_ACTION (0x4000+0xfa)
+#define SC38_RINGER_LOGIC (0x4000+0xfb)
+#define SC39_EXIT_31_WALK_ON (0x4000+0xfc)
+#define GT_SC39_EXIT_31 (0x4000+0xfd)
+#define SC39_EXIT_31_ACTION (0x4000+0xfe)
+#define GT_SC39_EXIT_40 (0x4000+0xff)
+#define SC39_EXIT_40_ACTION (0x4000+0x100)
+#define SC39_EXIT_41_WALK_ON (0x4000+0x101)
+#define GT_SC39_EXIT_41 (0x4000+0x102)
+#define SC39_EXIT_41_ACTION (0x4000+0x103)
+#define GT_SC39_WALTERS (0x4000+0x104)
+#define SC39_WALTERS_ACTION (0x4000+0x105)
+#define GT_SC40_EXIT_39 (0x4000+0x106)
+#define SC40_EXIT_39_ACTION (0x4000+0x107)
+#define GT_SC40_CABINET (0x4000+0x108)
+#define SC40_CABINET_ACTION (0x4000+0x109)
+#define GT_SC40_TROLLEY (0x4000+0x10a)
+#define SC40_TROLLEY_ACTION (0x4000+0x10b)
+#define GT_SC40_LOCKER_1 (0x4000+0x10c)
+#define SC40_LOCKER_1_ACTION (0x4000+0x10d)
+#define GT_SC40_LOCKER_2 (0x4000+0x10e)
+#define SC40_LOCKER_2_ACTION (0x4000+0x10f)
+#define GT_SC40_LOCKER_3 (0x4000+0x110)
+#define SC40_LOCKER_3_ACTION (0x4000+0x111)
+#define GT_SC40_LOCKER_4 (0x4000+0x112)
+#define SC40_LOCKER_4_ACTION (0x4000+0x113)
+#define GT_SC40_LOCKER_5 (0x4000+0x114)
+#define SC40_LOCKER_5_ACTION (0x4000+0x115)
+#define GT_SC40_BODY_1 (0x4000+0x116)
+#define SC40_BODY_1_ACTION (0x4000+0x117)
+#define GT_SC40_BODY_2 (0x4000+0x118)
+#define SC40_BODY_2_ACTION (0x4000+0x119)
+#define GT_SC40_BODY_3 (0x4000+0x11a)
+#define SC40_BODY_3_ACTION (0x4000+0x11b)
+#define GT_SC40_BODY_4 (0x4000+0x11c)
+#define SC40_BODY_4_ACTION (0x4000+0x11d)
+#define GT_SC40_BODY_5 (0x4000+0x11e)
+#define SC40_BODY_5_ACTION (0x4000+0x11f)
+#define SC40_LOCKER_1_LOGIC (0x4000+0x120)
+#define SC40_LOCKER_2_LOGIC (0x4000+0x121)
+#define SC40_LOCKER_3_LOGIC (0x4000+0x122)
+#define SC40_LOCKER_4_LOGIC (0x4000+0x123)
+#define SC40_LOCKER_5_LOGIC (0x4000+0x124)
+#define SC41_EXIT_39_WALK_ON (0x4000+0x125)
+#define GT_SC41_EXIT_39 (0x4000+0x126)
+#define SC41_EXIT_39_ACTION (0x4000+0x127)
+#define SC41_HEAT_1_LOGIC (0x4000+0x128)
+#define SC41_HEAT_2_LOGIC (0x4000+0x129)
+#define SC41_HEAT_3_LOGIC (0x4000+0x12a)
+#define FOSTER_ENTER_COURT (0x4000+0x12b)
+#define SC42_JUDGE_LOGIC (0x4000+0x12c)
+#define SC42_CLERK_LOGIC (0x4000+0x12d)
+#define SC42_PROSECUTION_LOGIC (0x4000+0x12e)
+#define SC42_JOBSWORTH_LOGIC (0x4000+0x12f)
+#define SC42_BLUNT_LOGIC (0x4000+0x130)
+#define SC42_DANI_LOGIC (0x4000+0x131)
+#define SC42_SIGN_LOGIC (0x4000+0x132)
+#define SC44_EXIT_45_WALK_ON (0x4000+0x133)
+#define GT_SC44_EXIT_45 (0x4000+0x134)
+#define SC44_EXIT_45_ACTION (0x4000+0x135)
+#define GT_SC44_GRILL (0x4000+0x136)
+#define SC44_GRILL_ACTION (0x4000+0x137)
+#define GT_SC44_RUBBLE (0x4000+0x138)
+#define SC44_RUBBLE_ACTION (0x4000+0x139)
+#define SC45_EXIT_44_WALK_ON (0x4000+0x13a)
+#define GT_SC45_EXIT_44 (0x4000+0x13b)
+#define SC45_EXIT_44_ACTION (0x4000+0x13c)
+#define SC45_EXIT_46_WALK_ON (0x4000+0x13d)
+#define GT_SC45_EXIT_46 (0x4000+0x13e)
+#define SC45_EXIT_46_ACTION (0x4000+0x13f)
+#define SC45_EXIT_47_WALK_ON (0x4000+0x140)
+#define GT_SC45_EXIT_47 (0x4000+0x141)
+#define SC45_EXIT_47_ACTION (0x4000+0x142)
+#define SC46_EXIT_45_WALK_ON (0x4000+0x143)
+#define GT_SC46_EXIT_45 (0x4000+0x144)
+#define SC46_EXIT_45_ACTION (0x4000+0x145)
+#define GT_SC46_RUBBLE (0x4000+0x146)
+#define SC46_RUBBLE_ACTION (0x4000+0x147)
+#define SC47_EXIT_45_WALK_ON (0x4000+0x148)
+#define GT_SC47_EXIT_45 (0x4000+0x149)
+#define SC47_EXIT_45_ACTION (0x4000+0x14a)
+#define SC47_EXIT_48_WALK_ON (0x4000+0x14b)
+#define GT_SC47_EXIT_48 (0x4000+0x14c)
+#define SC47_EXIT_48_ACTION (0x4000+0x14d)
+#define SC48_EXIT_47_WALK_ON (0x4000+0x14e)
+#define GT_SC48_EXIT_47 (0x4000+0x14f)
+#define SC48_EXIT_47_ACTION (0x4000+0x150)
+#define SC48_EXIT_65_WALK_ON (0x4000+0x151)
+#define GT_SC48_EXIT_65 (0x4000+0x152)
+#define SC48_EXIT_65_ACTION (0x4000+0x153)
+#define GT_SC48_SOCKET (0x4000+0x154)
+#define SC48_SOCKET_ACTION (0x4000+0x155)
+#define SC48_SOCKET_LOGIC (0x4000+0x156)
+#define GT_SC48_HOLE (0x4000+0x157)
+#define SC48_HOLE_ACTION (0x4000+0x158)
+#define FOSTER_SEES_EYES (0x4000+0x159)
+#define SC48_HOLE_LOGIC (0x4000+0x15a)
+#define SC48_EYES_LOGIC (0x4000+0x15b)
+#define SC65_EXIT_48_WALK_ON (0x4000+0x15c)
+#define GT_SC65_EXIT_48 (0x4000+0x15d)
+#define SC65_EXIT_48_ACTION (0x4000+0x15e)
+#define GT_SC65_EXIT_66 (0x4000+0x15f)
+#define GT_SC65_POSTER1 (0x4000+0x160)
+#define SC65_POSTER1_ACTION (0x4000+0x161)
+#define GT_SC65_POSTER2 (0x4000+0x162)
+#define SC65_POSTER2_ACTION (0x4000+0x163)
+#define GT_SC65_SIGN (0x4000+0x164)
+#define SC65_SIGN_ACTION (0x4000+0x165)
+#define WALTER_SPEECH (0x5000+0x1)
+#define JOEY_MEDIC (0x5000+0x2)
+#define KEN_SPEECH (0x5000+0x3)
+#define BORED_ROOM (0x5000+0x4)
+#define HOBS_END (0x0000+0x46)
+#define GT_JOEY_PARK (0x5000+0x5)
+#define JOEY_MED_EXTRA (0x5000+0x6)
+#define JOEY_MED_LOGIC (0x5000+0x7)
+#define JOEY_MISSION72_EXTRA (0x5000+0x8)
+#define JOEY_MED_MISSION72 (0x5000+0x9)
+#define GT_RECHARGING_MEDI (0x5000+0xa)
+#define RECHARGING_MEDI_ACTION (0x5000+0xb)
+#define MEDI_LOGIC (0x5000+0xc)
+#define SC67_MEND_LOGIC (0x5000+0xd)
+#define MEDI_ACTION (0x5000+0xe)
+#define GT_SC71_MEDI_SLOT (0x5000+0xf)
+#define SC71_MEDI_SLOT_ACTION (0x5000+0x10)
+#define SC66_FOSTER_GETS_CRUSHED (0x5000+0x11)
+#define SC66_TIMER_LOGIC (0x5000+0x12)
+#define SC66_DOOR_LOGIC (0x5000+0x13)
+#define SC66_STONES_LOGIC (0x5000+0x14)
+#define SC66_LO_BEAM_LOGIC (0x5000+0x15)
+#define SC66_HI_BEAM_LOGIC (0x5000+0x16)
+#define SC66_ROCK1_LOGIC (0x5000+0x17)
+#define SC66_ROCK2_LOGIC (0x5000+0x18)
+#define SC66_ROCK3_LOGIC (0x5000+0x19)
+#define SC66_HOLE_ACTION (0x5000+0x1a)
+#define SC67_PULSE1_LOGIC (0x5000+0x1b)
+#define SC67_PULSE2_LOGIC (0x5000+0x1c)
+#define SC67_PULSE3_LOGIC (0x5000+0x1d)
+#define SC67_PULSE4_LOGIC (0x5000+0x1e)
+#define SC67_ROCK_LOGIC (0x5000+0x1f)
+#define GT_SC67_BRICKWORK (0x5000+0x20)
+#define SC67_BRICKWORK_ACTION (0x5000+0x21)
+#define SC67_CLOT_LOGIC (0x5000+0x22)
+#define GN_SC67_CLOT (0x5000+0x23)
+#define GT_SC67_CLOT (0x5000+0x24)
+#define SC67_CLOT_ACTION (0x5000+0x25)
+#define GT_SC67_VEIN (0x5000+0x26)
+#define SC67_VEIN_ACTION (0x5000+0x27)
+#define SC67_DOOR_MOUSE_ON (0x5000+0x28)
+#define SC67_DOOR_LOGIC (0x5000+0x29)
+#define SC67_DOOR_WALK_ON (0x5000+0x2a)
+#define GN_SC67_DOOR (0x5000+0x2b)
+#define GT_SC67_DOOR (0x5000+0x2c)
+#define SC67_DOOR_ACTION (0x5000+0x2d)
+#define SC67_PLASTER_LOGIC (0x5000+0x2e)
+#define GT_SC67_PLASTER (0x5000+0x2f)
+#define SC67_PLASTER_ACTION (0x5000+0x30)
+#define SC67_BRICK_LOGIC (0x5000+0x31)
+#define GT_SC67_BRICK (0x5000+0x32)
+#define SC67_BRICK_ACTION (0x5000+0x33)
+#define SC67_CROWBAR_LOGIC (0x5000+0x34)
+#define GT_SC67_CROWBAR (0x5000+0x35)
+#define SC67_CROWBAR_ACTION (0x5000+0x36)
+#define GT_SC68_JOEY_WAIT (0x5000+0x37)
+#define SC68_PULSE1_LOGIC (0x5000+0x38)
+#define SC68_PULSE2_LOGIC (0x5000+0x39)
+#define SC68_PULSE3_LOGIC (0x5000+0x3a)
+#define SC68_PULSE4_LOGIC (0x5000+0x3b)
+#define SC68_PULSE5_LOGIC (0x5000+0x3c)
+#define SC68_PULSE6_LOGIC (0x5000+0x3d)
+#define SC68_SENSOR_LOGIC (0x5000+0x3e)
+#define SC68_DOOR_WALK_ON (0x5000+0x3f)
+#define GN_SC68_DOOR (0x5000+0x40)
+#define GT_SC68_DOOR (0x5000+0x41)
+#define SC68_DOOR_ACTION (0x5000+0x42)
+#define SC68_DOOR_MOUSE_ON (0x5000+0x43)
+#define SC68_DOOR_LOGIC (0x5000+0x44)
+#define GT_SC68_SENSOR (0x5000+0x45)
+#define SC68_SENSOR_ACTION (0x5000+0x46)
+#define GT_SC68_STAIRS (0x5000+0x47)
+#define SC68_STAIRS_ACTION (0x5000+0x48)
+#define SC68_EXIT_WALK_ON (0x5000+0x49)
+#define GT2_SC68_EXIT (0x5000+0x4a)
+#define GT_SC68_EXIT (0x5000+0x4b)
+#define SC68_EXIT_ACTION (0x5000+0x4c)
+#define GT_SC68_GRILL (0x5000+0x4d)
+#define SC68_GRILL_ACTION (0x5000+0x4e)
+#define SC69_PULSE1_LOGIC (0x5000+0x4f)
+#define SC69_PULSE2_LOGIC (0x5000+0x50)
+#define SC69_PULSE3_LOGIC (0x5000+0x51)
+#define SC69_PULSE4_LOGIC (0x5000+0x52)
+#define SC69_PULSE5_LOGIC (0x5000+0x53)
+#define SC69_PULSE6_LOGIC (0x5000+0x54)
+#define SC69_EXIT_WALK_ON (0x5000+0x55)
+#define GT2_SC69_EXIT (0x5000+0x56)
+#define GT_SC69_EXIT (0x5000+0x57)
+#define SC69_EXIT_ACTION (0x5000+0x58)
+#define SC69_DOOR_WALK_ON (0x5000+0x59)
+#define GN_SC69_DOOR (0x5000+0x5a)
+#define GT_SC69_DOOR (0x5000+0x5b)
+#define SC69_DOOR_ACTION (0x5000+0x5c)
+#define GT_SC69_GRILL (0x5000+0x5d)
+#define SC69_GRILL_ACTION (0x5000+0x5e)
+#define GT_SC70_DOOR (0x5000+0x5f)
+#define SC70_DOOR_ACTION (0x5000+0x60)
+#define SC70_IRIS_LOGIC (0x5000+0x61)
+#define SC70_IRIS_OPENED (0x5000+0x62)
+#define SC70_IRIS_CLOSED (0x5000+0x63)
+#define GT_SC70_IRIS (0x5000+0x64)
+#define SC70_IRIS_ACTION (0x5000+0x65)
+#define SC70_BAR_LOGIC (0x5000+0x66)
+#define GT_SC70_BAR (0x5000+0x67)
+#define SC70_BAR_ACTION (0x5000+0x68)
+#define GT_SC70_GRILL (0x5000+0x69)
+#define SC70_GRILL_ACTION (0x5000+0x6a)
+#define SC70_CONTROL_LOGIC (0x5000+0x6b)
+#define GT_SC70_CONTROL (0x5000+0x6c)
+#define SC70_CONTROL_ACTION (0x5000+0x6d)
+#define SC70_PIT_LOGIC (0x5000+0x6e)
+#define GT_SC70_PIT (0x5000+0x6f)
+#define SC70_PIT_ACTION (0x5000+0x70)
+#define GT_SC70_FLOOR (0x5000+0x71)
+#define SC71_DOOR69_WALK_ON (0x5000+0x72)
+#define GN_SC71_DOOR69 (0x5000+0x73)
+#define GT_SC71_DOOR69 (0x5000+0x74)
+#define SC71_DOOR69_ACTION (0x5000+0x75)
+#define SC71_DOOR72_WALK_ON (0x5000+0x76)
+#define GN_SC71_DOOR72 (0x5000+0x77)
+#define GT_SC71_DOOR72 (0x5000+0x78)
+#define SC71_DOOR72_ACTION (0x5000+0x79)
+#define GN_INTO_RECHARGING_UNIT (0x5000+0x7a)
+#define GET_INTO_RECHARGING_UNIT (0x5000+0x7b)
+#define GT_SC71_RECHARGER (0x5000+0x7c)
+#define SC71_RECHARGER_ACTION (0x5000+0x7d)
+#define GT_SC71_MONITOR (0x5000+0x7e)
+#define SC71_MONITOR_ACTION (0x5000+0x7f)
+#define GT_SC71_CONTROLS (0x5000+0x80)
+#define SC71_CONTROLS_ACTION (0x5000+0x81)
+#define GT_SC71_LOCKED_DOOR (0x5000+0x82)
+#define SC71_LOCKED_DOOR_ACTION (0x5000+0x83)
+#define SC71_RECHARGER_LOGIC (0x5000+0x84)
+#define SC71_PANEL2_LOGIC (0x5000+0x85)
+#define SC71_LIGHT1_LOGIC (0x5000+0x86)
+#define SC71_CHLITE_LOGIC (0x5000+0x87)
+#define SC71_MONITOR_LOGIC (0x5000+0x88)
+#define SC71_CONTROLS_LOGIC (0x5000+0x89)
+#define WITNESS_LOGIC (0x5000+0x8a)
+#define SC72_FOSTER_DEATH (0x5000+0x8b)
+#define WITNESS_CATCHES_FOSTER (0x5000+0x8c)
+#define SC72_DOOR_WALK_ON (0x5000+0x8d)
+#define GN_SC72_DOOR (0x5000+0x8e)
+#define GT_SC72_DOOR (0x5000+0x8f)
+#define SC72_DOOR_ACTION (0x5000+0x90)
+#define SC72_EXIT_WALK_ON (0x5000+0x91)
+#define GN_SC72_EXIT (0x5000+0x92)
+#define GT_SC72_EXIT (0x5000+0x93)
+#define SC72_EXIT_ACTION (0x5000+0x94)
+#define SC72_TANK_LOGIC (0x5000+0x95)
+#define GT_SC72_TANK (0x5000+0x96)
+#define SC72_TANK_ACTION (0x5000+0x97)
+#define GT_SC72_TAP (0x5000+0x98)
+#define SC72_TAP_ACTION (0x5000+0x99)
+#define SC72_SPILL_LOGIC (0x5000+0x9a)
+#define GT_SC72_SPILL (0x5000+0x9b)
+#define SC72_SPILL_ACTION (0x5000+0x9c)
+#define SC72_GRILL_LOGIC (0x5000+0x9d)
+#define GT_SC72_GRILL (0x5000+0x9e)
+#define SC72_GRILL_ACTION (0x5000+0x9f)
+#define SC72_CHAMBER1_LOGIC (0x5000+0xa0)
+#define SC72_CHAM1_LIGHT_LOGIC (0x5000+0xa1)
+#define SC72_CHAMBER2_LOGIC (0x5000+0xa2)
+#define SC72_CHAM2_LIGHT_LOGIC (0x5000+0xa3)
+#define SC72_CHAMBER3_LOGIC (0x5000+0xa4)
+#define GT_SC72_CHAMBER1 (0x5000+0xa5)
+#define GT_SC72_CHAMBER2 (0x5000+0xa6)
+#define GT_SC72_CHAMBER3 (0x5000+0xa7)
+#define SC72_CHAMBERS_ACTION (0x5000+0xa8)
+#define GT_SC72_LIGHT1 (0x5000+0xa9)
+#define GT_SC72_LIGHT2 (0x5000+0xaa)
+#define GT_SC72_LIGHT3 (0x5000+0xab)
+#define SC72_ROT_LIGHT_LOGIC (0x5000+0xac)
+#define SC72_COMPUTER_LOGIC (0x5000+0xad)
+#define SC72_COMPUTER2_LOGIC (0x5000+0xae)
+#define GT_SC72_COMPUTER (0x5000+0xaf)
+#define SC72_COMPUTER_ACTION (0x5000+0xb0)
+#define GN_SC72_WITNESS_TALK (0x5000+0xb1)
+#define GT_SC72_WITNESS_TALK (0x5000+0xb2)
+#define GN_SC72_FOSTER_TALK (0x5000+0xb3)
+#define GT_SC72_FOSTER_TALK (0x5000+0xb4)
+#define GT_SC72_WITNESS_KILL (0x5000+0xb5)
+#define GT_SC73_CORPSE (0x5000+0xb6)
+#define SC73_CORPSE_ACTION (0x5000+0xb7)
+#define GALLAGHER_LOGIC73 (0x5000+0xb8)
+#define GT_SC73_GALL_1 (0x5000+0xb9)
+#define GT_SC73_GALL_2 (0x5000+0xba)
+#define GT_SC73_JOEY_WAIT (0x5000+0xbb)
+#define SC73_SENSOR_LOGIC (0x5000+0xbc)
+#define SC73_EXIT_WALK_ON (0x5000+0xbd)
+#define GT2_SC73_EXIT (0x5000+0xbe)
+#define GT_SC73_EXIT (0x5000+0xbf)
+#define SC73_EXIT_ACTION (0x5000+0xc0)
+#define SC73_DOOR_WALK_ON (0x5000+0xc1)
+#define GT_SC73_DOOR (0x5000+0xc2)
+#define SC73_DOOR_ACTION (0x5000+0xc3)
+#define SC73_CHAMBER3_LOGIC (0x5000+0xc4)
+#define SC73_CHAMBER4_LOGIC (0x5000+0xc5)
+#define SC73_CHAM4_LIGHT_LOGIC (0x5000+0xc6)
+#define GT_SC73_CHAMBER4 (0x5000+0xc7)
+#define SC73_CHAMBER4_ACTION (0x5000+0xc8)
+#define SC73_CHAMBER5_LOGIC (0x5000+0xc9)
+#define SC73_CHAM5_LIGHT_LOGIC (0x5000+0xca)
+#define GT_SC73_CHAMBER5 (0x5000+0xcb)
+#define SC73_CHAMBER5_ACTION (0x5000+0xcc)
+#define SC73_BIG_DOOR_MOUSE_ON (0x5000+0xcd)
+#define SC73_BIG_DOOR_WALK_ON (0x5000+0xce)
+#define GT_SC73_BIG_DOOR (0x5000+0xcf)
+#define SC73_BIG_DOOR_ACTION (0x5000+0xd0)
+#define GT_SC73_SENSOR (0x5000+0xd1)
+#define SC73_SENSOR_ACTION (0x5000+0xd2)
+#define GT_SC73_LOCKED_DOOR (0x5000+0xd3)
+#define SC73_LOCKED_DOOR_ACTION (0x5000+0xd4)
+#define SC73_BITS_LOGIC (0x5000+0xd5)
+#define SC73_BITS2_LOGIC (0x5000+0xd6)
+#define SC73_SPRAY_LOGIC (0x5000+0xd7)
+#define GT_SC73_WRECKED_DROID (0x5000+0xd8)
+#define SC73_WRECKED_DROID_ACTION (0x5000+0xd9)
+#define JOEY_MED_LOGIC73 (0x5000+0xda)
+#define SC74_DOOR_WALK_ON (0x5000+0xdb)
+#define GT_SC74_DOOR (0x5000+0xdc)
+#define SC74_DOOR_ACTION (0x5000+0xdd)
+#define SC74_MONITOR1_LOGIC (0x5000+0xde)
+#define SC74_MONITOR2_LOGIC (0x5000+0xdf)
+#define SC74_MONITOR3_LOGIC (0x5000+0xe0)
+#define SC74_MONITOR4_LOGIC (0x5000+0xe1)
+#define SC74_LEFT_TV_LOGIC (0x5000+0xe2)
+#define SC74_RIGHT_TV_LOGIC (0x5000+0xe3)
+#define SC74_LIGHTS_LOGIC (0x5000+0xe4)
+#define GT_SC74_MONITOR1 (0x5000+0xe5)
+#define GT_SC74_LEFT_TV (0x5000+0xe6)
+#define GT_SC74_RIGHT_TV (0x5000+0xe7)
+#define SC74_MONITORS_ACTION (0x5000+0xe8)
+#define GT_SC74_INTERFACE (0x5000+0xe9)
+#define SC74_INTERFACE_ACTION (0x5000+0xea)
+#define GT_SC74_FLOOR (0x5000+0xeb)
+#define GT_SC74_INT_SLOT (0x5000+0xec)
+#define SC74_INT_SLOT_ACTION (0x5000+0xed)
+#define SC74_INT_SLOT_LOGIC (0x5000+0xee)
+#define GT_SC74_TERMINAL (0x5000+0xef)
+#define SC74_TERMINAL_ACTION (0x5000+0xf0)
+#define SC74_POD_LOGIC (0x5000+0xf1)
+#define SC75_BIG_DOOR_WALK_ON (0x5000+0xf2)
+#define GT_SC75_BIG_DOOR (0x5000+0xf3)
+#define SC75_BIG_DOOR_ACTION (0x5000+0xf4)
+#define SC75_DOOR_WALK_ON (0x5000+0xf5)
+#define GT_SC75_DOOR (0x5000+0xf6)
+#define SC75_DOOR_ACTION (0x5000+0xf7)
+#define SC75_NITRO_TANK_LOGIC (0x5000+0xf8)
+#define GT_SC75_NITRO_TANK (0x5000+0xf9)
+#define SC75_NITRO_TANK_ACTION (0x5000+0xfa)
+#define SC75_LIVE_TANK_LOGIC (0x5000+0xfb)
+#define GT_SC75_LIVE_TANK (0x5000+0xfc)
+#define SC75_TISSUE_LOGIC (0x5000+0xfd)
+#define SC75_LIVE_TANK_ACTION (0x5000+0xfe)
+#define SC75_CONSOLE_LOGIC (0x5000+0xff)
+#define SC75_CRASH_LOGIC (0x5000+0x100)
+#define GT_SC75_CONSOLE (0x5000+0x101)
+#define SC75_CONSOLE_ACTION (0x5000+0x102)
+#define SC75_TONGS_LOGIC (0x5000+0x103)
+#define GT_SC75_TONGS (0x5000+0x104)
+#define SC75_TONGS_ACTION (0x5000+0x105)
+#define SC75_LIGHT1_LOGIC (0x5000+0x106)
+#define SC75_LIGHT2_LOGIC (0x5000+0x107)
+#define SC76_DOOR75_WALK_ON (0x5000+0x108)
+#define GT_SC76_DOOR75 (0x5000+0x109)
+#define SC76_DOOR75_ACTION (0x5000+0x10a)
+#define SC76_DOOR77_WALK_ON (0x5000+0x10b)
+#define GT_SC76_DOOR77 (0x5000+0x10c)
+#define SC76_DOOR77_ACTION (0x5000+0x10d)
+#define GT_SC76_ANYTHING (0x5000+0x10e)
+#define SC76_ANDROID_ACTION (0x5000+0x10f)
+#define SC76_CONSOLE_1_ACTION (0x5000+0x110)
+#define SC76_CONSOLE_2_ACTION (0x5000+0x111)
+#define SC76_CONSOLE_3_ACTION (0x5000+0x112)
+#define SC76_BOARD_1_ACTION (0x5000+0x113)
+#define SC76_BOARD_2_ACTION (0x5000+0x114)
+#define SC76_BOARD_3_ACTION (0x5000+0x115)
+#define SC76_BOARD_1_LOGIC (0x5000+0x116)
+#define SC76_BOARD_2_LOGIC (0x5000+0x117)
+#define SC76_BOARD_3_LOGIC (0x5000+0x118)
+#define SC76_CABINET_1_ACTION (0x5000+0x119)
+#define SC76_CABINET_2_ACTION (0x5000+0x11a)
+#define SC76_CABINET_3_ACTION (0x5000+0x11b)
+#define SC76_CABINET_1_LOGIC (0x5000+0x11c)
+#define SC76_CABINET_2_LOGIC (0x5000+0x11d)
+#define SC76_CABINET_3_LOGIC (0x5000+0x11e)
+#define SC76_LIGHT1_LOGIC (0x5000+0x11f)
+#define SC76_LIGHT2_LOGIC (0x5000+0x120)
+#define SC76_LIGHT3_LOGIC (0x5000+0x121)
+#define SC76_LIGHT4_LOGIC (0x5000+0x122)
+#define SC76_LIGHT5_LOGIC (0x5000+0x123)
+#define SC76_LIGHT6_LOGIC (0x5000+0x124)
+#define SC76_LIGHT7_LOGIC (0x5000+0x125)
+#define SC76_LIGHT8_LOGIC (0x5000+0x126)
+#define SC76_LIGHT9_LOGIC (0x5000+0x127)
+#define SC76_ANDROID_1_LOGIC (0x5000+0x128)
+#define SC76_ANDROID_2_LOGIC (0x5000+0x129)
+#define KEN_START_LOGIC (0x5000+0x12a)
+#define SC76_ANDROID_3_LOGIC (0x5000+0x12b)
+#define KEN_EXTRA (0x5000+0x12c)
+#define KEN_LOGIC (0x5000+0x12d)
+#define KEN_STUCK_LOGIC (0x5000+0x12e)
+#define STUCK_SSS (0x5000+0x12f)
+#define GT_SC77_STUCK_KEN (0x5000+0x130)
+#define STUCK_KEN_ACTION (0x5000+0x131)
+#define KEN_MISSION_HAND_EXTRA (0x5000+0x132)
+#define KEN_MISSION_HAND (0x5000+0x133)
+#define SC77_DOOR76_WALK_ON (0x5000+0x134)
+#define GT_SC77_DOOR76 (0x5000+0x135)
+#define SC77_DOOR76_ACTION (0x5000+0x136)
+#define SC77_BIG_DOOR_MOUSE_ON (0x5000+0x137)
+#define SC77_BIG_DOOR_LOGIC (0x5000+0x138)
+#define SC77_BIG_DOOR_WALK_ON (0x5000+0x139)
+#define GT_SC77_BIG_DOOR (0x5000+0x13a)
+#define SC77_BIG_DOOR_ACTION (0x5000+0x13b)
+#define GT_SC77_TANKS (0x5000+0x13c)
+#define SC77_TANKS_ACTION (0x5000+0x13d)
+#define GT_SC77_HAND_1 (0x5000+0x13e)
+#define SC77_HAND_1_ACTION (0x5000+0x13f)
+#define GN_SC77_HAND_2 (0x5000+0x140)
+#define GT_SC77_HAND_2 (0x5000+0x141)
+#define SC77_HAND_2_ACTION (0x5000+0x142)
+#define GT_SC78_LEDGE (0x5000+0x143)
+#define GT_SC78_PIPE (0x5000+0x144)
+#define SC78_BIG_DOOR_WALK_ON (0x5000+0x145)
+#define GT_SC78_BIG_DOOR (0x5000+0x146)
+#define SC78_BIG_DOOR_ACTION (0x5000+0x147)
+#define SC78_EXIT_WALK_ON (0x5000+0x148)
+#define GT_SC78_EXIT (0x5000+0x149)
+#define SC78_EXIT_ACTION (0x5000+0x14a)
+#define GT_SC78_SUPPORT (0x5000+0x14b)
+#define SC78_SUPPORT_ACTION (0x5000+0x14c)
+#define SC79_EXIT_WALK_ON (0x5000+0x14d)
+#define GT_SC79_EXIT (0x5000+0x14e)
+#define SC79_EXIT_ACTION (0x5000+0x14f)
+#define GT_SC79_SUPPORT (0x5000+0x150)
+#define SC79_SUPPORT_ACTION (0x5000+0x151)
+#define SC79_KNOT_LOGIC (0x5000+0x152)
+#define GT_SC79_KNOT (0x5000+0x153)
+#define SC79_KNOT_ACTION (0x5000+0x154)
+#define SC79_ROPE_LOGIC (0x5000+0x155)
+#define GT_SC79_ROPE (0x5000+0x156)
+#define SC79_ROPE_ACTION (0x5000+0x157)
+#define GT_SC79_LADDER (0x5000+0x158)
+#define SC79_LADDER_ACTION (0x5000+0x159)
+#define SC80_LADDER_ACTION (0x5000+0x15a)
+#define SC80_ROPE_ACTION (0x5000+0x15b)
+#define SC80_ROPE_LOGIC (0x5000+0x15c)
+#define SC80_SPOUT_ACTION (0x5000+0x15d)
+#define SC80_ORIFICE_ACTION (0x5000+0x15e)
+#define SC80_SAMPLE_LOGIC (0x5000+0x15f)
+#define SC80_EXIT_LOGIC (0x5000+0x160)
+#define SC80_EXIT_ACTION (0x5000+0x161)
+#define SC80_GOO_LOGIC (0x5000+0x162)
+#define SC80_BUBBLE1_LOGIC (0x5000+0x163)
+#define SC80_BUBBLE2_LOGIC (0x5000+0x164)
+#define SC80_BUBBLE3_LOGIC (0x5000+0x165)
+#define SC80_BUBBLE4_LOGIC (0x5000+0x166)
+#define SC80_BUBBLE5_LOGIC (0x5000+0x167)
+#define SC80_BUBBLE6_LOGIC (0x5000+0x168)
+#define SC80_BUBBLE7_LOGIC (0x5000+0x169)
+#define SC80_BUBBLE8_LOGIC (0x5000+0x16a)
+#define SC80_BUBBLE9_LOGIC (0x5000+0x16b)
+#define SC80_BUBBLE10_LOGIC (0x5000+0x16c)
+#define SC80_BUBBLE11_LOGIC (0x5000+0x16d)
+#define SC80_BUBBLE12_LOGIC (0x5000+0x16e)
+#define SC81_PULSE_LOGIC (0x5000+0x16f)
+#define SC81_FATHER_CHAIR_LOGIC (0x5000+0x170)
+#define SC81_FATHER_FLOOR_LOGIC (0x5000+0x171)
+#define SC81_FATHER_FINISHED (0x5000+0x172)
+#define SC81_FATHER_SSS (0x5000+0x173)
+#define SC81_FATHER_FALL (0x5000+0x174)
+#define FOSTER_ENTER_BOARDROOM (0x5000+0x175)
+#define SC81_FATHER_ACTION (0x5000+0x176)
+#define LAST_WORDS_WITH_FATHER (0x5000+0x177)
+#define SC81_KEN_SSS (0x5000+0x178)
+#define SC81_KEN_ACTION (0x5000+0x179)
+#define SC81_DOOR_LOGIC (0x5000+0x17a)
+#define SC81_KEN_LOGIC (0x5000+0x17b)
+#define SC81_FOSTER_ABSORBED (0x5000+0x17c)
+#define SC81_FOSTER_GRABBED (0x5000+0x17d)
+#define SC81_CHAIR_ACTION (0x5000+0x17e)
+#define SC81_TENT1_LOGIC (0x5000+0x17f)
+#define SC81_TENT2_LOGIC (0x5000+0x180)
+#define SC81_TENT3_LOGIC (0x5000+0x181)
+#define SC81_TENT4_LOGIC (0x5000+0x182)
+#define SC81_TENT5_LOGIC (0x5000+0x183)
+#define SC81_TENT6_LOGIC (0x5000+0x184)
+#define SC81_BIG_TENT1_LOGIC (0x5000+0x185)
+#define SC81_BIG_TENT2_LOGIC (0x5000+0x186)
+#define SC81_BIG_TENT3_LOGIC (0x5000+0x187)
+#define SC82_JOBS_SSS (0x0000+0x47)
+#define SC82_JOBSWORTH_LOGIC (0x0000+0x48)
+#define PRINT_CREDITS (0x0000+0x49)
+#define END_SEQUENCE (0x0000+0x4a)
+#define FOSTER_ENTER_NEW_BOARDROOM (0x0000+0x4b)
+#define SC82_KEN_LOGIC (0x0000+0x4c)
+#define S19_LEFT_ON (0x0000+0x4d)
+#define S19_RIGHT_ON (0x0000+0x4e)
+#define GT_RIGHT_EXIT_19 (0x0000+0x4f)
+#define ER19_ACTION (0x0000+0x50)
+#define CABLE2_LOGIC (0x0000+0x51)
+#define CABLE_FALL_LOGIC (0x0000+0x52)
+#define SMASHED_WINDOW_LOGIC (0x0000+0x53)
+#define BITS_LOGIC (0x0000+0x54)
+#define GT_CABLE_11 (0x0000+0x55)
+#define CABLE_11_ACTION (0x0000+0x56)
+#define SPY11_LOGIC (0x0000+0x57)
+#define LOCKER_11_LOGIC (0x0000+0x58)
+#define GT_LOCKER_11 (0x0000+0x59)
+#define LOCKER_11_ACTION (0x0000+0x5a)
+#define START90 (0x0000+0x5b)
+#define EXIT_LINC (0x0000+0x5c)
+#define LINC_MENU_SCRIPT (0x6000+0x1)
+#define LINC_MENU_SELECT (0x6000+0x2)
+#define INFO_MENU_SELECT (0x6000+0x3)
+#define DIS_MENU_SELECT (0x6000+0x4)
+#define JOIN_MENU_SELECT (0x6000+0x5)
+#define DECOMP_MENU_SELECT (0x6000+0x6)
+#define DECRYPT_MENU_SELECT (0x6000+0x7)
+#define DOC_MENU_SELECT (0x6000+0x8)
+#define SET_UP_INFO_WINDOW (0x6000+0x9)
+#define INFO_WINDOW_LOGIC (0x6000+0xa)
+#define INFO_BUTTON_LOGIC (0x6000+0xb)
+#define CLOSE_WINDOW (0x6000+0xc)
+#define NORMAL_MOUSE (0x6000+0xd)
+#define BUTTON_MOUSE (0x6000+0xe)
+#define DISCONNECT_FOSTER (0x6000+0xf)
+#define DOOR_L90_LOGIC (0x6000+0x10)
+#define DOOR_L90F_LOGIC (0x6000+0x11)
+#define GET_TO_DOOR_L90 (0x6000+0x12)
+#define DOOR_L90_ACTION (0x6000+0x13)
+#define DOOR_R90_LOGIC (0x6000+0x14)
+#define DOOR_R90F_LOGIC (0x6000+0x15)
+#define GET_TO_DOOR_R90 (0x6000+0x16)
+#define DOOR_R90_ACTION (0x6000+0x17)
+#define GET_TO_JOIN_OBJECT (0x6000+0x18)
+#define JOIN_OBJECT_ACTION (0x6000+0x19)
+#define JOIN_OBJECT_LOGIC (0x6000+0x1a)
+#define GET_TO_OSCILLATOR (0x6000+0x1b)
+#define OSCILLATOR_ACTION (0x6000+0x1c)
+#define OSCILLATOR_LOGIC (0x6000+0x1d)
+#define GET_TO_EYEBALL_90 (0x6000+0x1e)
+#define EYEBALL_90_ACTION (0x6000+0x1f)
+#define EYEBALL_90_LOGIC (0x6000+0x20)
+#define DOOR_L91_LOGIC (0x6000+0x21)
+#define DOOR_L91F_LOGIC (0x6000+0x22)
+#define GET_TO_DOOR_L91 (0x6000+0x23)
+#define DOOR_L91_ACTION (0x6000+0x24)
+#define DOOR_R91_LOGIC (0x6000+0x25)
+#define DOOR_R91F_LOGIC (0x6000+0x26)
+#define GET_TO_DOOR_R91 (0x6000+0x27)
+#define DOOR_R91_ACTION (0x6000+0x28)
+#define DOOR_T91_LOGIC (0x6000+0x29)
+#define DOOR_T91R_LOGIC (0x6000+0x2a)
+#define GET_TO_DOOR_T91 (0x6000+0x2b)
+#define DOOR_T91_ACTION (0x6000+0x2c)
+#define GET_TO_BAG_91 (0x6000+0x2d)
+#define BAG_91_ACTION (0x6000+0x2e)
+#define BAG_91_LOGIC (0x6000+0x2f)
+#define GET_TO_DECOMP_OBJ (0x6000+0x30)
+#define DECOMP_OBJ_ACTION (0x6000+0x31)
+#define DECOMP_OBJ_LOGIC (0x6000+0x32)
+#define GET_TO_DECRYPT_OBJ (0x6000+0x33)
+#define DECRYPT_OBJ_ACTION (0x6000+0x34)
+#define DECRYPT_OBJ_LOGIC (0x6000+0x35)
+#define GET_TO_REPORT_BOOK (0x6000+0x36)
+#define REPORT_BOOK_ACTION (0x6000+0x37)
+#define REPORT_BOOK_LOGIC (0x6000+0x38)
+#define GET_TO_EYEBALL_91 (0x6000+0x39)
+#define EYEBALL_91_ACTION (0x6000+0x3a)
+#define EYEBALL_91_LOGIC (0x6000+0x3b)
+#define DOOR_L92_LOGIC (0x6000+0x3c)
+#define DOOR_L92F_LOGIC (0x6000+0x3d)
+#define GET_TO_DOOR_L92 (0x6000+0x3e)
+#define DOOR_L92_ACTION (0x6000+0x3f)
+#define DOOR_R92_LOGIC (0x6000+0x40)
+#define DOOR_R92R_LOGIC (0x6000+0x41)
+#define GET_TO_DOOR_R92 (0x6000+0x42)
+#define DOOR_R92_ACTION (0x6000+0x43)
+#define SLAB1_LOGIC (0x6000+0x44)
+#define SLAB2_LOGIC (0x6000+0x45)
+#define SLAB3_LOGIC (0x6000+0x46)
+#define SLAB4_LOGIC (0x6000+0x47)
+#define SLAB5_LOGIC (0x6000+0x48)
+#define SLAB6_LOGIC (0x6000+0x49)
+#define SLAB7_LOGIC (0x6000+0x4a)
+#define SLAB8_LOGIC (0x6000+0x4b)
+#define SLAB9_LOGIC (0x6000+0x4c)
+#define GET_TO_SLAB (0x6000+0x4d)
+#define SLAB_ACTION (0x6000+0x4e)
+#define SLAB_6_9_ACTION (0x6000+0x4f)
+#define BRIDGE_A_LOGIC (0x6000+0x50)
+#define BRIDGE_B_LOGIC (0x6000+0x51)
+#define BRIDGE_C_LOGIC (0x6000+0x52)
+#define BRIDGE_D_LOGIC (0x6000+0x53)
+#define BRIDGE_E_LOGIC (0x6000+0x54)
+#define BRIDGE_F_LOGIC (0x6000+0x55)
+#define BRIDGE_G_LOGIC (0x6000+0x56)
+#define BRIDGE_H_LOGIC (0x6000+0x57)
+#define GET_TO_CIRCLE (0x6000+0x58)
+#define GREEN_CIRCLE_LOGIC (0x6000+0x59)
+#define GREEN_CIRCLE_ACTION (0x6000+0x5a)
+#define RED_CIRCLE_LOGIC (0x6000+0x5b)
+#define RED_CIRCLE_ACTION (0x6000+0x5c)
+#define SLAB_ON (0x6000+0x5d)
+#define SLAB_OFF (0x6000+0x5e)
+#define LEFT_MOUSE (0x6000+0x5f)
+#define RIGHT_MOUSE (0x6000+0x60)
+#define UP_MOUSE (0x6000+0x61)
+#define DOWN_MOUSE (0x6000+0x62)
+#define DOOR_L93_LOGIC (0x6000+0x63)
+#define DOOR_L93F_LOGIC (0x6000+0x64)
+#define GET_TO_DOOR_L93 (0x6000+0x65)
+#define DOOR_L93_ACTION (0x6000+0x66)
+#define GET_TO_PERSONA (0x6000+0x67)
+#define PERSONA_ACTION (0x6000+0x68)
+#define PERSONA_LOGIC (0x6000+0x69)
+#define GET_TO_ADJUST_BOOK (0x6000+0x6a)
+#define ADJUST_BOOK_ACTION (0x6000+0x6b)
+#define ADJUST_BOOK_LOGIC (0x6000+0x6c)
+#define DOOR_L94_LOGIC (0x6000+0x6d)
+#define DOOR_L94R_LOGIC (0x6000+0x6e)
+#define GET_TO_DOOR_L94 (0x6000+0x6f)
+#define DOOR_L94_ACTION (0x6000+0x70)
+#define DOOR_R94_LOGIC (0x6000+0x71)
+#define DOOR_R94R_LOGIC (0x6000+0x72)
+#define GET_TO_DOOR_R94 (0x6000+0x73)
+#define DOOR_R94_ACTION (0x6000+0x74)
+#define GET_TO_HOLOGRAM_PAD (0x6000+0x75)
+#define HOLOGRAM_PAD_ACTION (0x6000+0x76)
+#define HOLOGRAM_A_LOGIC (0x6000+0x77)
+#define HOLOGRAM_B_LOGIC (0x6000+0x78)
+#define DOOR_L95_LOGIC (0x6000+0x79)
+#define DOOR_L95F_LOGIC (0x6000+0x7a)
+#define GET_TO_DOOR_L95 (0x6000+0x7b)
+#define DOOR_L95_ACTION (0x6000+0x7c)
+#define DOOR_R95_LOGIC (0x6000+0x7d)
+#define DOOR_R95F_LOGIC (0x6000+0x7e)
+#define GET_TO_DOOR_R95 (0x6000+0x7f)
+#define DOOR_R95_ACTION (0x6000+0x80)
+#define DOOR_T95_LOGIC (0x6000+0x81)
+#define DOOR_T95R_LOGIC (0x6000+0x82)
+#define GET_TO_DOOR_T95 (0x6000+0x83)
+#define DOOR_T95_ACTION (0x6000+0x84)
+#define GET_TO_GUARDIAN (0x6000+0x85)
+#define GUARDIAN_ACTION (0x6000+0x86)
+#define GUARDIAN_LOGIC (0x6000+0x87)
+#define WEIGHT_LOGIC (0x6000+0x88)
+#define DOOR_L96_LOGIC (0x6000+0x89)
+#define DOOR_L96F_LOGIC (0x6000+0x8a)
+#define GET_TO_DOOR_L96 (0x6000+0x8b)
+#define DOOR_L96_ACTION (0x6000+0x8c)
+#define CRYSTAL_LOGIC (0x6000+0x8d)
+#define GET_TO_CRYSTAL (0x6000+0x8e)
+#define CRYSTAL_ACTION (0x6000+0x8f)
+#define VIRUS_LOGIC (0x6000+0x90)
+#define GET_TO_VIRUS (0x6000+0x91)
+#define VIRUS_ACTION (0x6000+0x92)
+#define ANITA_SPEECH (0x2000+0x105)
+#define LAMB_FACTORY (0x2000+0x106)
+#define LAMB_UNUSED (0x2000+0x107)
+#define LAMB_BELLEVUE (0x0000+0x5d)
+#define FORE_SPEECH (0x2000+0x108)
+#define GORDON_SPEECH (0x2000+0x109)
+#define GUARD_SPEECH (0x2000+0x10a)
+#define WANK (0x2000+0x10b)
+#define WRECK_SPEECH (0x2000+0x10c)
+#define LOB_DAD_SPEECH (0x2000+0x10d)
+#define LOB_SON_SPEECH (0x2000+0x10e)
+#define RADMAN_SPEECH (0x2000+0x10f)
+#define BURKE_SPEECH (0x3000+0x139)
+#define JASON_SPEECH (0x3000+0x13a)
+#define JOEY_RECYCLE (0x1000+0xab)
+#define JOEY_UNUSED (0x1000+0xac)
+#define JOEY_FACTORY (0x2000+0x110)
+#define JOEY_BELLEVUE (0x3000+0x13b)
+#define ANCHOR_SPEECH (0x3000+0x13c)
+#define TREVOR_SPEECH (0x3000+0x13d)
+#define HELGA_SPEECH (0x3000+0x13e)
+#define GALL_BELLEVUE (0x3000+0x13f)
+#define FULL_SCREEN_LOGIC (0x0000+0x5e)
+#define CANCEL_ACTION_101 (0x0000+0x5f)
+#define BUTTON_ACTION_101 (0x0000+0x60)
+#define FS_BUTTON_LOGIC (0x0000+0x61)
+#define FS_RETINA_SCAN_LOGIC (0x0000+0x62)
+#define START_0 (0x0000+0x63)
+#define START_S4 (0x0000+0x64)
+#define START_S2 (0x0000+0x65)
+#define START_S3 (0x0000+0x66)
+#define START_S6 (0x0000+0x67)
+#define START_29 (0x0000+0x68)
+#define START_TEN (0x0000+0x69)
+#define START_ONE (0x0000+0x6a)
+#define START_IN_FACTORY (0x0000+0x6b)
+#define START_14 (0x0000+0x6c)
+#define START_SC31 (0x0000+0x6d)
+#define START_SC37 (0x0000+0x6e)
+#define START_SC42 (0x0000+0x6f)
+#define START_SC48 (0x0000+0x70)
+#define START_SC66 (0x0000+0x71)
+#define START_SC73 (0x0000+0x72)
+#define START_SC81 (0x0000+0x73)
+#define START_SC82 (0x0000+0x74)
+#define START_SC90 (0x0000+0x75)
+#define MANTRACH_SPEECH (0x0000+0x76)
+#define ID_GRID81 21010
+#define ID_SC81_DOOR 21011
+#define ID_SC81_CHAIR 21012
+#define ID_SC81_HELMET 21013
+#define ID_SC81_FATHER 21014
+#define ID_SC81_FATHER_SAT 21015
+#define ID_SC81_FOSTER_SAT 21016
+#define ID_SC81_KEN_SAT 21017
+#define ID_SC81_TENT1 21025
+#define ID_SC81_TENT2 21026
+#define ID_SC81_TENT3 21027
+#define ID_SC81_TENT4 21028
+#define ID_SC81_TENT5 21029
+#define ID_SC81_TENT6 21030
+#define ID_SC81_BIG_TENT1 21037
+#define ID_SC81_BIG_TENT2 21038
+#define ID_SC81_BIG_TENT3 21039
+#define ID_SC39_WALTERS 16809
+#define ID_SC31_JOEY 16851
+#define ID_SC82_JOBSWORTH 21069
+#define DISQ_1 2048
+#define DISQ_2 4096
+#define DISQ_3 6144
+#define DISQ_5 10240
+#define DISQ_6 12288
+#define DISQ_7 14336
+#define DISQ_8 16384
+#define DISQ_9 18432
+#define DISQ_10 20480
+#define DISQ_11 22528
+#define DISQ_12 24576
+#define DISQ_13 26624
+#define DISQ_14 28672
+#define DISQ_15 30720
+#define T0 0
+#define T1 4096
+#define T2 8192
+#define T3 12288
+#define T4 16384
+#define T5 20480
+#define T6 24576
+#define T7 28672
+#define UP 0
+#define DOWN 1
+#define LEFT 2
+#define RIGHT 3
+#define TALK 4
+#define ID_FOSTER 3
+#define ID_JOEY 1
+#define JOBS 4122
+#define ID_JOBS 4122
+#define MINI_SS 4100
+#define FULL_SS 4101
+#define ID_S2_FLOOR 115
+#define ID_L_EXIT_S2 4315
+#define FOSTER_BIG 4098
+#define ID_R_EXIT_S2 4103
+#define ID_S4_FLOOR 4104
+#define ID_S4_L_EXIT 4105
+#define ID_TV_SCREENS 4108
+#define ID_KNOB 4109
+#define ID_CHUCK 4110
+#define ID_LAZER 4111
+#define ID_CUPBOARD 4112
+#define ID_SARNIE 4113
+#define ID_SPANNER 4114
+#define ID_BUTTONS 4115
+#define ID_TOP_LIFT 4116
+#define ID_MONITORS 4117
+#define ID_HOLE 4119
+#define ID_TOP_BARREL 4120
+#define ID_LOADER 4121
+#define ID_UPLOAD 4125
+#define ID_LIGHT1 4126
+#define ID_PANEL 4127
+#define ID_ALARM 4128
+#define ID_S3_FLOOR 4130
+#define ID_ROBOT_SHELL 4131
+#define ID_JOEY_PARK 2
+#define ID_DEAD_LOADER 4133
+#define IDO_CROW_BAR 63
+#define IDO_SARNIE 64
+#define IDO_SPANNER 65
+#define IDO_JOEY_BOARD 66
+#define IDO_CITYCARD 8
+#define IDO_SHADES 9
+#define IDO_PUTTY 10
+#define IDO_LIGHTBULB 11
+#define IDO_ANITA_CARD 71
+#define IDO_ANCHOR 74
+#define IDO_MAGAZINE 75
+#define IDO_TAPE 76
+#define IDO_GLASS 77
+#define IDO_TICKET 79
+#define IDO_SECATEURS 36
+#define IDO_ROPE 37
+#define IDO_PLASTER 38
+#define IDO_NEW_CABLE 39
+#define IDO_BRICK 42
+#define IDO_TONGS 43
+#define IDO_GALLCARD 6
+#define ID_LOW_LIFT 4137
+#define ID_STEVE_SPY 4138
+#define ID_LOW_BARREL 4139
+#define ID_CONVEY 4140
+#define ID_JOEY_FLY 4141
+#define ID_FURNACE 4142
+#define ID_LIGHTS1 4143
+#define ID_EYE_BALL 4144
+#define ID_EYE_BOLT 4145
+#define ID_FURNACE_DOOR 4146
+#define ID_SLOT 4147
+#define ID_SHADES 4148
+#define ID_LAZER_GUN 4149
+#define ID_SMOULDER 4150
+#define ID_NOTICE 4151
+#define ID_NOTICE2 4152
+#define ID_SS_SIGN 4153
+#define ID_POSTCARD 4154
+#define ID_NOTICE4 4155
+#define ID_SHRUG_SEQ 40
+#define ID_SMALL_SHRUG 13
+#define ID_SML_UP_GET_SEQ 14
+#define ID_TEXT_MOUSE 5
+#define ID_S_AND_R 19
+#define ID_MENU_LOGIC 4
+#define ID_STD_MENU_LOGIC 4
+#define ID_ANIM 4186
+#define ID_RESET 4282
+#define ID_RESET_MEGA 7
+#define ID_FAN1 4102
+#define ID_FAN2 4303
+#define ID_FAN3 4305
+#define ID_FAN4 4307
+#define ID_FAN5 4309
+#define ID_FAN6 4311
+#define ID_FAN7 4313
+#define ID_S6_FLOOR 8200
+#define ID_S6_STAIRS 8210
+#define ID_S6_JOEY_FLY 8215
+#define ID_LEFT_EXIT_S6 8221
+#define ID_S5_FLOOR 8223
+#define ID_RIGHT_EXIT_S5 8224
+#define ID_RIGHT_EXIT_S6 8226
+#define ID_S7_FLOOR 8231
+#define ID_LEFT_EXIT_S7 8234
+#define ID_LEFT_EXIT_S5 8238
+#define ID_S18_FLOOR 8243
+#define ID_RIGHT_EXIT_S18 8246
+#define ID_SECURITY_EXIT 8248
+#define ID_S9_FLOOR 8253
+#define ID_LEFT_EXIT_S9 8256
+#define ID_STEAM 8259
+#define ID_POWER_DOOR 8264
+#define ID_POWER_MOTOR 8266
+#define ID_POWER_PANEL 8270
+#define PANEL_FRAME 4160
+#define SWITCH_FRAME 4032
+#define ID_POWER_SWITCH 8271
+#define ID_POWER_CHAIR 8272
+#define ID_LEFT_SKULL 8273
+#define ID_RIGHT_SKULL 8274
+#define ID_POWER_BANG 8275
+#define ID_MONITOR 136
+#define ID_LEFT_LEVER 8290
+#define ID_RIGHT_LEVER 8291
+#define LEFT_LEVER_FRAME 5760
+#define RIGHT_LEVER_FRAME 5824
+#define ID_FANS 8292
+#define ID_LOBBY_DOOR 8295
+#define ID_SCANNER 8298
+#define ID_LOBBY_SLOT 8299
+#define NO_TEXT_MESSAGE 28707
+#define ID_DAD 8301
+#define ID_SON 8211
+#define ID_LOW_GET_SEQ 12
+#define ID_PRESS 4321
+#define ID_LOW_FLOOR 67
+#define ID_SMALL_DOOR 105
+#define ID_LFAN1 4326
+#define ID_LFAN2 4328
+#define ID_SMOKE1 4330
+#define ID_SMOKE2 4332
+#define ID_SKORL_GUARD 8309
+#define S5_SECURITY_EXIT 8310
+#define ID_S8_FLOOR 8316
+#define ID_S7_RIGHT_EXIT 8317
+#define ID_DOWN_EXIT_S8 8320
+#define ID_WRECK_GUARD 8324
+#define ID_FACTORY_ENTRY 8331
+#define ID_S12_FLOOR 8336
+#define ID_FACTORY_EXIT 8341
+#define ID_FACT1_EXIT 8344
+#define ID_S13_FLOOR 8349
+#define ID_FACT2_L_EXIT 8353
+#define ID_FACT2_R_EXIT 8355
+#define ID_S14_FLOOR 8360
+#define ID_FACT3_L_EXIT 8364
+#define ID_F2_STORE_EXIT 8366
+#define ID_S15_FLOOR 8371
+#define ID_NU_FLOOR 8441
+#define ID_STORE_EXIT 8375
+#define ID_ANITA 137
+#define ID_TOP_BELT 8379
+#define ID_BOT_BELT 8381
+#define ID_PIPES 8383
+#define ID_ANITA_SPY 8385
+#define ID_WELDER 8388
+#define ID_LAMB 16
+#define ID_COGS 8393
+#define ID_GEARS 8395
+#define ID_BELT1 8397
+#define ID_BELT2 8399
+#define ID_PIPE1 8401
+#define ID_PIPE2 8403
+#define ID_PIPE3 8405
+#define ID_PIPE4 8407
+#define ID_STD_LEFT_TALK 23
+#define ID_STD_RIGHT_TALK 24
+#define ID_SENSOR 8410
+#define ID_LITE1 8412
+#define ID_LITE2 8414
+#define ID_FOREMAN 8544
+#define ID_FACT2_SPY 8418
+#define ID_S7_CARD_SLOT 8420
+#define ID_LIFT_NOTICE 8421
+#define ID_LIFT_S7 8422
+#define ID_LINC_S7 8425
+#define ID_JUNCTION_BOX 8426
+#define ID_FAKE_FLOOR 8427
+#define ID_FACT_CONSOLE 8435
+#define ID_FLAP 8438
+#define ID_SKEY 8442
+#define ID_WD40 8443
+#define IDO_WD40 34
+#define IDO_SKEY 35
+#define ID_FLOOR_PUTTY 8446
+#define ID_NEW_GRID 15
+#define ST_BACKGROUND 1
+#define ST_FOREGROUND 2
+#define ST_SORT 4
+#define ST_RECREATE 8
+#define ST_MOUSE 16
+#define ST_COLLISION 32
+#define ST_LOGIC 64
+#define ST_GRID_PLOT 128
+#define ST_AR_PRIORITY 256
+#define S62 3968
+#define S91 5824
+#define S94 6016
+#define S95 6080
+#define S96 6144
+#define S106 6784
+#define S108 6912
+#define S137 8768
+#define S152 9728
+#define S182 11648
+#define S191 12224
+#define HEAD_TEXT 24681
+#define PAL_90 24717
+#define PAL_90A 24718
+#define PAL_90B 24719
+#define PAL_91 24720
+#define PAL_92 24721
+#define PAL_93 24722
+#define PAL_94 24723
+#define PAL_95 24724
+#define PAL_96 24725
+#define RST_L_ARR_LINC 142
+#define RST_R_ARR_LINC 143
+#define RST_BLANKS_LINC 144
+#define RST_FOST_S90 24656
+#define RST_FOST_90_91 24657
+#define RST_FOST_90_94 24658
+#define RST_FOST_91_90 24659
+#define RST_FOST_91_92 24660
+#define RST_FOST_91_95 24661
+#define RST_FOST_92_91 24662
+#define RST_FOST_92_93 24663
+#define RST_FOST_93_92 24664
+#define RST_FOST_94_90 24665
+#define RST_FOST_94_95 24666
+#define RST_FOST_95_91 24667
+#define RST_FOST_95_94 24668
+#define RST_FOST_95_96 24669
+#define RST_FOST_96_95 24670
+#define AMT_ENTER_TOP 24814
+#define AMT_EXIT_TOP 24815
+#define AMT_LOGON 24824
+#define AMT_LOGOFF 24825
+#define AMT_CROUCH_LEFT 24759
+#define AMT_CROUCH_RIGHT 24760
+#define AMT_CROUCH_RIGHT_A 24805
+#define AMT_CROUCH_RIGHT_B 24806
+#define AMT_CROUCH_DOWN 24704
+#define AMT_SHRUG 24618
+#define AMT_LIGHT1 24671
+#define AMT_LIGHT2 24672
+#define AMT_LIGHT3A 24673
+#define AMT_LIGHT3B 24674
+#define AMT_LIGHT3C 24675
+#define AMT_LIGHT4 24676
+#define AMT_LIGHT5 24677
+#define AMT_LIGHT6 24678
+#define AMT_LIGHT7 24679
+#define AMT_LIGHT8 24680
+#define AMT_LIGHT9A 24681
+#define AMT_LIGHT9B 24682
+#define AMT_LIGHT9C 24683
+#define AMT_LIGHT10A 24684
+#define AMT_LIGHT10B 24685
+#define AMT_LIGHT10C 24686
+#define AMT_LIGHT10D 24687
+#define AMT_DOOR_L90 24688
+#define AMT_DOOR_L90F 24689
+#define AMT_DOOR_R90 24690
+#define AMT_DOOR_R90F 24691
+#define AMT_GET_JOIN 24692
+#define AMT_GET_OSCILL 24693
+#define AMT_BLIND_EYE 24694
+#define AMT_SEE_EYE 24695
+#define AMT_GET_EYE 24758
+#define AMT_EYE90_ZAP 24802
+#define AMT_FOST_DIE90 24793
+#define AMT_DOOR_L91 24696
+#define AMT_DOOR_L91F 24697
+#define AMT_DOOR_R91 24796
+#define AMT_DOOR_R91F 24797
+#define AMT_DOOR_T91 24698
+#define AMT_DOOR_T91R 24699
+#define AMT_GET_DECOMP 24702
+#define AMT_GET_DECRYPT 24703
+#define AMT_GET_REPORT 24733
+#define AMT_EYE91_ZAP 24800
+#define AMT_FOST_DIE91 24728
+#define AMT_DOOR_L92 24822
+#define AMT_DOOR_L92F 24823
+#define AMT_DOOR_R92 24808
+#define AMT_DOOR_R92R 24809
+#define AMT_DOOR_L93 24812
+#define AMT_DOOR_L93F 24813
+#define AMT_GET_PERSONA 24705
+#define AMT_GET_ADJUST 24706
+#define AMT_DOOR_L94 24707
+#define AMT_DOOR_L94R 24708
+#define AMT_DOOR_R94 24709
+#define AMT_DOOR_R94R 24710
+#define AMT_HOLO1_A 24726
+#define AMT_HOLO1_B 24727
+#define AMT_HOLO3 24768
+#define AMT_DOOR_L95 24711
+#define AMT_DOOR_L95F 24712
+#define AMT_DOOR_R95 24771
+#define AMT_DOOR_R95F 24772
+#define AMT_DOOR_T95 24713
+#define AMT_DOOR_T95R 24714
+#define AMT_GUARDIAN_UP 24791
+#define AMT_GUARDIAN_DOWN 24801
+#define AMT_WEIGHT_ANIM 24826
+#define AMT_DOOR_L96 24780
+#define AMT_DOOR_L96F 24781
+#define AMT_CRYSTAL_SPIN 24788
+#define AMT_CRYSTAL_BREAK 24789
+#define AMT_VIRUS_SPIN 24790
+#define AMT_GET_VIRUS 24794
+#define ID_LINC_MENU_LOGIC 24831
+#define ID_LINC_MENU_MOUSE 24832
+#define IT_BLUE_FOSTER 182
+#define IT_LOGOFF 117
+#define IT_LINK_ARROWS 190
+#define IT_LINK_OBJECTS 191
+#define IT_WINDOW 26
+#define IT_INFO_BUTTON 137
+#define IT_WINDOW_LOGIC 24765
+#define IT_WINDOW_MOUSE 24766
+#define IT_GET_EYE 18
+#define IT_CROUCH_LEFT 16
+#define IT_CROUCH_RIGHT 17
+#define IT_CROUCH_DOWN 20
+#define IT_ENTER_TOP 135
+#define IT_EXIT_TOP 136
+#define IT_LIGHT1 64
+#define IT_LIGHT2 65
+#define IT_LIGHT3A 66
+#define IT_LIGHT3B 67
+#define IT_LIGHT3C 68
+#define IT_LIGHT4 69
+#define IT_LIGHT5 70
+#define IT_LIGHT6 71
+#define IT_LIGHT7 72
+#define IT_LIGHT8 73
+#define IT_LIGHT9A 74
+#define IT_LIGHT9B 75
+#define IT_LIGHT9C 76
+#define IT_LIGHT10A 85
+#define IT_LIGHT10B 86
+#define IT_LIGHT10C 87
+#define IT_LIGHT10D 88
+#define IT_SC90_LAYER_0 175
+#define IT_SC90_LAYER_1 176
+#define IT_SC90_GRID_1 177
+#define IT_SC90_FAST 102
+#define IT_SC90_CHIP 24735
+#define IT_SC90_LOGIC 24736
+#define IT_SC90_MOUSE 24737
+#define IT_DOOR_L90 45
+#define IT_DOOR_L90F 46
+#define IT_DOOR_R90 258
+#define IT_DOOR_R90F 259
+#define IT_JOIN_OBJECT 22
+#define IT_OSCILLATOR 132
+#define IT_EYEBALL 91
+#define IT_BLIND_EYE 89
+#define IT_SEE_EYE 90
+#define IT_EYE90_ZAP 113
+#define IT_FOST_DIE90 115
+#define IT_SC91_LAYER_0 183
+#define IT_SC91_LAYER_1 184
+#define IT_SC91_GRID_1 185
+#define IT_SC91_FAST 24738
+#define IT_SC91_CHIP 24739
+#define IT_SC91_LOGIC 24740
+#define IT_SC91_MOUSE 24741
+#define IT_DOOR_L91 260
+#define IT_DOOR_L91F 261
+#define IT_DOOR_R91 111
+#define IT_DOOR_R91F 112
+#define IT_DOOR_T91 31
+#define IT_DOOR_T91R 32
+#define IT_BAG_91 47
+#define IT_DECOMP_OBJ 48
+#define IT_DECRYPT_OBJ 131
+#define IT_REPORT_BOOK 95
+#define IT_EYE91_ZAP 114
+#define IT_FOST_DIE91 116
+#define IT_SC92_LAYER_0 192
+#define IT_SC92_LAYER_1 193
+#define IT_SC92_GRID_1 194
+#define IT_SC92_FAST 24742
+#define IT_SC92_CHIP 24743
+#define IT_SC92_LOGIC 24744
+#define IT_SC92_MOUSE 24745
+#define IT_BRIDGES 44
+#define IT_CIRCLES 62
+#define IT_DOOR_L92 54
+#define IT_DOOR_L92F 55
+#define IT_DOOR_R92 129
+#define IT_DOOR_R92R 130
+#define IT_SC93_LAYER_0 199
+#define IT_SC93_LAYER_1 250
+#define IT_SC93_GRID_1 251
+#define IT_SC93_FAST 24746
+#define IT_SC93_CHIP 24747
+#define IT_SC93_LOGIC 24748
+#define IT_SC93_MOUSE 24749
+#define IT_DOOR_L93 133
+#define IT_DOOR_L93F 134
+#define IT_PERSONA 51
+#define IT_ADJUST_BOOK 63
+#define IT_SC94_LAYER_0 13
+#define IT_SC94_FAST 24750
+#define IT_SC94_CHIP 24751
+#define IT_SC94_LOGIC 24752
+#define IT_SC94_MOUSE 24753
+#define IT_DOOR_L94 58
+#define IT_DOOR_L94R 59
+#define IT_DOOR_R94 60
+#define IT_DOOR_R94R 61
+#define IT_HOLO1_A 92
+#define IT_HOLO1_B 93
+#define IT_HOLO2_A 94
+#define IT_HOLO2_B 96
+#define IT_HOLO3 97
+#define IT_SC95_LAYER_0 23
+#define IT_SC95_LAYER_1 24
+#define IT_SC95_GRID_1 25
+#define IT_SC95_FAST 24754
+#define IT_SC95_CHIP 24755
+#define IT_SC95_LOGIC 24756
+#define IT_SC95_MOUSE 24757
+#define IT_DOOR_L95 56
+#define IT_DOOR_L95F 57
+#define IT_DOOR_R95 100
+#define IT_DOOR_R95F 101
+#define IT_DOOR_T95 52
+#define IT_DOOR_T95R 53
+#define IT_GUARDIAN 102
+#define IT_WEIGHT 103
+#define IT_SC96_LAYER_0 27
+#define IT_SC96_LAYER_1 28
+#define IT_SC96_GRID_1 29
+#define IT_SC96_FAST 24773
+#define IT_SC96_CHIP 24774
+#define IT_SC96_LOGIC 24775
+#define IT_SC96_MOUSE 24776
+#define IT_DOOR_L96 98
+#define IT_DOOR_L96F 99
+#define IT_CRYSTAL_SPIN 106
+#define IT_CRYSTAL_BREAK 107
+#define IT_VIRUS_SPIN 108
+#define IT_GET_VIRUS 110
+#define ID_BLUE_FOSTER 3
+#define ID_WINDOW_1 24761
+#define ID_WINDOW_2 24762
+#define ID_WINDOW_3 24763
+#define ID_WINDOW_4 24764
+#define ID_INFO_BUTTON 24810
+#define ID_HEAD_MODULE 24816
+#define ID_FILE_MODULE 24817
+#define ID_SIZE_MODULE 24818
+#define ID_AUTH_MODULE 24819
+#define ID_NOTE_MODULE 24820
+#define ID_SKY 24640
+#define ID_LIGHTNING 24645
+#define ID_LIGHTNING1 24646
+#define ID_LIGHTNING2 24647
+#define ID_LIGHTNING3 24648
+#define ID_GRID90 24701
+#define ID_GRID91 24715
+#define ID_GRID92 24716
+#define ID_GRID93 24782
+#define ID_GRID94 24783
+#define ID_GRID95 24784
+#define ID_GRID96 24785
+#define ID_INFO_MENU 24581
+#define ID_READ_MENU 24582
+#define ID_OPEN_MENU 24583
+#define ID_ORDERS_MENU 24630
+#define ID_ORDERS2_MENU 24828
+#define ID_CHARON_MENU 24628
+#define ID_JOIN_MENU 24584
+#define ID_GREEN_MENU 24626
+#define ID_RED_MENU 24627
+#define ID_REPORT_MENU 24732
+#define ID_REPORT2_MENU 24829
+#define ID_DECOMP_MENU 24629
+#define ID_DECRYPT_MENU 24631
+#define ID_PERSONA_MENU 24632
+#define ID_ADJUST_MENU 24643
+#define ID_ADJUST2_MENU 24830
+#define ID_PLAYBAK_MENU 24650
+#define ID_BLIND_MENU 24625
+#define ID_OSCILL_MENU 24649
+#define ID_KILL_MENU 24827
+#define ID_VIRUS_MENU 24651
+#define ID_SC90_FLOOR 24577
+#define ID_SC90_SMFLOOR 24591
+#define ID_DOOR_L90 24635
+#define ID_DOOR_L90F 24636
+#define ID_DOOR_R90 24579
+#define ID_DOOR_R90F 24600
+#define ID_JOIN_OBJECT 24604
+#define ID_OSCILLATOR 24641
+#define ID_EYEBALL_90 24644
+#define ID_EYE_90_TABLE 24652
+#define ID_SC91_FLOOR 24578
+#define ID_DOOR_L91 24580
+#define ID_DOOR_L91F 24601
+#define ID_DOOR_R91 24585
+#define ID_DOOR_R91F 24795
+#define ID_DOOR_T91 24606
+#define ID_DOOR_T91R 24607
+#define ID_BAG_91 24637
+#define ID_DECOMP_OBJ 24638
+#define ID_DECRYPT_OBJ 24639
+#define ID_REPORT_BOOK 24731
+#define ID_EYEBALL_91 24798
+#define ID_EYE_91_TABLE 24799
+#define ID_SLAB1 24586
+#define ID_SLAB2 24592
+#define ID_SLAB3 24593
+#define ID_SLAB4 24594
+#define ID_SLAB5 24595
+#define ID_SLAB6 24596
+#define ID_SLAB7 24597
+#define ID_SLAB8 24598
+#define ID_SLAB9 24599
+#define ID_BRIDGE_A 24610
+#define ID_BRIDGE_B 24611
+#define ID_BRIDGE_C 24612
+#define ID_BRIDGE_D 24613
+#define ID_BRIDGE_E 24614
+#define ID_BRIDGE_F 24615
+#define ID_BRIDGE_G 24616
+#define ID_BRIDGE_H 24617
+#define ID_DOOR_L92 24587
+#define ID_DOOR_L92F 24821
+#define ID_DOOR_R92 24588
+#define ID_DOOR_R92R 24807
+#define ID_GREEN_CIRCLE 24633
+#define ID_RED_CIRCLE 24634
+#define ID_SC93_FLOOR 24589
+#define ID_DOOR_L93 24590
+#define ID_DOOR_L93F 24792
+#define ID_PERSONA 24602
+#define ID_ADJUST_BOOK 24642
+#define ID_SC94_FLOOR 24603
+#define ID_DOOR_L94 24623
+#define ID_DOOR_L94R 24624
+#define ID_DOOR_R94 24621
+#define ID_DOOR_R94R 24622
+#define ID_HOLOGRAM_A 24729
+#define ID_HOLOGRAM_B 24767
+#define ID_HOLOGRAM_PAD 24730
+#define ID_SC95_FLOOR 24605
+#define ID_DOOR_L95 24608
+#define ID_DOOR_L95F 24609
+#define ID_DOOR_R95 24769
+#define ID_DOOR_R95F 24770
+#define ID_DOOR_T95 24619
+#define ID_DOOR_T95R 24620
+#define ID_GUARDIAN 24804
+#define ID_WEIGHT 24811
+#define ID_SC96_FLOOR 24777
+#define ID_DOOR_L96 24778
+#define ID_DOOR_L96F 24779
+#define ID_CRYSTAL 24786
+#define ID_VIRUS 24787
+#define BEFORE_SHRUG 5
+#define OFF_LEFT 104
+#define OFF_RIGHT 472
+#define DOOR_SHUT 1
+#define DOOR_OPEN 2
+#define DOOR_MOVING 3
+#define AR_OK 0
+#define AR_FAIL 1
+#define AR_ZERO 2
+#define L_BUTTON 2
+#define R_BUTTON 1
+#define F_UP 9
+#define W_UP 86
+#define M_UP 104
+#define G_UP 114
+#define K_UP 134
+#define ID_PIPE_TALK 144
+#define ID_MEDI 20511
+#define ID_WITNESS 20754
+#define ID_GALLAGHER 20812
+#define ID_KEN 20911
+#define ID_WALTER_TALK_UP 20983
+#define ID_WALTER_TALK_DWN 20984
+#define ID_WALTER_TALK_LFT 20985
+#define ID_WALTER_CONV 20986
+#define ID_MEDI_TALK_UP 20987
+#define ID_MEDI_TALK_DOWN 20988
+#define ID_MEDI_TALK_LEFT 20989
+#define ID_MEDI_TALK_RIGHT 20990
+#define ID_FOST_CONV_LEFT 20991
+#define ID_GALL_TALK_UP 20992
+#define ID_GALL_TALK_LEFT 20993
+#define ID_SC75_FREEZE_TLK 20994
+#define ID_SC75_DEAD_TLK 20995
+#define ID_KEN_TALK_UP 20996
+#define ID_KEN_TALK_DOWN 20997
+#define ID_KEN_TALK_LEFT 20998
+#define ID_KEN_TALK_RIGHT 20999
+#define ID_ANDROID_BABBLE 21000
+#define ID_STUCK_TALK 21001
+#define ID_FOST_PIPE_TALK 21002
+#define ID_SC66_FAST_LIST 20481
+#define ID_SC66_CHIP_LIST 20482
+#define ID_SC66_LOGIC_LIST 20483
+#define ID_SC66_MOUSE_LIST 20484
+#define ID_SC66_PALETTE 20485
+#define ID_RESET_66 20486
+#define ID_SC66_DOOR 20977
+#define ID_SC66_DOOR_CLOSE 20978
+#define ID_SC66_HOLE 20487
+#define ID_SC66_FOS_WALK_IN 20982
+#define ID_SC66_FOS_CRUSHED 20981
+#define ID_SC66_LO_BEAM 20969
+#define ID_SC66_LO_BEAM_ANM 20970
+#define ID_SC66_HI_BEAM 20966
+#define ID_SC66_HI_BEAM_AN1 20967
+#define ID_SC66_HI_BEAM_AN2 20968
+#define ID_SC66_ROCK1 20971
+#define ID_SC66_ROCK1_ANIM 20972
+#define ID_SC66_ROCK2 20973
+#define ID_SC66_ROCK2_ANIM 20974
+#define ID_SC66_ROCK3 20975
+#define ID_SC66_ROCK3_ANIM 20976
+#define ID_SC66_STONES 20979
+#define ID_SC66_STONES_ANIM 20980
+#define ID_SC67_FAST_LIST 20488
+#define ID_SC67_CHIP_LIST 20489
+#define ID_SC67_LOGIC_LIST 20490
+#define ID_SC67_MOUSE_LIST 20491
+#define ID_SC67_PALETTE 20492
+#define ID_GRID67 20502
+#define ID_RESET_66_67 20523
+#define ID_RESET_68_67 20529
+#define ID_SC67_FLOOR 20501
+#define ID_SC67_DOOR 20506
+#define ID_SC67_DOOR_OPEN 20508
+#define ID_SC67_DOOR_CLOSE 20509
+#define ID_SC67_BRICKWORK 20503
+#define ID_SC67_VEIN 20510
+#define ID_SC67_CLOT 20507
+#define ID_SC67_CRAWL 20521
+#define ID_SC67_DUSTOFF 20522
+#define ID_SC67_GETBRICK 20524
+#define ID_SC67_PLASTER 20526
+#define ID_SC67_PLAST_FALL 20525
+#define ID_SC67_PICK_PLAST 20651
+#define ID_SC67_BRICK 20527
+#define ID_SC67_BRICK_FALL 20528
+#define ID_SC67_PICK_BRICK 20650
+#define ID_SC67_STICK_IN 20652
+#define ID_SC67_PULL_OUT 20653
+#define ID_SC67_BRICK_HIT 20654
+#define ID_SC67_PLAST_HIT 20655
+#define ID_SC67_LPOCKET 20661
+#define ID_SC67_RPOCKET 20662
+#define ID_SC67_RUB_HEAD 20663
+#define ID_SC67_TRY_STICK 20677
+#define ID_SC67_CROWBAR 20678
+#define ID_SC67_BAR_FALL 20679
+#define ID_SC67_PUSS_LEAK 20680
+#define ID_SC67_MEDIFIX 20681
+#define ID_SC67_MEND 20682
+#define ID_SC67_MENDING 20683
+#define ID_SC67_ROCK 20504
+#define ID_SC67_ROCK_ANIM 20505
+#define ID_SC67_PULSE1 20493
+#define ID_SC67_PULSE1_ANIM 20497
+#define ID_SC67_PULSE2 20494
+#define ID_SC67_PULSE2_ANIM 20498
+#define ID_SC67_PULSE3 20495
+#define ID_SC67_PULSE3_ANIM 20499
+#define ID_SC67_PULSE4 20496
+#define ID_SC67_PULSE4_ANIM 20500
+#define ID_SC68_FAST_LIST 20512
+#define ID_SC68_CHIP_LIST 20513
+#define ID_SC68_LOGIC_LIST 20514
+#define ID_SC68_MOUSE_LIST 20515
+#define ID_SC68_PALETTE 20516
+#define ID_GRID68 20520
+#define ID_SC68_JOEY_LIST 20784
+#define ID_RESET_67_68 20517
+#define ID_RESET_69_68 20561
+#define ID_RESET_70_68 20599
+#define ID_SC68_FLOOR 20519
+#define ID_SC68_DOOR 20518
+#define ID_SC68_DOOR_CLOSE 20533
+#define ID_SC68_STAIRS 20532
+#define ID_SC68_DESCEND 20684
+#define ID_SC68_ASCEND 20685
+#define ID_SC68_EXIT 20558
+#define ID_SC68_SENSOR 20531
+#define ID_SC68_SENSOR_ANIM 20656
+#define ID_SC68_GRILL 20530
+#define ID_SC68_PULSE1 20534
+#define ID_SC68_PULSE1_ANIM 20540
+#define ID_SC68_PULSE2 20535
+#define ID_SC68_PULSE2_ANIM 20541
+#define ID_SC68_PULSE3 20536
+#define ID_SC68_PULSE3_ANIM 20542
+#define ID_SC68_PULSE4 20537
+#define ID_SC68_PULSE4_ANIM 20543
+#define ID_SC68_PULSE5 20538
+#define ID_SC68_PULSE5_ANIM 20544
+#define ID_SC68_PULSE6 20539
+#define ID_SC68_PULSE6_ANIM 20545
+#define ID_SC69_FAST_LIST 20552
+#define ID_SC69_CHIP_LIST 20553
+#define ID_SC69_LOGIC_LIST 20554
+#define ID_SC69_MOUSE_LIST 20555
+#define ID_SC69_PALETTE 20556
+#define ID_GRID69 20563
+#define ID_SC69_JOEY_LIST 20813
+#define ID_RESET_68_69 20559
+#define ID_RESET_71_69 20574
+#define ID_SC69_FLOOR 20557
+#define ID_SC69_EXIT 20560
+#define ID_SC69_GRILL 20562
+#define ID_SC69_DOOR 20570
+#define ID_SC69_PULSE1 20635
+#define ID_SC69_PULSE1_ANIM 20641
+#define ID_SC69_PULSE2 20636
+#define ID_SC69_PULSE2_ANIM 20642
+#define ID_SC69_PULSE3 20637
+#define ID_SC69_PULSE3_ANIM 20643
+#define ID_SC69_PULSE4 20638
+#define ID_SC69_PULSE4_ANIM 20644
+#define ID_SC69_PULSE5 20639
+#define ID_SC69_PULSE5_ANIM 20645
+#define ID_SC69_PULSE6 20640
+#define ID_SC69_PULSE6_ANIM 20646
+#define ID_SC70_FAST_LIST 20589
+#define ID_SC70_CHIP_LIST 20590
+#define ID_SC70_LOGIC_LIST 20591
+#define ID_SC70_MOUSE_LIST 20592
+#define ID_SC70_PALETTE 20593
+#define ID_GRID70 20597
+#define ID_RESET_68_70 20594
+#define ID_SC70_FLOOR 20595
+#define ID_SC70_DOOR 20598
+#define ID_SC70_IRIS 20600
+#define ID_SC70_BAR 20601
+#define ID_SC70_CONTROL 20602
+#define ID_SC70_GRILL 20603
+#define ID_SC70_CONSOL_ANIM 20647
+#define ID_SC70_PIT 20648
+#define ID_SC70_PIT_ANIM 20649
+#define ID_SC70_STEP_UP 20756
+#define ID_SC70_STEP_DOWN 20757
+#define ID_SC70_BAR_ANIM 20758
+#define ID_SC70_PULL_BAR 20759
+#define ID_SC70_ENTER_ANIM 20778
+#define ID_SC70_EXIT_ANIM 20779
+#define ID_SC710_FAST_LIST 20687
+#define ID_SC71_FAST_LIST 20564
+#define ID_SC71_CHIP_LIST 20565
+#define ID_SC71_LOGIC_LIST 20566
+#define ID_SC71_MOUSE_LIST 20567
+#define ID_SC71_PALETTE 20568
+#define ID_GRID71 20575
+#define ID_SC71_JOEY_LIST 20814
+#define ID_RESET_69_71 20571
+#define ID_RESET_72_71 20582
+#define ID_SC71_FAKE_FLOOR 20569
+#define ID_SC71_FLOOR 20572
+#define ID_SC71_DOOR69 20573
+#define ID_SC71_DOOR72 20579
+#define ID_SC71_LOCKED_DOOR 20674
+#define ID_SC71_MONITOR 20576
+#define ID_SC71_RECHARGER 20577
+#define ID_SC71_PANEL_ANIM 20776
+#define ID_SC71_PANEL2 20775
+#define ID_SC71_PANEL2_ANIM 20777
+#define ID_SC71_CONTROLS 20578
+#define ID_SC71_LIGHT2_ANIM 20768
+#define ID_SC71_LIGHT1 20766
+#define ID_SC71_LIGHT1_ANIM 20767
+#define ID_SC71_CHLITE 20769
+#define ID_SC71_CHLITE_ANIM 20770
+#define ID_SC71_MON_ANIM 20771
+#define ID_SC71_MEDI_CHARGE 20772
+#define ID_SC71_MEDI_GET_UP 20774
+#define ID_SC71_MEDI_SLOT 20675
+#define ID_SC71_USE_BOARD 20773
+#define ID_SC720_FAST_LIST 20686
+#define ID_SC72_FAST_LIST 20546
+#define ID_SC72_CHIP_LIST 20547
+#define ID_SC72_LOGIC_LIST 20548
+#define ID_SC72_MOUSE_LIST 20549
+#define ID_SC72_PALETTE 20550
+#define ID_GRID72 20596
+#define ID_SC72_JOEY_LIST 20815
+#define ID_RESET_71_72 20581
+#define ID_RESET_73_72 20614
+#define ID_SC72_FAKE_FLOOR 20551
+#define ID_SC72_FLOOR 20580
+#define ID_SC72_DOOR 20583
+#define ID_SC72_EXIT 20604
+#define ID_SC72_TAP 20588
+#define ID_SC72_TANK 20584
+#define ID_SC72_TANK_ANIM 20785
+#define ID_SC72_ROT_LIGHT 20792
+#define ID_SC72_ROTATING 20793
+#define ID_SC72_CHAMBER1 20585
+#define ID_SC72_CHAM1_ANIM 20789
+#define ID_SC72_CHAM1_LIGHT 20780
+#define ID_SC72_CHAM1_FLASH 20781
+#define ID_SC72_CHAMBER2 20586
+#define ID_SC72_CHAM2_ANIM 20790
+#define ID_SC72_CHAM2_LIGHT 20782
+#define ID_SC72_CHAM2_FLASH 20783
+#define ID_SC72_CHAMBER3 20761
+#define ID_SC72_CHAM3_ANIM 20791
+#define ID_SC72_COMPUTER 20765
+#define ID_SC72_COMP_FLASH 20786
+#define ID_SC72_COMPUTER2 20787
+#define ID_SC72_COMP2_FLASH 20788
+#define ID_SC72_LIGHT1 20762
+#define ID_SC72_LIGHT2 20763
+#define ID_SC72_LIGHT3 20764
+#define ID_SC72_GRILL 20587
+#define ID_SC72_WALTER_KILL 20794
+#define ID_SC72_FOSTER_DIE 20795
+#define ID_SC72_WALTER_DIE 20800
+#define ID_SC72_JOEY_TAP 20796
+#define ID_SC72_SPILL 20798
+#define ID_SC72_SPILL_ANIM 20799
+#define ID_SC72_DRIP_ANIM 20797
+#define ID_SC73_FAST_LIST 20605
+#define ID_SC73_CHIP_LIST 20606
+#define ID_SC73_LOGIC_LIST 20607
+#define ID_SC73_MOUSE_LIST 20608
+#define ID_SC73_PALETTE 20609
+#define ID_GRID73 20612
+#define ID_SC73_JOEY_LIST 20816
+#define ID_RESET_72_73 20610
+#define ID_RESET_74_73 20629
+#define ID_RESET_75_73 20673
+#define ID_SC73_FLOOR 20611
+#define ID_SC73_EXIT 20613
+#define ID_SC73_BIG_DOOR 20617
+#define ID_SC73_SENSOR 20618
+#define ID_SC73_SENSOR_ANIM 20657
+#define ID_SC73_DOOR 20619
+#define ID_SC73_LOCKED_DOOR 20676
+#define ID_SC73_CHAMBER3 20817
+#define ID_SC73_CHAM3_ANIM 20818
+#define ID_SC73_CHAMBER4 20615
+#define ID_SC73_CHAM4_ANIM 20658
+#define ID_SC73_CHAM4_LIGHT 20819
+#define ID_SC73_CHAM4_FLASH 20820
+#define ID_SC73_CHAMBER5 20616
+#define ID_SC73_CHAM5_ANIM 20755
+#define ID_SC73_CHAM5_LIGHT 20821
+#define ID_SC73_CHAM5_FLASH 20822
+#define ID_SC73_JOEY_LUNGE 20846
+#define ID_SC73_JOEY_FIGHT1 20847
+#define ID_SC73_GALL_FIGHT1 20848
+#define ID_SC73_JOEY_FIGHT2 20849
+#define ID_SC73_GALL_FIGHT2 20850
+#define ID_SC73_GET_BOARD 20859
+#define ID_SC73_SEARCH 20860
+#define ID_SC73_BITS 20851
+#define ID_SC73_BITS_ANIM 20852
+#define ID_SC73_BITS2 20853
+#define ID_SC73_BITS2_ANIM 20854
+#define ID_SC73_SPRAY 20855
+#define ID_SC73_SPRAY_ANIM 20856
+#define ID_SC74_FAST_LIST 20620
+#define ID_SC74_CHIP_LIST 20621
+#define ID_SC74_LOGIC_LIST 20622
+#define ID_SC74_MOUSE_LIST 20623
+#define ID_SC74_PALETTE 20624
+#define ID_GRID74 20627
+#define ID_RESET_73_74 20625
+#define ID_SC74_FLOOR 20626
+#define ID_SC74_DOOR 20628
+#define ID_SC74_INTERFACE 20633
+#define ID_SC74_INT_SLOT 20659
+#define ID_SC74_TERMINAL 20634
+#define ID_SC74_POD 20823
+#define ID_SC74_POD_DOWN 20824
+#define ID_SC74_POD_UP 20825
+#define ID_SC74_FOST_SIT 20826
+#define ID_SC74_GET_UP 20827
+#define ID_SC74_USECARD 20702
+#define ID_SC74_USECARD2 20704
+#define ID_SC74_RPOCKET 20862
+#define ID_SC74_MONITOR1 20630
+#define ID_SC74_MON1_ANIM 20801
+#define ID_SC74_MONITOR2 20802
+#define ID_SC74_MON2_ANIM 20803
+#define ID_SC74_MONITOR3 20804
+#define ID_SC74_MON3_ANIM 20805
+#define ID_SC74_MONITOR4 20806
+#define ID_SC74_MON4_ANIM 20807
+#define ID_SC74_LEFT_TV 20631
+#define ID_SC74_LTV_ANIM 20808
+#define ID_SC74_RIGHT_TV 20632
+#define ID_SC74_RTV_ANIM 20809
+#define ID_SC74_LIGHTS 20810
+#define ID_SC74_LIGHTS_ANIM 20811
+#define ID_SC75_FAST_LIST 20664
+#define ID_SC75_CHIP_LIST 20665
+#define ID_SC75_LOGIC_LIST 20666
+#define ID_SC75_MOUSE_LIST 20667
+#define ID_SC75_PALETTE 20668
+#define ID_GRID75 20671
+#define ID_SC75_JOEY_LIST 20912
+#define ID_RESET_73_75 20669
+#define ID_RESET_76_75 20698
+#define ID_RS_TONGS_EMPTY 20868
+#define ID_RS_TONGS_LIVE 20869
+#define ID_RS_TONGS_FROZEN 20870
+#define ID_RS_TONGS_DEAD 20871
+#define ID_SC75_FLOOR 20670
+#define ID_SC75_BIG_DOOR 20672
+#define ID_SC75_DOOR 20696
+#define ID_SC75_TONGS 20660
+#define ID_SC75_GET_TONGS 20857
+#define ID_SC75_NITRO_TANK 20699
+#define ID_SC75_NITRO_ANIM 20828
+#define ID_SC75_LIVE_TANK 20700
+#define ID_SC75_TANK_ANIM 20872
+#define ID_SC75_CONSOLE 20703
+#define ID_SC75_MON_ANIM 20829
+#define ID_SC75_CRASH_ANIM 20701
+#define ID_SC75_LIGHT1 20830
+#define ID_SC75_LIGHT1_ANIM 20831
+#define ID_SC75_LIGHT2 20832
+#define ID_SC75_LIGHT2_ANIM 20833
+#define ID_SC75_USECARD 20858
+#define ID_SC75_RPOCKET 20861
+#define ID_SC75_HAND_TANK 20875
+#define ID_SC75_GET_TISS 20863
+#define ID_SC75_FREEZE_IT 20864
+#define ID_SC75_FREEZE_IT2 20865
+#define ID_SC75_FREEZE_DED 20866
+#define ID_SC75_FREEZE_DED2 20867
+#define ID_SC75_FREEZE_TALK 126
+#define ID_SC75_DEAD_TALK 128
+#define ID_SC76_FAST_LIST 20688
+#define ID_SC76_CHIP_LIST 20689
+#define ID_SC76_LOGIC_LIST 20690
+#define ID_SC76_MOUSE_LIST 20691
+#define ID_SC76_PALETTE 20692
+#define ID_GRID76 20695
+#define ID_SC76_JOEY_LIST 20913
+#define ID_RESET_75_76 20693
+#define ID_RESET_77_76 20727
+#define ID_SC76_FLOOR 20694
+#define ID_SC76_DOOR75 20697
+#define ID_SC76_DOOR77 20725
+#define ID_SC76_ANDROID_1 20705
+#define ID_SC76_HATCH_1 20909
+#define ID_SC76_ANDROID_2 20706
+#define ID_SC76_HATCH_2 20910
+#define ID_SC76_ANDROID_3 20707
+#define ID_SC76_HATCH_3 20908
+#define ID_SC76_PUNCH 20916
+#define ID_SC76_FOSTFALL 20917
+#define ID_SC76_CONSOLE_1 20711
+#define ID_SC76_CONSOLE_2 20712
+#define ID_SC76_CONSOLE_3 20713
+#define ID_SC76_CABINET_1 20714
+#define ID_SC76_CAB1_OPEN 20890
+#define ID_SC76_CAB1_CLOSE 20891
+#define ID_SC76_CABINET_2 20715
+#define ID_SC76_CAB2_OPEN 20892
+#define ID_SC76_CAB2_CLOSE 20893
+#define ID_SC76_CABINET_3 20716
+#define ID_SC76_CAB3_OPEN 20894
+#define ID_SC76_CAB3_CLOSE 20895
+#define ID_SC76_BOARD_1 20896
+#define ID_SC76_BOARD_2 20897
+#define ID_SC76_BOARD_3 20898
+#define ID_SC76_OPEN_CAB 20899
+#define ID_SC76_SHUT_CAB 20900
+#define ID_SC76_LOW_GET 20901
+#define ID_SC76_LIGHT1 20834
+#define ID_SC76_LIGHT1_ANIM 20835
+#define ID_SC76_LIGHT2 20836
+#define ID_SC76_LIGHT2_ANIM 20837
+#define ID_SC76_LIGHT3 20838
+#define ID_SC76_LIGHT3_ANIM 20839
+#define ID_SC76_LIGHT4 20840
+#define ID_SC76_LIGHT4_ANIM 20841
+#define ID_SC76_LIGHT5 20842
+#define ID_SC76_LIGHT5_ANIM 20843
+#define ID_SC76_LIGHT6 20844
+#define ID_SC76_LIGHT6_ANIM 20845
+#define ID_SC76_LIGHT7 20902
+#define ID_SC76_LIGHT7_ANIM 20903
+#define ID_SC76_LIGHT8 20904
+#define ID_SC76_LIGHT8_ANIM 20905
+#define ID_SC76_LIGHT9 20906
+#define ID_SC76_LIGHT9_ANIM 20907
+#define ID_SC76_AND2_BABBLE 142
+#define ID_SC77_FAST_LIST 20717
+#define ID_SC77_CHIP_LIST 20718
+#define ID_SC77_LOGIC_LIST 20719
+#define ID_SC77_MOUSE_LIST 20720
+#define ID_SC77_PALETTE 20721
+#define ID_GRID77 20724
+#define ID_SC77_JOEY_LIST 20914
+#define ID_RESET_76_77 20722
+#define ID_RESET_78_77 20742
+#define ID_SC77_FLOOR 20723
+#define ID_SC77_DOOR76 20726
+#define ID_SC77_BIG_DOOR 20728
+#define ID_SC77_TANK_1 20729
+#define ID_SC77_TANK_2 20730
+#define ID_SC77_HAND_1 20731
+#define ID_SC77_HAND_2 20732
+#define ID_SC77_DOOR_OPEN 20760
+#define ID_SC77_FPUSHL_1 20918
+#define ID_SC77_FPUSHL_2 20919
+#define ID_SC77_FPUSHR_1 20920
+#define ID_SC77_FPUSHR_2 20921
+#define ID_SC77_KPUSHR_1 20922
+#define ID_SC77_KPUSHR_2 20923
+#define ID_SC77_STRETCH 20924
+#define ID_SC78_FAST_LIST 20733
+#define ID_SC78_CHIP_LIST 20734
+#define ID_SC78_LOGIC_LIST 20735
+#define ID_SC78_MOUSE_LIST 20736
+#define ID_SC78_PALETTE 20737
+#define ID_SC781_PALETTE 20964
+#define ID_GRID78 20740
+#define ID_RESET_77_78 20738
+#define ID_RESET_79_78 20753
+#define ID_SC78_LEDGE 20739
+#define ID_SC78_PIPE 20915
+#define ID_SC78_BIG_DOOR 20741
+#define ID_SC78_EXIT 20743
+#define ID_SC78_SUPPORT 20874
+#define ID_SC78_JUMP_DOWN 20881
+#define ID_SC78_CLIMB_UP 20883
+#define ID_SC79_FAST_LIST 20744
+#define ID_SC79_CHIP_LIST 20745
+#define ID_SC79_LOGIC_LIST 20746
+#define ID_SC79_MOUSE_LIST 20747
+#define ID_SC79_PALETTE 20748
+#define ID_SC791_PALETTE 20963
+#define ID_GRID79 20751
+#define ID_RESET_78_79 20749
+#define ID_RESET_80_79 20889
+#define ID_SC79_PIPE 20750
+#define ID_SC79_EXIT 20752
+#define ID_SC79_SUPPORT 20873
+#define ID_SC79_LADDER 20940
+#define ID_SC79_CROUCH_DOWN 20941
+#define ID_SC79_CROUCH_UP 20942
+#define ID_SC79_CLIMB_DOWN 20943
+#define ID_SC79_CLIMB_UP 20944
+#define ID_SC79_TIE_ROPE 20951
+#define ID_SC79_TOSS_ROPE 20952
+#define ID_SC79_KNOT 20955
+#define ID_SC79_ROPE 20887
+#define ID_SC79_ROPE_ANIM 20953
+#define ID_SC80_FAST_LIST 20876
+#define ID_SC80_CHIP_LIST 20877
+#define ID_SC80_LOGIC_LIST 20878
+#define ID_SC80_MOUSE_LIST 20879
+#define ID_SC80_PALETTE 20880
+#define ID_SC801_PALETTE 20959
+#define ID_SC802_PALETTE 20960
+#define ID_SC803_PALETTE 20961
+#define ID_SC804_PALETTE 20962
+#define ID_RESET_79_80 20882
+#define ID_SC80_SPOUT 20884
+#define ID_SC80_LADDER 20950
+#define ID_SC80_ROPE 20888
+#define ID_SC80_ORIFICE 20885
+#define ID_SC80_EXIT 20886
+#define ID_SC80_EXIT_OPEN 20954
+#define ID_SC80_GOO 20925
+#define ID_SC80_GOO_ANIM 20926
+#define ID_SC80_BUBBLE1 20927
+#define ID_SC80_BUB1_ANIM 20928
+#define ID_SC80_BUBBLE2 20929
+#define ID_SC80_BUBBLE3 20930
+#define ID_SC80_BUBBLE4 20931
+#define ID_SC80_BUBBLE5 20932
+#define ID_SC80_BUBBLE6 20933
+#define ID_SC80_BUBBLE7 20934
+#define ID_SC80_BUBBLE8 20935
+#define ID_SC80_BUBBLE9 20936
+#define ID_SC80_BUBBLE10 20937
+#define ID_SC80_BUBBLE11 20938
+#define ID_SC80_BUBBLE12 20939
+#define ID_SC80_CLIMB_DOWN 20945
+#define ID_SC80_CLIMB_UP 20946
+#define ID_SC80_PIPE_SHRUG 20965
+#define ID_SC80_CLAMBER 20947
+#define ID_SC80_GET_ROPE 20948
+#define ID_SC80_SWING 20949
+#define ID_SC80_DROP 20956
+#define ID_SC80_SAMPLE 20957
+#define ID_SC80_SAMPLE_FALL 20958
+#define IT_MEDI 32
+#define IT_MEDI_TALK 180
+#define IT_WITNESS 159
+#define IT_GALLAGHER 90
+#define IT_GALL_TALK 91
+#define IT_SC66_LAYER_0 20
+#define IT_SC66_DOOR 105
+#define IT_SC66_HI_BEAM_AN1 98
+#define IT_SC66_HI_BEAM_AN2 99
+#define IT_SC66_LO_BEAM_ANM 22
+#define IT_SC66_ROCK1 100
+#define IT_SC66_ROCK2 101
+#define IT_SC66_ROCK3 102
+#define IT_SC66_STONES 103
+#define IT_SC66_FOS_CRUSHED 104
+#define IT_SC66_FOS_WALK_IN 21
+#define IT_SC67_LAYER_0 23
+#define IT_SC67_LAYER_1 24
+#define IT_SC67_GRID_1 25
+#define IT_SC67_PULSE1 26
+#define IT_SC67_PULSE2 27
+#define IT_SC67_PULSE3 28
+#define IT_SC67_PULSE4 29
+#define IT_SC67_DOOR 30
+#define IT_SC67_ROCK 31
+#define IT_SC67_CRAWL 46
+#define IT_SC67_DUSTOFF 47
+#define IT_SC67_GETBRICK 48
+#define IT_SC67_BRICK 55
+#define IT_SC67_PLASTER 56
+#define IT_SC67_PICK_BRICK 129
+#define IT_SC67_PICK_PLAST 130
+#define IT_SC67_STICK_IN 131
+#define IT_SC67_PULL_OUT 132
+#define IT_SC67_BRICK_HIT 133
+#define IT_SC67_PLAST_HIT 134
+#define IT_SC67_LPOCKET 141
+#define IT_SC67_RPOCKET 142
+#define IT_SC67_RUB_HEAD 143
+#define IT_SC67_PUSS 149
+#define IT_SC67_MEDIFIX 150
+#define IT_SC67_MENDING 151
+#define IT_SC67_CROWBAR 152
+#define IT_SC68_LAYER_0 43
+#define IT_SC68_LAYER_1 44
+#define IT_SC68_GRID_1 45
+#define IT_SC68_DOOR 57
+#define IT_SC68_PULSE1 58
+#define IT_SC68_PULSE2 59
+#define IT_SC68_PULSE3 60
+#define IT_SC68_PULSE4 61
+#define IT_SC68_PULSE5 62
+#define IT_SC68_PULSE6 63
+#define IT_SC68_SENSOR 137
+#define IT_SC68_DESCEND 153
+#define IT_SC68_ASCEND 154
+#define IT_SC69_LAYER_0 71
+#define IT_SC69_LAYER_1 72
+#define IT_SC69_LAYER_2 74
+#define IT_SC69_GRID_1 75
+#define IT_SC69_GRID_2 76
+#define IT_SC69_PULSE1 109
+#define IT_SC69_PULSE2 110
+#define IT_SC69_PULSE3 111
+#define IT_SC69_PULSE4 112
+#define IT_SC69_PULSE5 113
+#define IT_SC69_PULSE6 114
+#define IT_SC70_LAYER_0 90
+#define IT_SC70_LAYER_1 91
+#define IT_SC70_LAYER_2 92
+#define IT_SC70_GRID_1 93
+#define IT_SC70_GRID_2 94
+#define IT_SC70_IRIS 95
+#define IT_SC70_BAR 96
+#define IT_SC70_CONSOLE 115
+#define IT_SC70_GRILL 116
+#define IT_SC70_PIT 117
+#define IT_SC70_STEP_UP 14
+#define IT_SC70_STEP_DOWN 15
+#define IT_SC70_PULL_BAR 18
+#define IT_SC70_ENTER_ANIM 97
+#define IT_SC71_LAYER_0 85
+#define IT_SC71_LAYER_1 86
+#define IT_SC71_LAYER_2 87
+#define IT_SC71_GRID_1 88
+#define IT_SC71_GRID_2 89
+#define IT_SC710_LAYER_0 70
+#define IT_SC710_LAYER_1 16
+#define IT_SC710_LAYER_2 157
+#define IT_SC710_GRID_1 17
+#define IT_SC710_GRID_2 158
+#define IT_SC71_LIGHT1 162
+#define IT_SC71_LIGHT2 163
+#define IT_SC71_SCREEN 164
+#define IT_SC71_CHARGE_LIGHT 165
+#define IT_SC71_MEDI_CHARGE 166
+#define IT_SC71_USE_BOARD 148
+#define IT_SC71_PANEL 167
+#define IT_SC71_PANEL2 168
+#define IT_SC72_LAYER_0 64
+#define IT_SC72_LAYER_1 65
+#define IT_SC72_LAYER_2 66
+#define IT_SC72_GRID_1 68
+#define IT_SC72_GRID_2 69
+#define IT_SC720_LAYER_0 67
+#define IT_SC720_LAYER_1 160
+#define IT_SC720_LAYER_2 155
+#define IT_SC720_GRID_1 161
+#define IT_SC720_GRID_2 156
+#define IT_WALTER_CONVERSATION 129
+#define IT_WALTER_TALK_UP 130
+#define IT_WALTER_TALK_DOWN 131
+#define IT_WALTER_TALK_LEFT 132
+#define IT_SC72_CHAM1_LIGHT 171
+#define IT_SC72_CHAM2_LIGHT 172
+#define IT_SC72_TANK 173
+#define IT_SC72_ROT_LIGHT 177
+#define IT_SC72_COMPUTER 169
+#define IT_SC72_COMPUTER2 170
+#define IT_SC72_CHAMBER1 174
+#define IT_SC72_CHAMBER2 175
+#define IT_SC72_CHAMBER3 176
+#define IT_SC72_WALTER_KILL 178
+#define IT_SC72_FOSTER_DIE 179
+#define IT_SC72_WALTER_DIE 30
+#define IT_SC72_GRILL 28
+#define IT_SC72_JOEY_TAP 29
+#define IT_SC72_SPILL 31
+#define IT_SC73_LAYER_0 97
+#define IT_SC73_LAYER_1 98
+#define IT_SC73_LAYER_2 99
+#define IT_SC73_GRID_1 101
+#define IT_SC73_GRID_2 102
+#define IT_SC73_BIG_DOOR 138
+#define IT_SC73_SENSOR 139
+#define IT_SC73_CHAMBER3 142
+#define IT_SC73_CHAMBER4 140
+#define IT_SC73_CHAMBER5 141
+#define IT_SC73_CHAM4_LIGHT 95
+#define IT_SC73_CHAM5_LIGHT 96
+#define IT_SC73_JOEY_LUNGE 85
+#define IT_SC73_JOEY_FIGHT1 86
+#define IT_SC73_GALL_FIGHT1 87
+#define IT_SC73_JOEY_FIGHT2 88
+#define IT_SC73_GALL_FIGHT2 89
+#define IT_SC73_GET_BOARD 43
+#define IT_SC73_SEARCH 44
+#define IT_SC73_DEAD_GALL 72
+#define IT_SC73_BITS 74
+#define IT_SC73_BITS2 75
+#define IT_SC73_SPRAY 76
+#define IT_SC74_LAYER_0 104
+#define IT_SC74_LAYER_1 105
+#define IT_SC74_LAYER_2 106
+#define IT_SC74_GRID_1 107
+#define IT_SC74_GRID_2 108
+#define IT_SC74_POD_DOWN 109
+#define IT_SC74_POD_UP 110
+#define IT_SC74_FOST_SIT 92
+#define IT_SC74_GET_UP 93
+#define IT_SC74_USECARD 70
+#define IT_SC74_USECARD2 71
+#define IT_SC74_RPOCKET 62
+#define IT_SC74_MONITOR1 55
+#define IT_SC74_MONITOR2 56
+#define IT_SC74_MONITOR3 57
+#define IT_SC74_MONITOR4 58
+#define IT_SC74_LEFT_TV 59
+#define IT_SC74_RIGHT_TV 60
+#define IT_SC74_LIGHTS 61
+#define IT_SC75_LAYER_0 144
+#define IT_SC75_LAYER_1 145
+#define IT_SC75_LAYER_2 146
+#define IT_SC75_GRID_1 147
+#define IT_SC75_GRID_2 148
+#define IT_SC75_MONITOR 149
+#define IT_SC75_CRASH 164
+#define IT_SC75_TANK 165
+#define IT_SC75_STEAM 150
+#define IT_SC75_LIGHT1 151
+#define IT_SC75_LIGHT2 152
+#define IT_SC75_TONGS 153
+#define IT_SC75_GET_TONGS 154
+#define IT_SC75_USECARD 155
+#define IT_SC75_RPOCKET 156
+#define IT_SC75_HAND_TANK 166
+#define IT_SC75_GET_TISS 157
+#define IT_SC75_FREEZE_IT 158
+#define IT_SC75_FREEZE_TALK 159
+#define IT_SC75_FREEZE_IT2 160
+#define IT_SC75_FREEZE_DED 161
+#define IT_SC75_DEAD_TALK 162
+#define IT_SC75_FREEZE_DED2 163
+#define IT_SC76_LAYER_0 14
+#define IT_SC76_LAYER_1 15
+#define IT_SC76_LAYER_2 16
+#define IT_SC76_GRID_1 17
+#define IT_SC76_GRID_2 18
+#define IT_SC76_LIGHT1 29
+#define IT_SC76_LIGHT2 30
+#define IT_SC76_LIGHT3 31
+#define IT_SC76_LIGHT4 32
+#define IT_SC76_LIGHT5 43
+#define IT_SC76_LIGHT6 44
+#define IT_SC76_LIGHT7 45
+#define IT_SC76_LIGHT8 46
+#define IT_SC76_LIGHT9 47
+#define IT_SC76_CABINET_1 55
+#define IT_SC76_CABINET_2 56
+#define IT_SC76_CABINET_3 57
+#define IT_SC76_BOARD_1 58
+#define IT_SC76_BOARD_2 59
+#define IT_SC76_BOARD_3 60
+#define IT_SC76_OPEN_CAB 62
+#define IT_SC76_LOW_GET 63
+#define IT_KEN 61
+#define IT_SC76_HATCH_1 66
+#define IT_SC76_ANDROID_2 67
+#define IT_SC76_HATCH_2 68
+#define IT_SC76_ANDROID_3 64
+#define IT_SC76_HATCH_3 65
+#define IT_SC76_PUNCH 69
+#define IT_SC76_FOSTFALL 70
+#define IT_SC76_KEN_TALK 71
+#define IT_SC76_AND2_BABBLE 72
+#define IT_SC77_LAYER_0 20
+#define IT_SC77_LAYER_1 21
+#define IT_SC77_GRID_1 22
+#define IT_SC77_BIG_DOOR 28
+#define IT_SC77_FPUSHL 74
+#define IT_SC77_FPUSHR 75
+#define IT_SC77_KPUSHR 76
+#define IT_SC77_STRETCH 87
+#define IT_SC78_LAYER_0 23
+#define IT_SC78_LAYER_1 24
+#define IT_SC78_GRID_1 25
+#define IT_SC78_JUMP_DOWN 85
+#define IT_SC78_CLIMB_UP 86
+#define IT_SC79_LAYER_0 26
+#define IT_SC79_SUPPORT 48
+#define IT_SC79_CROUCH 91
+#define IT_SC79_CLIMB 92
+#define IT_SC79_TIE_ROPE 96
+#define IT_SC79_TOSS_ROPE 97
+#define IT_SC79_ROPE 98
+#define IT_SC79_KNOT 101
+#define IT_SC80_LAYER_0 27
+#define IT_SC80_EXIT 100
+#define IT_SC80_ROPE 99
+#define IT_SC80_GOO 88
+#define IT_SC80_BUBBLE 89
+#define IT_SC80_CLIMB 90
+#define IT_SC80_CLAMBER 93
+#define IT_SC80_GET_ROPE 94
+#define IT_SC80_SWING 95
+#define IT_SC80_DROP 103
+#define IT_SC80_SAMPLE 104
+#define IT_SC80_PIPE_TALK 105
+#define IT_SC80_PIPE_SHRUG 106
+#define IDO_DOG_FOOD 49
+#define ID_SC30_FAST_LIST 16385
+#define ID_SC30_CHIP_LIST 16386
+#define ID_SC30_LOGIC_LIST 16387
+#define ID_SC30_MOUSE_LIST 16388
+#define ID_SC30_PALETTE 16389
+#define ID_SC30_WALK_GRID 16390
+#define ID_SC30_JOEY_LIST 16547
+#define ID_RESET_31_30 16413
+#define ID_RESET_33_30 16414
+#define ID_RESET_36_30 16539
+#define ID_RESET_42_30 16811
+#define ID_RESET_COURT_OPEN 16813
+#define ID_SC30_FLOOR 16392
+#define ID_SC30_EXIT_31 16393
+#define ID_SC30_EXIT_33 16394
+#define ID_SC30_EXIT_36 16492
+#define ID_SC30_COURT_DOOR 16487
+#define ID_SC30_COURT_CLOSE 16814
+#define ID_SC30_NOTICE 16489
+#define ID_SC30_STATUE_1 16490
+#define ID_SC30_STATUE_2 16491
+#define ID_SC30_HENRI 16516
+#define ID_SC30_HENRI_TALK 16517
+#define ID_SC30_HENRI_TIE 16518
+#define ID_SC30_HEN_STEP_F 16519
+#define ID_SC30_HEN_STEP_B 16520
+#define ID_SC30_HEN_BLINK 16521
+#define ID_SC30_PUSH_DOOR 16522
+#define ID_SC31_FAST_LIST 16774
+#define ID_SC31_CHIP_LIST 16396
+#define ID_SC31_LOGIC_LIST 16397
+#define ID_SC31_MOUSE_LIST 16398
+#define ID_SC31_PALETTE 16399
+#define ID_SC31_WALK_GRID 16400
+#define ID_SC31_JOEY_LIST 16548
+#define ID_RESET_START_31 16391
+#define ID_RESET_30_31 16401
+#define ID_RESET_32_31 16425
+#define ID_RESET_39_31 16463
+#define ID_RS_GUARD_CHAT 16699
+#define ID_RS_GUARD_AVAIL 16700
+#define ID_SC31_FLOOR 16402
+#define ID_SC31_EXIT_30 16403
+#define ID_SC31_EXIT_32 16415
+#define ID_SC31_EXIT_39 16453
+#define ID_SC31_LIFT_SLOT 16493
+#define ID_SC31_LIFT 16513
+#define ID_SC31_LIFT_OPEN 16514
+#define ID_SC31_LIFT_CLOSE 16515
+#define ID_SC31_USE_CARD 16523
+#define ID_SC31_PULL_ROPE 16551
+#define ID_SC31_LOWER_ROPE 16552
+#define ID_SC31_DROP_ROPE 16553
+#define ID_SC31_END_OF_ROPE 16554
+#define ID_SC31_ROPE 16555
+#define ID_SC31_ROPE_PULLED 16556
+#define ID_SC31_ROPE_LOWER 16557
+#define ID_SC31_ROPE_DROP 16558
+#define ID_SC31_BRICKS 16559
+#define ID_SC31_BRICKS_UP 16560
+#define ID_SC31_BRICKS_DOWN 16561
+#define ID_SC31_BRICKS_FALL 16562
+#define ID_SC31_PLANK 16563
+#define ID_SC31_PLANK_DROP 16564
+#define ID_SC31_PLANK_RAISE 16565
+#define ID_SC31_PLANK_FLICK 16566
+#define ID_SC31_GUARD 16601
+#define ID_SC31_GUARD_TALK 16607
+#define ID_SC31_GUARD_BLINK 16693
+#define ID_SC31_GUARD_MOVE 16694
+#define ID_SC31_GUARD_REACH 16695
+#define ID_SC31_GUARD_TALK2 16696
+#define ID_SC31_GET_BRICKS 16683
+#define ID_SC31_GET_PLANK 16687
+#define ID_SC31_CLIMB_PLANK 16684
+#define ID_SC31_DOG_FLY 16685
+#define ID_SC31_DOG_RISE 16697
+#define ID_SC31_DOG_SWIM 16698
+#define ID_SC31_PUT_BISC 16688
+#define ID_SC31_BISCUITS 16692
+#define ID_SC31_BISC_PLACED 16689
+#define ID_SC31_BISC_DROP 16690
+#define ID_SC31_BISC_RAISE 16691
+#define ID_SC32_FAST_LIST 16416
+#define ID_SC32_CHIP_LIST 16417
+#define ID_SC32_LOGIC_LIST 16418
+#define ID_SC32_MOUSE_LIST 16419
+#define ID_SC32_PALETTE 16420
+#define ID_SC32_WALK_GRID 16421
+#define ID_SC32_JOEY_LIST 16549
+#define ID_RESET_31_32 16422
+#define ID_RESET_33_32 16429
+#define ID_RESET_38_32 16452
+#define ID_SC32_FLOOR 16423
+#define ID_SC32_EXIT_31 16424
+#define ID_SC32_EXIT_33 16426
+#define ID_SC32_LIFT 16442
+#define ID_SC32_LIFT_OPEN 16540
+#define ID_SC32_LIFT_CLOSE 16541
+#define ID_SC32_TERMINAL 16494
+#define ID_SC32_BUZZER 16495
+#define ID_SC32_PLANT_1 16496
+#define ID_SC32_PLANT_2 16497
+#define ID_SC32_PLANT_3 16498
+#define ID_SC32_USE_CARD 16524
+#define ID_SC32_USE_COM 16525
+#define ID_SC32_VINCENT 16599
+#define ID_SC32_VINC_ANIM 16602
+#define ID_SC32_GARDENER 16600
+#define ID_SC32_GARDENING1 16622
+#define ID_SC32_GARDENING2 16623
+#define ID_SC32_GARDENER_UP 16624
+#define ID_SC32_GARDENER_DN 16625
+#define ID_SC32_GARD_TURN_D 16626
+#define ID_SC32_GARD_TURN_U 16627
+#define ID_SC32_GARDEN_TALK 16628
+#define ID_SC33_FAST_LIST 16404
+#define ID_SC33_CHIP_LIST 16405
+#define ID_SC33_LOGIC_LIST 16406
+#define ID_SC33_MOUSE_LIST 16407
+#define ID_SC33_PALETTE 16408
+#define ID_SC33_WALK_GRID 16409
+#define ID_SC33_JOEY_LIST 16550
+#define ID_RESET_30_33 16410
+#define ID_RESET_32_33 16427
+#define ID_RESET_34_33 16440
+#define ID_SC33_FLOOR 16411
+#define ID_SC33_EXIT_30 16412
+#define ID_SC33_EXIT_32 16428
+#define ID_SC33_SHED_DOOR 16430
+#define ID_SC33_LOCK 16499
+#define ID_SC33_USE_CARD 16526
+#define ID_SC33_PUSH_DOOR1 16527
+#define ID_SC33_PUSH_DOOR2 16528
+#define ID_SC33_DOOR_OPEN 16529
+#define ID_SC34_FAST_LIST 16431
+#define ID_SC34_CHIP_LIST 16432
+#define ID_SC34_LOGIC_LIST 16433
+#define ID_SC34_MOUSE_LIST 16434
+#define ID_SC34_PALETTE 16435
+#define ID_SC34_WALK_GRID 16436
+#define ID_RESET_33_34 16437
+#define ID_SC34_FLOOR 16438
+#define ID_SC34_DOOR 16439
+#define ID_SC34_SECATEURS 16501
+#define ID_SC34_TKT_MACHINE 16502
+#define ID_SC34_MAP 16503
+#define ID_SC34_BRICKS 16504
+#define ID_SC34_GET_SECS 16544
+#define ID_SC34_STAIRS1 16545
+#define ID_SC34_STAIRS2 16546
+#define ID_SC36_FAST_LIST 16530
+#define ID_SC36_CHIP_LIST 16531
+#define ID_SC36_LOGIC_LIST 16532
+#define ID_SC36_MOUSE_LIST 16533
+#define ID_SC36_PALETTE 16534
+#define ID_SC36_WALK_GRID 16535
+#define ID_RESET_30_36 16536
+#define ID_RESET_37_36 16593
+#define ID_RESET_COLSTON 16812
+#define ID_SC36_FLOOR 16537
+#define ID_SC36_LOW_FLOOR 16596
+#define ID_SC36_EXIT_30 16538
+#define ID_SC36_DOOR 16583
+#define ID_SC36_DOOROPEN 16792
+#define ID_SC36_DOORSHUT 16793
+#define ID_SC36_FOS_DOWN1 16748
+#define ID_SC36_FOS_DOWN2 16749
+#define ID_SC36_FOS_UP1 16750
+#define ID_SC36_FOS_UP2 16751
+#define ID_SC36_PRESS_PLATE 16752
+#define ID_SC36_USE_JUKEBOX 16753
+#define ID_SC36_REACH_GLASS 16759
+#define ID_SC36_GET_GLASS 16760
+#define ID_SC36_JUKEBOX 16597
+#define ID_SC36_JUKE_TALK 16756
+#define ID_SC36_JUKE_STUCK 16770
+#define ID_SC36_JUKE_BREAK 16771
+#define ID_SC36_JUKE_LIGHT 16757
+#define ID_SC36_JUKEBOX_ON 16754
+#define ID_SC36_JUKEBOX_OFF 16755
+#define ID_SC36_JUKE_KICKED 16758
+#define ID_SC36_CARDS 16742
+#define ID_SC36_GLASS 16747
+#define ID_SC36_SENSOR 16594
+#define ID_SC36_BAND 16598
+#define ID_SC36_BAND_ANIM 16686
+#define ID_SC36_BARMAN 16701
+#define ID_BAR_BLINK 16702
+#define ID_BAR_GET_DRINK 16703
+#define ID_BAR_DRINK 16704
+#define ID_BAR_GET_CLOTH 16705
+#define ID_BAR_PUT_CLOTH 16706
+#define ID_BAR_WIPE 16707
+#define ID_BAR_WIPE2 16708
+#define ID_BARMAN_TALK 16709
+#define ID_SC36_BABS 16772
+#define ID_SC36_BABS_TALK 16773
+#define ID_SC36_COLSTON 16731
+#define ID_SC36_COL_FEET 16732
+#define ID_SC36_COL_TALK1 16743
+#define ID_SC36_COL_TALK2 16744
+#define ID_SC36_COL_DRINK 16746
+#define ID_SC36_COL_DEAL 16733
+#define ID_SC36_COL_THINK 16734
+#define ID_SC36_COL_BLINK1 16735
+#define ID_SC36_COL_BLINK2 16736
+#define ID_SC36_COL_DOWN1 16761
+#define ID_SC36_COL_DOWN2 16762
+#define ID_SC36_COL_DOWN3 16763
+#define ID_SC36_COL_DOWN4 16764
+#define ID_SC36_COL_UP1 16765
+#define ID_SC36_COL_UP2 16766
+#define ID_SC36_COL_UP3 16767
+#define ID_SC36_COL_UP4 16768
+#define ID_SC36_COL_KICK 16769
+#define ID_SC36_GALLAGHER 16737
+#define ID_SC36_GAL_TALK 16745
+#define ID_SC36_GAL_LEGS 16738
+#define ID_SC36_GAL_DEAL 16739
+#define ID_SC36_GAL_LOOK1 16740
+#define ID_SC36_GAL_LOOK2 16741
+#define ID_SC37_FAST_LIST 16584
+#define ID_SC37_CHIP_LIST 16585
+#define ID_SC37_LOGIC_LIST 16586
+#define ID_SC37_MOUSE_LIST 16587
+#define ID_SC37_PALETTE 16588
+#define ID_SC37_WALK_GRID 16589
+#define ID_RESET_36_37 16590
+#define ID_SC37_FLOOR 16591
+#define ID_SC37_HOLDING_LID 16794
+#define ID_SC37_DOOR 16592
+#define ID_SC37_DOOROPEN 16790
+#define ID_SC37_DOORSHUT 16791
+#define ID_SC37_SENSOR 16595
+#define ID_SC37_BIG_BOX 16620
+#define ID_SC37_FLIMSY_BOX 16619
+#define ID_SC37_WINE_RACK 16799
+#define ID_SC37_LID 16621
+#define ID_SC37_LIDUP 16786
+#define ID_SC37_LIDDOWN 16787
+#define ID_SC37_LIDUSED 16788
+#define ID_SC37_GRILL 16617
+#define ID_SC37_GRILLOPEN 16789
+#define ID_SC37_CRBARBOX 16775
+#define ID_SC37_GETLID 16776
+#define ID_SC37_PUTLID 16777
+#define ID_SC37_USELID 16778
+#define ID_SC37_STEPUP 16779
+#define ID_SC37_FOOTDROP 16780
+#define ID_SC37_STEPDOWN 16781
+#define ID_SC37_USEBAR 16782
+#define ID_SC37_USESEC 16783
+#define ID_SC37_CLIMBOUT 16784
+#define ID_SC37_THUMBSUP 16785
+#define ID_SC38_FAST_LIST 16443
+#define ID_SC38_CHIP_LIST 16444
+#define ID_SC38_LOGIC_LIST 16445
+#define ID_SC38_MOUSE_LIST 16446
+#define ID_SC38_PALETTE 16447
+#define ID_SC38_WALK_GRID 16448
+#define ID_RESET_32_38 16449
+#define ID_RESET_SPUNKY_38 16616
+#define ID_RESET_DANI_SIT 16608
+#define ID_RESET_DANI_STAND 16609
+#define ID_RESET_DANI_32 16629
+#define ID_RESET_SPUNKY_32 16630
+#define ID_SC38_FLOOR 16450
+#define ID_SC38_LIFT 16451
+#define ID_SC38_LIFT_UP 16542
+#define ID_SC38_LIFT_DOWN 16543
+#define ID_SC38_STATUE 16505
+#define ID_SC38_MONITOR 16506
+#define ID_SC38_VIDEO 16507
+#define ID_SC38_SOFA 16508
+#define ID_SC38_DOG_TRAY 16615
+#define ID_SC38_BISCUITS 16618
+#define ID_SC38_HAND_SET 16610
+#define ID_SC38_RINGER 16611
+#define ID_SC38_RINGER_ANIM 16612
+#define ID_DANIELLE 16441
+#define ID_DANI_CONV 16603
+#define ID_SC38_DANI_ANIM_1 16395
+#define ID_SC38_DANI_ANIM_2 16488
+#define ID_SC38_DANI_ANIM_3 16500
+#define ID_SC38_DANI_GET_UP 16605
+#define ID_SC38_DANI_SATTLK 16604
+#define ID_SC38_GET_PHONE 16613
+#define ID_SC38_PHONE_TALK 16614
+#define ID_SPUNKY 16486
+#define ID_SNIFF_LEFT 16509
+#define ID_SNIFF_RIGHT 16510
+#define ID_PISS_LEFT 16511
+#define ID_PISS_RIGHT 16512
+#define ID_BARK 16637
+#define ID_SC38_USE_VIDEO 16631
+#define ID_SC38_VIDEO_ANIM 16632
+#define ID_SC38_SCREEN_1 16633
+#define ID_SC38_SCREEN_2 16634
+#define ID_SC38_SCREEN_3 16635
+#define ID_SC38_SCREEN_4 16636
+#define ID_SC38_REACH_FOOD 16638
+#define ID_SC38_GET_FOOD 16639
+#define ID_SC39_FAST_LIST 16454
+#define ID_SC39_CHIP_LIST 16455
+#define ID_SC39_LOGIC_LIST 16456
+#define ID_SC39_MOUSE_LIST 16457
+#define ID_SC39_PALETTE 16458
+#define ID_SC39_WALK_GRID 16459
+#define ID_RESET_31_39 16460
+#define ID_RESET_40_39 16475
+#define ID_RESET_41_39 16485
+#define ID_SC39_FLOOR 16461
+#define ID_SC39_EXIT_31 16462
+#define ID_SC39_EXIT_40 16464
+#define ID_SC39_EXIT_41 16465
+#define ID_SC40_FAST_LIST 16466
+#define ID_SC40_CHIP_LIST 16467
+#define ID_SC40_LOGIC_LIST 16468
+#define ID_SC40_MOUSE_LIST 16469
+#define ID_SC40_PALETTE 16470
+#define ID_SC40_WALK_GRID 16471
+#define ID_RESET_39_40 16472
+#define ID_SC40_FLOOR 16473
+#define ID_SC40_EXIT_39 16474
+#define ID_SC40_CABINET 16567
+#define ID_SC40_TROLLEY 16568
+#define ID_SC40_LOCKER_1 16569
+#define ID_SC40_LOCKER_2 16570
+#define ID_SC40_LOCKER_3 16571
+#define ID_SC40_LOCKER_4 16572
+#define ID_SC40_LOCKER_5 16573
+#define ID_SC40_LOCKER_OPEN 16574
+#define ID_SC40_LOCKER_SHUT 16575
+#define ID_SC40_BODY_1 16576
+#define ID_SC40_BODY_2 16577
+#define ID_SC40_BODY_3 16578
+#define ID_SC40_BODY_4 16579
+#define ID_SC40_BODY_5 16580
+#define ID_SC40_OPEN_DOOR 16581
+#define ID_SC40_CLOSE_DOOR 16582
+#define ID_SC41_FAST_LIST 16476
+#define ID_SC41_CHIP_LIST 16477
+#define ID_SC41_LOGIC_LIST 16478
+#define ID_SC41_MOUSE_LIST 16479
+#define ID_SC41_PALETTE 16480
+#define ID_SC41_WALK_GRID 16481
+#define ID_RESET_39_41 16482
+#define ID_SC41_FLOOR 16483
+#define ID_SC41_EXIT_39 16484
+#define ID_SC42_FAST_LIST 16802
+#define ID_SC42_CHIP_LIST 16803
+#define ID_SC42_LOGIC_LIST 16804
+#define ID_SC42_MOUSE_LIST 16805
+#define ID_SC42_PALETTE 16806
+#define ID_SC42_WALK_GRID 16807
+#define ID_RESET_30_42 16808
+#define ID_SC44_FAST_LIST 16640
+#define ID_SC44_CHIP_LIST 16641
+#define ID_SC44_LOGIC_LIST 16642
+#define ID_SC44_MOUSE_LIST 16643
+#define ID_SC44_PALETTE 16644
+#define ID_SC44_WALK_GRID 16645
+#define ID_RESET_37_44 16646
+#define ID_RESET_45_44 16647
+#define ID_SC44_FLOOR 16648
+#define ID_SC44_EXIT_45 16649
+#define ID_SC44_GRILL 16795
+#define ID_SC44_RUBBLE 16800
+#define ID_SC45_FAST_LIST 16650
+#define ID_SC45_CHIP_LIST 16651
+#define ID_SC45_LOGIC_LIST 16652
+#define ID_SC45_MOUSE_LIST 16653
+#define ID_SC45_PALETTE 16654
+#define ID_SC45_WALK_GRID 16655
+#define ID_RESET_44_45 16656
+#define ID_RESET_46_45 16657
+#define ID_RESET_47_45 16658
+#define ID_SC45_FLOOR 16659
+#define ID_SC45_EXIT_44 16660
+#define ID_SC45_EXIT_46 16661
+#define ID_SC45_EXIT_47 16662
+#define ID_SC46_FAST_LIST 16663
+#define ID_SC46_CHIP_LIST 16664
+#define ID_SC46_LOGIC_LIST 16665
+#define ID_SC46_MOUSE_LIST 16666
+#define ID_SC46_PALETTE 16667
+#define ID_SC46_WALK_GRID 16668
+#define ID_RESET_45_46 16669
+#define ID_SC46_FLOOR 16670
+#define ID_SC46_EXIT_45 16671
+#define ID_SC46_RUBBLE 16801
+#define ID_SC47_FAST_LIST 16672
+#define ID_SC47_CHIP_LIST 16673
+#define ID_SC47_LOGIC_LIST 16674
+#define ID_SC47_MOUSE_LIST 16675
+#define ID_SC47_PALETTE 16676
+#define ID_SC47_WALK_GRID 16677
+#define ID_RESET_45_47 16678
+#define ID_RESET_48_47 16679
+#define ID_SC47_FLOOR 16680
+#define ID_SC47_EXIT_45 16681
+#define ID_SC47_EXIT_48 16682
+#define ID_SC48_FAST_LIST 16710
+#define ID_SC48_CHIP_LIST 16711
+#define ID_SC48_LOGIC_LIST 16712
+#define ID_SC48_MOUSE_LIST 16713
+#define ID_SC48_PALETTE 16714
+#define ID_SC48_WALK_GRID 16715
+#define ID_RESET_47_48 16716
+#define ID_RESET_65_48 16717
+#define ID_SC48_FLOOR 16718
+#define ID_SC48_EXIT_47 16719
+#define ID_SC48_EXIT_65 16720
+#define ID_SC65_FAST_LIST 16721
+#define ID_SC65_CHIP_LIST 16722
+#define ID_SC65_LOGIC_LIST 16723
+#define ID_SC65_MOUSE_LIST 16724
+#define ID_SC65_PALETTE 16725
+#define ID_SC65_WALK_GRID 16726
+#define ID_RESET_48_65 16727
+#define ID_SC65_FLOOR 16728
+#define ID_SC65_EXIT_48 16729
+#define ID_SC65_EXIT_66 16730
+#define ID_SC65_POSTER1 16796
+#define ID_SC65_POSTER2 16797
+#define ID_SC65_SIGN 16798
+#define IT_SC30_LAYER_0 14
+#define IT_SC30_LAYER_1 15
+#define IT_SC30_LAYER_2 16
+#define IT_SC30_GRID_1 17
+#define IT_SC30_GRID_2 18
+#define IT_SC30_HENRI_TALK 87
+#define IT_SC30_HENRI_TIE 88
+#define IT_SC30_HENRI_STEP 89
+#define IT_SC30_HENRI_BLINK 90
+#define IT_SC30_COURT_DOOR 134
+#define IT_SC30_PUSH_DOOR 91
+#define IT_SC31_LAYER_0 20
+#define IT_SC31_LAYER_1 21
+#define IT_SC31_GRID_1 22
+#define IT_SC31_LIFT 86
+#define IT_SC31_USE_CARD 92
+#define IT_SC31_PULL_ROPE 31
+#define IT_SC31_HOLD_ROPE 108
+#define IT_SC31_LOWER_ROPE 32
+#define IT_SC31_DROP_ROPE 43
+#define IT_SC31_PLANK 44
+#define IT_SC31_BRICK_UP 45
+#define IT_SC31_BRICK_FALL 46
+#define IT_SC31_END_OF_ROPE 61
+#define IT_SC31_ROPE_PULLED 62
+#define IT_SC31_ROPE_LOWER 63
+#define IT_SC31_ROPE_DROP 64
+#define IT_SC31_GUARD_TALK 101
+#define IT_SC31_GUARD_BLINK 110
+#define IT_SC31_GUARD_MOVE 129
+#define IT_SC31_GUARD_REACH 130
+#define IT_SC31_GUARD_TALK2 131
+#define IT_SC31_GET_BRICKS 102
+#define IT_SC31_GET_PLANK 106
+#define IT_SC31_CLIMB_PLANK 103
+#define IT_SC31_DOG_FLY 104
+#define IT_SC31_DOG_RISE 132
+#define IT_SC31_DOG_SWIM 133
+#define IT_SC31_PUT_BISC 109
+#define IT_SC31_HAND 107
+#define IT_SC31_BISCUITS 105
+#define IT_SC32_LAYER_0 23
+#define IT_SC32_LAYER_1 24
+#define IT_SC32_LAYER_2 98
+#define IT_SC32_GRID_1 25
+#define IT_SC32_GRID_2 99
+#define IT_SC32_USE_CARD 93
+#define IT_SC32_USE_COM 94
+#define IT_SC32_LIFT 100
+#define IT_SC32_VINCENT 56
+#define IT_SC32_VINC_TALK 57
+#define IT_SC32_GARDENER 58
+#define IT_SC32_GARD_TURN 59
+#define IT_SC32_GARDEN_TALK 60
+#define IT_SC33_LAYER_0 26
+#define IT_SC33_LAYER_1 27
+#define IT_SC33_LAYER_2 28
+#define IT_SC33_GRID_1 29
+#define IT_SC33_GRID_2 30
+#define IT_SC33_USE_CARD 95
+#define IT_SC33_PUSH_DOOR 96
+#define IT_SC33_SHED_DOOR 97
+#define IT_SC34_LAYER_0 31
+#define IT_SC34_LAYER_1 32
+#define IT_SC34_GRID_1 43
+#define IT_SC34_STAIRS1 102
+#define IT_SC34_STAIRS2 103
+#define IT_SC34_SECATEURS 104
+#define IT_SC34_GET_SECS 105
+#define IT_SC36_LAYER_0 20
+#define IT_SC36_LAYER_1 21
+#define IT_SC36_LAYER_2 22
+#define IT_SC36_LAYER_3 56
+#define IT_SC36_GRID_1 23
+#define IT_SC36_GRID_2 24
+#define IT_SC36_GRID_3 57
+#define IT_SC36_BABS 106
+#define IT_SC36_BABS_TALK 107
+#define IT_SC36_FOS_DOWN1 92
+#define IT_SC36_FOS_DOWN2 93
+#define IT_SC36_FOS_UP1 94
+#define IT_SC36_FOS_UP2 95
+#define IT_SC36_PRESS_PLATE 70
+#define IT_SC36_USE_JUKEBOX 67
+#define IT_SC36_GET_GLASS 96
+#define IT_SC36_JUKE_LIGHT 68
+#define IT_SC36_JUKEBOX 86
+#define IT_SC36_GLASS 66
+#define IT_SC36_BAND 31
+#define IT_SC36_BARMAN 32
+#define IT_BARMAN_TALK 61
+#define IT_SC36_COLSTON 47
+#define IT_SC36_COL_FEET 48
+#define IT_SC36_COL_TALK1 62
+#define IT_SC36_COL_TALK2 63
+#define IT_SC36_COL_DRINK 69
+#define IT_SC36_COL_DOWN1 97
+#define IT_SC36_COL_DOWN2 98
+#define IT_SC36_COL_DOWN3 99
+#define IT_SC36_COL_DOWN4 100
+#define IT_SC36_COL_UP1 101
+#define IT_SC36_COL_UP2 102
+#define IT_SC36_COL_UP3 103
+#define IT_SC36_COL_UP4 104
+#define IT_SC36_COL_KICK 105
+#define IT_SC36_GALLAGHER 58
+#define IT_SC36_GAL_LEGS 59
+#define IT_SC36_GAL_TALK 64
+#define IT_SC36_CARDS 60
+#define IT_SC36_DOOR 144
+#define IT_SC37_LAYER_0 14
+#define IT_SC37_LAYER_1 15
+#define IT_SC37_LAYER_2 16
+#define IT_SC37_GRID_1 17
+#define IT_SC37_GRID_2 18
+#define IT_SC37_CRBARBOX 108
+#define IT_SC37_GETLID 109
+#define IT_SC37_USELID 110
+#define IT_SC37_STEPUP 129
+#define IT_SC37_FOOTDROP 130
+#define IT_SC37_STEPDOWN 131
+#define IT_SC37_USEBAR 132
+#define IT_SC37_USESEC 133
+#define IT_SC37_CLIMBOUT 134
+#define IT_SC37_THUMBSUP 136
+#define IT_SC37_BOXLID 137
+#define IT_SC37_LIDUP 138
+#define IT_SC37_LIDUSED 139
+#define IT_SC37_LOOSEBIT 140
+#define IT_SC37_GRILL 141
+#define IT_SC37_GRILLOPEN 142
+#define IT_SC37_DOOR 143
+#define IT_SC38_LAYER_0 44
+#define IT_SC38_LAYER_1 45
+#define IT_SC38_LAYER_2 46
+#define IT_SC38_GRID_1 47
+#define IT_SC38_GRID_2 48
+#define IT_DANIELLE 55
+#define IT_DANI_CONV 85
+#define IT_SPUNKY 71
+#define IT_SC38_SEXY_DANI 106
+#define IT_SC38_DANI_ANIMS 107
+#define IT_SC38_DANI_SATTLK 108
+#define IT_SC38_DANI_GET_UP 109
+#define IT_SNIFF_LEFT 72
+#define IT_SNIFF_RIGHT 74
+#define IT_PISS_LEFT 75
+#define IT_PISS_RIGHT 76
+#define IT_BARK 65
+#define IT_SC38_FOSTER_LIFT 101
+#define IT_SC38_HAND_SET 110
+#define IT_SC38_RINGER 129
+#define IT_SC38_GET_PHONE 130
+#define IT_SC38_PHONE_TALK 131
+#define IT_SC38_USE_VIDEO 132
+#define IT_SC38_VIDEO_ANIM 133
+#define IT_SC38_SCREEN_1 134
+#define IT_SC38_SCREEN_2 136
+#define IT_SC38_SCREEN_3 137
+#define IT_SC38_SCREEN_4 138
+#define IT_SC38_GET_FOOD 139
+#define IT_SC39_LAYER_0 56
+#define IT_SC39_LAYER_1 57
+#define IT_SC39_LAYER_2 58
+#define IT_SC39_GRID_1 59
+#define IT_SC39_GRID_2 60
+#define IT_SC40_LAYER_0 61
+#define IT_SC40_LAYER_1 62
+#define IT_SC40_LAYER_2 63
+#define IT_SC40_GRID_1 64
+#define IT_SC40_GRID_2 65
+#define IT_SC40_LOCKER 14
+#define IT_SC40_OPEN_DOOR 15
+#define IT_SC40_CLOSE_DOOR 16
+#define IT_SC41_LAYER_0 66
+#define IT_SC41_LAYER_1 67
+#define IT_SC41_LAYER_2 68
+#define IT_SC41_GRID_1 69
+#define IT_SC41_GRID_2 70
+#define IT_SC42_LAYER_0 20
+#define IT_SC42_LAYER_1 21
+#define IT_SC42_GRID_1 23
+#define IT_SC44_LAYER_0 25
+#define IT_SC45_LAYER_0 26
+#define IT_SC45_LAYER_1 27
+#define IT_SC45_GRID_1 28
+#define IT_SC46_LAYER_0 29
+#define IT_SC47_LAYER_0 30
+#define IT_SC48_LAYER_0 43
+#define IT_SC65_LAYER_0 44
+#define IT_SC65_LAYER_1 45
+#define IT_SC65_GRID_1 46
+#define ID_RADMAN 8205
+#define ID_FACT3_R_EXIT 8459
+#define ID_LOCKER3 8460
+#define ID_LOCKER2 8463
+#define ID_LOCKER1 8464
+#define ID_MACHINE 8467
+#define ID_STUMP 8468
+#define ID_S16_FLOOR 8473
+#define ID_ENTRANCE_EXIT 8478
+#define ID_REACTOR_PC 8480
+#define ID_REACTOR_DOOR 8481
+#define ID_RAD_SCREEN 8482
+#define ID_14_CONSOLE 8483
+#define ID_COAT 8484
+#define ID_SENSORS 8500
+#define ID_REACTOR_LOWER 8502
+#define ID_S17_FLOOR 8507
+#define ID_CORE_EXIT 8511
+#define ID_PULSE 8513
+#define ID_PULSEB 8515
+#define ID_ANITA_CARD 8517
+#define ID_CONSOLE_12 8524
+#define ID_JUNK1 4339
+#define ID_JUNK2 4340
+#define ID_LIFT7_LIGHT 8529
+#define ID_S29_FLOOR 12292
+#define ID_LIFT_29 12296
+#define ID_S29_CARD_SLOT 12299
+#define ID_LIFT29_LIGHT 12301
+#define ID_RIGHT_EXIT_29 12304
+#define ID_S23_FLOOR 12309
+#define ID_LEFT_EXIT_23 12313
+#define ID_ANCHOR_EXIT_23 12315
+#define ID_S25_FLOOR 12320
+#define ID_ANCHOR_EXIT_25 12324
+#define ID_TRAVEL_EXIT_23 12327
+#define ID_S24_FLOOR 12332
+#define ID_LEFT_EXIT_24 12336
+#define ID_LEFT_EXIT_29 12338
+#define ID_S28_FLOOR 12343
+#define ID_RIGHT_EXIT_28 12347
+#define ID_LEFT_EXIT_28 12349
+#define ID_S19_FLOOR 12354
+#define ID_RIGHT_EXIT_19 12358
+#define ID_LEFT_EXIT_19 12361
+#define ID_S26_FLOOR 12366
+#define ID_RIGHT_EXIT_26 12370
+#define ID_DUSTBIN_28 12372
+#define ID_POSTER1 12375
+#define ID_POSTER2 12376
+#define ID_POSTER3 12377
+#define ID_POSTER4 12378
+#define ID_26_PLANT 12379
+#define ID_LEAFLET 12380
+#define ID_HOLO 12381
+#define ID_BIN_23 12382
+#define ID_SCULPTURE 12383
+#define ID_LINK_23 12384
+#define ID_WRECK_23 12385
+#define ID_LONDON_POSTER 12386
+#define ID_NEW_YORK 12387
+#define ID_MURAL 12388
+#define ID_PIDGEONS 12405
+#define ID_LEFT_EXIT_26 12390
+#define ID_S27_FLOOR 12395
+#define ID_RIGHT_EXIT_27 12399
+#define ID_CHART1 12401
+#define ID_CHART2 12402
+#define ID_GAS 12403
+#define ID_SCANNER_27 12404
+#define ID_BURKE 12407
+#define ID_MEDI_COMP 12425
+#define ID_CHAIR_27 12417
+#define ID_HELMET_COLE 12420
+#define ID_BODY 12429
+#define ID_ANCHOR 12430
+#define ID_ANCHOR_PC 3
+#define ID_HOOK 12434
+#define ID_STATUE_25 12435
+#define ID_LAZER_25 12437
+#define ID_SPARK_25 12439
+#define ID_TREVOR 12442
+#define ID_UP_EXIT_28 12447
+#define ID_S20_FLOOR 12452
+#define ID_DOWN_EXIT_20 12456
+#define ID_REICH_DOOR_20 12459
+#define ID_REICH_SLOT 12462
+#define ID_S22_FLOOR 12467
+#define ID_RIGHT_EXIT_22 12471
+#define ID_LAMB_DOOR_20 12474
+#define ID_LAMB_SLOT 12477
+#define ID_S21_FLOOR 12482
+#define ID_LEFT_EXIT_21 12486
+#define ID_SHRUB_1 12488
+#define ID_SHRUB_2 12489
+#define ID_SHRUB_3 12490
+#define ID_LAMB_BED 12492
+#define ID_LAMB_TV 12493
+#define ID_FISH_TANK 12494
+#define ID_FISH_POSTER 12495
+#define ID_PILLOW 12496
+#define ID_MAGAZINE 12501
+#define ID_REICH_CHAIR 12505
+#define ID_CABINET 12506
+#define ID_CERT 12507
+#define ID_REICH_PICTURE 12508
+#define ID_FISH_FOOD 12509
+#define ID_LAMBS_BOOKS 12510
+#define ID_LAMBS_CHAIR 12511
+#define ID_DISPENSOR 12512
+#define ID_CATFOOD 12514
+#define ID_VIDEO 12516
+#define ID_CASSETTE 12517
+#define ID_BIG_PICT1 12524
+#define ID_VIDEO_SCREEN 12525
+#define ID_BIG_PICT2 12526
+#define ID_BIG_PICT3 12527
+#define ID_CAT 12534
+#define ID_BIO_DOOR 12541
+#define ID_SALES_CHART 12545
+#define ID_GALLAGER_BEL 12546
+#define ID_FAKE_FLOOR_22 12554
+#define ID_REICH_WINDOW 12555
+#define ID_LAMB_WINDOW 12556
+#define ID_FAKE_FLOOR_21 12557
+#define ID_INNER_LAMB_DOOR 12558
+#define ID_TICKET 12565
+#define ID_GLOBE 12568
+#define ID_INNER_R_DOOR 12571
+#define ID_GLASS_SLOT 12574
+#define ID_LIFT_WAIT 42
+#define ID_CABLE_7 8204
+#define ID_CABLE_29 12588
+#define ID_S11_FLOOR 12594
+#define ID_CABLE_FALL 12601
+#define ID_CABLE_FALL2 12604
+#define ID_SMASHED_WINDOW 12605
+#define ID_BITS 12607
+#define ID_BITS2 12609
+#define ID_LOCKER_11 12613
+#define ID_SPY_11 12612
+#define ID_SLOT_11 12616
+#define ID_SOCCER_1 12620
+#define ID_SOCCER_2 12621
+#define ID_SOCCER_3 12622
+#define ID_SOCCER_4 12623
+#define ID_SOCCER_5 12624
+#define ID_SLAT_1 12626
+#define ID_SLAT_2 12627
+#define ID_SLAT_3 12628
+#define ID_SLAT_4 12629
+#define ID_SLAT_5 12630
+#define ID_RIGHT_EXIT_11 12631
+#define ID_S10_FLOOR 12636
+#define ID_LEFT_EXIT_10 12641
+#define ID_LIFT_10 12642
+#define ID_LIFT_SLOT_10 12644
+#define ID_SCANNER_10 12647
+#define ID_POD 12648
+#define ID_LINC_10 12651
+#define ID_POD_LIGHT 12652
+#define ID_MONITOR_10 12657
+#define ID_LIYT_1 12659
+#define ID_LIYT_2 12661
+#define ID_LIYT_3 12663
+#define ID_LIYT_4 12665
+#define ID_LITEBANK 12667
+#define ID_TERMINAL_10 12670
+#define ID_FAKE_FLOOR_9 8536
+#define ID_FAKE_FLOOR_10 12672
+#define ID_LINC_S9 8543
+#define ID_SMALL_23 12676
+#define ID_SMALL_R_29 12677
+#define ID_SMALL_L_29 12678
+#define ID_SMALL_R_28 12679
+#define ID_SMALL_L_28 12680
+#define ID_SMALL_19 12681
+#define ID_S29_SML_FLOOR 12682
+#define ID_S28_SML_FLOOR 12686
+#define ID_LIFT_28 12694
+#define ID_SLOT_28 12697
+#define ID_COPTER 8209
+#define ID_SC48_SOCKET 16815
+#define ID_SC48_HOLE 16816
+#define ID_SC48_EYES 16817
+#define ID_SC48_LIGHT_PAL 16820
+#define ID_SC42_JUDGE 16821
+#define ID_SC42_CLERK 16822
+#define ID_SC42_PROSECUTION 16823
+#define ID_SC42_JOBSWORTH 16824
+#define ID_SC42_SIGN 16849
+#define ID_DOG_BARK_THING 16855
+#define ID_SC41_HEAT_1 16856
+#define ID_SC41_HEAT_2 16857
+#define ID_SC41_HEAT_3 16858
+#define ID_FIRE1 4360
+#define ID_FIRE2 4362
+#define ID_CAR_UP 4364
+#define ID_CAR_DOWN 4366
+#define C_LOGIC 0
+#define C_STATUS 2
+#define C_SYNC 4
+#define C_SCREEN 6
+#define C_PLACE 8
+#define C_GET_TO_TABLE 10
+#define C_XCOOD 14
+#define C_YCOOD 16
+#define C_FRAME 18
+#define C_CURSOR_TEXT 20
+#define C_MOUSE_ON 22
+#define C_MOUSE_OFF 24
+#define C_MOUSE_CLICK 26
+#define C_MOUSE_REL_X 28
+#define C_MOUSE_REL_Y 30
+#define C_MOUSE_SIZE_X 32
+#define C_MOUSE_SIZE_Y 34
+#define C_ACTION_SCRIPT 36
+#define C_UP_FLAG 38
+#define C_DOWN_FLAG 40
+#define C_GET_TO_FLAG 42
+#define C_FLAG 44
+#define C_MOOD 46
+#define C_GRAFIX_PROG 48
+#define C_OFFSET 52
+#define C_MODE 54
+#define C_BASE_SUB 56
+#define C_ACTION_SUB 60
+#define C_GET_TO_SUB 64
+#define C_EXTRA_SUB 68
+#define C_DIR 72
+#define C_STOP_SCRIPT 74
+#define C_MINI_BUMP 76
+#define C_LEAVING 78
+#define C_AT_WATCH 80
+#define C_AT_WAS 82
+#define C_ALT 84
+#define C_REQUEST 86
+
+//system flags
+#define SF_TIMER (1 << 0) // set if timer interrupt redirected
+#define SF_GRAPHICS (1 << 1) // set if screen is in graphics mode
+#define SF_MOUSE (1 << 2) // set if mouse handler installed
+#define SF_KEYBOARD (1 << 3) // set if keyboard interrupt redirected
+#define SF_MUSIC_BOARD (1 << 4) // set if a music board detected
+#define SF_ROLAND (1 << 5) // set if roland board present
+#define SF_ADLIB (1 << 6) // set if adlib board present
+#define SF_SBLASTER (1 << 7) // set if sblaster present
+#define SF_TANDY (1 << 8) // set if tandy present
+#define SF_MUSIC_BIN (1 << 9) // set if music driver is loaded
+#define SF_PLUS_FX (1 << 10) // set if extra fx module needed
+#define SF_FX_OFF (1 << 11) // set if fx disabled
+#define SF_MUS_OFF (1 << 12) // set if music disabled
+#define SF_TIMER_TICK (1 << 13) // set every timer interupt
+
+// Status flags
+#define SF_CHOOSING (1 << 14) // set when choosing text
+#define SF_NO_SCROLL (1 << 15) // when set don't scroll
+#define SF_SPEED (1 << 16) // when set allow speed options
+#define SF_GAME_RESTORED (1 << 17) // set when game restored or restarted
+#define SF_REPLAY_RST (1 << 18) // set when loading restart data (used to stop rewriting of replay file)
+#define SF_SPEECH_FILE (1 << 19) // set when loading speech file
+#define SF_VOC_PLAYING (1 << 20) // set when a voc file is playing
+#define SF_PLAY_VOCS (1 << 21) // set when we want speech instead of text
+#define SF_CRIT_ERR (1 << 22) // set when critical error routine trapped
+#define SF_ALLOW_SPEECH (1 << 23) // speech allowes on cd sblaster version
+#define SF_ALLOW_TEXT (1 << 24) // text allowed on cd sblaster version
+#define SF_ALLOW_QUICK (1 << 25) // when set allow speed playing
+#define SF_TEST_DISK (1 << 26) // set when loading files
+#define SF_MOUSE_LOCKED (1 << 27) // set if coordinates are locked
+
+// Mouse flags
+#define MF_NO_UPDATE (1 << 0) // set to disable mouse updating
+#define MF_IN_INT (1 << 1) // set when in mouse interrupt
+#define MF_SAVED (1 << 2) // set when saved data is valid
+#define MF_GOT_INT (1 << 3) // set when mouse interrupt received
+
+#define MOUSE_NORMAL 1 // normal mouse
+#define MOUSE_DISK 2 // disk mouse
+#define MOUSE_DOWN 3
+#define MOUSE_RIGHT 4 // right pointer
+#define MOUSE_LEFT 5 // left pointer
+#define MOUSE_BLANK 6 // blank mouse
+#define MOUSE_CROSS 7 // angry mouse
+#define MOUSE_UP 8 // mouse up
+
+#define TEXT_MOUSE_WIDTH 0x80
+
+} // End of namespace Sky
+
+#endif
diff --git a/engines/sky/sound.cpp b/engines/sky/sound.cpp
new file mode 100644
index 0000000000..0cd015d49d
--- /dev/null
+++ b/engines/sky/sound.cpp
@@ -0,0 +1,1259 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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 "sky/disk.h"
+#include "sky/logic.h"
+#include "sky/sky.h"
+#include "sky/skydefs.h"
+#include "sky/sound.h"
+#include "sky/struc.h"
+
+namespace Sky {
+
+#define SOUND_FILE_BASE 60203
+#define MAX_FX_NUMBER 393
+#define SFXF_START_DELAY 0x80
+#define SFXF_SAVE 0x20
+
+#if !defined(__GNUC__)
+#pragma START_PACK_STRUCTS
+#endif
+
+struct RoomList {
+ uint8 room;
+ uint8 adlibVolume;
+ uint8 rolandVolume;
+} GCC_PACK;
+
+struct Sfx {
+ uint8 soundNo;
+ uint8 flags;
+ RoomList roomList[10];
+} GCC_PACK;
+
+#if !defined(__GNUC__)
+#pragma END_PACK_STRUCTS
+#endif
+
+uint16 Sound::_speechConvertTable[8] = {
+ 0, //;Text numbers to file numbers
+ 600, //; 553 lines in section 0
+ 600+500, //; 488 lines in section 1
+ 600+500+1330, //;1303 lines in section 2
+ 600+500+1330+950, //; 922 lines in section 3
+ 600+500+1330+950+1150, //;1140 lines in section 4
+ 600+500+1330+950+1150+550, //; 531 lines in section 5
+ 600+500+1330+950+1150+550+150, //; 150 lines in section 6
+};
+
+
+static Sfx fx_null = {
+ 0,
+ 0,
+ {
+ { 200,127,127 },
+ { 255,0,0 }
+ }
+};
+
+static Sfx fx_level_3_ping = {
+ 1,
+ 0,
+ {
+ { 28,63,63 },
+ { 29,63,63 },
+ { 31,63,63 },
+ { 255,0,0 },
+ }
+};
+
+static Sfx fx_factory_sound = {
+ 1,
+ SFXF_SAVE,
+ {
+ { 255,30,30 },
+ }
+};
+
+static Sfx fx_crowbar_plaster = {
+ 1,
+ 0,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_masonry_fall = {
+ 1,
+ 0,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_prise_brick = {
+ 2,
+ 0,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_rope_creak = {
+ 2,
+ 0,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_ping = {
+ 3,
+ 0,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_force_fire_door = {
+ 3,
+ 0,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_brick_hit_foster = {
+ 3,
+ 10+SFXF_START_DELAY,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_brick_hit_plank = {
+ 3,
+ 8+SFXF_START_DELAY,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_rm3_lift_moving = {
+ 4,
+ SFXF_SAVE,
+ {
+ { 3,127,127 },
+ { 2,127,127 },
+ { 255,0,0 },
+ }
+};
+
+static Sfx fx_weld = {
+ 4,
+ 0,
+ {
+ { 15,127,127 },
+ { 7,127,127 },
+ { 6,60,60 },
+ { 12,60,60 },
+ { 13,60,60 },
+ { 255,0,0 },
+ }
+};
+
+static Sfx fx_weld12 = {
+ 4,
+ 0,
+ {
+ { 12,127,127 },
+ { 255,0,0 },
+ }
+};
+
+static Sfx fx_spray_on_skin = {
+ 4,
+ 0,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_plank_vibrating = {
+ 4,
+ 6+SFXF_START_DELAY,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_press_bang = {
+ 5,
+ 0,
+ {
+ { 0,50,100 },
+ { 255,0,0 },
+ }
+};
+
+static Sfx fx_spanner_clunk = {
+ 5,
+ 0,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_break_crystals = {
+ 5,
+ 0,
+ {
+ { 96,127,127 },
+ { 255,0,0 },
+ }
+};
+
+static Sfx fx_press_hiss = {
+ 6,
+ 0,
+ {
+ { 0,40,40 },
+ { 255,0,0 },
+ }
+};
+
+static Sfx fx_open_door = {
+ 6,
+ 0,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_open_lamb_door = {
+ 6,
+ 0,
+ {
+ { 20,127,127 },
+ { 21,127,127 },
+ { 255,0,0 },
+ }
+};
+
+static Sfx fx_splash = {
+ 6,
+ 22+SFXF_START_DELAY,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_disintegrate = {
+ 7,
+ 0,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_buzzer = {
+ 7,
+ 4+SFXF_START_DELAY,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_lathe = {
+ 7,
+ SFXF_SAVE,
+ {
+ { 4,60,60 },
+ { 2,20,20 },
+ { 255,0,0 },
+ }
+};
+
+static Sfx fx_hit_crowbar_brick = {
+ 7,
+ 9+SFXF_START_DELAY,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_hello_helga = {
+ 8,
+ 0,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_statue_on_armour = {
+ 8,
+ 0,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_lift_alarm = {
+ 8,
+ SFXF_SAVE,
+ {
+ { 2,63,63 },
+ { 255,0,0 },
+ }
+};
+
+static Sfx fx_drop_crowbar = {
+ 8,
+ 5+SFXF_START_DELAY,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_byee_helga = {
+ 9,
+ 3+SFXF_START_DELAY,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_shed_door_creak = {
+ 10,
+ 0,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_explosion = {
+ 10,
+ 0,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_fire_crackle_in_pit = {
+ 9,
+ SFXF_SAVE,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_remove_bar_grill = {
+ 10,
+ 7+SFXF_START_DELAY,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_grill_creak = {
+ 10,
+ 43+SFXF_START_DELAY,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_steam1 = {
+ 11,
+ SFXF_SAVE,
+ {
+ { 18,20,20 },
+ { 255,0,0 },
+ }
+};
+
+static Sfx fx_steam2 = {
+ 11,
+ SFXF_SAVE,
+ {
+ { 18,63,63 },
+ { 255,0,0 },
+ }
+};
+
+static Sfx fx_steam3 = {
+ 11,
+ SFXF_SAVE,
+ {
+ { 18,127,127 },
+ { 255,0,0 },
+ }
+};
+
+static Sfx fx_crowbar_wooden = {
+ 11,
+ 0,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_helmet_down_3 = {
+ 11,
+ 0,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_guard_fall = {
+ 11,
+ 4,
+ {
+ { 255,127,127 },
+ }
+};
+
+#if 0
+static Sfx fx_furnace = {
+ 11,
+ 0,
+ {
+ { 3,90,90 },
+ { 255,0,0 },
+ }
+};
+#endif
+
+static Sfx fx_fall_thru_box = {
+ 12,
+ 0,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_lazer = {
+ 12,
+ 0,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_scanner = {
+ 12,
+ 0,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_helmet_up_3 = {
+ 12,
+ 0,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_liquid_bubble = {
+ 12,
+ SFXF_SAVE,
+ {
+ { 80,127,127 },
+ { 72,127,127 },
+ { 255,0,0 },
+ }
+};
+
+static Sfx fx_liquid_drip = {
+ 13,
+ 6+SFXF_START_DELAY,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_goo_drip = {
+ 13,
+ 5+SFXF_START_DELAY,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_comp_bleeps = {
+ 13,
+ 0,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_use_crowbar_grill = {
+ 13,
+ 34+SFXF_START_DELAY,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_helmet_grind = {
+ 14,
+ 0,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_lift_moving = {
+ 14,
+ SFXF_SAVE,
+ {
+ { 7,127,127 },
+ { 29,127,127 },
+ { 255,0,0 },
+ }
+};
+
+static Sfx fx_use_secateurs = {
+ 14,
+ 18+SFXF_START_DELAY,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_hit_joey1 = {
+ 14,
+ 7+SFXF_START_DELAY,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_hit_joey2 = {
+ 14,
+ 13+SFXF_START_DELAY,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_dani_phone_ring = {
+ 15,
+ 0,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_sc74_pod_down = {
+ 15,
+ 0,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_phone = {
+ 15,
+ 0,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_25_weld = {
+ 15,
+ 0,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_lift_open_7 = {
+ 15,
+ 0,
+ {
+ { 7,127,127 },
+ { 255,0,0 },
+ }
+};
+
+static Sfx fx_lift_close_7 = {
+ 16,
+ 0,
+ {
+ { 7,127,127 },
+ { 255,0,0 },
+ }
+};
+
+static Sfx fx_s2_helmet = {
+ 16,
+ 0,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_hiss_in_nitrogen = {
+ 16,
+ 0,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_dog_yap_indoors = {
+ 16,
+ 0,
+ {
+ { 38,127,127 },
+ { 255,0,0 },
+ }
+};
+
+static Sfx fx_dog_yap_outdoors = {
+ 16,
+ 0,
+ {
+ { 31,127,127 },
+ { 30,40,40 },
+ { 32,40,40 },
+ { 33,40,40 },
+ { 255,0,0 },
+ }
+};
+
+static Sfx fx_locker_creak_open = {
+ 17,
+ 0,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_big_tent_gurgle = {
+ 17,
+ 0,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_wind_howl = {
+ 17,
+ SFXF_SAVE,
+ {
+ { 1,127,127 },
+ { 255,0,0 },
+ }
+};
+
+static Sfx fx_lift_open_29 = {
+ 17,
+ 0,
+ {
+ { 29,127,127 },
+ { 255,0,0 },
+ }
+};
+
+static Sfx fx_lift_arrive_7 = {
+ 17,
+ 0,
+ {
+ { 7,63,63 },
+ { 255,0,0 },
+ }
+};
+
+static Sfx fx_lift_close_29 = {
+ 18,
+ 0,
+ {
+ { 29,127,127 },
+ { 28,127,127 },
+ { 255,0,0 },
+ }
+};
+
+static Sfx fx_shaft_industrial_noise = {
+ 18,
+ SFXF_SAVE,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_gall_drop = {
+ 18,
+ 29+SFXF_START_DELAY,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_door_slam_under = {
+ 19,
+ 0,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_reichs_fish = {
+ 19,
+ SFXF_SAVE,
+ {
+ { 255,60,60 },
+ }
+};
+
+static Sfx fx_judges_gavel1 = {
+ 19,
+ 13+SFXF_START_DELAY,
+ {
+ { 255,60,60 },
+ }
+};
+
+static Sfx fx_judges_gavel2 = {
+ 19,
+ 16+SFXF_START_DELAY,
+ {
+ { 255,90,90 },
+ }
+};
+
+static Sfx fx_judges_gavel3 = {
+ 19,
+ 19+SFXF_START_DELAY,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_wind_3 = {
+ 20,
+ SFXF_SAVE,
+ {
+ { 255,60,60 },
+ }
+};
+
+static Sfx fx_fact_sensor = {
+ 20,
+ SFXF_SAVE,
+ {
+ { 255,60,60 },
+ }
+};
+
+static Sfx fx_medi_stab_gall = {
+ 20,
+ 17+SFXF_START_DELAY,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_computer_3 = {
+ 21,
+ SFXF_SAVE,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_timber_cracking = {
+ 21,
+ 0,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_anchor_fall = {
+ 22,
+ 0,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_elevator_4 = {
+ 22,
+ 0,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_star_trek_2 = {
+ 22,
+ SFXF_SAVE,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_lift_closing = {
+ 23,
+ 0,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_heartbeat = {
+ 23,
+ 11+SFXF_START_DELAY,
+ {
+ { 67,60,60 },
+ { 68,60,60 },
+ { 69,60,60 },
+ { 77,20,20 },
+ { 78,50,50 },
+ { 79,70,70 },
+ { 80,127,127 },
+ { 81,60,60 },
+ { 255,0,0 },
+ }
+};
+
+static Sfx fx_pos_key = {
+ 25,
+ 2+SFXF_START_DELAY,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx fx_neg_key = {
+ 26,
+ 2+SFXF_START_DELAY,
+ {
+ { 255,100,100 },
+ }
+};
+
+static Sfx fx_orifice_swallow_drip = {
+ 28,
+ 0,
+ {
+ { 255,127,127 },
+ }
+};
+
+static Sfx *musicList[] = {
+ &fx_press_bang, // 256 banging of the press
+ &fx_press_hiss, // 257 hissing press
+ &fx_wind_howl, // 258 howling wind
+ &fx_spanner_clunk, // 259 spanner in works
+ &fx_reichs_fish, // 260 Reichs fish
+ &fx_explosion, // 261 panel blows open
+ &fx_wind_3, // 262 single steam
+ &fx_open_door, // 263 general open door
+ &fx_open_lamb_door, // 264 lamb door opens
+ &fx_comp_bleeps, // 265 scanner bleeps
+ &fx_helmet_down_3, // 266
+ &fx_helmet_up_3, // 267
+ &fx_helmet_grind, // 268
+ &fx_lift_close_29, // 269 rm 29 lift closes
+ &fx_lift_open_29, // 270 rm 29 lift opens
+ &fx_computer_3, // 271 rm 29 lift arrives
+ &fx_level_3_ping, // 272 background noise in room 4
+ &fx_lift_alarm, // 273 loader alarm
+ &fx_null, // 274 furnace room background noise
+ &fx_rm3_lift_moving, // 275 lift moving in room 3
+ &fx_lathe, // 276 jobsworth lathe
+ &fx_factory_sound, // 277 factory background sound
+ &fx_weld, // 278 do some welding
+ &fx_lift_close_7, // 279 rm 7 lift closes
+ &fx_lift_open_7, // 280 rm 7 lift opens
+ &fx_lift_arrive_7, // 281 rm 7 lift arrives
+ &fx_lift_moving, // 282 lift moving
+ &fx_scanner, // 283 scanner operating
+ &fx_force_fire_door, // 284 Force fire door open
+ &fx_null, // 285 General door creak
+ &fx_phone, // 286 telephone
+ &fx_lazer, // 287 lazer
+ &fx_lazer, // 288 lazer
+ &fx_anchor_fall, // 289 electric ;not used on amiga
+ &fx_weld12, // 290 welding in room 12 (not joey)
+ &fx_hello_helga, // 291 helga appears
+ &fx_byee_helga, // 292 helga disapears
+ &fx_null, // 293 smash through window ;doesn't exist
+ &fx_pos_key, // 294
+ &fx_neg_key, // 295
+ &fx_s2_helmet, // 296 ;helmet down section 2
+ &fx_s2_helmet, // 297 ; " up " "
+ &fx_lift_arrive_7, // 298 ;security door room 7
+ &fx_null, // 299
+ &fx_rope_creak, // 300
+ &fx_crowbar_wooden, // 301
+ &fx_fall_thru_box, // 302
+ &fx_use_crowbar_grill, // 303
+ &fx_use_secateurs, // 304
+ &fx_grill_creak, // 305
+ &fx_timber_cracking, // 306
+ &fx_masonry_fall, // 307
+ &fx_masonry_fall, // 308
+ &fx_crowbar_plaster, // 309
+ &fx_prise_brick, // 310
+ &fx_brick_hit_foster, // 311
+ &fx_spray_on_skin, // 312
+ &fx_hit_crowbar_brick, // 313
+ &fx_drop_crowbar, // 314
+ &fx_fire_crackle_in_pit, // 315
+ &fx_remove_bar_grill, // 316
+ &fx_liquid_bubble, // 317
+ &fx_liquid_drip, // 318
+ &fx_guard_fall, // 319
+ &fx_sc74_pod_down, // 320
+ &fx_hiss_in_nitrogen, // 321
+ &fx_null, // 322
+ &fx_hit_joey1, // 323
+ &fx_hit_joey2, // 324
+ &fx_medi_stab_gall, // 325
+ &fx_gall_drop, // 326
+ &fx_null, // 327
+ &fx_null, // 328
+ &fx_null, // 329
+ &fx_big_tent_gurgle, // 330
+ &fx_null, // 331
+ &fx_orifice_swallow_drip, // 332
+ &fx_brick_hit_plank, // 333
+ &fx_goo_drip, // 334
+ &fx_plank_vibrating, // 335
+ &fx_splash, // 336
+ &fx_buzzer, // 337
+ &fx_shed_door_creak, // 338
+ &fx_dog_yap_outdoors, // 339
+ &fx_dani_phone_ring, // 340
+ &fx_locker_creak_open, // 341
+ &fx_judges_gavel1, // 342
+ &fx_dog_yap_indoors, // 343
+ &fx_brick_hit_plank, // 344
+ &fx_brick_hit_plank, // 345
+ &fx_shaft_industrial_noise, // 346
+ &fx_judges_gavel2, // 347
+ &fx_judges_gavel3, // 348
+ &fx_elevator_4, // 349
+ &fx_lift_closing, // 350
+ &fx_null, // 351
+ &fx_null, // 352
+ &fx_sc74_pod_down, // 353
+ &fx_null, // 354
+ &fx_null, // 355
+ &fx_heartbeat, // 356
+ &fx_star_trek_2, // 357
+ &fx_null, // 358
+ &fx_null, // 359
+ &fx_null, // 350
+ &fx_null, // 361
+ &fx_null, // 362
+ &fx_null, // 363
+ &fx_null, // 364
+ &fx_null, // 365
+ &fx_break_crystals, // 366
+ &fx_disintegrate, // 367
+ &fx_statue_on_armour, // 368
+ &fx_null, // 369
+ &fx_null, // 360
+ &fx_ping, // 371
+ &fx_null, // 372
+ &fx_door_slam_under, // 373
+ &fx_null, // 374
+ &fx_null, // 375
+ &fx_null, // 376
+ &fx_null, // 377
+ &fx_null, // 378
+ &fx_null, // 379
+ &fx_steam1, // 380
+ &fx_steam2, // 381
+ &fx_steam2, // 382
+ &fx_steam3, // 383
+ &fx_null, // 384
+ &fx_null, // 385
+ &fx_fact_sensor, // 386 Sensor in Potts' room
+ &fx_null, // 387
+ &fx_null, // 388
+ &fx_null, // 389
+ &fx_null, // 390
+ &fx_null, // 391
+ &fx_null, // 392
+ &fx_null, // 393
+ &fx_25_weld // 394 my anchor weld bodge
+};
+
+SfxQueue Sound::_sfxQueue[MAX_QUEUED_FX] = {
+ { 0, 0, 0, 0},
+ { 0, 0, 0, 0},
+ { 0, 0, 0, 0},
+ { 0, 0, 0, 0}
+};
+
+Sound::Sound(Audio::Mixer *mixer, Disk *pDisk, uint8 pVolume) {
+ _skyDisk = pDisk;
+ _soundData = NULL;
+ _mixer = mixer;
+ _saveSounds[0] = _saveSounds[1] = 0xFFFF;
+ _mainSfxVolume = pVolume;
+}
+
+Sound::~Sound(void) {
+
+ _mixer->stopAll();
+ if (_soundData)
+ free(_soundData);
+}
+
+void Sound::playSound(uint32 id, byte *sound, uint32 size, Audio::SoundHandle *handle) {
+
+ byte flags = 0;
+ flags |= Audio::Mixer::FLAG_UNSIGNED|Audio::Mixer::FLAG_AUTOFREE;
+ size -= sizeof(struct dataFileHeader);
+ byte *buffer = (byte *)malloc(size);
+ memcpy(buffer, sound+sizeof(struct dataFileHeader), size);
+
+ _mixer->stopID(id);
+ _mixer->playRaw(handle, buffer, size, 11025, flags, id);
+}
+
+void Sound::loadSection(uint8 pSection) {
+
+ fnStopFx();
+ _mixer->stopAll();
+
+ if (_soundData)
+ free(_soundData);
+ _soundData = _skyDisk->loadFile(pSection * 4 + SOUND_FILE_BASE);
+ uint16 asmOfs;
+ if (SkyEngine::_systemVars.gameVersion == 109) {
+ if (pSection == 0)
+ asmOfs = 0x78;
+ else
+ asmOfs = 0x7C;
+ } else
+ asmOfs = 0x7E;
+
+ if ((_soundData[asmOfs] != 0x3C) || (_soundData[asmOfs + 0x27] != 0x8D) ||
+ (_soundData[asmOfs + 0x28] != 0x1E) || (_soundData[asmOfs + 0x2F] != 0x8D) ||
+ (_soundData[asmOfs + 0x30] != 0x36))
+ error("Unknown sounddriver version!");
+
+ _soundsTotal = _soundData[asmOfs + 1];
+ _sfxBaseOfs = READ_LE_UINT16(_soundData + asmOfs + 0x31);
+
+ _sfxInfo = _soundData + _sfxBaseOfs;
+ // if we just restored a savegame, the sfxqueue holds the sound we need to restart
+ if (!(SkyEngine::_systemVars.systemFlags & SF_GAME_RESTORED))
+ for (uint8 cnt = 0; cnt < 4; cnt++)
+ _sfxQueue[cnt].count = 0;
+}
+
+void Sound::playSound(uint16 sound, uint16 volume, uint8 channel) {
+
+ if (channel == 0)
+ _mixer->stopID(SOUND_CH0);
+ else
+ _mixer->stopID(SOUND_CH1);
+
+ if (!_soundData) {
+ warning("Sound::playSound(%04X, %04X) called with a section having been loaded", sound, volume);
+ return;
+ }
+
+ if (sound > _soundsTotal) {
+ debug(5, "Sound::playSound %d ignored, only %d sfx in file", sound, _soundsTotal);
+ return;
+ }
+
+ volume = (volume & 0x7F) << 1;
+ sound &= 0xFF;
+
+ // note: all those tables are big endian. Don't ask me why. *sigh*
+ uint32 dataOfs = READ_BE_UINT16(_sfxInfo + (sound << 3) + 0) << 4;
+ uint32 dataSize = READ_BE_UINT16(_sfxInfo + (sound << 3) + 2);
+ uint32 dataLoop = READ_BE_UINT16(_sfxInfo + (sound << 3) + 6);
+ dataOfs += _sfxBaseOfs;
+
+ byte flags = Audio::Mixer::FLAG_UNSIGNED;
+
+ uint32 loopSta = 0, loopEnd = 0;
+ if (dataLoop) {
+ loopSta = dataSize - dataLoop;
+ loopEnd = dataSize;
+ flags |= Audio::Mixer::FLAG_LOOP;
+ }
+
+ if (channel == 0)
+ _mixer->playRaw(&_ingameSound0, _soundData + dataOfs, dataSize, 11025, flags, SOUND_CH0, volume, 0, loopSta, loopEnd);
+ else
+ _mixer->playRaw(&_ingameSound1, _soundData + dataOfs, dataSize, 11025, flags, SOUND_CH1, volume, 0, loopSta, loopEnd);
+}
+
+void Sound::fnStartFx(uint32 sound, uint8 channel) {
+
+ _saveSounds[channel] = 0xFFFF;
+ if (sound < 256 || sound > MAX_FX_NUMBER || (SkyEngine::_systemVars.systemFlags & SF_FX_OFF))
+ return;
+
+ uint8 screen = (uint8)(Logic::_scriptVariables[SCREEN] & 0xff);
+ if (sound == 278 && screen == 25) // is this weld in room 25
+ sound= 394;
+
+ sound &= ~(1 << 8);
+
+ Sfx *sfx = musicList[sound];
+ RoomList *roomList = sfx->roomList;
+
+ int i = 0;
+ if (roomList[i].room != 0xff) // if room list empty then do all rooms
+ while (roomList[i].room != screen) { // check rooms
+ i++;
+ if (roomList[i].room == 0xff)
+ return;
+ }
+
+ // get fx volume
+
+ uint8 volume = _mainSfxVolume; // start with standard vol
+
+ if (SkyEngine::_systemVars.systemFlags & SF_SBLASTER)
+ volume = roomList[i].adlibVolume;
+ else if (SkyEngine::_systemVars.systemFlags & SF_ROLAND)
+ volume = roomList[i].rolandVolume;
+ volume = (volume * _mainSfxVolume) >> 8;
+
+ // Check the flags, the sound may come on after a delay.
+ if (sfx->flags & SFXF_START_DELAY) {
+ for (uint8 cnt = 0; cnt < MAX_QUEUED_FX; cnt++) {
+ if (_sfxQueue[cnt].count == 0) {
+ _sfxQueue[cnt].chan = channel;
+ _sfxQueue[cnt].fxNo = sfx->soundNo;
+ _sfxQueue[cnt].vol = volume;
+ _sfxQueue[cnt].count = sfx->flags & 0x7F;
+ return;
+ }
+ }
+ return; // ignore sound if it can't be queued
+ }
+
+ if (sfx->flags & SFXF_SAVE)
+ _saveSounds[channel] = sfx->soundNo | (volume << 8);
+
+ playSound(sfx->soundNo, volume, channel);
+}
+
+void Sound::checkFxQueue(void) {
+ for (uint8 cnt = 0; cnt < MAX_QUEUED_FX; cnt++) {
+ if (_sfxQueue[cnt].count) {
+ _sfxQueue[cnt].count--;
+ if (_sfxQueue[cnt].count == 0)
+ playSound(_sfxQueue[cnt].fxNo, _sfxQueue[cnt].vol, _sfxQueue[cnt].chan);
+ }
+ }
+}
+
+void Sound::restoreSfx(void) {
+
+ // queue sfx, so they will be started when the player exits the control panel
+ memset(_sfxQueue, 0, sizeof(_sfxQueue));
+ uint8 queueSlot = 0;
+ if (_saveSounds[0] != 0xFFFF) {
+ _sfxQueue[queueSlot].fxNo = (uint8)_saveSounds[0];
+ _sfxQueue[queueSlot].vol = (uint8)(_saveSounds[0] >> 8);
+ _sfxQueue[queueSlot].chan = 0;
+ _sfxQueue[queueSlot].count = 1;
+ queueSlot++;
+ }
+ if (_saveSounds[1] != 0xFFFF) {
+ _sfxQueue[queueSlot].fxNo = (uint8)_saveSounds[1];
+ _sfxQueue[queueSlot].vol = (uint8)(_saveSounds[1] >> 8);
+ _sfxQueue[queueSlot].chan = 1;
+ _sfxQueue[queueSlot].count = 1;
+ }
+}
+
+void Sound::fnStopFx(void) {
+ _mixer->stopID(SOUND_CH0);
+ _mixer->stopID(SOUND_CH1);
+ _saveSounds[0] = _saveSounds[1] = 0xFFFF;
+}
+
+void Sound::stopSpeech(void) {
+ _mixer->stopID(SOUND_SPEECH);
+}
+
+bool Sound::startSpeech(uint16 textNum) {
+
+ if (!(SkyEngine::_systemVars.systemFlags & SF_ALLOW_SPEECH))
+ return false;
+ uint16 speechFileNum = _speechConvertTable[textNum >> 12] + (textNum & 0xFFF);
+
+ uint8 *speechData = _skyDisk->loadFile(speechFileNum + 50000);
+ if (!speechData) {
+ debug(9,"File %d (speechFile %d from section %d) wasn't found", speechFileNum + 50000, textNum & 0xFFF, textNum >> 12);
+ return false;
+ }
+
+ uint32 speechSize = ((dataFileHeader *)speechData)->s_tot_size - sizeof(dataFileHeader);
+ uint8 *playBuffer = (uint8 *)malloc(speechSize);
+ memcpy(playBuffer, speechData + sizeof(dataFileHeader), speechSize);
+
+ free(speechData);
+
+ // Workaround for BASS bug #897775 - some voice-overs are played at
+ // half speed in 0.0368 (the freeware CD version), in 0.0372 they sound
+ // just fine.
+
+ uint rate;
+ if (_skyDisk->determineGameVersion() == 368 && (textNum == 20905 || textNum == 20906))
+ rate = 22050;
+ else
+ rate = 11025;
+
+ _mixer->stopID(SOUND_SPEECH);
+ _mixer->playRaw(&_ingameSpeech, playBuffer, speechSize, rate, Audio::Mixer::FLAG_UNSIGNED | Audio::Mixer::FLAG_AUTOFREE, SOUND_SPEECH);
+ return true;
+}
+
+void Sound::fnPauseFx(void) {
+
+ _mixer->pauseID(SOUND_CH0, true);
+ _mixer->pauseID(SOUND_CH1, true);
+}
+
+void Sound::fnUnPauseFx(void) {
+
+ _mixer->pauseID(SOUND_CH0, false);
+ _mixer->pauseID(SOUND_CH1, false);
+}
+
+} // End of namespace Sky
diff --git a/engines/sky/sound.h b/engines/sky/sound.h
new file mode 100644
index 0000000000..6d8283e33a
--- /dev/null
+++ b/engines/sky/sound.h
@@ -0,0 +1,95 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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 SKYSOUND_H
+#define SKYSOUND_H
+
+#include "common/stdafx.h"
+#include "common/scummsys.h"
+#include "sound/mixer.h"
+
+namespace Sky {
+
+class Disk;
+
+enum {
+ SOUND_CH0 = 0,
+ SOUND_CH1 = 1,
+ SOUND_BG = 2,
+ SOUND_VOICE = 3,
+ SOUND_SPEECH = 4
+};
+
+struct SfxQueue {
+ uint8 count, fxNo, chan, vol;
+};
+
+#define MAX_QUEUED_FX 4
+
+class Sound {
+protected:
+
+public:
+
+ Audio::Mixer *_mixer;
+ Audio::SoundHandle _voiceHandle;
+ Audio::SoundHandle _effectHandle;
+ Audio::SoundHandle _bgSoundHandle;
+ Audio::SoundHandle _ingameSound0, _ingameSound1, _ingameSpeech;
+
+ uint16 _saveSounds[2];
+
+protected:
+
+ void playSound(uint32 id, byte *sound, uint32 size, Audio::SoundHandle *handle);
+
+public:
+ Sound(Audio::Mixer *mixer, Disk *pDisk, uint8 pVolume);
+ ~Sound(void);
+
+ void loadSection(uint8 pSection);
+ void playSound(uint16 sound, uint16 volume, uint8 channel);
+ void fnStartFx(uint32 sound, uint8 channel);
+ bool startSpeech(uint16 textNum);
+ bool speechFinished(void) { return !_mixer->isSoundHandleActive(_ingameSpeech); };
+ void fnPauseFx(void);
+ void fnUnPauseFx(void);
+ void fnStopFx(void);
+ void stopSpeech(void);
+ void checkFxQueue(void);
+ void restoreSfx(void);
+ uint8 _soundsTotal;
+
+private:
+ Disk *_skyDisk;
+ uint16 _sfxBaseOfs;
+ uint8 *_soundData;
+ uint8 *_sfxInfo;
+ uint8 _mainSfxVolume;
+
+ static uint16 _speechConvertTable[8];
+ static SfxQueue _sfxQueue[MAX_QUEUED_FX];
+};
+
+} // End of namespace Sky
+
+#endif
diff --git a/engines/sky/struc.h b/engines/sky/struc.h
new file mode 100644
index 0000000000..45d1d946ca
--- /dev/null
+++ b/engines/sky/struc.h
@@ -0,0 +1,175 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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 SKYSTRUC_H
+#define SKYSTRUC_H
+
+namespace Sky {
+
+struct lowTextManager_t {
+ byte *textData;
+ uint32 textWidth;
+ uint16 compactNum;
+};
+
+struct displayText_t {
+ byte *textData;
+ uint32 textWidth;
+};
+
+#if !defined(__GNUC__)
+#pragma START_PACK_STRUCTS
+#endif
+
+struct dataFileHeader {
+ uint16 flag; // bit 0: set for colour data, clear for not
+ // bit 1: set for compressed, clear for uncompressed
+ // bit 2: set for 32 colours, clear for 16 colours
+ uint16 s_x;
+ uint16 s_y;
+ uint16 s_width;
+ uint16 s_height;
+ uint16 s_sp_size;
+ uint16 s_tot_size;
+ uint16 s_n_sprites;
+ int16 s_offset_x;
+ int16 s_offset_y;
+ uint16 s_compressed_size;
+} GCC_PACK;
+
+struct TurnTable {
+ uint16 turnTableUp[5];
+ uint16 turnTableDown[5];
+ uint16 turnTableLeft[5];
+ uint16 turnTableRight[5];
+ uint16 turnTableTalk[5];
+} GCC_PACK;
+
+struct MegaSet {
+ uint16 gridWidth; // 0
+ uint16 colOffset; // 1
+ uint16 colWidth; // 2
+ uint16 lastChr; // 3
+
+ uint16 animUpId; // 4
+ uint16 animDownId; // 5
+ uint16 animLeftId; // 6
+ uint16 animRightId; // 7
+
+ uint16 standUpId; // 8
+ uint16 standDownId; // 9
+ uint16 standLeftId; // 10
+ uint16 standRightId; // 11
+ uint16 standTalkId; // 12
+ uint16 turnTableId; // 13
+} GCC_PACK;
+
+struct Compact {
+ uint16 logic; // 0: Entry in logic table to run (byte as <256entries in logic table
+ uint16 status; // 1
+ uint16 sync; // 2: flag sent to compacts by other things
+
+ uint16 screen; // 3: current screen
+ uint16 place; // 4: so's this one
+ uint16 getToTableId; // 5: Address of how to get to things table
+
+ uint16 xcood; // 6
+ uint16 ycood; // 7
+
+ uint16 frame; // 8
+
+ uint16 cursorText; // 9
+ uint16 mouseOn; // 10
+ uint16 mouseOff; // 11
+ uint16 mouseClick; // 12
+
+ int16 mouseRelX; // 13
+ int16 mouseRelY; // 14
+ uint16 mouseSizeX; // 15
+ uint16 mouseSizeY; // 16
+
+ uint16 actionScript; // 17
+
+ uint16 upFlag; // 18: usually holds the Action Mode
+ uint16 downFlag; // 19: used for passing back
+ uint16 getToFlag; // 20: used by action script for get to attempts, also frame store (hence word)
+ uint16 flag; // 21: a use any time flag
+
+ uint16 mood; // 22: high level - stood or not
+
+ uint16 grafixProgId; // 23
+ uint16 grafixProgPos;// 24
+
+ uint16 offset; // 25
+
+ uint16 mode; // 26: which mcode block
+
+ uint16 baseSub; // 27: 1st mcode block relative to start of compact
+ uint16 baseSub_off; // 28
+ uint16 actionSub; // 29
+ uint16 actionSub_off;// 30
+ uint16 getToSub; // 31
+ uint16 getToSub_off; // 32
+ uint16 extraSub; // 33
+ uint16 extraSub_off; // 34
+
+ uint16 dir; // 35
+
+ uint16 stopScript; // 36
+ uint16 miniBump; // 37
+ uint16 leaving; // 38
+ uint16 atWatch; // 39: pointer to script variable
+ uint16 atWas; // 40: pointer to script variable
+ uint16 alt; // 41: alternate script
+ uint16 request; // 42
+
+ uint16 spWidth_xx; // 43
+ uint16 spColour; // 44
+ uint16 spTextId; // 45
+ uint16 spTime; // 46
+
+ uint16 arAnimIndex; // 47
+ uint16 turnProgId; // 48
+ uint16 turnProgPos; // 49
+
+ uint16 waitingFor; // 50
+
+ uint16 arTargetX; // 51
+ uint16 arTargetY; // 52
+
+ uint16 animScratchId;// 53: data area for AR
+
+ uint16 megaSet; // 54
+
+ MegaSet megaSet0; // 55
+ MegaSet megaSet1; //
+ MegaSet megaSet2; //
+ MegaSet megaSet3; //
+} GCC_PACK;
+
+#if !defined(__GNUC__)
+#pragma END_PACK_STRUCTS
+#endif
+
+} // End of namespace Sky
+
+#endif
diff --git a/engines/sky/text.cpp b/engines/sky/text.cpp
new file mode 100644
index 0000000000..2c997340ab
--- /dev/null
+++ b/engines/sky/text.cpp
@@ -0,0 +1,703 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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 "sky/disk.h"
+#include "sky/logic.h"
+#include "sky/text.h"
+#include "sky/sky.h"
+#include "sky/skydefs.h"
+#include "sky/struc.h"
+#include "sky/compact.h"
+
+namespace Sky {
+
+#define FIRST_TEXT_SEC 77
+#define FIRST_TEXT_BUFFER 274
+#define LAST_TEXT_BUFFER 284
+#define NO_OF_TEXT_SECTIONS 8 // 8 sections per language
+#define CHAR_SET_FILE 60150
+#define MAX_SPEECH_SECTION 7
+#define CHAR_SET_HEADER 128
+#define MAX_NO_LINES 10
+
+Text::Text(Disk *skyDisk, SkyCompact *skyCompact) {
+ _skyDisk = skyDisk;
+ _skyCompact = skyCompact;
+
+ initHuffTree();
+
+ _mainCharacterSet.addr = _skyDisk->loadFile(CHAR_SET_FILE);
+ _mainCharacterSet.charHeight = MAIN_CHAR_HEIGHT;
+ _mainCharacterSet.charSpacing = 0;
+
+ fnSetFont(0);
+
+ if (!SkyEngine::isDemo()) {
+ _controlCharacterSet.addr = _skyDisk->loadFile(60520);
+ _controlCharacterSet.charHeight = 12;
+ _controlCharacterSet.charSpacing = 0;
+
+ _linkCharacterSet.addr = _skyDisk->loadFile(60521);
+ _linkCharacterSet.charHeight = 12;
+ _linkCharacterSet.charSpacing = 1;
+
+ patchLINCCharset();
+ } else {
+ _controlCharacterSet.addr = NULL;
+ _linkCharacterSet.addr = NULL;
+ }
+}
+
+Text::~Text(void) {
+ for (int i = FIRST_TEXT_BUFFER; i <= LAST_TEXT_BUFFER; i++)
+ if (SkyEngine::_itemList[i]) {
+ free(SkyEngine::_itemList[i]);
+ SkyEngine::_itemList[i] = NULL;
+ }
+
+ if (_mainCharacterSet.addr)
+ free(_mainCharacterSet.addr);
+ if (_controlCharacterSet.addr)
+ free(_controlCharacterSet.addr);
+ if (_linkCharacterSet.addr)
+ free(_linkCharacterSet.addr);
+}
+
+void Text::patchChar(byte *charSetPtr, int width, int height, int c, const uint16 *data) {
+ byte *ptr = charSetPtr + (CHAR_SET_HEADER + (height << 2) * c);
+
+ charSetPtr[c] = width;
+
+ for (int i = 0; i < height; i++) {
+ ptr[i * 4 + 0] = (data[i] & 0xFF00) >> 8;
+ ptr[i * 4 + 1] = data[i] & 0x00FF;
+ ptr[i * 4 + 2] = (data[i + height] & 0xFF00) >> 8;
+ ptr[i * 4 + 3] = data[i + height] & 0x00FF;
+ }
+}
+
+void Text::patchLINCCharset() {
+ // The LINC terminal charset looks strange in some cases. This
+ // function attempts to patch up the worst blemishes.
+
+ byte *charSetPtr = _controlCharacterSet.addr;
+ int charHeight = _controlCharacterSet.charHeight;
+
+ // In v0.0288, the character spacing is too wide. Decrease the width
+ // for every character by one, except for space which needs to be one
+ // pixel wider than before.
+
+ if (SkyEngine::_systemVars.gameVersion == 288) {
+ for (int i = 1; i < CHAR_SET_HEADER; i++)
+ charSetPtr[i]--;
+ charSetPtr[0]++;
+ }
+
+ // NOTE: I have only tested this part of the code with v0.0372
+
+ // Several characters are different in this charset than in the other
+ // two. This is particularly noticeable when using a non-English
+ // version.
+
+ // Since the same character data is used both in LINC terminals and
+ // in LINC-space, we need to provide a mask (for the black outline)
+ // even though it's only visible in the latter. We store the mask
+ // as the second half of the array to make it more human-readable.
+ // In the actual game data, the character and mask are interleaved.
+
+ const uint16 slash[] = {
+ 0x0000, 0x0000, 0x0000, 0x0800, 0x1000, 0x1000,
+ 0x2000, 0x2000, 0x4000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0800, 0x1C00, 0x3800, 0x3800,
+ 0x7000, 0x7000, 0xE000, 0x4000, 0x0000, 0x0000
+ };
+
+ const uint16 lt[] = {
+ 0x0000, 0x0000, 0x0800, 0x1000, 0x2000, 0x4000,
+ 0x2000, 0x1000, 0x0800, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0800, 0x1C00, 0x3800, 0x7000, 0xE000,
+ 0x7000, 0x3800, 0x1C00, 0x0800, 0x0000, 0x0000
+ };
+
+ const uint16 gt[] = {
+ 0x0000, 0x0000, 0x4000, 0x2000, 0x1000, 0x0800,
+ 0x1000, 0x2000, 0x4000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x4000, 0xE000, 0x7000, 0x3800, 0x1C00,
+ 0x3800, 0x7000, 0xE000, 0x4000, 0x0000, 0x0000
+ };
+
+ const uint16 a_umlaut[] = {
+ 0x0000, 0x0000, 0x2800, 0x0000, 0x3000, 0x0800,
+ 0x3800, 0x4800, 0x3800, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x2800, 0x7C00, 0x3800, 0x7800, 0x3C00,
+ 0x7C00, 0xFC00, 0x7C00, 0x3800, 0x0000, 0x0000
+ };
+
+ const uint16 o_umlaut[] = {
+ 0x0000, 0x0000, 0x4800, 0x0000, 0x3000, 0x4800,
+ 0x4800, 0x4800, 0x3000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x4800, 0xFC00, 0x7800, 0x7800, 0xFC00,
+ 0xFC00, 0xFC00, 0x7800, 0x3000, 0x0000, 0x0000
+ };
+
+ const uint16 u_umlaut[] = {
+ 0x0000, 0x0000, 0x4800, 0x0000, 0x4800, 0x4800,
+ 0x4800, 0x4800, 0x3800, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x4800, 0xFC00, 0x4800, 0xFC00, 0xFC00,
+ 0xFC00, 0xFC00, 0x7C00, 0x3800, 0x0000, 0x0000
+ };
+
+ const uint16 A_umlaut[] = {
+ 0x0000, 0x4800, 0x0000, 0x3000, 0x4800, 0x4800,
+ 0x7800, 0x4800, 0x4800, 0x0000, 0x0000, 0x0000,
+ 0x4800, 0xFC00, 0x7800, 0x7800, 0xFC00, 0xFC00,
+ 0xFC00, 0xFC00, 0xFC00, 0x4800, 0x0000, 0x0000
+ };
+
+ const uint16 O_umlaut[] = {
+ 0x0000, 0x4800, 0x0000, 0x3000, 0x4800, 0x4800,
+ 0x4800, 0x4800, 0x3000, 0x0000, 0x0000, 0x0000,
+ 0x4800, 0xFC00, 0x7800, 0x7800, 0xFC00, 0xFC00,
+ 0xFC00, 0xFC00, 0x7800, 0x3000, 0x0000, 0x0000
+ };
+
+ const uint16 U_umlaut[] = {
+ 0x0000, 0x4800, 0x0000, 0x4800, 0x4800, 0x4800,
+ 0x4800, 0x4800, 0x3000, 0x0000, 0x0000, 0x0000,
+ 0x4800, 0xFC00, 0x4800, 0xFC00, 0xFC00, 0xFC00,
+ 0xFC00, 0xFC00, 0x7800, 0x3000, 0x0000, 0x0000
+ };
+
+ const uint16 normal_j[] = {
+ 0x0000, 0x0000, 0x0000, 0x0800, 0x0000, 0x0800,
+ 0x0800, 0x0800, 0x0800, 0x4800, 0x3000, 0x0000,
+ 0x0000, 0x0000, 0x0800, 0x1C00, 0x0800, 0x1C00,
+ 0x1C00, 0x1C00, 0x5C00, 0xFC00, 0x7800, 0x3000
+ };
+
+ const uint16 german_sz[] = {
+ 0x0000, 0x0000, 0x2000, 0x5000, 0x5000, 0x4800,
+ 0x4800, 0x4800, 0x5000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x2000, 0x7000, 0xF800, 0xF800, 0xFC00,
+ 0xFC00, 0xFC00, 0xF800, 0x7000, 0x0000, 0x0000
+ };
+
+ const uint16 normal_1[] = {
+ 0x0000, 0x0000, 0x0000, 0x1000, 0x7000, 0x1000,
+ 0x1000, 0x1000, 0x7c00, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x1000, 0x7800, 0xF800, 0x7800,
+ 0x3800, 0x7c00, 0xFE00, 0x7c00, 0x0000, 0x0000
+ };
+
+ // The next five are needed for at least the French version
+
+ const uint16 e_acute[] = {
+ 0x0000, 0x1000, 0x2000, 0x0000, 0x3000, 0x4800,
+ 0x7800, 0x4000, 0x3000, 0x0000, 0x0000, 0x0000,
+ 0x1000, 0x3800, 0x7000, 0x7000, 0x7800, 0xFC00,
+ 0xFC00, 0xF800, 0x7800, 0x3000, 0x0000, 0x0000
+ };
+
+ const uint16 e_grave[] = {
+ 0x0000, 0x2000, 0x1000, 0x0000, 0x3000, 0x4800,
+ 0x7800, 0x4000, 0x3000, 0x0000, 0x0000, 0x0000,
+ 0x2000, 0x7000, 0x3800, 0x3800, 0x7800, 0xFC00,
+ 0xFC00, 0xF800, 0x7800, 0x3000, 0x0000, 0x0000
+ };
+
+ const uint16 e_circumflex[] = {
+ 0x0000, 0x1000, 0x2800, 0x0000, 0x3000, 0x4800,
+ 0x7800, 0x4000, 0x3000, 0x0000, 0x0000, 0x0000,
+ 0x1000, 0x3800, 0x7C00, 0x7800, 0x7800, 0xFC00,
+ 0xFC00, 0xF800, 0x7800, 0x3000, 0x0000, 0x0000
+ };
+
+ const uint16 o_circumflex[] = {
+ 0x0000, 0x1000, 0x2800, 0x0000, 0x3000, 0x4800,
+ 0x4800, 0x4800, 0x3000, 0x0000, 0x0000, 0x0000,
+ 0x1000, 0x3800, 0x7C00, 0x3800, 0x7800, 0xFC00,
+ 0xFC00, 0xFC00, 0x7800, 0x3000, 0x0000, 0x0000
+ };
+
+ const uint16 u_circumflex[] = {
+ 0x0000, 0x1000, 0x2800, 0x0000, 0x4800, 0x4800,
+ 0x4800, 0x4800, 0x3800, 0x0000, 0x0000, 0x0000,
+ 0x1000, 0x3800, 0x7C00, 0x7800, 0xFC00, 0xFC00,
+ 0xFC00, 0xFC00, 0x7C00, 0x3800, 0x0000, 0x0000
+ };
+
+ patchChar(charSetPtr, 5, charHeight, 3, u_umlaut);
+ patchChar(charSetPtr, 5, charHeight, 8, german_sz);
+ patchChar(charSetPtr, 5, charHeight, 9, o_umlaut);
+ patchChar(charSetPtr, 5, charHeight, 93, U_umlaut);
+ patchChar(charSetPtr, 5, charHeight, 74, normal_j);
+ patchChar(charSetPtr, 6, charHeight, 17, normal_1);
+
+ patchChar(charSetPtr, 5, charHeight, 11, e_acute);
+ patchChar(charSetPtr, 5, charHeight, 61, e_grave);
+ patchChar(charSetPtr, 5, charHeight, 29, e_circumflex);
+ patchChar(charSetPtr, 5, charHeight, 32, o_circumflex);
+ patchChar(charSetPtr, 5, charHeight, 30, u_circumflex);
+
+ if (SkyEngine::_systemVars.gameVersion <= 303) {
+ patchChar(charSetPtr, 5, charHeight, 10, a_umlaut);
+ } else {
+ patchChar(charSetPtr, 5, charHeight, 94, A_umlaut);
+ patchChar(charSetPtr, 5, charHeight, 95, O_umlaut);
+
+ // Used by, for instance, the BRIEFING.DOC file in all (?) languages
+ patchChar(charSetPtr, 5, charHeight, 96, lt);
+ patchChar(charSetPtr, 5, charHeight, 97, gt);
+ patchChar(charSetPtr, 5, charHeight, 98, slash);
+ }
+}
+
+void Text::fnSetFont(uint32 fontNr) {
+
+ struct charSet *newCharSet;
+
+ switch (fontNr) {
+ case 0:
+ newCharSet = &_mainCharacterSet;
+ break;
+ case 1:
+ newCharSet = &_controlCharacterSet;
+ break;
+ case 2:
+ newCharSet = &_linkCharacterSet;
+ break;
+ default:
+ error("Tried to set invalid font (%d)", fontNr);
+ }
+
+ _curCharSet = fontNr;
+ _characterSet = newCharSet->addr;
+ _charHeight = (byte)newCharSet->charHeight;
+ _dtCharSpacing = newCharSet->charSpacing;
+}
+
+void Text::fnTextModule(uint32 textInfoId, uint32 textNo) {
+
+ fnSetFont(1);
+ uint16* msgData = (uint16 *)_skyCompact->fetchCpt(textInfoId);
+ lowTextManager_t textId = lowTextManager(textNo, msgData[1], msgData[2], 209, false);
+ Logic::_scriptVariables[RESULT] = textId.compactNum;
+ Compact *textCompact = _skyCompact->fetchCpt(textId.compactNum);
+ textCompact->xcood = msgData[3];
+ textCompact->ycood = msgData[4];
+ fnSetFont(0);
+}
+
+void Text::getText(uint32 textNr) { //load text #"textNr" into textBuffer
+
+ if (patchMessage(textNr))
+ return;
+
+ uint32 sectionNo = (textNr & 0x0F000) >> 12;
+
+ if (SkyEngine::_itemList[FIRST_TEXT_SEC + sectionNo] == NULL) { //check if already loaded
+ debug(5, "Loading Text item(s) for Section %d", (sectionNo >> 2));
+
+ uint32 fileNo = sectionNo + ((SkyEngine::_systemVars.language * NO_OF_TEXT_SECTIONS) + 60600);
+ SkyEngine::_itemList[FIRST_TEXT_SEC + sectionNo] = (void **)_skyDisk->loadFile((uint16)fileNo);
+ }
+ uint8 *textDataPtr = (uint8 *)SkyEngine::_itemList[FIRST_TEXT_SEC + sectionNo];
+
+ uint32 offset = 0;
+
+ uint32 blockNr = textNr & 0xFE0;
+ textNr &= 0x1F;
+
+ if (blockNr) {
+ uint16 *blockPtr = (uint16*)(textDataPtr + 4);
+ uint32 nr32MsgBlocks = blockNr >> 5;
+
+ do {
+ offset += READ_LE_UINT16(blockPtr);
+ blockPtr++;
+ } while (--nr32MsgBlocks);
+ }
+
+ if (textNr) {
+ uint8 *blockPtr = textDataPtr + blockNr + READ_LE_UINT16(textDataPtr);
+ do {
+ uint8 skipBytes = *blockPtr++;
+ if (skipBytes & 0x80) {
+ skipBytes &= 0x7F;
+ skipBytes <<= 3;
+ }
+ offset += skipBytes;
+ } while (--textNr);
+ }
+
+ uint32 bitPos = offset & 3;
+ offset >>= 2;
+ offset += READ_LE_UINT16(textDataPtr + 2);
+
+ textDataPtr += offset;
+
+ //bit pointer: 0->8, 1->6, 2->4 ...
+ bitPos ^= 3;
+ bitPos++;
+ bitPos <<= 1;
+
+ char *dest = (char *)_textBuffer;
+ char textChar;
+
+ do {
+ textChar = getTextChar(&textDataPtr, &bitPos);
+ *dest++ = textChar;
+ } while (textChar);
+}
+
+void Text::fnPointerText(uint32 pointedId, uint16 mouseX, uint16 mouseY) {
+
+ Compact *ptrComp = _skyCompact->fetchCpt(pointedId);
+ lowTextManager_t text = lowTextManager(ptrComp->cursorText, TEXT_MOUSE_WIDTH, L_CURSOR, 242, false);
+ Logic::_scriptVariables[CURSOR_ID] = text.compactNum;
+ if (Logic::_scriptVariables[MENU]) {
+ _mouseOfsY = TOP_LEFT_Y - 2;
+ if (mouseX < 150)
+ _mouseOfsX = TOP_LEFT_X + 24;
+ else
+ _mouseOfsX = TOP_LEFT_X - 8 - text.textWidth;
+ } else {
+ _mouseOfsY = TOP_LEFT_Y - 10;
+ if (mouseX < 150)
+ _mouseOfsX = TOP_LEFT_X + 13;
+ else
+ _mouseOfsX = TOP_LEFT_X - 8 - text.textWidth;
+ }
+ Compact *textCompact = _skyCompact->fetchCpt(text.compactNum);
+ logicCursor(textCompact, mouseX, mouseY);
+}
+
+void Text::logicCursor(Compact *textCompact, uint16 mouseX, uint16 mouseY) {
+
+ textCompact->xcood = (uint16)(mouseX + _mouseOfsX);
+ textCompact->ycood = (uint16)(mouseY + _mouseOfsY);
+ if (textCompact->ycood < TOP_LEFT_Y)
+ textCompact->ycood = TOP_LEFT_Y;
+}
+
+bool Text::getTextBit(uint8 **data, uint32 *bitPos) {
+
+ if (*bitPos) {
+ (*bitPos)--;
+ } else {
+ (*data)++;
+ *bitPos = 7;
+ }
+
+ return (bool)(((**data) >> (*bitPos)) & 1);
+}
+
+char Text::getTextChar(uint8 **data, uint32 *bitPos) {
+ int pos = 0;
+ while (1) {
+ if (getTextBit(data, bitPos))
+ pos = _huffTree[pos].rChild;
+ else
+ pos = _huffTree[pos].lChild;
+
+ if (_huffTree[pos].lChild == 0 && _huffTree[pos].rChild == 0) {
+ return _huffTree[pos].value;
+ }
+ }
+}
+
+displayText_t Text::displayText(uint32 textNum, uint8 *dest, bool centre, uint16 pixelWidth, uint8 color) {
+ //Render text into buffer *dest
+ getText(textNum);
+ return displayText(_textBuffer, dest, centre, pixelWidth, color);
+}
+
+displayText_t Text::displayText(char *textPtr, uint8 *dest, bool centre, uint16 pixelWidth, uint8 color) {
+
+ //Render text pointed to by *textPtr in buffer *dest
+ uint32 centerTable[10];
+ uint16 lineWidth = 0;
+
+ uint32 numLines = 0;
+ _numLetters = 2;
+
+ // work around bug #778105 (line width exceeded)
+ char *tmpPtr = strstr(textPtr, "MUND-BEATMUNG!");
+ if (tmpPtr)
+ strcpy(tmpPtr, "MUND BEATMUNG!");
+
+ // work around bug #1151924 (line width exceeded when talking to gardener using spanish text)
+ // This text apparently only is broken in the floppy versions, the CD versions contain
+ // the correct string "MANIFESTACION - ARTISTICA.", which doesn't break the algorithm/game.
+ tmpPtr = strstr(textPtr, "MANIFESTACION-ARTISTICA.");
+ if (tmpPtr)
+ strcpy(tmpPtr, "MANIFESTACION ARTISTICA.");
+
+ char *curPos = textPtr;
+ char *lastSpace = textPtr;
+ uint8 textChar = (uint8)*curPos++;
+
+ while (textChar >= 0x20) {
+ if ((_curCharSet == 1) && (textChar >= 0x80))
+ textChar = 0x20;
+
+ textChar -= 0x20;
+ if (textChar == 0) {
+ lastSpace = curPos; //keep track of last space
+ centerTable[numLines] = lineWidth;
+ }
+
+ lineWidth += _characterSet[textChar]; //add character width
+ lineWidth += (uint16)_dtCharSpacing; //include character spacing
+
+ if (pixelWidth <= lineWidth) {
+
+ if (*(lastSpace-1) == 10)
+ error("line width exceeded!");
+
+ *(lastSpace-1) = 10;
+ lineWidth = 0;
+ numLines++;
+ curPos = lastSpace; //go back for new count
+ }
+
+ textChar = (uint8)*curPos++;
+ _numLetters++;
+ }
+
+ uint32 dtLastWidth = lineWidth; //save width of last line
+ centerTable[numLines] = lineWidth; //and update centering table
+ numLines++;
+
+ if (numLines > MAX_NO_LINES)
+ error("Maximum no. of lines exceeded!");
+
+ uint32 dtLineSize = pixelWidth * _charHeight;
+ uint32 numBytes = (dtLineSize * numLines) + sizeof(struct dataFileHeader) + 4;
+
+ if (!dest)
+ dest = (uint8*)malloc(numBytes);
+
+ // clear text sprite buffer
+ memset(dest + sizeof(struct dataFileHeader), 0, numBytes - sizeof(struct dataFileHeader));
+
+ //make the header
+ ((struct dataFileHeader *)dest)->s_width = pixelWidth;
+ ((struct dataFileHeader *)dest)->s_height = (uint16)(_charHeight * numLines);
+ ((struct dataFileHeader *)dest)->s_sp_size = (uint16)(pixelWidth * _charHeight * numLines);
+ ((struct dataFileHeader *)dest)->s_offset_x = 0;
+ ((struct dataFileHeader *)dest)->s_offset_y = 0;
+
+ //reset position
+ curPos = textPtr;
+
+ uint8 *curDest = dest + sizeof(struct dataFileHeader); //point to where pixels start
+ byte *prevDest = curDest;
+ uint32 *centerTblPtr = centerTable;
+
+ do {
+ if (centre) {
+ uint32 width = (pixelWidth - *centerTblPtr) >> 1;
+ centerTblPtr++;
+ curDest += width;
+ }
+
+ textChar = (uint8)*curPos++;
+ while (textChar >= 0x20) {
+ makeGameCharacter(textChar - 0x20, _characterSet, curDest, color, pixelWidth);
+ textChar = *curPos++;
+ }
+
+ prevDest = curDest = prevDest + dtLineSize; //start of last line + start of next
+
+ } while (textChar >= 10);
+
+ struct displayText_t ret;
+ ret.textData = dest;
+ ret.textWidth = dtLastWidth;
+ return ret;
+}
+
+void Text::makeGameCharacter(uint8 textChar, uint8 *charSetPtr, uint8 *&dest, uint8 color, uint16 bufPitch) {
+
+ bool maskBit, dataBit;
+ uint8 charWidth = (uint8)((*(charSetPtr + textChar)) + 1 - _dtCharSpacing);
+ uint16 data, mask;
+ byte *charSpritePtr = charSetPtr + (CHAR_SET_HEADER + ((_charHeight << 2) * textChar));
+ byte *startPos = dest;
+ byte *curPos = startPos;
+
+ for (int i = 0; i < _charHeight; i++) {
+
+ byte *prevPos = curPos;
+
+ data = READ_BE_UINT16(charSpritePtr);
+ mask = READ_BE_UINT16(charSpritePtr + 2);
+ charSpritePtr += 4;
+
+ for (int j = 0; j < charWidth; j++) {
+
+ maskBit = (mask & 0x8000) != 0; //check mask
+ mask <<= 1;
+ dataBit = (data & 0x8000) != 0; //check data
+ data <<= 1;
+
+ if (maskBit)
+ if (dataBit)
+ *curPos = color;
+ else
+ *curPos = 240; //black edge
+
+ curPos++;
+ }
+ //advance a line
+ curPos = prevPos + bufPitch;
+ }
+ //update position
+ dest = startPos + charWidth + _dtCharSpacing * 2 - 1;
+}
+
+lowTextManager_t Text::lowTextManager(uint32 textNum, uint16 width, uint16 logicNum, uint8 color, bool centre) {
+
+ getText(textNum);
+ struct displayText_t textInfo = displayText(_textBuffer, NULL, centre, width, color);
+
+ uint32 compactNum = FIRST_TEXT_COMPACT;
+ Compact *cpt = _skyCompact->fetchCpt(compactNum);
+ while (cpt->status != 0) {
+ compactNum++;
+ cpt = _skyCompact->fetchCpt(compactNum);
+ }
+
+ cpt->flag = (uint16)(compactNum - FIRST_TEXT_COMPACT) + FIRST_TEXT_BUFFER;
+
+ if (SkyEngine::_itemList[cpt->flag])
+ free(SkyEngine::_itemList[cpt->flag]);
+
+ SkyEngine::_itemList[cpt->flag] = textInfo.textData;
+
+ cpt->logic = logicNum;
+ cpt->status = ST_LOGIC | ST_FOREGROUND | ST_RECREATE;
+ cpt->screen = (uint16) Logic::_scriptVariables[SCREEN];
+
+ struct lowTextManager_t ret;
+ ret.textData = textInfo.textData;
+ ret.textWidth = textInfo.textWidth;
+ ret.compactNum = (uint16)compactNum;
+
+ return ret;
+}
+
+void Text::changeTextSpriteColour(uint8 *sprData, uint8 newCol) {
+
+ dataFileHeader *header = (dataFileHeader *)sprData;
+ sprData += sizeof(dataFileHeader);
+ for (uint16 cnt = 0; cnt < header->s_sp_size; cnt++)
+ if (sprData[cnt] >= 241)
+ sprData[cnt] = newCol;
+}
+
+uint32 Text::giveCurrentCharSet(void) {
+ return _curCharSet;
+}
+
+void Text::initHuffTree() {
+ switch (SkyEngine::_systemVars.gameVersion) {
+ case 109:
+ _huffTree = _huffTree_00109;
+ break;
+ case 267:
+ _huffTree = _huffTree_00267;
+ break;
+ case 288:
+ _huffTree = _huffTree_00288;
+ break;
+ case 303:
+ _huffTree = _huffTree_00303;
+ break;
+ case 331:
+ _huffTree = _huffTree_00331;
+ break;
+ case 348:
+ _huffTree = _huffTree_00348;
+ break;
+ case 365:
+ _huffTree = _huffTree_00365;
+ break;
+ case 368:
+ _huffTree = _huffTree_00368;
+ break;
+ case 372:
+ _huffTree = _huffTree_00372;
+ break;
+ default:
+ error("Unknown game version %d", SkyEngine::_systemVars.gameVersion);
+ }
+}
+
+bool Text::patchMessage(uint32 textNum) {
+
+ uint16 patchIdx = _patchLangIdx[SkyEngine::_systemVars.language];
+ uint16 patchNum = _patchLangNum[SkyEngine::_systemVars.language];
+ for (uint16 cnt = 0; cnt < patchNum; cnt++) {
+ if (_patchedMessages[cnt + patchIdx].textNr == textNum) {
+ strcpy(_textBuffer, _patchedMessages[cnt + patchIdx].text);
+ return true;
+ }
+ }
+ return false;
+}
+
+const PatchMessage Text::_patchedMessages[NUM_PATCH_MSG] = {
+ { 28724, "Testo e Parlato" }, // - italian
+ { 28707, "Solo Testo" },
+ { 28693, "Solo Parlato" },
+ { 28724, "Text och tal" }, // - swedish
+ { 28707, "Endast text" },
+ { 28693, "Endast tal" },
+ { 28686, "Musikvolym" },
+ { 4336, "Wir befinden uns EINHUNDERTZWANZIG METER #ber dem ERBODEN!" }, // - german
+};
+
+const uint16 Text::_patchLangIdx[8] = {
+ 0xFFFF, // SKY_ENGLISH
+ 7, // SKY_GERMAN
+ 0xFFFF, // SKY_FRENCH
+ 0xFFFF, // SKY_USA
+ 3, // SKY_SWEDISH
+ 0, // SKY_ITALIAN
+ 0xFFFF, // SKY_PORTUGUESE
+ 0xFFFF // SKY_SPANISH
+};
+
+const uint16 Text::_patchLangNum[8] = {
+ 0, // SKY_ENGLISH
+ 1, // SKY_GERMAN
+ 0, // SKY_FRENCH
+ 0, // SKY_USA
+ 4, // SKY_SWEDISH
+ 3, // SKY_ITALIAN
+ 0, // SKY_PORTUGUESE
+ 0 // SKY_SPANISH
+};
+
+} // End of namespace Sky
diff --git a/engines/sky/text.h b/engines/sky/text.h
new file mode 100644
index 0000000000..33aa6f8df7
--- /dev/null
+++ b/engines/sky/text.h
@@ -0,0 +1,124 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003-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 SKYTEXT_H
+#define SKYTEXT_H
+
+#include "common/stdafx.h"
+#include "common/scummsys.h"
+
+namespace Sky {
+
+struct Compact;
+class Disk;
+class SkyCompact;
+
+struct HuffTree {
+ unsigned char lChild;
+ unsigned char rChild;
+ unsigned char value;
+};
+
+#define NUM_PATCH_MSG 8
+
+struct PatchMessage {
+ uint32 textNr;
+ char text[100];
+};
+
+class Text {
+public:
+ Text(Disk *skyDisk, SkyCompact *skyCompact);
+ ~Text(void);
+ struct displayText_t displayText(uint32 textNum, uint8 *dest, bool centre, uint16 pixelWidth, uint8 color);
+ struct displayText_t displayText(char *textPtr, uint8 *dest, bool centre, uint16 pixelWidth, uint8 color);
+ struct lowTextManager_t lowTextManager(uint32 textNum, uint16 width, uint16 logicNum, uint8 color, bool centre);
+ void fnSetFont(uint32 fontNr);
+ void fnTextModule(uint32 textInfoId, uint32 textNo);
+ void fnPointerText(uint32 pointedId, uint16 mouseX, uint16 mouseY);
+ void logicCursor(Compact *textCompact, uint16 mouseX, uint16 mouseY);
+ void changeTextSpriteColour(uint8 *sprData, uint8 newCol);
+ uint32 giveCurrentCharSet(void);
+
+ uint32 _numLetters; //no of chars in message
+
+private:
+ void initHuffTree();
+ void getText(uint32 textNr);
+ char getTextChar(uint8 **data, uint32 *bitPos);
+ bool getTextBit(uint8 **data, uint32 *bitPos);
+ void makeGameCharacter(uint8 textChar, uint8 *charSetPtr, uint8 *&data, uint8 color, uint16 bufPitch);
+
+ void patchChar(byte *charSetPtr, int width, int height, int c, const uint16 *data);
+ void patchLINCCharset();
+ bool patchMessage(uint32 textNum);
+
+ Disk *_skyDisk;
+ SkyCompact *_skyCompact;
+
+ const HuffTree *_huffTree;
+
+ struct charSet {
+ uint8 *addr;
+ uint32 charHeight;
+ uint32 charSpacing;
+ } _mainCharacterSet, _linkCharacterSet, _controlCharacterSet;
+
+ uint32 _curCharSet;
+ uint8 *_characterSet;
+ uint8 _charHeight;
+
+ char _textBuffer[1024];
+
+ uint32 _dtCharSpacing; //character separation adjustment
+ uint32 _mouseOfsX, _mouseOfsY;
+ static const PatchMessage _patchedMessages[NUM_PATCH_MSG];
+ static const uint16 _patchLangIdx[8];
+ static const uint16 _patchLangNum[8];
+
+#ifndef PALMOS_68K
+ static const HuffTree _huffTree_00109[]; // trees moved to hufftext.cpp
+ static const HuffTree _huffTree_00267[];
+ static const HuffTree _huffTree_00288[];
+ static const HuffTree _huffTree_00303[];
+ static const HuffTree _huffTree_00331[];
+ static const HuffTree _huffTree_00348[];
+ static const HuffTree _huffTree_00365[];
+ static const HuffTree _huffTree_00368[];
+ static const HuffTree _huffTree_00372[];
+#else
+public:
+ static const HuffTree *_huffTree_00109; // trees moved to hufftext.cpp
+ static const HuffTree *_huffTree_00267;
+ static const HuffTree *_huffTree_00288;
+ static const HuffTree *_huffTree_00303;
+ static const HuffTree *_huffTree_00331;
+ static const HuffTree *_huffTree_00348;
+ static const HuffTree *_huffTree_00365;
+ static const HuffTree *_huffTree_00368;
+ static const HuffTree *_huffTree_00372;
+#endif
+};
+
+} // End of namespace Sky
+
+#endif