diff options
Diffstat (limited to 'engines/sky')
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 |