aboutsummaryrefslogtreecommitdiff
path: root/engines/sword1
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sword1')
-rw-r--r--engines/sword1/animation.cpp307
-rw-r--r--engines/sword1/animation.h120
-rw-r--r--engines/sword1/collision.h50
-rw-r--r--engines/sword1/control.cpp1301
-rw-r--r--engines/sword1/control.h152
-rw-r--r--engines/sword1/credits.cpp346
-rw-r--r--engines/sword1/credits.h72
-rw-r--r--engines/sword1/debug.cpp140
-rw-r--r--engines/sword1/debug.h42
-rw-r--r--engines/sword1/eventman.cpp103
-rw-r--r--engines/sword1/eventman.h51
-rw-r--r--engines/sword1/logic.cpp1803
-rw-r--r--engines/sword1/logic.h239
-rw-r--r--engines/sword1/memman.cpp129
-rw-r--r--engines/sword1/memman.h64
-rw-r--r--engines/sword1/menu.cpp393
-rw-r--r--engines/sword1/menu.h109
-rw-r--r--engines/sword1/module.mk32
-rw-r--r--engines/sword1/mouse.cpp313
-rw-r--r--engines/sword1/mouse.h113
-rw-r--r--engines/sword1/music.cpp352
-rw-r--r--engines/sword1/music.h122
-rw-r--r--engines/sword1/object.h130
-rw-r--r--engines/sword1/objectman.cpp163
-rw-r--r--engines/sword1/objectman.h66
-rw-r--r--engines/sword1/resman.cpp421
-rw-r--r--engines/sword1/resman.h98
-rw-r--r--engines/sword1/router.cpp2606
-rw-r--r--engines/sword1/router.h180
-rw-r--r--engines/sword1/screen.cpp986
-rw-r--r--engines/sword1/screen.h157
-rw-r--r--engines/sword1/sound.cpp382
-rw-r--r--engines/sword1/sound.h127
-rw-r--r--engines/sword1/staticres.cpp7168
-rw-r--r--engines/sword1/sword1.cpp615
-rw-r--r--engines/sword1/sword1.h110
-rw-r--r--engines/sword1/sworddefs.h1606
-rw-r--r--engines/sword1/swordres.h5223
-rw-r--r--engines/sword1/text.cpp191
-rw-r--r--engines/sword1/text.h65
40 files changed, 26647 insertions, 0 deletions
diff --git a/engines/sword1/animation.cpp b/engines/sword1/animation.cpp
new file mode 100644
index 0000000000..f6865cc5e2
--- /dev/null
+++ b/engines/sword1/animation.cpp
@@ -0,0 +1,307 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004-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 "sword1/sword1.h"
+#include "sword1/animation.h"
+#include "sword1/credits.h"
+#include "sound/vorbis.h"
+
+#include "common/config-manager.h"
+#include "common/str.h"
+#include "common/system.h"
+
+namespace Sword1 {
+
+AnimationState::AnimationState(Screen *scr, Audio::Mixer *snd, OSystem *sys)
+ : BaseAnimationState(snd, sys, 640, 400), _scr(scr) {
+}
+
+AnimationState::~AnimationState() {
+}
+
+
+#ifdef BACKEND_8BIT
+void AnimationState::setPalette(byte *pal) {
+ _sys->setPalette(pal, 0, 256);
+}
+#endif
+
+void AnimationState::drawYUV(int width, int height, byte *const *dat) {
+#ifdef BACKEND_8BIT
+ _scr->plotYUV(_lut, width, height, dat);
+#else
+ plotYUV(width, height, dat);
+#endif
+}
+
+void AnimationState::updateScreen(void) {
+#ifndef BACKEND_8BIT
+ _sys->copyRectToOverlay(_overlay, _movieWidth, 0, 40, _movieWidth, _movieHeight);
+#endif
+ _sys->updateScreen();
+}
+
+OverlayColor *AnimationState::giveRgbBuffer(void) {
+#ifdef BACKEND_8BIT
+ return NULL;
+#else
+ return _overlay;
+#endif
+}
+
+bool AnimationState::soundFinished(void) {
+ return !_snd->isSoundHandleActive(_bgSound);
+}
+
+AudioStream *AnimationState::createAudioStream(const char *name, void *arg) {
+ if (arg)
+ return (AudioStream*)arg;
+ else
+ return AudioStream::openStreamFile(name);
+}
+
+MoviePlayer::MoviePlayer(Screen *scr, Audio::Mixer *snd, OSystem *sys)
+ : _scr(scr), _snd(snd), _sys(sys) {
+ for (uint8 cnt = 0; cnt < INTRO_LOGO_OVLS; cnt++)
+ _logoOvls[cnt] = NULL;
+ _introPal = NULL;
+}
+
+MoviePlayer::~MoviePlayer(void) {
+ if (_introPal)
+ free(_introPal);
+ for (uint8 cnt = 0; cnt < INTRO_LOGO_OVLS; cnt++)
+ if (_logoOvls[cnt])
+ free(_logoOvls[cnt]);
+}
+
+/**
+ * Plays an animated cutscene.
+ * @param id the id of the file
+ */
+void MoviePlayer::play(uint32 id) {
+#if defined(USE_MPEG2) && defined(USE_VORBIS)
+ AnimationState *anim = new AnimationState(_scr, _snd, _sys);
+ AudioStream *stream = NULL;
+ if (SwordEngine::_systemVars.cutscenePackVersion == 1) {
+ if ((id == SEQ_INTRO) || (id == SEQ_FINALE) || (id == SEQ_HISTORY) || (id == SEQ_FERRARI)) {
+ // these sequences are language specific
+ char sndName[20];
+ sprintf(sndName, "%s.snd", _sequenceList[id]);
+ Common::File *oggSource = new Common::File();
+ if (oggSource->open(sndName)) {
+ SplittedAudioStream *sStream = new SplittedAudioStream();
+ uint32 numSegs = oggSource->readUint32LE(); // number of audio segments, either 1 or 2.
+ // for each segment and each of the 7 languages, we've got fileoffset and size
+ uint32 *header = (uint32*)malloc(numSegs * 7 * 2 * 4);
+ for (uint32 cnt = 0; cnt < numSegs * 7 * 2; cnt++)
+ header[cnt] = oggSource->readUint32LE();
+ for (uint32 segCnt = 0; segCnt < numSegs; segCnt++) {
+ oggSource->seek( header[SwordEngine::_systemVars.language * 2 + 0 + segCnt * 14]);
+ uint32 segSize = header[SwordEngine::_systemVars.language * 2 + 1 + segCnt * 14];
+ AudioStream *apStream = makeVorbisStream(oggSource, segSize);
+ if (!apStream)
+ error("Can't create Vorbis Stream from file %s", sndName);
+ sStream->appendStream(apStream);
+ }
+ free(header);
+ stream = sStream;
+ } else
+ warning("Sound file \"%s\" not found", sndName);
+ initOverlays(id);
+ oggSource->decRef();
+ }
+ }
+ bool initOK = anim->init(_sequenceList[id], stream);
+
+ uint32 frameCount = 0;
+ if (initOK) {
+ while (anim->decodeFrame()) {
+ processFrame(id, anim, frameCount);
+ anim->updateScreen();
+ frameCount++;
+ OSystem::Event event;
+ while (_sys->pollEvent(event)) {
+ switch (event.type) {
+#ifndef BACKEND_8BIT
+ case OSystem::EVENT_SCREEN_CHANGED:
+ anim->buildLookup();
+ break;
+#endif
+ case OSystem::EVENT_KEYDOWN:
+ if (event.kbd.keycode == 27) {
+ delete anim;
+ return;
+ }
+ break;
+ case OSystem::EVENT_QUIT:
+ _sys->quit();
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+ while (!anim->soundFinished())
+ _sys->delayMillis(100);
+ delete anim;
+#endif // USE_MPEG2 && USE_VORBIS
+}
+
+void MoviePlayer::insertOverlay(OverlayColor *buf, uint8 *ovl, OverlayColor *pal) {
+ if (ovl != NULL)
+ for (uint32 cnt = 0; cnt < 640 * 400; cnt++)
+ if (ovl[cnt])
+ buf[cnt] = pal[ovl[cnt]];
+}
+
+void MoviePlayer::processFrame(uint32 animId, AnimationState *anim, uint32 frameNo) {
+#if defined(USE_MPEG2) && !defined(BACKEND_8BIT)
+ if ((animId != 4) || (SwordEngine::_systemVars.cutscenePackVersion == 0))
+ return;
+ OverlayColor *buf = anim->giveRgbBuffer();
+ if ((frameNo > 397) && (frameNo < 444)) { // Broken Sword Logo
+ if (frameNo <= 403)
+ insertOverlay(buf, _logoOvls[frameNo - 398], _introPal); // fade up
+ else if (frameNo <= 437)
+ insertOverlay(buf, _logoOvls[(frameNo - 404) % 6 + 6], _introPal); // animation
+ else {
+ insertOverlay(buf, _logoOvls[5 - (frameNo - 438)], _introPal); // fade down
+ }
+ }
+#endif
+}
+
+bool MoviePlayer::initOverlays(uint32 id) {
+#if defined(USE_MPEG2) && !defined(BACKEND_8BIT)
+ if (id == SEQ_INTRO) {
+ ArcFile ovlFile;
+ if (!ovlFile.open("intro.dat")) {
+ warning("\"intro.dat\" not found");
+ return false;
+ }
+ ovlFile.enterPath(SwordEngine::_systemVars.language);
+ for (uint8 fcnt = 0; fcnt < 12; fcnt++) {
+ _logoOvls[fcnt] = ovlFile.decompressFile(fcnt);
+ if (fcnt > 0)
+ for (uint32 cnt = 0; cnt < 640 * 400; cnt++)
+ if (_logoOvls[fcnt - 1][cnt] && !_logoOvls[fcnt][cnt])
+ _logoOvls[fcnt][cnt] = _logoOvls[fcnt - 1][cnt];
+ }
+ uint8 *pal = ovlFile.fetchFile(12);
+ _introPal = (OverlayColor*)malloc(256 * sizeof(OverlayColor));
+ for (uint16 cnt = 0; cnt < 256; cnt++)
+ _introPal[cnt] = _sys->RGBToColor(pal[cnt * 3 + 0], pal[cnt * 3 + 1], pal[cnt * 3 + 2]);
+ }
+#endif
+
+ return true;
+}
+
+SplittedAudioStream::SplittedAudioStream(void) {
+ _queue = NULL;
+}
+
+SplittedAudioStream::~SplittedAudioStream(void) {
+ while (_queue) {
+ delete _queue->stream;
+ FileQueue *que = _queue->next;
+ delete _queue;
+ _queue = que;
+ }
+}
+
+int SplittedAudioStream::getRate(void) const {
+ if (_queue)
+ return _queue->stream->getRate();
+ else
+ return 22050;
+}
+
+void SplittedAudioStream::appendStream(AudioStream *stream) {
+ FileQueue **que = &_queue;
+ while (*que)
+ que = &((*que)->next);
+ *que = new FileQueue;
+ (*que)->stream = stream;
+ (*que)->next = NULL;
+}
+
+bool SplittedAudioStream::endOfData(void) const {
+ if (_queue)
+ return _queue->stream->endOfData();
+ else
+ return true;
+}
+
+bool SplittedAudioStream::isStereo(void) const {
+ if (_queue)
+ return _queue->stream->isStereo();
+ else
+ return false; // all the BS1 files are mono, anyways.
+}
+
+int SplittedAudioStream::readBuffer(int16 *buffer, const int numSamples) {
+ int retVal = 0;
+ int needSamples = numSamples;
+ while (needSamples && _queue) {
+ int retSmp = _queue->stream->readBuffer(buffer, needSamples);
+ needSamples -= retSmp;
+ retVal += retSmp;
+ buffer += retSmp;
+ if (_queue->stream->endOfData()) {
+ delete _queue->stream;
+ FileQueue *que = _queue->next;
+ delete _queue;
+ _queue = que;
+ }
+ }
+ return retVal;
+}
+
+const char * MoviePlayer::_sequenceList[20] = {
+ "ferrari", // 0 CD2 ferrari running down fitz in sc19
+ "ladder", // 1 CD2 george walking down ladder to dig sc24->sc$
+ "steps", // 2 CD2 george walking down steps sc23->sc24
+ "sewer", // 3 CD1 george entering sewer sc2->sc6
+ "intro", // 4 CD1 intro sequence ->sc1
+ "river", // 5 CD1 george being thrown into river by flap & g$
+ "truck", // 6 CD2 truck arriving at bull's head sc45->sc53/4
+ "grave", // 7 BOTH george's grave in scotland, from sc73 + from sc38 $
+ "montfcon", // 8 CD2 monfaucon clue in ireland dig, sc25
+ "tapestry", // 9 CD2 tapestry room beyond spain well, sc61
+ "ireland", // 10 CD2 ireland establishing shot europe_map->sc19
+ "finale", // 11 CD2 grand finale at very end, from sc73
+ "history", // 12 CD1 George's history lesson from Nico, in sc10
+ "spanish", // 13 CD2 establishing shot for 1st visit to Spain, europe_m$
+ "well", // 14 CD2 first time being lowered down well in Spai$
+ "candle", // 15 CD2 Candle burning down in Spain mausoleum sc59
+ "geodrop", // 16 CD2 from sc54, George jumping down onto truck
+ "vulture", // 17 CD2 from sc54, vultures circling George's dead body
+ "enddemo", // 18 --- for end of single CD demo
+ "credits", // 19 CD2 credits, to follow "finale" sequence
+};
+
+} // End of namespace Sword1
diff --git a/engines/sword1/animation.h b/engines/sword1/animation.h
new file mode 100644
index 0000000000..2200212384
--- /dev/null
+++ b/engines/sword1/animation.h
@@ -0,0 +1,120 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2004-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 ANIMATION_H
+#define ANIMATION_H
+
+#include "graphics/animation.h"
+
+#include "sword1/screen.h"
+#include "sword1/sound.h"
+#include "sound/audiostream.h"
+
+namespace Sword1 {
+
+enum {
+ SEQ_FERRARI = 0,
+ SEQ_LADDER,
+ SEQ_STEPS,
+ SEQ_SEWER,
+ SEQ_INTRO,
+ SEQ_RIVER,
+ SEQ_TRUCK,
+ SEQ_GRAVE,
+ SEQ_MONTFCON,
+ SEQ_TAPESTRY,
+ SEQ_IRELAND,
+ SEQ_FINALE,
+ SEQ_HISTORY,
+ SEQ_SPANISH,
+ SEQ_WELL,
+ SEQ_CANDLE,
+ SEQ_GEODROP,
+ SEQ_VULTURE,
+ SEQ_ENDDEMO,
+ SEQ_CREDITS
+};
+
+#define INTRO_LOGO_OVLS 12
+#define INTRO_TEXT_OVLS 8
+
+class AnimationState : public Graphics::BaseAnimationState {
+private:
+ Screen *_scr;
+
+public:
+ AnimationState(Screen *scr, Audio::Mixer *snd, OSystem *sys);
+ ~AnimationState();
+ void updateScreen();
+ OverlayColor *giveRgbBuffer(void);
+ bool soundFinished();
+
+private:
+ void drawYUV(int width, int height, byte *const *dat);
+
+#ifdef BACKEND_8BIT
+ void setPalette(byte *pal);
+#endif
+
+protected:
+ virtual AudioStream *createAudioStream(const char *name, void *arg);
+};
+
+class MoviePlayer {
+public:
+ MoviePlayer(Screen *scr, Audio::Mixer *snd, OSystem *sys);
+ ~MoviePlayer(void);
+ void play(uint32 id);
+private:
+ void insertOverlay(OverlayColor *buf, uint8 *ovl, OverlayColor *pal);
+ void processFrame(uint32 animId, AnimationState *anim, uint32 frameNo);
+ bool initOverlays(uint32 id);
+ Screen *_scr;
+ Audio::Mixer *_snd;
+ OSystem *_sys;
+
+ static const char *_sequenceList[20];
+ uint8 *_logoOvls[INTRO_LOGO_OVLS];
+ OverlayColor *_introPal;
+};
+
+struct FileQueue {
+ AudioStream *stream;
+ FileQueue *next;
+};
+
+class SplittedAudioStream : public AudioStream {
+public:
+ SplittedAudioStream(void);
+ ~SplittedAudioStream(void);
+ void appendStream(AudioStream *stream);
+ virtual int readBuffer(int16 *buffer, const int numSamples);
+ virtual bool isStereo(void) const;
+ virtual bool endOfData(void) const;
+ virtual int getRate(void) const;
+private:
+ FileQueue *_queue;
+};
+
+} // End of namespace Sword1
+
+#endif
diff --git a/engines/sword1/collision.h b/engines/sword1/collision.h
new file mode 100644
index 0000000000..0795298ec6
--- /dev/null
+++ b/engines/sword1/collision.h
@@ -0,0 +1,50 @@
+/* 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 BSCOLLISION_H
+#define BSCOLLISION_H
+
+/*#include "objectman.h"
+
+namespace Sword1 {
+
+class Logic;
+
+class Collision {
+public:
+ Collision(ObjectMan *pObjMan, Logic *pLogic);
+ ~Collision(void);
+ void checkCollisions(void);
+ void fnBumpOff(void);
+ void fnBumpOn(void);
+private:
+ int32 getIntersect(int32 x0, int32 y0, int32 x1, int32 y1, int32 x2, int32 y2, int32 x3, int32 y3);
+ int noCol;
+ ObjectMan *_objMan;
+ Logic *_logic; // for CFN_preset_script
+};
+
+} // End of namespace Sword1
+*/
+// maybe it's better to make this part of Router
+
+#endif // BSCOLLISION_H
diff --git a/engines/sword1/control.cpp b/engines/sword1/control.cpp
new file mode 100644
index 0000000000..bf101e9638
--- /dev/null
+++ b/engines/sword1/control.cpp
@@ -0,0 +1,1301 @@
+/* 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/savefile.h"
+#include "common/system.h"
+
+#include "gui/message.h"
+
+#include "sword1/control.h"
+#include "sword1/logic.h"
+#include "sword1/mouse.h"
+#include "sword1/music.h"
+#include "sword1/objectman.h"
+#include "sword1/resman.h"
+#include "sword1/sound.h"
+#include "sword1/sword1.h"
+#include "sword1/sworddefs.h"
+#include "sword1/swordres.h"
+
+namespace Sword1 {
+
+enum {
+ kKeyRepeatInitialDelay = 400,
+ kKeyRepeatSustainDelay = 100
+};
+
+enum LangStrings {
+ STR_PAUSED = 0,
+ STR_INSERT_CD_A,
+ STR_INSERT_CD_B,
+ STR_INCORRECT_CD,
+ STR_SAVE,
+ STR_RESTORE,
+ STR_RESTART,
+ STR_START,
+ STR_QUIT,
+ STR_SPEED,
+ STR_VOLUME,
+ STR_TEXT,
+ STR_DONE,
+ STR_OK,
+ STR_CANCEL,
+ STR_MUSIC,
+ STR_SPEECH,
+ STR_FX,
+ STR_THE_END,
+ STR_DRIVE_FULL
+};
+
+enum ButtonIds {
+ BUTTON_DONE = 1,
+ BUTTON_MAIN_PANEL,
+ BUTTON_SAVE_PANEL,
+ BUTTON_RESTORE_PANEL,
+ BUTTON_RESTART,
+ BUTTON_QUIT,
+ BUTTON_SPEED,
+ BUTTON_VOLUME_PANEL,
+ BUTTON_TEXT,
+ BUTTON_CONFIRM,
+//-
+ BUTTON_SCROLL_UP_FAST,
+ BUTTON_SCROLL_UP_SLOW,
+ BUTTON_SCROLL_DOWN_SLOW,
+ BUTTON_SCROLL_DOWN_FAST,
+ BUTTON_SAVE_SELECT1,
+ BUTTON_SAVE_SELECT2,
+ BUTTON_SAVE_SELECT3,
+ BUTTON_SAVE_SELECT4,
+ BUTTON_SAVE_SELECT5,
+ BUTTON_SAVE_SELECT6,
+ BUTTON_SAVE_SELECT7,
+ BUTTON_SAVE_SELECT8,
+ BUTTON_SAVE_RESTORE_OKAY,
+ BUTTON_SAVE_CANCEL,
+//-
+ CONFIRM_OKAY,
+ CONFIRM_CANCEL
+};
+
+enum TextModes {
+ TEXT_LEFT_ALIGN = 0,
+ TEXT_CENTER,
+ TEXT_RIGHT_ALIGN,
+ TEXT_RED_FONT = 128
+};
+
+ControlButton::ControlButton(uint16 x, uint16 y, uint32 resId, uint8 id, uint8 flag, ResMan *pResMan, uint8 *screenBuf, OSystem *system) {
+ _x = x;
+ _y = y;
+ _id = id;
+ _flag = flag;
+ _resId = resId;
+ _resMan = pResMan;
+ _frameIdx = 0;
+ _resMan->resOpen(_resId);
+ FrameHeader *tmp = _resMan->fetchFrame(_resMan->fetchRes(_resId), 0);
+ _width = FROM_LE_16(tmp->width);
+ _height = FROM_LE_16(tmp->height);
+ if ((x == 0) && (y == 0)) { // center the frame (used for panels);
+ _x = (640 - _width) / 2;
+ _y = (480 - _height) / 2;
+ }
+ _dstBuf = screenBuf + _y * SCREEN_WIDTH + _x;
+ _system = system;
+}
+
+ControlButton::~ControlButton(void) {
+ _resMan->resClose(_resId);
+}
+
+bool ControlButton::isSaveslot(void) {
+ return ((_resId >= SR_SLAB1) && (_resId <= SR_SLAB4));
+}
+
+void ControlButton::draw(void) {
+ FrameHeader *fHead = _resMan->fetchFrame(_resMan->fetchRes(_resId), _frameIdx);
+ uint8 *src = (uint8*)fHead + sizeof(FrameHeader);
+ uint8 *dst = _dstBuf;
+ for (uint16 cnt = 0; cnt < FROM_LE_16(fHead->height); cnt++) {
+ for (uint16 cntx = 0; cntx < FROM_LE_16(fHead->width); cntx++)
+ if (src[cntx])
+ dst[cntx] = src[cntx];
+ dst += SCREEN_WIDTH;
+ src += FROM_LE_16(fHead->width);
+ }
+ _system->copyRectToScreen(_dstBuf, SCREEN_WIDTH, _x, _y, _width, _height);
+}
+
+bool ControlButton::wasClicked(uint16 mouseX, uint16 mouseY) {
+ if ((_x <= mouseX) && (_y <= mouseY) && (_x + _width >= mouseX) && (_y + _height >= mouseY))
+ return true;
+ else
+ return false;
+}
+
+void ControlButton::setSelected(uint8 selected) {
+ _frameIdx = selected;
+ draw();
+}
+
+Control::Control(Common::SaveFileManager *saveFileMan, ResMan *pResMan, ObjectMan *pObjMan, OSystem *system, Mouse *pMouse, Sound *pSound, Music *pMusic) {
+ _saveFileMan = saveFileMan;
+ _resMan = pResMan;
+ _objMan = pObjMan;
+ _system = system;
+ _mouse = pMouse;
+ _music = pMusic;
+ _sound = pSound;
+ _lStrings = _languageStrings + SwordEngine::_systemVars.language * 20;
+ _keyRepeat = 0;
+ _keyRepeatTime = 0;
+}
+
+void Control::askForCd(void) {
+ _screenBuf = (uint8*)malloc(640 * 480);
+ uint32 fontId = SR_FONT;
+ if (SwordEngine::_systemVars.language == BS1_CZECH)
+ fontId = CZECH_SR_FONT;
+ _font = (uint8*)_resMan->openFetchRes(fontId);
+ uint8 *pal = (uint8*)_resMan->openFetchRes(SR_PALETTE);
+ uint8 *palOut = (uint8*)malloc(256 * 4);
+ for (uint16 cnt = 1; cnt < 256; cnt++) {
+ palOut[cnt * 4 + 0] = pal[cnt * 3 + 0] << 2;
+ palOut[cnt * 4 + 1] = pal[cnt * 3 + 1] << 2;
+ palOut[cnt * 4 + 2] = pal[cnt * 3 + 2] << 2;
+ }
+ palOut[0] = palOut[1] = palOut[2] = palOut[3] = 0;
+ _resMan->resClose(SR_PALETTE);
+ _system->setPalette(palOut, 0, 256);
+ free(palOut);
+
+ Common::File test;
+ char fName[10];
+ uint8 textA[50];
+ sprintf(fName, "cd%d.id", SwordEngine::_systemVars.currentCD);
+ sprintf((char*)textA, "%s%d", _lStrings[STR_INSERT_CD_A], SwordEngine::_systemVars.currentCD);
+ bool notAccepted = true;
+ bool refreshText = true;
+ do {
+ if (refreshText) {
+ memset(_screenBuf, 0, 640 * 480);
+ renderText(textA, 320, 220, TEXT_CENTER);
+ renderText(_lStrings[STR_INSERT_CD_B], 320, 240, TEXT_CENTER);
+ _system->copyRectToScreen(_screenBuf, 640, 0, 0, 640, 480);
+ _system->updateScreen();
+ }
+ delay(300);
+ if (_keyPressed) {
+ test.open(fName);
+ if (!test.isOpen()) {
+ memset(_screenBuf, 0, 640 * 480);
+ renderText(_lStrings[STR_INCORRECT_CD], 320, 230, TEXT_CENTER);
+ _system->copyRectToScreen(_screenBuf, 640, 0, 0, 640, 480);
+ _system->updateScreen();
+ delay(2000);
+ refreshText = true;
+ } else {
+ test.close();
+ notAccepted = false;
+ }
+ }
+ } while (notAccepted && (!SwordEngine::_systemVars.engineQuit));
+
+ _resMan->resClose(fontId);
+ free(_screenBuf);
+}
+
+uint8 Control::runPanel(void) {
+ _mouseDown = false;
+ _restoreBuf = NULL;
+ _keyPressed = _numButtons = 0;
+ _screenBuf = (uint8*)malloc(640 * 480);
+ memset(_screenBuf, 0, 640 * 480);
+ _system->copyRectToScreen(_screenBuf, 640, 0, 0, 640, 480);
+ _sound->quitScreen();
+
+ uint32 fontId = SR_FONT, redFontId = SR_REDFONT;
+ if (SwordEngine::_systemVars.language == BS1_CZECH) {
+ fontId = CZECH_SR_FONT;
+ redFontId = CZECH_SR_REDFONT;
+ }
+ _font = (uint8*)_resMan->openFetchRes(fontId);
+ _redFont = (uint8*)_resMan->openFetchRes(redFontId);
+
+ uint8 *pal = (uint8*)_resMan->openFetchRes(SR_PALETTE);
+ uint8 *palOut = (uint8*)malloc(256 * 4);
+ for (uint16 cnt = 1; cnt < 256; cnt++) {
+ palOut[cnt * 4 + 0] = pal[cnt * 3 + 0] << 2;
+ palOut[cnt * 4 + 1] = pal[cnt * 3 + 1] << 2;
+ palOut[cnt * 4 + 2] = pal[cnt * 3 + 2] << 2;
+ }
+ palOut[0] = palOut[1] = palOut[2] = palOut[3] = 0;
+ _resMan->resClose(SR_PALETTE);
+ _system->setPalette(palOut, 0, 256);
+ free(palOut);
+ uint8 mode = 0, newMode = BUTTON_MAIN_PANEL;
+ bool fullRefresh = false;
+ _mouse->controlPanel(true);
+ uint8 retVal = CONTROL_NOTHING_DONE;
+ _music->startMusic(61, 1);
+
+ do {
+ if (newMode) {
+ mode = newMode;
+ fullRefresh = true;
+ destroyButtons();
+ memset(_screenBuf, 0, 640 * 480);
+ if (mode != BUTTON_SAVE_PANEL)
+ _cursorVisible = false;
+ }
+ switch (mode) {
+ case BUTTON_MAIN_PANEL:
+ if (fullRefresh)
+ setupMainPanel();
+ break;
+ case BUTTON_SAVE_PANEL:
+ if (fullRefresh) {
+ setupSaveRestorePanel(true);
+ }
+ if (_selectedSavegame < 255) {
+ _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true);
+ bool visible = _cursorVisible;
+ _cursorTick++;
+ if (_cursorTick == 7)
+ _cursorVisible = true;
+ else if (_cursorTick == 14) {
+ _cursorVisible = false;
+ _cursorTick = 0;
+ }
+ if (_keyPressed)
+ handleSaveKey(_keyPressed);
+ else if (_cursorVisible != visible)
+ showSavegameNames();
+ } else {
+ _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
+ }
+ break;
+ case BUTTON_RESTORE_PANEL:
+ if (fullRefresh)
+ setupSaveRestorePanel(false);
+ break;
+ case BUTTON_VOLUME_PANEL:
+ if (fullRefresh)
+ setupVolumePanel();
+ break;
+ default:
+ break;
+ }
+ if (fullRefresh) {
+ fullRefresh = false;
+ _system->copyRectToScreen(_screenBuf, SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, 480);
+ }
+ _system->updateScreen();
+ delay(1000 / 12);
+ newMode = getClicks(mode, &retVal);
+ } while ((newMode != BUTTON_DONE) && (retVal == 0) && (!SwordEngine::_systemVars.engineQuit));
+ destroyButtons();
+ _resMan->resClose(fontId);
+ _resMan->resClose(redFontId);
+ memset(_screenBuf, 0, 640 * 480);
+ _system->copyRectToScreen(_screenBuf, 640, 0, 0, 640, 480);
+ free(_screenBuf);
+ _mouse->controlPanel(false);
+ _music->startMusic(Logic::_scriptVars[CURRENT_MUSIC], 1);
+ return retVal;
+}
+
+uint8 Control::getClicks(uint8 mode, uint8 *retVal) {
+ uint8 checkButtons = _numButtons;
+ if (mode == BUTTON_VOLUME_PANEL) {
+ handleVolumeClicks();
+ checkButtons = 1;
+ }
+
+ uint8 flag = 0;
+ if (_keyPressed == 27)
+ flag = kButtonCancel;
+ else if (_keyPressed == '\r' || _keyPressed == '\n')
+ flag = kButtonOk;
+
+ if (flag) {
+ for (uint8 cnt = 0; cnt < checkButtons; cnt++)
+ if (_buttons[cnt]->_flag == flag)
+ return handleButtonClick(_buttons[cnt]->_id, mode, retVal);
+ }
+
+ if (!_mouseState)
+ return 0;
+ if (_mouseState & BS1L_BUTTON_DOWN)
+ for (uint8 cnt = 0; cnt < checkButtons; cnt++)
+ if (_buttons[cnt]->wasClicked(_mouseX, _mouseY)) {
+ _selectedButton = cnt;
+ _buttons[cnt]->setSelected(1);
+ if (_buttons[cnt]->isSaveslot())
+ showSavegameNames();
+ }
+ if (_mouseState & BS1L_BUTTON_UP) {
+ for (uint8 cnt = 0; cnt < checkButtons; cnt++)
+ if (_buttons[cnt]->wasClicked(_mouseX, _mouseY))
+ if (_selectedButton == cnt) {
+ // saveslots stay selected after clicking
+ if (!_buttons[cnt]->isSaveslot())
+ _buttons[cnt]->setSelected(0);
+ _selectedButton = 255;
+ return handleButtonClick(_buttons[cnt]->_id, mode, retVal);
+ }
+ if (_selectedButton < checkButtons) {
+ _buttons[_selectedButton]->setSelected(0);
+ if (_buttons[_selectedButton]->isSaveslot())
+ showSavegameNames();
+ }
+ _selectedButton = 255;
+ }
+ if (_mouseState & BS1_WHEEL_UP) {
+ for (uint8 cnt = 0; cnt < checkButtons; cnt++)
+ if (_buttons[cnt]->_id == BUTTON_SCROLL_UP_SLOW)
+ return handleButtonClick(_buttons[cnt]->_id, mode, retVal);
+ }
+ if (_mouseState & BS1_WHEEL_DOWN) {
+ for (uint8 cnt = 0; cnt < checkButtons; cnt++)
+ if (_buttons[cnt]->_id == BUTTON_SCROLL_DOWN_SLOW)
+ return handleButtonClick(_buttons[cnt]->_id, mode, retVal);
+ }
+ return 0;
+}
+
+uint8 Control::handleButtonClick(uint8 id, uint8 mode, uint8 *retVal) {
+ switch (mode) {
+ case BUTTON_MAIN_PANEL:
+ if (id == BUTTON_RESTART) {
+ if (SwordEngine::_systemVars.controlPanelMode) // if player is dead or has just started, don't ask for confirmation
+ *retVal |= CONTROL_RESTART_GAME;
+ else if (getConfirm(_lStrings[STR_RESTART]))
+ *retVal |= CONTROL_RESTART_GAME;
+ else
+ return mode;
+ } else if ((id == BUTTON_RESTORE_PANEL) || (id == BUTTON_SAVE_PANEL) ||
+ (id == BUTTON_DONE) || (id == BUTTON_VOLUME_PANEL))
+ return id;
+ else if (id == BUTTON_TEXT) {
+ SwordEngine::_systemVars.showText ^= 1;
+ _buttons[5]->setSelected(SwordEngine::_systemVars.showText);
+ } else if (id == BUTTON_QUIT) {
+ if (getConfirm(_lStrings[STR_QUIT]))
+ SwordEngine::_systemVars.engineQuit = true;
+ return mode;
+ }
+ break;
+ case BUTTON_SAVE_PANEL:
+ case BUTTON_RESTORE_PANEL:
+ if ((id >= BUTTON_SCROLL_UP_FAST) && (id <= BUTTON_SCROLL_DOWN_FAST))
+ saveNameScroll(id, mode == BUTTON_SAVE_PANEL);
+ else if ((id >= BUTTON_SAVE_SELECT1) && (id <= BUTTON_SAVE_SELECT8))
+ saveNameSelect(id, mode == BUTTON_SAVE_PANEL);
+ else if (id == BUTTON_SAVE_RESTORE_OKAY) {
+ if (mode == BUTTON_SAVE_PANEL) {
+ _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
+ if (saveToFile()) // don't go back to main panel if save fails.
+ return BUTTON_DONE;
+ } else {
+ if (restoreFromFile()) { // don't go back to main panel if restore fails.
+ *retVal |= CONTROL_GAME_RESTORED;
+ return BUTTON_MAIN_PANEL;
+ }
+ }
+ } else if (id == BUTTON_SAVE_CANCEL) {
+ _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
+ return BUTTON_MAIN_PANEL; // mode down to main panel
+ }
+ break;
+ case BUTTON_VOLUME_PANEL:
+ return id;
+ }
+ return 0;
+}
+
+void Control::deselectSaveslots(void) {
+ for (uint8 cnt = 0; cnt < 8; cnt++)
+ _buttons[cnt]->setSelected(0);
+}
+
+void Control::setupMainPanel(void) {
+ uint32 panelId;
+
+ if (SwordEngine::_systemVars.controlPanelMode == CP_DEATHSCREEN)
+ panelId = SR_DEATHPANEL;
+ else {
+ if (SwordEngine::_systemVars.language <= BS1_SPANISH)
+ panelId = SR_PANEL_ENGLISH + SwordEngine::_systemVars.language;
+ else
+ panelId = SR_PANEL_ENGLISH;
+ }
+
+ ControlButton *panel = new ControlButton(0, 0, panelId, 0, 0, _resMan, _screenBuf, _system);
+ panel->draw();
+ delete panel;
+
+ if (SwordEngine::_systemVars.controlPanelMode != CP_NORMAL)
+ createButtons(_deathButtons, 3);
+ else {
+ createButtons(_panelButtons, 7);
+ _buttons[5]->setSelected(SwordEngine::_systemVars.showText);
+ }
+
+ if (SwordEngine::_systemVars.controlPanelMode == CP_THEEND) // end of game
+ renderText(_lStrings[STR_THE_END], 480, 188 + 40, TEXT_RIGHT_ALIGN);
+
+ if (SwordEngine::_systemVars.controlPanelMode == CP_NORMAL) { // normal panel
+ renderText(_lStrings[STR_SAVE], 180, 188 + 40, TEXT_LEFT_ALIGN);
+ renderText(_lStrings[STR_DONE], 460, 332 + 40, TEXT_RIGHT_ALIGN);
+ renderText(_lStrings[STR_RESTORE], 180, 224 + 40, TEXT_LEFT_ALIGN);
+ renderText(_lStrings[STR_RESTART], 180, 260 + 40, TEXT_LEFT_ALIGN);
+ renderText(_lStrings[STR_QUIT], 180, 296 + 40, TEXT_LEFT_ALIGN);
+
+ renderText(_lStrings[STR_VOLUME], 460, 188 + 40, TEXT_RIGHT_ALIGN);
+ renderText(_lStrings[STR_TEXT], 460, 224 + 40, TEXT_RIGHT_ALIGN);
+ } else {
+ renderText(_lStrings[STR_RESTORE], 285, 224 + 40, TEXT_LEFT_ALIGN);
+ if (SwordEngine::_systemVars.controlPanelMode == CP_NEWGAME) // just started game
+ renderText(_lStrings[STR_START], 285, 260 + 40, TEXT_LEFT_ALIGN);
+ else
+ renderText(_lStrings[STR_RESTART], 285, 260 + 40, TEXT_LEFT_ALIGN);
+ renderText(_lStrings[STR_QUIT], 285, 296 + 40, TEXT_LEFT_ALIGN);
+ }
+}
+
+void Control::setupSaveRestorePanel(bool saving) {
+ FrameHeader *savePanel = _resMan->fetchFrame(_resMan->openFetchRes(SR_WINDOW), 0);
+ uint16 panelX = (640 - FROM_LE_16(savePanel->width)) / 2;
+ uint16 panelY = (480 - FROM_LE_16(savePanel->height)) / 2;
+ ControlButton *panel = new ControlButton(panelX, panelY, SR_WINDOW, 0, 0, _resMan, _screenBuf, _system);
+ panel->draw();
+ delete panel;
+ _resMan->resClose(SR_WINDOW);
+ createButtons(_saveButtons, 14);
+ renderText(_lStrings[STR_CANCEL], _saveButtons[13].x - 10, _saveButtons[13].y, TEXT_RIGHT_ALIGN);
+ if (saving) {
+ renderText(_lStrings[STR_SAVE], _saveButtons[12].x + 30, _saveButtons[13].y, TEXT_LEFT_ALIGN);
+ } else {
+ renderText(_lStrings[STR_RESTORE], _saveButtons[12].x + 30, _saveButtons[13].y, TEXT_LEFT_ALIGN);
+ }
+ readSavegameDescriptions();
+ _selectedSavegame = 255;
+ showSavegameNames();
+}
+
+void Control::setupVolumePanel(void) {
+ ControlButton *panel = new ControlButton(0, 0, SR_VOLUME, 0, 0, _resMan, _screenBuf, _system);
+ panel->draw();
+ delete panel;
+
+ renderText(_lStrings[STR_MUSIC], 149, 39 + 40, TEXT_LEFT_ALIGN);
+ renderText(_lStrings[STR_SPEECH], 320, 39 + 40, TEXT_CENTER);
+ renderText(_lStrings[STR_FX], 438, 39 + 40, TEXT_LEFT_ALIGN);
+
+ createButtons(_volumeButtons, 4);
+ renderText(_lStrings[STR_DONE], _volumeButtons[0].x - 10, _volumeButtons[0].y, TEXT_RIGHT_ALIGN);
+
+ uint8 volL, volR;
+ _music->giveVolume(&volL, &volR);
+ renderVolumeBar(1, volL, volR);
+ _sound->giveSpeechVol(&volL, &volR);
+ renderVolumeBar(2, volL, volR);
+ _sound->giveSfxVol(&volL, &volR);
+ renderVolumeBar(3, volL, volR);
+}
+
+void Control::handleVolumeClicks(void) {
+ if (_mouseDown) {
+ uint8 clickedId = 0;
+ for (uint8 cnt = 1; cnt < 4; cnt++)
+ if (_buttons[cnt]->wasClicked(_mouseX, _mouseY))
+ clickedId = cnt;
+ if (clickedId) { // these are circle shaped, so check again if it was clicked.
+ uint8 clickDest = 0;
+ int16 mouseDiffX = _mouseX - (_volumeButtons[clickedId].x + 48);
+ int16 mouseDiffY = _mouseY - (_volumeButtons[clickedId].y + 48);
+ int16 mouseOffs = (int16)sqrt((double)(mouseDiffX * mouseDiffX + mouseDiffY * mouseDiffY));
+ // check if the player really hit the button (but not the center).
+ if ((mouseOffs <= 42) && (mouseOffs >= 8)) {
+ if (mouseDiffX > 8) { // right part
+ if (mouseDiffY < -8) // upper right
+ clickDest = 2;
+ else if (ABS(mouseDiffY) <= 8) // right
+ clickDest = 3;
+ else // lower right
+ clickDest = 4;
+ } else if (mouseDiffX < -8) { // left part
+ if (mouseDiffY < -8) // upper left
+ clickDest = 8;
+ else if (ABS(mouseDiffY) <= 8) // left
+ clickDest = 7;
+ else // lower left
+ clickDest = 6;
+ } else { // middle
+ if (mouseDiffY < -8)
+ clickDest = 1; // upper
+ else if (mouseDiffY > 8)
+ clickDest = 5; // lower
+ }
+ }
+ _buttons[clickedId]->setSelected(clickDest);
+ changeVolume(clickedId, clickDest);
+ }
+ } else if (_mouseState & BS1L_BUTTON_UP) {
+ _buttons[1]->setSelected(0);
+ _buttons[2]->setSelected(0);
+ _buttons[3]->setSelected(0);
+ }
+}
+
+void Control::changeVolume(uint8 id, uint8 action) {
+ // ids: 1 = music, 2 = speech, 3 = sfx
+ uint8 volL = 0, volR = 0;
+ if (id == 1)
+ _music->giveVolume(&volL, &volR);
+ else if (id == 2)
+ _sound->giveSpeechVol(&volL, &volR);
+ else if (id == 3)
+ _sound->giveSfxVol(&volL, &volR);
+
+ int8 direction = 0;
+ if ((action >= 4) && (action <= 6)) // lower part of the button => decrease volume
+ direction = -1;
+ else if ((action == 8) || (action == 1) || (action == 2)) // upper part => increase volume
+ direction = 1;
+ else if ((action == 3) || (action == 7)) // middle part => pan volume
+ direction = 1;
+ int8 factorL = 8, factorR = 8;
+ if ((action >= 6) && (action <= 8)) { // left part => left pan
+ factorL = 8;
+ factorR = (action == 7) ? -8 : 0;
+ } else if ((action >= 2) && (action <= 4)) { // right part
+ factorR = 8;
+ factorL = (action == 3) ? -8 : 0;
+ }
+ int16 resVolL = volL + direction * factorL;
+ int16 resVolR = volR + direction * factorR;
+
+ volL = (uint8)MAX((int16)0, MIN(resVolL, (int16)255));
+ volR = (uint8)MAX((int16)0, MIN(resVolR, (int16)255));
+
+ if (id == 1)
+ _music->setVolume(volL, volR);
+ else if (id == 2)
+ _sound->setSpeechVol(volL, volR);
+ else if (id == 3)
+ _sound->setSfxVol(volL, volR);
+
+ renderVolumeBar(id, volL, volR);
+}
+
+bool Control::getConfirm(const uint8 *title) {
+ ControlButton *panel = new ControlButton(0, 0, SR_CONFIRM, 0, 0, _resMan, _screenBuf, _system);
+ panel->draw();
+ delete panel;
+ renderText(title, 320, 160, TEXT_CENTER);
+ ControlButton *buttons[2];
+ buttons[0] = new ControlButton(260, 192 + 40, SR_BUTTON, 0, 0, _resMan, _screenBuf, _system);
+ renderText(_lStrings[STR_OK], 640 - 260, 192 + 40, TEXT_RIGHT_ALIGN);
+ buttons[1] = new ControlButton(260, 256 + 40, SR_BUTTON, 0, 0, _resMan, _screenBuf, _system);
+ renderText(_lStrings[STR_CANCEL], 640 - 260, 256 + 40, TEXT_RIGHT_ALIGN);
+ uint8 retVal = 0;
+ uint8 clickVal = 0;
+ do {
+ buttons[0]->draw();
+ buttons[1]->draw();
+ _system->updateScreen();
+ delay(1000 / 12);
+ if (_keyPressed == 27)
+ retVal = 2;
+ else if (_keyPressed == '\r' || _keyPressed == '\n')
+ retVal = 1;
+ if (_mouseState & BS1L_BUTTON_DOWN) {
+ if (buttons[0]->wasClicked(_mouseX, _mouseY))
+ clickVal = 1;
+ else if (buttons[1]->wasClicked(_mouseX, _mouseY))
+ clickVal = 2;
+ else
+ clickVal = 0;
+ if (clickVal)
+ buttons[clickVal - 1]->setSelected(1);
+ }
+ if ((_mouseState & BS1L_BUTTON_UP) && (clickVal)) {
+ if (buttons[clickVal - 1]->wasClicked(_mouseX, _mouseY))
+ retVal = clickVal;
+ else
+ buttons[clickVal - 1]->setSelected(0);
+ clickVal = 0;
+ }
+ } while (!retVal);
+ delete buttons[0];
+ delete buttons[1];
+ return retVal == 1;
+}
+
+bool Control::keyAccepted(uint8 key) {
+ // this routine needs changes for Czech keys... No idea how to do that, though.
+ // FIXME: It is not a good idea to put non-ASCII chars into a C source file,
+ // since there is no way to specify which encoding you are using.
+ // It is better to encode them as hex/octal. Although in this particular
+ // case, it seems questionable to do this at all, since we currently
+ // do not at all specify which encoding keyboard events use, so this
+ // check here is probably not portable anyway...
+ static const char allowedSpecials[] = "éèáàúùäöüÄÖÜß,.:-()?! \"\'";
+ if (((key >= 'A') && (key <= 'Z')) ||
+ ((key >= 'a') && (key <= 'z')) ||
+ ((key >= '0') && (key <= '9')) ||
+ strchr(allowedSpecials, key))
+ return true;
+ else
+ return false;
+}
+
+void Control::handleSaveKey(uint8 key) {
+ if (_selectedSavegame < 255) {
+ uint8 len = strlen((char*)_saveNames[_selectedSavegame]);
+ if ((key == 8) && len) // backspace
+ _saveNames[_selectedSavegame][len - 1] = '\0';
+ else if (keyAccepted(key) && (len < 31)) {
+ _saveNames[_selectedSavegame][len] = key;
+ _saveNames[_selectedSavegame][len + 1] = '\0';
+ }
+ showSavegameNames();
+ }
+}
+
+bool Control::saveToFile(void) {
+ if ((_selectedSavegame == 255) || !strlen((char*)_saveNames[_selectedSavegame]))
+ return false; // no saveslot selected or no name entered
+ saveGameToFile(_selectedSavegame);
+ writeSavegameDescriptions();
+ return true;
+}
+
+bool Control::restoreFromFile(void) {
+ if (_selectedSavegame < 255) {
+ return restoreGameFromFile(_selectedSavegame);
+ } else
+ return false;
+}
+
+void Control::readSavegameDescriptions(void) {
+ Common::InSaveFile *inf;
+ inf = _saveFileMan->openForLoading("SAVEGAME.INF");
+ _saveScrollPos = _saveFiles = 0;
+ _selectedSavegame = 255;
+ if (inf) {
+ uint8 curFileNum = 0;
+ uint8 ch;
+ do {
+ uint8 pos = 0;
+ do {
+ ch = inf->readByte();
+ if ((ch == 10) || (ch == 255))
+ _saveNames[curFileNum][pos] = '\0';
+ else
+ _saveNames[curFileNum][pos] = ch;
+ pos++;
+ } while ((ch != 10) && (ch != 255));
+ curFileNum++;
+ } while (ch != 255);
+ _saveFiles = curFileNum;
+ for (uint8 cnt = _saveFiles; cnt < 64; cnt++)
+ _saveNames[cnt][0] = '\0';
+ } else
+ for (uint8 cnt = 0; cnt < 64; cnt++)
+ _saveNames[cnt][0] = '\0';
+ delete inf;
+}
+
+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();
+ _mouse->setPointer(MSE_POINTER, 0);
+ return result;
+}
+
+void Control::writeSavegameDescriptions(void) {
+ Common::OutSaveFile *outf;
+ outf = _saveFileMan->openForSaving("SAVEGAME.INF");
+
+ if (!outf) {
+ // Display an error message, and do nothing
+ displayMessage(0, "Can't create SAVEGAME.INF in directory '%s'", _saveFileMan->getSavePath());
+ return;
+ }
+
+ // if the player accidently clicked the last slot and then deselected it again,
+ // we'd still have _saveFiles == 64, so get rid of the empty end.
+ while (strlen((char*)_saveNames[_saveFiles - 1]) == 0)
+ _saveFiles--;
+ for (uint8 cnt = 0; cnt < _saveFiles; cnt++) {
+ int len = strlen((char*)_saveNames[cnt]);
+ if (len > 0)
+ outf->write(_saveNames[cnt], len);
+ if (cnt < _saveFiles - 1)
+ outf->writeByte(10);
+ else
+ outf->writeByte(255);
+ }
+ outf->flush();
+ if (outf->ioFailed())
+ displayMessage(0, "Can't write to SAVEGAME.INF in directory '%s'. Device full?", _saveFileMan->getSavePath());
+ delete outf;
+}
+
+bool Control::savegamesExist(void) {
+ bool retVal = false;
+ Common::InSaveFile *inf;
+ inf = _saveFileMan->openForLoading("SAVEGAME.INF");
+ if (inf)
+ retVal = true;
+ delete inf;
+ return retVal;
+}
+
+void Control::showSavegameNames(void) {
+ for (uint8 cnt = 0; cnt < 8; cnt++) {
+ _buttons[cnt]->draw();
+ uint8 textMode = TEXT_LEFT_ALIGN;
+ uint16 ycoord = _saveButtons[cnt].y + 2;
+ uint8 str[40];
+ sprintf((char*)str, "%d. %s", cnt + _saveScrollPos + 1, _saveNames[cnt + _saveScrollPos]);
+ if (cnt + _saveScrollPos == _selectedSavegame) {
+ textMode |= TEXT_RED_FONT;
+ ycoord += 2;
+ if (_cursorVisible)
+ strcat((char*)str, "_");
+ }
+ renderText(str, _saveButtons[cnt].x + 6, ycoord, textMode);
+ }
+}
+
+void Control::saveNameSelect(uint8 id, bool saving) {
+ deselectSaveslots();
+ _buttons[id - BUTTON_SAVE_SELECT1]->setSelected(1);
+ uint8 num = (id - BUTTON_SAVE_SELECT1) + _saveScrollPos;
+ if (saving && (_selectedSavegame != 255)) // the player may have entered something, clear it again
+ strcpy((char*)_saveNames[_selectedSavegame], (char*)_oldName);
+ if (num < _saveFiles) {
+ _selectedSavegame = num;
+ strcpy((char*)_oldName, (char*)_saveNames[num]); // save for later
+ } else {
+ if (!saving)
+ _buttons[id - BUTTON_SAVE_SELECT1]->setSelected(0); // no save in slot, deselect it
+ else {
+ if (_saveFiles <= num)
+ _saveFiles = num + 1;
+ _selectedSavegame = num;
+ _oldName[0] = '\0';
+ }
+ }
+ if (_selectedSavegame < 255)
+ _cursorTick = 0;
+ showSavegameNames();
+}
+
+void Control::saveNameScroll(uint8 scroll, bool saving) {
+ uint16 maxScroll;
+ if (saving)
+ maxScroll = 64;
+ else
+ maxScroll = _saveFiles; // for loading, we can only scroll as far as there are savegames
+ if (scroll == BUTTON_SCROLL_UP_FAST) {
+ if (_saveScrollPos >= 8)
+ _saveScrollPos -= 8;
+ else
+ _saveScrollPos = 0;
+ } else if (scroll == BUTTON_SCROLL_UP_SLOW) {
+ if (_saveScrollPos >= 1)
+ _saveScrollPos--;
+ } else if (scroll == BUTTON_SCROLL_DOWN_SLOW) {
+ if (_saveScrollPos + 8 < maxScroll)
+ _saveScrollPos++;
+ } else if (scroll == BUTTON_SCROLL_DOWN_FAST) {
+ if (_saveScrollPos + 16 < maxScroll)
+ _saveScrollPos += 8;
+ else {
+ if (maxScroll >= 8)
+ _saveScrollPos = maxScroll - 8;
+ else
+ _saveScrollPos = 0;
+ }
+ }
+ _selectedSavegame = 255; // deselect savegame
+ deselectSaveslots();
+ showSavegameNames();
+}
+
+void Control::createButtons(const ButtonInfo *buttons, uint8 num) {
+ for (uint8 cnt = 0; cnt < num; cnt++) {
+ _buttons[cnt] = new ControlButton(buttons[cnt].x, buttons[cnt].y, buttons[cnt].resId, buttons[cnt].id, buttons[cnt].flag, _resMan, _screenBuf, _system);
+ _buttons[cnt]->draw();
+ }
+ _numButtons = num;
+}
+
+void Control::destroyButtons(void) {
+ for (uint8 cnt = 0; cnt < _numButtons; cnt++)
+ delete _buttons[cnt];
+ _numButtons = 0;
+}
+
+uint16 Control::getTextWidth(const uint8 *str) {
+ uint16 width = 0;
+ while (*str) {
+ width += FROM_LE_16(_resMan->fetchFrame(_font, *str - 32)->width) - 3;
+ str++;
+ }
+ return width;
+}
+
+void Control::renderText(const uint8 *str, uint16 x, uint16 y, uint8 mode) {
+ uint8 *font = _font;
+ if (mode & TEXT_RED_FONT) {
+ mode &= ~TEXT_RED_FONT;
+ font = _redFont;
+ }
+
+ if (mode == TEXT_RIGHT_ALIGN) // negative x coordinate means right-aligned.
+ x -= getTextWidth(str);
+ else if (mode == TEXT_CENTER)
+ x -= getTextWidth(str) / 2;
+
+ uint16 destX = x;
+ while (*str) {
+ uint8 *dst = _screenBuf + y * SCREEN_WIDTH + destX;
+
+ FrameHeader *chSpr = _resMan->fetchFrame(font, *str - 32);
+ uint8 *sprData = (uint8*)chSpr + sizeof(FrameHeader);
+ for (uint16 cnty = 0; cnty < FROM_LE_16(chSpr->height); cnty++) {
+ for (uint16 cntx = 0; cntx < FROM_LE_16(chSpr->width); cntx++) {
+ if (sprData[cntx])
+ dst[cntx] = sprData[cntx];
+ }
+ sprData += FROM_LE_16(chSpr->width);
+ dst += SCREEN_WIDTH;
+ }
+ destX += FROM_LE_16(chSpr->width) - 3;
+ str++;
+ }
+ _system->copyRectToScreen(_screenBuf + y * SCREEN_WIDTH + x, SCREEN_WIDTH, x, y, (destX - x) + 3, 28);
+}
+
+void Control::renderVolumeBar(uint8 id, uint8 volL, uint8 volR) {
+ uint16 destX = _volumeButtons[id].x + 20;
+ uint16 destY = _volumeButtons[id].y + 116;
+
+ for (uint8 chCnt = 0; chCnt < 2; chCnt++) {
+ uint8 vol = (chCnt == 0) ? volL : volR;
+ FrameHeader *frHead = _resMan->fetchFrame(_resMan->openFetchRes(SR_VLIGHT), (vol + 15) >> 4);
+ uint8 *destMem = _screenBuf + destY * SCREEN_WIDTH + destX;
+ uint8 *srcMem = (uint8*)frHead + sizeof(FrameHeader);
+ for (uint16 cnty = 0; cnty < FROM_LE_16(frHead->height); cnty++) {
+ memcpy(destMem, srcMem, FROM_LE_16(frHead->width));
+ srcMem += FROM_LE_16(frHead->width);
+ destMem += SCREEN_WIDTH;
+ }
+ _system->copyRectToScreen(_screenBuf + destY * SCREEN_WIDTH + destX, SCREEN_WIDTH, destX, destY, FROM_LE_16(frHead->width), FROM_LE_16(frHead->height));
+ _resMan->resClose(SR_VLIGHT);
+ destX += 32;
+ }
+}
+
+void Control::saveGameToFile(uint8 slot) {
+ char fName[15];
+ uint16 cnt;
+ sprintf(fName, "SAVEGAME.%03d", slot);
+ uint16 liveBuf[TOTAL_SECTIONS];
+ Common::OutSaveFile *outf;
+ outf = _saveFileMan->openForSaving(fName);
+ if (!outf) {
+ // Display an error message and do nothing
+ displayMessage(0, "Unable to create file '%s' in directory '%s'", fName, _saveFileMan->getSavePath());
+ return;
+ }
+
+ _objMan->saveLiveList(liveBuf);
+ for (cnt = 0; cnt < TOTAL_SECTIONS; cnt++)
+ outf->writeUint16LE(liveBuf[cnt]);
+
+ Object *cpt = _objMan->fetchObject(PLAYER);
+ Logic::_scriptVars[CHANGE_DIR] = cpt->o_dir;
+ Logic::_scriptVars[CHANGE_X] = cpt->o_xcoord;
+ Logic::_scriptVars[CHANGE_Y] = cpt->o_ycoord;
+ Logic::_scriptVars[CHANGE_STANCE] = STAND;
+ Logic::_scriptVars[CHANGE_PLACE] = cpt->o_place;
+
+ for (cnt = 0; cnt < NUM_SCRIPT_VARS; cnt++)
+ outf->writeUint32LE(Logic::_scriptVars[cnt]);
+
+ uint32 playerSize = (sizeof(Object) - 12000) / 4;
+ uint32 *playerRaw = (uint32*)cpt;
+ for (uint32 cnt2 = 0; cnt2 < playerSize; cnt2++)
+ outf->writeUint32LE(playerRaw[cnt2]);
+ outf->flush();
+ if (outf->ioFailed())
+ displayMessage(0, "Couldn't write to file '%s' in directory '%s'. Device full?", fName, _saveFileMan->getSavePath());
+ delete outf;
+}
+
+bool Control::restoreGameFromFile(uint8 slot) {
+ char fName[15];
+ uint16 cnt;
+ sprintf(fName, "SAVEGAME.%03d", slot);
+ Common::InSaveFile *inf;
+ inf = _saveFileMan->openForLoading(fName);
+ if (!inf) {
+ // Display an error message, and do nothing
+ displayMessage(0, "Can't open file '%s' in directory '%s'", fName, _saveFileMan->getSavePath());
+ return false;
+ }
+
+ _restoreBuf = (uint8*)malloc(
+ TOTAL_SECTIONS * 2 +
+ NUM_SCRIPT_VARS * 4 +
+ (sizeof(Object) - 12000));
+
+ uint16 *liveBuf = (uint16*)_restoreBuf;
+ uint32 *scriptBuf = (uint32*)(_restoreBuf + 2 * TOTAL_SECTIONS);
+ uint32 *playerBuf = (uint32*)(_restoreBuf + 2 * TOTAL_SECTIONS + 4 * NUM_SCRIPT_VARS);
+
+ for (cnt = 0; cnt < TOTAL_SECTIONS; cnt++)
+ liveBuf[cnt] = inf->readUint16LE();
+
+ for (cnt = 0; cnt < NUM_SCRIPT_VARS; cnt++)
+ scriptBuf[cnt] = inf->readUint32LE();
+
+ uint32 playerSize = (sizeof(Object) - 12000) / 4;
+ for (uint32 cnt2 = 0; cnt2 < playerSize; cnt2++)
+ playerBuf[cnt2] = inf->readUint32LE();
+
+ if (inf->ioFailed()) {
+ displayMessage(0, "Can't read from file '%s' in directory '%s'", fName, _saveFileMan->getSavePath());
+ delete inf;
+ free(_restoreBuf);
+ _restoreBuf = NULL;
+ return false;
+ }
+ delete inf;
+ return true;
+}
+
+void Control::doRestore(void) {
+ uint8 *bufPos = _restoreBuf;
+ _objMan->loadLiveList((uint16*)bufPos);
+ bufPos += TOTAL_SECTIONS * 2;
+ for (uint16 cnt = 0; cnt < NUM_SCRIPT_VARS; cnt++) {
+ Logic::_scriptVars[cnt] = *(uint32*)bufPos;
+ bufPos += 4;
+ }
+ uint32 playerSize = (sizeof(Object) - 12000) / 4;
+ uint32 *playerRaw = (uint32*)_objMan->fetchObject(PLAYER);
+ Object *cpt = _objMan->fetchObject(PLAYER);
+ for (uint32 cnt2 = 0; cnt2 < playerSize; cnt2++) {
+ *playerRaw = *(uint32*)bufPos;
+ playerRaw++;
+ bufPos += 4;
+ }
+ free(_restoreBuf);
+ Logic::_scriptVars[CHANGE_DIR] = cpt->o_dir;
+ Logic::_scriptVars[CHANGE_X] = cpt->o_xcoord;
+ Logic::_scriptVars[CHANGE_Y] = cpt->o_ycoord;
+ Logic::_scriptVars[CHANGE_STANCE] = STAND;
+ Logic::_scriptVars[CHANGE_PLACE] = cpt->o_place;
+ SwordEngine::_systemVars.justRestoredGame = 1;
+ if (SwordEngine::_systemVars.isDemo)
+ Logic::_scriptVars[PLAYINGDEMO] = 1;
+}
+
+void Control::delay(uint32 msecs) {
+ OSystem::Event event;
+
+ uint32 now = _system->getMillis();
+ uint32 endTime = now + msecs;
+ _keyPressed = 0; //reset
+ _mouseState = 0;
+
+ 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;
+ _keyRepeatTime = now + kKeyRepeatInitialDelay;
+ _keyRepeat = _keyPressed;
+ // we skip the rest of the delay and return immediately
+ // to handle keyboard input
+ return;
+ case OSystem::EVENT_KEYUP:
+ _keyRepeatTime = 0;
+ _keyRepeat = 0;
+ break;
+ case OSystem::EVENT_MOUSEMOVE:
+ _mouseX = event.mouse.x;
+ _mouseY = event.mouse.y;
+ break;
+ case OSystem::EVENT_LBUTTONDOWN:
+ _mouseDown = true;
+ _mouseState |= BS1L_BUTTON_DOWN;
+#if defined(_WIN32_WCE) || defined(PALMOS_MODE)
+ _mouseX = event.mouse.x;
+ _mouseY = event.mouse.y;
+#endif
+ break;
+ case OSystem::EVENT_LBUTTONUP:
+ _mouseDown = false;
+ _mouseState |= BS1L_BUTTON_UP;
+ break;
+ case OSystem::EVENT_WHEELUP:
+ _mouseDown = false;
+ _mouseState |= BS1_WHEEL_UP;
+ break;
+ case OSystem::EVENT_WHEELDOWN:
+ _mouseDown = false;
+ _mouseState |= BS1_WHEEL_DOWN;
+ break;
+ case OSystem::EVENT_QUIT:
+ SwordEngine::_systemVars.engineQuit = true;
+ break;
+ default:
+ break;
+ }
+ }
+ if (_keyRepeatTime && now > _keyRepeatTime) {
+ _keyRepeatTime += kKeyRepeatSustainDelay;
+ _keyPressed = _keyRepeat;
+ }
+
+ _system->delayMillis(10);
+ } while (_system->getMillis() < endTime);
+}
+
+const ButtonInfo Control::_deathButtons[3] = {
+ {250, 224 + 40, SR_BUTTON, BUTTON_RESTORE_PANEL, 0 },
+ {250, 260 + 40, SR_BUTTON, BUTTON_RESTART, kButtonOk },
+ {250, 296 + 40, SR_BUTTON, BUTTON_QUIT, kButtonCancel }
+};
+
+const ButtonInfo Control::_panelButtons[7] = {
+ {145, 188 + 40, SR_BUTTON, BUTTON_SAVE_PANEL, 0 },
+ {145, 224 + 40, SR_BUTTON, BUTTON_RESTORE_PANEL, 0 },
+ {145, 260 + 40, SR_BUTTON, BUTTON_RESTART, 0 },
+ {145, 296 + 40, SR_BUTTON, BUTTON_QUIT, kButtonCancel },
+ {475, 188 + 40, SR_BUTTON, BUTTON_VOLUME_PANEL, 0 },
+ {475, 224 + 40, SR_TEXT_BUTTON, BUTTON_TEXT, 0 },
+ {475, 332 + 40, SR_BUTTON, BUTTON_DONE, kButtonOk }
+};
+
+const ButtonInfo Control::_saveButtons[16] = {
+ {114, 32 + 40, SR_SLAB1, BUTTON_SAVE_SELECT1, 0 },
+ {114, 68 + 40, SR_SLAB2, BUTTON_SAVE_SELECT2, 0 },
+ {114, 104 + 40, SR_SLAB3, BUTTON_SAVE_SELECT3, 0 },
+ {114, 140 + 40, SR_SLAB4, BUTTON_SAVE_SELECT4, 0 },
+ {114, 176 + 40, SR_SLAB1, BUTTON_SAVE_SELECT5, 0 },
+ {114, 212 + 40, SR_SLAB2, BUTTON_SAVE_SELECT6, 0 },
+ {114, 248 + 40, SR_SLAB3, BUTTON_SAVE_SELECT7, 0 },
+ {114, 284 + 40, SR_SLAB4, BUTTON_SAVE_SELECT8, 0 },
+
+ {516, 25 + 40, SR_BUTUF, BUTTON_SCROLL_UP_FAST, 0 },
+ {516, 45 + 40, SR_BUTUS, BUTTON_SCROLL_UP_SLOW, 0 },
+ {516, 289 + 40, SR_BUTDS, BUTTON_SCROLL_DOWN_SLOW, 0 },
+ {516, 310 + 40, SR_BUTDF, BUTTON_SCROLL_DOWN_FAST, 0 },
+
+ {125, 338 + 40, SR_BUTTON, BUTTON_SAVE_RESTORE_OKAY, kButtonOk},
+ {462, 338 + 40, SR_BUTTON, BUTTON_SAVE_CANCEL, kButtonCancel }
+};
+
+const ButtonInfo Control::_volumeButtons[4] = {
+ { 478, 338 + 40, SR_BUTTON, BUTTON_MAIN_PANEL, kButtonOk },
+ { 138, 135, SR_VKNOB, 0, 0 },
+ { 273, 135, SR_VKNOB, 0, 0 },
+ { 404, 135, SR_VKNOB, 0, 0 },
+};
+
+const uint8 Control::_languageStrings[8 * 20][43] = {
+ // BS1_ENGLISH:
+ "PAUSED",
+ "PLEASE INSERT CD-",
+ "THEN PRESS A KEY",
+ "INCORRECT CD",
+ "Save",
+ "Restore",
+ "Restart",
+ "Start",
+ "Quit",
+ "Speed",
+ "Volume",
+ "Text",
+ "Done",
+ "OK",
+ "Cancel",
+ "Music",
+ "Speech",
+ "Fx",
+ "The End",
+ "DRIVE FULL!",
+// BS1_FRENCH:
+ "PAUSE",
+ "INS\xC9REZ LE CD-",
+ "ET APPUYES SUR UNE TOUCHE",
+ "CD INCORRECT",
+ "Sauvegarder",
+ "Recharger",
+ "Recommencer",
+ "Commencer",
+ "Quitter",
+ "Vitesse",
+ "Volume",
+ "Texte",
+ "Termin\xE9",
+ "OK",
+ "Annuler",
+ "Musique",
+ "Voix",
+ "Fx",
+ "Fin",
+ "DISQUE PLEIN!",
+//BS1_GERMAN:
+ "PAUSE",
+ "BITTE LEGEN SIE CD-",
+ "EIN UND DR\xDC CKEN SIE EINE BELIEBIGE TASTE",
+ "FALSCHE CD",
+ "Speichern",
+ "Laden",
+ "Neues Spiel",
+ "Start",
+ "Beenden",
+ "Geschwindigkeit",
+ "Lautst\xE4rke",
+ "Text",
+ "Fertig",
+ "OK",
+ "Abbrechen",
+ "Musik",
+ "Sprache",
+ "Fx",
+ "Ende",
+ "DRIVE FULL!",
+//BS1_ITALIAN:
+ "PAUSA",
+ "INSERITE IL CD-",
+ "E PREMETE UN TASTO",
+ "CD ERRATO",
+ "Salva",
+ "Ripristina",
+ "Ricomincia",
+ "Inizio",
+ "Esci",
+ "Velocit\xE0",
+ "Volume",
+ "Testo",
+ "Fatto",
+ "OK",
+ "Annula",
+ "Musica",
+ "Parlato",
+ "Fx",
+ "Fine",
+ "DISCO PIENO!",
+//BS1_SPANISH:
+ "PAUSA",
+ "POR FAVOR INTRODUCE EL CD-",
+ "Y PULSA UNA TECLA",
+ "CD INCORRECTO",
+ "Guardar",
+ "Recuperar",
+ "Reiniciar",
+ "Empezar",
+ "Abandonar",
+ "Velocidad",
+ "Volumen",
+ "Texto",
+ "Hecho",
+ "OK",
+ "Cancelar",
+ "M\xFAsica",
+ "Di\xE1logo",
+ "Fx",
+ "Fin",
+ "DISCO LLENO",
+// BS1_CZECH:
+ "\xAC\x41S SE ZASTAVIL",
+ "VLO\xA6TE DO MECHANIKY CD DISK",
+ "PAK STISKN\xB7TE LIBOVOLNOU KL\xB5VESU",
+ "TO NEBUDE TO SPR\xB5VN\x90 CD",
+ "Ulo\xA7it pozici",
+ "Nahr\xA0t pozici",
+ "Za\x9F\xA1t znovu",
+ "Start",
+ "Ukon\x9Fit hru",
+ "Rychlost",
+ "Hlasitost",
+ "Titulky",
+ "Souhlas\xA1m",
+ "Ano",
+ "Ne",
+ "Hudba",
+ "Mluven, slovo",
+ "Zvuky",
+ "Konec",
+ "Disk pln\xEC",
+//BS1_PORTUGESE:
+ "PAUSA",
+ "FAVOR INSERIR CD",
+ "E DIGITAR UMA TECLA",
+ "CD INCORRETO",
+ "Salvar",
+ "Restaurar",
+ "Reiniciar",
+ "Iniciar",
+ "Sair",
+ "Velocidade",
+ "Volume",
+ "Texto",
+ "Feito",
+ "OK",
+ "Cancelar",
+ "M\xFAsica",
+ "Voz",
+ "Efeitos",
+ "Fim",
+ "UNIDADE CHEIA!",
+};
+
+} // End of namespace Sword1
diff --git a/engines/sword1/control.h b/engines/sword1/control.h
new file mode 100644
index 0000000000..b1f81165be
--- /dev/null
+++ b/engines/sword1/control.h
@@ -0,0 +1,152 @@
+/* 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 BSCONTROL_H
+#define BSCONTROL_H
+
+#include "common/scummsys.h"
+#include "sword1/sworddefs.h"
+
+class OSystem;
+namespace Common {
+ class SaveFileManager;
+}
+
+namespace Sword1 {
+
+class ObjectMan;
+class ResMan;
+class Mouse;
+class Music;
+class Sound;
+
+#define MAX_BUTTONS 16
+
+#define CONTROL_NOTHING_DONE 0
+#define CONTROL_GAME_RESTORED 1
+#define CONTROL_RESTART_GAME 2
+
+class ControlButton {
+public:
+ ControlButton(uint16 x, uint16 y, uint32 resId, uint8 id, uint8 flag, ResMan *pResMan, uint8 *screenBuf, OSystem *system);
+ ~ControlButton(void);
+ void draw(void);
+ bool wasClicked(uint16 mouseX, uint16 mouseY);
+ void setSelected(uint8 selected);
+ bool isSaveslot(void);
+ uint8 _id;
+ uint8 _flag;
+private:
+ int _frameIdx;
+ uint16 _x, _y;
+ uint16 _width, _height;
+ uint32 _resId;
+ ResMan *_resMan;
+ uint8 *_dstBuf;
+ OSystem *_system;
+};
+
+enum {
+ kButtonOk = 1,
+ kButtonCancel = 2
+};
+
+struct ButtonInfo {
+ uint16 x, y;
+ uint32 resId, id;
+ uint8 flag;
+};
+
+class Control {
+public:
+ Control(Common::SaveFileManager *saveFileMan, ResMan *pResMan, ObjectMan *pObjMan, OSystem *system, Mouse *pMouse, Sound *pSound, Music *pMusic);
+ uint8 runPanel(void);
+ void doRestore(void);
+ void askForCd(void);
+ bool savegamesExist(void);
+private:
+ int displayMessage(const char *altButton, const char *message, ...);
+
+ void saveGameToFile(uint8 slot);
+ bool restoreGameFromFile(uint8 slot);
+ void readSavegameDescriptions(void);
+ void writeSavegameDescriptions(void);
+ void showSavegameNames(void);
+ void deselectSaveslots(void);
+ uint8 *_restoreBuf;
+ uint8 _saveFiles;
+ uint8 _saveScrollPos;
+ uint8 _selectedSavegame;
+ uint8 _saveNames[64][32];
+ uint8 _oldName[32];
+ uint8 _cursorTick;
+ bool _cursorVisible;
+
+ uint8 getClicks(uint8 mode, uint8 *retVal);
+ uint8 handleButtonClick(uint8 id, uint8 mode, uint8 *retVal);
+ void handleVolumeClicks(void);
+ void changeVolume(uint8 id, uint8 action);
+
+ void setupMainPanel(void);
+ void setupSaveRestorePanel(bool saving);
+ void setupVolumePanel(void);
+ bool getConfirm(const uint8 *title);
+
+ void saveNameScroll(uint8 scroll, bool saving);
+ void saveNameSelect(uint8 id, bool saving);
+ bool saveToFile(void);
+ bool restoreFromFile(void);
+ bool keyAccepted(uint8 key);
+ void handleSaveKey(uint8 key);
+
+ void renderVolumeBar(uint8 id, uint8 volL, uint8 volR);
+ uint16 getTextWidth(const uint8 *str);
+ void renderText(const uint8 *str, uint16 x, uint16 y, uint8 mode);
+ uint8 _numButtons;
+ uint8 _selectedButton;
+ void createButtons(const ButtonInfo *buttons, uint8 num);
+ void destroyButtons(void);
+ ControlButton *_buttons[MAX_BUTTONS];
+ static const ButtonInfo _deathButtons[3], _panelButtons[7], _saveButtons[16], _volumeButtons[4];
+ static const uint8 _languageStrings[8 * 20][43];
+ const uint8 (*_lStrings)[43];
+ Common::SaveFileManager *_saveFileMan;
+ ObjectMan *_objMan;
+ ResMan *_resMan;
+ OSystem *_system;
+ Mouse *_mouse;
+ Music *_music;
+ Sound *_sound;
+ uint8 *_font, *_redFont;
+ uint8 *_screenBuf;
+ uint8 _keyPressed;
+ uint8 _keyRepeat;
+ uint32 _keyRepeatTime;
+ void delay(uint32 msecs);
+ uint16 _mouseX, _mouseY, _mouseState;
+ bool _mouseDown;
+};
+
+} // End of namespace Sword1
+
+#endif //BSCONTROL_H
+
diff --git a/engines/sword1/credits.cpp b/engines/sword1/credits.cpp
new file mode 100644
index 0000000000..117430b96f
--- /dev/null
+++ b/engines/sword1/credits.cpp
@@ -0,0 +1,346 @@
+/* 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 "sword1/credits.h"
+#include "sword1/screen.h"
+#include "sword1/sword1.h"
+
+#include "sound/audiostream.h"
+#include "sound/mixer.h"
+
+#include "common/file.h"
+#include "common/util.h"
+#include "common/system.h"
+
+
+#define CREDITS_X 480
+#define CREDITS_Y 300
+#define BUFSIZE_Y 640
+
+#define START_X ((640 - CREDITS_X) / 2)
+#define START_Y ((480 - CREDITS_Y) / 2)
+
+#define SCROLL_TIMING (2000 / 59) // 29.5 frames per second
+
+#define LOGO_FADEUP_TIME (133 * 1000)
+#define LOGO_FADEDOWN_TIME (163 * 1000)
+
+namespace Sword1 {
+
+enum {
+ FONT_PAL = 0,
+ FONT,
+ TEXT,
+ REVO_PAL,
+ REVO_LOGO,
+ F_EOF
+};
+
+enum {
+ FNT_LFT = 0, // left column
+ FNT_RGT, // right column
+ FNT_CEN, // centered
+ FNT_BIG = 64, // big font
+ FNT_EOL = 128, // linebreak
+ FNT_EOB = 255 // end of textblock
+};
+
+
+CreditsPlayer::CreditsPlayer(OSystem *pSystem, Audio::Mixer *pMixer) {
+ _system = pSystem;
+ _mixer = pMixer;
+ _smlFont = _bigFont = NULL;
+}
+
+bool spaceInBuf(uint16 blitSta, uint16 blitEnd, uint16 renderDest) {
+ if (blitEnd > blitSta) {
+ if ((renderDest > blitEnd) || (renderDest + 15 < blitSta))
+ return true;
+ } else {
+ if ((renderDest > blitEnd) && (renderDest + 15 < blitSta))
+ return true;
+ }
+ return false;
+}
+
+void CreditsPlayer::play(void) {
+ AudioStream *bgSoundStream = AudioStream::openStreamFile("credits");
+ if (bgSoundStream == NULL) {
+ warning("\"credits.ogg\" not found, skipping credits sequence");
+ return;
+ }
+ ArcFile credFile;
+ if (!credFile.open("credits.dat")) {
+ warning("\"credits.dat\" not found, skipping credits sequence");
+ return;
+ }
+
+ uint8 *palSrc = credFile.fetchFile(FONT_PAL, &_palLen);
+ for (uint32 cnt = 0; cnt < _palLen; cnt++)
+ _palette[(cnt / 3) * 4 + cnt % 3] = palSrc[cnt];
+ _palLen /= 3;
+
+ generateFonts(&credFile);
+
+ uint8 *textData = credFile.fetchFile(TEXT);
+ textData += READ_LE_UINT32(textData + SwordEngine::_systemVars.language * 4);
+
+ uint8 *screenBuf = (uint8*)malloc(CREDITS_X * BUFSIZE_Y);
+ memset(screenBuf, 0, CREDITS_X * BUFSIZE_Y);
+ _system->copyRectToScreen(screenBuf, 640, 0, 0, 640, 480);
+ _system->setPalette(_palette, 0, _palLen);
+ _system->updateScreen();
+
+ // everything's initialized, time to render and show the credits.
+ Audio::SoundHandle bgSound;
+ _mixer->playInputStream(Audio::Mixer::kMusicSoundType, &bgSound, bgSoundStream, 0);
+
+ int relDelay = 0;
+ uint16 scrollY = 0;
+ uint16 renderY = BUFSIZE_Y / 2;
+ uint16 clearY = 0xFFFF;
+ bool clearLine = false;
+ while (((*textData != FNT_EOB) || (scrollY != renderY)) && !SwordEngine::_systemVars.engineQuit) {
+ if ((int32)_mixer->getSoundElapsedTime(bgSound) - relDelay < (SCROLL_TIMING * 2)) { // sync to audio
+ if (scrollY < BUFSIZE_Y - CREDITS_Y)
+ _system->copyRectToScreen(screenBuf + scrollY * CREDITS_X, CREDITS_X, START_X, START_Y, CREDITS_X, CREDITS_Y);
+ else {
+ _system->copyRectToScreen(screenBuf + scrollY * CREDITS_X, CREDITS_X, START_X, START_Y, CREDITS_X, BUFSIZE_Y - scrollY);
+ _system->copyRectToScreen(screenBuf, CREDITS_X, START_X, START_Y + BUFSIZE_Y - scrollY, CREDITS_X, CREDITS_Y - (BUFSIZE_Y - scrollY));
+ }
+ _system->updateScreen();
+ } else
+ warning("frame skipped");
+
+ while (spaceInBuf(scrollY, (scrollY + CREDITS_Y) % BUFSIZE_Y, renderY) && (*textData != FNT_EOB)) {
+ if (*textData & FNT_EOL) {
+ renderY = (renderY + 16) % BUFSIZE_Y; // linebreak
+ clearLine = true;
+ *textData &= ~FNT_EOL;
+ }
+ if (spaceInBuf(scrollY, (scrollY + CREDITS_Y) % BUFSIZE_Y, renderY)) {
+ if (clearLine)
+ memset(screenBuf + renderY * CREDITS_X, 0, 16 * CREDITS_X);
+ clearLine = false;
+ renderLine(screenBuf, textData + 1, renderY, *textData);
+ if (*textData & FNT_BIG)
+ renderY += 16;
+ while (*++textData != 0) // search for the start of next string
+ ;
+ textData++;
+ }
+ if (*textData == FNT_EOB)
+ clearY = renderY;
+ }
+ if ((*textData == FNT_EOB) && spaceInBuf(scrollY, (scrollY + CREDITS_Y) % BUFSIZE_Y, clearY)) {
+ memset(screenBuf + clearY * CREDITS_X, 0, 16 * CREDITS_X);
+ clearY = (clearY + 16) % BUFSIZE_Y;
+ }
+
+ relDelay += SCROLL_TIMING;
+ delay(relDelay - (int32)_mixer->getSoundElapsedTime(bgSound));
+ scrollY = (scrollY + 1) % BUFSIZE_Y;
+ }
+ free(_smlFont);
+ free(_bigFont);
+ _smlFont = _bigFont = NULL;
+ free(screenBuf);
+
+ // credits done, now show the revolution logo
+ uint8 *revoBuf = credFile.decompressFile(REVO_LOGO);
+ uint8 *revoPal = credFile.fetchFile(REVO_PAL, &_palLen);
+ _palLen /= 3;
+ while ((_mixer->getSoundElapsedTime(bgSound) < LOGO_FADEUP_TIME) && !SwordEngine::_systemVars.engineQuit) {
+ _system->updateScreen();
+ delay(100);
+ }
+ memset(_palette, 0, 256 * 4);
+ _system->setPalette(_palette, 0, 256);
+ _system->copyRectToScreen(revoBuf, 480, START_X, START_Y, CREDITS_X, CREDITS_Y);
+ _system->updateScreen();
+
+ fadePalette(revoPal, true, _palLen);
+ while ((_mixer->getSoundElapsedTime(bgSound) < LOGO_FADEDOWN_TIME) && !SwordEngine::_systemVars.engineQuit) {
+ _system->updateScreen();
+ delay(100);
+ }
+ fadePalette(revoPal, false, _palLen);
+ delay(3000);
+
+ if (SwordEngine::_systemVars.engineQuit)
+ _mixer->stopAll();
+ free(revoBuf);
+}
+
+void CreditsPlayer::fadePalette(uint8 *srcPal, bool fadeup, uint16 len) {
+ int8 fadeDir = fadeup ? 1 : -1;
+ int fadeStart = fadeup ? 0 : 12;
+
+ int relDelay = _system->getMillis();
+ for (int fadeStep = fadeStart; (fadeStep >= 0) && (fadeStep <= 12) && !SwordEngine::_systemVars.engineQuit; fadeStep += fadeDir) {
+ for (uint16 cnt = 0; cnt < len * 3; cnt++)
+ _palette[(cnt / 3) * 4 + (cnt % 3)] = (srcPal[cnt] * fadeStep) / 12;
+ _system->setPalette(_palette, 0, 256);
+ _system->updateScreen();
+ relDelay += 1000 / 12;
+ delay(relDelay - _system->getMillis());
+ }
+}
+
+void CreditsPlayer::renderLine(uint8 *screenBuf, uint8 *line, uint16 yBufPos, uint8 flags) {
+ uint8 *font;
+ uint16 fntSize = 16;
+ if (flags & FNT_BIG) {
+ font = _bigFont;
+ fntSize = 32;
+ flags &= ~FNT_BIG;
+ } else
+ font = _smlFont;
+
+ uint16 width = getWidth(font, line);
+ uint16 xBufPos = (flags == FNT_CEN) ? (CREDITS_X - width) / 2 : ((flags == FNT_LFT) ? (234 - width) : 255);
+ uint8 *bufDest = screenBuf + yBufPos * CREDITS_X + xBufPos;
+ while (*line) {
+ uint8 *chrSrc = font + _numChars + (*line - 1) * fntSize * fntSize;
+ for (uint16 cnty = 0; cnty < fntSize; cnty++) {
+ for (uint16 cntx = 0; cntx < fntSize; cntx++)
+ bufDest[cnty * CREDITS_X + cntx] = chrSrc[cntx];
+ chrSrc += fntSize;
+ }
+ bufDest += font[*line++ - 1];
+ }
+}
+
+uint16 CreditsPlayer::getWidth(uint8 *font, uint8 *line) {
+ uint16 width = 0;
+ while (*line)
+ width += font[*line++ - 1];
+ return width;
+}
+
+void CreditsPlayer::generateFonts(ArcFile *arcFile) {
+ _bigFont = arcFile->decompressFile(FONT);
+ _numChars = *_bigFont;
+ memmove(_bigFont, _bigFont + 1, _numChars * (32 * 32 + 1));
+ _smlFont = (uint8*)malloc(_numChars * (32 * 32 + 1));
+ uint8 *src = _bigFont + _numChars;
+ uint8 *dst = _smlFont + _numChars;
+ for (uint16 cnt = 0; cnt < _numChars; cnt++) {
+ _smlFont[cnt] = (_bigFont[cnt]++ + 1) / 2; // width table
+ for (uint16 cnty = 0; cnty < 16; cnty++) {
+ for (uint16 cntx = 0; cntx < 16; cntx++) {
+ uint8 resR = (uint8)((_palette[src[0] * 4 + 0] + _palette[src[1] * 4 + 0] + _palette[src[32] * 4 + 0] + _palette[src[33] * 4 + 0]) >> 2);
+ uint8 resG = (uint8)((_palette[src[0] * 4 + 1] + _palette[src[1] * 4 + 1] + _palette[src[32] * 4 + 1] + _palette[src[33] * 4 + 1]) >> 2);
+ uint8 resB = (uint8)((_palette[src[0] * 4 + 2] + _palette[src[1] * 4 + 2] + _palette[src[32] * 4 + 2] + _palette[src[33] * 4 + 2]) >> 2);
+ *dst++ = getPalIdx(resR, resG, resB);
+ src += 2;
+ }
+ src += 32;
+ }
+ }
+}
+
+uint8 CreditsPlayer::getPalIdx(uint8 r, uint8 g, uint8 b) {
+ for (uint16 cnt = 0; cnt < _palLen; cnt++)
+ if ((_palette[cnt * 4 + 0] == r) && (_palette[cnt * 4 + 1] == g) && (_palette[cnt * 4 + 2] == b))
+ return (uint8)cnt;
+ assert(_palLen < 256);
+ _palette[_palLen * 4 + 0] = r;
+ _palette[_palLen * 4 + 1] = g;
+ _palette[_palLen * 4 + 2] = b;
+ return (uint8)_palLen++;
+}
+
+void CreditsPlayer::delay(int msecs) {
+
+ OSystem::Event event;
+ uint32 start = _system->getMillis();
+ do {
+ while (_system->pollEvent(event)) {
+ switch (event.type) {
+ case OSystem::EVENT_QUIT:
+ SwordEngine::_systemVars.engineQuit = true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (msecs > 0)
+ _system->delayMillis(10);
+
+ } while ((_system->getMillis() < start + msecs) && !SwordEngine::_systemVars.engineQuit);
+}
+
+ArcFile::ArcFile(void) {
+ _buf = NULL;
+}
+
+ArcFile::~ArcFile(void) {
+ if (_buf)
+ free(_buf);
+}
+
+bool ArcFile::open(const char *name) {
+ Common::File arc;
+ if (!arc.open(name))
+ return false;
+ _bufPos = _buf = (uint8*)malloc(arc.size());
+ arc.read(_buf, arc.size());
+ arc.close();
+ return true;
+}
+
+void ArcFile::enterPath(uint32 id) {
+ _bufPos += READ_LE_UINT32(_bufPos + id * 4);
+}
+
+uint8 *ArcFile::fetchFile(uint32 fileId, uint32 *size) {
+ if (size)
+ *size = READ_LE_UINT32(_bufPos + (fileId + 1) * 4) - READ_LE_UINT32(_bufPos + fileId * 4);
+ return _bufPos + READ_LE_UINT32(_bufPos + fileId * 4);
+}
+
+uint8 *ArcFile::decompressFile(uint32 fileId) {
+ uint32 size;
+ uint8 *srcBuf = fetchFile(fileId, &size);
+ uint8 *dstBuf = (uint8*)malloc(READ_LE_UINT32(srcBuf));
+ uint8 *srcPos = srcBuf + 4;
+ uint8 *dstPos = dstBuf;
+ while (srcPos < srcBuf + size) {
+ uint16 len = READ_LE_UINT16(srcPos);
+ memset(dstPos, 0, len);
+ dstPos += len;
+ srcPos += 2;
+ if (srcPos < srcBuf + size) {
+ len = *srcPos++;
+ memcpy(dstPos, srcPos, len);
+ dstPos += len;
+ srcPos += len;
+ }
+ }
+ return dstBuf;
+}
+
+} // end of namespace Sword1
diff --git a/engines/sword1/credits.h b/engines/sword1/credits.h
new file mode 100644
index 0000000000..a964744f22
--- /dev/null
+++ b/engines/sword1/credits.h
@@ -0,0 +1,72 @@
+/* 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 BS1CREDITS_H
+#define BS1CREDITS_H
+
+#include "common/util.h"
+
+namespace Audio {
+ class Mixer;
+}
+class OSystem;
+
+namespace Sword1 {
+
+class ArcFile {
+public:
+ ArcFile(void);
+ ~ArcFile(void);
+ bool open(const char *name);
+ uint8 *fetchFile(uint32 fileId, uint32 *size = NULL);
+ uint8 *decompressFile(uint32 fileId);
+ void enterPath(uint32 id);
+ void backToRoot(void) { _bufPos = _buf; };
+private:
+ uint8 *_bufPos;
+ uint8 *_buf;
+};
+
+class CreditsPlayer {
+public:
+ CreditsPlayer(OSystem *pSystem, Audio::Mixer *pMixer);
+ void play(void);
+private:
+ void generateFonts(ArcFile *arcFile);
+ void renderLine(uint8 *screenBuf, uint8 *line, uint16 yBufPos, uint8 flags);
+ void fadePalette(uint8 *srcPal, bool fadeup, uint16 len);
+ void delay(int msecs);
+ uint16 getWidth(uint8 *font, uint8 *line);
+ uint8 getPalIdx(uint8 r, uint8 g, uint8 b);
+ uint8 _palette[256 * 4];
+ uint32 _palLen;
+ uint8 _numChars;
+
+ OSystem *_system;
+ Audio::Mixer *_mixer;
+
+ uint8 *_smlFont, *_bigFont;
+};
+
+} // end of namespace Sword1
+
+#endif // BS1CREDITS_H
diff --git a/engines/sword1/debug.cpp b/engines/sword1/debug.cpp
new file mode 100644
index 0000000000..d5ef5f87da
--- /dev/null
+++ b/engines/sword1/debug.cpp
@@ -0,0 +1,140 @@
+/* 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 "sword1/debug.h"
+
+namespace Sword1 {
+
+void Debug::interpretScript(uint32 id, uint32 level, uint32 script, uint32 pc) {
+ debug(8, "\nInterpreting %d@%d: script %X from %X", id, level, script, pc);
+}
+
+void Debug::callMCode(uint32 mcodeNum, uint32 paramCount, int32 a, int32 b, int32 c, int32 d, int32 e, int32 f) {
+ debug(9, "mcode: %s(%d, %d, %d, %d, %d, %d) [%d]", _mCodeNames[mcodeNum], a, b, c, d, e, f, paramCount);
+}
+
+const char Debug::_mCodeNames[100][35] = {
+ "fnBackground",
+ "fnForeground",
+ "fnSort",
+ "fnNoSprite",
+ "fnMegaSet",
+ "fnAnim",
+ "fnSetFrame",
+ "fnFullAnim",
+ "fnFullSetFrame",
+ "fnFadeDown",
+ "fnFadeUp",
+ "fnCheckFade",
+ "fnSetSpritePalette",
+ "fnSetWholePalette",
+ "fnSetFadeTargetPalette",
+ "fnSetPaletteToFade",
+ "fnSetPaletteToCut",
+ "fnPlaySequence",
+ "fnIdle",
+ "fnPause",
+ "fnPauseSeconds",
+ "fnQuit",
+ "fnKillId",
+ "fnSuicide",
+ "fnNewScript",
+ "fnSubScript",
+ "fnRestartScript",
+ "fnSetBookmark",
+ "fnGotoBookmark",
+ "fnSendSync",
+ "fnWaitSync",
+ "cfnClickInteract",
+ "cfnSetScript",
+ "cfnPresetScript",
+ "fnInteract",
+ "fnIssueEvent",
+ "fnCheckForEvent",
+ "fnWipeHands",
+ "fnISpeak",
+ "fnTheyDo",
+ "fnTheyDoWeWait",
+ "fnWeWait",
+ "fnChangeSpeechText",
+ "fnTalkError",
+ "fnStartTalk",
+ "fnCheckForTextLine",
+ "fnAddTalkWaitStatusBit",
+ "fnRemoveTalkWaitStatusBit",
+ "fnNoHuman",
+ "fnAddHuman",
+ "fnBlankMouse",
+ "fnNormalMouse",
+ "fnLockMouse",
+ "fnUnlockMouse",
+ "fnSetMousePointer",
+ "fnSetMouseLuggage",
+ "fnMouseOn",
+ "fnMouseOff",
+ "fnChooser",
+ "fnEndChooser",
+ "fnStartMenu",
+ "fnEndMenu",
+ "cfnReleaseMenu",
+ "fnAddSubject",
+ "fnAddObject",
+ "fnRemoveObject",
+ "fnEnterSection",
+ "fnLeaveSection",
+ "fnChangeFloor",
+ "fnWalk",
+ "fnTurn",
+ "fnStand",
+ "fnStandAt",
+ "fnFace",
+ "fnFaceXy",
+ "fnIsFacing",
+ "fnGetTo",
+ "fnGetToError",
+ "fnGetPos",
+ "fnGetGamepadXy",
+ "fnPlayFx",
+ "fnStopFx",
+ "fnPlayMusic",
+ "fnStopMusic",
+ "fnInnerSpace",
+ "fnRandom",
+ "fnSetScreen",
+ "fnPreload",
+ "fnCheckCD",
+ "fnRestartGame",
+ "fnQuitGame",
+ "fnDeathScreen",
+ "fnSetParallax",
+ "fnTdebug",
+ "fnRedFlash",
+ "fnBlueFlash",
+ "fnYellow",
+ "fnGreen",
+ "fnPurple",
+ "fnBlack"
+};
+
+} // End of namespace Sword1
diff --git a/engines/sword1/debug.h b/engines/sword1/debug.h
new file mode 100644
index 0000000000..36ddf26973
--- /dev/null
+++ b/engines/sword1/debug.h
@@ -0,0 +1,42 @@
+/* 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 BSDEBUG_H
+#define BSDEBUG_H
+
+#include "common/scummsys.h"
+
+namespace Sword1 {
+
+class Debug {
+public:
+ static void interpretScript(uint32 id, uint32 level, uint32 script, uint32 pc);
+ static void callMCode(uint32 mcodeNum, uint32 paramCount, int32 a, int32 b, int32 c, int32 d, int32 e, int32 f);
+
+private:
+ static const char _mCodeNames[100][35];
+};
+
+} // End of namespace Sword1
+
+#endif // BSDEBUG_H
+
diff --git a/engines/sword1/eventman.cpp b/engines/sword1/eventman.cpp
new file mode 100644
index 0000000000..c13007e8fc
--- /dev/null
+++ b/engines/sword1/eventman.cpp
@@ -0,0 +1,103 @@
+/* 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 "sword1/eventman.h"
+#include "sword1/sworddefs.h"
+#include "common/util.h"
+
+namespace Sword1 {
+
+EventManager::EventManager(void) {
+ for (uint8 cnt = 0; cnt < TOTAL_EVENT_SLOTS; cnt++)
+ _eventPendingList[cnt].delay = _eventPendingList[cnt].eventNumber = 0;
+}
+
+void EventManager::serviceGlobalEventList(void) {
+ for (uint8 slot = 0; slot < TOTAL_EVENT_SLOTS; slot++)
+ if (_eventPendingList[slot].delay)
+ _eventPendingList[slot].delay--;
+}
+
+void EventManager::checkForEvent(Object *compact) {
+ for (uint8 objCnt = 0; objCnt < O_TOTAL_EVENTS; objCnt++) {
+ if (compact->o_event_list[objCnt].o_event)
+ for (uint8 globCnt = 0; globCnt < TOTAL_EVENT_SLOTS; globCnt++) {
+ if (_eventPendingList[globCnt].delay &&
+ (_eventPendingList[globCnt].eventNumber == compact->o_event_list[objCnt].o_event)) {
+ compact->o_logic = LOGIC_script; //force into script mode
+ _eventPendingList[globCnt].delay = 0; //started, so remove from queue
+ compact->o_tree.o_script_level++;
+ compact->o_tree.o_script_id[compact->o_tree.o_script_level] =
+ compact->o_event_list[objCnt].o_event_script;
+ compact->o_tree.o_script_pc[compact->o_tree.o_script_level] =
+ compact->o_event_list[objCnt].o_event_script;
+ }
+ }
+ }
+}
+
+bool EventManager::eventValid(int32 event) {
+ for (uint8 slot = 0; slot < TOTAL_EVENT_SLOTS; slot++)
+ if ((_eventPendingList[slot].eventNumber == event) &&
+ (_eventPendingList[slot].delay))
+ return true;
+ return false;
+}
+
+int EventManager::fnCheckForEvent(Object *cpt, int32 id, int32 pause) {
+ if (pause) {
+ cpt->o_pause = pause;
+ cpt->o_logic = LOGIC_pause_for_event;
+ return SCRIPT_STOP;
+ }
+
+ for (uint8 objCnt = 0; objCnt < O_TOTAL_EVENTS; objCnt++) {
+ if (cpt->o_event_list[objCnt].o_event)
+ for (uint8 globCnt = 0; globCnt < TOTAL_EVENT_SLOTS; globCnt++) {
+ if (_eventPendingList[globCnt].delay &&
+ (_eventPendingList[globCnt].eventNumber == cpt->o_event_list[objCnt].o_event)) {
+ cpt->o_logic = LOGIC_script; //force into script mode
+ _eventPendingList[globCnt].delay = 0; //started, so remove from queue
+ cpt->o_tree.o_script_level++;
+ cpt->o_tree.o_script_id[cpt->o_tree.o_script_level] =
+ cpt->o_event_list[objCnt].o_event_script;
+ cpt->o_tree.o_script_pc[cpt->o_tree.o_script_level] =
+ cpt->o_event_list[objCnt].o_event_script;
+ return SCRIPT_STOP;
+ }
+ }
+ }
+ return SCRIPT_CONT;
+}
+
+void EventManager::fnIssueEvent(Object *compact, int32 id, int32 event, int32 delay) {
+ uint8 evSlot = 0;
+ while (_eventPendingList[evSlot].delay)
+ evSlot++;
+ if (evSlot >= TOTAL_EVENT_SLOTS)
+ error("EventManager ran out of event slots!");
+ _eventPendingList[evSlot].delay = delay;
+ _eventPendingList[evSlot].eventNumber = event;
+}
+
+} // End of namespace Sword1
diff --git a/engines/sword1/eventman.h b/engines/sword1/eventman.h
new file mode 100644
index 0000000000..c04b12e711
--- /dev/null
+++ b/engines/sword1/eventman.h
@@ -0,0 +1,51 @@
+/* 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 BSEVENTMAN_H
+#define BSEVENTMAN_H
+
+#include "sword1/object.h"
+
+namespace Sword1 {
+
+#define TOTAL_EVENT_SLOTS 20
+
+struct GlobalEvent {
+ int32 eventNumber;
+ int32 delay;
+};
+
+class EventManager {
+public:
+ EventManager(void);
+ void serviceGlobalEventList(void);
+ void checkForEvent(Object *compact);
+ int fnCheckForEvent(Object *cpt, int32 id, int32 pause);
+ void fnIssueEvent(Object *compact, int32 id, int32 event, int32 delay);
+ bool eventValid(int32 event);
+private:
+ GlobalEvent _eventPendingList[TOTAL_EVENT_SLOTS];
+};
+
+} // End of namespace Sword1
+
+#endif // BSEVENTMAN_H
diff --git a/engines/sword1/logic.cpp b/engines/sword1/logic.cpp
new file mode 100644
index 0000000000..27108e9e51
--- /dev/null
+++ b/engines/sword1/logic.cpp
@@ -0,0 +1,1803 @@
+/* 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 "sword1/logic.h"
+#include "sword1/text.h"
+#include "sword1/sound.h"
+#include "sword1/eventman.h"
+#include "sword1/menu.h"
+#include "sword1/router.h"
+#include "sword1/screen.h"
+#include "sword1/mouse.h"
+#include "sword1/sword1.h"
+#include "sword1/music.h"
+#include "sword1/swordres.h"
+#include "sword1/animation.h"
+#include "sword1/credits.h"
+
+#include "sword1/debug.h"
+
+#include "gui/message.h"
+
+namespace Sword1 {
+
+#define MAX_STACK_SIZE 10
+#define SCRIPT_VERSION 13
+#define LAST_FRAME 999
+
+uint32 Logic::_scriptVars[NUM_SCRIPT_VARS];
+
+Logic::Logic(ObjectMan *pObjMan, ResMan *resMan, Screen *pScreen, Mouse *pMouse, Sound *pSound, Music *pMusic, Menu *pMenu, OSystem *system, Audio::Mixer *mixer) {
+ _objMan = pObjMan;
+ _resMan = resMan;
+ _screen = pScreen;
+ _mouse = pMouse;
+ _music = pMusic;
+ _sound = pSound;
+ _menu = pMenu;
+ _textMan = NULL;
+ _screen->useTextManager(_textMan);
+ _router = new Router(_objMan, _resMan);
+ _eventMan = NULL;
+ _system = system;
+ _mixer = mixer;
+}
+
+Logic::~Logic(void) {
+ delete _textMan;
+ delete _router;
+ delete _eventMan;
+}
+
+void Logic::initialize(void) {
+ memset(_scriptVars, 0, NUM_SCRIPT_VARS * sizeof(uint32));
+ for (uint8 cnt = 0; cnt < NON_ZERO_SCRIPT_VARS; cnt++)
+ _scriptVars[_scriptVarInit[cnt][0]] = _scriptVarInit[cnt][1];
+ if (SwordEngine::_systemVars.isDemo)
+ _scriptVars[PLAYINGDEMO] = 1;
+
+ delete _eventMan;
+ _eventMan = new EventManager();
+
+ delete _textMan;
+ _textMan = new Text(_objMan, _resMan,
+ (SwordEngine::_systemVars.language == BS1_CZECH) ? true : false);
+ _screen->useTextManager(_textMan);
+ _textRunning = _speechRunning = false;
+ _speechFinished = true;
+ _router->resetExtraData();
+}
+
+void Logic::newScreen(uint32 screen) {
+ Object *compact = (Object*)_objMan->fetchObject(PLAYER);
+
+ // work around script bug #911508
+ if (((screen == 25) || (_scriptVars[SCREEN] == 25)) && (_scriptVars[SAND_FLAG] == 4)) {
+ Object *cpt = _objMan->fetchObject(SAND_25);
+ Object *george = _objMan->fetchObject(PLAYER);
+ if (george->o_place == HOLDING_REPLICA_25) // is george holding the replica in his hands?
+ fnFullSetFrame(cpt, SAND_25, IMPFLRCDT, IMPFLR, 0, 0, 0, 0); // empty impression in floor
+ else
+ fnFullSetFrame(cpt, SAND_25, IMPPLSCDT, IMPPLS, 0, 0, 0, 0); // impression filled with plaster
+ }
+
+ if (SwordEngine::_systemVars.justRestoredGame) { // if we've just restored a game - we want George to be exactly as saved
+ fnAddHuman(NULL, 0, 0, 0, 0, 0, 0, 0);
+ if (_scriptVars[GEORGE_WALKING]) { // except that if George was walking when we saveed the game
+ fnStandAt(compact, PLAYER, _scriptVars[CHANGE_X], _scriptVars[CHANGE_Y], _scriptVars[CHANGE_DIR], _scriptVars[CHANGE_STANCE], 0,0);
+ fnIdle(compact,PLAYER,0,0,0,0,0,0);
+ _scriptVars[GEORGE_WALKING] = 0;
+ }
+ SwordEngine::_systemVars.justRestoredGame = 0;
+ _music->startMusic(_scriptVars[CURRENT_MUSIC], 1);
+ } else { // if we haven't just restored a game, set George to stand, etc
+ compact->o_screen = _scriptVars[NEW_SCREEN]; //move the mega/player at this point between screens
+ fnStandAt(compact, PLAYER, _scriptVars[CHANGE_X], _scriptVars[CHANGE_Y], _scriptVars[CHANGE_DIR], _scriptVars[CHANGE_STANCE], 0,0);
+ fnChangeFloor(compact, PLAYER, _scriptVars[CHANGE_PLACE], 0, 0, 0, 0, 0);
+ }
+}
+
+void Logic::engine(void) {
+ debug(8, "\n\nNext logic cycle");
+ _eventMan->serviceGlobalEventList();
+
+ for (uint16 sectCnt = 0; sectCnt < TOTAL_SECTIONS; sectCnt++) {
+ if (_objMan->sectionAlive(sectCnt)) {
+ uint32 numCpts = _objMan->fetchNoObjects(sectCnt);
+ for (uint32 cptCnt = 0; cptCnt < numCpts; cptCnt++) {
+ uint32 currentId = sectCnt * ITM_PER_SEC + cptCnt;
+ Object *compact = _objMan->fetchObject(currentId);
+
+ if (compact->o_status & STAT_LOGIC) { // does the object want to be processed?
+ if (compact->o_status & STAT_EVENTS) {
+ //subscribed to the global-event-switcher? and in logic mode
+ switch (compact->o_logic) {
+ case LOGIC_pause_for_event:
+ case LOGIC_idle:
+ case LOGIC_AR_animate:
+ _eventMan->checkForEvent(compact);
+ break;
+ }
+ }
+ debug(7, "Logic::engine: handling compact %d (%X)", currentId, currentId);
+ processLogic(compact, currentId);
+ compact->o_sync = 0; // syncs are only available for 1 cycle.
+ }
+
+ if ((uint32)compact->o_screen == _scriptVars[SCREEN]) {
+ if (compact->o_status & STAT_FORE)
+ _screen->addToGraphicList(0, currentId);
+ if (compact->o_status & STAT_SORT)
+ _screen->addToGraphicList(1, currentId);
+ if (compact->o_status & STAT_BACK)
+ _screen->addToGraphicList(2, currentId);
+
+ if (compact->o_status & STAT_MOUSE)
+ _mouse->addToList(currentId, compact);
+ }
+ }
+ }
+ }
+ //_collision->checkCollisions();
+
+}
+
+void Logic::processLogic(Object *compact, uint32 id) {
+ int logicRet;
+ do {
+ switch (compact->o_logic) {
+ case LOGIC_idle:
+ logicRet = 0;
+ break;
+ case LOGIC_pause:
+ case LOGIC_pause_for_event:
+ if (compact->o_pause) {
+ compact->o_pause--;
+ logicRet = 0;
+ } else {
+ compact->o_logic = LOGIC_script;
+ logicRet = 1;
+ }
+ break;
+ case LOGIC_quit:
+ compact->o_logic = LOGIC_script;
+ logicRet = 0;
+ break;
+ case LOGIC_wait_for_sync:
+ if (compact->o_sync) {
+ logicRet = 1;
+ compact->o_logic = LOGIC_script;
+ } else
+ logicRet = 0;
+ break;
+ case LOGIC_choose:
+ _scriptVars[CUR_ID] = id;
+ logicRet = _menu->logicChooser(compact);
+ break;
+ case LOGIC_wait_for_talk:
+ logicRet = logicWaitTalk(compact);
+ break;
+ case LOGIC_start_talk:
+ logicRet = logicStartTalk(compact);
+ break;
+ case LOGIC_script:
+ _scriptVars[CUR_ID] = id;
+ logicRet = scriptManager(compact, id);
+ break;
+ case LOGIC_new_script:
+ compact->o_tree.o_script_pc[compact->o_tree.o_script_level] = _newScript;
+ compact->o_tree.o_script_id[compact->o_tree.o_script_level] = _newScript;
+ compact->o_logic = LOGIC_script;
+ logicRet = 1;
+ break;
+ case LOGIC_AR_animate:
+ logicRet = logicArAnimate(compact, id);
+ break;
+ case LOGIC_restart:
+ compact->o_tree.o_script_pc[compact->o_tree.o_script_level] = compact->o_tree.o_script_id[compact->o_tree.o_script_level];
+ compact->o_logic = LOGIC_script;
+ logicRet=1;
+ break;
+ case LOGIC_bookmark:
+ memcpy(&(compact->o_tree.o_script_level), &(compact->o_bookmark.o_script_level), sizeof(ScriptTree));
+ if (id == GMASTER_79) {
+ // workaround for ending script.
+ // GMASTER_79 is not prepared for mega_interact receiving INS_quit
+ fnSuicide(compact, id, 0, 0, 0, 0, 0, 0);
+ logicRet = 0;
+ } else {
+ compact->o_logic = LOGIC_script;
+ logicRet = 1;
+ }
+ break;
+ case LOGIC_speech:
+ logicRet = speechDriver(compact);
+ break;
+ case LOGIC_full_anim:
+ logicRet = fullAnimDriver(compact);
+ break;
+ case LOGIC_anim:
+ logicRet = animDriver(compact);
+ break;
+
+ default:
+ error("Fatal error: compact %d's logic == %X!", id, compact->o_logic);
+ break;
+ }
+ } while (logicRet);
+}
+
+int Logic::logicWaitTalk(Object *compact) {
+ Object *target = _objMan->fetchObject(compact->o_down_flag);
+
+ if (target->o_status & STAT_TALK_WAIT) {
+ compact->o_logic = LOGIC_script;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+int Logic::logicStartTalk(Object *compact) {
+ Object *target = _objMan->fetchObject(compact->o_down_flag); //holds id of person we're waiting for
+ if (target->o_status & STAT_TALK_WAIT) { //response?
+ compact->o_logic = LOGIC_script; //back to script again
+ return SCRIPT_CONT;
+ }
+ if (_eventMan->eventValid(compact->o_down_flag))
+ return SCRIPT_STOP; //event still valid - keep waiting
+ //the event has gone - so back to script with error code
+ compact->o_down_flag = 0;
+ compact->o_logic = LOGIC_script;
+ return SCRIPT_CONT;
+}
+
+int Logic::logicArAnimate(Object *compact, uint32 id) {
+ WalkData *route;
+ int32 walkPc;
+ if ((_scriptVars[GEORGE_WALKING] == 0) && (id == PLAYER))
+ _scriptVars[GEORGE_WALKING] = 1;
+
+ compact->o_resource = compact->o_walk_resource;
+ compact->o_status |= STAT_SHRINK;
+ route = compact->o_route;
+
+ walkPc =compact->o_walk_pc;
+ compact->o_frame =route[walkPc].frame;
+ compact->o_dir =route[walkPc].dir;
+ compact->o_xcoord =route[walkPc].x;
+ compact->o_ycoord =route[walkPc].y;
+ compact->o_anim_x =compact->o_xcoord;
+ compact->o_anim_y =compact->o_ycoord;
+
+ if (((_scriptVars[GEORGE_WALKING] == 2) && (walkPc > 5) && (id == PLAYER) &&
+ (route[walkPc - 1].step == 5) && (route[walkPc].step == 0)) ||
+ ((_scriptVars[GEORGE_WALKING] == 3) && (id == PLAYER))) {
+
+ compact->o_frame = 96 + compact->o_dir; //reset
+ if ((compact->o_dir != 2) && (compact->o_dir != 6)) { // on verticals and diagonals stand where george is
+ compact->o_xcoord = route[walkPc - 1].x;
+ compact->o_ycoord = route[walkPc - 1].y;
+ compact->o_anim_x = compact->o_xcoord;
+ compact->o_anim_y = compact->o_ycoord;
+ }
+ compact->o_logic = LOGIC_script;
+ compact->o_down_flag = 0; //0 means error
+ _scriptVars[GEORGE_WALKING] = 0;
+ route[compact->o_walk_pc+1].frame = 512; //end of sequence
+ if (_scriptVars[MEGA_ON_GRID] == 2)
+ _scriptVars[MEGA_ON_GRID] = 0;
+ }
+ compact->o_walk_pc++;
+
+ if (route[compact->o_walk_pc].frame == 512) //end of sequence
+ {
+ compact->o_logic = LOGIC_script;
+ if (((_scriptVars[GEORGE_WALKING] == 2) || (_scriptVars[GEORGE_WALKING] == 1)) &&
+ (id == PLAYER)) {
+ _scriptVars[GEORGE_WALKING] = 0;
+ if (_scriptVars[MEGA_ON_GRID] == 2)
+ _scriptVars[MEGA_ON_GRID] = 0;
+ }
+ }
+ return 0;
+}
+
+int Logic::speechDriver(Object *compact) {
+ if ((!_speechClickDelay) && (_mouse->testEvent() & BS1L_BUTTON_DOWN))
+ _speechFinished = true;
+ if (_speechClickDelay)
+ _speechClickDelay--;
+
+ if (_speechRunning) {
+ if (_sound->speechFinished())
+ _speechFinished = true;
+ } else {
+ if (!compact->o_speech_time)
+ _speechFinished = true;
+ else
+ compact->o_speech_time--;
+ }
+ if (_speechFinished) {
+ if (_speechRunning)
+ _sound->stopSpeech();
+ compact->o_logic = LOGIC_script;
+ if (_textRunning) {
+ _textMan->releaseText(compact->o_text_id);
+ _objMan->fetchObject(compact->o_text_id)->o_status = 0; // kill compact linking text sprite
+ }
+ _speechRunning = _textRunning = false;
+ _speechFinished = true;
+ }
+ if (compact->o_anim_resource) {
+ uint8 *animData = ((uint8*)_resMan->openFetchRes(compact->o_anim_resource)) + sizeof(Header);
+ int32 numFrames = READ_LE_UINT32(animData);
+ animData += 4;
+ compact->o_anim_pc++; // go to next frame of anim
+
+ if (_speechFinished || (compact->o_anim_pc >= numFrames) ||
+ (_speechRunning && (_sound->amISpeaking() == 0)))
+ compact->o_anim_pc = 0; //set to frame 0, closed mouth
+
+ AnimUnit *animPtr = (AnimUnit*)(animData + sizeof(AnimUnit) * compact->o_anim_pc);
+ if (!(compact->o_status & STAT_SHRINK)) {
+ compact->o_anim_x = FROM_LE_32(animPtr->animX);
+ compact->o_anim_y = FROM_LE_32(animPtr->animY);
+ }
+ compact->o_frame = FROM_LE_32(animPtr->animFrame);
+ _resMan->resClose(compact->o_anim_resource);
+ }
+ return 0;
+}
+
+int Logic::fullAnimDriver(Object *compact) {
+ if (compact->o_sync) { // return to script immediately if we've received a sync
+ compact->o_logic = LOGIC_script;
+ return 1;
+ }
+ uint8 *data = ((uint8*)_resMan->openFetchRes(compact->o_anim_resource)) + sizeof(Header);
+ uint32 numFrames = READ_LE_UINT32(data);
+ data += 4;
+ AnimUnit *animPtr = (AnimUnit*)(data + compact->o_anim_pc * sizeof(AnimUnit));
+
+ compact->o_anim_x = compact->o_xcoord = FROM_LE_32(animPtr->animX);
+ compact->o_anim_y = compact->o_ycoord = FROM_LE_32(animPtr->animY);
+ compact->o_frame = FROM_LE_32(animPtr->animFrame);
+
+ compact->o_anim_pc++;
+ if (compact->o_anim_pc == (int)numFrames)
+ compact->o_logic = LOGIC_script;
+
+ _resMan->resClose(compact->o_anim_resource);
+ return 0;
+}
+
+int Logic::animDriver(Object *compact) {
+ if (compact->o_sync) {
+ compact->o_logic = LOGIC_script;
+ return 1;
+ }
+ uint8 *data = ((uint8*)_resMan->openFetchRes(compact->o_anim_resource)) + sizeof(Header);
+ uint32 numFrames = READ_LE_UINT32(data);
+ AnimUnit *animPtr = (AnimUnit*)(data + 4 + compact->o_anim_pc * sizeof(AnimUnit));
+
+ if (!(compact->o_status & STAT_SHRINK)) {
+ compact->o_anim_x = FROM_LE_32(animPtr->animX);
+ compact->o_anim_y = FROM_LE_32(animPtr->animY);
+ }
+
+ compact->o_frame = FROM_LE_32(animPtr->animFrame);
+ compact->o_anim_pc++;
+ if (compact->o_anim_pc == (int)numFrames)
+ compact->o_logic = LOGIC_script;
+
+ _resMan->resClose(compact->o_anim_resource);
+ return 0;
+}
+
+void Logic::updateScreenParams(void) {
+ Object *compact = (Object*)_objMan->fetchObject(PLAYER);
+ _screen->setScrolling((int16)(compact->o_xcoord - _scriptVars[FEET_X]),
+ (int16)(compact->o_ycoord - _scriptVars[FEET_Y]));
+}
+
+int Logic::scriptManager(Object *compact, uint32 id) {
+ int ret;
+ do {
+ uint32 level = compact->o_tree.o_script_level;
+ uint32 script = compact->o_tree.o_script_id[level];
+ Debug::interpretScript(id, level, script, compact->o_tree.o_script_pc[level] & ITM_ID);
+ ret = interpretScript(compact, id, _resMan->lockScript(script), script, compact->o_tree.o_script_pc[level] & ITM_ID);
+ _resMan->unlockScript(script);
+ if (!ret) {
+ if (compact->o_tree.o_script_level)
+ compact->o_tree.o_script_level--;
+ else
+ error("ScriptManager: basescript %d for cpt %d ended!", script, id);
+ } else
+ compact->o_tree.o_script_pc[level] = ret;
+ } while (!ret);
+ return 1;
+ //Logic continues - but the script must have changed logic mode
+ //this is a radical change from S2.0 where once a script finished there
+ //was no more processing for that object on that cycle - the Logic_engine terminated.
+ //This meant that new logics that needed immediate action got a first call from the
+ //setup function. This was a bit tweeky. This technique ensures that the script is a
+ //totally seamless concept that takes up zero cycle time. The only downside is that
+ //an FN_quit becomes slightly more convoluted, but so what you might ask.
+}
+
+void Logic::runMouseScript(Object *cpt, int32 scriptId) {
+ Header *script = _resMan->lockScript(scriptId);
+ debug(9, "running mouse script %d", scriptId);
+ interpretScript(cpt, _scriptVars[SPECIAL_ITEM], script, scriptId, scriptId);
+ _resMan->unlockScript(scriptId);
+}
+
+int Logic::interpretScript(Object *compact, int id, Header *scriptModule, int scriptBase, int scriptNum) {
+ int32 *scriptCode = (int32*)(((uint8*)scriptModule) + sizeof(Header));
+ int32 stack[MAX_STACK_SIZE];
+ int32 stackIdx = 0;
+ int32 offset;
+ int32 pc;
+ if (memcmp(scriptModule->type, "Script", 6))
+ error("Invalid script module!");
+ if (scriptModule->version != SCRIPT_VERSION)
+ error("Illegal script version!");
+ if (scriptNum < 0)
+ error("negative script number");
+ if ((uint32)scriptNum >= scriptModule->decomp_length)
+ error("Script number out of bounds");
+
+ if (scriptNum < scriptCode[0])
+ pc = scriptCode[scriptNum + 1];
+ else
+ pc = scriptNum;
+ int32 startOfScript = scriptCode[(scriptBase & ITM_ID) + 1];
+
+ int32 a, b, c, d, e, f;
+ int mCodeReturn = 0;
+ int32 mCodeNumber = 0, mCodeArguments = 0;
+ uint32 varNum = 0;
+ while (1) {
+ assert((stackIdx >= 0) && (stackIdx <= MAX_STACK_SIZE));
+ switch (scriptCode[pc++]) {
+ case IT_MCODE:
+ a = b = c = d = e = f = 0;
+ mCodeNumber = scriptCode[pc++];
+ mCodeArguments = scriptCode[pc++];
+ switch (mCodeArguments) {
+ case 6: f = stack[--stackIdx];
+ case 5: e = stack[--stackIdx];
+ case 4: d = stack[--stackIdx];
+ case 3: c = stack[--stackIdx];
+ case 2: b = stack[--stackIdx];
+ case 1: a = stack[--stackIdx];
+ case 0:
+ Debug::callMCode(mCodeNumber, mCodeArguments, a, b, c, d, e, f);
+ mCodeReturn = (this->*_mcodeTable[mCodeNumber])(compact, id, a, b, c, d, e, f);
+ break;
+ default:
+ warning("mcode[%d]: too many arguments(%d)", mCodeNumber, mCodeArguments);
+ }
+ if (mCodeReturn == 0)
+ return pc;
+ break;
+ case IT_PUSHNUMBER:
+ debug(9, "IT_PUSH: %d", scriptCode[pc]);
+ stack[stackIdx++] = scriptCode[pc++];
+ break;
+ case IT_PUSHVARIABLE:
+ debug(9, "IT_PUSHVARIABLE: ScriptVar[%d] => %d", scriptCode[pc], _scriptVars[scriptCode[pc]]);
+ varNum = scriptCode[pc++];
+ if (SwordEngine::_systemVars.isDemo) {
+ if (varNum >= 397) // BS1 Demo has different number of script variables
+ varNum++;
+ if (varNum >= 699)
+ varNum++;
+ }
+ stack[stackIdx++] = _scriptVars[varNum];
+ break;
+ case IT_NOTEQUAL:
+ stackIdx--;
+ debug(9, "IT_NOTEQUAL: RESULT = %d", stack[stackIdx - 1] != stack[stackIdx]);
+ stack[stackIdx - 1] = (stack[stackIdx - 1] != stack[stackIdx]);
+ break;
+ case IT_ISEQUAL:
+ stackIdx--;
+ debug(9, "IT_ISEQUAL: RESULT = %d", stack[stackIdx - 1] == stack[stackIdx]);
+ stack[stackIdx - 1] = (stack[stackIdx - 1] == stack[stackIdx]);
+ break;
+ case IT_PLUS:
+ stackIdx--;
+ debug(9, "IT_PLUS: RESULT = %d", stack[stackIdx - 1] + stack[stackIdx]);
+ stack[stackIdx - 1] = (stack[stackIdx - 1] + stack[stackIdx]);
+ break;
+ case IT_TIMES:
+ stackIdx--;
+ debug(9, "IT_TIMES: RESULT = %d", stack[stackIdx - 1] * stack[stackIdx]);
+ stack[stackIdx - 1] = (stack[stackIdx - 1] * stack[stackIdx]);
+ break;
+ case IT_ANDAND:
+ stackIdx--;
+ debug(9, "IT_ANDAND: RESULT = %d", stack[stackIdx - 1] && stack[stackIdx]);
+ stack[stackIdx - 1] = (stack[stackIdx - 1] && stack[stackIdx]);
+ break;
+ case IT_OROR: // ||
+ stackIdx--;
+ debug(9, "IT_OROR: RESULT = %d", stack[stackIdx - 1] || stack[stackIdx]);
+ stack[stackIdx - 1] = (stack[stackIdx - 1] || stack[stackIdx]);
+ break;
+ case IT_LESSTHAN:
+ stackIdx--;
+ debug(9, "IT_LESSTHAN: RESULT = %d", stack[stackIdx - 1] < stack[stackIdx]);
+ stack[stackIdx - 1] = (stack[stackIdx - 1] < stack[stackIdx]);
+ break;
+ case IT_NOT:
+ debug(9, "IT_NOT: RESULT = %d", stack[stackIdx - 1] ? 0 : 1);
+ if (stack[stackIdx - 1])
+ stack[stackIdx - 1] = 0;
+ else
+ stack[stackIdx - 1] = 1;
+ break;
+ case IT_MINUS:
+ stackIdx--;
+ debug(9, "IT_MINUS: RESULT = %d", stack[stackIdx - 1] - stack[stackIdx]);
+ stack[stackIdx - 1] = (stack[stackIdx - 1] - stack[stackIdx]);
+ break;
+ case IT_AND:
+ stackIdx--;
+ debug(9, "IT_AND: RESULT = %d", stack[stackIdx - 1] & stack[stackIdx]);
+ stack[stackIdx - 1] = (stack[stackIdx - 1] & stack[stackIdx]);
+ break;
+ case IT_OR:
+ stackIdx--;
+ debug(9, "IT_OR: RESULT = %d", stack[stackIdx - 1] | stack[stackIdx]);
+ stack[stackIdx - 1] = (stack[stackIdx - 1] | stack[stackIdx]);
+ break;
+ case IT_GTE:
+ stackIdx--;
+ debug(9, "IT_GTE: RESULT = %d", stack[stackIdx - 1] >= stack[stackIdx]);
+ stack[stackIdx - 1] = (stack[stackIdx - 1] >= stack[stackIdx]);
+ break;
+ case IT_LTE:
+ stackIdx--;
+ debug(9, "IT_LTE: RESULT = %d", stack[stackIdx - 1] <= stack[stackIdx]);
+ stack[stackIdx - 1] = (stack[stackIdx - 1] <= stack[stackIdx]);
+ break;
+ case IT_DEVIDE:
+ stackIdx--;
+ debug(9, "IT_DEVIDE: RESULT = %d", stack[stackIdx - 1] / stack[stackIdx]);
+ stack[stackIdx - 1] = (stack[stackIdx - 1] / stack[stackIdx]);
+ break;
+ case IT_GT:
+ stackIdx--;
+ debug(9, "IT_GT: RESULT = %d", stack[stackIdx - 1] > stack[stackIdx]);
+ stack[stackIdx - 1] = (stack[stackIdx - 1] > stack[stackIdx]);
+ break;
+ case IT_SCRIPTEND:
+ debug(9, "IT_SCRIPTEND");
+ return 0;
+ case IT_POPVAR: // pop a variable
+ debug(9, "IT_POPVAR: ScriptVars[%d] = %d", scriptCode[pc], stack[stackIdx-1]);
+ varNum = scriptCode[pc++];
+ if (SwordEngine::_systemVars.isDemo) {
+ if (varNum >= 397) // BS1 Demo has different number of script variables
+ varNum++;
+ if (varNum >= 699)
+ varNum++;
+ }
+ _scriptVars[varNum] = stack[--stackIdx];
+ break;
+ case IT_POPLONGOFFSET:
+ offset = scriptCode[pc++];
+ debug(9, "IT_POPLONGOFFSET: Cpt[%d] = %d", offset, stack[stackIdx - 1]);
+ *((int32 *)((uint8*)compact + offset)) = stack[--stackIdx];
+ break;
+ case IT_PUSHLONGOFFSET:
+ offset = scriptCode[pc++];
+ debug(9, "IT_PUSHLONGOFFSET: PUSH Cpt[%d] (==%d)", offset, *((int32 *)((uint8*)compact + offset)));
+ stack[stackIdx++] = *((int32 *)((uint8*)compact + offset));
+ break;
+ case IT_SKIPONFALSE:
+ debug(9, "IT_SKIPONFALSE: %d (%s)", scriptCode[pc], (stack[stackIdx-1] ? "IS TRUE (NOT SKIPPED)" : "IS FALSE (SKIPPED)"));
+ if (stack[--stackIdx])
+ pc++;
+ else
+ pc += scriptCode[pc];
+ break;
+ case IT_SKIP:
+ debug(9, "IT_SKIP: %d", scriptCode[pc]);
+ pc += scriptCode[pc];
+ break;
+ case IT_SWITCH: // The mega switch statement
+ debug(9, "IT_SWITCH: [SORRY, NO DEBUG INFO]");
+ {
+ int switchValue = stack[--stackIdx];
+ int switchCount = scriptCode[pc++];
+ int doneSwitch=0;
+
+ for (int cnt = 0; (cnt < switchCount) && (doneSwitch==0); cnt++) {
+ if (switchValue == scriptCode[pc]) {
+ pc += scriptCode[pc+1];
+ doneSwitch=1;
+ } else
+ pc += 2;
+ }
+ if (doneSwitch == 0)
+ pc += scriptCode[pc];
+ }
+ break;
+ case IT_SKIPONTRUE: // skip if expression true
+ debug(9, "IT_SKIPONTRUE: %d (%s)", scriptCode[pc], (stack[stackIdx-1] ? "IS TRUE (SKIPPED)" : "IS FALSE (NOT SKIPPED)"));
+ stackIdx--;
+ if (stack[stackIdx])
+ pc += scriptCode[pc];
+ else
+ pc++;
+ break;
+ case IT_PRINTF:
+ debug(0, "IT_PRINTF(%d)",stack[stackIdx]);
+ break;
+ case IT_RESTARTSCRIPT:
+ debug(9, "IT_RESTARTSCRIPT");
+ pc = startOfScript;
+ break;
+ case IT_POPWORDOFFSET:
+ offset = scriptCode[pc++];
+ debug(9, "IT_POPWORDOFFSET: Cpt[%d] = %d", offset, stack[stackIdx - 1] & 0xFFFF);
+ *((int32 *)((uint8*)compact + offset)) = stack[--stackIdx] & 0xffff;
+ break;
+ case IT_PUSHWORDOFFSET:
+ offset = scriptCode[pc++];
+ debug(9, "IT_PUSHWORDOFFSET: PUSH Cpt[%d] == %d", offset, (*((int32 *)((uint8*)compact + offset))) & 0xffff);
+ stack[stackIdx++] = (*((int32 *)((uint8*)compact + offset))) & 0xffff;
+ break;
+ default:
+ error("Invalid operator %d",scriptCode[pc-1]);
+ return 0;
+ }
+ }
+}
+
+BSMcodeTable Logic::_mcodeTable[100] = {
+ &Logic::fnBackground,
+ &Logic::fnForeground,
+ &Logic::fnSort,
+ &Logic::fnNoSprite,
+ &Logic::fnMegaSet,
+ &Logic::fnAnim,
+ &Logic::fnSetFrame,
+ &Logic::fnFullAnim,
+ &Logic::fnFullSetFrame,
+ &Logic::fnFadeDown,
+ &Logic::fnFadeUp,
+ &Logic::fnCheckFade,
+ &Logic::fnSetSpritePalette,
+ &Logic::fnSetWholePalette,
+ &Logic::fnSetFadeTargetPalette,
+ &Logic::fnSetPaletteToFade,
+ &Logic::fnSetPaletteToCut,
+ &Logic::fnPlaySequence,
+ &Logic::fnIdle,
+ &Logic::fnPause,
+ &Logic::fnPauseSeconds,
+ &Logic::fnQuit,
+ &Logic::fnKillId,
+ &Logic::fnSuicide,
+ &Logic::fnNewScript,
+ &Logic::fnSubScript,
+ &Logic::fnRestartScript,
+ &Logic::fnSetBookmark,
+ &Logic::fnGotoBookmark,
+ &Logic::fnSendSync,
+ &Logic::fnWaitSync,
+ &Logic::cfnClickInteract,
+ &Logic::cfnSetScript,
+ &Logic::cfnPresetScript,
+ &Logic::fnInteract,
+ &Logic::fnIssueEvent,
+ &Logic::fnCheckForEvent,
+ &Logic::fnWipeHands,
+ &Logic::fnISpeak,
+ &Logic::fnTheyDo,
+ &Logic::fnTheyDoWeWait,
+ &Logic::fnWeWait,
+ &Logic::fnChangeSpeechText,
+ &Logic::fnTalkError,
+ &Logic::fnStartTalk,
+ &Logic::fnCheckForTextLine,
+ &Logic::fnAddTalkWaitStatusBit,
+ &Logic::fnRemoveTalkWaitStatusBit,
+ &Logic::fnNoHuman,
+ &Logic::fnAddHuman,
+ &Logic::fnBlankMouse,
+ &Logic::fnNormalMouse,
+ &Logic::fnLockMouse,
+ &Logic::fnUnlockMouse,
+ &Logic::fnSetMousePointer,
+ &Logic::fnSetMouseLuggage,
+ &Logic::fnMouseOn,
+ &Logic::fnMouseOff,
+ &Logic::fnChooser,
+ &Logic::fnEndChooser,
+ &Logic::fnStartMenu,
+ &Logic::fnEndMenu,
+ &Logic::cfnReleaseMenu,
+ &Logic::fnAddSubject,
+ &Logic::fnAddObject,
+ &Logic::fnRemoveObject,
+ &Logic::fnEnterSection,
+ &Logic::fnLeaveSection,
+ &Logic::fnChangeFloor,
+ &Logic::fnWalk,
+ &Logic::fnTurn,
+ &Logic::fnStand,
+ &Logic::fnStandAt,
+ &Logic::fnFace,
+ &Logic::fnFaceXy,
+ &Logic::fnIsFacing,
+ &Logic::fnGetTo,
+ &Logic::fnGetToError,
+ &Logic::fnGetPos,
+ &Logic::fnGetGamepadXy,
+ &Logic::fnPlayFx,
+ &Logic::fnStopFx,
+ &Logic::fnPlayMusic,
+ &Logic::fnStopMusic,
+ &Logic::fnInnerSpace,
+ &Logic::fnRandom,
+ &Logic::fnSetScreen,
+ &Logic::fnPreload,
+ &Logic::fnCheckCD,
+ &Logic::fnRestartGame,
+ &Logic::fnQuitGame,
+ &Logic::fnDeathScreen,
+ &Logic::fnSetParallax,
+ &Logic::fnTdebug,
+ &Logic::fnRedFlash,
+ &Logic::fnBlueFlash,
+ &Logic::fnYellow,
+ &Logic::fnGreen,
+ &Logic::fnPurple,
+ &Logic::fnBlack
+};
+
+int Logic::fnBackground(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
+
+ cpt->o_status &= ~(STAT_FORE | STAT_SORT);
+ cpt->o_status |= STAT_BACK;
+ return SCRIPT_CONT;
+}
+
+int Logic::fnForeground(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ cpt->o_status &= ~(STAT_BACK | STAT_SORT);
+ cpt->o_status |= STAT_FORE;
+ return SCRIPT_CONT;
+}
+
+int Logic::fnSort(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ cpt->o_status &= ~(STAT_BACK | STAT_FORE);
+ cpt->o_status |= STAT_SORT;
+ return SCRIPT_CONT;
+}
+
+int Logic::fnNoSprite(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ cpt->o_status &= ~(STAT_BACK | STAT_FORE | STAT_SORT);
+ return SCRIPT_CONT;
+}
+
+int Logic::fnMegaSet(Object *cpt, int32 id, int32 walk_data, int32 spr, int32 e, int32 f, int32 z, int32 x) {
+ cpt->o_mega_resource = walk_data;
+ cpt->o_walk_resource = spr;
+ return SCRIPT_CONT;
+}
+
+int Logic::fnAnim(Object *cpt, int32 id, int32 cdt, int32 spr, int32 e, int32 f, int32 z, int32 x) {
+ AnimSet *animTab;
+
+ if (cdt && (!spr)) {
+ animTab = (AnimSet*)((uint8*)_resMan->openFetchRes(cdt) + sizeof(Header));
+ animTab += cpt->o_dir;
+
+ cpt->o_anim_resource = FROM_LE_32(animTab->cdt);
+ cpt->o_resource = FROM_LE_32(animTab->spr);
+ _resMan->resClose(cdt);
+ } else {
+ cpt->o_anim_resource = cdt;
+ cpt->o_resource = spr;
+ }
+ if ((cpt->o_anim_resource == 0) || (cpt->o_resource == 0))
+ error("fnAnim called width (%d/%d) => (%d/%d)", cdt, spr, cpt->o_anim_resource, cpt->o_resource);
+
+ FrameHeader *frameHead = _resMan->fetchFrame(_resMan->openFetchRes(cpt->o_resource), 0);
+ if (frameHead->offsetX || frameHead->offsetY) { // boxed mega anim?
+ cpt->o_status |= STAT_SHRINK;
+ cpt->o_anim_x = cpt->o_xcoord; // set anim coords to 'feet' coords - only need to do this once
+ cpt->o_anim_y = cpt->o_ycoord;
+ } else {
+ // Anim_driver sets anim coords to cdt coords for every frame of a loose anim
+ cpt->o_status &= ~STAT_SHRINK;
+ }
+ _resMan->resClose(cpt->o_resource);
+
+ cpt->o_logic = LOGIC_anim;
+ cpt->o_anim_pc = 0;
+ cpt->o_sync = 0;
+ return SCRIPT_STOP;
+}
+
+int Logic::fnSetFrame(Object *cpt, int32 id, int32 cdt, int32 spr, int32 frameNo, int32 f, int32 z, int32 x) {
+
+ AnimUnit *animPtr;
+
+ uint8 *data = (uint8*)_resMan->openFetchRes(cdt);
+ data += sizeof(Header);
+ if (frameNo == LAST_FRAME)
+ frameNo = READ_LE_UINT32(data) - 1;
+
+ data += 4;
+ animPtr = (AnimUnit*)(data + frameNo * sizeof(AnimUnit));
+
+ cpt->o_anim_x = FROM_LE_32(animPtr->animX);
+ cpt->o_anim_y = FROM_LE_32(animPtr->animY);
+ cpt->o_frame = FROM_LE_32(animPtr->animFrame);
+
+ cpt->o_resource = spr;
+ cpt->o_status &= ~STAT_SHRINK;
+ _resMan->resClose(cdt);
+ return SCRIPT_CONT;
+}
+
+int Logic::fnFullAnim(Object *cpt, int32 id, int32 anim, int32 graphic, int32 e, int32 f, int32 z, int32 x) {
+ cpt->o_logic = LOGIC_full_anim;
+
+ cpt->o_anim_pc = 0;
+ cpt->o_anim_resource = anim;
+ cpt->o_resource = graphic;
+ cpt->o_status &= ~STAT_SHRINK;
+ cpt->o_sync = 0;
+ return SCRIPT_STOP;
+}
+
+int Logic::fnFullSetFrame(Object *cpt, int32 id, int32 cdt, int32 spr, int32 frameNo, int32 f, int32 z, int32 x) {
+ uint8 *data = (uint8*)_resMan->openFetchRes(cdt) + sizeof(Header);
+
+ if (frameNo == LAST_FRAME)
+ frameNo = READ_LE_UINT32(data) - 1;
+ data += 4;
+
+ AnimUnit *animPtr = (AnimUnit*)(data + sizeof(AnimUnit) * frameNo);
+ cpt->o_anim_x = cpt->o_xcoord = FROM_LE_32(animPtr->animX);
+ cpt->o_anim_y = cpt->o_ycoord = FROM_LE_32(animPtr->animY);
+ cpt->o_frame = FROM_LE_32(animPtr->animFrame);
+
+ cpt->o_resource = spr;
+ cpt->o_status &= ~STAT_SHRINK;
+
+ _resMan->resClose(cdt);
+ return SCRIPT_CONT;
+}
+
+int Logic::fnFadeDown(Object *cpt, int32 id, int32 speed, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ _screen->fadeDownPalette();
+ return SCRIPT_CONT;
+}
+
+int Logic::fnFadeUp(Object *cpt, int32 id, int32 speed, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ _screen->fadeUpPalette();
+ return SCRIPT_CONT;
+}
+
+int Logic::fnCheckFade(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ _scriptVars[RETURN_VALUE] = (uint8)_screen->stillFading();
+ return SCRIPT_CONT;
+}
+
+int Logic::fnSetSpritePalette(Object *cpt, int32 id, int32 spritePal, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ _screen->fnSetPalette(184, 72, spritePal, false);
+ return SCRIPT_CONT;
+}
+
+int Logic::fnSetWholePalette(Object *cpt, int32 id, int32 spritePal, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ _screen->fnSetPalette(0, 256, spritePal, false);
+ return SCRIPT_CONT;
+}
+
+int Logic::fnSetFadeTargetPalette(Object *cpt, int32 id, int32 spritePal, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ _screen->fnSetPalette(0, 184, spritePal, true);
+ return SCRIPT_CONT;
+}
+
+int Logic::fnSetPaletteToFade(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ SwordEngine::_systemVars.wantFade = true;
+ return SCRIPT_CONT;
+}
+
+int Logic::fnSetPaletteToCut(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ SwordEngine::_systemVars.wantFade = false;
+ return SCRIPT_CONT;
+}
+
+int Logic::fnPlaySequence(Object *cpt, int32 id, int32 sequenceId, int32 d, int32 e, int32 f, int32 z, int32 x) {
+
+ // A cutscene usually (always?) means the room will change. In the
+ // meantime, we don't want any looping sound effects still playing.
+ _sound->quitScreen();
+
+ if ((SwordEngine::_systemVars.cutscenePackVersion == 1) && (sequenceId == SEQ_CREDITS)) {
+ CreditsPlayer player(_system, _mixer);
+ player.play();
+ } else {
+ MoviePlayer player(_screen, _mixer, _system);
+ player.play(sequenceId);
+ }
+ return SCRIPT_CONT;
+}
+
+int Logic::fnIdle(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ cpt->o_tree.o_script_level = 0; // force to level 0
+ cpt->o_logic = LOGIC_idle;
+ return SCRIPT_STOP;
+}
+
+int Logic::fnPause(Object *cpt, int32 id, int32 pause, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ cpt->o_pause = pause;
+ cpt->o_logic = LOGIC_pause;
+ return SCRIPT_STOP;
+}
+
+int Logic::fnPauseSeconds(Object *cpt, int32 id, int32 pause, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ cpt->o_pause = pause * FRAME_RATE;
+ cpt->o_logic = LOGIC_pause;
+ return SCRIPT_STOP;
+}
+
+int Logic::fnQuit(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ cpt->o_logic = LOGIC_quit;
+ return SCRIPT_STOP;
+}
+
+int Logic::fnKillId(Object *cpt, int32 id, int32 target, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ Object *targetObj = _objMan->fetchObject(target);
+ targetObj->o_status = 0;
+ return SCRIPT_CONT;
+}
+
+int Logic::fnSuicide(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ cpt->o_status = 0;
+ cpt->o_logic = LOGIC_quit;
+ return SCRIPT_STOP;
+}
+
+int Logic::fnNewScript(Object *cpt, int32 id, int32 script, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ cpt->o_logic = LOGIC_new_script;
+ _newScript = script;
+ return SCRIPT_STOP;
+}
+
+int Logic::fnSubScript(Object *cpt, int32 id, int32 script, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ cpt->o_tree.o_script_level++;
+ if (cpt->o_tree.o_script_level == TOTAL_script_levels)
+ error("Compact %d: script level exceeded in fnSubScript.", id);
+ cpt->o_tree.o_script_pc[cpt->o_tree.o_script_level] = script;
+ cpt->o_tree.o_script_id[cpt->o_tree.o_script_level] = script;
+ return SCRIPT_STOP;
+}
+
+int Logic::fnRestartScript(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ cpt->o_logic = LOGIC_restart;
+ return SCRIPT_STOP;
+}
+
+int Logic::fnSetBookmark(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ memcpy(&cpt->o_bookmark.o_script_level, &cpt->o_tree.o_script_level, sizeof(ScriptTree));
+ return SCRIPT_CONT;
+}
+
+int Logic::fnGotoBookmark(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ cpt->o_logic = LOGIC_bookmark;
+ return SCRIPT_STOP;
+}
+
+int Logic::fnSendSync(Object *cpt, int32 id, int32 sendId, int32 syncValue, int32 e, int32 f, int32 z, int32 x) {
+ Object *target = _objMan->fetchObject(sendId);
+ target->o_sync = syncValue;
+ return SCRIPT_CONT;
+}
+
+int Logic::fnWaitSync(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ cpt->o_logic = LOGIC_wait_for_sync;
+ return SCRIPT_STOP;
+}
+
+int Logic::cfnClickInteract(Object *cpt, int32 id, int32 target, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ Object *tar = _objMan->fetchObject(target);
+ cpt = _objMan->fetchObject(PLAYER);
+ cpt->o_tree.o_script_level = 0;
+ cpt->o_tree.o_script_pc[0] = tar->o_interact;
+ cpt->o_tree.o_script_id[0] = tar->o_interact;
+ cpt->o_logic = LOGIC_script;
+ return SCRIPT_STOP;
+}
+
+int Logic::cfnSetScript(Object *cpt, int32 id, int32 target, int32 script, int32 e, int32 f, int32 z, int32 x) {
+ Object *tar = _objMan->fetchObject(target);
+ tar->o_tree.o_script_level = 0;
+ tar->o_tree.o_script_pc[0] = script;
+ tar->o_tree.o_script_id[0] = script;
+ tar->o_logic = LOGIC_script;
+ return SCRIPT_CONT;
+}
+
+int Logic::cfnPresetScript(Object *cpt, int32 id, int32 target, int32 script, int32 e, int32 f, int32 z, int32 x) {
+ Object *tar = _objMan->fetchObject(target);
+ tar->o_tree.o_script_level = 0;
+ tar->o_tree.o_script_pc[0] = script;
+ tar->o_tree.o_script_id[0] = script;
+ if (tar->o_logic == LOGIC_idle)
+ tar->o_logic = LOGIC_script;
+ return SCRIPT_CONT;
+}
+
+int Logic::fnInteract(Object *cpt, int32 id, int32 target, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ Object *tar = _objMan->fetchObject(target);
+ cpt->o_place = tar->o_place;
+
+ Object *floorObject = _objMan->fetchObject(tar->o_place);
+ cpt->o_scale_a = floorObject->o_scale_a;
+ cpt->o_scale_b = floorObject->o_scale_b;
+
+ cpt->o_tree.o_script_level++;
+ cpt->o_tree.o_script_pc[cpt->o_tree.o_script_level] = tar->o_interact;
+ cpt->o_tree.o_script_id[cpt->o_tree.o_script_level] = tar->o_interact;
+
+ return SCRIPT_STOP;
+}
+
+int Logic::fnIssueEvent(Object *cpt, int32 id, int32 event, int32 delay, int32 e, int32 f, int32 z, int32 x) {
+ _eventMan->fnIssueEvent(cpt, id, event, delay);
+ return SCRIPT_CONT;
+}
+
+int Logic::fnCheckForEvent(Object *cpt, int32 id, int32 pause, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ return _eventMan->fnCheckForEvent(cpt, id, pause);
+}
+
+int Logic::fnWipeHands(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ _scriptVars[OBJECT_HELD] = 0;
+ _mouse->setLuggage(0, 0);
+ _menu->refresh(MENU_TOP);
+ return SCRIPT_CONT;
+}
+
+int Logic::fnISpeak(Object *cpt, int32 id, int32 cdt, int32 textNo, int32 spr, int32 f, int32 z, int32 x) {
+ _speechClickDelay = 3;
+ if (((textNo & ~1) == 0x3f0012) && (!cdt) && (!spr)) {
+ cdt = GEOSTDLCDT; // workaround for missing animation when examining
+ spr = GEOSTDL; // the conductor on the train roof
+ }
+ cpt->o_logic = LOGIC_speech;
+
+ // first setup the talk animation
+ if (cdt && (!spr)) { // if 'cdt' is non-zero but 'spr' is zero - 'cdt' is an anim table tag
+ AnimSet *animTab = (AnimSet*)((uint8*)_resMan->openFetchRes(cdt) + sizeof(Header));
+ animTab += cpt->o_dir;
+
+ cpt->o_anim_resource = FROM_LE_32(animTab->cdt);
+ if (animTab->cdt)
+ cpt->o_resource = FROM_LE_32(animTab->spr);
+ _resMan->resClose(cdt);
+ } else {
+ cpt->o_anim_resource = cdt;
+ if (cdt)
+ cpt->o_resource = spr;
+ }
+ cpt->o_anim_pc = 0; // start anim from first frame
+ if (cpt->o_anim_resource) {
+ if (!cpt->o_resource)
+ error("ID %d: Can't run anim with cdt=%d, spr=%d", id, cdt, spr);
+
+ FrameHeader *frameHead = _resMan->fetchFrame(_resMan->openFetchRes(cpt->o_resource), 0);
+ if (frameHead->offsetX && frameHead->offsetY) { // is this a boxed mega?
+ cpt->o_status |= STAT_SHRINK;
+ cpt->o_anim_x = cpt->o_xcoord;
+ cpt->o_anim_y = cpt->o_ycoord;
+ } else
+ cpt->o_status &= ~STAT_SHRINK;
+
+ _resMan->resClose(cpt->o_resource);
+ }
+ if (SwordEngine::_systemVars.playSpeech)
+ _speechRunning = _sound->startSpeech(textNo >> 16, textNo & 0xFFFF);
+ else
+ _speechRunning = false;
+ _speechFinished = false;
+ if (SwordEngine::_systemVars.showText || (!_speechRunning)) {
+ _textRunning = true;
+
+ char *text = _objMan->lockText(textNo);
+ cpt->o_speech_time = strlen(text) + 5;
+ uint32 textCptId = _textMan->lowTextManager((uint8*)text, cpt->o_speech_width, (uint8)cpt->o_speech_pen);
+ _objMan->unlockText(textNo);
+
+ Object * textCpt = _objMan->fetchObject(textCptId);
+ textCpt->o_screen = cpt->o_screen;
+ textCpt->o_target = textCptId;
+
+ // the graphic is a property of Text, so we don't lock/unlock it.
+ uint16 textSpriteWidth = FROM_LE_16(_textMan->giveSpriteData(textCpt->o_target)->width);
+ uint16 textSpriteHeight = FROM_LE_16(_textMan->giveSpriteData(textCpt->o_target)->height);
+
+ cpt->o_text_id = textCptId;
+
+ // now set text coords, above the player, usually
+
+#define TEXT_MARGIN 3 // distance kept from edges of screen
+#define ABOVE_HEAD 20 // distance kept above talking sprite
+ uint16 textX, textY;
+ if (((id == GEORGE) || ((id == NICO) && (_scriptVars[SCREEN] == 10))) && (!cpt->o_anim_resource)) {
+ // if George is doing Voice-Over text (centered at the bottom of the screen)
+ textX = _scriptVars[SCROLL_OFFSET_X] + 128 + (640 / 2) - textSpriteWidth / 2;
+ textY = _scriptVars[SCROLL_OFFSET_Y] + 128 + 400;
+ } else {
+ if ((id == GEORGE) && (_scriptVars[SCREEN] == 79))
+ textX = cpt->o_mouse_x2; // move it off george's head
+ else
+ textX = (cpt->o_mouse_x1 + cpt->o_mouse_x2) / 2 - textSpriteWidth / 2;
+
+ textY = cpt->o_mouse_y1 - textSpriteHeight - ABOVE_HEAD;
+ }
+ // now ensure text is within visible screen
+ uint16 textLeftMargin, textRightMargin, textTopMargin, textBottomMargin;
+ textLeftMargin = SCREEN_LEFT_EDGE + TEXT_MARGIN + _scriptVars[SCROLL_OFFSET_X];
+ textRightMargin = SCREEN_RIGHT_EDGE - TEXT_MARGIN + _scriptVars[SCROLL_OFFSET_X] - textSpriteWidth;
+ textTopMargin = SCREEN_TOP_EDGE + TEXT_MARGIN + _scriptVars[SCROLL_OFFSET_Y];
+ textBottomMargin = SCREEN_BOTTOM_EDGE - TEXT_MARGIN + _scriptVars[SCROLL_OFFSET_Y] - textSpriteHeight;
+
+ textCpt->o_anim_x = textCpt->o_xcoord = inRange(textLeftMargin, textX, textRightMargin);
+ textCpt->o_anim_y = textCpt->o_ycoord = inRange(textTopMargin, textY, textBottomMargin);
+ }
+ return SCRIPT_STOP;
+}
+
+//send instructions to mega in conversation with player
+//the instruction is interpreted by the script mega_interact
+int Logic::fnTheyDo(Object *cpt, int32 id, int32 tar, int32 instruc, int32 param1, int32 param2, int32 param3, int32 x) {
+ Object *target;
+ target = _objMan->fetchObject(tar);
+ target->o_down_flag = instruc; // instruction for the mega
+ target->o_ins1 = param1;
+ target->o_ins2 = param2;
+ target->o_ins3 = param3;
+ return SCRIPT_CONT;
+}
+
+//send an instruction to mega we're talking to and wait
+//until it has finished before returning to script
+int Logic::fnTheyDoWeWait(Object *cpt, int32 id, int32 tar, int32 instruc, int32 param1, int32 param2, int32 param3, int32 x) {
+ // workaround for scriptbug #928791: Freeze at hospital
+ // in at least one game version, a script forgets to set sam_returning back to zero
+ if ((tar == SAM) && (instruc == INS_talk) && (param2 == 2162856))
+ _scriptVars[SAM_RETURNING] = 0;
+ Object *target = _objMan->fetchObject(tar);
+ target->o_down_flag = instruc; // instruction for the mega
+ target->o_ins1 = param1;
+ target->o_ins2 = param2;
+ target->o_ins3 = param3;
+ target->o_status &= ~STAT_TALK_WAIT;
+
+ cpt->o_logic = LOGIC_wait_for_talk;
+ cpt->o_down_flag = tar;
+ return SCRIPT_STOP;
+}
+
+int Logic::fnWeWait(Object *cpt, int32 id, int32 tar, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ Object *target = _objMan->fetchObject(tar);
+ target->o_status &= ~STAT_TALK_WAIT;
+
+ cpt->o_logic = LOGIC_wait_for_talk;
+ cpt->o_down_flag = tar;
+
+ return SCRIPT_STOP;
+}
+
+int Logic::fnChangeSpeechText(Object *cpt, int32 id, int32 tar, int32 width, int32 pen, int32 f, int32 z, int32 x) {
+ Object *target = _objMan->fetchObject(tar);
+ target->o_speech_width = width;
+ target->o_speech_pen = pen;
+ return SCRIPT_STOP;
+}
+
+//mega_interact has received an instruction it does not understand -
+//The game is halted for debugging. Maybe we'll remove this later.
+int Logic::fnTalkError(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ error("fnTalkError for id %d, instruction %d", id, cpt->o_down_flag);
+ return SCRIPT_STOP;
+}
+
+int Logic::fnStartTalk(Object *cpt, int32 id, int32 target, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ cpt->o_down_flag = target;
+ cpt->o_logic = LOGIC_start_talk;
+ return SCRIPT_STOP;
+}
+
+int Logic::fnCheckForTextLine(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ _scriptVars[RETURN_VALUE] = _objMan->fnCheckForTextLine(id);
+ return SCRIPT_CONT;
+}
+
+int Logic::fnAddTalkWaitStatusBit(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ cpt->o_status |= STAT_TALK_WAIT;
+ return SCRIPT_CONT;
+}
+
+int Logic::fnRemoveTalkWaitStatusBit(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ cpt->o_status &= ~STAT_TALK_WAIT;
+ return SCRIPT_CONT;
+}
+
+int Logic::fnNoHuman(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ _mouse->fnNoHuman();
+ return SCRIPT_CONT;
+}
+
+int Logic::fnAddHuman(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ _mouse->fnAddHuman();
+ return SCRIPT_CONT;
+}
+
+int Logic::fnBlankMouse(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ _mouse->fnBlankMouse();
+ return SCRIPT_CONT;
+}
+
+int Logic::fnNormalMouse(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ _mouse->fnNormalMouse();
+ return SCRIPT_CONT;
+}
+
+int Logic::fnLockMouse(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ _mouse->fnLockMouse();
+ return SCRIPT_CONT;
+}
+
+int Logic::fnUnlockMouse(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ _mouse->fnUnlockMouse();
+ return SCRIPT_CONT;
+}
+
+int Logic::fnSetMousePointer(Object *cpt, int32 id, int32 tag, int32 rate, int32 e, int32 f, int32 z, int32 x) {
+ _mouse->setPointer(tag, rate);
+ return SCRIPT_CONT;
+}
+
+int Logic::fnSetMouseLuggage(Object *cpt, int32 id, int32 tag, int32 rate, int32 e, int32 f, int32 z, int32 x) {
+ _mouse->setLuggage(tag, rate);
+ return SCRIPT_CONT;
+}
+
+int Logic::fnMouseOn(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ cpt->o_status |= STAT_MOUSE;
+ return SCRIPT_CONT;
+}
+
+int Logic::fnMouseOff(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ cpt->o_status &= ~STAT_MOUSE;
+ return SCRIPT_CONT;
+}
+
+int Logic::fnChooser(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ _menu->fnChooser(cpt);
+ return SCRIPT_STOP;
+}
+
+int Logic::fnEndChooser(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ _menu->fnEndChooser();
+ return SCRIPT_CONT;
+}
+
+int Logic::fnStartMenu(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ _menu->fnStartMenu();
+ return SCRIPT_CONT;
+}
+
+int Logic::fnEndMenu(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ _menu->fnEndMenu();
+ return SCRIPT_CONT;
+}
+
+int Logic::cfnReleaseMenu(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ _menu->cfnReleaseMenu();
+ return SCRIPT_STOP;
+}
+
+int Logic::fnAddSubject(Object *cpt, int32 id, int32 sub, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ _menu->fnAddSubject(sub);
+ return SCRIPT_CONT;
+}
+
+int Logic::fnAddObject(Object *cpt, int32 id, int32 objectNo, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ _scriptVars[POCKET_1 + objectNo - 1] = 1; // basically means: carrying object objectNo = true;
+ return SCRIPT_CONT;
+}
+
+int Logic::fnRemoveObject(Object *cpt, int32 id, int32 objectNo, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ _scriptVars[POCKET_1 + objectNo - 1] = 0;
+ return SCRIPT_CONT;
+}
+
+int Logic::fnEnterSection(Object *cpt, int32 id, int32 screen, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ if (screen >= TOTAL_SECTIONS)
+ error("mega %d tried entering section %d", id, screen);
+
+ /* if (cpt->o_type == TYPE_PLAYER)
+ ^= this was the original condition from the game sourcecode.
+ not sure why it doesn't work*/
+ if (id == PLAYER)
+ _scriptVars[NEW_SCREEN] = screen;
+ else
+ cpt->o_screen = screen; // move the mega
+ _objMan->megaEntering(screen);
+ return SCRIPT_CONT;
+}
+
+int Logic::fnLeaveSection(Object *cpt, int32 id, int32 oldScreen, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ if (oldScreen >= TOTAL_SECTIONS)
+ error("mega %d leaving section %d", id, oldScreen);
+ _objMan->megaLeaving(oldScreen, id);
+ return SCRIPT_CONT;
+}
+
+int Logic::fnChangeFloor(Object *cpt, int32 id, int32 floor, int32 d, int32 e, int32 f, int32 z, int32 x) {
+ cpt->o_place = floor;
+ Object *floorCpt = _objMan->fetchObject(floor);
+ cpt->o_scale_a = floorCpt->o_scale_a;
+ cpt->o_scale_b = floorCpt->o_scale_b;
+ return SCRIPT_CONT;
+}
+
+int Logic::fnWalk(Object *cpt, int32 id, int32 x, int32 y, int32 dir, int32 stance, int32 a, int32 b) {
+ if (stance > 0)
+ dir = 9;
+ cpt->o_walk_pc = 0;
+ cpt->o_route[1].frame = 512; // end of sequence
+ if (id == PLAYER)
+ _router->setPlayerTarget(x, y, dir, stance);
+
+ int32 routeRes = _router->routeFinder(id, cpt, x, y, dir);
+
+ if (id == PLAYER) {
+ _router->resetExtraData();
+ if ((routeRes == 1) || (routeRes == 2)) {
+ _scriptVars[MEGA_ON_GRID] = 0;
+ _scriptVars[REROUTE_GEORGE] = 0;
+ }
+ }
+ if ((routeRes == 1) || (routeRes == 2)) {
+ cpt->o_down_flag = 1; // 1 means okay.
+ // if both mouse buttons were pressed on an exit => skip george's walk
+ if ((id == GEORGE) && (_mouse->testEvent() == MOUSE_BOTH_BUTTONS)) {
+ int32 target = _scriptVars[CLICK_ID];
+ // exceptions: compacts that use hand pointers but are not actually exits
+ if ((target != LEFT_SCROLL_POINTER) && (target != RIGHT_SCROLL_POINTER) &&
+ (target != FLOOR_63) && (target != ROOF_63) && (target != GUARD_ROOF_63) &&
+ (target != LEFT_TREE_POINTER_71) && (target != RIGHT_TREE_POINTER_71)) {
+
+ target = _objMan->fetchObject(_scriptVars[CLICK_ID])->o_mouse_on;
+ if ((target >= SCR_exit0) && (target <= SCR_exit9)) {
+ fnStandAt(cpt,id,x,y,dir,stance,0,0);
+ return SCRIPT_STOP;
+ }
+ }
+ }
+ cpt->o_logic = LOGIC_AR_animate;
+ return SCRIPT_STOP;
+ } else if (routeRes == 3)
+ cpt->o_down_flag = 1; // pretend it was successful
+ else
+ cpt->o_down_flag = 0; // 0 means error
+
+ return SCRIPT_CONT;
+}
+
+int Logic::fnTurn(Object *cpt, int32 id, int32 dir, int32 stance, int32 c, int32 d, int32 a, int32 b) {
+ if (stance > 0)
+ dir = 9;
+ int route = _router->routeFinder(id, cpt, cpt->o_xcoord, cpt->o_ycoord, dir);
+
+ if (route)
+ cpt->o_down_flag = 1; //1 means ok
+ else
+ cpt->o_down_flag = 0; //0 means error
+
+ cpt->o_logic = LOGIC_AR_animate;
+ cpt->o_walk_pc = 0; //reset
+
+ return SCRIPT_STOP;
+}
+
+int Logic::fnStand(Object *cpt, int32 id, int32 dir, int32 stance, int32 c, int32 d, int32 a, int32 b) {
+ if ((dir < 0) || (dir > 8)) {
+ warning("fnStand:: invalid direction %d", dir);
+ return SCRIPT_CONT;
+ }
+ if (dir == 8)
+ dir = cpt->o_dir;
+ cpt->o_resource = cpt->o_walk_resource;
+ cpt->o_status |= STAT_SHRINK;
+ cpt->o_anim_x = cpt->o_xcoord;
+ cpt->o_anim_y = cpt->o_ycoord;
+ cpt->o_frame = 96 + dir;
+ cpt->o_dir = dir;
+ return SCRIPT_STOP;
+}
+
+int Logic::fnStandAt(Object *cpt, int32 id, int32 x, int32 y, int32 dir, int32 stance, int32 a, int32 b) {
+ if ((dir < 0) || (dir > 8)) {
+ warning("fnStandAt:: invalid direction %d", dir);
+ return SCRIPT_CONT;
+ }
+ if (dir == 8)
+ dir = cpt->o_dir;
+ cpt->o_xcoord = x;
+ cpt->o_ycoord = y;
+ return fnStand(cpt, id, dir, stance, 0, 0, 0, 0);
+}
+
+int Logic::fnFace(Object *cpt, int32 id, int32 targetId, int32 b, int32 c, int32 d, int32 a, int32 z) {
+ Object *target = _objMan->fetchObject(targetId);
+ int32 x, y;
+ if ((target->o_type == TYPE_MEGA) || (target->o_type == TYPE_PLAYER)) {
+ x = target->o_xcoord;
+ y = target->o_ycoord;
+ } else {
+ x = (target->o_mouse_x1 + target->o_mouse_x2) / 2;
+ y = target->o_mouse_y2;
+ }
+ int32 megaTarDir = whatTarget(cpt->o_xcoord, cpt->o_ycoord, x, y);
+ fnTurn(cpt, id, megaTarDir, 0, 0, 0, 0, 0);
+ return SCRIPT_STOP;
+}
+
+int Logic::fnFaceXy(Object *cpt, int32 id, int32 x, int32 y, int32 c, int32 d, int32 a, int32 b) {
+ int megaTarDir = whatTarget(cpt->o_xcoord, cpt->o_ycoord, x, y);
+ fnTurn(cpt, id, megaTarDir, 0, 0, 0, 0, 0);
+ return SCRIPT_STOP;
+}
+
+int Logic::fnIsFacing(Object *cpt, int32 id, int32 targetId, int32 b, int32 c, int32 d, int32 a, int32 z) {
+ Object *target = _objMan->fetchObject(targetId);
+ int32 x, y, dir;
+ if ((target->o_type == TYPE_MEGA) || (target->o_type == TYPE_PLAYER)) {
+ x = target->o_xcoord;
+ y = target->o_ycoord;
+ dir = target->o_dir;
+ } else
+ error("fnIsFacing:: Target isn't a mega!");
+
+ int32 lookDir = whatTarget(x, y, cpt->o_xcoord, cpt->o_ycoord);
+ lookDir -= dir;
+ lookDir = ABS(lookDir);
+
+ if (lookDir > 4)
+ lookDir = 8 - lookDir;
+
+ _scriptVars[RETURN_VALUE] = lookDir;
+ return SCRIPT_STOP;
+}
+
+int Logic::fnGetTo(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
+ Object *place = _objMan->fetchObject(cpt->o_place);
+
+ cpt->o_tree.o_script_level++;
+ cpt->o_tree.o_script_pc[cpt->o_tree.o_script_level] = place->o_get_to_script;
+ cpt->o_tree.o_script_id[cpt->o_tree.o_script_level] = place->o_get_to_script;
+ return SCRIPT_STOP;
+}
+
+int Logic::fnGetToError(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
+ debug(1, "fnGetToError: compact %d at place %d no get-to for target %d, click_id %d\n", id, cpt->o_place, cpt->o_target, _scriptVars[CLICK_ID]);
+ return SCRIPT_CONT;
+}
+
+int Logic::fnRandom(Object *compact, int32 id, int32 min, int32 max, int32 e, int32 f, int32 z, int32 x) {
+ _scriptVars[RETURN_VALUE] = _rnd.getRandomNumberRng(min, max);
+ return SCRIPT_CONT;
+}
+
+int Logic::fnGetPos(Object *cpt, int32 id, int32 targetId, int32 b, int32 c, int32 d, int32 z, int32 x) {
+ Object *target = _objMan->fetchObject(targetId);
+ if ((target->o_type == TYPE_MEGA) || (target->o_type == TYPE_PLAYER)) {
+ _scriptVars[RETURN_VALUE] = target->o_xcoord;
+ _scriptVars[RETURN_VALUE_2] = target->o_ycoord;
+ } else {
+ _scriptVars[RETURN_VALUE] = (target->o_mouse_x1 + target->o_mouse_x2) / 2;
+ _scriptVars[RETURN_VALUE_2] = target->o_mouse_y2;
+ }
+ _scriptVars[RETURN_VALUE_3] = target->o_dir;
+
+ int32 megaSeperation;
+ if (targetId == DUANE)
+ megaSeperation = 70; // George & Duane stand with feet 70 pixels apart when at full scale
+ else if (targetId == BENOIR)
+ megaSeperation = 61; // George & Benoir
+ else
+ megaSeperation = 42; // George & Nico/Goinfre stand with feet 42 pixels apart when at full scale
+
+ if (target->o_status & STAT_SHRINK) {
+ int32 scale = (target->o_scale_a * target->o_ycoord + target->o_scale_b) / 256;
+ _scriptVars[RETURN_VALUE_4] = (megaSeperation * scale) / 256;
+ } else
+ _scriptVars[RETURN_VALUE_4] = megaSeperation;
+ return SCRIPT_CONT;
+}
+
+int Logic::fnGetGamepadXy(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
+ // playstation only
+ return SCRIPT_CONT;
+}
+
+int Logic::fnPlayFx(Object *cpt, int32 id, int32 fxNo, int32 b, int32 c, int32 d, int32 z, int32 x) {
+ _scriptVars[RETURN_VALUE] = _sound->addToQueue(fxNo);
+ return SCRIPT_CONT;
+}
+
+int Logic::fnStopFx(Object *cpt, int32 id, int32 fxNo, int32 b, int32 c, int32 d, int32 z, int32 x) {
+ _sound->fnStopFx(fxNo);
+ //_sound->removeFromQueue(fxNo);
+ return SCRIPT_CONT;
+}
+
+int Logic::fnPlayMusic(Object *cpt, int32 id, int32 tuneId, int32 loopFlag, int32 c, int32 d, int32 z, int32 x) {
+ if (tuneId == 153)
+ return SCRIPT_CONT;
+ if (loopFlag == LOOPED)
+ _scriptVars[CURRENT_MUSIC] = tuneId; // so it gets restarted when saving & reloading
+ else
+ _scriptVars[CURRENT_MUSIC] = 0;
+
+ _music->startMusic(tuneId, loopFlag);
+ return SCRIPT_CONT;
+}
+
+int Logic::fnStopMusic(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
+ _scriptVars[CURRENT_MUSIC] = 0;
+ _music->fadeDown();
+ return SCRIPT_CONT;
+}
+
+int Logic::fnInnerSpace(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
+ error("fnInnerSpace() not working.");
+ return SCRIPT_STOP;
+}
+
+int Logic::fnSetScreen(Object *cpt, int32 id, int32 target, int32 screen, int32 c, int32 d, int32 z, int32 x) {
+ _objMan->fetchObject(target)->o_screen = screen;
+ return SCRIPT_CONT;
+}
+
+int Logic::fnPreload(Object *cpt, int32 id, int32 resId, int32 b, int32 c, int32 d, int32 z, int32 x) {
+ _resMan->resOpen(resId);
+ _resMan->resClose(resId);
+ return SCRIPT_CONT;
+}
+
+int Logic::fnCheckCD(Object *cpt, int32 id, int32 screen, int32 b, int32 c, int32 d, int32 z, int32 x) {
+ // only a dummy, here.
+ // the check is done in the mainloop
+ return SCRIPT_CONT;
+}
+
+int Logic::fnRestartGame(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
+ SwordEngine::_systemVars.forceRestart = true;
+ cpt->o_logic = LOGIC_quit;
+ return SCRIPT_STOP;
+}
+
+int Logic::fnQuitGame(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
+ if (SwordEngine::_systemVars.isDemo) {
+ GUI::MessageDialog dialog("This is the end of the Broken Sword 1 Demo", "OK", NULL);
+ dialog.runModal();
+ SwordEngine::_systemVars.engineQuit = true;
+ } else
+ error("fnQuitGame() called");
+ return SCRIPT_STOP;
+}
+
+int Logic::fnDeathScreen(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
+
+ if (_scriptVars[FINALE_OPTION_FLAG] == 4) // successful end of game!
+ SwordEngine::_systemVars.controlPanelMode = CP_THEEND;
+ else
+ SwordEngine::_systemVars.controlPanelMode = CP_DEATHSCREEN;
+
+ cpt->o_logic = LOGIC_quit;
+ return SCRIPT_STOP;
+}
+
+int Logic::fnSetParallax(Object *cpt, int32 id, int32 screen, int32 resId, int32 c, int32 d, int32 z, int32 x) {
+ _screen->fnSetParallax(screen, resId);
+ return SCRIPT_CONT;
+}
+
+int Logic::fnTdebug(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
+ debug(1, "Script TDebug id %d code %d, %d", id, a, b);
+ return SCRIPT_CONT;
+}
+
+int Logic::fnRedFlash(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
+ _screen->fnFlash(FLASH_RED);
+ return SCRIPT_CONT;
+}
+
+int Logic::fnBlueFlash(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
+ _screen->fnFlash(FLASH_BLUE);
+ return SCRIPT_CONT;
+}
+
+int Logic::fnYellow(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
+ _screen->fnFlash(BORDER_YELLOW);
+ return SCRIPT_CONT;
+}
+
+int Logic::fnGreen(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
+ _screen->fnFlash(BORDER_GREEN);
+ return SCRIPT_CONT;
+}
+
+int Logic::fnPurple(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
+ _screen->fnFlash(BORDER_PURPLE);
+ return SCRIPT_CONT;
+}
+
+int Logic::fnBlack(Object *cpt, int32 id, int32 a, int32 b, int32 c, int32 d, int32 z, int32 x) {
+ _screen->fnFlash(BORDER_BLACK);
+ return SCRIPT_CONT;
+}
+
+uint16 Logic::inRange(uint16 a, uint16 b, uint16 c) {
+ return (a > b)? a : (((b > c) ? c : b));
+}
+
+void Logic::startPosCallFn(uint8 fnId, uint32 param1, uint32 param2, uint32 param3) {
+ Object *obj = NULL;
+ switch (fnId) {
+ case opcPlaySequence:
+ fnPlaySequence(NULL, 0, param1, 0, 0, 0, 0, 0);
+ break;
+ case opcAddObject:
+ fnAddObject(NULL, 0, param1, 0, 0, 0, 0, 0);
+ break;
+ case opcRemoveObject:
+ fnRemoveObject(NULL, 0, param1, 0, 0, 0, 0, 0);
+ break;
+ case opcMegaSet:
+ obj = _objMan->fetchObject(param1);
+ fnMegaSet(obj, param1, param2, param3, 0, 0, 0, 0);
+ break;
+ case opcNoSprite:
+ obj = _objMan->fetchObject(param1);
+ fnNoSprite(obj, param1, param2, param3, 0, 0, 0, 0);
+ break;
+ default:
+ error("Illegal fnCallfn argument %d", fnId);
+ }
+}
+
+void Logic::runStartScript(const uint8 *data) {
+ uint16 varId = 0;
+ uint8 fnId = 0;
+ uint32 param1 = 0;
+ while (*data != opcSeqEnd) {
+ switch (*data++) {
+ case opcCallFn:
+ fnId = *data++;
+ param1 = *data++;
+ startPosCallFn(fnId, param1, 0, 0);
+ break;
+ case opcCallFnLong:
+ fnId = *data++;
+ startPosCallFn(fnId, READ_LE_UINT32(data), READ_LE_UINT32(data + 4), READ_LE_UINT32(data + 8));
+ data += 12;
+ break;
+ case opcSetVar8:
+ varId = READ_LE_UINT16(data);
+ _scriptVars[varId] = data[2];
+ data += 3;
+ break;
+ case opcSetVar16:
+ varId = READ_LE_UINT16(data);
+ _scriptVars[varId] = READ_LE_UINT16(data + 2);
+ data += 4;
+ break;
+ case opcSetVar32:
+ varId = READ_LE_UINT16(data);
+ _scriptVars[varId] = READ_LE_UINT32(data + 2);
+ data += 6;
+ break;
+ case opcGeorge:
+ _scriptVars[CHANGE_X] = READ_LE_UINT16(data + 0);
+ _scriptVars[CHANGE_Y] = READ_LE_UINT16(data + 2);
+ _scriptVars[CHANGE_DIR] = data[4];
+ _scriptVars[CHANGE_PLACE] = READ_LE_UINT24(data + 5);
+ data += 8;
+ break;
+ case opcRunStart:
+ data = _startData[*data];
+ break;
+ case opcRunHelper:
+ data = _helperData[*data];
+ break;
+ default:
+ error("Unexpected opcode in StartScript");
+ }
+ }
+}
+
+void Logic::startPositions(uint32 pos) {
+ bool spainVisit2 = false;
+ if ((pos >= 956) && (pos <= 962)) {
+ spainVisit2 = true;
+ pos -= 900;
+ }
+ if ((pos > 80) || (_startData[pos] == NULL))
+ error("Starting in Section %d is not supported", pos);
+
+ Logic::_scriptVars[CHANGE_STANCE] = STAND;
+ Logic::_scriptVars[GEORGE_CDT_FLAG] = GEO_TLK_TABLE;
+
+ runStartScript(_startData[pos]);
+ if (spainVisit2)
+ runStartScript(_helperData[HELP_SPAIN2]);
+
+ if (pos == 0)
+ pos = 1;
+ Object *compact = _objMan->fetchObject(PLAYER);
+ fnEnterSection(compact, PLAYER, pos, 0, 0, 0, 0, 0); // (automatically opens the compact resource for that section)
+ SwordEngine::_systemVars.controlPanelMode = CP_NORMAL;
+ SwordEngine::_systemVars.wantFade = true;
+}
+
+const uint32 Logic::_scriptVarInit[NON_ZERO_SCRIPT_VARS][2] = {
+ { 42, 448}, { 43, 378}, { 51, 1}, { 92, 1}, { 147, 71}, { 201, 1},
+ { 209, 1}, { 215, 1}, { 242, 2}, { 244, 1}, { 246, 3}, { 247, 1},
+ { 253, 1}, { 297, 1}, { 398, 1}, { 508, 1}, { 605, 1}, { 606, 1},
+ { 701, 1}, { 709, 1}, { 773, 1}, { 843, 1}, { 907, 1}, { 923, 1},
+ { 966, 1}, { 988, 2}, {1058, 1}, {1059, 2}, {1060, 3}, {1061, 4},
+ {1062, 5}, {1063, 6}, {1064, 7}, {1065, 8}, {1066, 9}, {1067, 10},
+ {1068, 11}, {1069, 12}, {1070, 13}, {1071, 14}, {1072, 15}, {1073, 16},
+ {1074, 17}, {1075, 18}, {1076, 19}, {1077, 20}, {1078, 21}, {1079, 22},
+ {1080, 23}, {1081, 24}, {1082, 25}, {1083, 26}, {1084, 27}, {1085, 28},
+ {1086, 29}, {1087, 30}, {1088, 31}, {1089, 32}, {1090, 33}, {1091, 34},
+ {1092, 35}, {1093, 36}, {1094, 37}, {1095, 38}, {1096, 39}, {1097, 40},
+ {1098, 41}, {1099, 42}, {1100, 43}, {1101, 44}, {1102, 48}, {1103, 45},
+ {1104, 47}, {1105, 49}, {1106, 50}, {1107, 52}, {1108, 54}, {1109, 56},
+ {1110, 57}, {1111, 58}, {1112, 59}, {1113, 60}, {1114, 61}, {1115, 62},
+ {1116, 63}, {1117, 64}, {1118, 65}, {1119, 66}, {1120, 67}, {1121, 68},
+ {1122, 69}, {1123, 71}, {1124, 72}, {1125, 73}, {1126, 74}
+};
+
+} // End of namespace Sword1
diff --git a/engines/sword1/logic.h b/engines/sword1/logic.h
new file mode 100644
index 0000000000..32977dc83c
--- /dev/null
+++ b/engines/sword1/logic.h
@@ -0,0 +1,239 @@
+/* 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 BSLOGIC_H
+#define BSLOGIC_H
+// combination of logic.c and scr_int.c
+
+#include "sword1/sworddefs.h"
+#include "sword1/objectman.h"
+#include "common/util.h"
+#include "sound/mixer.h"
+
+namespace Sword1 {
+
+#define NON_ZERO_SCRIPT_VARS 95
+#define NUM_SCRIPT_VARS 1179
+
+class Text;
+class Sound;
+class EventManager;
+class Menu;
+class Router;
+class Screen;
+class Mouse;
+class Music;
+
+class Logic;
+typedef int (Logic::*BSMcodeTable)(Object *, int32, int32, int32, int32, int32, int32, int32);
+
+class Logic {
+public:
+ Logic(ObjectMan *pObjMan, ResMan *resMan, Screen *pScreen, Mouse *pMouse, Sound *pSound, Music *pMusic, Menu *pMenu, OSystem *system, Audio::Mixer *mixer);
+ ~Logic(void);
+ void initialize(void);
+ void newScreen(uint32 screen);
+ void engine(void);
+ void updateScreenParams(void);
+ void runMouseScript(Object *cpt, int32 scriptId);
+ void startPositions(uint32 pos);
+
+ static uint32 _scriptVars[NUM_SCRIPT_VARS];
+// public for mouse (menu looking)
+ int cfnPresetScript (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+private:
+ ObjectMan *_objMan;
+ OSystem *_system;
+ Audio::Mixer *_mixer;
+ ResMan *_resMan;
+ Screen *_screen;
+ Sound *_sound;
+ Mouse *_mouse;
+ Router *_router;
+ Text *_textMan;
+ EventManager *_eventMan;
+ Menu *_menu;
+ Music *_music;
+ uint32 _newScript; // <= ugly, but I can't avoid it.
+ bool _speechRunning, _speechFinished, _textRunning;
+ uint8 _speechClickDelay;
+ Common::RandomSource _rnd;
+
+ int scriptManager(Object *compact, uint32 id);
+ void processLogic(Object *compact, uint32 id);
+ int interpretScript(Object *compact, int id, Header *scriptModule, int scriptBase, int scriptNum);
+
+ int logicWaitTalk(Object *compact);
+ int logicStartTalk(Object *compact);
+ int logicArAnimate(Object *compact, uint32 id);
+ int speechDriver(Object *compact);
+ int fullAnimDriver(Object *compact);
+ int animDriver(Object *compact);
+
+ static BSMcodeTable _mcodeTable[100];
+
+ uint16 inRange(uint16 a, uint16 b, uint16 c);
+
+//- mcodeTable:
+ int fnBackground (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnForeground (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnSort (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnNoSprite (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnMegaSet (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnAnim (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnSetFrame (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnFullAnim (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnFullSetFrame (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnFadeDown (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnFadeUp (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnCheckFade (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnSetSpritePalette(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnSetWholePalette(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnSetFadeTargetPalette(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnSetPaletteToFade(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnSetPaletteToCut(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnPlaySequence (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+
+ int fnIdle (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnPause (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnPauseSeconds (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnQuit (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnKillId (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnSuicide (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnNewScript (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnSubScript (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnRestartScript (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnSetBookmark (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnGotoBookmark (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnSendSync (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnWaitSync (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+
+ int cfnClickInteract(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int cfnSetScript (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+
+ int fnInteract (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnIssueEvent (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnCheckForEvent (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnWipeHands (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnISpeak (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnTheyDo (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnTheyDoWeWait (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnWeWait (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnChangeSpeechText(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnTalkError (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnStartTalk (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnCheckForTextLine(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnAddTalkWaitStatusBit(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnRemoveTalkWaitStatusBit(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+
+ int fnNoHuman (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnAddHuman (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnBlankMouse (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnNormalMouse (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnLockMouse (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnUnlockMouse (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnSetMousePointer(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnSetMouseLuggage(Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnMouseOn (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnMouseOff (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnChooser (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnEndChooser (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnStartMenu (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnEndMenu (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+
+ int cfnReleaseMenu (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+
+ int fnAddSubject (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnAddObject (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnRemoveObject (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnEnterSection (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnLeaveSection (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnChangeFloor (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnWalk (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnTurn (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnStand (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnStandAt (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnFace (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnFaceXy (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnIsFacing (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnGetTo (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnGetToError (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnGetPos (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnGetGamepadXy (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnPlayFx (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnStopFx (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnPlayMusic (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnStopMusic (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnInnerSpace (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnRandom (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnSetScreen (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnPreload (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnCheckCD (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnRestartGame (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnQuitGame (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnDeathScreen (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnSetParallax (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnTdebug (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+
+ int fnRedFlash (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnBlueFlash (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnYellow (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnGreen (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnPurple (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ int fnBlack (Object *cpt, int32 id, int32 c, int32 d, int32 e, int32 f, int32 z, int32 x);
+ static const uint32 _scriptVarInit[NON_ZERO_SCRIPT_VARS][2];
+ static const uint8 *_startData[];
+ static const uint8 *_helperData[];
+ void startPosCallFn(uint8 fnId, uint32 param1, uint32 param2, uint32 param3);
+ void runStartScript(const uint8 *data);
+};
+
+enum StartPosOpcodes {
+ opcSeqEnd = 0,
+ opcCallFn,
+ opcCallFnLong,
+ opcSetVar8,
+ opcSetVar16,
+ opcSetVar32,
+ opcGeorge,
+ opcRunStart,
+ opcRunHelper,
+ opcPlaySequence,
+ opcAddObject,
+ opcRemoveObject,
+ opcMegaSet,
+ opcNoSprite
+};
+
+enum HelperScripts {
+ HELP_IRELAND = 0,
+ HELP_SYRIA,
+ HELP_SPAIN,
+ HELP_NIGHTTRAIN,
+ HELP_SCOTLAND,
+ HELP_WHITECOAT,
+ HELP_SPAIN2
+};
+
+} // End of namespace Sword1
+
+#endif //BSLOGIC_H
diff --git a/engines/sword1/memman.cpp b/engines/sword1/memman.cpp
new file mode 100644
index 0000000000..b9b0dc5d24
--- /dev/null
+++ b/engines/sword1/memman.cpp
@@ -0,0 +1,129 @@
+/* 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 "sword1/memman.h"
+#include "common/util.h"
+
+namespace Sword1 {
+
+MemMan::MemMan(void) {
+ _alloced = 0;
+ _memListFree = _memListFreeEnd = NULL;
+}
+
+MemMan::~MemMan(void) {
+ flush();
+ if (_alloced)
+ warning("deleting MemMan, still %d bytes alloced\n", _alloced);
+}
+
+void MemMan::alloc(MemHandle *bsMem, uint32 pSize, uint16 pCond) {
+ _alloced += pSize;
+ bsMem->data = (void*)malloc(pSize);
+ if (!bsMem->data)
+ error("MemMan::alloc(): Can't alloc %d bytes of memory.", pSize);
+ bsMem->cond = pCond;
+ bsMem->size = pSize;
+ if (pCond == MEM_CAN_FREE) {
+ warning("%d Bytes alloced as FREEABLE.", pSize); // why should one want to alloc mem if it can be freed?
+ addToFreeList(bsMem);
+ } else if (bsMem->next || bsMem->prev) // it's in our _freeAble list, remove it from there
+ removeFromFreeList(bsMem);
+ checkMemoryUsage();
+}
+
+void MemMan::freeNow(MemHandle *bsMem) {
+ if (bsMem->cond != MEM_FREED) {
+ _alloced -= bsMem->size;
+ removeFromFreeList(bsMem);
+ free(bsMem->data);
+ bsMem->cond = MEM_FREED;
+ }
+}
+
+void MemMan::setCondition(MemHandle *bsMem, uint16 pCond) {
+ if ((pCond == MEM_FREED) || (pCond > MEM_DONT_FREE))
+ error("MemMan::setCondition: program tried to set illegal memory condition");
+ if (bsMem->cond != pCond) {
+ bsMem->cond = pCond;
+ if (pCond == MEM_DONT_FREE)
+ removeFromFreeList(bsMem);
+ else if (pCond == MEM_CAN_FREE)
+ addToFreeList(bsMem);
+ }
+}
+
+void MemMan::flush(void) {
+ while (_memListFree) {
+ free(_memListFreeEnd->data);
+ _memListFreeEnd->data = NULL;
+ _memListFreeEnd->cond = MEM_FREED;
+ _alloced -= _memListFreeEnd->size;
+ removeFromFreeList(_memListFreeEnd);
+ }
+ if (_alloced)
+ warning("MemMan::flush: Something's wrong: still %d bytes alloced", _alloced);
+}
+
+void MemMan::checkMemoryUsage(void) {
+ while ((_alloced > MAX_ALLOC) && _memListFree) {
+ free(_memListFreeEnd->data);
+ _memListFreeEnd->data = NULL;
+ _memListFreeEnd->cond = MEM_FREED;
+ _alloced -= _memListFreeEnd->size;
+ removeFromFreeList(_memListFreeEnd);
+ }
+}
+
+void MemMan::addToFreeList(MemHandle *bsMem) {
+ if (bsMem->next || bsMem->prev) {
+ warning("addToFreeList: mem block is already in freeList");
+ return;
+ }
+ bsMem->prev = NULL;
+ bsMem->next = _memListFree;
+ if (bsMem->next)
+ bsMem->next->prev = bsMem;
+ _memListFree = bsMem;
+ if (!_memListFreeEnd)
+ _memListFreeEnd = _memListFree;
+}
+
+void MemMan::removeFromFreeList(MemHandle *bsMem) {
+ if (_memListFree == bsMem)
+ _memListFree = bsMem->next;
+ if (_memListFreeEnd == bsMem)
+ _memListFreeEnd = bsMem->prev;
+
+ if (bsMem->next)
+ bsMem->next->prev = bsMem->prev;
+ if (bsMem->prev)
+ bsMem->prev->next = bsMem->next;
+ bsMem->next = bsMem->prev = NULL;
+}
+
+void MemMan::initHandle(MemHandle *bsMem) {
+ memset(bsMem, 0, sizeof(MemHandle));
+}
+
+} // End of namespace Sword1
diff --git a/engines/sword1/memman.h b/engines/sword1/memman.h
new file mode 100644
index 0000000000..e230fac1af
--- /dev/null
+++ b/engines/sword1/memman.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 MEMMAN_H
+#define MEMMAN_H
+
+#include "common/scummsys.h"
+
+namespace Sword1 {
+
+struct MemHandle {
+ void *data;
+ uint32 size;
+ uint32 refCount;
+ uint16 cond;
+ MemHandle *next, *prev;
+};
+// mem conditions:
+#define MEM_FREED 0
+#define MEM_CAN_FREE 1
+#define MEM_DONT_FREE 2
+
+#define MAX_ALLOC (6*1024*1024) // max amount of mem we want to alloc().
+
+class MemMan {
+public:
+ MemMan(void);
+ ~MemMan(void);
+ void alloc(MemHandle *bsMem, uint32 pSize, uint16 pCond = MEM_DONT_FREE);
+ void setCondition(MemHandle *bsMem, uint16 pCond);
+ void freeNow(MemHandle *bsMem);
+ void initHandle(MemHandle *bsMem);
+ void flush(void);
+private:
+ void addToFreeList(MemHandle *bsMem);
+ void removeFromFreeList(MemHandle *bsMem);
+ void checkMemoryUsage(void);
+ uint32 _alloced; //currently allocated memory
+ MemHandle *_memListFree;
+ MemHandle *_memListFreeEnd;
+};
+
+} // End of namespace Sword1
+
+#endif //MEMMAN_H
diff --git a/engines/sword1/menu.cpp b/engines/sword1/menu.cpp
new file mode 100644
index 0000000000..1266d39daa
--- /dev/null
+++ b/engines/sword1/menu.cpp
@@ -0,0 +1,393 @@
+/* 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 "sword1/menu.h"
+#include "sword1/resman.h"
+#include "common/scummsys.h"
+#include "common/util.h"
+#include "common/system.h"
+#include "sword1/mouse.h"
+#include "sword1/screen.h"
+#include "sword1/logic.h"
+
+namespace Sword1 {
+
+enum {
+ MENU_CLOSED,
+ MENU_CLOSING,
+ MENU_OPENING,
+ MENU_OPEN
+};
+
+const byte Menu::_fadeEffectTop[64] = {
+ 1, 7, 5, 3, 2, 4, 6, 0,
+ 3, 1, 7, 5, 4, 6, 0, 2,
+ 5, 3, 1, 7, 6, 0, 2, 4,
+ 7, 5, 3, 1, 0, 2, 4, 6,
+ 7, 5, 3, 1, 0, 2, 4, 6,
+ 5, 3, 1, 7, 6, 0, 2, 4,
+ 3, 1, 7, 5, 4, 6, 0, 2,
+ 1, 7, 5, 3, 2, 4, 6, 0
+};
+
+const byte Menu::_fadeEffectBottom[64] = {
+ 7, 6, 5, 4, 3, 2, 1, 0,
+ 0, 7, 6, 5, 4, 3, 2, 1,
+ 1, 0, 7, 6, 5, 4, 3, 2,
+ 2, 1, 0, 7, 6, 5, 4, 3,
+ 3, 2, 1, 0, 7, 6, 5, 4,
+ 4, 3, 2, 1, 0, 7, 6, 5,
+ 5, 4, 3, 2, 1, 0, 7, 6,
+ 6, 5, 4, 3, 2, 1, 0, 7
+};
+
+MenuIcon::MenuIcon(uint8 menuType, uint8 menuPos, uint32 resId, uint32 frame, Screen *screen) {
+ _menuType = menuType;
+ _menuPos = menuPos;
+ _resId = resId;
+ _frame = frame;
+ _screen = screen;
+ _selected = false;
+}
+
+bool MenuIcon::wasClicked(uint16 mouseX, uint16 mouseY) {
+ if (((_menuType == MENU_TOP) && (mouseY >= 40)) || ((_menuType == MENU_BOT) && (mouseY < 440)))
+ return false;
+ if ((mouseX >= _menuPos * 40) && (mouseX < (_menuPos + 1) * 40))
+ return true;
+ else
+ return false;
+}
+
+void MenuIcon::setSelect(bool pSel) {
+ _selected = pSel;
+}
+
+void MenuIcon::draw(const byte *fadeMask, int8 fadeStatus) {
+ uint16 x = _menuPos * 40;
+ uint16 y = (_menuType == MENU_TOP)?(0):(440);
+ _screen->showFrame(x, y, _resId, _frame + (_selected ? 1 : 0), fadeMask, fadeStatus);
+}
+
+Menu::Menu(Screen *pScreen, Mouse *pMouse) {
+ uint8 cnt;
+ _screen = pScreen;
+ _mouse = pMouse;
+ _subjectBarStatus = MENU_CLOSED;
+ _objectBarStatus = MENU_CLOSED;
+ _fadeSubject = 0;
+ _fadeObject = 0;
+ for (cnt = 0; cnt < 16; cnt++)
+ _subjects[cnt] = NULL;
+ for (cnt = 0; cnt < TOTAL_pockets; cnt++)
+ _objects[cnt] = NULL;
+ _inMenu = 0;
+}
+
+Menu::~Menu(void) {
+ int i;
+ // the menu may be open, so delete the icons
+ for (i = 0; i < TOTAL_pockets; i++) {
+ delete _objects[i];
+ _objects[i] = NULL;
+ }
+ for (i = 0; i < 16; i++) {
+ delete _subjects[i];
+ _subjects[i] = NULL;
+ }
+}
+
+void Menu::refreshMenus() {
+ if (_objectBarStatus == MENU_OPEN) {
+ buildMenu();
+ for (uint8 cnt = 0; cnt < 16; cnt++) {
+ if (_objects[cnt])
+ _objects[cnt]->draw();
+ else
+ _screen->showFrame(cnt * 40, 0, 0xffffffff, 0);
+ }
+ }
+ if (_subjectBarStatus == MENU_OPEN) {
+ buildSubjects();
+ for (uint8 cnt = 0; cnt < 16; cnt++) {
+ if (_subjects[cnt])
+ _subjects[cnt]->draw();
+ else
+ _screen->showFrame(cnt * 40, 440, 0xffffffff, 0);
+ }
+ }
+}
+
+uint8 Menu::checkMenuClick(uint8 menuType) {
+ uint16 mouseEvent = _mouse->testEvent();
+ if (!mouseEvent)
+ return 0;
+ uint16 x, y;
+ _mouse->giveCoords(&x, &y);
+ if (_subjectBarStatus == MENU_OPEN) {
+ // Conversation mode. Icons are highlighted on mouse-down, but
+ // the actual response is made on mouse-up.
+ if (menuType == MENU_BOT) {
+ if (Logic::_scriptVars[OBJECT_HELD] && (mouseEvent & BS1L_BUTTON_UP)) {
+ for (uint8 cnt = 0; cnt < Logic::_scriptVars[IN_SUBJECT]; cnt++) {
+ if (_subjectBar[cnt] == Logic::_scriptVars[OBJECT_HELD])
+ return cnt + 1;
+ }
+ } else if (mouseEvent & BS1L_BUTTON_DOWN) {
+ for (uint8 cnt = 0; cnt < Logic::_scriptVars[IN_SUBJECT]; cnt++) {
+ if (_subjects[cnt]->wasClicked(x, y)) {
+ Logic::_scriptVars[OBJECT_HELD] = _subjectBar[cnt];
+ refreshMenus();
+ break;
+ }
+ }
+ }
+ } else {
+ if (Logic::_scriptVars[OBJECT_HELD] && (mouseEvent & BS1L_BUTTON_UP)) {
+ for (uint8 cnt = 0; cnt < _inMenu; cnt++) {
+ if (_menuList[cnt] == Logic::_scriptVars[OBJECT_HELD])
+ return cnt + 1;
+ }
+ } else if (mouseEvent & BS1L_BUTTON_DOWN) {
+ for (uint8 cnt = 0; cnt < _inMenu; cnt++) {
+ if (_objects[cnt]->wasClicked(x, y)) {
+ Logic::_scriptVars[OBJECT_HELD] = _menuList[cnt];
+ refreshMenus();
+ break;
+ }
+ }
+ }
+ }
+ } else {
+ // Normal use, i.e. inventory. Things happen on mouse-down.
+ if (menuType == MENU_TOP) {
+ for (uint8 cnt = 0; cnt < _inMenu; cnt++) {
+ if (_objects[cnt]->wasClicked(x, y)) {
+ if (mouseEvent & BS1R_BUTTON_DOWN) { // looking at item
+ Logic::_scriptVars[OBJECT_HELD] = _menuList[cnt];
+ Logic::_scriptVars[MENU_LOOKING] = 1;
+ Logic::_scriptVars[DEFAULT_ICON_TEXT] = _objectDefs[_menuList[cnt]].textDesc;
+ } else if (mouseEvent & BS1L_BUTTON_DOWN) {
+ if (Logic::_scriptVars[OBJECT_HELD]) {
+ if (Logic::_scriptVars[OBJECT_HELD] == _menuList[cnt]) {
+ _mouse->setLuggage(0, 0);
+ Logic::_scriptVars[OBJECT_HELD] = 0; // reselected => deselect it
+ } else { // the player is clicking another item on this one.
+ // run its use-script, if there is one
+ Logic::_scriptVars[SECOND_ITEM] = _menuList[cnt];
+ _mouse->setLuggage(0, 0);
+ }
+ } else {
+ Logic::_scriptVars[OBJECT_HELD] = _menuList[cnt];
+ _mouse->setLuggage(_objectDefs[_menuList[cnt]].luggageIconRes, 0);
+ }
+ }
+ refreshMenus();
+ break;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+void Menu::buildSubjects(void) {
+ uint8 cnt;
+ for (cnt = 0; cnt < 16; cnt++)
+ if (_subjects[cnt]) {
+ delete _subjects[cnt];
+ _subjects[cnt] = NULL;
+ }
+ for (cnt = 0; cnt < Logic::_scriptVars[IN_SUBJECT]; cnt++) {
+ uint32 res = _subjectList[(_subjectBar[cnt] & 65535) - BASE_SUBJECT].subjectRes;
+ uint32 frame = _subjectList[(_subjectBar[cnt] & 65535) - BASE_SUBJECT].frameNo;
+ _subjects[cnt] = new MenuIcon(MENU_BOT, cnt, res, frame, _screen);
+ if (Logic::_scriptVars[OBJECT_HELD])
+ _subjects[cnt]->setSelect(_subjectBar[cnt] == Logic::_scriptVars[OBJECT_HELD]);
+ else
+ _subjects[cnt]->setSelect(true);
+ }
+}
+
+void Menu::refresh(uint8 menuType) {
+ uint i;
+
+ if (menuType == MENU_TOP) {
+ if (_objectBarStatus == MENU_OPENING || _objectBarStatus == MENU_CLOSING) {
+ for (i = 0; i < 16; i++) {
+ if (_objects[i])
+ _objects[i]->draw(_fadeEffectTop, _fadeObject);
+ else
+ _screen->showFrame(i * 40, 0, 0xffffffff, 0, _fadeEffectTop, _fadeObject);
+ }
+ }
+ if (_objectBarStatus == MENU_OPENING) {
+ if (_fadeObject < 8)
+ _fadeObject++;
+ else
+ _objectBarStatus = MENU_OPEN;
+ } else if (_objectBarStatus == MENU_CLOSING) {
+ if (_fadeObject > 0)
+ _fadeObject--;
+ else {
+ for (i = 0; i < _inMenu; i++) {
+ delete _objects[i];
+ _objects[i] = NULL;
+ }
+ _objectBarStatus = MENU_CLOSED;
+ }
+ }
+ } else {
+ if (_subjectBarStatus == MENU_OPENING || _subjectBarStatus == MENU_CLOSING) {
+ for (i = 0; i < 16; i++) {
+ if (_subjects[i])
+ _subjects[i]->draw(_fadeEffectBottom, _fadeSubject);
+ else
+ _screen->showFrame(i * 40, 440, 0xffffffff, 0, _fadeEffectBottom, _fadeSubject);
+ }
+ }
+ if (_subjectBarStatus == MENU_OPENING) {
+ if (_fadeSubject < 8)
+ _fadeSubject++;
+ else
+ _subjectBarStatus = MENU_OPEN;
+ } else if (_subjectBarStatus == MENU_CLOSING) {
+ if (_fadeSubject > 0)
+ _fadeSubject--;
+ else {
+ for (i = 0; i < Logic::_scriptVars[IN_SUBJECT]; i++) {
+ delete _subjects[i];
+ _subjects[i] = NULL;
+ }
+ _subjectBarStatus = MENU_CLOSED;
+ }
+ }
+ }
+}
+
+void Menu::buildMenu(void) {
+ uint32 *pockets = Logic::_scriptVars + POCKET_1;
+ for (uint8 cnt = 0; cnt < _inMenu; cnt++)
+ if (_objects[cnt]) {
+ delete _objects[cnt];
+ _objects[cnt] = NULL;
+ }
+ _inMenu = 0;
+ for (uint32 pocketNo = 0; pocketNo < TOTAL_pockets; pocketNo++)
+ if (pockets[pocketNo]) {
+ _menuList[_inMenu] = pocketNo + 1;
+ _inMenu++;
+ }
+ for (uint32 menuSlot = 0; menuSlot < _inMenu; menuSlot++) {
+ _objects[menuSlot] = new MenuIcon(MENU_TOP, menuSlot, _objectDefs[_menuList[menuSlot]].bigIconRes, _objectDefs[_menuList[menuSlot]].bigIconFrame, _screen);
+ uint32 objHeld = Logic::_scriptVars[OBJECT_HELD];
+
+ // check highlighting
+ if (Logic::_scriptVars[MENU_LOOKING] || _subjectBarStatus == MENU_OPEN) { // either we're in the chooser or we're doing a 'LOOK AT'
+ if ((!objHeld) || (objHeld == _menuList[menuSlot]))
+ _objects[menuSlot]->setSelect(true);
+ } else if (Logic::_scriptVars[SECOND_ITEM]) { // clicked luggage onto 2nd icon - we need to colour-highlight the 2 relevant icons & grey out the rest
+ if ((_menuList[menuSlot] == objHeld) || (_menuList[menuSlot] == Logic::_scriptVars[SECOND_ITEM]))
+ _objects[menuSlot]->setSelect(true);
+ } else { // this object is selected - ie. GREYED OUT
+ if (objHeld != _menuList[menuSlot])
+ _objects[menuSlot]->setSelect(true);
+ }
+ }
+}
+
+void Menu::showMenu(uint8 menuType) {
+ if (menuType == MENU_TOP) {
+ if (_objectBarStatus == MENU_OPEN) {
+ for (uint8 cnt = 0; cnt < 16; cnt++) {
+ if (_objects[cnt])
+ _objects[cnt]->draw();
+ else
+ _screen->showFrame(cnt * 40, 0, 0xffffffff, 0);
+ }
+ } else if (_objectBarStatus == MENU_CLOSED) {
+ _objectBarStatus = MENU_OPENING;
+ _fadeObject = 0;
+ } else if (_objectBarStatus == MENU_CLOSING)
+ _objectBarStatus = MENU_OPENING;
+ }
+}
+
+void Menu::fnStartMenu(void) {
+ Logic::_scriptVars[OBJECT_HELD] = 0; // icon no longer selected
+ Logic::_scriptVars[SECOND_ITEM] = 0; // second icon no longer selected (after using one on another)
+ Logic::_scriptVars[MENU_LOOKING] = 0; // no longer 'looking at' an icon
+ buildMenu();
+ showMenu(MENU_TOP);
+}
+
+void Menu::fnEndMenu(void) {
+ if (_objectBarStatus != MENU_CLOSED)
+ _objectBarStatus = MENU_CLOSING;
+}
+
+void Menu::fnChooser(Object *compact) {
+ Logic::_scriptVars[OBJECT_HELD] = 0;
+ _mouse->setLuggage(0, 0);
+ buildSubjects();
+ compact->o_logic = LOGIC_choose;
+ _mouse->controlPanel(true); // so the mouse cursor will be shown.
+ _subjectBarStatus = MENU_OPENING;
+}
+
+void Menu::fnEndChooser(void) {
+ Logic::_scriptVars[OBJECT_HELD] = 0;
+ _subjectBarStatus = MENU_CLOSING;
+ _objectBarStatus = MENU_CLOSING;
+ _mouse->controlPanel(false);
+ _mouse->setLuggage(0, 0);
+}
+
+void Menu::checkTopMenu(void) {
+ if (_objectBarStatus == MENU_OPEN)
+ checkMenuClick(MENU_TOP);
+}
+
+int Menu::logicChooser(Object *compact) {
+ uint8 objSelected = 0;
+ if (_objectBarStatus == MENU_OPEN)
+ objSelected = checkMenuClick(MENU_TOP);
+ if (!objSelected)
+ objSelected = checkMenuClick(MENU_BOT);
+ if (objSelected) {
+ compact->o_logic = LOGIC_script;
+ return 1;
+ }
+ return 0;
+}
+
+void Menu::fnAddSubject(int32 sub) {
+ _subjectBar[Logic::_scriptVars[IN_SUBJECT]] = sub;
+ Logic::_scriptVars[IN_SUBJECT]++;
+}
+
+void Menu::cfnReleaseMenu(void) {
+ _objectBarStatus = MENU_CLOSING;
+}
+
+} // End of namespace Sword1
diff --git a/engines/sword1/menu.h b/engines/sword1/menu.h
new file mode 100644
index 0000000000..134ad9ab30
--- /dev/null
+++ b/engines/sword1/menu.h
@@ -0,0 +1,109 @@
+/* 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 BSMENU_H
+#define BSMENU_H
+
+#include "sword1/sworddefs.h"
+#include "sword1/object.h"
+
+namespace Sword1 {
+
+class Screen;
+class Mouse;
+class ResMan;
+
+#define MENU_TOP 0
+#define MENU_BOT 1
+
+struct Subject {
+ uint32 subjectRes;
+ uint32 frameNo;
+};
+
+struct MenuObject {
+ int32 textDesc;
+ uint32 bigIconRes;
+ uint32 bigIconFrame;
+ uint32 luggageIconRes;
+ uint32 useScript;
+};
+
+class MenuIcon {
+public:
+ MenuIcon(uint8 menuType, uint8 menuPos, uint32 resId, uint32 frame, Screen *screen);
+ bool wasClicked(uint16 mouseX, uint16 mouseY);
+ void setSelect(bool pSel);
+ void draw(const byte *fadeMask = NULL, int8 fadeStatus = 0);
+
+private:
+ uint8 _menuType, _menuPos;
+ uint32 _resId, _frame;
+ bool _selected;
+ Screen *_screen;
+};
+
+class Menu {
+public:
+ Menu(Screen *pScreen, Mouse *pMouse);
+ ~Menu(void);
+ void fnChooser(Object *compact);
+ void fnEndChooser(void);
+ void fnAddSubject(int32 sub);
+ void cfnReleaseMenu(void);
+ int logicChooser(Object *compact);
+ void engine(void);
+ void refresh(uint8 menuType);
+ void fnStartMenu(void);
+ void fnEndMenu(void);
+ void checkTopMenu(void);
+ static const MenuObject _objectDefs[TOTAL_pockets + 1];
+
+private:
+ void buildSubjects(void);
+ void buildMenu(void);
+ void showMenu(uint8 menuType);
+ byte _subjectBarStatus;
+ byte _objectBarStatus;
+ int8 _fadeSubject;
+ int8 _fadeObject;
+ void refreshMenus(void);
+ uint8 checkMenuClick(uint8 menuType);
+ //- lower menu, speech subjects:
+ MenuIcon *_subjects[16];
+ uint32 _subjectBar[16];
+ //- top menu, items
+ MenuIcon *_objects[TOTAL_pockets];
+ uint32 _menuList[TOTAL_pockets];
+ uint32 _inMenu;
+
+ Screen *_screen;
+ Mouse *_mouse;
+ static const Subject _subjectList[TOTAL_subjects];
+
+ static const byte _fadeEffectTop[64];
+ static const byte _fadeEffectBottom[64];
+};
+
+} // End of namespace Sword1
+
+#endif //BSMENU_H
diff --git a/engines/sword1/module.mk b/engines/sword1/module.mk
new file mode 100644
index 0000000000..9f4b3f2c3a
--- /dev/null
+++ b/engines/sword1/module.mk
@@ -0,0 +1,32 @@
+MODULE := engines/sword1
+
+MODULE_OBJS := \
+ engines/sword1/animation.o \
+ engines/sword1/control.o \
+ engines/sword1/credits.o \
+ engines/sword1/debug.o \
+ engines/sword1/eventman.o \
+ engines/sword1/logic.o \
+ engines/sword1/memman.o \
+ engines/sword1/menu.o \
+ engines/sword1/mouse.o \
+ engines/sword1/music.o \
+ engines/sword1/objectman.o \
+ engines/sword1/resman.o \
+ engines/sword1/router.o \
+ engines/sword1/screen.o \
+ engines/sword1/sound.o \
+ engines/sword1/staticres.o \
+ engines/sword1/sword1.o \
+ engines/sword1/text.o
+
+MODULE_DIRS += \
+ engines/sword1
+
+# 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/sword1/mouse.cpp b/engines/sword1/mouse.cpp
new file mode 100644
index 0000000000..a84708c6b9
--- /dev/null
+++ b/engines/sword1/mouse.cpp
@@ -0,0 +1,313 @@
+/* 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 "sword1/mouse.h"
+#include "sword1/menu.h"
+#include "sword1/screen.h"
+#include "sword1/logic.h"
+#include "sword1/resman.h"
+#include "sword1/objectman.h"
+#include "sword1/sworddefs.h"
+#include "common/system.h"
+#include "sword1/swordres.h"
+#include "sword1/menu.h"
+
+namespace Sword1 {
+
+Mouse::Mouse(OSystem *system, ResMan *pResMan, ObjectMan *pObjMan) {
+ _resMan = pResMan;
+ _objMan = pObjMan;
+ _system = system;
+ _currentPtr = NULL;
+}
+
+Mouse::~Mouse(void) {
+ setLuggage(0, 0);
+ setPointer(0, 0);
+
+ for (uint8 cnt = 0; cnt < 17; cnt++) // close mouse cursor resources
+ _resMan->resClose(MSE_POINTER + cnt);
+}
+
+void Mouse::initialize(void) {
+ _numObjs = 0;
+ Logic::_scriptVars[MOUSE_STATUS] = 0; // mouse off and unlocked
+ _getOff = 0;
+ _inTopMenu = false;
+ _lastState = 0;
+ _mouseOverride = false;
+ _currentPtrId = _currentLuggageId = 0;
+
+ for (uint8 cnt = 0; cnt < 17; cnt++) // force res manager to keep mouse
+ _resMan->resOpen(MSE_POINTER + cnt); // cursors in memory all the time
+
+ _system->showMouse(false);
+ createPointer(0, 0);
+}
+
+void Mouse::controlPanel(bool on) { // true on entering cpanel, false when leaving
+ static uint32 savedPtrId = 0;
+ if (on) {
+ savedPtrId = _currentPtrId;
+ _mouseOverride = true;
+ setLuggage(0, 0);
+ setPointer(MSE_POINTER, 0);
+ } else {
+ _currentPtrId = savedPtrId;
+ _mouseOverride = false;
+ setLuggage(_currentLuggageId, 0);
+ setPointer(_currentPtrId, 0);
+ }
+}
+
+void Mouse::useLogicAndMenu(Logic *pLogic, Menu *pMenu) {
+ _logic = pLogic;
+ _menu = pMenu;
+}
+
+void Mouse::addToList(int id, Object *compact) {
+ _objList[_numObjs].id = id;
+ _objList[_numObjs].compact = compact;
+ _numObjs++;
+}
+
+void Mouse::engine(uint16 x, uint16 y, uint16 eventFlags) {
+ _state = 0; // all mouse events are flushed after one cycle.
+ if (_lastState) { // delay all events by one cycle to notice L_button + R_button clicks correctly.
+ _state = _lastState | eventFlags;
+ _lastState = 0;
+ } else if (eventFlags)
+ _lastState = eventFlags;
+
+ // if we received both, mouse down and mouse up event in this cycle, resort them so that
+ // we'll receive the up event in the next one.
+ if ((_state & MOUSE_DOWN_MASK) && (_state & MOUSE_UP_MASK)) {
+ _lastState = _state & MOUSE_UP_MASK;
+ _state &= MOUSE_DOWN_MASK;
+ }
+
+ _mouseX = x;
+ _mouseY = y;
+ if (!(Logic::_scriptVars[MOUSE_STATUS] & 1)) { // no human?
+ _numObjs = 0;
+ return; // no human, so we don't want the mouse engine
+ }
+
+ if (!Logic::_scriptVars[TOP_MENU_DISABLED]) {
+ if (y < 40) { // okay, we are in the top menu.
+ if (!_inTopMenu) { // are we just entering it?
+ if (!Logic::_scriptVars[OBJECT_HELD])
+ _menu->fnStartMenu();
+ setPointer(MSE_POINTER, 0);
+ }
+ _menu->checkTopMenu();
+ _inTopMenu = true;
+ } else if (_inTopMenu) { // we're not in the menu. did we just leave it?
+ if (!Logic::_scriptVars[OBJECT_HELD])
+ _menu->fnEndMenu();
+ _inTopMenu = false;
+ }
+ } else if (_inTopMenu) {
+ _menu->fnEndMenu();
+ _inTopMenu = false;
+ }
+
+ Logic::_scriptVars[MOUSE_X] = Logic::_scriptVars[SCROLL_OFFSET_X] + x + 128;
+ Logic::_scriptVars[MOUSE_Y] = Logic::_scriptVars[SCROLL_OFFSET_Y] + y + 128 - 40;
+
+ //-
+ int32 touchedId = 0;
+ uint16 clicked = 0;
+ if (y > 40) {
+ for (uint16 priority = 0; (priority < 10) && (!touchedId); priority++) {
+ for (uint16 cnt = 0; (cnt < _numObjs) && (!touchedId); cnt++) {
+ if ((_objList[cnt].compact->o_priority == priority) &&
+ (Logic::_scriptVars[MOUSE_X] >= (uint32)_objList[cnt].compact->o_mouse_x1) &&
+ (Logic::_scriptVars[MOUSE_X] <= (uint32)_objList[cnt].compact->o_mouse_x2) &&
+ (Logic::_scriptVars[MOUSE_Y] >= (uint32)_objList[cnt].compact->o_mouse_y1) &&
+ (Logic::_scriptVars[MOUSE_Y] <= (uint32)_objList[cnt].compact->o_mouse_y2)) {
+ touchedId = _objList[cnt].id;
+ clicked = cnt;
+ }
+ }
+ }
+ if (touchedId != (int)Logic::_scriptVars[SPECIAL_ITEM]) { //the mouse collision situation has changed in one way or another
+ Logic::_scriptVars[SPECIAL_ITEM] = touchedId;
+ if (_getOff) { // there was something else selected before, run its get-off script
+ _logic->runMouseScript(NULL, _getOff);
+ _getOff = 0;
+ }
+ if (touchedId) { // there's something new selected, now.
+ if (_objList[clicked].compact->o_mouse_on) //run its get on
+ _logic->runMouseScript(_objList[clicked].compact, _objList[clicked].compact->o_mouse_on);
+
+ _getOff = _objList[clicked].compact->o_mouse_off; //setup get-off for later
+ }
+ }
+ } else
+ Logic::_scriptVars[SPECIAL_ITEM] = 0;
+ if (_state & MOUSE_DOWN_MASK) {
+ if (_inTopMenu) {
+ if (Logic::_scriptVars[SECOND_ITEM])
+ _logic->runMouseScript(NULL, _menu->_objectDefs[Logic::_scriptVars[SECOND_ITEM]].useScript);
+ if (Logic::_scriptVars[MENU_LOOKING])
+ _logic->cfnPresetScript(NULL, -1, PLAYER, SCR_menu_look, 0, 0, 0, 0);
+ }
+
+ Logic::_scriptVars[MOUSE_BUTTON] = _state & MOUSE_DOWN_MASK;
+ if (Logic::_scriptVars[SPECIAL_ITEM]) {
+ Object *compact = _objMan->fetchObject(Logic::_scriptVars[SPECIAL_ITEM]);
+ _logic->runMouseScript(compact, compact->o_mouse_click);
+ }
+ }
+ _numObjs = 0;
+}
+
+uint16 Mouse::testEvent(void) {
+ return _state;
+}
+
+void Mouse::createPointer(uint32 ptrId, uint32 luggageId) {
+ if (_currentPtr) {
+ free(_currentPtr);
+ _currentPtr = NULL;
+ }
+ if (ptrId) {
+ MousePtr *lugg = NULL;
+ MousePtr *ptr = (MousePtr*)_resMan->openFetchRes(ptrId);
+ uint16 resSizeX = FROM_LE_16(ptr->sizeX);
+ uint16 resSizeY = FROM_LE_16(ptr->sizeY);
+ uint16 noFrames = FROM_LE_16(ptr->numFrames);
+ if (luggageId) {
+ lugg = (MousePtr*)_resMan->openFetchRes(luggageId);
+ resSizeX = MAX(resSizeX, (uint16)((resSizeX / 2) + FROM_LE_16(lugg->sizeX)));
+ resSizeY = MAX(resSizeY, (uint16)((resSizeY / 2) + FROM_LE_16(lugg->sizeY)));
+ }
+ _currentPtr = (MousePtr*)malloc(sizeof(MousePtr) + resSizeX * resSizeY * noFrames);
+ _currentPtr->hotSpotX = FROM_LE_16(ptr->hotSpotX);
+ _currentPtr->hotSpotY = FROM_LE_16(ptr->hotSpotY);
+ _currentPtr->numFrames = noFrames;
+ _currentPtr->sizeX = resSizeX;
+ _currentPtr->sizeY = resSizeY;
+ uint8 *ptrData = (uint8*)_currentPtr + sizeof(MousePtr);
+ memset(ptrData, 255, resSizeX * resSizeY * noFrames);
+ if (luggageId) {
+ uint8 *dstData = ptrData + resSizeX - FROM_LE_16(lugg->sizeX);
+ for (uint32 frameCnt = 0; frameCnt < noFrames; frameCnt++) {
+ uint8 *luggSrc = (uint8*)lugg + sizeof(MousePtr);
+ dstData += (resSizeY - FROM_LE_16(lugg->sizeY)) * resSizeX;
+ for (uint32 cnty = 0; cnty < FROM_LE_16(lugg->sizeY); cnty++) {
+ for (uint32 cntx = 0; cntx < FROM_LE_16(lugg->sizeX); cntx++)
+ if (luggSrc[cntx])
+ dstData[cntx] = luggSrc[cntx];
+ dstData += resSizeX;
+ luggSrc += FROM_LE_16(lugg->sizeX);
+ }
+ }
+ _resMan->resClose(luggageId);
+ }
+ uint8 *dstData = ptrData;
+ uint8 *srcData = (uint8*)ptr + sizeof(MousePtr);
+ for (uint32 frameCnt = 0; frameCnt < noFrames; frameCnt++) {
+ for (uint32 cnty = 0; cnty < FROM_LE_16(ptr->sizeY); cnty++) {
+ for (uint32 cntx = 0; cntx < FROM_LE_16(ptr->sizeX); cntx++)
+ if (srcData[cntx])
+ dstData[cntx] = srcData[cntx];
+ srcData += FROM_LE_16(ptr->sizeX);
+ dstData += resSizeX;
+ }
+ dstData += (resSizeY - FROM_LE_16(ptr->sizeY)) * resSizeX;
+ }
+ _resMan->resClose(ptrId);
+ }
+}
+
+void Mouse::setPointer(uint32 resId, uint32 rate) {
+ _currentPtrId = resId;
+ _frame = 0;
+
+ createPointer(resId, _currentLuggageId);
+
+ if ((resId == 0) || (!(Logic::_scriptVars[MOUSE_STATUS] & 1) && (!_mouseOverride))) {
+ _system->setMouseCursor(NULL, 0, 0, 0, 0);
+ _system->showMouse(false);
+ } else {
+ animate();
+ _system->showMouse(true);
+ }
+}
+
+void Mouse::setLuggage(uint32 resId, uint32 rate) {
+ _currentLuggageId = resId;
+ _frame = 0;
+ createPointer(_currentPtrId, resId);
+}
+
+void Mouse::animate(void) {
+ if ((Logic::_scriptVars[MOUSE_STATUS] == 1) || (_mouseOverride && _currentPtr)) {
+ _frame = (_frame + 1) % _currentPtr->numFrames;
+ uint8 *ptrData = (uint8*)_currentPtr + sizeof(MousePtr);
+ ptrData += _frame * _currentPtr->sizeX * _currentPtr->sizeY;
+ _system->setMouseCursor(ptrData, _currentPtr->sizeX, _currentPtr->sizeY, _currentPtr->hotSpotX, _currentPtr->hotSpotY);
+ }
+}
+
+void Mouse::fnNoHuman(void) {
+ if (Logic::_scriptVars[MOUSE_STATUS] & 2) // locked, can't do anything
+ return ;
+ Logic::_scriptVars[MOUSE_STATUS] = 0; // off & unlocked
+ setLuggage(0, 0);
+ setPointer(0, 0);
+}
+
+void Mouse::fnAddHuman(void) {
+ if (Logic::_scriptVars[MOUSE_STATUS] & 2) // locked, can't do anything
+ return ;
+ Logic::_scriptVars[MOUSE_STATUS] = 1;
+ Logic::_scriptVars[SPECIAL_ITEM] = 0;
+ _getOff = SCR_std_off;
+ setPointer(MSE_POINTER, 0);
+}
+
+void Mouse::fnBlankMouse(void) {
+ setPointer(0, 0);
+}
+
+void Mouse::fnNormalMouse(void) {
+ setPointer(MSE_POINTER, 0);
+}
+
+void Mouse::fnLockMouse(void) {
+ Logic::_scriptVars[MOUSE_STATUS] |= 2;
+}
+
+void Mouse::fnUnlockMouse(void) {
+ Logic::_scriptVars[MOUSE_STATUS] &= 1;
+}
+
+void Mouse::giveCoords(uint16 *x, uint16 *y) {
+ *x = _mouseX;
+ *y = _mouseY;
+}
+
+} // End of namespace Sword1
diff --git a/engines/sword1/mouse.h b/engines/sword1/mouse.h
new file mode 100644
index 0000000000..8512d85791
--- /dev/null
+++ b/engines/sword1/mouse.h
@@ -0,0 +1,113 @@
+/* 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 BSMOUSE_H
+#define BSMOUSE_H
+
+#include "common/scummsys.h"
+#include "sword1/sworddefs.h"
+#include "sword1/object.h"
+
+class OSystem;
+
+namespace Sword1 {
+
+#define MAX_MOUSE 30
+
+#define BS1L_BUTTON_DOWN 2
+#define BS1L_BUTTON_UP 4
+#define BS1R_BUTTON_DOWN 8
+#define BS1R_BUTTON_UP 16
+#define BS1_WHEEL_UP 32
+#define BS1_WHEEL_DOWN 64
+#define MOUSE_BOTH_BUTTONS (BS1L_BUTTON_DOWN | BS1R_BUTTON_DOWN)
+#define MOUSE_DOWN_MASK (BS1L_BUTTON_DOWN | BS1R_BUTTON_DOWN)
+#define MOUSE_UP_MASK (BS1L_BUTTON_UP | BS1R_BUTTON_UP)
+
+struct MouseObj {
+ int id;
+ Object *compact;
+};
+
+#if !defined(__GNUC__)
+ #pragma START_PACK_STRUCTS
+#endif
+
+struct MousePtr {
+ uint16 numFrames;
+ uint16 sizeX;
+ uint16 sizeY;
+ uint16 hotSpotX;
+ uint16 hotSpotY;
+ uint8 dummyData[0x30];
+} GCC_PACK;
+
+#if !defined(__GNUC__)
+ #pragma END_PACK_STRUCTS
+#endif
+
+class Logic;
+class Menu;
+class ResMan;
+class ObjectMan;
+
+class Mouse {
+public:
+ Mouse(OSystem *system, ResMan *pResMan, ObjectMan *pObjMan);
+ ~Mouse(void);
+ void initialize(void);
+ void addToList(int id, Object *compact);
+ void useLogicAndMenu(Logic *pLogic, Menu *pMenu);
+ void setLuggage(uint32 resID, uint32 rate);
+ void setPointer(uint32 resID, uint32 rate);
+ void animate(void);
+ void engine(uint16 x, uint16 y, uint16 eventFlags);
+ uint16 testEvent(void);
+ void giveCoords(uint16 *x, uint16 *y);
+ void fnNoHuman(void);
+ void fnAddHuman(void);
+ void fnBlankMouse(void);
+ void fnNormalMouse(void);
+ void fnLockMouse(void);
+ void fnUnlockMouse(void);
+ void controlPanel(bool on);
+private:
+ void createPointer(uint32 ptrId, uint32 luggageId);
+ OSystem *_system;
+ Logic *_logic;
+ Menu *_menu;
+ MouseObj _objList[MAX_MOUSE];
+ ResMan *_resMan;
+ ObjectMan *_objMan;
+ uint16 _mouseX, _mouseY;
+
+ uint32 _currentPtrId, _currentLuggageId, _frame;
+ MousePtr *_currentPtr;
+ uint16 _numObjs;
+ uint16 _lastState, _state;
+ uint32 _getOff;
+ bool _inTopMenu, _mouseOverride;
+};
+
+} // End of namespace Sword1
+
+#endif //BSMOUSE_H
diff --git a/engines/sword1/music.cpp b/engines/sword1/music.cpp
new file mode 100644
index 0000000000..a5ed77d30d
--- /dev/null
+++ b/engines/sword1/music.cpp
@@ -0,0 +1,352 @@
+/* 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 "sword1/music.h"
+
+#include "common/util.h"
+#include "common/file.h"
+#include "common/system.h"
+
+#include "sound/mixer.h"
+#include "sound/mp3.h"
+#include "sound/vorbis.h"
+#include "sound/wave.h"
+
+#define SMP_BUFSIZE 8192
+
+namespace Sword1 {
+
+WaveAudioStream *makeWaveStream(Common::File *source, uint32 size) {
+ return new WaveAudioStream(source, size);
+}
+
+WaveAudioStream::WaveAudioStream(Common::File *source, uint32 pSize) {
+ int rate, size;
+ byte flags;
+
+ _sourceFile = source;
+ _sampleBuf = (uint8*)malloc(SMP_BUFSIZE);
+ _sourceFile->incRef();
+ if (_sourceFile->isOpen() && loadWAVFromStream(*_sourceFile, size, rate, flags)) {
+ _isStereo = (flags & Audio::Mixer::FLAG_STEREO) != 0;
+ _rate = rate;
+ if (pSize && (int)pSize < size)
+ size = pSize;
+ assert((uint32)size <= (source->size() - source->pos()));
+ _bitsPerSample = ((flags & Audio::Mixer::FLAG_16BITS) != 0) ? 16 : 8;
+ _samplesLeft = (size * 8) / _bitsPerSample;
+ if ((_bitsPerSample != 16) && (_bitsPerSample != 8))
+ error("WaveAudioStream: unknown wave type");
+ } else {
+ _samplesLeft = 0;
+ _isStereo = false;
+ _bitsPerSample = 16;
+ _rate = 22050;
+ }
+}
+
+WaveAudioStream::~WaveAudioStream(void) {
+ free(_sampleBuf);
+ _sourceFile->decRef();
+}
+
+int WaveAudioStream::readBuffer(int16 *buffer, const int numSamples) {
+ int samples = MIN((int)_samplesLeft, numSamples);
+ int retVal = samples;
+
+ while (samples > 0) {
+ int readBytes = MIN(samples * (_bitsPerSample >> 3), SMP_BUFSIZE);
+ _sourceFile->read(_sampleBuf, readBytes);
+ if (_bitsPerSample == 16) {
+ readBytes >>= 1;
+ samples -= readBytes;
+ int16 *src = (int16*)_sampleBuf;
+ while (readBytes--)
+ *buffer++ = (int16)READ_LE_UINT16(src++);
+ } else {
+ samples -= readBytes;
+ int8 *src = (int8*)_sampleBuf;
+ while (readBytes--)
+ *buffer++ = (int16)*src++ << 8;
+ }
+ }
+ _samplesLeft -= retVal;
+ return retVal;
+}
+
+bool WaveAudioStream::endOfData(void) const {
+ if (_samplesLeft == 0)
+ return true;
+ else
+ return false;
+}
+
+// This means fading takes 3 seconds.
+#define FADE_LENGTH 3
+
+// These functions are only called from Music, so I'm just going to
+// assume that if locking is needed it has already been taken care of.
+
+AudioStream *MusicHandle::createAudioSource(void) {
+ _file.seek(0);
+ switch (_musicMode) {
+#ifdef USE_MAD
+ case MusicMp3:
+ return makeMP3Stream(&_file, _file.size());
+#endif
+#ifdef USE_VORBIS
+ case MusicVorbis:
+ return makeVorbisStream(&_file, _file.size());
+#endif
+ case MusicWave:
+ return makeWaveStream(&_file, 0);
+ case MusicNone: // shouldn't happen
+ warning("createAudioSource ran into null create\n");
+ return NULL;
+ default:
+ error("MusicHandle::createAudioSource: called with illegal MusicMode");
+ }
+ return NULL; // never reached
+}
+
+bool MusicHandle::play(const char *fileBase, bool loop) {
+ char fileName[30];
+ stop();
+ _musicMode = MusicNone;
+#ifdef USE_MAD
+ sprintf(fileName, "%s.mp3", fileBase);
+ if (_file.open(fileName))
+ _musicMode = MusicMp3;
+#endif
+#ifdef USE_VORBIS
+ if (!_file.isOpen()) { // mp3 doesn't exist (or not compiled with MAD support)
+ sprintf(fileName, "%s.ogg", fileBase);
+ if (_file.open(fileName))
+ _musicMode = MusicVorbis;
+ }
+#endif
+ if (!_file.isOpen()) {
+ sprintf(fileName, "%s.wav", fileBase);
+ if (_file.open(fileName))
+ _musicMode = MusicWave;
+ else
+ return false;
+ }
+ _audioSource = createAudioSource();
+ _looping = loop;
+ fadeUp();
+ return true;
+}
+
+void MusicHandle::fadeDown() {
+ if (streaming()) {
+ if (_fading < 0)
+ _fading = -_fading;
+ else if (_fading == 0)
+ _fading = FADE_LENGTH * getRate();
+ _fadeSamples = FADE_LENGTH * getRate();
+ }
+}
+
+void MusicHandle::fadeUp() {
+ if (streaming()) {
+ if (_fading > 0)
+ _fading = -_fading;
+ else if (_fading == 0)
+ _fading = -1;
+ _fadeSamples = FADE_LENGTH * getRate();
+ }
+}
+
+bool MusicHandle::endOfData() const {
+ return !streaming();
+}
+
+// is we don't have an audiosource, return some dummy values.
+// shouldn't happen anyways.
+bool MusicHandle::streaming(void) const {
+ return (_audioSource) ? (!_audioSource->endOfStream()) : false;
+}
+
+bool MusicHandle::isStereo(void) const {
+ return (_audioSource) ? _audioSource->isStereo() : false;
+}
+
+int MusicHandle::getRate(void) const {
+ return (_audioSource) ? _audioSource->getRate() : 11025;
+}
+
+int MusicHandle::readBuffer(int16 *buffer, const int numSamples) {
+ int totalSamples = 0;
+ int16 *bufStart = buffer;
+ if (!_audioSource)
+ return 0;
+ int expectedSamples = numSamples;
+ while ((expectedSamples > 0) && _audioSource) { // _audioSource becomes NULL if we reach EOF and aren't looping
+ int samplesReturned = _audioSource->readBuffer(buffer, expectedSamples);
+ buffer += samplesReturned;
+ totalSamples += samplesReturned;
+ expectedSamples -= samplesReturned;
+ if ((expectedSamples > 0) && _audioSource->endOfData()) {
+ debug(2, "Music reached EOF");
+ _audioSource->endOfData();
+ if (_looping) {
+ delete _audioSource; // recreate same source.
+ _audioSource = createAudioSource();
+ }
+ if ((!_looping) || (!_audioSource))
+ stop();
+ }
+ }
+ // buffer was filled, now do the fading (if necessary)
+ int samplePos = 0;
+ while ((_fading > 0) && (samplePos < totalSamples)) { // fade down
+ bufStart[samplePos] = (bufStart[samplePos] * --_fading) / _fadeSamples;
+ samplePos++;
+ if (_fading == 0) {
+ stop();
+ // clear the rest of the buffer
+ memset(bufStart + samplePos, 0, (totalSamples - samplePos) * 2);
+ return samplePos;
+ }
+ }
+ while ((_fading < 0) && (samplePos < totalSamples)) { // fade up
+ bufStart[samplePos] = -(bufStart[samplePos] * --_fading) / _fadeSamples;
+ if (_fading <= -_fadeSamples)
+ _fading = 0;
+ }
+ return totalSamples;
+}
+
+void MusicHandle::stop() {
+ if (_audioSource) {
+ delete _audioSource;
+ _audioSource = NULL;
+ }
+ if (_file.isOpen())
+ _file.close();
+ _fading = 0;
+ _looping = false;
+}
+
+Music::Music(Audio::Mixer *pMixer) {
+ _mixer = pMixer;
+ _sampleRate = pMixer->getOutputRate();
+ _converter[0] = NULL;
+ _converter[1] = NULL;
+ _volumeL = _volumeR = 192;
+ _mixer->setupPremix(this);
+}
+
+Music::~Music() {
+ _mixer->setupPremix(0);
+ delete _converter[0];
+ delete _converter[1];
+}
+
+void Music::mixer(int16 *buf, uint32 len) {
+ Common::StackLock lock(_mutex);
+ memset(buf, 0, 2 * len * sizeof(int16));
+ for (int i = 0; i < ARRAYSIZE(_handles); i++)
+ if (_handles[i].streaming() && _converter[i])
+ _converter[i]->flow(_handles[i], buf, len, _volumeL, _volumeR);
+}
+
+void Music::setVolume(uint8 volL, uint8 volR) {
+ _volumeL = (Audio::st_volume_t)volL;
+ _volumeR = (Audio::st_volume_t)volR;
+}
+
+void Music::giveVolume(uint8 *volL, uint8 *volR) {
+ *volL = (uint8)_volumeL;
+ *volR = (uint8)_volumeR;
+}
+
+void Music::startMusic(int32 tuneId, int32 loopFlag) {
+ if (strlen(_tuneList[tuneId]) > 0) {
+ int newStream = 0;
+ _mutex.lock();
+ if (_handles[0].streaming() && _handles[1].streaming()) {
+ int streamToStop;
+ // Both streams playing - one must be forced to stop.
+ if (!_handles[0].fading() && !_handles[1].fading()) {
+ // None of them are fading. Shouldn't happen,
+ // so it doesn't matter which one we pick.
+ streamToStop = 0;
+ } else if (_handles[0].fading() && !_handles[1].fading()) {
+ // Stream 0 is fading, so pick that one.
+ streamToStop = 0;
+ } else if (!_handles[0].fading() && _handles[1].fading()) {
+ // Stream 1 is fading, so pick that one.
+ streamToStop = 1;
+ } else {
+ // Both streams are fading. Pick the one that
+ // is closest to silent.
+ if (ABS(_handles[0].fading()) < ABS(_handles[1].fading()))
+ streamToStop = 0;
+ else
+ streamToStop = 1;
+ }
+ _handles[streamToStop].stop();
+ }
+ if (_handles[0].streaming()) {
+ _handles[0].fadeDown();
+ newStream = 1;
+ } else if (_handles[1].streaming()) {
+ _handles[1].fadeDown();
+ newStream = 0;
+ }
+ delete _converter[newStream];
+ _converter[newStream] = NULL;
+ _mutex.unlock();
+
+ /* The handle will load the music file now. It can take a while, so unlock
+ the mutex before, to have the soundthread playing normally.
+ As the corresponding _converter is NULL, the handle will be ignored by the playing thread */
+ if (_handles[newStream].play(_tuneList[tuneId], loopFlag != 0)) {
+ _mutex.lock();
+ _converter[newStream] = Audio::makeRateConverter(_handles[newStream].getRate(), _mixer->getOutputRate(), _handles[newStream].isStereo(), false);
+ _mutex.unlock();
+ } else {
+ if (tuneId != 81) // file 81 was apparently removed from BS.
+ warning("Can't find music file %s", _tuneList[tuneId]);
+ }
+ } else {
+ _mutex.lock();
+ if (_handles[0].streaming())
+ _handles[0].fadeDown();
+ if (_handles[1].streaming())
+ _handles[1].fadeDown();
+ _mutex.unlock();
+ }
+}
+
+void Music::fadeDown() {
+ Common::StackLock lock(_mutex);
+ for (int i = 0; i < ARRAYSIZE(_handles); i++)
+ if (_handles[i].streaming())
+ _handles[i].fadeDown();
+}
+
+} // End of namespace Sword1
diff --git a/engines/sword1/music.h b/engines/sword1/music.h
new file mode 100644
index 0000000000..4f355d3931
--- /dev/null
+++ b/engines/sword1/music.h
@@ -0,0 +1,122 @@
+/* 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 BSMUSIC_H
+#define BSMUSIC_H
+
+#include "common/scummsys.h"
+#include "common/mutex.h"
+#include "common/file.h"
+#include "sound/audiostream.h"
+#include "sound/rate.h"
+
+namespace Audio {
+ class Mixer;
+}
+
+namespace Sword1 {
+
+#define TOTAL_TUNES 270
+
+enum MusicMode {
+ MusicNone = 0,
+ MusicWave,
+ MusicMp3,
+ MusicVorbis
+};
+
+class WaveAudioStream : public AudioStream {
+public:
+ WaveAudioStream(Common::File *source, uint32 pSize);
+ virtual ~WaveAudioStream();
+ virtual int readBuffer(int16 *buffer, const int numSamples);
+ virtual bool isStereo(void) const { return _isStereo; };
+ virtual bool endOfData(void) const;
+ virtual int getRate(void) const { return _rate; };
+private:
+ Common::File *_sourceFile;
+ uint8 *_sampleBuf;
+ uint32 _rate;
+ bool _isStereo;
+ uint32 _samplesLeft;
+ uint16 _bitsPerSample;
+};
+
+class MusicHandle : public AudioStream {
+private:
+ Common::File _file;
+ bool _looping;
+ int32 _fading;
+ int32 _fadeSamples;
+ MusicMode _musicMode;
+ AudioStream *_audioSource;
+ AudioStream *createAudioSource(void);
+public:
+ MusicHandle() : _looping(false), _fading(0), _audioSource(NULL) {}
+ virtual int readBuffer(int16 *buffer, const int numSamples);
+ bool play(const char *filename, bool loop);
+ void stop();
+ void fadeUp();
+ void fadeDown();
+ bool streaming() const;
+ int32 fading() { return _fading; }
+ bool endOfData() const;
+ bool endOfStream() const { return false; }
+ bool isStereo() const;
+ int getRate() const;
+};
+
+class Music : public AudioStream {
+public:
+ Music(Audio::Mixer *pMixer);
+ ~Music();
+ void startMusic(int32 tuneId, int32 loopFlag);
+ void fadeDown();
+ void setVolume(uint8 volL, uint8 volR);
+ void giveVolume(uint8 *volL, uint8 *volR);
+
+ // AudioStream API
+ int readBuffer(int16 *buffer, const int numSamples) {
+ mixer(buffer, numSamples / 2);
+ return numSamples;
+ }
+ bool isStereo() const { return true; }
+ bool endOfData() const { return false; }
+ int getRate() const { return _sampleRate; }
+
+private:
+ Audio::st_volume_t _volumeL, _volumeR;
+ MusicHandle _handles[2];
+ Audio::RateConverter *_converter[2];
+ Audio::Mixer *_mixer;
+ uint32 _sampleRate;
+ Common::Mutex _mutex;
+
+ static void passMixerFunc(void *param, int16 *buf, uint len);
+ void mixer(int16 *buf, uint32 len);
+
+ static const char _tuneList[TOTAL_TUNES][8]; // in staticres.cpp
+};
+
+} // End of namespace Sword1
+
+#endif // BSMUSIC_H
diff --git a/engines/sword1/object.h b/engines/sword1/object.h
new file mode 100644
index 0000000000..3d2cde4a6d
--- /dev/null
+++ b/engines/sword1/object.h
@@ -0,0 +1,130 @@
+/* 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 BSOBJECT_H
+#define BSOBJECT_H
+
+#include "common/scummsys.h"
+
+namespace Sword1 {
+
+#define O_TOTAL_EVENTS 5
+#define O_WALKANIM_SIZE 600 //max number of nodes in router output
+#define O_GRID_SIZE 200
+#define EXTRA_GRID_SIZE 20
+
+#if !defined(__GNUC__)
+ #pragma START_PACK_STRUCTS
+#endif
+
+struct OEventSlot { //receiving event list in the compact -
+ int32 o_event; //array of these with O_TOTAL_EVENTS elements
+ int32 o_event_script;
+} GCC_PACK; // size = 2*int32 = 8 bytes
+
+#define TOTAL_script_levels 5
+
+struct ScriptTree { //this is a logic tree, used by OBJECTs
+ int32 o_script_level; //logic level
+ int32 o_script_id[TOTAL_script_levels]; //script id's (are unique to each level)
+ int32 o_script_pc[TOTAL_script_levels]; //pc of script for each (if script_manager)
+} GCC_PACK; // size = 11*int32 = 44 bytes
+
+struct TalkOffset {
+ int32 x;
+ int32 y;
+} GCC_PACK; // size = 2*int32 = 8 bytes
+
+struct WalkData {
+ int32 frame;
+ int32 x;
+ int32 y;
+ int32 step;
+ int32 dir;
+} GCC_PACK; // size = 5*int32 = 20 bytes
+
+struct Object {
+ int32 o_type; // 0 broad description of type - object, floor, etc.
+ int32 o_status; // 4 bit flags for logic, graphics, mouse, etc.
+ int32 o_logic; // 8 logic type
+ int32 o_place; // 12 where is the mega character
+ int32 o_down_flag; // 16 pass back down with this - with C possibly both are unnecessary?
+ int32 o_target; // 20 target object for the GTM *these are linked to script
+ int32 o_screen; // 24 physical screen/section
+ int32 o_frame; // 28 frame number &
+ int32 o_resource; // 32 id of spr file it comes from
+ int32 o_sync; // 36 receive sync here
+ int32 o_pause; // 40 logic_engine() pauses these cycles
+ int32 o_xcoord; // 44
+ int32 o_ycoord; // 48
+ int32 o_mouse_x1; // 52 top-left of mouse area is (x1,y1)
+ int32 o_mouse_y1; // 56
+ int32 o_mouse_x2; // 60 bottom-right of area is (x2,y2) (these coords are inclusive)
+ int32 o_mouse_y2; // 64
+ int32 o_priority; // 68
+ int32 o_mouse_on; // 72
+ int32 o_mouse_off; // 76
+ int32 o_mouse_click; // 80
+ int32 o_interact; // 84
+ int32 o_get_to_script; // 88
+ int32 o_scale_a; // 92 used by floors
+ int32 o_scale_b; // 96
+ int32 o_anim_x; // 100
+ int32 o_anim_y; // 104
+
+ ScriptTree o_tree; // 108 size = 44 bytes
+ ScriptTree o_bookmark; // 152 size = 44 bytes
+
+ int32 o_dir; // 196
+ int32 o_speech_pen; // 200
+ int32 o_speech_width; // 204
+ int32 o_speech_time; // 208
+ int32 o_text_id; // 212 working back from o_ins1
+ int32 o_tag; // 216
+ int32 o_anim_pc; // 220 position within an animation structure
+ int32 o_anim_resource; // 224 cdt or anim table
+
+ int32 o_walk_pc; // 228
+
+ TalkOffset talk_table[6]; // 232 size = 6*8 bytes = 48
+
+ OEventSlot o_event_list[O_TOTAL_EVENTS]; // 280 size = 5*8 bytes = 40
+
+ int32 o_ins1; // 320
+ int32 o_ins2; // 324
+ int32 o_ins3; // 328
+
+ int32 o_mega_resource; // 332
+ int32 o_walk_resource; // 336
+
+ WalkData o_route[O_WALKANIM_SIZE]; // 340 size = 600*20 bytes = 12000
+ // mega size = 12340 bytes (+ 8 byte offset table + 20 byte header = 12368)
+} GCC_PACK;
+
+#if !defined(__GNUC__)
+ #pragma END_PACK_STRUCTS
+#endif
+
+} // End of namespace Sword1
+
+#endif //BSOBJECT_H
+
diff --git a/engines/sword1/objectman.cpp b/engines/sword1/objectman.cpp
new file mode 100644
index 0000000000..330e5566ee
--- /dev/null
+++ b/engines/sword1/objectman.cpp
@@ -0,0 +1,163 @@
+/* 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 "sword1/objectman.h"
+#include "common/scummsys.h"
+#include "common/util.h"
+#include "sword1/sworddefs.h"
+#include "sword1/swordres.h"
+#include "sword1/sword1.h"
+
+namespace Sword1 {
+
+ObjectMan::ObjectMan(ResMan *pResourceMan) {
+ _resMan = pResourceMan;
+}
+
+void ObjectMan::initialize(void) {
+ uint16 cnt;
+ for (cnt = 0; cnt < TOTAL_SECTIONS; cnt++)
+ _liveList[cnt] = 0; // we don't need to close the files here. When this routine is
+ // called, the memory was flushed() anyways, so these resources
+ // already *are* closed.
+
+ _liveList[128] = _liveList[129] = _liveList[130] = _liveList[131] = _liveList[133] =
+ _liveList[134] = _liveList[145] = _liveList[146] = _liveList[TEXT_sect] = 1;
+
+ for (cnt = 0; cnt < TOTAL_SECTIONS; cnt++) {
+ if (_liveList[cnt])
+ _cptData[cnt] = (uint8*)_resMan->cptResOpen(_objectList[cnt]) + sizeof(Header);
+ else
+ _cptData[cnt] = NULL;
+ }
+}
+
+ObjectMan::~ObjectMan(void) {
+ for (uint16 cnt = 0; cnt < TOTAL_SECTIONS; cnt++)
+ if (_liveList[cnt])
+ _resMan->resClose(_objectList[cnt]);
+}
+
+bool ObjectMan::sectionAlive(uint16 section) {
+ return (_liveList[section] > 0);
+}
+
+void ObjectMan::megaEntering(uint16 section) {
+ _liveList[section]++;
+ if (_liveList[section] == 1)
+ _cptData[section] = ((uint8*)_resMan->cptResOpen(_objectList[section])) + sizeof(Header);
+}
+
+void ObjectMan::megaLeaving(uint16 section, int id) {
+ if (_liveList[section] == 0)
+ error("mega %d is leaving empty section %d", id, section);
+ _liveList[section]--;
+ if ((_liveList[section] == 0) && (id != PLAYER)) {
+ _resMan->resClose(_objectList[section]);
+ _cptData[section] = NULL;
+ }
+ /* if the player is leaving the section then we have to close the resources after
+ mainloop ends, because the screen will still need the resources*/
+}
+
+uint8 ObjectMan::fnCheckForTextLine(uint32 textId) {
+ uint8 retVal = 0;
+ if (!_textList[textId / ITM_PER_SEC][0])
+ return 0; // section does not exist
+
+ uint8 lang = SwordEngine::_systemVars.language;
+ uint32 *textData = (uint32*)((uint8*)_resMan->openFetchRes(_textList[textId / ITM_PER_SEC][lang]) + sizeof(Header));
+ if ((textId & ITM_ID) < READ_LE_UINT32(textData)) {
+ textData++;
+ if (textData[textId & ITM_ID])
+ retVal = 1;
+ }
+ _resMan->resClose(_textList[textId / ITM_PER_SEC][lang]);
+ return retVal;
+}
+
+char *ObjectMan::lockText(uint32 textId) {
+ uint8 lang = SwordEngine::_systemVars.language;
+ char *addr = (char*)_resMan->openFetchRes(_textList[textId / ITM_PER_SEC][lang]) + sizeof(Header);
+ if ((textId & ITM_ID) >= READ_LE_UINT32(addr)) {
+ warning("ObjectMan::lockText(%d): only %d texts in file", textId & ITM_ID, READ_LE_UINT32(addr));
+ textId = 0; // get first line instead
+ }
+ uint32 offset = READ_LE_UINT32(addr + ((textId & ITM_ID) + 1)* 4);
+ if (offset == 0) {
+ warning("ObjectMan::lockText(%d): text number has no text lines", textId);
+ return _errorStr;
+ }
+ return addr + offset;
+}
+
+void ObjectMan::unlockText(uint32 textId) {
+ _resMan->resClose(_textList[textId / ITM_PER_SEC][SwordEngine::_systemVars.language]);
+}
+
+uint32 ObjectMan::lastTextNumber(int section) {
+ uint8 *data = (uint8*)_resMan->openFetchRes(_textList[section][SwordEngine::_systemVars.language]) + sizeof(Header);
+ uint32 result = READ_LE_UINT32(data) - 1;
+ _resMan->resClose(_textList[section][SwordEngine::_systemVars.language]);
+ return result;
+}
+
+Object *ObjectMan::fetchObject(uint32 id) {
+ uint8 *addr = _cptData[id / ITM_PER_SEC];
+ if (!addr)
+ error("fetchObject: section %d is not open!", id / ITM_PER_SEC);
+ id &= ITM_ID;
+ // DON'T do endian conversion here. it's already done.
+ return (Object*)(addr + *(uint32*)(addr + (id + 1)*4));
+}
+
+uint32 ObjectMan::fetchNoObjects(int section) {
+ if (_cptData[section] == NULL)
+ error("fetchNoObjects: section %d is not open!", section);
+ return *(uint32*)_cptData[section];
+}
+
+void ObjectMan::closeSection(uint32 screen) {
+ if (_liveList[screen] == 0) // close the section that PLAYER has just left, if it's empty now
+ _resMan->resClose(_objectList[screen]);
+}
+
+void ObjectMan::loadLiveList(uint16 *src) {
+ for (uint16 cnt = 0; cnt < TOTAL_SECTIONS; cnt++) {
+ if (_liveList[cnt]) {
+ _resMan->resClose(_objectList[cnt]);
+ _cptData[cnt] = NULL;
+ }
+ _liveList[cnt] = src[cnt];
+ if (_liveList[cnt])
+ _cptData[cnt] = ((uint8*)_resMan->cptResOpen(_objectList[cnt])) + sizeof(Header);
+ }
+}
+
+void ObjectMan::saveLiveList(uint16 *dest) {
+ memcpy(dest, _liveList, TOTAL_SECTIONS * sizeof(uint16));
+}
+
+char ObjectMan::_errorStr[] = "Error: Text not found.";
+
+} // End of namespace Sword1
diff --git a/engines/sword1/objectman.h b/engines/sword1/objectman.h
new file mode 100644
index 0000000000..398d7d85a4
--- /dev/null
+++ b/engines/sword1/objectman.h
@@ -0,0 +1,66 @@
+/* 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$
+ *
+ */
+
+// this is the object manager. our equivalent to protocol.c and coredata.c
+
+#ifndef OBJECTMAN_H
+#define OBJECTMAN_H
+
+#include "sword1/resman.h"
+#include "sword1/sworddefs.h"
+#include "sword1/object.h"
+
+namespace Sword1 {
+
+class ObjectMan {
+public:
+ ObjectMan(ResMan *pResourceMan);
+ ~ObjectMan(void);
+ void initialize(void);
+
+ Object *fetchObject(uint32 id);
+ uint32 fetchNoObjects(int section);
+ bool sectionAlive(uint16 section);
+ void megaEntering(uint16 section);
+ void megaLeaving(uint16 section, int id);
+
+ uint8 fnCheckForTextLine(uint32 textId);
+ char *lockText(uint32 textId);
+ void unlockText(uint32 textId);
+ uint32 lastTextNumber(int section);
+
+ void closeSection(uint32 screen);
+
+ void saveLiveList(uint16 *dest); // for loading/saving
+ void loadLiveList(uint16 *src);
+private:
+ ResMan *_resMan;
+ static const uint32 _objectList[TOTAL_SECTIONS]; //a table of pointers to object files
+ static const uint32 _textList[TOTAL_SECTIONS][7]; //a table of pointers to text files
+ uint16 _liveList[TOTAL_SECTIONS]; //which sections are active
+ uint8 *_cptData[TOTAL_SECTIONS];
+ static char _errorStr[];
+};
+
+} // End of namespace Sword1
+
+#endif //OBJECTMAN_H
diff --git a/engines/sword1/resman.cpp b/engines/sword1/resman.cpp
new file mode 100644
index 0000000000..fd86993dfa
--- /dev/null
+++ b/engines/sword1/resman.cpp
@@ -0,0 +1,421 @@
+/* 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 "sword1/memman.h"
+#include "sword1/resman.h"
+#include "sword1/sworddefs.h"
+#include "base/engine.h"
+#include "common/config-manager.h"
+#include "common/util.h"
+#include "common/str.h"
+#include "sword1/swordres.h"
+
+#include "gui/message.h"
+#include "gui/newgui.h"
+
+namespace Sword1 {
+ void guiFatalError(char *msg) {
+ // Displays a dialog on-screen before terminating the engine.
+ // TODO: We really need to setup a special palette for cases when
+ // the engine is erroring before setting one... otherwise invisible cursor :)
+
+ GUI::MessageDialog dialog(msg);
+ dialog.runModal();
+ error(msg);
+}
+
+#define MAX_PATH_LEN 260
+
+ResMan::ResMan(const char *fileName) {
+ _openCluStart = _openCluEnd = NULL;
+ _openClus = 0;
+ _memMan = new MemMan();
+ loadCluDescript(fileName);
+}
+
+ResMan::~ResMan(void) {
+#if 0
+ for (uint32 clusCnt = 0; clusCnt < _prj.noClu; clusCnt++) {
+ Clu *cluster = _prj.clu[clusCnt];
+ if (cluster) {
+ for (uint32 grpCnt = 0; grpCnt < cluster->noGrp; grpCnt++) {
+ Grp *group = cluster->grp[grpCnt];
+ if (group) {
+ for (uint32 resCnt = 0; resCnt < group->noRes; resCnt++) {
+ if (group->resHandle[resCnt].cond == MEM_DONT_FREE) {
+ warning("ResMan::~ResMan: Resource %02X.%04X.%02X is still open",
+ clusCnt + 1, grpCnt, resCnt);
+ }
+ }
+ }
+ }
+ }
+ }
+ debug(0, "ResMan closed\n");
+#endif
+ flush();
+ freeCluDescript();
+ delete _memMan;
+}
+
+void ResMan::loadCluDescript(const char *fileName) {
+ Common::File file;
+ file.open(fileName);
+
+ if (!file.isOpen()) {
+ char msg[512];
+ sprintf(msg, "Couldn't open CLU description '%s'\n\nIf you are running from CD, please ensure you have read the ScummVM documentation regarding multi-cd games.", fileName);
+ guiFatalError(msg);
+ }
+
+
+ _prj.noClu = file.readUint32LE();
+ _prj.clu = new Clu[_prj.noClu];
+ memset(_prj.clu, 0, _prj.noClu * sizeof(Clu));
+
+ uint32 *cluIndex = (uint32*)malloc(_prj.noClu * 4);
+ file.read(cluIndex, _prj.noClu * 4);
+
+ for (uint32 clusCnt = 0; clusCnt < _prj.noClu; clusCnt++)
+ if (cluIndex[clusCnt]) {
+ Clu *cluster = _prj.clu + clusCnt;
+ file.read(cluster->label, MAX_LABEL_SIZE);
+
+ cluster->file = NULL;
+ cluster->noGrp = file.readUint32LE();
+ cluster->grp = new Grp[cluster->noGrp];
+ cluster->nextOpen = NULL;
+ memset(cluster->grp, 0, cluster->noGrp * sizeof(Grp));
+ cluster->refCount = 0;
+
+ uint32 *grpIndex = (uint32*)malloc(cluster->noGrp * 4);
+ file.read(grpIndex, cluster->noGrp * 4);
+
+ for (uint32 grpCnt = 0; grpCnt < cluster->noGrp; grpCnt++)
+ if (grpIndex[grpCnt]) {
+ Grp *group = cluster->grp + grpCnt;
+ group->noRes = file.readUint32LE();
+ group->resHandle = new MemHandle[group->noRes];
+ group->offset = new uint32[group->noRes];
+ group->length = new uint32[group->noRes];
+ uint32 *resIdIdx = (uint32*)malloc(group->noRes * 4);
+ file.read(resIdIdx, group->noRes * 4);
+
+ for (uint32 resCnt = 0; resCnt < group->noRes; resCnt++) {
+ if (resIdIdx[resCnt]) {
+ group->offset[resCnt] = file.readUint32LE();
+ group->length[resCnt] = file.readUint32LE();
+ _memMan->initHandle(group->resHandle + resCnt);
+ } else {
+ group->offset[resCnt] = 0xFFFFFFFF;
+ group->length[resCnt] = 0;
+ _memMan->initHandle(group->resHandle + resCnt);
+ }
+ }
+ free(resIdIdx);
+ }
+ free(grpIndex);
+ }
+ free(cluIndex);
+
+ if (_prj.clu[3].grp[5].noRes == 29)
+ for (uint8 cnt = 0; cnt < 29; cnt++)
+ _srIdList[cnt] = 0x04050000 | cnt;
+}
+
+void ResMan::freeCluDescript(void) {
+
+ for (uint32 clusCnt = 0; clusCnt < _prj.noClu; clusCnt++) {
+ Clu *cluster = _prj.clu + clusCnt;
+ for (uint32 grpCnt = 0; grpCnt < cluster->noGrp; grpCnt++) {
+ Grp *group = cluster->grp + grpCnt;
+ if (group->resHandle != NULL) {
+ for (uint32 resCnt = 0; resCnt < group->noRes; resCnt++)
+ _memMan->freeNow(group->resHandle + resCnt);
+
+ delete[] group->resHandle;
+ delete[] group->offset;
+ delete[] group->length;
+ }
+ }
+ delete[] cluster->grp;
+
+ if (cluster->file != NULL)
+ delete cluster->file;
+ }
+ delete[] _prj.clu;
+}
+
+void ResMan::flush(void) {
+ for (uint32 clusCnt = 0; clusCnt < _prj.noClu; clusCnt++) {
+ Clu *cluster = _prj.clu + clusCnt;
+ for (uint32 grpCnt = 0; grpCnt < cluster->noGrp; grpCnt++) {
+ Grp *group = cluster->grp + grpCnt;
+ for (uint32 resCnt = 0; resCnt < group->noRes; resCnt++)
+ if (group->resHandle[resCnt].cond != MEM_FREED) {
+ _memMan->setCondition(group->resHandle + resCnt, MEM_CAN_FREE);
+ group->resHandle[resCnt].refCount = 0;
+ }
+ }
+ if (cluster->file) {
+ cluster->file->close();
+ delete cluster->file;
+ cluster->file = NULL;
+ cluster->refCount = 0;
+ }
+ }
+ _openClus = 0;
+ _openCluStart = _openCluEnd = NULL;
+ // the memory manager cached the blocks we asked it to free, so explicitly make it free them
+ _memMan->flush();
+}
+
+void *ResMan::fetchRes(uint32 id) {
+ MemHandle *memHandle = resHandle(id);
+ if (!memHandle->data)
+ error("fetchRes:: resource %d is not open!", id);
+ return memHandle->data;
+}
+
+void *ResMan::openFetchRes(uint32 id) {
+ resOpen(id);
+ return fetchRes(id);
+}
+
+void ResMan::dumpRes(uint32 id) {
+ char outn[30];
+ sprintf(outn, "DUMP%08X.BIN", id);
+ Common::File outf;
+ if (outf.open(outn, Common::File::kFileWriteMode)) {
+ resOpen(id);
+ MemHandle *memHandle = resHandle(id);
+ outf.write(memHandle->data, memHandle->size);
+ outf.close();
+ resClose(id);
+ }
+}
+
+Header *ResMan::lockScript(uint32 scrID) {
+ if (!_scriptList[scrID / ITM_PER_SEC])
+ error("Script id %d not found.\n", scrID);
+ scrID = _scriptList[scrID / ITM_PER_SEC];
+#ifdef SCUMM_BIG_ENDIAN
+ MemHandle *memHandle = resHandle(scrID);
+ if (memHandle->cond == MEM_FREED)
+ openScriptResourceBigEndian(scrID);
+ else
+ resOpen(scrID);
+#else
+ resOpen(scrID);
+#endif
+ return (Header*)resHandle(scrID)->data;
+}
+
+void ResMan::unlockScript(uint32 scrID) {
+ resClose(_scriptList[scrID / ITM_PER_SEC]);
+}
+
+void *ResMan::cptResOpen(uint32 id) {
+#ifdef SCUMM_BIG_ENDIAN
+ MemHandle *memHandle = resHandle(id);
+ if (memHandle->cond == MEM_FREED)
+ openCptResourceBigEndian(id);
+ else
+ resOpen(id);
+#else
+ resOpen(id);
+#endif
+ return resHandle(id)->data;
+}
+
+void ResMan::resOpen(uint32 id) { // load resource ID into memory
+ MemHandle *memHandle = resHandle(id);
+ if (memHandle->cond == MEM_FREED) { // memory has been freed
+ uint32 size = resLength(id);
+ _memMan->alloc(memHandle, size);
+ Common::File *clusFile = resFile(id);
+ assert(clusFile);
+ clusFile->seek( resOffset(id) );
+ clusFile->read( memHandle->data, size);
+ if (clusFile->ioFailed()) {
+ error("Can't read %d bytes from offset %d from cluster file %s\nResource ID: %d (%08X)\n", size, resOffset(id), _prj.clu[(id >> 24) - 1].label, id, id);
+ }
+ } else
+ _memMan->setCondition(memHandle, MEM_DONT_FREE);
+
+ memHandle->refCount++;
+ if (memHandle->refCount > 20) {
+ debug(1, "%d references to id %d. Guess there's something wrong.", memHandle->refCount, id);
+ }
+}
+
+void ResMan::resClose(uint32 id) {
+ MemHandle *handle = resHandle(id);
+ if (!handle->refCount) {
+ warning("Resource Manager fail: unlocking object with refCount 0. Id: %d\n", id);
+ } else {
+ handle->refCount--;
+ if (!handle->refCount)
+ _memMan->setCondition( handle, MEM_CAN_FREE);
+ }
+}
+
+FrameHeader *ResMan::fetchFrame(void *resourceData, uint32 frameNo) {
+ uint8 *frameFile = (uint8*)resourceData;
+ uint8 *idxData = frameFile + sizeof(Header);
+ if (frameNo >= READ_LE_UINT32(idxData))
+ error("fetchFrame:: frame %d doesn't exist in resource.", frameNo);
+ frameFile += READ_LE_UINT32(idxData + (frameNo+1) * 4);
+ return (FrameHeader*)frameFile;
+}
+
+Common::File *ResMan::resFile(uint32 id) {
+ Clu *cluster = _prj.clu + ((id >> 24) - 1);
+ if (cluster->file == NULL) {
+ _openClus++;
+ if (_openCluEnd == NULL) {
+ _openCluStart = _openCluEnd = cluster;
+ } else {
+ _openCluEnd->nextOpen = cluster;
+ _openCluEnd = cluster;
+ }
+ cluster->file = new Common::File();
+ char fileName[15];
+ sprintf(fileName, "%s.CLU", _prj.clu[(id >> 24)-1].label);
+ cluster->file->open(fileName);
+
+ if (!cluster->file->isOpen()) {
+ char msg[512];
+ sprintf(msg, "Couldn't open game cluster file '%s'\n\nIf you are running from CD, please ensure you have read the ScummVM documentation regarding multi-cd games.", fileName);
+ guiFatalError(msg);
+ }
+ while (_openClus > MAX_OPEN_CLUS) {
+ assert(_openCluStart);
+ Clu *closeClu = _openCluStart;
+ _openCluStart = _openCluStart->nextOpen;
+
+ closeClu->file->close();
+ delete closeClu->file;
+ closeClu->file = NULL;
+ closeClu->nextOpen = NULL;
+ _openClus--;
+ }
+ }
+ return cluster->file;
+}
+
+MemHandle *ResMan::resHandle(uint32 id) {
+ if ((id >> 16) == 0x0405)
+ id = _srIdList[id & 0xFFFF];
+ uint8 cluster = (uint8)((id >> 24) - 1);
+ uint8 group = (uint8)(id >> 16);
+
+ return &(_prj.clu[cluster].grp[group].resHandle[id & 0xFFFF]);
+}
+
+uint32 ResMan::resLength(uint32 id) {
+ if ((id >> 16) == 0x0405)
+ id = _srIdList[id & 0xFFFF];
+ uint8 cluster = (uint8)((id >> 24) - 1);
+ uint8 group = (uint8)(id >> 16);
+
+ return _prj.clu[cluster].grp[group].length[id & 0xFFFF];
+}
+
+uint32 ResMan::resOffset(uint32 id) {
+ if ((id >> 16) == 0x0405)
+ id = _srIdList[id & 0xFFFF];
+ uint8 cluster = (uint8)((id >> 24) - 1);
+ uint8 group = (uint8)(id >> 16);
+
+ return _prj.clu[cluster].grp[group].offset[id & 0xFFFF];
+}
+
+void ResMan::openCptResourceBigEndian(uint32 id) {
+ resOpen(id);
+ MemHandle *handle = resHandle(id);
+ uint32 totSize = handle->size;
+ uint32 *data = (uint32*)((uint8*)handle->data + sizeof(Header));
+ totSize -= sizeof(Header);
+ if (totSize & 3)
+ error("Illegal compact size for id %d: %d", id, totSize);
+ totSize /= 4;
+ for (uint32 cnt = 0; cnt < totSize; cnt++) {
+ *data = READ_LE_UINT32(data);
+ data++;
+ }
+}
+
+void ResMan::openScriptResourceBigEndian(uint32 id) {
+ resOpen(id);
+ MemHandle *handle = resHandle(id);
+ // uint32 totSize = handle->size;
+ Header *head = (Header*)handle->data;
+ head->comp_length = FROM_LE_32(head->comp_length);
+ head->decomp_length = FROM_LE_32(head->decomp_length);
+ head->version = FROM_LE_16(head->version);
+ uint32 *data = (uint32*)((uint8*)handle->data + sizeof(Header));
+ uint32 size = handle->size - sizeof(Header);
+ if (size & 3)
+ error("Odd size during script endian conversion. Resource ID =%d, size = %d", id, size);
+ size >>= 2;
+ for (uint32 cnt = 0; cnt < size; cnt++) {
+ *data = READ_LE_UINT32(data);
+ data++;
+ }
+}
+
+uint32 ResMan::_srIdList[29] = { // the file numbers differ for the control panel file IDs, so we need this array
+ OTHER_SR_FONT, // SR_FONT
+ 0x04050000, // SR_BUTTON
+ OTHER_SR_REDFONT, // SR_REDFONT
+ 0x04050001, // SR_PALETTE
+ 0x04050002, // SR_PANEL_ENGLISH
+ 0x04050003, // SR_PANEL_FRENCH
+ 0x04050004, // SR_PANEL_GERMAN
+ 0x04050005, // SR_PANEL_ITALIAN
+ 0x04050006, // SR_PANEL_SPANISH
+ 0x04050007, // SR_PANEL_AMERICAN
+ 0x04050008, // SR_TEXT_BUTTON
+ 0x04050009, // SR_SPEED
+ 0x0405000A, // SR_SCROLL1
+ 0x0405000B, // SR_SCROLL2
+ 0x0405000C, // SR_CONFIRM
+ 0x0405000D, // SR_VOLUME
+ 0x0405000E, // SR_VLIGHT
+ 0x0405000F, // SR_VKNOB
+ 0x04050010, // SR_WINDOW
+ 0x04050011, // SR_SLAB1
+ 0x04050012, // SR_SLAB2
+ 0x04050013, // SR_SLAB3
+ 0x04050014, // SR_SLAB4
+ 0x04050015, // SR_BUTUF
+ 0x04050016, // SR_BUTUS
+ 0x04050017, // SR_BUTDS
+ 0x04050018, // SR_BUTDF
+ 0x04050019, // SR_DEATHPANEL
+ 0,
+};
+
+} // End of namespace Sword1
diff --git a/engines/sword1/resman.h b/engines/sword1/resman.h
new file mode 100644
index 0000000000..e2920b0a81
--- /dev/null
+++ b/engines/sword1/resman.h
@@ -0,0 +1,98 @@
+/* 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 RESMAN_H
+#define RESMAN_H
+
+#include "sword1/memman.h"
+#include "common/file.h"
+#include "sword1/sworddefs.h"
+
+namespace Sword1 {
+
+#define MAX_LABEL_SIZE (31+1)
+
+#if defined(__PSP__)
+#define MAX_OPEN_CLUS 4 // the PSP can't have more than 8 files open simultaneously
+ // since we also need filehandles for music and sometimes savegames
+ // set the maximum number of open clusters to 4.
+#else
+#define MAX_OPEN_CLUS 8 // don't open more than 8 files at once
+#endif
+
+struct Grp {
+ uint32 noRes;
+ MemHandle *resHandle;
+ uint32 *offset;
+ uint32 *length;
+};
+
+struct Clu {
+ uint32 refCount;
+ Common::File *file;
+ char label[MAX_LABEL_SIZE];
+ uint32 noGrp;
+ Grp *grp;
+ Clu *nextOpen;
+};
+
+struct Prj {
+ uint32 noClu;
+ Clu *clu;
+};
+
+class ResMan {
+public:
+ ResMan(const char *fileName);
+ ~ResMan(void);
+ void flush(void);
+ void resClose(uint32 id);
+ void resOpen(uint32 id);
+ void *fetchRes(uint32 id);
+ void dumpRes(uint32 id);
+ void *openFetchRes(uint32 id);
+ void *cptResOpen(uint32 id);
+ Header *lockScript(uint32 scrID);
+ void unlockScript(uint32 scrID);
+ FrameHeader *fetchFrame(void *resourceData, uint32 frameNo);
+private:
+ uint32 resLength(uint32 id);
+ MemHandle *resHandle(uint32 id);
+ uint32 resOffset(uint32 id);
+ Common::File *resFile(uint32 id);
+
+ void openCptResourceBigEndian(uint32 id);
+ void openScriptResourceBigEndian(uint32 id);
+
+ void loadCluDescript(const char *fileName);
+ void freeCluDescript(void);
+ Prj _prj;
+ MemMan *_memMan;
+ static const uint32 _scriptList[TOTAL_SECTIONS]; //a table of resource tags
+ static uint32 _srIdList[29];
+ Clu *_openCluStart, *_openCluEnd;
+ int _openClus;
+};
+
+} // End of namespace Sword1
+
+#endif //RESMAN_H
diff --git a/engines/sword1/router.cpp b/engines/sword1/router.cpp
new file mode 100644
index 0000000000..d4a1b26648
--- /dev/null
+++ b/engines/sword1/router.cpp
@@ -0,0 +1,2606 @@
+/* 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 "sword1/router.h"
+#include "common/util.h"
+#include "common/scummsys.h"
+#include "sword1/swordres.h"
+#include "sword1/sworddefs.h"
+#include "sword1/objectman.h"
+#include "sword1/resman.h"
+
+namespace Sword1 {
+
+/****************************************************************************
+ * JROUTER.C polygon router with modular walks
+ * using a tree of modules
+ * 21 july 94
+ * 3 november 94
+ * System currently works by scanning grid data and coming up with a ROUTE
+ * as a series of way points(nodes), the smoothest eight directional PATH
+ * through these nodes is then found, and a WALK created to fit the PATH.
+ *
+ * Two funtions are called by the user, RouteFinder creates a route as a
+ * module list, HardWalk creates an animation list from the module list.
+ * The split is only provided to allow the possibility of turning the
+ * autorouter over two game cycles.
+ ****************************************************************************
+ *
+ * Routine timings on osborne 486
+ *
+ * Read floor resource (file already loaded) 112 pixels
+ *
+ * Read mega resource (file already loaded) 112 pixels
+ *
+ *
+ *
+ ****************************************************************************
+ *
+ * Modified 12 Oct 95
+ *
+ * Target Points within 1 pixel of a line are ignored ???
+ *
+ * Modules split into Points within 1 pixel of a line are ignored ???
+ *
+ ****************************************************************************/
+
+#define NO_DIRECTIONS 8
+#define SLOW_IN 3
+#define SLOW_OUT 7
+#define ROUTE_END_FLAG 255
+//#define PLOT_PATHS 1
+#undef PLOT_PATHS
+
+Router::Router(ObjectMan *pObjMan, ResMan *pResMan) {
+ _objMan = pObjMan;
+ _resMan = pResMan;
+ _numExtraBars = _numExtraNodes = 0;
+ nnodes = nbars = 0;
+ _playerTargetX = _playerTargetY = _playerTargetDir = _playerTargetStance = 0;
+ diagonalx = diagonaly = 0;
+}
+
+/*
+ * CODE
+ */
+
+int32 Router::routeFinder(int32 id, Object *megaObject, int32 x, int32 y, int32 dir)
+{
+/****************************************************************************
+ * RouteFinder.C polygon router with modular walks
+ * 21 august 94
+ * 3 november 94
+ * RouteFinder creates a list of modules that enables HardWalk to create
+ * an animation list.
+ *
+ * RouteFinder currently works by scanning grid data and coming up with a ROUTE
+ * as a series of way points(nodes), the smoothest eight directional PATH
+ * through these nodes is then found, this information is made available to
+ * HardWalk for a WALK to be created to fit the PATH.
+ *
+ * 30 november 94 return values modified
+ *
+ * return 0 = failed to find a route
+ *
+ * 1 = found a route
+ *
+ * 2 = mega already at target
+ *
+ ****************************************************************************/
+
+ int32 routeFlag = 0;
+ int32 solidFlag = 0;
+
+ megaId = id;
+
+ LoadWalkResources(megaObject, x, y, dir);
+
+ framesPerStep = nWalkFrames/2;
+ framesPerChar = nWalkFrames * NO_DIRECTIONS;
+
+ // offset pointers added Oct 30 95 JPS
+ standFrames = framesPerChar;
+ turnFramesLeft = standFrames;
+ turnFramesRight = standFrames;
+ walkFramesLeft = 0;
+ walkFramesRight = 0;
+ slowInFrames = 0;
+ slowOutFrames = 0;
+
+ if (megaId == GEORGE)
+ {
+ turnFramesLeft = 3 * framesPerChar + NO_DIRECTIONS + 2 * SLOW_IN + 4 * SLOW_OUT;
+ turnFramesRight = 3 * framesPerChar + NO_DIRECTIONS + 2 * SLOW_IN + 4 * SLOW_OUT + NO_DIRECTIONS;
+ walkFramesLeft = framesPerChar + NO_DIRECTIONS;
+ walkFramesRight = 2 * framesPerChar + NO_DIRECTIONS;
+ slowInFrames = 3 * framesPerChar + NO_DIRECTIONS;
+ slowOutFrames = 3 * framesPerChar + NO_DIRECTIONS + 2 * SLOW_IN;
+ }
+ else if (megaId == NICO)
+ {
+ turnFramesLeft = framesPerChar + NO_DIRECTIONS;
+ turnFramesRight = framesPerChar + 2 * NO_DIRECTIONS;
+ walkFramesLeft = 0;
+ walkFramesRight = 0;
+ slowInFrames = 0;
+ slowOutFrames = 0;
+ }
+
+// **************************************************************************
+// All route data now loaded start finding a route
+// **************************************************************************
+// **************************************************************************
+// Check if we can get a route through the floor changed 12 Oct95 JPS
+// **************************************************************************
+
+ routeFlag = GetRoute();
+
+ if (routeFlag == 2) //special case for zero length route
+ {
+ if (targetDir >7)// if target direction specified as any
+ {
+ targetDir = startDir;
+ }
+ // just a turn on the spot is required set an end module for the route let the animator deal with it
+ // modularPath is normally set by ExtractRoute
+ modularPath[0].dir = startDir;
+ modularPath[0].num = 0;
+ modularPath[0].x = startX;
+ modularPath[0].y = startY;
+ modularPath[1].dir = targetDir;
+ modularPath[1].num = 0;
+ modularPath[1].x = startX;
+ modularPath[1].y = startY;
+ modularPath[2].dir = 9;
+ modularPath[2].num = ROUTE_END_FLAG;
+
+ SlidyWalkAnimator(megaObject->o_route);
+ routeFlag = 2;
+ }
+ else if (routeFlag == 1) // a normal route
+ {
+ SmoothestPath();//Converts the route to an exact path
+ // The Route had waypoints and direction options
+ // The Path is an exact set of lines in 8 directions that reach the target.
+ // The path is in module format, but steps taken in each direction are not accurate
+ // if target dir = 8 then the walk isn't linked to an anim so
+ // we can create a route without sliding and miss the exact target
+ if (targetDir == NO_DIRECTIONS)
+ {
+ SolidPath();
+ solidFlag = SolidWalkAnimator(megaObject->o_route);
+ }
+
+ if (!solidFlag)
+ {
+ SlidyPath();
+ SlidyWalkAnimator(megaObject->o_route);
+ }
+ }
+ else // Route didn't reach target so assume point was off the floor
+ {
+// routeFlag = 0;
+ }
+ return routeFlag; // send back null route
+}
+
+// ****************************************************************************
+// * GET A ROUTE
+// ****************************************************************************
+
+int32 Router::GetRoute()
+{
+ /****************************************************************************
+ * GetRoute.C extract a path from walk grid
+ * 12 october 94
+ *
+ * GetRoute currently works by scanning grid data and coming up with a ROUTE
+ * as a series of way points(nodes).
+ * static _routeData route[O_ROUTE_SIZE];
+ *
+ * return 0 = failed to find a route
+ *
+ * 1 = found a route
+ *
+ * 2 = mega already at target
+ *
+ * 3 = failed to find a route because target was on a line
+ *
+ ****************************************************************************/
+ int32 routeGot = 0;
+ int32 level;
+ int32 changed;
+
+ if ((startX == targetX) && (startY == targetY))
+ routeGot = 2;
+
+ else // 'else' added by JEL (23jan96) otherwise 'routeGot' affected even when already set to '2' above - causing some 'turns' to walk downwards on the spot
+ routeGot = CheckTarget(targetX,targetY);// returns 3 if target on a line ( +- 1 pixel )
+
+
+ if (routeGot == 0) //still looking for a route check if target is within a pixel of a line
+ {
+ // scan through the nodes linking each node to its nearest neighbour until no more nodes change
+ // This is the routine that finds a route using Scan()
+ level = 1;
+ do
+ {
+ changed = Scan(level);
+ level =level + 1;
+ }
+ while (changed == 1);
+
+ // Check to see if the route reached the target
+ if (node[nnodes].dist < 9999)
+ {
+ routeGot = 1;
+ ExtractRoute(); // it did so extract the route as nodes and the directions to go between each node
+ // route.X,route.Y and route.Dir now hold all the route infomation with the target dir or route continuation
+ }
+ }
+
+ return routeGot;
+}
+
+// ****************************************************************************
+// * THE SLIDY PATH ROUTINES
+// ****************************************************************************
+
+int32 Router::SmoothestPath()
+{
+/*
+ * This is the second big part of the route finder and the the only bit that tries to be clever
+ * (the other bits are clever).
+ * This part of the autorouter creates a list of modules from a set of lines running across the screen
+ * The task is complicated by two things;
+ * Firstly in chosing a route through the maze of nodes the routine tries to minimise the amount of each
+ * individual turn avoiding 90 degree and greater turns (where possible) and reduces the total nuber of
+ * turns (subject to two 45 degree turns being better than one 90 degree turn).
+ * Secondly when walking in a given direction the number of steps required to reach the end of that run
+ * is not calculated accurately. This is because I was unable to derive a function to relate number of
+ * steps taken between two points to the shrunken step size
+ *
+ */
+ int32 p;
+ int32 dirS;
+ int32 dirD;
+ int32 dS;
+ int32 dD;
+ int32 dSS;
+ int32 dSD;
+ int32 dDS;
+ int32 dDD;
+ int32 SS;
+ int32 SD;
+ int32 DS;
+ int32 DD;
+ int32 i;
+ int32 j;
+ int32 temp;
+ int32 steps;
+ int32 option;
+ int32 options;
+ int32 lastDir;
+ int32 nextDirS;
+ int32 nextDirD;
+ int32 tempturns[4];
+ int32 turns[4];
+ int32 turntable[NO_DIRECTIONS] = {0,1,3,5,7,5,3,1};
+
+// targetDir;// no warnings
+
+ // route.X route.Y and route.Dir start at far end
+ smoothPath[0].x = startX;
+ smoothPath[0].y = startY;
+ smoothPath[0].dir = startDir;
+ smoothPath[0].num = 0;
+ p = 0;
+ lastDir = startDir;
+ // for each section of the route
+ do
+ {
+ dirS = route[p].dirS;
+ dirD = route[p].dirD;
+ nextDirS = route[p+1].dirS;
+ nextDirD = route[p+1].dirD;
+
+ // Check directions into and out of a pair of nodes
+ // going in
+ dS = dirS - lastDir;
+ if ( dS < 0)
+ dS = dS + NO_DIRECTIONS;
+
+ dD = dirD - lastDir;
+ if ( dD < 0)
+ dD = dD + NO_DIRECTIONS;
+
+ // coming out
+ dSS = dirS - nextDirS;
+ if ( dSS < 0)
+ dSS = dSS + NO_DIRECTIONS;
+
+ dDD = dirD - nextDirD;
+ if ( dDD < 0)
+ dDD = dDD + NO_DIRECTIONS;
+
+ dSD = dirS - nextDirD;
+ if ( dSD < 0)
+ dSD = dSD + NO_DIRECTIONS;
+
+ dDS = dirD - nextDirS;
+ if ( dDS < 0)
+ dDS = dDS + NO_DIRECTIONS;
+
+ // Determine the amount of turning involved in each possible path
+ dS = turntable[dS];
+ dD = turntable[dD];
+ dSS = turntable[dSS];
+ dDD = turntable[dDD];
+ dSD = turntable[dSD];
+ dDS = turntable[dDS];
+ // get the best path out ie assume next section uses best direction
+ if (dSD < dSS)
+ {
+ dSS = dSD;
+ }
+ if (dDS < dDD)
+ {
+ dDD = dDS;
+ }
+ // rate each option
+ SS = dS + dSS + 3; // Split routes look crap so weight against them
+ SD = dS + dDD;
+ DS = dD + dSS;
+ DD = dD + dDD + 3;
+ // set up turns as a sorted array of the turn values
+ tempturns[0] = SS;
+ turns[0] = 0;
+ tempturns[1] = SD;
+ turns[1] = 1;
+ tempturns[2] = DS;
+ turns[2] = 2;
+ tempturns[3] = DD;
+ turns[3] = 3;
+ i = 0;
+ do
+ {
+ j = 0;
+ do
+ {
+ if (tempturns[j] > tempturns[j + 1])
+ {
+ temp = turns[j];
+ turns[j] = turns[j+1];
+ turns[j+1] = temp;
+ temp = tempturns[j];
+ tempturns[j] = tempturns[j+1];
+ tempturns[j+1] = temp;
+ }
+ j = j + 1;
+ }
+ while (j < 3);
+ i = i + 1;
+ }
+ while (i < 3);
+
+ // best option matched in order of the priority we would like to see on the screen
+ // but each option must be checked to see if it can be walked
+
+ options = NewCheck(1, route[p].x, route[p].y, route[p + 1].x, route[p + 1].y);
+
+ if (options == 0)
+ {
+ /*Tdebug("BestTurns fail %d %d %d %d",route[p].x, route[p].y, route[p + 1].x, route[p + 1].y);
+ Tdebug("BestTurns fail %d %d %d %d",turns[0],turns[1],turns[2],options);
+ Go_dos("BestTurns failed");*/
+ error("BestTurns failed");
+ }
+ i = 0;
+ steps = 0;
+ do
+ {
+ option = 1 << turns[i];
+ if (option & options)
+ steps = SmoothCheck(turns[i],p,dirS,dirD);
+ i = i + 1;
+ }
+ while ((steps == 0) && (i < 4));
+
+#ifdef PLOT_PATHS // plot the best path
+ if (steps != 0)
+ {
+ i = 0;
+ do
+ {
+ RouteLine(smoothPath[i].x, smoothPath[i].y, smoothPath[i+1].x, smoothPath[i+1].y, 228);
+ i = i + 1;
+ }
+ while (i < steps);
+ }
+#endif
+
+ if (steps == 0)
+ {
+ /*Tdebug("BestTurns failed %d %d %d %d",route[p].x, route[p].y, route[p + 1].x, route[p + 1].y);
+ Tdebug("BestTurns failed %d %d %d %d",turns[0],turns[1],turns[2],options);
+ Go_dos("BestTurns failed");*/
+ error("BestTurns failed");
+ }
+ // route.X route.Y route.dir and bestTurns start at far end
+ p = p + 1;
+
+
+ }
+ while (p < (routeLength));
+ // best turns will end heading as near as possible to target dir rest is down to anim for now
+ smoothPath[steps].dir = 9;
+ smoothPath[steps].num = ROUTE_END_FLAG;
+ return 1;
+}
+
+
+
+
+int32 Router::SmoothCheck(int32 best, int32 p, int32 dirS, int32 dirD)
+/****************************************************************************
+ * Slip sliding away
+ * This path checker checks to see if a walk that exactly follows the path
+ * would be valid. This should be inherently true for atleast one of the turn
+ * options.
+ * No longer checks the data it only creates the smoothPath array JPS
+ ****************************************************************************/
+{
+ static int32 k;
+ int32 tempK;
+ int32 x;
+ int32 y;
+ int32 x2;
+ int32 y2;
+ int32 dx;
+ int32 dy;
+ int32 dsx;
+ int32 dsy;
+ int32 ddx;
+ int32 ddy;
+ int32 dirX;
+ int32 dirY;
+ int32 ss0;
+ int32 ss1;
+ int32 ss2;
+ int32 sd0;
+ int32 sd1;
+ int32 sd2;
+
+ if (p == 0)
+ {
+ k = 1;
+ }
+ tempK = 0;
+ x = route[p].x;
+ y = route[p].y;
+ x2 = route[p + 1].x;
+ y2 = route[p + 1].y;
+ dx = x2 - x;
+ dy = y2 - y;
+ dirX = 1;
+ dirY = 1;
+ if (dx < 0)
+ {
+ dx = -dx;
+ dirX = -1;
+ }
+
+ if (dy < 0)
+ {
+ dy = -dy;
+ dirY = -1;
+ }
+
+// set up sd0-ss2 to reflect possible movement in each direction
+ if ((dirS == 0) || (dirS == 4))// vert and diag
+ {
+ ddx = dx;
+ ddy = (dx*diagonaly)/diagonalx;
+ dsy = dy - ddy;
+ ddx = ddx * dirX;
+ ddy = ddy * dirY;
+ dsy = dsy * dirY;
+ dsx = 0;
+
+ sd0 = (ddx + modX[dirD]/2)/ modX[dirD];
+ ss0 = (dsy + modY[dirS]/2) / modY[dirS];
+ sd1 = sd0/2;
+ ss1 = ss0/2;
+ sd2 = sd0 - sd1;
+ ss2 = ss0 - ss1;
+ }
+ else
+ {
+ ddy = dy;
+ ddx = (dy*diagonalx)/diagonaly;
+ dsx = dx - ddx;
+ ddy = ddy * dirY;
+ ddx = ddx * dirX;
+ dsx = dsx * dirX;
+ dsy = 0;
+
+ sd0 = (ddy + modY[dirD]/2)/ modY[dirD];
+ ss0 = (dsx + modX[dirS]/2)/ modX[dirS];
+ sd1 = sd0/2;
+ ss1 = ss0/2;
+ sd2 = sd0 - sd1;
+ ss2 = ss0 - ss1;
+ }
+
+ if (best == 0) //halfsquare, diagonal, halfsquare
+ {
+ smoothPath[k].x = x+dsx/2;
+ smoothPath[k].y = y+dsy/2;
+ smoothPath[k].dir = dirS;
+ smoothPath[k].num = ss1;
+ k = k + 1;
+ smoothPath[k].x = x+dsx/2+ddx;
+ smoothPath[k].y = y+dsy/2+ddy;
+ smoothPath[k].dir = dirD;
+ smoothPath[k].num = sd0;
+ k = k + 1;
+ smoothPath[k].x = x+dsx+ddx;
+ smoothPath[k].y = y+dsy+ddy;
+ smoothPath[k].dir = dirS;
+ smoothPath[k].num = ss2;
+ k = k + 1;
+ tempK = k;
+ }
+ else if (best == 1) //square, diagonal
+ {
+ smoothPath[k].x = x+dsx;
+ smoothPath[k].y = y+dsy;
+ smoothPath[k].dir = dirS;
+ smoothPath[k].num = ss0;
+ k = k + 1;
+ smoothPath[k].x = x2;
+ smoothPath[k].y = y2;
+ smoothPath[k].dir = dirD;
+ smoothPath[k].num = sd0;
+ k = k + 1;
+ tempK = k;
+ }
+ else if (best == 2) //diagonal square
+ {
+ smoothPath[k].x = x+ddx;
+ smoothPath[k].y = y+ddy;
+ smoothPath[k].dir = dirD;
+ smoothPath[k].num = sd0;
+ k = k + 1;
+ smoothPath[k].x = x2;
+ smoothPath[k].y = y2;
+ smoothPath[k].dir = dirS;
+ smoothPath[k].num = ss0;
+ k = k + 1;
+ tempK = k;
+ }
+ else //halfdiagonal, square, halfdiagonal
+ {
+ smoothPath[k].x = x+ddx/2;
+ smoothPath[k].y = y+ddy/2;
+ smoothPath[k].dir = dirD;
+ smoothPath[k].num = sd1;
+ k = k + 1;
+ smoothPath[k].x = x+dsx+ddx/2;
+ smoothPath[k].y = y+dsy+ddy/2;
+ smoothPath[k].dir = dirS;
+ smoothPath[k].num = ss0;
+ k = k + 1;
+ smoothPath[k].x = x2;
+ smoothPath[k].y = y2;
+ smoothPath[k].dir = dirD;
+ smoothPath[k].num = sd2;
+ k = k + 1;
+ tempK = k;
+ }
+
+ return tempK;
+}
+
+int32 Router::SlidyPath()
+{
+/****************************************************************************
+ * SlidyPath creates a path based on part steps with no sliding to get
+ * as near as possible to the target without any sliding this routine is
+ * currently unused, but is intended for use when just clicking about.
+ *
+ * produce a module list from the line data
+ *
+ ****************************************************************************/
+ int32 smooth;
+ int32 slidy;
+ int32 scale;
+ int32 stepX;
+ int32 stepY;
+ int32 deltaX;
+ int32 deltaY;
+
+ // strip out the short sections
+ slidy = 1;
+ smooth = 1;
+ modularPath[0].x = smoothPath[0].x;
+ modularPath[0].y = smoothPath[0].y;
+ modularPath[0].dir = smoothPath[0].dir;
+ modularPath[0].num = 0;
+
+ while (smoothPath[smooth].num < ROUTE_END_FLAG)
+ {
+ scale = scaleA * smoothPath[smooth].y + scaleB;
+ deltaX = smoothPath[smooth].x - modularPath[slidy-1].x;
+ deltaY = smoothPath[smooth].y - modularPath[slidy-1].y;
+ stepX = modX[smoothPath[smooth].dir];
+ stepY = modY[smoothPath[smooth].dir];
+ stepX = stepX * scale;
+ stepY = stepY * scale;
+ stepX = stepX >> 19;// quarter a step minimum
+ stepY = stepY >> 19;
+ if ((ABS(deltaX)>=ABS(stepX)) && (ABS(deltaY)>=ABS(stepY)))
+ {
+ modularPath[slidy].x = smoothPath[smooth].x;
+ modularPath[slidy].y = smoothPath[smooth].y;
+ modularPath[slidy].dir = smoothPath[smooth].dir;
+ modularPath[slidy].num = 1;
+ slidy += 1;
+ }
+ smooth += 1;
+ }
+ // in case the last bit had no steps
+ if (slidy > 1)
+ {
+ modularPath[slidy-1].x = smoothPath[smooth-1].x;
+ modularPath[slidy-1].y = smoothPath[smooth-1].y;
+ }
+ // set up the end of the walk
+ modularPath[slidy].x = smoothPath[smooth-1].x;
+ modularPath[slidy].y = smoothPath[smooth-1].y;
+ modularPath[slidy].dir = targetDir;
+ modularPath[slidy].num = 0;
+ slidy += 1;
+ modularPath[slidy].x = smoothPath[smooth-1].x;
+ modularPath[slidy].y = smoothPath[smooth-1].y;
+ modularPath[slidy].dir = 9;
+ modularPath[slidy].num = ROUTE_END_FLAG;
+ return 1;
+
+}
+
+void Router::SlidyWalkAnimator(WalkData *walkAnim)
+/****************************************************************************
+ * Skidding every where HardWalk creates an animation that exactly fits the
+ * smoothPath and uses foot slipping to fit whole steps into the route
+ * Parameters: georgeg,mouseg
+ * Returns: rout
+ *
+ * produce a module list from the line data
+ *
+ ****************************************************************************/
+{
+
+ static int32 left = 0;
+ int32 p;
+ int32 lastDir;
+ int32 lastRealDir;
+ int32 currentDir;
+ int32 turnDir;
+ int32 scale;
+ int32 step;
+ int32 module;
+ int32 moduleEnd;
+ int32 moduleX;
+ int32 moduleY;
+ int32 module16X = 0;
+ int32 module16Y = 0;
+ int32 stepX;
+ int32 stepY;
+ int32 errorX;
+ int32 errorY;
+ int32 lastErrorX;
+ int32 lastErrorY;
+ int32 lastCount;
+ int32 stepCount;
+ int32 frameCount;
+ int32 frames;
+ int32 frame;
+
+ // start at the begining for a change
+ p = 0;
+ lastDir = modularPath[0].dir;
+ currentDir = modularPath[1].dir;
+ if (currentDir == NO_DIRECTIONS)
+ {
+ currentDir = lastDir;
+ }
+ moduleX = startX;
+ moduleY = startY;
+ module16X = moduleX << 16;
+ module16Y = moduleY << 16;
+ stepCount = 0;
+
+ //****************************************************************************
+ // SLIDY
+ // START THE WALK WITH THE FIRST STANDFRAME THIS MAY CAUSE A DELAY
+ // BUT IT STOPS THE PLAYER MOVING FOR COLLISIONS ARE DETECTED
+ //****************************************************************************
+ module = framesPerChar + lastDir;
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = lastDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+
+ //****************************************************************************
+ // SLIDY
+ // TURN TO START THE WALK
+ //****************************************************************************
+ // rotate if we need to
+ if (lastDir != currentDir)
+ {
+ // get the direction to turn
+ turnDir = currentDir - lastDir;
+ if ( turnDir < 0)
+ turnDir += NO_DIRECTIONS;
+
+ if (turnDir > 4)
+ turnDir = -1;
+ else if (turnDir > 0)
+ turnDir = 1;
+
+ // rotate to new walk direction
+ // for george and nico put in a head turn at the start
+ if ((megaId == GEORGE) || (megaId == NICO))
+ {
+ if ( turnDir < 0) // new frames for turn frames 29oct95jps
+ {
+ module = turnFramesLeft + lastDir;
+ }
+ else
+ {
+ module = turnFramesRight + lastDir;
+ }
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = lastDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+
+ // rotate till were facing new dir then go back 45 degrees
+ while (lastDir != currentDir)
+ {
+ lastDir += turnDir;
+ if ( turnDir < 0) // new frames for turn frames 29oct95jps
+ {
+ if ( lastDir < 0)
+ lastDir += NO_DIRECTIONS;
+ module = turnFramesLeft + lastDir;
+ }
+ else
+ {
+ if ( lastDir > 7)
+ lastDir -= NO_DIRECTIONS;
+ module = turnFramesRight + lastDir;
+ }
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = lastDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+ // the back 45 degrees bit
+ stepCount -= 1;// step back one because new head turn for george takes us past the new dir
+ }
+ // his head is in the right direction
+ lastRealDir = currentDir;
+
+ //****************************************************************************
+ // SLIDY
+ // THE WALK
+ //****************************************************************************
+
+ if (left == 0)
+ left = framesPerStep;
+ else
+ left = 0;
+
+ lastCount = stepCount;
+ lastDir = 99;// this ensures that we don't put in turn frames for the start
+ currentDir = 99;// this ensures that we don't put in turn frames for the start
+ do
+ {
+ while (modularPath[p].num == 0)
+ {
+ p = p + 1;
+ if (currentDir != 99)
+ lastRealDir = currentDir;
+ lastDir = currentDir;
+ lastCount = stepCount;
+ }
+ //calculate average amount to lose in each step on the way to the next node
+ currentDir = modularPath[p].dir;
+ if (currentDir < NO_DIRECTIONS)
+ {
+ module = currentDir * framesPerStep * 2 + left;
+ if (left == 0)
+ left = framesPerStep;
+ else
+ left = 0;
+ moduleEnd = module + framesPerStep;
+ step = 0;
+ scale = (scaleA * moduleY + scaleB);
+ do
+ {
+ module16X += _dx[module]*scale;
+ module16Y += _dy[module]*scale;
+ moduleX = module16X >> 16;
+ moduleY = module16Y >> 16;
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = step;
+ walkAnim[stepCount].dir = currentDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ step += 1;
+ module += 1;
+ }
+ while ( module < moduleEnd) ;
+ stepX = modX[modularPath[p].dir];
+ stepY = modY[modularPath[p].dir];
+ errorX = modularPath[p].x - moduleX;
+ errorX = errorX * stepX;
+ errorY = modularPath[p].y - moduleY;
+ errorY = errorY * stepY;
+ if ((errorX < 0) || (errorY < 0))
+ {
+ modularPath[p].num = 0; // the end of the path
+ // okay those last steps took us past our target but do we want to scoot or moonwalk
+ frames = stepCount - lastCount;
+ errorX = modularPath[p].x - walkAnim[stepCount-1].x;
+ errorY = modularPath[p].y - walkAnim[stepCount-1].y;
+
+ if (frames > framesPerStep)
+ {
+ lastErrorX = modularPath[p].x - walkAnim[stepCount-7].x;
+ lastErrorY = modularPath[p].y - walkAnim[stepCount-7].y;
+ if (stepX==0)
+ {
+ if (3*ABS(lastErrorY) < ABS(errorY)) //the last stop was closest
+ {
+ stepCount -= framesPerStep;
+ if (left == 0)
+ left = framesPerStep;
+ else
+ left = 0;
+ }
+ }
+ else
+ {
+ if (3*ABS(lastErrorX) < ABS(errorX)) //the last stop was closest
+ {
+ stepCount -= framesPerStep;
+ if (left == 0)
+ left = framesPerStep;
+ else
+ left = 0;
+ }
+ }
+ }
+ errorX = modularPath[p].x - walkAnim[stepCount-1].x;
+ errorY = modularPath[p].y - walkAnim[stepCount-1].y;
+ // okay we've reached the end but we still have an error
+ if (errorX != 0)
+ {
+ frameCount = 0;
+ frames = stepCount - lastCount;
+ do
+ {
+ frameCount += 1;
+ walkAnim[lastCount + frameCount - 1].x += errorX*frameCount/frames;
+ }
+ while (frameCount<frames);
+ }
+ if (errorY != 0)
+ {
+ frameCount = 0;
+ frames = stepCount - lastCount;
+ do
+ {
+ frameCount += 1;
+ walkAnim[lastCount + frameCount-1].y += errorY*frameCount/frames;
+ }
+ while (frameCount<frames);
+ }
+ // Now is the time to put in the turn frames for the last turn
+ if (frames < framesPerStep)
+ currentDir = 99;// this ensures that we don't put in turn frames for this walk or the next
+ if (currentDir != 99)
+ lastRealDir = currentDir;
+ // check each turn condition in turn
+ if (((lastDir != 99) && (currentDir != 99)) && (megaId == GEORGE)) // only for george
+ {
+ lastDir = currentDir - lastDir;//1 and -7 going right -1 and 7 going left
+ if (((lastDir == -1) || (lastDir == 7)) || ((lastDir == -2) || (lastDir == 6)))
+ {
+ // turn at the end of the last walk
+ frame = lastCount - framesPerStep;
+ do
+ {
+ walkAnim[frame].frame += 104;//turning left
+ frame += 1;
+ }
+ while (frame < lastCount );
+ }
+ if (((lastDir == 1) || (lastDir == -7)) || ((lastDir == 2) || (lastDir == -6)))
+ {
+ // turn at the end of the current walk
+ frame = lastCount - framesPerStep;
+ do
+ {
+ walkAnim[frame].frame += 200; //was 60 now 116
+ frame += 1;
+ }
+ while (frame < lastCount );
+ }
+ lastDir = currentDir;
+ }
+ // all turns checked
+
+ lastCount = stepCount;
+ moduleX = walkAnim[stepCount-1].x;
+ moduleY = walkAnim[stepCount-1].y;
+ module16X = moduleX << 16;
+ module16Y = moduleY << 16;
+ }
+ }
+ }
+ while (modularPath[p].dir < NO_DIRECTIONS);
+
+
+
+ if (lastRealDir == 99)
+ {
+ error("SlidyWalkAnimatorlast direction error\n");
+ }
+ //****************************************************************************
+ // SLIDY
+ // TURNS TO END THE WALK ?
+ //****************************************************************************
+
+ // We've done the walk now put in any turns at the end
+
+
+ if (targetDir == NO_DIRECTIONS) // stand in the last direction
+ {
+ module = standFrames + lastRealDir;
+ targetDir = lastRealDir;
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = lastRealDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+ if (targetDir == 9)
+ {
+ if (stepCount == 0)
+ {
+ module = framesPerChar + lastRealDir;
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = lastRealDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+ }
+ else if (targetDir != lastRealDir) // rotate to targetDir
+ {
+ // rotate to target direction
+ turnDir = targetDir - lastRealDir;
+ if ( turnDir < 0)
+ turnDir += NO_DIRECTIONS;
+
+ if (turnDir > 4)
+ turnDir = -1;
+ else if (turnDir > 0)
+ turnDir = 1;
+
+ // rotate to target direction
+ // for george and nico put in a head turn at the start
+ if ((megaId == GEORGE) || (megaId == NICO))
+ {
+ if ( turnDir < 0) // new frames for turn frames 29oct95jps
+ {
+ module = turnFramesLeft + lastDir;
+ }
+ else
+ {
+ module = turnFramesRight + lastDir;
+ }
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = lastRealDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+
+ // rotate if we need to
+ while (lastRealDir != targetDir)
+ {
+ lastRealDir += turnDir;
+ if ( turnDir < 0) // new frames for turn frames 29oct95jps
+ {
+ if ( lastRealDir < 0)
+ lastRealDir += NO_DIRECTIONS;
+ module = turnFramesLeft + lastRealDir;
+ }
+ else
+ {
+ if ( lastRealDir > 7)
+ lastRealDir -= NO_DIRECTIONS;
+ module = turnFramesRight + lastRealDir;
+ }
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = lastRealDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+ module = standFrames + lastRealDir;
+ walkAnim[stepCount-1].frame = module;
+ }
+ else // just stand at the end
+ {
+ module = standFrames + lastRealDir;
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = lastRealDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+
+ walkAnim[stepCount].frame = 512;
+ stepCount += 1;
+ walkAnim[stepCount].frame = 512;
+ stepCount += 1;
+ walkAnim[stepCount].frame = 512;
+// Tdebug("RouteFinder RouteSize is %d", stepCount);
+ return;
+}
+
+// ****************************************************************************
+// * THE SOLID PATH ROUTINES
+// ****************************************************************************
+
+int32 Router::SolidPath()
+{
+/****************************************************************************
+ * SolidPath creates a path based on whole steps with no sliding to get
+ * as near as possible to the target without any sliding this routine is
+ * currently unused, but is intended for use when just clicking about.
+ *
+ * produce a module list from the line data
+ *
+ ****************************************************************************/
+ int32 smooth;
+ int32 solid;
+ int32 scale;
+ int32 stepX;
+ int32 stepY;
+ int32 deltaX;
+ int32 deltaY;
+
+ // strip out the short sections
+ solid = 1;
+ smooth = 1;
+ modularPath[0].x = smoothPath[0].x;
+ modularPath[0].y = smoothPath[0].y;
+ modularPath[0].dir = smoothPath[0].dir;
+ modularPath[0].num = 0;
+
+ do
+ {
+ scale = scaleA * smoothPath[smooth].y + scaleB;
+ deltaX = smoothPath[smooth].x - modularPath[solid-1].x;
+ deltaY = smoothPath[smooth].y - modularPath[solid-1].y;
+ stepX = modX[smoothPath[smooth].dir];
+ stepY = modY[smoothPath[smooth].dir];
+ stepX = stepX * scale;
+ stepY = stepY * scale;
+ stepX = stepX >> 16;
+ stepY = stepY >> 16;
+ if ((ABS(deltaX)>=ABS(stepX)) && (ABS(deltaY)>=ABS(stepY)))
+ {
+ modularPath[solid].x = smoothPath[smooth].x;
+ modularPath[solid].y = smoothPath[smooth].y;
+ modularPath[solid].dir = smoothPath[smooth].dir;
+ modularPath[solid].num = 1;
+ solid += 1;
+ }
+ smooth += 1;
+ }
+ while (smoothPath[smooth].num < ROUTE_END_FLAG);
+ // in case the last bit had no steps
+ if (solid == 1) //there were no paths so put in a dummy end
+ {
+ solid = 2;
+ modularPath[1].dir = smoothPath[0].dir;
+ modularPath[1].num = 0;
+ }
+ modularPath[solid-1].x = smoothPath[smooth-1].x;
+ modularPath[solid-1].y = smoothPath[smooth-1].y;
+ // set up the end of the walk
+ modularPath[solid].x = smoothPath[smooth-1].x;
+ modularPath[solid].y = smoothPath[smooth-1].y;
+ modularPath[solid].dir = 9;
+ modularPath[solid].num = ROUTE_END_FLAG;
+ return 1;
+
+}
+
+int32 Router::SolidWalkAnimator(WalkData *walkAnim)
+{
+/****************************************************************************
+ * SolidWalk creates an animation based on whole steps with no sliding to get
+ * as near as possible to the target without any sliding this routine is
+ * is intended for use when just clicking about.
+ *
+ * produce a module list from the line data
+ *
+ * returns 0 if solid route not found
+ ****************************************************************************/
+ int32 p;
+ int32 i;
+ int32 left;
+ int32 lastDir;
+ int32 currentDir;
+ int32 turnDir;
+ int32 scale;
+ int32 step;
+ int32 module;
+ int32 moduleX;
+ int32 moduleY;
+ int32 module16X;
+ int32 module16Y;
+ int32 errorX;
+ int32 errorY;
+ int32 moduleEnd;
+ int32 slowStart;
+ int32 stepCount;
+ int32 lastCount;
+ int32 frame;
+
+ // start at the begining for a change
+ lastDir = modularPath[0].dir;
+ p = 1;
+ currentDir = modularPath[1].dir;
+ module = framesPerChar + lastDir;
+ moduleX = startX;
+ moduleY = startY;
+ module16X = moduleX << 16;
+ module16Y = moduleY << 16;
+ slowStart = 0;
+ stepCount = 0;
+
+ //****************************************************************************
+ // SOLID
+ // START THE WALK WITH THE FIRST STANDFRAME THIS MAY CAUSE A DELAY
+ // BUT IT STOPS THE PLAYER MOVING FOR COLLISIONS ARE DETECTED
+ //****************************************************************************
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = lastDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+
+ //****************************************************************************
+ // SOLID
+ // TURN TO START THE WALK
+ //****************************************************************************
+ // rotate if we need to
+ if (lastDir != currentDir)
+ {
+ // get the direction to turn
+ turnDir = currentDir - lastDir;
+ if ( turnDir < 0)
+ turnDir += NO_DIRECTIONS;
+
+ if (turnDir > 4)
+ turnDir = -1;
+ else if (turnDir > 0)
+ turnDir = 1;
+
+ // rotate to new walk direction
+ // for george and nico put in a head turn at the start
+ if ((megaId == GEORGE) || (megaId == NICO))
+ {
+ if ( turnDir < 0) // new frames for turn frames 29oct95jps
+ {
+ module = turnFramesLeft + lastDir;
+ }
+ else
+ {
+ module = turnFramesRight + lastDir;
+ }
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = lastDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+
+ // rotate till were facing new dir then go back 45 degrees
+ while (lastDir != currentDir)
+ {
+ lastDir += turnDir;
+ if ( turnDir < 0) // new frames for turn frames 29oct95jps
+ {
+ if ( lastDir < 0)
+ lastDir += NO_DIRECTIONS;
+ module = turnFramesLeft + lastDir;
+ }
+ else
+ {
+ if ( lastDir > 7)
+ lastDir -= NO_DIRECTIONS;
+ module = turnFramesRight + lastDir;
+ }
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = lastDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+ // the back 45 degrees bit
+ stepCount -= 1;// step back one because new head turn for george takes us past the new dir
+ }
+
+ //****************************************************************************
+ // SOLID
+ // THE SLOW IN
+ //****************************************************************************
+
+ // do start frames if its george and left or right
+ if (megaId == GEORGE)
+ {
+ if (modularPath[1].num > 0)
+ {
+ if (currentDir == 2) // only for george
+ {
+ slowStart = 1;
+ walkAnim[stepCount].frame = 296;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = currentDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ walkAnim[stepCount].frame = 297;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = currentDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ walkAnim[stepCount].frame = 298;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = currentDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+ else if (currentDir == 6) // only for george
+ {
+ slowStart = 1;
+ walkAnim[stepCount].frame = 299;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = currentDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ walkAnim[stepCount].frame = 300;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = currentDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ walkAnim[stepCount].frame = 301;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = currentDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+ }
+ }
+ //****************************************************************************
+ // SOLID
+ // THE WALK
+ //****************************************************************************
+
+ if (currentDir > 4)
+ left = framesPerStep;
+ else
+ left = 0;
+
+ lastCount = stepCount;
+ lastDir = 99;// this ensures that we don't put in turn frames for the start
+ currentDir = 99;// this ensures that we don't put in turn frames for the start
+
+ do
+ {
+ while (modularPath[p].num > 0)
+ {
+ currentDir = modularPath[p].dir;
+ if (currentDir< NO_DIRECTIONS)
+ {
+
+ module = currentDir * framesPerStep * 2 + left;
+ if (left == 0)
+ left = framesPerStep;
+ else
+ left = 0;
+ moduleEnd = module + framesPerStep;
+ step = 0;
+ scale = (scaleA * moduleY + scaleB);
+ do
+ {
+ module16X += _dx[module]*scale;
+ module16Y += _dy[module]*scale;
+ moduleX = module16X >> 16;
+ moduleY = module16Y >> 16;
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = step;
+ walkAnim[stepCount].dir = currentDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ module += 1;
+ step += 1;
+ }
+ while ( module < moduleEnd) ;
+ errorX = modularPath[p].x - moduleX;
+ errorX = errorX * modX[modularPath[p].dir];
+ errorY = modularPath[p].y - moduleY;
+ errorY = errorY * modY[modularPath[p].dir];
+ if ((errorX < 0) || (errorY < 0))
+ {
+ modularPath[p].num = 0;
+ stepCount -= framesPerStep;
+ if (left == 0)
+ left = framesPerStep;
+ else
+ left = 0;
+ // Okay this is the end of a section
+ moduleX = walkAnim[stepCount-1].x;
+ moduleY = walkAnim[stepCount-1].y;
+ module16X = moduleX << 16;
+ module16Y = moduleY << 16;
+ modularPath[p].x =moduleX;
+ modularPath[p].y =moduleY;
+ // Now is the time to put in the turn frames for the last turn
+ if ((stepCount - lastCount) < framesPerStep)// no step taken
+ {
+ currentDir = 99;// this ensures that we don't put in turn frames for this walk or the next
+ if (slowStart == 1)// clean up if a slow in but no walk
+ {
+ stepCount -= 3;
+ lastCount -= 3;
+ slowStart = 0;
+ }
+ }
+ // check each turn condition in turn
+ if (((lastDir != 99) && (currentDir != 99)) && (megaId == GEORGE)) // only for george
+ {
+ lastDir = currentDir - lastDir;//1 and -7 going right -1 and 7 going left
+ if (((lastDir == -1) || (lastDir == 7)) || ((lastDir == -2) || (lastDir == 6)))
+ {
+ // turn at the end of the last walk
+ frame = lastCount - framesPerStep;
+ do
+ {
+ walkAnim[frame].frame += 104;//turning left
+ frame += 1;
+ }
+ while (frame < lastCount );
+ }
+ if (((lastDir == 1) || (lastDir == -7)) || ((lastDir == 2) || (lastDir == -6)))
+ {
+ // turn at the end of the current walk
+ frame = lastCount - framesPerStep;
+ do
+ {
+ walkAnim[frame].frame += 200; //was 60 now 116
+ frame += 1;
+ }
+ while (frame < lastCount );
+ }
+ }
+ // all turns checked
+ lastCount = stepCount;
+ }
+ }
+ }
+ p = p + 1;
+ lastDir = currentDir;
+ slowStart = 0; //can only be valid first time round
+ }
+ while (modularPath[p].dir < NO_DIRECTIONS);
+
+ //****************************************************************************
+ // SOLID
+ // THE SLOW OUT
+ //****************************************************************************
+
+ if ((currentDir == 2) && (megaId == GEORGE)) // only for george
+ {
+ // place stop frames here
+ // slowdown at the end of the last walk
+ frame = lastCount - framesPerStep;
+ if (walkAnim[frame].frame == 24)
+ {
+ do
+ {
+ walkAnim[frame].frame += 278;//stopping right
+ frame += 1;
+ }
+ while (frame < lastCount );
+ walkAnim[stepCount].frame = 308;
+ walkAnim[stepCount].step = 7;
+ walkAnim[stepCount].dir = currentDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+ else if (walkAnim[frame].frame == 30)
+ {
+ do
+ {
+ walkAnim[frame].frame += 279;//stopping right
+ frame += 1;
+ }
+ while (frame < lastCount );
+ walkAnim[stepCount].frame = 315;
+ walkAnim[stepCount].step = 7;
+ walkAnim[stepCount].dir = currentDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+ }
+ else if ((currentDir == 6) && (megaId == GEORGE)) // only for george
+ {
+ // place stop frames here
+ // slowdown at the end of the last walk
+ frame = lastCount - framesPerStep;
+ if (walkAnim[frame].frame == 72)
+ {
+ do
+ {
+ walkAnim[frame].frame += 244;//stopping left
+ frame += 1;
+ }
+ while (frame < lastCount );
+ walkAnim[stepCount].frame = 322;
+ walkAnim[stepCount].step = 7;
+ walkAnim[stepCount].dir = currentDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+ else if (walkAnim[frame].frame == 78)
+ {
+ do
+ {
+ walkAnim[frame].frame += 245;//stopping left
+ frame += 1;
+ }
+ while (frame < lastCount );
+ walkAnim[stepCount].frame = 329;
+ walkAnim[stepCount].step = 7;
+ walkAnim[stepCount].dir = currentDir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+ }
+ }
+ module = framesPerChar + modularPath[p-1].dir;
+ walkAnim[stepCount].frame = module;
+ walkAnim[stepCount].step = 0;
+ walkAnim[stepCount].dir = modularPath[p-1].dir;
+ walkAnim[stepCount].x = moduleX;
+ walkAnim[stepCount].y = moduleY;
+ stepCount += 1;
+
+ walkAnim[stepCount].frame = 512;
+ stepCount += 1;
+ walkAnim[stepCount].frame = 512;
+ stepCount += 1;
+ walkAnim[stepCount].frame = 512;
+
+ //****************************************************************************
+ // SOLID
+ // NO END TURNS
+ //****************************************************************************
+
+// Tdebug("RouteFinder RouteSize is %d", stepCount);
+// now check the route
+ i = 0;
+ do
+ {
+ if (!Check(modularPath[i].x, modularPath[i].y, modularPath[i+1].x, modularPath[i+1].y))
+ p=0;
+#ifdef PLOT_PATHS
+ RouteLine(modularPath[i].x, modularPath[i].y, modularPath[i+1].x, modularPath[i+1].y, 227);
+#endif
+ i += 1;
+ }
+ while (i<p-1);
+ if (p != 0)
+ {
+ targetDir = modularPath[p-1].dir;
+ }
+ if (p != 0)
+ {
+ if (CheckTarget(moduleX,moduleY) == 3)// new target on a line
+ {
+ p = 0;
+ //Tdebug("Solid walk target was on a line %d %d", moduleX, moduleY);
+ }
+ }
+
+ return p;
+}
+
+// ****************************************************************************
+// * THE SCAN ROUTINES
+// ****************************************************************************
+
+int32 Router::Scan(int32 level)
+/******************************************************************************
+ * Called successively from RouteFinder until no more changes take place in the
+ * grid array ie he best path has been found
+ *
+ * Scans through every point in the node array and checks if there is a route
+ * between each point and if this route gives a new route.
+ *
+ * This routine could probably halve its processing time if it doubled up on
+ * the checks after each route check
+ *****************************************************************************/
+{
+ int32 i;
+ int32 k;
+ int32 x1;
+ int32 y1;
+ int32 x2;
+ int32 y2;
+ int32 distance;
+ int32 changed = 0;
+ // For all the nodes that have new values and a distance less than enddist
+ // ie dont check for new routes from a point we checked before or from a point
+ // that is already further away than the best route so far.
+ i = 0;
+ do
+ {
+ if ((node[i].dist < node[nnodes].dist) && (node[i].level == level))
+ {
+ x1 = node[i].x;
+ y1 = node[i].y;
+ k=nnodes;
+ do
+ {
+ if (node[k].dist > node[i].dist)
+ {
+ x2 = node[k].x;
+ y2 = node[k].y;
+
+ if (ABS(x2-x1)>(4.5*ABS(y2-y1)))
+ {
+ distance = (8*ABS(x2-x1)+18*ABS(y2-y1))/(54*8)+1;
+ }
+ else
+ {
+ distance = (6*ABS(x2-x1)+36*ABS(y2-y1))/(36*14)+1;
+ }
+
+ if ((distance + node[i].dist < node[nnodes].dist) && (distance + node[i].dist < node[k].dist))
+ {
+ if (NewCheck(0, x1,y1,x2,y2))
+ {
+ node[k].level = level + 1;
+ node[k].dist = distance + node[i].dist;
+ node[k].prev = i;
+ changed = 1;
+ }
+ }
+ }
+ k-=1;
+ }
+ while (k > 0);
+ }
+ i=i+1;
+ }
+ while (i < nnodes);
+ return changed;
+}
+
+
+int32 Router::NewCheck(int32 status, int32 x1 , int32 y1 , int32 x2 ,int32 y2)
+/******************************************************************************
+ * NewCheck routine checks if the route between two points can be achieved
+ * without crossing any of the bars in the Bars array.
+ *
+ * NewCheck differs from check in that that 4 route options are considered
+ * corresponding to actual walked routes.
+ *
+ * Note distance doesnt take account of shrinking ???
+ *
+ * Note Bars array must be properly calculated ie min max dx dy co
+ *****************************************************************************/
+{
+ int32 dx;
+ int32 dy;
+ int32 dlx;
+ int32 dly;
+ int32 dirX;
+ int32 dirY;
+ int32 step1;
+ int32 step2;
+ int32 step3;
+ int32 steps;
+ int32 options;
+
+ steps = 0;
+ options = 0;
+ dx = x2 - x1;
+ dy = y2 - y1;
+ dirX = 1;
+ dirY = 1;
+ if (dx < 0)
+ {
+ dx = -dx;
+ dirX = -1;
+ }
+
+ if (dy < 0)
+ {
+ dy = -dy;
+ dirY = -1;
+ }
+
+ //make the route options
+ if ((diagonaly * dx) > (diagonalx * dy)) // dir = 1,2 or 2,3 or 5,6 or 6,7
+ {
+ dly = dy;
+ dlx = (dy*diagonalx)/diagonaly;
+ dx = dx - dlx;
+ dlx = dlx * dirX;
+ dly = dly * dirY;
+ dx = dx * dirX;
+ dy = 0;
+
+ //options are
+ //square, diagonal a code 1 route
+ step1 = Check(x1, y1, x1+dx, y1);
+ if (step1 != 0)
+ {
+ step2 = Check(x1+dx, y1, x2, y2);
+ if (step2 != 0)
+ {
+ steps = step1 + step2; // yes
+ options = options + 2;
+#ifdef PLOT_PATHS
+ if (status == 1)
+ RouteLine(x1, y1, x1+dx, y1, 231);
+#endif
+#ifdef PLOT_PATHS
+ if (status == 1)
+ RouteLine(x1+dx, y1, x2, y2, 231);
+#endif
+ }
+ }
+ //diagonal, square a code 2 route
+ if ((steps == 0) || (status == 1))
+ {
+ step1 = Check(x1, y1, x1+dlx,y1+dly);
+ if (step1 != 0)
+ {
+ step2 = Check(x1+dlx, y2, x2, y2);
+ if (step2 != 0)
+ {
+ steps = step1 + step2; // yes
+ options = options + 4;
+#ifdef PLOT_PATHS
+ if (status == 1)
+ RouteLine(x1, y1, x1+dlx,y1+dly, 231);
+#endif
+#ifdef PLOT_PATHS
+ if (status == 1)
+ RouteLine(x1+dlx, y2, x2, y2, 231);
+#endif
+ }
+ }
+ }
+ //halfsquare, diagonal, halfsquare a code 0 route
+ if ((steps == 0) || (status == 1))
+ {
+ step1 = Check(x1, y1, x1+dx/2, y1);
+ if (step1 != 0)
+ {
+ step2 = Check(x1+dx/2, y1, x1+dx/2+dlx, y2);
+ if (step2 != 0)
+ {
+ step3 = Check(x1+dx/2+dlx, y2, x2, y2);
+ if (step3 != 0)
+ {
+ steps = step1 + step2 + step3; // yes
+ options = options + 1;
+#ifdef PLOT_PATHS
+ if (status == 1)
+ RouteLine(x1, y1, x1+dx/2, y1, 231);
+#endif
+#ifdef PLOT_PATHS
+ if (status == 1)
+ RouteLine(x1+dx/2, y1, x1+dx/2+dlx, y2, 231);
+#endif
+#ifdef PLOT_PATHS
+ if (status == 1)
+ RouteLine(x1+dx/2+dlx, y2, x2, y2, 231);
+#endif
+ }
+ }
+ }
+ }
+ //halfdiagonal, square, halfdiagonal a code 3 route
+ if ((steps == 0) || (status == 1))
+ {
+ step1 = Check(x1, y1, x1+dlx/2, y1+dly/2);
+ if (step1 != 0)
+ {
+ step2 = Check(x1+dlx/2, y1+dly/2, x1+dx+dlx/2, y1+dly/2);
+ if (step2 != 0)
+ {
+ step3 = Check(x1+dx+dlx/2, y1+dly/2, x2, y2);
+ if (step3 != 0)
+ {
+ steps = step1 + step2 + step3; // yes
+#ifdef PLOT_PATHS
+ if (status == 1)
+ RouteLine(x1, y1, x1+dlx/2, y1+dly/2, 231);
+#endif
+#ifdef PLOT_PATHS
+ if (status == 1)
+ RouteLine(x1+dlx/2, y1+dly/2, x1+dx+dlx/2, y1+dly/2, 231);
+#endif
+#ifdef PLOT_PATHS
+ if (status == 1)
+ RouteLine(x1+dx+dlx/2, y1+dly/2, x2, y2, 231);
+#endif
+ options = options + 8;
+ }
+ }
+ }
+ }
+ }
+ else // dir = 7,0 or 0,1 or 3,4 or 4,5
+ {
+ dlx = dx;
+ dly = (dx*diagonaly)/diagonalx;
+ dy = dy - dly;
+ dlx = dlx * dirX;
+ dly = dly * dirY;
+ dy = dy * dirY;
+ dx = 0;
+
+ //options are
+ //square, diagonal a code 1 route
+ step1 = Check(x1 ,y1 ,x1 ,y1+dy );
+ if (step1 != 0)
+ {
+ step2 = Check(x1 ,y1+dy ,x2,y2);
+ if (step2 != 0)
+ {
+ steps = step1 + step2; // yes
+#ifdef PLOT_PATHS
+ if (status == 1)
+ RouteLine(x1 ,y1 ,x1 ,y1+dy, 231);
+#endif
+#ifdef PLOT_PATHS
+ if (status == 1)
+ RouteLine(x1 ,y1+dy ,x2, y2, 231);
+#endif
+ options = options + 2;
+ }
+ }
+ //diagonal, square a code 2 route
+ if ((steps == 0) || (status == 1))
+ {
+ step1 = Check(x1, y1, x2, y1+dly);
+ if (step1 != 0)
+ {
+ step2 = Check(x2, y1+dly, x2, y2);
+ if (step2 != 0)
+ {
+ steps = step1 + step2; // yes
+#ifdef PLOT_PATHS
+ if (status == 1)
+ RouteLine(x1, y1, x2, y1+dly, 231);
+#endif
+#ifdef PLOT_PATHS
+ if (status == 1)
+ RouteLine(x2, y1+dly, x2, y2, 231);
+#endif
+ options = options + 4;
+ }
+ }
+ }
+ //halfsquare, diagonal, halfsquare a code 0 route
+ if ((steps == 0) || (status == 1))
+ {
+ step1 = Check(x1, y1, x1, y1+dy/2);
+ if (step1 != 0)
+ {
+ step2 = Check(x1, y1+dy/2, x2, y1+dy/2+dly);
+ if (step2 != 0)
+ {
+ step3 = Check(x2, y1+dy/2+dly, x2, y2);
+ if (step3 != 0)
+ {
+ steps = step1 + step2 + step3; // yes
+#ifdef PLOT_PATHS
+ if (status == 1)
+ RouteLine(x1, y1, x1, y1+dy/2, 231);
+#endif
+#ifdef PLOT_PATHS
+ if (status == 1)
+ RouteLine(x1, y1+dy/2, x2, y1+dy/2+dly, 231);
+#endif
+#ifdef PLOT_PATHS
+ if (status == 1)
+ RouteLine(x2, y1+dy/2+dly, x2, y2, 231);
+#endif
+ options = options + 1;
+ }
+ }
+ }
+ }
+ //halfdiagonal, square, halfdiagonal a code 3 route
+ if ((steps == 0) || (status == 1))
+ {
+ step1 = Check(x1, y1, x1+dlx/2, y1+dly/2);
+ if (step1 != 0)
+ {
+ step2 = Check(x1+dlx/2, y1+dly/2, x1+dlx/2, y1+dy+dly/2);
+ if (step2 != 0)
+ {
+ step3 = Check(x1+dlx/2, y1+dy+dly/2, x2, y2);
+ if (step3 != 0)
+ {
+ steps = step1 + step2 + step3; // yes
+ options = options + 8;
+#ifdef PLOT_PATHS
+ if (status == 1)
+ RouteLine(x1, y1, x1+dlx/2, y1+dly/2, 231);
+#endif
+#ifdef PLOT_PATHS
+ if (status == 1)
+ RouteLine(x1+dlx/2, y1+dly/2, x1+dlx/2, y1+dy+dly/2, 231);
+#endif
+#ifdef PLOT_PATHS
+ if (status == 1)
+ RouteLine(x1+dlx/2, y1+dy+dly/2, x2, y2, 231);
+#endif
+ }
+ }
+ }
+ }
+ }
+ if (status == 0)
+ {
+ status = steps;
+ }
+ else
+ {
+ status = options;
+ }
+ return status;
+}
+
+// ****************************************************************************
+// * CHECK ROUTINES
+// ****************************************************************************
+
+int32 Router::Check(int32 x1 , int32 y1 , int32 x2 ,int32 y2)
+{
+//call the fastest line check for the given line
+//returns 1 if line didn't cross any bars
+ int32 steps;
+
+ if ((x1 == x2) && (y1 == y2))
+ {
+ steps = 1;
+ }
+ else if (x1 == x2)
+ {
+ steps = VertCheck(x1, y1, y2);
+ }
+ else if (y1 == y2)
+ {
+ steps = HorizCheck(x1, y1, x2);
+ }
+ else
+ {
+ steps = LineCheck(x1, y1, x2, y2);
+ }
+ return steps;
+
+}
+
+
+int32 Router::LineCheck(int32 x1 , int32 y1 , int32 x2 ,int32 y2)
+{
+ int32 dirx;
+ int32 diry;
+ int32 co;
+ int32 slope;
+ int32 i;
+ int32 xc;
+ int32 yc;
+ int32 xmin;
+ int32 ymin;
+ int32 xmax;
+ int32 ymax;
+ int32 linesCrossed = 1;
+
+
+ if (x1 > x2)
+ {
+ xmin = x2;
+ xmax = x1;
+ }
+ else
+ {
+ xmin = x1;
+ xmax = x2;
+ }
+ if (y1 > y2)
+ {
+ ymin = y2;
+ ymax = y1;
+ }
+ else
+ {
+ ymin = y1;
+ ymax = y2;
+ }
+ //line set to go one step in chosen direction
+ //so ignore if it hits anything
+ dirx = x2 - x1;
+ diry = y2 - y1;
+ co = (y1 *dirx)- (x1*diry); //new line equation
+
+ i = 0;
+ do
+ {
+ // this is the inner inner loop
+ if ((xmax >= bars[i].xmin) && ( xmin <= bars[i].xmax)) //skip if not on module
+ {
+ if ((ymax >= bars[i].ymin) && ( ymin <= bars[i].ymax)) //skip if not on module
+ {
+ // okay its a valid line calculate an intersept
+ // wow but all this arithmatic we must have loads of time
+ slope = (bars[i].dx * diry) - (bars[i].dy *dirx);// slope it he slope between the two lines
+ if (slope != 0)//assuming parallel lines don't cross
+ {
+ //calculate x intercept and check its on both lines
+ xc = ((bars[i].co * dirx) - (co * bars[i].dx)) / slope;
+
+ if ((xc >= xmin-1) && (xc <= xmax+1)) //skip if not on module
+ {
+ if ((xc >= bars[i].xmin-1) && (xc <= bars[i].xmax+1)) //skip if not on line
+ {
+
+ yc = ((bars[i].co * diry) - (co * bars[i].dy)) / slope;
+
+ if ((yc >= ymin-1) && (yc <= ymax+1)) //skip if not on module
+ {
+ if ((yc >= bars[i].ymin-1) && (yc <= bars[i].ymax+1)) //skip if not on line
+ {
+ linesCrossed = 0;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ i = i + 1;
+ }
+ while ((i < nbars) && linesCrossed);
+
+ return linesCrossed;
+}
+
+int32 Router::HorizCheck(int32 x1 , int32 y , int32 x2)
+{
+ int32 dy;
+ int32 i;
+ int32 xc;
+ int32 xmin;
+ int32 xmax;
+ int32 linesCrossed = 1;
+
+ if (x1 > x2)
+ {
+ xmin = x2;
+ xmax = x1;
+ }
+ else
+ {
+ xmin = x1;
+ xmax = x2;
+ }
+ //line set to go one step in chosen direction
+ //so ignore if it hits anything
+
+ i = 0;
+ do
+ {
+ // this is the inner inner loop
+ if ((xmax >= bars[i].xmin) && ( xmin <= bars[i].xmax)) //skip if not on module
+ {
+ if ((y >= bars[i].ymin) && ( y <= bars[i].ymax)) //skip if not on module
+ {
+ // okay its a valid line calculate an intersept
+ // wow but all this arithmatic we must have loads of time
+ if (bars[i].dy == 0)
+ {
+ linesCrossed = 0;
+ }
+ else
+ {
+ dy = y-bars[i].y1;
+ xc = bars[i].x1 + (bars[i].dx * dy)/bars[i].dy;
+ if ((xc >= xmin-1) && (xc <= xmax+1)) //skip if not on module
+ {
+ linesCrossed = 0;
+ }
+ }
+ }
+ }
+ i = i + 1;
+ }
+ while ((i < nbars) && linesCrossed);
+
+ return linesCrossed;
+}
+
+
+int32 Router::VertCheck(int32 x, int32 y1, int32 y2)
+{
+ int32 dx;
+ int32 i;
+ int32 yc;
+ int32 ymin;
+ int32 ymax;
+ int32 linesCrossed = 1;
+
+ if (y1 > y2)
+ {
+ ymin = y2;
+ ymax = y1;
+ }
+ else
+ {
+ ymin = y1;
+ ymax = y2;
+ }
+ //line set to go one step in chosen direction
+ //so ignore if it hits anything
+ i = 0;
+ do // this is the inner inner loop
+ {
+ if ((x >= bars[i].xmin) && ( x <= bars[i].xmax)) //overlapping
+ {
+ if ((ymax >= bars[i].ymin) && ( ymin <= bars[i].ymax)) //skip if not on module
+ {
+ // okay its a valid line calculate an intersept
+ // wow but all this arithmatic we must have loads of time
+ if (bars[i].dx == 0)//both lines vertical and overlap in x and y so they cross
+ {
+ linesCrossed = 0;
+ }
+ else
+ {
+ dx = x-bars[i].x1;
+ yc = bars[i].y1 + (bars[i].dy * dx)/bars[i].dx;
+ if ((yc >= ymin-1) && (yc <= ymax+1)) //the intersept overlaps
+ {
+ linesCrossed = 0;
+ }
+ }
+ }
+ }
+ i = i + 1;
+ }
+ while ((i < nbars) && linesCrossed);
+
+ return linesCrossed;
+}
+
+int32 Router::CheckTarget(int32 x , int32 y)
+{
+ int32 dx;
+ int32 dy;
+ int32 i;
+ int32 xc;
+ int32 yc;
+ int32 xmin;
+ int32 xmax;
+ int32 ymin;
+ int32 ymax;
+ int32 onLine = 0;
+
+ xmin = x - 1;
+ xmax = x + 1;
+ ymin = y - 1;
+ ymax = y + 1;
+
+ // check if point +- 1 is on the line
+ //so ignore if it hits anything
+
+ i = 0;
+ do
+ {
+
+ // this is the inner inner loop
+
+ if ((xmax >= bars[i].xmin) && ( xmin <= bars[i].xmax)) //overlapping line
+ {
+ if ((ymax >= bars[i].ymin) && ( ymin <= bars[i].ymax)) //overlapping line
+ {
+
+ // okay this line overlaps the target calculate an y intersept for x
+
+ if (bars[i].dx == 0)// vertical line so we know it overlaps y
+ {
+ yc = 0;
+ }
+ else
+ {
+ dx = x-bars[i].x1;
+ yc = bars[i].y1 + (bars[i].dy * dx)/bars[i].dx;
+ }
+
+ if ((yc >= ymin) && (yc <= ymax)) //overlapping point for y
+ {
+ onLine = 3;// target on a line so drop out
+ //Tdebug("RouteFail due to target on a line %d %d",x,y);
+ }
+ else
+ {
+ if (bars[i].dy == 0)// vertical line so we know it overlaps y
+ {
+ xc = 0;
+ }
+ else
+ {
+ dy = y-bars[i].y1;
+ xc = bars[i].x1 + (bars[i].dx * dy)/bars[i].dy;
+ }
+
+ if ((xc >= xmin) && (xc <= xmax)) //skip if not on module
+ {
+ onLine = 3;// target on a line so drop out
+ //Tdebug("RouteFail due to target on a line %d %d",x,y);
+ }
+ }
+ }
+ }
+ i = i + 1;
+ }
+ while ((i < nbars) && (onLine == 0));
+
+ return onLine;
+}
+
+// ****************************************************************************
+// * THE SETUP ROUTINES
+// ****************************************************************************
+
+int32 Router::LoadWalkResources(Object *megaObject, int32 x, int32 y, int32 dir)
+{
+ WalkGridHeader floorHeader;
+ int32 i;
+ int32 j;
+ uint8 *fPolygrid;
+ uint8 *fMegaWalkData;
+
+ int32 floorId;
+ int32 walkGridResourceId;
+ Object *floorObject;
+
+ int32 cnt;
+ uint32 cntu;
+
+ // load in floor grid for current mega
+
+ floorId = megaObject->o_place;
+
+ //floorObject = (object *) Lock_object(floorId);
+ floorObject = _objMan->fetchObject(floorId);
+ walkGridResourceId = floorObject->o_resource;
+ //Unlock_object(floorId);
+
+ //ResOpen(walkGridResourceId); // mouse wiggle
+ //fPolygrid = ResLock(walkGridResourceId); // mouse wiggle
+ fPolygrid = (uint8*)_resMan->openFetchRes(walkGridResourceId);
+
+
+ fPolygrid += sizeof(Header);
+ memcpy(&floorHeader,fPolygrid,sizeof(WalkGridHeader));
+ fPolygrid += sizeof(WalkGridHeader);
+ nbars = FROM_LE_32(floorHeader.numBars);
+
+ if (nbars >= O_GRID_SIZE)
+ {
+ #ifdef DEBUG //check for id > number in file,
+ error("RouteFinder Error too many bars %d", nbars);
+ #endif
+ nbars = 0;
+ }
+
+ nnodes = FROM_LE_32(floorHeader.numNodes)+1; //array starts at 0 begins at a start node has nnodes nodes and a target node
+
+ if (nnodes >= O_GRID_SIZE)
+ {
+ #ifdef DEBUG //check for id > number in file,
+ error("RouteFinder Error too many nodes %d", nnodes);
+ #endif
+ nnodes = 0;
+ }
+
+ /*memmove(&bars[0],fPolygrid,nbars*sizeof(BarData));
+ fPolygrid += nbars*sizeof(BarData);//move pointer to start of node data*/
+ for (cnt = 0; cnt < nbars; cnt++) {
+ bars[cnt].x1 = READ_LE_UINT16(fPolygrid); fPolygrid += 2;
+ bars[cnt].y1 = READ_LE_UINT16(fPolygrid); fPolygrid += 2;
+ bars[cnt].x2 = READ_LE_UINT16(fPolygrid); fPolygrid += 2;
+ bars[cnt].y2 = READ_LE_UINT16(fPolygrid); fPolygrid += 2;
+ bars[cnt].xmin = READ_LE_UINT16(fPolygrid); fPolygrid += 2;
+ bars[cnt].ymin = READ_LE_UINT16(fPolygrid); fPolygrid += 2;
+ bars[cnt].xmax = READ_LE_UINT16(fPolygrid); fPolygrid += 2;
+ bars[cnt].ymax = READ_LE_UINT16(fPolygrid); fPolygrid += 2;
+ bars[cnt].dx = READ_LE_UINT16(fPolygrid); fPolygrid += 2;
+ bars[cnt].dy = READ_LE_UINT16(fPolygrid); fPolygrid += 2;
+ bars[cnt].co = READ_LE_UINT32(fPolygrid); fPolygrid += 4;
+ }
+
+ /*j = 1;// leave node 0 for start node
+ do
+ {
+ memmove(&node[j].x,fPolygrid,2*sizeof(int16));
+ fPolygrid += 2*sizeof(int16);
+ j ++;
+ }
+ while (j < nnodes);//array starts at 0*/
+ for (cnt = 1; cnt < nnodes; cnt++) {
+ node[cnt].x = READ_LE_UINT16(fPolygrid); fPolygrid += 2;
+ node[cnt].y = READ_LE_UINT16(fPolygrid); fPolygrid += 2;
+ }
+
+ //ResUnlock(walkGridResourceId); // mouse wiggle
+ //ResClose(walkGridResourceId); // mouse wiggle
+ _resMan->resClose(walkGridResourceId);
+
+
+ // floor grid loaded
+ // if its george copy extra bars and nodes
+
+ if (megaId == GEORGE)
+ {
+ // copy any extra bars from extraBars array
+
+ //Zdebug("%d", nExtraBars);
+
+ memmove(&bars[nbars], &_extraBars[0], _numExtraBars*sizeof(BarData));
+ nbars += _numExtraBars;
+
+ // copy any extra nodes from extraNode array
+ j = 0;
+ while (j < _numExtraNodes)//array starts at 0
+ {
+ node[nnodes+j].x = _extraNodes[j].x ;
+ node[nnodes+j].y = _extraNodes[j].y ;
+ j++;
+ }
+
+ nnodes += _numExtraNodes;
+ }
+
+// copy the mega structure into the local variables for use in all subroutines
+
+ startX = megaObject->o_xcoord;
+ startY = megaObject->o_ycoord;
+ startDir = megaObject->o_dir;
+ targetX = x;
+ targetY= y;
+ targetDir = dir;
+
+ scaleA = megaObject->o_scale_a;
+ scaleB = megaObject->o_scale_b;
+
+ //ResOpen(megaObject->o_mega_resource); // mouse wiggle
+ //fMegaWalkData = ResLock(megaObject->o_mega_resource); // mouse wiggle
+ fMegaWalkData = (uint8*)_resMan->openFetchRes(megaObject->o_mega_resource);
+
+ nWalkFrames = fMegaWalkData[0];
+ nTurnFrames = fMegaWalkData[1];
+ fMegaWalkData += 2;
+
+ for (cnt = 0; cnt < NO_DIRECTIONS * (nWalkFrames + 1 + nTurnFrames); cnt++) {
+ _dx[cnt] = (int32)READ_LE_UINT32(fMegaWalkData);
+ fMegaWalkData += 4;
+ }
+ for (cnt = 0; cnt < NO_DIRECTIONS * (nWalkFrames + 1 + nTurnFrames); cnt++) {
+ _dy[cnt] = (int32)READ_LE_UINT32(fMegaWalkData);
+ fMegaWalkData += 4;
+ }
+ /*memmove(&_dx[0],fMegaWalkData,NO_DIRECTIONS*(nWalkFrames+1+nTurnFrames)*sizeof(int32));
+ fMegaWalkData += NO_DIRECTIONS*(nWalkFrames+1+nTurnFrames)*sizeof(int32);
+ memmove(&_dy[0],fMegaWalkData,NO_DIRECTIONS*(nWalkFrames+1+nTurnFrames)*sizeof(int32));
+ fMegaWalkData += NO_DIRECTIONS*(nWalkFrames+1+nTurnFrames)*sizeof(int32);*/
+
+ for (cntu = 0; cntu < NO_DIRECTIONS; cntu++) {
+ modX[cntu] = (int32)READ_LE_UINT32(fMegaWalkData);
+ fMegaWalkData += 4;
+ }
+ for (cntu = 0; cntu < NO_DIRECTIONS; cntu++) {
+ modY[cntu] = (int32)READ_LE_UINT32(fMegaWalkData);
+ fMegaWalkData += 4;
+ }
+ /*memmove(&modX[0],fMegaWalkData,NO_DIRECTIONS*sizeof(int32));
+ fMegaWalkData += NO_DIRECTIONS*sizeof(int32);
+ memmove(&modY[0],fMegaWalkData,NO_DIRECTIONS*sizeof(int32));
+ fMegaWalkData += NO_DIRECTIONS*sizeof(int32);*/
+
+ //ResUnlock(megaObject->o_mega_resource); // mouse wiggle
+ //ResClose(megaObject->o_mega_resource); // mouse wiggle
+ _resMan->resClose(megaObject->o_mega_resource);
+
+ diagonalx = modX[3] ;//36
+ diagonaly = modY[3] ;//8
+
+// mega data ready
+
+// finish setting grid by putting mega node at begining
+// and target node at end and reset current values
+ node[0].x = startX;
+ node[0].y = startY;
+ node[0].level = 1;
+ node[0].prev = 0;
+ node[0].dist = 0;
+ i=1;
+ do
+ {
+ node[i].level = 0;
+ node[i].prev = 0;
+ node[i].dist = 9999;
+ i=i+1;
+ }
+ while (i < nnodes);
+ node[nnodes].x = targetX;
+ node[nnodes].y = targetY;
+ node[nnodes].level = 0;
+ node[nnodes].prev = 0;
+ node[nnodes].dist = 9999;
+
+ return 1;
+}
+
+// ****************************************************************************
+// * THE ROUTE EXTRACTOR
+// ****************************************************************************
+
+void Router::ExtractRoute()
+/****************************************************************************
+ * ExtractRoute gets route from the node data after a full scan, route is
+ * written with just the basic way points and direction options for heading
+ * to the next point.
+ ****************************************************************************/
+{
+ int32 prev;
+ int32 prevx;
+ int32 prevy;
+ int32 last;
+ int32 point;
+ int32 p;
+ int32 dirx;
+ int32 diry;
+ int32 dir;
+ int32 dx;
+ int32 dy;
+
+
+ // extract the route from the node data
+ prev = nnodes;
+ last = prev;
+ point = O_ROUTE_SIZE - 1;
+ route[point].x = node[last].x;
+ route[point].y = node[last].y;
+ do
+ {
+ point = point - 1;
+ prev = node[last].prev;
+ prevx = node[prev].x;
+ prevy = node[prev].y;
+ route[point].x = prevx;
+ route[point].y = prevy;
+ last = prev;
+ }
+ while (prev > 0);
+
+ // now shuffle route down in the buffer
+ routeLength = 0;
+ do
+ {
+ route[routeLength].x = route[point].x;
+ route[routeLength].y = route[point].y;
+ point = point + 1;
+ routeLength = routeLength + 1;
+ }
+ while (point < O_ROUTE_SIZE);
+ routeLength = routeLength - 1;
+
+ // okay the route exists as a series point now put in some directions
+ p = 0;
+ do
+ {
+#ifdef PLOT_PATHS
+ BresenhamLine(route[p+1].x-128,route[p+1].y-128, route[p].x-128,route[p].y-128, (uint8*)screen_ad, true_pixel_size_x, pixel_size_y, ROUTE_END_FLAG);
+#endif
+ dx = route[p+1].x - route[p].x;
+ dy = route[p+1].y - route[p].y;
+ dirx = 1;
+ diry = 1;
+ if (dx < 0)
+ {
+ dx = -dx;
+ dirx = -1;
+ }
+ if (dy < 0)
+ {
+ dy = -dy;
+ diry = -1;
+ }
+
+ if ((diagonaly * dx) > (diagonalx * dy)) // dir = 1,2 or 2,3 or 5,6 or 6,7
+ {
+ dir = 4 - 2 * dirx; // 2 or 6
+ route[p].dirS = dir;
+ dir = dir + diry * dirx; // 1,3,5 or 7
+ route[p].dirD = dir;
+ }
+ else // dir = 7,0 or 0,1 or 3,4 or 4,5
+ {
+ dir = 2 + 2 * diry; // 0 or 4
+ route[p].dirS = dir;
+ dir = 4 - 2 * dirx; // 2 or 6
+ dir = dir + diry * dirx; // 1,3,5 or 7
+ route[p].dirD = dir;
+ }
+ p = p + 1;
+ }
+ while (p < (routeLength));
+ // set the last dir to continue previous route unless specified
+ if (targetDir == NO_DIRECTIONS)
+ {
+ route[p].dirS = route[p-1].dirS;
+ route[p].dirD = route[p-1].dirD;
+ }
+ else
+ {
+ route[p].dirS = targetDir;
+ route[p].dirD = targetDir;
+ }
+ return;
+}
+
+#define screen_ad NULL
+#define pixel_size_y 1
+#define true_pixel_size_x 1
+void Router::RouteLine(int32 x1,int32 y1,int32 x2,int32 y2 ,int32 colour)
+{
+ BresenhamLine(x1-128, y1-128, x2-128, y2-128, (uint8*)screen_ad, true_pixel_size_x, pixel_size_y, colour);
+ return;
+}
+
+void Router::BresenhamLine(int32 x1,int32 y1,int32 x2,int32 y2, uint8 *screen, int32 width, int32 height, int32 colour) {
+
+}
+
+#define DIAGONALX 36
+#define DIAGONALY 8
+int whatTarget(int32 startX, int32 startY, int32 destX, int32 destY) {
+ int tar_dir;
+//setting up
+ int deltaX = destX-startX;
+ int deltaY = destY-startY;
+ int signX = (deltaX > 0);
+ int signY = (deltaY > 0);
+ int slope;
+
+ if ( (ABS(deltaY) * DIAGONALX ) < (ABS(deltaX) * DIAGONALY / 2))
+ slope = 0;// its flat
+ else if ( (ABS(deltaY) * DIAGONALX / 2) > (ABS(deltaX) * DIAGONALY ) )
+ slope = 2;// its vertical
+ else
+ slope = 1;// its diagonal
+
+ if (slope == 0) { //flat
+ if (signX == 1) // going right
+ tar_dir = 2;
+ else
+ tar_dir = 6;
+ } else if (slope == 2) { //vertical
+ if (signY == 1) // going down
+ tar_dir = 4;
+ else
+ tar_dir = 0;
+ } else if (signX == 1) { //right diagonal
+ if (signY == 1) // going down
+ tar_dir = 3;
+ else
+ tar_dir = 1;
+ } else { //left diagonal
+ if (signY == 1) // going down
+ tar_dir = 5;
+ else
+ tar_dir = 7;
+ }
+ return tar_dir;
+}
+
+void Router::resetExtraData(void) {
+ _numExtraBars = _numExtraNodes = 0;
+}
+
+void Router::setPlayerTarget(int32 x, int32 y, int32 dir, int32 stance) {
+ _playerTargetX = x;
+ _playerTargetY = y;
+ _playerTargetDir = dir;
+ _playerTargetStance = stance;
+}
+
+} // End of namespace Sword1
diff --git a/engines/sword1/router.h b/engines/sword1/router.h
new file mode 100644
index 0000000000..e7c835f6d2
--- /dev/null
+++ b/engines/sword1/router.h
@@ -0,0 +1,180 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) Revolution Software Ltd.
+ *
+ * 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 BSROUTER_H
+#define BSROUTER_H
+
+#include "common/scummsys.h"
+#include "sword1/object.h"
+
+namespace Sword1 {
+
+#define EXTRA_GRID_SIZE 20
+#define O_GRID_SIZE 200
+
+#if !defined(__GNUC__)
+ #pragma START_PACK_STRUCTS
+#endif
+
+struct BarData {
+ int16 x1;
+ int16 y1;
+ int16 x2;
+ int16 y2;
+ int16 xmin;
+ int16 ymin;
+ int16 xmax;
+ int16 ymax;
+ int16 dx; // x2 - x1
+ int16 dy; // y2 - y1
+ int32 co; // co = (y1 *dx)- (x1*dy) from an equation for a line y*dx = x*dy + co
+} GCC_PACK;
+
+struct NodeData {
+ int16 x;
+ int16 y;
+ int16 level;
+ int16 prev;
+ int16 dist;
+} GCC_PACK;
+
+#if !defined(__GNUC__)
+ #pragma END_PACK_STRUCTS
+#endif
+
+struct FloorData {
+ int32 nbars;
+ BarData *bars;
+ int32 nnodes;
+ NodeData *node;
+};
+
+struct RouteData {
+ int32 x;
+ int32 y;
+ int32 dirS;
+ int32 dirD;
+};
+
+struct PathData {
+ int32 x;
+ int32 y;
+ int32 dir;
+ int32 num;
+};
+
+#define ROUTE_END_FLAG 255
+#define NO_DIRECTIONS 8
+#define MAX_FRAMES_PER_CYCLE 16
+#define MAX_FRAMES_PER_CHAR (MAX_FRAMES_PER_CYCLE * NO_DIRECTIONS)
+#define O_ROUTE_SIZE 50
+
+class ObjectMan;
+class ResMan;
+class Screen;
+
+extern int whatTarget(int32 startX, int32 startY, int32 destX, int32 destY);
+
+class Router {
+public:
+ Router(ObjectMan *pObjMan, ResMan *pResMan);
+ int32 routeFinder(int32 id, Object *mega, int32 x, int32 y, int32 dir);
+ void setPlayerTarget(int32 x, int32 y, int32 dir, int32 stance);
+ void resetExtraData(void);
+
+ // these should be private but are read by Screen for debugging:
+ BarData bars[O_GRID_SIZE+EXTRA_GRID_SIZE];
+ NodeData node[O_GRID_SIZE+EXTRA_GRID_SIZE];
+ int32 nbars, nnodes;
+private:
+ // when the player collides with another mega, we'll receive a ReRouteRequest here.
+ // that's why we need to remember the player's target coordinates
+ int32 _playerTargetX, _playerTargetY, _playerTargetDir, _playerTargetStance;
+ // additional route data to block parts of the floor and enable routine around megas:
+ int32 _numExtraBars, _numExtraNodes;
+ BarData _extraBars[EXTRA_GRID_SIZE];
+ NodeData _extraNodes[EXTRA_GRID_SIZE];
+ ObjectMan *_objMan;
+ ResMan *_resMan;
+
+ /*uint8 _nWalkFrames, _nTurnFrames;
+ int32 _dx[NO_DIRECTIONS + MAX_FRAMES_PER_CHAR];
+ int32 _dy[NO_DIRECTIONS + MAX_FRAMES_PER_CHAR];
+ int32 _modX[NO_DIRECTIONS];
+ int32 _modY[NO_DIRECTIONS];
+ int32 _diagonalx, _diagonaly;*/
+
+ int32 startX, startY, startDir;
+ int32 targetX, targetY, targetDir;
+ int32 scaleA, scaleB;
+ int32 megaId;
+
+ /*RouteData _route[O_ROUTE_SIZE];
+ //int32 _routeLength;
+ PathData _smoothPath[O_ROUTE_SIZE];
+ PathData _modularPath[O_ROUTE_SIZE];*/
+ RouteData route[O_ROUTE_SIZE];
+ PathData smoothPath[O_ROUTE_SIZE];
+ PathData modularPath[O_ROUTE_SIZE];
+ int32 routeLength;
+
+ int32 framesPerStep, framesPerChar;
+ uint8 nWalkFrames, nTurnFrames;
+ int32 _dx[NO_DIRECTIONS + MAX_FRAMES_PER_CHAR];
+ int32 _dy[NO_DIRECTIONS + MAX_FRAMES_PER_CHAR];
+ int32 modX[NO_DIRECTIONS];
+ int32 modY[NO_DIRECTIONS];
+ int32 diagonalx, diagonaly;
+ int32 standFrames;
+ int32 turnFramesLeft, turnFramesRight;
+ int32 walkFramesLeft, walkFramesRight; // left/right walking turn
+ int32 slowInFrames, slowOutFrames;
+
+
+ int32 LoadWalkResources(Object *mega, int32 x, int32 y, int32 targetDir);
+ int32 GetRoute(void);
+ int32 CheckTarget(int32 x, int32 y);
+
+ int32 Scan(int32 level);
+ int32 NewCheck(int32 status, int32 x1, int32 x2, int32 y1, int32 y2);
+ int32 Check(int32 x1, int32 y1, int32 x2, int32 y2);
+ int32 HorizCheck(int32 x1, int32 y, int32 x2);
+ int32 VertCheck(int32 x, int32 y1, int32 y2);
+ int32 LineCheck(int32 x1, int32 y1, int32 x2, int32 y2);
+
+ void ExtractRoute();
+
+ int32 SlidyPath();
+ void SlidyWalkAnimator(WalkData *walkAnim);
+
+ int32 SmoothestPath();
+ int32 SmoothCheck(int32 best, int32 p, int32 dirS, int32 dirD);
+
+ int32 SolidPath();
+ int32 SolidWalkAnimator(WalkData *walkAnim);
+ void RouteLine(int32 x1,int32 y1,int32 x2,int32 y2 ,int32 colour);
+ void BresenhamLine(int32 x1,int32 y1,int32 x2,int32 y2, uint8 *screen, int32 width, int32 height, int32 colour);
+};
+
+} // End of namespace Sword1
+
+#endif //BSROUTER_H
diff --git a/engines/sword1/screen.cpp b/engines/sword1/screen.cpp
new file mode 100644
index 0000000000..248f1d3227
--- /dev/null
+++ b/engines/sword1/screen.cpp
@@ -0,0 +1,986 @@
+/* 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 "common/system.h"
+#include "common/util.h"
+#include "sword1/screen.h"
+#include "sword1/logic.h"
+#include "sword1/sworddefs.h"
+#include "sword1/text.h"
+#include "sword1/resman.h"
+#include "sword1/objectman.h"
+#include "sword1/menu.h"
+#include "sword1/sword1.h"
+
+#ifdef BACKEND_8BIT
+#include "sword1/animation.h"
+#endif
+
+namespace Sword1 {
+
+#define SCROLL_FRACTION 16
+#define MAX_SCROLL_DISTANCE 8
+#define FADE_UP 1
+#define FADE_DOWN -1
+
+Screen::Screen(OSystem *system, ResMan *pResMan, ObjectMan *pObjMan) {
+ _system = system;
+ _resMan = pResMan;
+ _objMan = pObjMan;
+ _screenBuf = _screenGrid = NULL;
+ _backLength = _foreLength = _sortLength = 0;
+ _fadingStep = 0;
+ _currentScreen = 0xFFFF;
+}
+
+Screen::~Screen(void) {
+ if (_screenBuf)
+ free(_screenBuf);
+ if (_screenGrid)
+ free(_screenGrid);
+ if (_currentScreen != 0xFFFF)
+ quitScreen();
+}
+
+void Screen::useTextManager(Text *pTextMan) {
+ _textMan = pTextMan;
+}
+
+int32 Screen::inRange(int32 a, int32 b, int32 c) { // return b(!) so that: a <= b <= c
+ return (a > b) ? (a) : ((b < c) ? b : c);
+}
+
+void Screen::setScrolling(int16 offsetX, int16 offsetY) {
+ offsetX = inRange(0, offsetX, Logic::_scriptVars[MAX_SCROLL_OFFSET_X]);
+ offsetY = inRange(0, offsetY, Logic::_scriptVars[MAX_SCROLL_OFFSET_Y]);
+
+ if (Logic::_scriptVars[SCROLL_FLAG] == 2) { // first time on this screen - need absolute scroll immediately!
+ _oldScrollX = Logic::_scriptVars[SCROLL_OFFSET_X] = (uint32)offsetX;
+ _oldScrollY = Logic::_scriptVars[SCROLL_OFFSET_Y] = (uint32)offsetY;
+ Logic::_scriptVars[SCROLL_FLAG] = 1;
+ _fullRefresh = true;
+ } else if (Logic::_scriptVars[SCROLL_FLAG] == 1) {
+ // Because parallax layers may be drawn on the old scroll offset, we
+ // want a full refresh not only when the scroll offset changes, but
+ // also on the frame where they become the same.
+ if (_oldScrollX != Logic::_scriptVars[SCROLL_OFFSET_X] || _oldScrollY != Logic::_scriptVars[SCROLL_OFFSET_Y])
+ _fullRefresh = true;
+ _oldScrollX = Logic::_scriptVars[SCROLL_OFFSET_X];
+ _oldScrollY = Logic::_scriptVars[SCROLL_OFFSET_Y];
+ int dx = offsetX - Logic::_scriptVars[SCROLL_OFFSET_X];
+ int dy = offsetY - Logic::_scriptVars[SCROLL_OFFSET_Y];
+ int scrlDistX = inRange(-MAX_SCROLL_DISTANCE, (((SCROLL_FRACTION - 1) + ABS(dx)) / SCROLL_FRACTION) * ((dx > 0) ? 1 : -1), MAX_SCROLL_DISTANCE);
+ int scrlDistY = inRange(-MAX_SCROLL_DISTANCE, (((SCROLL_FRACTION - 1) + ABS(dy)) / SCROLL_FRACTION) * ((dy > 0) ? 1 : -1), MAX_SCROLL_DISTANCE);
+ if ((scrlDistX != 0) || (scrlDistY != 0))
+ _fullRefresh = true;
+ Logic::_scriptVars[SCROLL_OFFSET_X] = inRange(0, Logic::_scriptVars[SCROLL_OFFSET_X] + scrlDistX, Logic::_scriptVars[MAX_SCROLL_OFFSET_X]);
+ Logic::_scriptVars[SCROLL_OFFSET_Y] = inRange(0, Logic::_scriptVars[SCROLL_OFFSET_Y] + scrlDistY, Logic::_scriptVars[MAX_SCROLL_OFFSET_Y]);
+ } else {
+ // SCROLL_FLAG == 0, this usually means that the screen is smaller than 640x400 and doesn't need scrolling at all
+ // however, it can also mean that the gamescript overwrote the scrolling flag to take care of scrolling directly,
+ // (see bug report #1345130) so we ignore the offset arguments in this case
+ Logic::_scriptVars[SCROLL_OFFSET_X] = inRange(0, Logic::_scriptVars[SCROLL_OFFSET_X], Logic::_scriptVars[MAX_SCROLL_OFFSET_X]);
+ Logic::_scriptVars[SCROLL_OFFSET_Y] = inRange(0, Logic::_scriptVars[SCROLL_OFFSET_Y], Logic::_scriptVars[MAX_SCROLL_OFFSET_Y]);
+ if ((Logic::_scriptVars[SCROLL_OFFSET_X] != _oldScrollX) || (Logic::_scriptVars[SCROLL_OFFSET_Y] != _oldScrollY)) {
+ _fullRefresh = true;
+ _oldScrollX = Logic::_scriptVars[SCROLL_OFFSET_X];
+ _oldScrollY = Logic::_scriptVars[SCROLL_OFFSET_Y];
+ }
+ }
+}
+
+void Screen::fadeDownPalette(void) {
+ if (!_isBlack) { // don't fade down twice
+ _fadingStep = 15;
+ _fadingDirection = FADE_DOWN;
+ }
+}
+
+void Screen::fadeUpPalette(void) {
+ _fadingStep = 1;
+ _fadingDirection = FADE_UP;
+}
+
+void Screen::fnSetPalette(uint8 start, uint16 length, uint32 id, bool fadeUp) {
+ uint8 *palData = (uint8*)_resMan->openFetchRes(id);
+ if (start == 0) // force color 0 to black
+ palData[0] = palData[1] = palData[2] = 0;
+ for (uint32 cnt = 0; cnt < length; cnt++) {
+ _targetPalette[(start + cnt) * 4 + 0] = palData[cnt * 3 + 0] << 2;
+ _targetPalette[(start + cnt) * 4 + 1] = palData[cnt * 3 + 1] << 2;
+ _targetPalette[(start + cnt) * 4 + 2] = palData[cnt * 3 + 2] << 2;
+ }
+ _resMan->resClose(id);
+ _isBlack = false;
+ if (fadeUp) {
+ _fadingStep = 1;
+ _fadingDirection = FADE_UP;
+ memset(_currentPalette, 0, 256 * 4);
+ _system->setPalette(_currentPalette, 0, 256);
+ } else
+ _system->setPalette(_targetPalette + 4 * start, start, length);
+}
+
+void Screen::fullRefresh(void) {
+ _fullRefresh = true;
+ _system->setPalette(_targetPalette, 0, 256);
+}
+
+bool Screen::stillFading(void) {
+ return (_fadingStep != 0);
+}
+
+bool Screen::showScrollFrame(void) {
+ if ((!_fullRefresh) || Logic::_scriptVars[NEW_PALETTE])
+ return false; // don't draw an additional frame if we aren't scrolling or have to change the palette
+ if ((_oldScrollX == Logic::_scriptVars[SCROLL_OFFSET_X]) &&
+ (_oldScrollY == Logic::_scriptVars[SCROLL_OFFSET_Y]))
+ return false; // check again if we *really* are scrolling.
+
+ uint16 avgScrlX = (uint16)(_oldScrollX + Logic::_scriptVars[SCROLL_OFFSET_X]) / 2;
+ uint16 avgScrlY = (uint16)(_oldScrollY + Logic::_scriptVars[SCROLL_OFFSET_Y]) / 2;
+
+ _system->copyRectToScreen(_screenBuf + avgScrlY * _scrnSizeX + avgScrlX, _scrnSizeX, 0, 40, SCREEN_WIDTH, SCREEN_DEPTH);
+ _system->updateScreen();
+ return true;
+}
+
+void Screen::updateScreen(void) {
+ if (Logic::_scriptVars[NEW_PALETTE]) {
+ _fadingStep = 1;
+ _fadingDirection = FADE_UP;
+ fnSetPalette(0, 184, _roomDefTable[_currentScreen].palettes[0], true);
+ fnSetPalette(184, 72, _roomDefTable[_currentScreen].palettes[1], true);
+ Logic::_scriptVars[NEW_PALETTE] = 0;
+ }
+ if (_fadingStep) {
+ fadePalette();
+ _system->setPalette(_currentPalette, 0, 256);
+ }
+
+ uint16 scrlX = (uint16)Logic::_scriptVars[SCROLL_OFFSET_X];
+ uint16 scrlY = (uint16)Logic::_scriptVars[SCROLL_OFFSET_Y];
+ if (_fullRefresh) {
+ _fullRefresh = false;
+ uint16 copyWidth = SCREEN_WIDTH;
+ uint16 copyHeight = SCREEN_DEPTH;
+ if (scrlX + copyWidth > _scrnSizeX)
+ copyWidth = _scrnSizeX - scrlX;
+ if (scrlY + copyHeight > _scrnSizeY)
+ copyHeight = _scrnSizeY - scrlY;
+ _system->copyRectToScreen(_screenBuf + scrlY * _scrnSizeX + scrlX, _scrnSizeX, 0, 40, copyWidth, copyHeight);
+ } else {
+ // partial screen update only. The screen coordinates probably won't fit to the
+ // grid holding the informations on which blocks have to be updated.
+ // as the grid will be X pixel higher and Y pixel more to the left, this can be cured
+ // by first checking the top border, then the left column and then the remaining (aligned) part.
+ uint8 *gridPos = _screenGrid + (scrlX / SCRNGRID_X) + (scrlY / SCRNGRID_Y) * _gridSizeX;
+ uint8 *scrnBuf = _screenBuf + scrlY * _scrnSizeX + scrlX;
+ uint8 diffX = (uint8)(scrlX % SCRNGRID_X);
+ uint8 diffY = (uint8)(scrlY % SCRNGRID_Y);
+ uint16 gridW = SCREEN_WIDTH / SCRNGRID_X;
+ uint16 gridH = SCREEN_DEPTH / SCRNGRID_Y;
+ if (diffY) {
+ diffY = SCRNGRID_Y - diffY;
+ uint16 cpWidth = 0;
+ for (uint16 cntx = 0; cntx < gridW; cntx++)
+ if (gridPos[cntx]) {
+ gridPos[cntx] >>= 1;
+ cpWidth++;
+ } else if (cpWidth) {
+ int16 xPos = (cntx - cpWidth) * SCRNGRID_X - diffX;
+ if (xPos < 0)
+ xPos = 0;
+ _system->copyRectToScreen(scrnBuf + xPos, _scrnSizeX, xPos, 40, cpWidth * SCRNGRID_X, diffY);
+ cpWidth = 0;
+ }
+ if (cpWidth) {
+ int16 xPos = (gridW - cpWidth) * SCRNGRID_X - diffX;
+ if (xPos < 0)
+ xPos = 0;
+ _system->copyRectToScreen(scrnBuf + xPos, _scrnSizeX, xPos, 40, SCREEN_WIDTH - xPos, diffY);
+ }
+ scrlY += diffY;
+ }
+ // okay, y scrolling is compensated. check x now.
+ gridPos = _screenGrid + (scrlX / SCRNGRID_X) + (scrlY / SCRNGRID_Y) * _gridSizeX;
+ scrnBuf = _screenBuf + scrlY * _scrnSizeX + scrlX;
+ if (diffX) {
+ diffX = SCRNGRID_X - diffX;
+ uint16 cpHeight = 0;
+ for (uint16 cnty = 0; cnty < gridH; cnty++) {
+ if (*gridPos) {
+ *gridPos >>= 1;
+ cpHeight++;
+ } else if (cpHeight) {
+ uint16 yPos = (cnty - cpHeight) * SCRNGRID_Y;
+ _system->copyRectToScreen(scrnBuf + yPos * _scrnSizeX, _scrnSizeX, 0, yPos + diffY + 40, diffX, cpHeight * SCRNGRID_Y);
+ cpHeight = 0;
+ }
+ gridPos += _gridSizeX;
+ }
+ if (cpHeight) {
+ uint16 yPos = (gridH - cpHeight) * SCRNGRID_Y;
+ _system->copyRectToScreen(scrnBuf + yPos * _scrnSizeX, _scrnSizeX, 0, yPos + diffY + 40, diffX, SCREEN_DEPTH - (yPos + diffY));
+ }
+ scrlX += diffX;
+ }
+ // x scroll is compensated, too. check the rest of the screen, now.
+ scrnBuf = _screenBuf + scrlY * _scrnSizeX + scrlX;
+ gridPos = _screenGrid + (scrlX / SCRNGRID_X) + (scrlY / SCRNGRID_Y) * _gridSizeX;
+ for (uint16 cnty = 0; cnty < gridH; cnty++) {
+ uint16 cpWidth = 0;
+ uint16 cpHeight = SCRNGRID_Y;
+ if (cnty == gridH - 1)
+ cpHeight = SCRNGRID_Y - diffY;
+ for (uint16 cntx = 0; cntx < gridW; cntx++)
+ if (gridPos[cntx]) {
+ gridPos[cntx] >>= 1;
+ cpWidth++;
+ } else if (cpWidth) {
+ _system->copyRectToScreen(scrnBuf + (cntx - cpWidth) * SCRNGRID_X, _scrnSizeX, (cntx - cpWidth) * SCRNGRID_X + diffX, cnty * SCRNGRID_Y + diffY + 40, cpWidth * SCRNGRID_X, cpHeight);
+ cpWidth = 0;
+ }
+ if (cpWidth) {
+ uint16 xPos = (gridW - cpWidth) * SCRNGRID_X;
+ _system->copyRectToScreen(scrnBuf + xPos, _scrnSizeX, xPos + diffX, cnty * SCRNGRID_Y + diffY + 40, SCREEN_WIDTH - (xPos + diffX), cpHeight);
+ }
+ gridPos += _gridSizeX;
+ scrnBuf += _scrnSizeX * SCRNGRID_Y;
+ }
+ }
+ _system->updateScreen();
+}
+
+void Screen::newScreen(uint32 screen) {
+ uint8 cnt;
+ // set sizes and scrolling, initialize/load screengrid, force screen refresh
+ _currentScreen = screen;
+ _scrnSizeX = _roomDefTable[screen].sizeX;
+ _scrnSizeY = _roomDefTable[screen].sizeY;
+ _gridSizeX = _scrnSizeX / SCRNGRID_X;
+ _gridSizeY = _scrnSizeY / SCRNGRID_Y;
+ if ((_scrnSizeX % SCRNGRID_X) || (_scrnSizeY % SCRNGRID_Y))
+ error("Illegal screensize: %d: %d/%d", screen, _scrnSizeX, _scrnSizeY);
+ if ((_scrnSizeX > SCREEN_WIDTH) || (_scrnSizeY > SCREEN_DEPTH)) {
+ Logic::_scriptVars[SCROLL_FLAG] = 2;
+ Logic::_scriptVars[MAX_SCROLL_OFFSET_X] = _scrnSizeX - SCREEN_WIDTH;
+ Logic::_scriptVars[MAX_SCROLL_OFFSET_Y] = _scrnSizeY - SCREEN_DEPTH;
+ } else {
+ Logic::_scriptVars[SCROLL_FLAG] = 0;
+ Logic::_scriptVars[MAX_SCROLL_OFFSET_X] = 0;
+ Logic::_scriptVars[MAX_SCROLL_OFFSET_Y] = 0;
+ }
+ Logic::_scriptVars[SCROLL_OFFSET_X] = 0;
+ Logic::_scriptVars[SCROLL_OFFSET_Y] = 0;
+
+ if (_screenBuf)
+ free(_screenBuf);
+ if (_screenGrid)
+ free(_screenGrid);
+ _screenBuf = (uint8*)malloc(_scrnSizeX * _scrnSizeY);
+ _screenGrid = (uint8*)malloc(_gridSizeX * _gridSizeY);
+ memset(_screenGrid, 0, _gridSizeX * _gridSizeY);
+ for (cnt = 0; cnt < _roomDefTable[_currentScreen].totalLayers; cnt++) {
+ // open and lock all resources, will be closed in quitScreen()
+ _layerBlocks[cnt] = (uint8*)_resMan->openFetchRes(_roomDefTable[_currentScreen].layers[cnt]);
+ if (cnt > 0)
+ _layerBlocks[cnt] += sizeof(Header);
+ }
+ for (cnt = 0; cnt < _roomDefTable[_currentScreen].totalLayers - 1; cnt++) {
+ // there's no grid for the background layer, so it's totalLayers - 1
+ _layerGrid[cnt] = (uint16*)_resMan->openFetchRes(_roomDefTable[_currentScreen].grids[cnt]);
+ _layerGrid[cnt] += 14;
+ }
+ _parallax[0] = _parallax[1] = NULL;
+ if (_roomDefTable[_currentScreen].parallax[0])
+ _parallax[0] = (uint8*)_resMan->openFetchRes(_roomDefTable[_currentScreen].parallax[0]);
+ if (_roomDefTable[_currentScreen].parallax[1])
+ _parallax[1] = (uint8*)_resMan->openFetchRes(_roomDefTable[_currentScreen].parallax[1]);
+
+ fnSetPalette(0, 184, _roomDefTable[_currentScreen].palettes[0], SwordEngine::_systemVars.wantFade);
+ fnSetPalette(184, 72, _roomDefTable[_currentScreen].palettes[1], SwordEngine::_systemVars.wantFade);
+ _fullRefresh = true;
+}
+
+void Screen::quitScreen(void) {
+ uint8 cnt;
+ for (cnt = 0; cnt < _roomDefTable[_currentScreen].totalLayers; cnt++)
+ _resMan->resClose(_roomDefTable[_currentScreen].layers[cnt]);
+ for (cnt = 0; cnt < _roomDefTable[_currentScreen].totalLayers - 1; cnt++)
+ _resMan->resClose(_roomDefTable[_currentScreen].grids[cnt]);
+ if (_roomDefTable[_currentScreen].parallax[0])
+ _resMan->resClose(_roomDefTable[_currentScreen].parallax[0]);
+ if (_roomDefTable[_currentScreen].parallax[1])
+ _resMan->resClose(_roomDefTable[_currentScreen].parallax[1]);
+ _currentScreen = 0xFFFF;
+}
+
+void Screen::draw(void) {
+ uint8 cnt;
+ if (_currentScreen == 54) {
+ // rm54 has a BACKGROUND parallax layer in parallax[0]
+ if (_parallax[0])
+ renderParallax(_parallax[0]);
+ uint8 *src = _layerBlocks[0];
+ uint8 *dest = _screenBuf;
+
+ for (uint16 cnty = 0; cnty < _scrnSizeY; cnty++)
+ for (uint16 cntx = 0; cntx < _scrnSizeX; cntx++) {
+ if (*src)
+ *dest = *src;
+ dest++;
+ src++;
+ }
+
+ } else
+ memcpy(_screenBuf, _layerBlocks[0], _scrnSizeX * _scrnSizeY);
+
+ for (cnt = 0; cnt < _backLength; cnt++)
+ processImage(_backList[cnt]);
+
+ for (cnt = 0; cnt < _sortLength - 1; cnt++)
+ for (uint8 sCnt = 0; sCnt < _sortLength - 1; sCnt++)
+ if (_sortList[sCnt].y > _sortList[sCnt + 1].y) {
+ SWAP(_sortList[sCnt], _sortList[sCnt + 1]);
+ }
+ for (cnt = 0; cnt < _sortLength; cnt++)
+ processImage(_sortList[cnt].id);
+
+ if ((_currentScreen != 54) && _parallax[0])
+ renderParallax(_parallax[0]); // screens other than 54 have FOREGROUND parallax layer in parallax[0]
+ if (_parallax[1])
+ renderParallax(_parallax[1]);
+
+ for (cnt = 0; cnt < _foreLength; cnt++)
+ processImage(_foreList[cnt]);
+
+ _backLength = _sortLength = _foreLength = 0;
+}
+
+void Screen::processImage(uint32 id) {
+ Object *compact;
+ FrameHeader *frameHead;
+ int scale;
+
+ compact = _objMan->fetchObject(id);
+ if (compact->o_type == TYPE_TEXT)
+ frameHead = _textMan->giveSpriteData((uint8)compact->o_target);
+ else
+ frameHead = _resMan->fetchFrame(_resMan->openFetchRes(compact->o_resource), compact->o_frame);
+
+ uint8 *sprData = ((uint8*)frameHead) + sizeof(FrameHeader);
+
+ uint16 spriteX = compact->o_anim_x;
+ uint16 spriteY = compact->o_anim_y;
+ if (compact->o_status & STAT_SHRINK) {
+ scale = (compact->o_scale_a * compact->o_ycoord + compact->o_scale_b) / 256;
+ spriteX += ((int16)READ_LE_UINT16(&frameHead->offsetX) * scale) / 256;
+ spriteY += ((int16)READ_LE_UINT16(&frameHead->offsetY) * scale) / 256;
+ } else {
+ scale = 256;
+ spriteX += (int16)READ_LE_UINT16(&frameHead->offsetX);
+ spriteY += (int16)READ_LE_UINT16(&frameHead->offsetY);
+ }
+
+ uint8 *tonyBuf = NULL;
+ if (frameHead->runTimeComp[3] == '7') { // RLE7 encoded?
+ decompressRLE7(sprData, READ_LE_UINT32(&frameHead->compSize), _rleBuffer);
+ sprData = _rleBuffer;
+ } else if (frameHead->runTimeComp[3] == '0') { // RLE0 encoded?
+ decompressRLE0(sprData, READ_LE_UINT32(&frameHead->compSize), _rleBuffer);
+ sprData = _rleBuffer;
+ } else if (frameHead->runTimeComp[1] == 'I') { // new type
+ tonyBuf = (uint8*)malloc(READ_LE_UINT16(&frameHead->width) * READ_LE_UINT16(&frameHead->height));
+ decompressTony(sprData, READ_LE_UINT32(&frameHead->compSize), tonyBuf);
+ sprData = tonyBuf;
+ }
+
+ uint16 sprSizeX, sprSizeY;
+ if (compact->o_status & STAT_SHRINK) {
+ sprSizeX = (scale * READ_LE_UINT16(&frameHead->width)) / 256;
+ sprSizeY = (scale * READ_LE_UINT16(&frameHead->height)) / 256;
+ fastShrink(sprData, READ_LE_UINT16(&frameHead->width), READ_LE_UINT16(&frameHead->height), scale, _shrinkBuffer);
+ sprData = _shrinkBuffer;
+ } else {
+ sprSizeX = READ_LE_UINT16(&frameHead->width);
+ sprSizeY = READ_LE_UINT16(&frameHead->height);
+ }
+ if (!(compact->o_status & STAT_OVERRIDE)) {
+ //mouse size linked to exact size & coordinates of sprite box - shrink friendly
+ if (READ_LE_UINT16(&frameHead->offsetX) || READ_LE_UINT16(&frameHead->offsetY)) {
+ //for megas the mouse area is reduced to account for sprite not
+ //filling the box size is reduced to 1/2 width, 4/5 height
+ compact->o_mouse_x1 = spriteX + sprSizeX / 4;
+ compact->o_mouse_x2 = spriteX + (3 * sprSizeX) / 4;
+ compact->o_mouse_y1 = spriteY + sprSizeY / 10;
+ compact->o_mouse_y2 = spriteY + (9 * sprSizeY) / 10;
+ } else {
+ compact->o_mouse_x1 = spriteX;
+ compact->o_mouse_x2 = spriteX + sprSizeX;
+ compact->o_mouse_y1 = spriteY;
+ compact->o_mouse_y2 = spriteY + sprSizeY;
+ }
+ }
+ uint16 sprPitch = sprSizeX;
+ uint16 incr;
+ spriteClipAndSet(&spriteX, &spriteY, &sprSizeX, &sprSizeY, &incr);
+ if ((sprSizeX > 0) && (sprSizeY > 0)) {
+ drawSprite(sprData + incr, spriteX, spriteY, sprSizeX, sprSizeY, sprPitch);
+ if (!(compact->o_status&STAT_FORE))
+ verticalMask(spriteX, spriteY, sprSizeX, sprSizeY);
+ }
+ if (compact->o_type != TYPE_TEXT)
+ _resMan->resClose(compact->o_resource);
+ if (tonyBuf)
+ free(tonyBuf);
+}
+
+void Screen::verticalMask(uint16 x, uint16 y, uint16 bWidth, uint16 bHeight) {
+ if (_roomDefTable[_currentScreen].totalLayers <= 1)
+ return;
+
+ bWidth = (bWidth + (x & (SCRNGRID_X - 1)) + (SCRNGRID_X - 1)) / SCRNGRID_X;
+ bHeight = (bHeight + (y & (SCRNGRID_Y - 1)) + (SCRNGRID_Y - 1)) / SCRNGRID_Y;
+
+ x /= SCRNGRID_X;
+ y /= SCRNGRID_Y;
+ if (x + bWidth > _gridSizeX)
+ bWidth = _gridSizeX - x;
+ if (y + bHeight > _gridSizeY)
+ bHeight = _gridSizeY - y;
+
+ uint16 gridY = y + SCREEN_TOP_EDGE / SCRNGRID_Y; // imaginary screen on top
+ gridY += bHeight - 1; // we start from the bottom edge
+ uint16 gridX = x + SCREEN_LEFT_EDGE / SCRNGRID_X; // imaginary screen left
+ uint16 lGridSizeX = _gridSizeX + 2 * (SCREEN_LEFT_EDGE / SCRNGRID_X); // width of the grid for the imaginary screen
+
+ for (uint16 blkx = 0; blkx < bWidth; blkx++) {
+ // A sprite can be masked by several layers at the same time,
+ // so we have to check them all. See bug #917427.
+ for (int16 level = _roomDefTable[_currentScreen].totalLayers - 2; level >= 0; level--) {
+ if (_layerGrid[level][gridX + blkx + gridY * lGridSizeX]) {
+ uint16 *grid = _layerGrid[level] + gridX + blkx + gridY * lGridSizeX;
+ for (int16 blky = bHeight - 1; blky >= 0; blky--) {
+ if (*grid) {
+ uint8 *blkData = _layerBlocks[level + 1] + (READ_LE_UINT16(grid) - 1) * 128;
+ blitBlockClear(x + blkx, y + blky, blkData);
+ } else
+ break;
+ grid -= lGridSizeX;
+ }
+ }
+ }
+ }
+}
+
+void Screen::blitBlockClear(uint16 x, uint16 y, uint8 *data) {
+ uint8 *dest = _screenBuf + (y * SCRNGRID_Y) * _scrnSizeX + (x * SCRNGRID_X);
+ for (uint8 cnty = 0; cnty < SCRNGRID_Y; cnty++) {
+ for (uint8 cntx = 0; cntx < SCRNGRID_X; cntx++)
+ if (data[cntx])
+ dest[cntx] = data[cntx];
+ data += SCRNGRID_X;
+ dest += _scrnSizeX;
+ }
+}
+
+void Screen::renderParallax(uint8 *data) {
+ ParallaxHeader *header = (ParallaxHeader*)data;
+ uint32 *lineIndexes = (uint32*)(data + sizeof(ParallaxHeader));
+ assert((FROM_LE_16(header->sizeX) >= SCREEN_WIDTH) && (FROM_LE_16(header->sizeY) >= SCREEN_DEPTH));
+
+ uint16 paraScrlX, paraScrlY;
+ uint16 scrnScrlX, scrnScrlY;
+ uint16 scrnWidth, scrnHeight;
+
+ // we have to render more than the visible screen part for displaying scroll frames
+ scrnScrlX = MIN((uint32)_oldScrollX, Logic::_scriptVars[SCROLL_OFFSET_X]);
+ scrnWidth = SCREEN_WIDTH + ABS((int32)_oldScrollX - (int32)Logic::_scriptVars[SCROLL_OFFSET_X]);
+ scrnScrlY = MIN((uint32)_oldScrollY, Logic::_scriptVars[SCROLL_OFFSET_Y]);
+ scrnHeight = SCREEN_DEPTH + ABS((int32)_oldScrollY - (int32)Logic::_scriptVars[SCROLL_OFFSET_Y]);
+
+ if (_scrnSizeX != SCREEN_WIDTH) {
+ double scrlfx = (FROM_LE_16(header->sizeX) - SCREEN_WIDTH) / ((double)(_scrnSizeX - SCREEN_WIDTH));
+ paraScrlX = (uint16)(scrnScrlX * scrlfx);
+ } else
+ paraScrlX = 0;
+
+ if (_scrnSizeY != SCREEN_DEPTH) {
+ double scrlfy = (FROM_LE_16(header->sizeY) - SCREEN_DEPTH) / ((double)(_scrnSizeY - SCREEN_DEPTH));
+ paraScrlY = (uint16)(scrnScrlY * scrlfy);
+ } else
+ paraScrlY = 0;
+
+ for (uint16 cnty = 0; cnty < scrnHeight; cnty++) {
+ uint8 *src = data + READ_LE_UINT32(lineIndexes + cnty + paraScrlY);
+ uint8 *dest = _screenBuf + scrnScrlX + (cnty + scrnScrlY) * _scrnSizeX;
+ uint16 remain = paraScrlX;
+ uint16 xPos = 0;
+ while (remain) { // skip past the first part of the parallax to get to the right scrolling position
+ uint8 doSkip = *src++;
+ if (doSkip <= remain)
+ remain -= doSkip;
+ else {
+ xPos = doSkip - remain;
+ dest += xPos;
+ remain = 0;
+ }
+ uint8 doCopy = *src++;
+ if (doCopy <= remain) {
+ remain -= doCopy;
+ src += doCopy;
+ } else {
+ uint16 remCopy = doCopy - remain;
+ memcpy(dest, src + remain, remCopy);
+ dest += remCopy;
+ src += doCopy;
+ xPos = remCopy;
+ remain = 0;
+ }
+ }
+ while (xPos < scrnWidth) {
+ if (uint8 skip = *src++) {
+ dest += skip;
+ xPos += skip;
+ }
+ if (xPos < scrnWidth) {
+ if (uint8 doCopy = *src++) {
+ if (xPos + doCopy > scrnWidth)
+ doCopy = scrnWidth - xPos;
+ memcpy(dest, src, doCopy);
+ dest += doCopy;
+ xPos += doCopy;
+ src += doCopy;
+ }
+ }
+ }
+ }
+}
+
+void Screen::drawSprite(uint8 *sprData, uint16 sprX, uint16 sprY, uint16 sprWidth, uint16 sprHeight, uint16 sprPitch) {
+ uint8 *dest = _screenBuf + (sprY * _scrnSizeX) + sprX;
+
+ for (uint16 cnty = 0; cnty < sprHeight; cnty++) {
+ for (uint16 cntx = 0; cntx < sprWidth; cntx++)
+ if (sprData[cntx])
+ dest[cntx] = sprData[cntx];
+ sprData += sprPitch;
+ dest += _scrnSizeX;
+ }
+}
+
+// nearest neighbor filter:
+void Screen::fastShrink(uint8 *src, uint32 width, uint32 height, uint32 scale, uint8 *dest) {
+ uint32 resHeight = (height * scale) >> 8;
+ uint32 resWidth = (width * scale) >> 8;
+ uint32 step = 0x10000 / scale;
+ uint8 columnTab[160];
+ uint32 res = step >> 1;
+ for (uint16 cnt = 0; cnt < resWidth; cnt++) {
+ columnTab[cnt] = (uint8)(res >> 8);
+ res += step;
+ }
+
+ uint32 newRow = step >> 1;
+ uint32 oldRow = 0;
+
+ uint8 *destPos = dest;
+ uint16 lnCnt;
+ for (lnCnt = 0; lnCnt < resHeight; lnCnt++) {
+ while (oldRow < (newRow >> 8)) {
+ oldRow++;
+ src += width;
+ }
+ for (uint16 colCnt = 0; colCnt < resWidth; colCnt++) {
+ *destPos++ = src[columnTab[colCnt]];
+ }
+ newRow += step;
+ }
+ // scaled, now stipple shadows if there are any
+ for (lnCnt = 0; lnCnt < resHeight; lnCnt++) {
+ uint16 xCnt = lnCnt & 1;
+ destPos = dest + lnCnt * resWidth + (lnCnt & 1);
+ while (xCnt < resWidth) {
+ if (*destPos == 200)
+ *destPos = 0;
+ destPos += 2;
+ xCnt += 2;
+ }
+ }
+}
+
+void Screen::addToGraphicList(uint8 listId, uint32 objId) {
+ if (listId == 0) {
+ assert(_foreLength < MAX_FORE);
+ _foreList[_foreLength++] = objId;
+ }
+ if (listId == 1) {
+ assert(_sortLength < MAX_SORT);
+ Object *cpt = _objMan->fetchObject(objId);
+ _sortList[_sortLength].id = objId;
+ _sortList[_sortLength].y = cpt->o_anim_y; // gives feet coords if boxed mega, otherwise top of sprite box
+ if (!(cpt->o_status & STAT_SHRINK)) { // not a boxed mega using shrinking
+ Header *frameRaw = (Header*)_resMan->openFetchRes(cpt->o_resource);
+ FrameHeader *frameHead = _resMan->fetchFrame(frameRaw, cpt->o_frame);
+ _sortList[_sortLength].y += READ_LE_UINT16(&frameHead->height) - 1; // now pointing to base of sprite
+ _resMan->resClose(cpt->o_resource);
+ }
+ _sortLength++;
+ }
+ if (listId == 2) {
+ assert(_backLength < MAX_BACK);
+ _backList[_backLength++] = objId;
+ }
+}
+
+void Screen::decompressTony(uint8 *src, uint32 compSize, uint8 *dest) {
+ uint8 *endOfData = src + compSize;
+ while (src < endOfData) {
+ uint8 numFlat = *src++;
+ if (numFlat) {
+ memset(dest, *src, numFlat);
+ src++;
+ dest += numFlat;
+ }
+ if (src < endOfData) {
+ uint8 numNoFlat = *src++;
+ memcpy(dest, src, numNoFlat);
+ src += numNoFlat;
+ dest += numNoFlat;
+ }
+ }
+}
+
+void Screen::decompressRLE7(uint8 *src, uint32 compSize, uint8 *dest) {
+ uint8 *compBufEnd = src + compSize;
+ while (src < compBufEnd) {
+ uint8 code = *src++;
+ if ((code > 127) || (code == 0))
+ *dest++ = code;
+ else {
+ code++;
+ memset(dest, *src++, code);
+ dest += code;
+ }
+ }
+}
+
+void Screen::decompressRLE0(uint8 *src, uint32 compSize, uint8 *dest) {
+ uint8 *srcBufEnd = src + compSize;
+ while (src < srcBufEnd) {
+ uint8 color = *src++;
+ if (color) {
+ *dest++ = color;
+ } else {
+ uint8 skip = *src++;
+ memset(dest, 0, skip);
+ dest += skip;
+ }
+ }
+}
+
+void Screen::fadePalette(void) {
+ if (_fadingStep == 16)
+ memcpy(_currentPalette, _targetPalette, 256 * 4);
+ else if ((_fadingStep == 1) && (_fadingDirection == FADE_DOWN)) {
+ memset(_currentPalette, 0, 4 * 256);
+ } else
+ for (uint16 cnt = 0; cnt < 256 * 4; cnt++)
+ _currentPalette[cnt] = (_targetPalette[cnt] * _fadingStep) >> 4;
+
+ _fadingStep += _fadingDirection;
+ if (_fadingStep == 17) {
+ _fadingStep = 0;
+ _isBlack = false;
+ } else if (_fadingStep == 0)
+ _isBlack = true;
+}
+
+void Screen::fnSetParallax(uint32 screen, uint32 resId) {
+ _roomDefTable[screen].parallax[0] = resId;
+}
+
+void Screen::spriteClipAndSet(uint16 *pSprX, uint16 *pSprY, uint16 *pSprWidth, uint16 *pSprHeight, uint16 *incr) {
+ int16 sprX = *pSprX - SCREEN_LEFT_EDGE;
+ int16 sprY = *pSprY - SCREEN_TOP_EDGE;
+ int16 sprW = *pSprWidth;
+ int16 sprH = *pSprHeight;
+
+ if (sprY < 0) {
+ *incr = (uint16)((-sprY) * sprW);
+ sprH += sprY;
+ sprY = 0;
+ } else
+ *incr = 0;
+ if (sprX < 0) {
+ *incr -= sprX;
+ sprW += sprX;
+ sprX = 0;
+ }
+
+ if (sprY + sprH > _scrnSizeY)
+ sprH = _scrnSizeY - sprY;
+ if (sprX + sprW > _scrnSizeX)
+ sprW = _scrnSizeX - sprX;
+
+ if (sprH < 0)
+ *pSprHeight = 0;
+ else
+ *pSprHeight = (uint16)sprH;
+ if (sprW < 0)
+ *pSprWidth = 0;
+ else
+ *pSprWidth = (uint16)sprW;
+ *pSprX = (uint16)sprX;
+ *pSprY = (uint16)sprY;
+
+ if (*pSprWidth && *pSprHeight) {
+ // sprite will be drawn, so mark it in the grid buffer
+ uint16 gridH = (*pSprHeight + (sprY & (SCRNGRID_Y - 1)) + (SCRNGRID_Y - 1)) / SCRNGRID_Y;
+ uint16 gridW = (*pSprWidth + (sprX & (SCRNGRID_X - 1)) + (SCRNGRID_X - 1)) / SCRNGRID_X;
+ uint16 gridX = sprX / SCRNGRID_X;
+ uint16 gridY = sprY / SCRNGRID_Y;
+ uint8 *gridBuf = _screenGrid + gridX + gridY * _gridSizeX;
+ if (gridX + gridW > _gridSizeX)
+ gridW = _gridSizeX - gridX;
+ if (gridY + gridH > _gridSizeY)
+ gridH = _gridSizeY - gridY;
+
+ for (uint16 cnty = 0; cnty < gridH; cnty++) {
+ for (uint16 cntx = 0; cntx < gridW; cntx++)
+ gridBuf[cntx] = 2;
+ gridBuf += _gridSizeX;
+ }
+ }
+}
+
+void Screen::fnFlash(uint8 color) {
+ warning("stub: Screen::fnFlash(%d)", color);
+}
+
+// ------------------- Menu screen interface ---------------------------
+
+void Screen::showFrame(uint16 x, uint16 y, uint32 resId, uint32 frameNo, const byte *fadeMask, int8 fadeStatus) {
+ uint8 frame[40 * 40];
+ int i, j;
+
+ memset(frame, 199, sizeof(frame)); // Dark gray background
+
+ if (resId != 0xffffffff) {
+ FrameHeader *frameHead = _resMan->fetchFrame(_resMan->openFetchRes(resId), frameNo);
+ uint8 *frameData = ((uint8*)frameHead) + sizeof(FrameHeader);
+
+ for (i = 0; i < FROM_LE_16(frameHead->height); i++) {
+ for (j = 0; j < FROM_LE_16(frameHead->height); j++) {
+ frame[(i + 4) * 40 + j + 2] = frameData[i * FROM_LE_16(frameHead->width) + j];
+ }
+ }
+
+ _resMan->resClose(resId);
+ }
+
+ if (fadeMask) {
+ for (i = 0; i < 40; i++) {
+ for (j = 0; j < 40; j++) {
+ if (fadeMask[((i % 8) * 8) + (j % 8)] >= fadeStatus)
+ frame[i * 40 + j] = 0;
+ }
+ }
+ }
+
+ _system->copyRectToScreen(frame, 40, x, y, 40, 40);
+}
+
+// ------------------- router debugging code --------------------------------
+
+void Screen::vline(uint16 x, uint16 y1, uint16 y2) {
+ for (uint16 cnty = y1; cnty <= y2; cnty++)
+ _screenBuf[x + _scrnSizeX * cnty] = 0;
+}
+
+void Screen::hline(uint16 x1, uint16 x2, uint16 y) {
+ for (uint16 cntx = x1; cntx <= x2; cntx++)
+ _screenBuf[y * _scrnSizeX + cntx] = 0;
+}
+
+void Screen::bsubline_1(uint16 x1, uint16 y1, uint16 x2, uint16 y2) {
+ int x, y, ddx, ddy, e;
+ ddx = ABS(x2 - x1);
+ ddy = ABS(y2 - y1) << 1;
+ e = ddx - ddy;
+ ddx <<= 1;
+
+ if (x1 > x2) {
+ uint16 tmp;
+ tmp = x1; x1 = x2; x2 = tmp;
+ tmp = y1; y1 = y2; y2 = tmp;
+ }
+
+ for (x = x1, y = y1; x <= x2; x++) {
+ _screenBuf[y * _scrnSizeX + x] = 0;
+ if (e < 0) {
+ y++;
+ e += ddx - ddy;
+ } else {
+ e -= ddy;
+ }
+ }
+}
+
+void Screen::bsubline_2(uint16 x1, uint16 y1, uint16 x2, uint16 y2) {
+ int x, y, ddx, ddy, e;
+ ddx = ABS(x2 - x1) << 1;
+ ddy = ABS(y2 - y1);
+ e = ddy - ddx;
+ ddy <<= 1;
+
+ if (y1 > y2) {
+ uint16 tmp;
+ tmp = x1; x1 = x2; x2 = tmp;
+ tmp = y1; y1 = y2; y2 = tmp;
+ }
+
+ for (y = y1, x = x1; y <= y2; y++) {
+ _screenBuf[y * _scrnSizeX + x] = 0;
+ if (e < 0) {
+ x++;
+ e += ddy - ddx;
+ } else {
+ e -= ddx;
+ }
+ }
+}
+
+void Screen::bsubline_3(uint16 x1, uint16 y1, uint16 x2, uint16 y2) {
+ int x, y, ddx, ddy, e;
+ ddx = ABS(x1 - x2) << 1;
+ ddy = ABS(y2 - y1);
+ e = ddy - ddx;
+ ddy <<= 1;
+
+ if (y1 > y2) {
+ uint16 tmp;
+ tmp = x1; x1 = x2; x2 = tmp;
+ tmp = y1; y1 = y2; y2 = tmp;
+ }
+
+ for (y = y1, x = x1; y <= y2; y++) {
+ _screenBuf[y * _scrnSizeX + x] = 0;
+ if (e < 0) {
+ x--;
+ e += ddy - ddx;
+ } else {
+ e -= ddx;
+ }
+ }
+}
+
+void Screen::bsubline_4(uint16 x1, uint16 y1, uint16 x2, uint16 y2) {
+ int x, y, ddx, ddy, e;
+ ddy = ABS(y2 - y1) << 1;
+ ddx = ABS(x1 - x2);
+ e = ddx - ddy;
+ ddx <<= 1;
+
+ if (x1 > x2) {
+ uint16 tmp;
+ tmp = x1; x1 = x2; x2 = tmp;
+ tmp = y1; y1 = y2; y2 = tmp;
+ }
+
+ for (x = x1, y = y1; x <= x2; x++) {
+ _screenBuf[y * _scrnSizeX + x] = 0;
+ if (e < 0) {
+ y--;
+ e += ddx - ddy;
+ } else {
+ e -= ddy;
+ }
+ }
+}
+
+void Screen::drawLine(uint16 x1, uint16 y1, uint16 x2, uint16 y2) {
+ if ((x1 == x2) && (y1 == y2)) {
+ _screenBuf[x1 + y1 * _scrnSizeX] = 0;
+ }
+ if (x1 == x2) {
+ vline(x1, MIN(y1, y2), MAX(y1, y2));
+ return;
+ }
+
+ if (y1 == y2) {
+ hline(MIN(x1, x2), MAX(x1, x2), y1);
+ return;
+ }
+
+ float k = float(y2 - y1) / float(x2 - x1);
+
+ if ((k >= 0) && (k <= 1)) {
+ bsubline_1(x1, y1, x2, y2);
+ } else if (k > 1) {
+ bsubline_2(x1, y1, x2, y2);
+ } else if ((k < 0) && (k >= -1)) {
+ bsubline_4(x1, y1, x2, y2);
+ } else {
+ bsubline_3(x1, y1, x2, y2);
+ }
+}
+
+#ifdef BACKEND_8BIT
+void Screen::plotYUV(byte *lut, int width, int height, byte *const *dat) {
+
+ byte * buf = (uint8*)malloc(width * height);
+
+ int x, y;
+
+ int ypos = 0;
+ int cpos = 0;
+ int linepos = 0;
+
+ for (y = 0; y < height; y += 2) {
+ for (x = 0; x < width; x += 2) {
+ int i = ((((dat[2][cpos] + ROUNDADD) >> SHIFT) * (BITDEPTH+1)) + ((dat[1][cpos] + ROUNDADD)>>SHIFT)) * (BITDEPTH+1);
+ cpos++;
+
+ buf[linepos ] = lut[i + ((dat[0][ ypos ] + ROUNDADD) >> SHIFT)];
+ buf[width + linepos++] = lut[i + ((dat[0][width + ypos++] + ROUNDADD) >> SHIFT)];
+ buf[linepos ] = lut[i + ((dat[0][ ypos ] + ROUNDADD) >> SHIFT)];
+ buf[width + linepos++] = lut[i + ((dat[0][width + ypos++] + ROUNDADD) >> SHIFT)];
+ }
+ linepos += (2 * width - width);
+ ypos += width;
+ }
+
+ _system->copyRectToScreen(buf, width, (640-width)/2, (480-height)/2, width, height);
+ _system->updateScreen();
+
+ free(buf);
+
+}
+#endif
+
+
+
+} // End of namespace Sword1
diff --git a/engines/sword1/screen.h b/engines/sword1/screen.h
new file mode 100644
index 0000000000..43a0b74cab
--- /dev/null
+++ b/engines/sword1/screen.h
@@ -0,0 +1,157 @@
+/* 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 BSSCREEN_H
+#define BSSCREEN_H
+
+#include "sword1/sworddefs.h"
+
+class OSystem;
+
+namespace Sword1 {
+
+#define MAX_FORE 20
+#define MAX_BACK 20
+#define MAX_SORT 20
+
+struct SortSpr {
+ int32 id, y;
+};
+
+struct RoomDef {
+ int totalLayers;
+ int sizeX;
+ int sizeY;
+ int gridWidth; //number of 16*16 grid blocks across - including off screen edges.
+ uint32 layers[4];
+ uint32 grids[3];
+ uint32 palettes[2];
+ uint32 parallax[2];
+};
+
+#define SCRNGRID_X 16
+#define SCRNGRID_Y 8
+#define SHRINK_BUFFER_SIZE 50000
+#define RLE_BUFFER_SIZE 50000
+
+#define FLASH_RED 0
+#define FLASH_BLUE 1
+#define BORDER_YELLOW 2
+#define BORDER_GREEN 3
+#define BORDER_PURPLE 4
+#define BORDER_BLACK 5
+
+class ResMan;
+class ObjectMan;
+class Text; // Text objects use sprites that are created internally at run-time
+ // the buffer belongs to Text, so we need a reference here.
+
+class Screen {
+public:
+ Screen(OSystem *system, ResMan *pResMan, ObjectMan *pObjMan);
+ ~Screen(void);
+ void useTextManager(Text *pTextMan);
+ void draw(void);
+
+ void quitScreen(void);
+ void newScreen(uint32 screen);
+
+ void setScrolling(int16 offsetX, int16 offsetY);
+ void addToGraphicList(uint8 listId, uint32 objId);
+
+ void fadeDownPalette(void);
+ void fadeUpPalette(void);
+ void fnSetPalette(uint8 start, uint16 length, uint32 id, bool fadeUp);
+ bool stillFading(void);
+ void fullRefresh(void);
+
+ bool showScrollFrame(void);
+ void updateScreen(void);
+ void showFrame(uint16 x, uint16 y, uint32 resId, uint32 frameNo, const byte *fadeMask = NULL, int8 fadeStatus = 0);
+
+ void fnSetParallax(uint32 screen, uint32 resId);
+ void fnFlash(uint8 color);
+ void fnBorder(uint8 color);
+
+#ifdef BACKEND_8BIT
+ void plotYUV(byte *lut, int width, int height, byte *const *dat);
+#endif
+
+private:
+ // for router debugging
+ void drawLine(uint16 x1, uint16 y1, uint16 x2, uint16 y2);
+ void vline(uint16 x, uint16 y1, uint16 y2);
+ void hline(uint16 x1, uint16 x2, uint16 y);
+ void bsubline_1(uint16 x1, uint16 y1, uint16 x2, uint16 y2);
+ void bsubline_2(uint16 x1, uint16 y1, uint16 x2, uint16 y2);
+ void bsubline_3(uint16 x1, uint16 y1, uint16 x2, uint16 y2);
+ void bsubline_4(uint16 x1, uint16 y1, uint16 x2, uint16 y2);
+
+ void verticalMask(uint16 x, uint16 y, uint16 bWidth, uint16 bHeight);
+ void blitBlockClear(uint16 x, uint16 y, uint8 *data);
+ void renderParallax(uint8 *data);
+ void processImage(uint32 id);
+ void spriteClipAndSet(uint16 *pSprX, uint16 *pSprY, uint16 *sprWidth, uint16 *sprHeight, uint16 *incr);
+ void drawSprite(uint8 *sprData, uint16 sprX, uint16 sprY, uint16 sprWidth, uint16 sprHeight, uint16 sprPitch);
+ void decompressRLE7(uint8 *src, uint32 compSize, uint8 *dest);
+ void decompressRLE0(uint8 *src, uint32 compSize, uint8 *dest);
+ void decompressTony(uint8 *src, uint32 compSize, uint8 *dest);
+ void fastShrink(uint8 *src, uint32 width, uint32 height, uint32 scale, uint8 *dest);
+ int32 inRange(int32 a, int32 b, int32 c);
+ void fadePalette(void);
+
+ OSystem *_system;
+ ResMan *_resMan;
+ ObjectMan *_objMan;
+ Text *_textMan;
+
+ uint16 _currentScreen;
+ uint8 *_screenBuf;
+ uint8 *_screenGrid;
+ uint16 *_layerGrid[4];
+ uint8 *_layerBlocks[4];
+ uint8 *_parallax[2];
+ uint8 _rleBuffer[RLE_BUFFER_SIZE];
+ uint8 _shrinkBuffer[SHRINK_BUFFER_SIZE];
+ bool _fullRefresh;
+ uint16 _oldScrollX, _oldScrollY; // for drawing additional frames
+
+ uint32 _foreList[MAX_FORE];
+ uint32 _backList[MAX_BACK];
+ SortSpr _sortList[MAX_SORT];
+ uint8 _foreLength, _backLength, _sortLength;
+ uint16 _scrnSizeX, _scrnSizeY, _gridSizeX, _gridSizeY;
+
+ static RoomDef _roomDefTable[TOTAL_ROOMS]; // from ROOMS.C (not const, see fnSetParallax)
+
+ uint8 _targetPalette[256 * 4];
+ uint8 _currentPalette[256 * 4]; // for fading
+ uint8 _fadingStep;
+ int8 _fadingDirection; // 1 for fade up, -1 for fade down
+ bool _isBlack; // if the logic already faded down the palette, this is set to show the
+ // mainloop that no further fading is necessary.
+};
+
+} // End of namespace Sword1
+
+#endif //BSSCREEN_H
+
diff --git a/engines/sword1/sound.cpp b/engines/sword1/sound.cpp
new file mode 100644
index 0000000000..5275c5683e
--- /dev/null
+++ b/engines/sword1/sound.cpp
@@ -0,0 +1,382 @@
+/* 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 "sword1/sound.h"
+#include "common/util.h"
+#include "sword1/resman.h"
+#include "sword1/logic.h"
+#include "sword1/sword1.h"
+
+#include "sound/mp3.h"
+#include "sound/vorbis.h"
+#include "sound/wave.h"
+
+namespace Sword1 {
+
+#define SOUND_SPEECH_ID 1
+#define SPEECH_FLAGS (Audio::Mixer::FLAG_16BITS | Audio::Mixer::FLAG_AUTOFREE | Audio::Mixer::FLAG_LITTLE_ENDIAN)
+
+Sound::Sound(const char *searchPath, Audio::Mixer *mixer, ResMan *pResMan) {
+ strcpy(_filePath, searchPath);
+ _mixer = mixer;
+ _resMan = pResMan;
+ _cowHeader = NULL;
+ _endOfQueue = 0;
+ _currentCowFile = 0;
+ _speechVolL = _speechVolR = _sfxVolL = _sfxVolR = 192;
+}
+
+Sound::~Sound(void) {
+ // clean up fx queue
+ _mixer->stopAll();
+ for (uint8 cnt = 0; cnt < _endOfQueue; cnt++)
+ if (_fxQueue[cnt].delay == 0)
+ _resMan->resClose(_fxList[_fxQueue[cnt].id].sampleId);
+ _endOfQueue = 0;
+ closeCowSystem();
+}
+
+int Sound::addToQueue(int32 fxNo) {
+ bool alreadyInQueue = false;
+ for (uint8 cnt = 0; (cnt < _endOfQueue) && (!alreadyInQueue); cnt++)
+ if (_fxQueue[cnt].id == (uint32)fxNo)
+ alreadyInQueue = true;
+ if (!alreadyInQueue) {
+ if (_endOfQueue == MAX_FXQ_LENGTH) {
+ warning("Sound queue overflow");
+ return 0;
+ }
+ if ((fxNo == 168) && (SwordEngine::_systemVars.isDemo)) {
+ // this sound doesn't exist in demo
+ return 0;
+ }
+ _resMan->resOpen(_fxList[fxNo].sampleId);
+ _fxQueue[_endOfQueue].id = fxNo;
+ if (_fxList[fxNo].type == FX_SPOT)
+ _fxQueue[_endOfQueue].delay = _fxList[fxNo].delay + 1;
+ else
+ _fxQueue[_endOfQueue].delay = 1;
+ _endOfQueue++;
+ return 1;
+ }
+ return 0;
+}
+
+void Sound::engine(void) {
+ // first of all, add any random sfx to the queue...
+ for (uint16 cnt = 0; cnt < TOTAL_FX_PER_ROOM; cnt++) {
+ uint16 fxNo = _roomsFixedFx[Logic::_scriptVars[SCREEN]][cnt];
+ if (fxNo) {
+ if (_fxList[fxNo].type == FX_RANDOM) {
+ if (_rnd.getRandomNumber(_fxList[fxNo].delay) == 0)
+ addToQueue(fxNo);
+ }
+ } else
+ break;
+ }
+ // now process the queue
+ for (uint8 cnt2 = 0; cnt2 < _endOfQueue; cnt2++) {
+ if (_fxQueue[cnt2].delay > 0) {
+ _fxQueue[cnt2].delay--;
+ if (_fxQueue[cnt2].delay == 0)
+ playSample(&_fxQueue[cnt2]);
+ } else {
+ if (!_mixer->isSoundHandleActive(_fxQueue[cnt2].handle)) { // sound finished
+ _resMan->resClose(_fxList[_fxQueue[cnt2].id].sampleId);
+ if (cnt2 != _endOfQueue-1)
+ _fxQueue[cnt2] = _fxQueue[_endOfQueue - 1];
+ _endOfQueue--;
+ }
+ }
+ }
+}
+
+void Sound::fnStopFx(int32 fxNo) {
+ _mixer->stopID(fxNo);
+ for (uint8 cnt = 0; cnt < _endOfQueue; cnt++)
+ if (_fxQueue[cnt].id == (uint32)fxNo) {
+ if (!_fxQueue[cnt].delay) // sound was started
+ _resMan->resClose(_fxList[_fxQueue[cnt].id].sampleId);
+ if (cnt != _endOfQueue-1)
+ _fxQueue[cnt] = _fxQueue[_endOfQueue-1];
+ _endOfQueue--;
+ return ;
+ }
+ debug(8, "fnStopFx: id not found in queue");
+}
+
+bool Sound::amISpeaking(void) {
+ _waveVolPos++;
+ return _waveVolume[_waveVolPos - 1];
+}
+
+bool Sound::speechFinished(void) {
+ return !_mixer->isSoundHandleActive(_speechHandle);
+}
+
+void Sound::newScreen(uint32 screen) {
+ if (_currentCowFile != SwordEngine::_systemVars.currentCD) {
+ if (_currentCowFile)
+ closeCowSystem();
+ initCowSystem();
+ }
+}
+
+void Sound::quitScreen(void) {
+ // stop all running SFX
+ while (_endOfQueue)
+ fnStopFx(_fxQueue[0].id);
+}
+
+void Sound::playSample(QueueElement *elem) {
+ uint8 *sampleData = (uint8*)_resMan->fetchRes(_fxList[elem->id].sampleId);
+ for (uint16 cnt = 0; cnt < MAX_ROOMS_PER_FX; cnt++) {
+ if (_fxList[elem->id].roomVolList[cnt].roomNo) {
+ if ((_fxList[elem->id].roomVolList[cnt].roomNo == (int)Logic::_scriptVars[SCREEN]) ||
+ (_fxList[elem->id].roomVolList[cnt].roomNo == -1)) {
+
+ uint8 volL = (_fxList[elem->id].roomVolList[cnt].leftVol * 10 * _sfxVolL) / 255;
+ uint8 volR = (_fxList[elem->id].roomVolList[cnt].rightVol * 10 * _sfxVolR) / 255;
+ int8 pan = (volR - volL) / 2;
+ uint8 volume = (volR + volL) / 2;
+ uint32 size = READ_LE_UINT32(sampleData + 0x28);
+ uint8 flags;
+ if (READ_LE_UINT16(sampleData + 0x22) == 16)
+ flags = Audio::Mixer::FLAG_16BITS | Audio::Mixer::FLAG_LITTLE_ENDIAN;
+ else
+ flags = Audio::Mixer::FLAG_UNSIGNED;
+ if (READ_LE_UINT16(sampleData + 0x16) == 2)
+ flags |= Audio::Mixer::FLAG_STEREO;
+ if (_fxList[elem->id].type == FX_LOOP)
+ flags |= Audio::Mixer::FLAG_LOOP;
+ _mixer->playRaw(&elem->handle, sampleData + 0x2C, size, 11025, flags, elem->id, volume, pan);
+ }
+ } else
+ break;
+ }
+}
+
+bool Sound::startSpeech(uint16 roomNo, uint16 localNo) {
+ if (_cowHeader == NULL) {
+ warning("Sound::startSpeech: COW file isn't open!");
+ return false;
+ }
+
+ uint32 locIndex = _cowHeader[roomNo] >> 2;
+ uint32 sampleSize = _cowHeader[locIndex + (localNo * 2)];
+ uint32 index = _cowHeader[locIndex + (localNo * 2) - 1];
+ debug(6, "startSpeech(%d, %d): locIndex %d, sampleSize %d, index %d", roomNo, localNo, locIndex, sampleSize, index);
+ if (sampleSize) {
+ uint8 speechVol = (_speechVolR + _speechVolL) / 2;
+ int8 speechPan = (_speechVolR - _speechVolL) / 2;
+ if ((_cowMode == CowWave) || (_cowMode == CowDemo)) {
+ uint32 size;
+ int16 *data = uncompressSpeech(index + _cowHeaderSize, sampleSize, &size);
+ if (data)
+ _mixer->playRaw(&_speechHandle, data, size, 11025, SPEECH_FLAGS, SOUND_SPEECH_ID, speechVol, speechPan);
+ }
+#ifdef USE_MAD
+ else if (_cowMode == CowMp3) {
+ _cowFile.seek(index);
+ _mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_speechHandle, makeMP3Stream(&_cowFile, sampleSize), SOUND_SPEECH_ID, speechVol, speechPan);
+ // with compressed audio, we can't calculate the wave volume.
+ // so default to talking.
+ for (int cnt = 0; cnt < 480; cnt++)
+ _waveVolume[cnt] = true;
+ _waveVolPos = 0;
+ }
+#endif
+#ifdef USE_VORBIS
+ else if (_cowMode == CowVorbis) {
+ _cowFile.seek(index);
+ _mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_speechHandle, makeVorbisStream(&_cowFile, sampleSize), SOUND_SPEECH_ID, speechVol, speechPan);
+ for (int cnt = 0; cnt < 480; cnt++)
+ _waveVolume[cnt] = true;
+ _waveVolPos = 0;
+ }
+#endif
+ return true;
+ } else
+ return false;
+}
+
+int16 *Sound::uncompressSpeech(uint32 index, uint32 cSize, uint32 *size) {
+ uint8 *fBuf = (uint8*)malloc(cSize);
+ _cowFile.seek(index);
+ _cowFile.read(fBuf, cSize);
+ uint32 headerPos = 0;
+
+ // TODO: use loadWAVFromStream to load the WAVE data!
+ /*
+ int rate, size;
+ bye flags;
+ Common::MemoryReadStream stream(fBuf, cSize);
+ isValidWAV = loadWAVFromStream(stream, size, rate, flags);
+ */
+
+ while ((READ_BE_UINT32(fBuf + headerPos) != 'data') && (headerPos < 100))
+ headerPos++;
+ if (headerPos < 100) {
+ int32 resSize;
+ headerPos += 4; // skip 'data' tag
+ if (_cowMode != CowDemo) {
+ resSize = READ_LE_UINT32(fBuf + headerPos) >> 1;
+ headerPos += 4;
+ } else {
+ // the demo speech files have the uncompressed size embedded
+ // in the compressed stream *sigh*
+ if (READ_LE_UINT16(fBuf + headerPos) == 1) {
+ resSize = READ_LE_UINT16(fBuf + headerPos + 2);
+ resSize |= READ_LE_UINT16(fBuf + headerPos + 6) << 16;
+ } else
+ resSize = READ_LE_UINT32(fBuf + headerPos + 2);
+ resSize >>= 1;
+ }
+ assert(!(headerPos & 1));
+ int16 *srcData = (int16*)fBuf;
+ uint32 srcPos = headerPos >> 1;
+ cSize /= 2;
+ uint32 dstPos = 0;
+ /* alloc 200 additional bytes, as the demo sometimes has ASCII junk
+ at the end of the wave data */
+ int16 *dstData = (int16*)malloc(resSize * 2 + 200);
+ while (srcPos < cSize) {
+ int16 length = (int16)READ_LE_UINT16(srcData + srcPos);
+ srcPos++;
+ if (length < 0) {
+ length = -length;
+ for (uint16 cnt = 0; cnt < (uint16)length; cnt++)
+ dstData[dstPos++] = srcData[srcPos];
+ srcPos++;
+ } else {
+ memcpy(dstData + dstPos, srcData + srcPos, length * 2);
+ dstPos += length;
+ srcPos += length;
+ }
+ }
+ assert(dstPos < (uint32)resSize + 100);
+ if (_cowMode == CowDemo) // demo has wave output size embedded in the compressed data
+ *(uint32*)dstData = 0;
+ free(fBuf);
+ *size = resSize * 2;
+ calcWaveVolume(dstData, resSize);
+ return dstData;
+ } else {
+ free(fBuf);
+ warning("Sound::uncompressSpeech(): DATA tag not found in wave header");
+ *size = 0;
+ return NULL;
+ }
+}
+
+void Sound::calcWaveVolume(int16 *data, uint32 length) {
+ int16 *blkPos = data + 918;
+ uint32 cnt;
+ for (cnt = 0; cnt < WAVE_VOL_TAB_LENGTH; cnt++)
+ _waveVolume[cnt] = false;
+ _waveVolPos = 0;
+ for (uint32 blkCnt = 1; blkCnt < length / 918; blkCnt++) {
+ if (blkCnt >= WAVE_VOL_TAB_LENGTH) {
+ warning("Wave vol tab too small.");
+ return;
+ }
+ int32 average = 0;
+ for (cnt = 0; cnt < 918; cnt++)
+ average += blkPos[cnt];
+ average /= 918;
+ uint32 diff = 0;
+ for (cnt = 0; cnt < 918; cnt++) {
+ int16 smpDiff = *blkPos - average;
+ diff += (uint32)ABS(smpDiff);
+ blkPos++;
+ }
+ if (diff > WAVE_VOL_THRESHOLD)
+ _waveVolume[blkCnt - 1] = true;
+ }
+}
+
+void Sound::stopSpeech(void) {
+ _mixer->stopID(SOUND_SPEECH_ID);
+}
+
+void Sound::initCowSystem(void) {
+ char cowName[25];
+ /* look for speech1/2.clu in the data dir
+ and speech/speech.clu (running from cd or using cd layout)
+ */
+#ifdef USE_MAD
+ sprintf(cowName, "SPEECH%d.CL3", SwordEngine::_systemVars.currentCD);
+ _cowFile.open(cowName);
+ if (_cowFile.isOpen()) {
+ debug(1, "Using MP3 compressed Speech Cluster");
+ _cowMode = CowMp3;
+ }
+#endif
+#ifdef USE_VORBIS
+ if (!_cowFile.isOpen()) {
+ sprintf(cowName, "SPEECH%d.CLV", SwordEngine::_systemVars.currentCD);
+ _cowFile.open(cowName);
+ if (_cowFile.isOpen()) {
+ debug(1, "Using Vorbis compressed Speech Cluster");
+ _cowMode = CowVorbis;
+ }
+ }
+#endif
+ if (!_cowFile.isOpen()) {
+ sprintf(cowName, "SPEECH%d.CLU", SwordEngine::_systemVars.currentCD);
+ _cowFile.open(cowName);
+ if (!_cowFile.isOpen()) {
+ _cowFile.open("speech.clu");
+ }
+ debug(1, "Using uncompressed Speech Cluster");
+ _cowMode = CowWave;
+ }
+ if (!_cowFile.isOpen())
+ _cowFile.open("speech.clu");
+ if (!_cowFile.isOpen()) {
+ _cowFile.open("cows.mad");
+ if (_cowFile.isOpen())
+ _cowMode = CowDemo;
+ }
+ if (_cowFile.isOpen()) {
+ _cowHeaderSize = _cowFile.readUint32LE();
+ _cowHeader = (uint32*)malloc(_cowHeaderSize);
+ if (_cowHeaderSize & 3)
+ error("Unexpected cow header size %d", _cowHeaderSize);
+ for (uint32 cnt = 0; cnt < (_cowHeaderSize / 4) - 1; cnt++)
+ _cowHeader[cnt] = _cowFile.readUint32LE();
+ _currentCowFile = SwordEngine::_systemVars.currentCD;
+ } else
+ warning("Sound::initCowSystem: Can't open SPEECH%d.CLU", SwordEngine::_systemVars.currentCD);
+}
+
+void Sound::closeCowSystem(void) {
+ if (_cowFile.isOpen())
+ _cowFile.close();
+ if (_cowHeader)
+ free(_cowHeader);
+ _cowHeader = NULL;
+ _currentCowFile = 0;
+}
+
+} // End of namespace Sword1
diff --git a/engines/sword1/sound.h b/engines/sword1/sound.h
new file mode 100644
index 0000000000..10fed8b33c
--- /dev/null
+++ b/engines/sword1/sound.h
@@ -0,0 +1,127 @@
+/* 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 BSSOUND_H
+#define BSSOUND_H
+
+#include "sword1/object.h"
+#include "sword1/sworddefs.h"
+#include "common/file.h"
+#include "sound/mixer.h"
+#include "common/util.h"
+
+namespace Audio {
+ class Mixer;
+}
+
+namespace Sword1 {
+
+#define TOTAL_FX_PER_ROOM 7 // total loop & random fx per room (see fx_list.c)
+#define MAX_ROOMS_PER_FX 7 // max no. of rooms in the fx's room,vol list
+#define MAX_FXQ_LENGTH 32 // max length of sound queue - ie. max number of fx that can be stored up/playing together
+
+#define FX_SPOT 1
+#define FX_LOOP 2
+#define FX_RANDOM 3
+
+struct QueueElement {
+ uint32 id, delay;
+ Audio::SoundHandle handle;
+};
+
+struct RoomVol {
+ int32 roomNo, leftVol, rightVol;
+};
+
+struct FxDef {
+ uint32 sampleId, type, delay;
+ RoomVol roomVolList[MAX_ROOMS_PER_FX];
+};
+
+class ResMan;
+#define WAVE_VOL_TAB_LENGTH 480
+#define WAVE_VOL_THRESHOLD 190000 //120000
+
+enum CowMode {
+ CowWave = 0,
+ CowMp3,
+ CowVorbis,
+ CowDemo
+};
+
+class Sound {
+public:
+ Sound(const char *searchPath, Audio::Mixer *mixer, ResMan *pResMan);
+ ~Sound(void);
+ void setSpeechVol(uint8 volL, uint8 volR) { _speechVolL = volL; _speechVolR = volR; };
+ void setSfxVol(uint8 volL, uint8 volR) { _sfxVolL = volL; _sfxVolR = volR; };
+ void giveSpeechVol(uint8 *volL, uint8 *volR) { *volL = _speechVolL; *volR = _speechVolR; };
+ void giveSfxVol(uint8 *volL, uint8 *volR) { *volL = _sfxVolL; *volR = _sfxVolR; };
+ void newScreen(uint32 screen);
+ void quitScreen(void);
+ void closeCowSystem(void);
+
+ bool startSpeech(uint16 roomNo, uint16 localNo);
+ bool speechFinished(void);
+ void stopSpeech();
+ bool amISpeaking(void);
+
+ void fnStopFx(int32 fxNo);
+ int addToQueue(int32 fxNo);
+
+ void engine(void);
+
+private:
+ uint8 _sfxVolL, _sfxVolR, _speechVolL, _speechVolR;
+ void playSample(QueueElement *elem);
+ void initCowSystem(void);
+
+ int16 *uncompressSpeech(uint32 index, uint32 cSize, uint32 *size);
+ void calcWaveVolume(int16 *data, uint32 length);
+ bool _waveVolume[WAVE_VOL_TAB_LENGTH];
+ uint16 _waveVolPos;
+ Common::File _cowFile;
+ uint32 *_cowHeader;
+ uint32 _cowHeaderSize;
+ uint8 _currentCowFile;
+ CowMode _cowMode;
+ Audio::SoundHandle _speechHandle, _fxHandle;
+ Common::RandomSource _rnd;
+
+ QueueElement _fxQueue[MAX_FXQ_LENGTH];
+ uint8 _endOfQueue;
+ Audio::Mixer *_mixer;
+ ResMan *_resMan;
+ char _filePath[100];
+ static const char _musicList[270];
+ static const uint16 _roomsFixedFx[TOTAL_ROOMS][TOTAL_FX_PER_ROOM];
+#ifdef PALMOS_68K
+public:
+ static const FxDef *_fxList;
+#else
+ static const FxDef _fxList[312];
+#endif
+};
+
+} // End of namespace Sword1
+
+#endif //BSSOUND_H
diff --git a/engines/sword1/staticres.cpp b/engines/sword1/staticres.cpp
new file mode 100644
index 0000000000..9991d0e826
--- /dev/null
+++ b/engines/sword1/staticres.cpp
@@ -0,0 +1,7168 @@
+/* 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 "sword1/sworddefs.h"
+#include "sword1/swordres.h"
+#include "sword1/screen.h"
+#include "sword1/resman.h"
+#include "sword1/objectman.h"
+#include "sword1/menu.h"
+#include "sword1/music.h"
+#include "sword1/sound.h"
+#include "sword1/sword1.h"
+#include "sword1/logic.h"
+
+namespace Sword1 {
+
+const uint8 SwordEngine::_cdList[TOTAL_SECTIONS] = {
+ 0, // 0 inventory
+
+ 1, // 1 PARIS 1
+ 1, // 2
+ 1, // 3
+ 1, // 4
+ 1, // 5
+ 1, // 6
+ 1, // 7
+ 1, // 8
+
+ 1, // 9 PARIS 2
+ 1, // 10
+ 1, // 11
+ 1, // 12
+ 1, // 13
+ 1, // 14
+ 1, // 15
+ 1, // 16
+ 1, // 17
+ 1, // 18
+
+ 2, // 19 IRELAND
+ 2, // 20
+ 2, // 21
+ 2, // 22
+ 2, // 23
+ 2, // 24
+ 2, // 25
+ 2, // 26
+
+ 1, // 27 PARIS 3
+ 1, // 28
+ 1, // 29
+ 1, // 30 - Heart Monitor
+ 1, // 31
+ 1, // 32
+ 1, // 33
+ 1, // 34
+ 1, // 35
+
+ 1, // 36 PARIS 4
+ 1, // 37
+ 1, // 38
+ 1, // 39
+ 1, // 40
+ 1, // 41
+ 1, // 42
+ 1, // 43
+ 0, // 44 <NOT USED>
+
+ 2, // 45 SYRIA
+ 1, // 46 PARIS 4
+ 2, // 47
+ 1, // 48 PARIS 4
+ 2, // 49
+ 2, // 50
+ 0, // 51 <NOT USED>
+ 0, // 52 <NOT USED>
+ 2, // 53
+ 2, // 54
+ 2, // 55
+
+ 2, // 56 SPAIN
+ 2, // 57
+ 2, // 58
+ 2, // 59
+ 2, // 60
+ 2, // 61
+ 2, // 62
+
+ 2, // 63 NIGHT TRAIN
+ 0, // 64 <NOT USED>
+ 2, // 65
+ 2, // 66
+ 2, // 67
+ 0, // 68 <NOT USED>
+ 2, // 69
+ 0, // 70 <NOT USED>
+
+ 2, // 71 SCOTLAND
+ 2, // 72
+ 2, // 73
+ 2, // 74 END SEQUENCE IN SECRET_CRYPT
+ 2, // 75
+ 2, // 76
+ 2, // 77
+ 2, // 78
+ 2, // 79
+
+ 1, // 80 PARIS MAP
+
+ 1, // 81 Full-screen for "Asstair" in Paris2
+
+ 2, // 82 Full-screen BRITMAP in sc55 (Syrian Cave)
+ 0, // 83 <NOT USED>
+ 0, // 84 <NOT USED>
+ 0, // 85 <NOT USED>
+
+ 1, // 86 EUROPE MAP
+ 1, // 87 fudged in for normal window (sc48)
+ 1, // 88 fudged in for filtered window (sc48)
+ 0, // 89 <NOT USED>
+
+ 0, // 90 PHONE SCREEN
+ 0, // 91 ENVELOPE SCREEN
+ 1, // 92 fudged in for George close-up surprised in sc17 wardrobe
+ 1, // 93 fudged in for George close-up inquisitive in sc17 wardrobe
+ 1, // 94 fudged in for George close-up in sc29 sarcophagus
+ 1, // 95 fudged in for George close-up in sc29 sarcophagus
+ 1, // 96 fudged in for chalice close-up from sc42
+ 0, // 97 <NOT USED>
+ 0, // 98 <NOT USED>
+ 0, // 99 MESSAGE SCREEN (BLANK)
+
+ 0, // 100
+ 0, // 101
+ 0, // 102
+ 0, // 103
+ 0, // 104
+ 0, // 105
+ 0, // 106
+ 0, // 107
+ 0, // 108
+ 0, // 109
+
+ 0, // 110
+ 0, // 111
+ 0, // 112
+ 0, // 113
+ 0, // 114
+ 0, // 115
+ 0, // 116
+ 0, // 117
+ 0, // 118
+ 0, // 119
+
+ 0, // 120
+ 0, // 121
+ 0, // 122
+ 0, // 123
+ 0, // 124
+ 0, // 125
+ 0, // 126
+ 0, // 127
+ 0, // 128 GEORGE'S GAME SECTION
+ 0, // 129 NICO'S TEXT - on both CD's
+
+ 0, // 130
+ 1, // 131 BENOIR'S TEXT - on CD1
+ 0, // 132
+ 1, // 133 ROSSO'S TEXT - on CD1
+ 0, // 134
+ 0, // 135
+ 0, // 136
+ 0, // 137
+ 0, // 138
+ 0, // 139
+
+ 0, // 140
+ 0, // 141
+ 0, // 142
+ 0, // 143
+ 0, // 144
+ 1, // 145 MOUE'S TEXT - on CD1
+ 1, // 146 ALBERT'S TEXT - on CD1
+};
+
+const MenuObject Menu::_objectDefs[TOTAL_pockets + 1] = {
+ { // 0 can't use
+ 0, 0, 0, 0, 0
+ },
+ { // 1 NEWSPAPER
+ menu_newspaper, // text_desc
+ ICON_NEWSPAPER, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_NEWSPAPER, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 2 HAZEL_WAND
+ menu_hazel_wand, // text_desc
+ ICON_HAZEL_WAND, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_HAZEL_WAND, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 3 BEER_TOWEL
+ 0, // text_desc - SEE MENU.SCR
+ ICON_BEER_TOWEL, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_BEER_TOWEL, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 4 HOTEL_KEY
+ menu_hotel_key, // text_desc
+ ICON_HOTEL_KEY, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_HOTEL_KEY, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 5 BALL
+ menu_ball, // text_desc
+ ICON_BALL, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_BALL, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 6 STATUETTE
+ menu_statuette, // text_desc
+ ICON_STATUETTE, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_STATUETTE, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 7 RED_NOSE
+ 0, // text_desc - SEE MENU.SCR
+ ICON_RED_NOSE, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_RED_NOSE, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 8 POLISHED_CHALICE
+ menu_polished_chalice, // text_desc
+ ICON_POLISHED_CHALICE, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_POLISHED_CHALICE, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 9 DOLLAR_BILL
+ menu_dollar_bill, // text_desc
+ ICON_DOLLAR_BILL, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_DOLLAR_BILL, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 10 PHOTO
+ menu_photograph, // text_desc
+ ICON_PHOTOGRAPH, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_PHOTOGRAPH, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 11 FLASHLIGHT
+ menu_flashlight, // text_desc
+ ICON_FLASHLIGHT, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_FLASHLIGHT, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 12 FUSE_WIRE
+ menu_fuse_wire, // text_desc
+ ICON_FUSE_WIRE, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_FUSE_WIRE, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 13 GEM
+ menu_gem, // text_desc
+ ICON_GEM, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_GEM, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 14 STATUETTE_PAINT
+ menu_statuette_paint, // text_desc
+ ICON_STATUETTE_PAINT, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_STATUETTE_PAINT, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 15 STICK
+ menu_stick, // text_desc
+ ICON_STICK, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_STICK, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 16 EXCAV_KEY
+ menu_excav_key, // text_desc
+ ICON_EXCAV_KEY, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_EXCAV_KEY, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 17 LAB_PASS
+ menu_lab_pass, // text_desc
+ ICON_LAB_PASS, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_LAB_PASS, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 18 LIFTING_KEYS
+ menu_lifting_keys, // text_desc
+ ICON_LIFTING_KEYS, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_LIFTING_KEYS, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 19 MANUSCRIPT
+ menu_manuscript, // text_desc
+ ICON_MANUSCRIPT, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_MANUSCRIPT, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 20 MATCH_BOOK
+ menu_match_book, // text_desc
+ ICON_MATCHBOOK, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_MATCHBOOK, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 21 SUIT_MATERIAL
+ menu_suit_material, // text_desc
+ ICON_SUIT_MATERIAL, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_SUIT_MATERIAL, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 22 STICK_TOWEL
+ menu_stick_towel, // text_desc
+ ICON_STICK_TOWEL, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_STICK_TOWEL, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 23 PLASTER
+ menu_plaster, // text_desc
+ ICON_PLASTER, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_PLASTER, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 24 PRESSURE_GAUGE
+ menu_pressure_gauge, // text_desc
+ ICON_PRESSURE_GAUGE, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_PRESSURE_GAUGE, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 25 RAILWAY_TICKET
+ menu_railway_ticket, // text_desc
+ ICON_RAILWAY_TICKET, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_RAILWAY_TICKET, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 26 BUZZER
+ menu_buzzer, // text_desc
+ ICON_BUZZER, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_BUZZER, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 27 ROSSO_CARD
+ menu_rosso_card, // text_desc
+ ICON_ROSSO_CARD, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_ROSSO_CARD, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 28 TOILET_KEY
+ menu_toilet_key, // text_desc
+ ICON_TOILET_KEY, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_TOILET_KEY, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 29 SOAP
+ menu_soap, // text_desc
+ ICON_SOAP, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_SOAP, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 30 STONE_KEY
+ menu_stone_key, // text_desc
+ ICON_STONE_KEY, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_STONE_KEY, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 31 CHALICE
+ menu_chalice, // text_desc
+ ICON_CHALICE, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_CHALICE, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 32 TISSUE
+ menu_tissue, // text_desc
+ ICON_TISSUE, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_TISSUE, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 33 TOILET_BRUSH
+ menu_toilet_brush, // text_desc
+ ICON_TOILET_BRUSH, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_TOILET_BRUSH, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 34 TOILET_CHAIN
+ menu_toilet_chain, // text_desc
+ ICON_TOILET_CHAIN, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_TOILET_CHAIN, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 35 TOWEL
+ menu_towel, // text_desc
+ ICON_TOWEL, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_TOWEL, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 36 TRIPOD
+ menu_tripod, // text_desc
+ ICON_TRIPOD, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_TRIPOD, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 37 LENS
+ menu_lens, // text_desc
+ ICON_LENS, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_LENS, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 38 MIRROR
+ menu_mirror, // text_desc
+ ICON_MIRROR, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_MIRROR, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 39 TOWEL_CUT
+ menu_towel_cut, // text_desc
+ ICON_TOWEL_CUT, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_TOWEL_CUT, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 40 BIBLE
+ menu_bible, // text_desc
+ ICON_BIBLE, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_BIBLE, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 41 TISSUE_CHARRED
+ menu_tissue_charred, // text_desc
+ ICON_TISSUE_CHARRED, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_TISSUE_CHARRED, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 42 FALSE_KEY
+ menu_false_key, // text_desc
+ ICON_FALSE_KEY, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_FALSE_KEY, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 43 PAINTED_KEY - looks identical to excav key, so uses that icon & luggage
+ menu_painted_key, // text_desc
+ ICON_EXCAV_KEY, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_EXCAV_KEY, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 44 KEYRING
+ 0, // text_desc - SEE MENU.SCR
+ ICON_KEYRING, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_KEYRING, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 45 SOAP_IMP
+ menu_soap_imp, // text_desc
+ ICON_SOAP_IMP, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_SOAP_IMP, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 46 SOAP_PLAS
+ menu_soap_plas, // text_desc
+ ICON_SOAP_PLAS, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_SOAP_PLAS, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 47 COG_1 - the larger cog with spindle attached
+ menu_cog_1, // text_desc
+ ICON_COG_1, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_COG_1, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 48 COG_2 - the smaller cog, found in the rubble
+ menu_cog_2, // text_desc
+ ICON_COG_2, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_COG_2, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 49 HANDLE
+ menu_handle, // text_desc
+ ICON_HANDLE, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_HANDLE, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 50 COIN
+ menu_coin, // text_desc
+ ICON_COIN, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_COIN, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 51 BIRO
+ menu_biro, // text_desc
+ ICON_BIRO, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_BIRO, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ },
+ { // 52 PIPE
+ menu_pipe, // text_desc
+ ICON_PIPE, // big_icon_res
+ 0, // big_icon_frame
+ LUGG_PIPE, // luggage_icon_res
+ SCR_icon_combine_script, // use_script
+ }
+};
+
+const Subject Menu::_subjectList[TOTAL_subjects] = {
+ { // 256
+ 0, // subject_res
+ 0 // subject_frame
+ },
+ { // 257
+ ICON_BEER, // subject_res
+ 0 // subject_frame
+ },
+ { // 258
+ ICON_CASTLE, // subject_res
+ 0 // subject_frame
+ },
+ { // 259
+ ICON_YES, // subject_res
+ 0 // subject_frame
+ },
+ { // 260
+ ICON_NO, // subject_res
+ 0 // subject_frame
+ },
+ { // 261
+ ICON_PEAGRAM, // subject_res
+ 0 // subject_frame
+ },
+ { // 262
+ ICON_DIG, // subject_res
+ 0 // subject_frame
+ },
+ { // 263
+ ICON_SEAN, // subject_res
+ 0 // subject_frame
+ },
+ { // 264
+ ICON_GEM, // subject_res
+ 0 // subject_frame
+ },
+ { // 265
+ ICON_TEMPLARS, // subject_res
+ 0 // subject_frame
+ },
+ { // 266
+ ICON_LEPRECHAUN, // subject_res
+ 0 // subject_frame
+ },
+ { // 267
+ ICON_GOODBYE, // subject_res
+ 0 // subject_frame
+ },
+ { // 268
+ ICON_GEORGE, // subject_res
+ 0 // subject_frame
+ },
+ { // 269
+ ICON_ROSSO, // subject_res
+ 0 // subject_frame
+ },
+ { // 270
+ ICON_GHOST, // subject_res
+ 0 // subject_frame
+ },
+ { // 271
+ ICON_CLOWN, // subject_res
+ 0 // subject_frame
+ },
+ { // 272
+ ICON_CAR, // subject_res
+ 0 // subject_frame
+ },
+ { // 273
+ ICON_MOUE, // subject_res
+ 0 // subject_frame
+ },
+ { // 274
+ ICON_NICO, // subject_res
+ 0 // subject_frame
+ },
+ { // 275
+ ICON_MOB, // subject_res
+ 0 // subject_frame
+ },
+ { // 276
+ ICON_CHANTELLE, // subject_res
+ 0 // subject_frame
+ },
+ { // 277
+ ICON_PLANTARD, // subject_res
+ 0 // subject_frame
+ },
+ { // 278
+ ICON_JACKET, // subject_res
+ 0 // subject_frame
+ },
+ { // 279
+ ICON_BRIEFCASE, // subject_res
+ 0 // subject_frame
+ },
+ {
+ 0, //ICON_GLASS, // subject_res
+ 0 // subject_frame
+ },
+ { // 281
+ ICON_GLASS_EYE, // subject_res
+ 0 // subject_frame
+ },
+ { // 282
+ ICON_BULL, // subject_res
+ 0 // subject_frame
+ },
+ { // 283
+ ICON_KLAUSNER, // subject_res
+ 0 // subject_frame
+ },
+ { // 284
+ 0, //ICON_LOOM, // subject_res
+ 0 // subject_frame
+ },
+ { // 285
+ ICON_ULTAR, // subject_res
+ 0 // subject_frame
+ },
+ { // 286
+ ICON_PHONE, // subject_res
+ 0 // subject_frame
+ },
+ { // 287
+ ICON_PHOTOGRAPH, // subject_res
+ 0 // subject_frame
+ },
+ { // 288
+ ICON_CREST, // subject_res
+ 0 // subject_frame
+ },
+ { // 289
+ ICON_LOBINEAU, // subject_res
+ 0 // subject_frame
+ },
+ { // 290
+ ICON_BOOK, // subject_res
+ 0 // subject_frame
+ },
+ { // 291 (SNARE)
+ ICON_FUSE_WIRE, // subject_res
+ 0 // subject_frame
+ },
+ { // 292
+ ICON_LEARY, // subject_res
+ 0 // subject_frame
+ },
+ { // 293
+ ICON_LADDER, // subject_res
+ 0 // subject_frame
+ },
+ { // 294
+ ICON_GOAT, // subject_res
+ 0 // subject_frame
+ },
+ { // 295
+ ICON_TOOLBOX, // subject_res
+ 0 // subject_frame
+ },
+ { // 296
+ ICON_PACKAGE, // subject_res
+ 0 // subject_frame
+ },
+ { // 297
+ ICON_FISH, // subject_res
+ 0 // subject_frame
+ },
+ { // 298
+ ICON_NEJO, // subject_res
+ 0 // subject_frame
+ },
+ { // 299
+ ICON_CAT, // subject_res
+ 0 // subject_frame
+ },
+ { // 300
+ ICON_AYUB, // subject_res
+ 0 // subject_frame
+ },
+ { // 301
+ ICON_STATUETTE, // subject_res
+ 0 // subject_frame
+ },
+ { // 302
+ ICON_NEJO_STALL, // subject_res
+ 0 // subject_frame
+ },
+ { // 303
+ ICON_TEMPLARS, // subject_res
+ 0 // subject_frame
+ },
+ { // 304
+ ICON_ARTO, // subject_res
+ 0 // subject_frame
+ },
+ { // 305
+ ICON_HENDERSONS, // subject_res
+ 0 // subject_frame
+ },
+ { // 306
+ ICON_CLUB, // subject_res
+ 0 // subject_frame
+ },
+ { // 307
+ ICON_SIGN, // subject_res
+ 0 // subject_frame
+ },
+ { // 308
+ ICON_TAXI, // subject_res
+ 0 // subject_frame
+ },
+ { // 309
+ ICON_BULLS_HEAD, // subject_res
+ 0 // subject_frame
+ },
+ { // 310
+ ICON_DUANE, // subject_res
+ 0 // subject_frame
+ },
+ { // 311
+ ICON_PEARL, // subject_res
+ 0 // subject_frame
+ },
+ { // 312
+ ICON_TRUTH, // subject_res
+ 0 // subject_frame
+ },
+ { // 313
+ ICON_LIE, // subject_res
+ 0 // subject_frame
+ },
+ { // 314
+ 0, //ICON_SUBJECT,// subject_res
+ 0 // subject_frame
+ },
+ { // 315 KEY
+ ICON_HOTEL_KEY, // subject_res
+ 0 // subject_frame
+ },
+ { // 316
+ ICON_FLOWERS, // subject_res
+ 0 // subject_frame
+ },
+ { // 317
+ ICON_BUST, // subject_res
+ 0 // subject_frame
+ },
+ { // 318
+ ICON_MANUSCRIPT, // subject_res
+ 0 // subject_frame
+ },
+ { // 319
+ ICON_WEASEL, // subject_res
+ 0 // subject_frame
+ },
+ { // 320
+ ICON_BANANA, // subject_res
+ 0 // subject_frame
+ },
+ { // 321
+ ICON_WEAVER, // subject_res
+ 0 // subject_frame
+ },
+ { // 322
+ ICON_KNIGHT, // subject_res
+ 0 // subject_frame
+ },
+ { // 323
+ ICON_QUEEN, // subject_res
+ 0 // subject_frame
+ },
+ { // 324
+ ICON_PIERMONT, // subject_res
+ 0 // subject_frame
+ },
+ { // 325
+ ICON_BALL, // subject_res
+ 0 // subject_frame
+ },
+ { // 326
+ ICON_COUNTESS, // subject_res
+ 0 // subject_frame
+ },
+ { // 327
+ ICON_MARQUET, // subject_res
+ 0 // subject_frame
+ },
+ { // 328
+ ICON_SAFE, // subject_res
+ 0 // subject_frame
+ },
+ { // 329
+ ICON_COINS, // subject_res
+ 0 // subject_frame
+ },
+ { // 330
+ ICON_CHESS_SET, // subject_res
+ 0 // subject_frame
+ },
+ { // 331
+ ICON_TOMB, // subject_res
+ 0 // subject_frame
+ },
+ { // 332
+ ICON_CANDLE, // subject_res
+ 0 // subject_frame
+ },
+ { // 333
+ ICON_MARY, // subject_res
+ 0 // subject_frame
+ },
+ { // 334
+ ICON_CHESSBOARD, // subject_res
+ 0 // subject_frame
+ },
+ { // 335
+ ICON_TRIPOD, // subject_res
+ 0 // subject_frame
+ },
+ { // 336
+ ICON_POTS, // subject_res
+ 0 // subject_frame
+ },
+ { // 337
+ ICON_ALARM, // subject_res
+ 0 // subject_frame
+ },
+ { // 338
+ ICON_BAPHOMET, // subject_res
+ 0 // subject_frame
+ },
+ { // 339
+ ICON_PHRASE, // subject_res
+ 0 // subject_frame
+ },
+ { // 340
+ ICON_POLISHED_CHALICE, // subject_res
+ 0 // subject_frame
+ },
+ { // 341
+ ICON_NURSE, // subject_res
+ 0 // subject_frame
+ },
+ { // 342
+ ICON_WELL, // subject_res
+ 0 // subject_frame
+ },
+ { // 343
+ ICON_WELL2, // subject_res
+ 0 // subject_frame
+ },
+ { // 344
+ ICON_HAZEL_WAND, // subject_res
+ 0 // subject_frame
+ },
+ { // 345
+ ICON_CHALICE, // subject_res
+ 0 // subject_frame
+ },
+ { // 346
+ ICON_MR_SHINY, // subject_res
+ 0 // subject_frame
+ },
+ { // 347
+ ICON_PHOTOGRAPH, // subject_res
+ 0 // subject_frame
+ },
+ { // 348
+ ICON_PHILIPPE, // subject_res
+ 0 // subject_frame
+ },
+ { // 349
+ ICON_ERIC, // subject_res
+ 0 // subject_frame
+ },
+ { // 350
+ ICON_ROZZER, // subject_res
+ 0 // subject_frame
+ },
+ { // 351
+ ICON_JUGGLER, // subject_res
+ 0 // subject_frame
+ },
+ { // 352
+ ICON_PRIEST, // subject_res
+ 0 // subject_frame
+ },
+ { // 353
+ ICON_WINDOW, // subject_res
+ 0 // subject_frame
+ },
+ { // 354
+ ICON_SCROLL, // subject_res
+ 0 // subject_frame
+ },
+ { // 355
+ ICON_PRESSURE_GAUGE, // subject_res
+ 0 // subject_frame
+ },
+ { // 356
+ ICON_RENEE, // subject_res
+ 0 // subject_frame
+ },
+ { // 357
+ ICON_CHURCH, // subject_res
+ 0 // subject_frame
+ },
+ { // 358
+ ICON_EKLUND, // subject_res
+ 0 // subject_frame
+ },
+ { // 359
+ ICON_FORTUNE, // subject_res
+ 0 // subject_frame
+ },
+ { // 360
+ ICON_PAINTER, // subject_res
+ 0 // subject_frame
+ },
+ { // 361
+ 0, //ICON_SWORD, // subject_res
+ 0 // subject_frame
+ },
+ { // 362
+ ICON_GUARD, // subject_res
+ 0 // subject_frame
+ },
+ { // 363
+ ICON_THERMOSTAT, // subject_res
+ 0 // subject_frame
+ },
+ { // 364
+ ICON_TOILET, // subject_res
+ 0 // subject_frame
+ },
+ { // 365
+ ICON_MONTFAUCON, // subject_res
+ 0 // subject_frame
+ },
+ { // 366
+ ICON_ASSASSIN, // subject_res
+ 0 // subject_frame
+ },
+ { // 367
+ ICON_HASH, // subject_res
+ 0 // subject_frame
+ },
+ { // 368
+ ICON_DOG, // subject_res
+ 0 // subject_frame
+ },
+ { // 369
+ ICON_AYUB, // subject_res
+ 0 // subject_frame
+ },
+ { // 370
+ ICON_LENS, // subject_res
+ 0 // subject_frame
+ },
+ { // 371
+ ICON_RED_NOSE, // subject_res
+ 0 // subject_frame
+ },
+ { // 372
+ 0, // subject_res
+ 0 // subject_frame
+ },
+ { // 373
+ 0, // subject_res
+ 0 // subject_frame
+ },
+ { // 374
+ 0, // subject_res
+ 0 // subject_frame
+ }
+};
+
+const uint32 ResMan::_scriptList[TOTAL_SECTIONS] = { //a table of resource tags
+ SCRIPT0, // 0 STANDARD SCRIPTS
+
+ SCRIPT1, // 1 PARIS 1
+ SCRIPT2, // 2
+ SCRIPT3, // 3
+ SCRIPT4, // 4
+ SCRIPT5, // 5
+ SCRIPT6, // 6
+ SCRIPT7, // 7
+ SCRIPT8, // 8
+
+ SCRIPT9, // 9 PARIS 2
+ SCRIPT10, // 10
+ SCRIPT11, // 11
+ SCRIPT12, // 12
+ SCRIPT13, // 13
+ SCRIPT14, // 14
+ SCRIPT15, // 15
+ SCRIPT16, // 16
+ SCRIPT17, // 17
+ SCRIPT18, // 18
+
+ SCRIPT19, // 19 IRELAND
+ SCRIPT20, // 20
+ SCRIPT21, // 21
+ SCRIPT22, // 22
+ SCRIPT23, // 23
+ SCRIPT24, // 24
+ SCRIPT25, // 25
+ SCRIPT26, // 26
+
+ SCRIPT27, // 27 PARIS 3
+ SCRIPT28, // 28
+ SCRIPT29, // 29
+ 0, // 30
+ SCRIPT31, // 31
+ SCRIPT32, // 32
+ SCRIPT33, // 33
+ SCRIPT34, // 34
+ SCRIPT35, // 35
+
+ SCRIPT36, // 36 PARIS 4
+ SCRIPT37, // 37
+ SCRIPT38, // 38
+ SCRIPT39, // 39
+ SCRIPT40, // 40
+ SCRIPT41, // 41
+ SCRIPT42, // 42
+ SCRIPT43, // 43
+ 0, // 44
+
+ SCRIPT45, // 45 SYRIA
+ SCRIPT46, // 46 PARIS 4
+ SCRIPT47, // 47
+ SCRIPT48, // 48 PARIS 4
+ SCRIPT49, // 49
+ SCRIPT50, // 50
+ 0, // 51
+ 0, // 52
+ 0, // 53
+ SCRIPT54, // 54
+ SCRIPT55, // 55
+
+ SCRIPT56, // 56 SPAIN
+ SCRIPT57, // 57
+ SCRIPT58, // 58
+ SCRIPT59, // 59
+ SCRIPT60, // 60
+ SCRIPT61, // 61
+ SCRIPT62, // 62
+
+ SCRIPT63, // 63 NIGHT TRAIN
+ 0, // 64
+ SCRIPT65, // 65
+ SCRIPT66, // 66
+ SCRIPT67, // 67
+ 0, // 68
+ SCRIPT69, // 69
+ 0, // 70
+
+ SCRIPT71, // 71 SCOTLAND
+ SCRIPT72, // 72
+ SCRIPT73, // 73
+ SCRIPT74, // 74
+
+ 0, // 75
+ 0, // 76
+ 0, // 77
+ 0, // 78
+ 0, // 79
+ SCRIPT80, // 80
+ 0, // 81
+ 0, // 82
+ 0, // 83
+ 0, // 84
+ 0, // 85
+ SCRIPT86, // 86
+ 0, // 87
+ 0, // 88
+ 0, // 89
+ SCRIPT90, // 90
+ 0, // 91
+ 0, // 92
+ 0, // 93
+ 0, // 94
+ 0, // 95
+ 0, // 96
+ 0, // 97
+ 0, // 98
+ 0, // 99
+ 0, // 100
+ 0, // 101
+ 0, // 102
+ 0, // 103
+ 0, // 104
+ 0, // 105
+ 0, // 106
+ 0, // 107
+ 0, // 108
+ 0, // 109
+ 0, // 110
+ 0, // 111
+ 0, // 112
+ 0, // 113
+ 0, // 114
+ 0, // 115
+ 0, // 116
+ 0, // 117
+ 0, // 118
+ 0, // 119
+ 0, // 120
+ 0, // 121
+ 0, // 122
+ 0, // 123
+ 0, // 124
+ 0, // 125
+ 0, // 126
+ 0, // 127
+ SCRIPT128, // 128
+
+ SCRIPT129, // 129
+ SCRIPT130, // 130
+ SCRIPT131, // 131
+ 0, // 132
+ SCRIPT133, // 133
+ SCRIPT134, // 134
+ 0, // 135
+ 0, // 136
+ 0, // 137
+ 0, // 138
+ 0, // 139
+ 0, // 140
+ 0, // 141
+ 0, // 142
+ 0, // 143
+ 0, // 144
+ SCRIPT145, // 145
+ SCRIPT146, // 146
+ 0, // 147
+ 0, // 148
+ 0, // 149
+};
+
+const uint32 ObjectMan::_objectList[TOTAL_SECTIONS] = { //a table of pointers to object files
+ 0, // 0
+
+ COMP1, // 1 PARIS 1
+ COMP2, // 2
+ COMP3, // 3
+ COMP4, // 4
+ COMP5, // 5
+ COMP6, // 6
+ COMP7, // 7
+ COMP8, // 8
+
+ COMP9, // 9 PARIS 2
+ COMP10, // 10
+ COMP11, // 11
+ COMP12, // 12
+ COMP13, // 13
+ COMP14, // 14
+ COMP15, // 15
+ COMP16, // 16
+ COMP17, // 17
+ COMP18, // 18
+
+ COMP19, // 19 IRELAND
+ COMP20, // 20
+ COMP21, // 21
+ COMP22, // 22
+ COMP23, // 23
+ COMP24, // 24
+ COMP25, // 25
+ COMP26, // 26
+
+ COMP27, // 27 PARIS 3
+ COMP28, // 28
+ COMP29, // 29
+ COMP30, // 30 - Heart Monitor
+ COMP31, // 31
+ COMP32, // 32
+ COMP33, // 33
+ COMP34, // 34
+ COMP35, // 35
+
+ COMP36, // 36 PARIS 4
+ COMP37, // 37
+ COMP38, // 38
+ COMP39, // 39
+ COMP40, // 40
+ COMP41, // 41
+ COMP42, // 42
+ COMP43, // 43
+ 0, // 44
+
+ COMP45, // 45 SYRIA
+ COMP46, // 46 PARIS 4
+ COMP47, // 47
+ COMP48, // 48 PARIS 4
+ COMP49, // 49
+ COMP50, // 50
+ 0, // 51
+ 0, // 52
+ COMP53, // 53
+ COMP54, // 54
+ COMP55, // 55
+
+ COMP56, // 56 SPAIN
+ COMP57, // 57
+ COMP58, // 58
+ COMP59, // 59
+ COMP60, // 60
+ COMP61, // 61
+ COMP62, // 62
+
+ COMP63, // 63 NIGHT TRAIN
+ 0, // 64
+ COMP65, // 65
+ COMP66, // 66
+ COMP67, // 67
+ 0, // 68
+ COMP69, // 69
+ 0, // 70
+
+ COMP71, // 71 SCOTLAND
+ COMP72, // 72
+ COMP73, // 73
+ COMP74, // 74 END SEQUENCE IN SECRET_CRYPT
+ COMP75, // 75
+ COMP76, // 76
+ COMP77, // 77
+ COMP78, // 78
+ COMP79, // 79
+
+ COMP80, // 80 PARIS MAP
+
+ COMP81, // 81 Full-screen for "Asstair" in Paris2
+
+ COMP55, // 82 Full-screen BRITMAP in sc55 (Syrian Cave)
+ 0, // 83
+ 0, // 84
+ 0, // 85
+
+ COMP86, // 86 EUROPE MAP
+ COMP48, // 87 fudged in for normal window (sc48)
+ COMP48, // 88 fudged in for filtered window (sc48)
+ 0, // 89
+
+ COMP90, // 90 PHONE SCREEN
+ COMP91, // 91 ENVELOPE SCREEN
+ COMP17, // 92 fudged in for George close-up surprised in sc17 wardrobe
+ COMP17, // 93 fudged in for George close-up inquisitive in sc17 wardrobe
+ COMP29, // 94 fudged in for George close-up in sc29 sarcophagus
+ COMP38, // 95 fudged in for George close-up in sc29 sarcophagus
+ COMP42, // 96 fudged in for chalice close-up from sc42
+ 0, // 97
+ 0, // 98
+ COMP99, // 99 MESSAGE SCREEN (BLANK)
+
+ 0, // 100
+ 0, // 101
+ 0, // 102
+ 0, // 103
+ 0, // 104
+ 0, // 105
+ 0, // 106
+ 0, // 107
+ 0, // 108
+ 0, // 109
+
+ 0, // 110
+ 0, // 111
+ 0, // 112
+ 0, // 113
+ 0, // 114
+ 0, // 115
+ 0, // 116
+ 0, // 117
+ 0, // 118
+ 0, // 119
+
+ 0, // 120
+ 0, // 121
+ 0, // 122
+ 0, // 123
+ 0, // 124
+ 0, // 125
+ 0, // 126
+ 0, // 127
+
+//mega sections
+ MEGA_GEO, // 128 mega_one the player
+ MEGA_NICO, // 129 mega_two
+ MEGA_MUS, // 130
+ MEGA_BENOIR, // 131
+ 0, // 132
+ MEGA_ROSSO, // 133
+ MEGA_DUANE, // 134
+// james megas
+ 0, // 135
+ 0, // 136
+ 0, // 137
+ 0, // 138
+ 0, // 139
+ 0, // 140
+ 0, // 141
+ 0, // 142
+ 0, // 143
+
+// jeremy megas
+ 0, // 144 mega_phone
+ MEGA_MOUE, // 145 mega_moue
+ MEGA_ALBERT, // 146 mega_albert
+ 0, // 147
+ 0, // 148
+ TEXT_OBS, // 149
+};
+
+const uint32 ObjectMan::_textList[TOTAL_SECTIONS][7] = {
+ {ENGLISH0, FRENCH0, GERMAN0, ITALIAN0, SPANISH0, CZECH0, PORT0}, // 0 INVENTORY BOTH CD'S - used in almost all locations
+ {ENGLISH1, FRENCH1, GERMAN1, ITALIAN1, SPANISH1, CZECH1, PORT1}, // 1 PARIS 1 CD1
+ {ENGLISH2, FRENCH2, GERMAN2, ITALIAN2, SPANISH2, CZECH2, PORT2}, // 2 CD1
+ {ENGLISH3, FRENCH3, GERMAN3, ITALIAN3, SPANISH3, CZECH3, PORT3}, // 3 CD1
+ {ENGLISH4, FRENCH4, GERMAN4, ITALIAN4, SPANISH4, CZECH4, PORT4}, // 4 CD1
+ {ENGLISH5, FRENCH5, GERMAN5, ITALIAN5, SPANISH5, CZECH5, PORT5}, // 5 CD1
+ {ENGLISH6, FRENCH6, GERMAN6, ITALIAN6, SPANISH6, CZECH6, PORT6}, // 6 CD1
+ {ENGLISH7, FRENCH7, GERMAN7, ITALIAN7, SPANISH7, CZECH7, PORT7}, // 7 CD1
+ {0}, // 8 -
+ {ENGLISH9, FRENCH9, GERMAN9, ITALIAN9, SPANISH9, CZECH9, PORT9}, // 9 PARIS 2 CD1
+ {0}, // 10 -
+ {ENGLISH11, FRENCH11, GERMAN11, ITALIAN11, SPANISH11, CZECH11, PORT11}, // 11 CD1
+ {ENGLISH12, FRENCH12, GERMAN12, ITALIAN12, SPANISH12, CZECH12, PORT12}, // 12 CD1
+ {ENGLISH13, FRENCH13, GERMAN13, ITALIAN13, SPANISH13, CZECH13, PORT13}, // 13 CD1
+ {ENGLISH14, FRENCH14, GERMAN14, ITALIAN14, SPANISH14, CZECH14, PORT14}, // 14 CD1
+ {ENGLISH15, FRENCH15, GERMAN15, ITALIAN15, SPANISH15, CZECH15, PORT15}, // 15 CD1
+ {ENGLISH16, FRENCH16, GERMAN16, ITALIAN16, SPANISH16, CZECH16, PORT16}, // 16 CD1
+ {ENGLISH17, FRENCH17, GERMAN17, ITALIAN17, SPANISH17, CZECH17, PORT17}, // 17 CD1
+ {ENGLISH18, FRENCH18, GERMAN18, ITALIAN18, SPANISH18, CZECH18, PORT18}, // 18 CD1
+ {ENGLISH19, FRENCH19, GERMAN19, ITALIAN19, SPANISH19, CZECH19, PORT19}, // 19 IRELAND CD2
+ {ENGLISH20, FRENCH20, GERMAN20, ITALIAN20, SPANISH20, CZECH20, PORT20}, // 20 CD2
+ {ENGLISH21, FRENCH21, GERMAN21, ITALIAN21, SPANISH21, CZECH21, PORT21}, // 21 CD2
+ {ENGLISH22, FRENCH22, GERMAN22, ITALIAN22, SPANISH22, CZECH22, PORT22}, // 22 CD2
+ {ENGLISH23, FRENCH23, GERMAN23, ITALIAN23, SPANISH23, CZECH23, PORT23}, // 23 CD2
+ {ENGLISH24, FRENCH24, GERMAN24, ITALIAN24, SPANISH24, CZECH24, PORT24}, // 24 CD2
+ {ENGLISH25, FRENCH25, GERMAN25, ITALIAN25, SPANISH25, CZECH25, PORT25}, // 25 CD2
+ {0}, // 26 -
+ {ENGLISH27, FRENCH27, GERMAN27, ITALIAN27, SPANISH27, CZECH27, PORT27}, // 27 PARIS 3 CD1
+ {ENGLISH28, FRENCH28, GERMAN28, ITALIAN28, SPANISH28, CZECH28, PORT28}, // 28 CD1
+ {ENGLISH29, FRENCH29, GERMAN29, ITALIAN29, SPANISH29, CZECH29, PORT29}, // 29 CD1
+ {0}, // 30 -
+ {ENGLISH31, FRENCH31, GERMAN31, ITALIAN31, SPANISH31, CZECH31, PORT31}, // 31 CD1
+ {ENGLISH32, FRENCH32, GERMAN32, ITALIAN32, SPANISH32, CZECH32, PORT32}, // 32 CD1
+ {ENGLISH33, FRENCH33, GERMAN33, ITALIAN33, SPANISH33, CZECH33, PORT33}, // 33 CD1
+ {ENGLISH34, FRENCH34, GERMAN34, ITALIAN34, SPANISH34, CZECH34, PORT34}, // 34 CD1
+ {ENGLISH35, FRENCH35, GERMAN35, ITALIAN35, SPANISH35, CZECH35, PORT35}, // 35 CD1
+ {ENGLISH36, FRENCH36, GERMAN36, ITALIAN36, SPANISH36, CZECH36, PORT36}, // 36 PARIS 4 CD1
+ {ENGLISH37, FRENCH37, GERMAN37, ITALIAN37, SPANISH37, CZECH37, PORT37}, // 37 CD1
+ {ENGLISH38, FRENCH38, GERMAN38, ITALIAN38, SPANISH38, CZECH38, PORT38}, // 38 CD1
+ {ENGLISH39, FRENCH39, GERMAN39, ITALIAN39, SPANISH39, CZECH39, PORT39}, // 39 CD1
+ {ENGLISH40, FRENCH40, GERMAN40, ITALIAN40, SPANISH40, CZECH40, PORT40}, // 40 CD1
+ {ENGLISH41, FRENCH41, GERMAN41, ITALIAN41, SPANISH41, CZECH41, PORT41}, // 41 CD1
+ {ENGLISH42, FRENCH42, GERMAN42, ITALIAN42, SPANISH42, CZECH42, PORT42}, // 42 CD1
+ {ENGLISH43, FRENCH43, GERMAN43, ITALIAN43, SPANISH43, CZECH43, PORT43}, // 43 CD1
+ {0}, // 44 -
+ {ENGLISH45, FRENCH45, GERMAN45, ITALIAN45, SPANISH45, CZECH45, PORT45}, // 45 SYRIA CD2
+ {0}, // 46 (PARIS 4) -
+ {ENGLISH47, FRENCH47, GERMAN47, ITALIAN47, SPANISH47, CZECH47, PORT47}, // 47 CD2
+ {ENGLISH48, FRENCH48, GERMAN48, ITALIAN48, SPANISH48, CZECH48, PORT48}, // 48 (PARIS 4) CD1
+ {ENGLISH49, FRENCH49, GERMAN49, ITALIAN49, SPANISH49, CZECH49, PORT49}, // 49 CD2
+ {ENGLISH50, FRENCH50, GERMAN50, ITALIAN50, SPANISH50, CZECH50, PORT50}, // 50 CD2
+ {0}, // 51 -
+ {0}, // 52 -
+ {0}, // 53 -
+ {ENGLISH54, FRENCH54, GERMAN54, ITALIAN54, SPANISH54, CZECH54, PORT54}, // 54 CD2
+ {ENGLISH55, FRENCH55, GERMAN55, ITALIAN55, SPANISH55, CZECH55, PORT55}, // 55 CD2
+ {ENGLISH56, FRENCH56, GERMAN56, ITALIAN56, SPANISH56, CZECH56, PORT56}, // 56 SPAIN CD2
+ {ENGLISH57, FRENCH57, GERMAN57, ITALIAN57, SPANISH57, CZECH57, PORT57}, // 57 CD2
+ {ENGLISH58, FRENCH58, GERMAN58, ITALIAN58, SPANISH58, CZECH58, PORT58}, // 58 CD2
+ {ENGLISH59, FRENCH59, GERMAN59, ITALIAN59, SPANISH59, CZECH59, PORT59}, // 59 CD2
+ {ENGLISH60, FRENCH60, GERMAN60, ITALIAN60, SPANISH60, CZECH60, PORT60}, // 60 CD2
+ {ENGLISH61, FRENCH61, GERMAN61, ITALIAN61, SPANISH61, CZECH61, PORT61}, // 61 CD2
+ {0}, // 62 -
+ {ENGLISH63, FRENCH63, GERMAN63, ITALIAN63, SPANISH63, CZECH63, PORT63}, // 63 TRAIN CD2
+ {0}, // 64 -
+ {ENGLISH65, FRENCH65, GERMAN65, ITALIAN65, SPANISH65, CZECH65, PORT65}, // 65 CD2
+ {ENGLISH66, FRENCH66, GERMAN66, ITALIAN66, SPANISH66, CZECH66, PORT66}, // 66 CD2
+ {0}, // 67 -
+ {0}, // 68 -
+ {ENGLISH69, FRENCH69, GERMAN69, ITALIAN69, SPANISH69, CZECH69, PORT69}, // 69 CD2
+ {0}, // 70 -
+ {ENGLISH71, FRENCH71, GERMAN71, ITALIAN71, SPANISH71, CZECH71, PORT71}, // 71 SCOTLAND CD2
+ {ENGLISH72, FRENCH72, GERMAN72, ITALIAN72, SPANISH72, CZECH72, PORT72}, // 72 CD2
+ {ENGLISH73, FRENCH73, GERMAN73, ITALIAN73, SPANISH73, CZECH73, PORT73}, // 73 CD2
+ {ENGLISH74, FRENCH74, GERMAN74, ITALIAN74, SPANISH74, CZECH74, PORT74}, // 74 CD2
+ {0}, // 75 -
+ {0}, // 76 -
+ {0}, // 77 -
+ {0}, // 78 -
+ {0}, // 79 -
+ {0}, // 80 -
+ {0}, // 81 -
+ {0}, // 82 -
+ {0}, // 83 -
+ {0}, // 84 -
+ {0}, // 85 -
+ {0}, // 86 -
+ {0}, // 87 -
+ {0}, // 88 -
+ {0}, // 89 -
+ {ENGLISH90, FRENCH90, GERMAN90, ITALIAN90, SPANISH90, CZECH90, PORT90}, // 90 PHONE BOTH CD'S (NICO & TODRYK PHONE TEXT - can phone nico from a number of sections
+ {0}, // 91 -
+ {0}, // 92 -
+ {0}, // 93 -
+ {0}, // 94 -
+ {0}, // 95 -
+ {0}, // 96 -
+ {0}, // 97 -
+ {0}, // 98 -
+ {ENGLISH99, FRENCH99, GERMAN99, ITALIAN99, SPANISH99, CZECH99, PORT99}, // 99 MESSAGES BOTH CD'S - contains general text, most not requiring samples, but includes demo samples
+ {0}, // 100 -
+ {0}, // 101 -
+ {0}, // 102 -
+ {0}, // 103 -
+ {0}, // 104 -
+ {0}, // 105 -
+ {0}, // 106 -
+ {0}, // 107 -
+ {0}, // 108 -
+ {0}, // 109 -
+ {0}, // 110 -
+ {0}, // 111 -
+ {0}, // 112 -
+ {0}, // 113 -
+ {0}, // 114 -
+ {0}, // 115 -
+ {0}, // 116 -
+ {0}, // 117 -
+ {0}, // 118 -
+ {0}, // 119 -
+ {0}, // 120 -
+ {0}, // 121 -
+ {0}, // 122 -
+ {0}, // 123 -
+ {0}, // 124 -
+ {0}, // 125 -
+ {0}, // 126 -
+ {0}, // 127 -
+ {0}, // 128 -
+ {ENGLISH129, FRENCH129, GERMAN129, ITALIAN129, SPANISH129, CZECH129, PORT129}, // 129 NICO BOTH CD'S - used in screens 1,10,71,72,73
+ {0}, // 130 -
+ {ENGLISH131, FRENCH131, GERMAN131, ITALIAN131, SPANISH131, CZECH131, PORT131}, // 131 BENOIR CD1 - used in screens 31..35
+ {0}, // 132 -
+ {ENGLISH133, FRENCH133, GERMAN133, ITALIAN133, SPANISH133, CZECH133, PORT133}, // 133 ROSSO CD1 - used in screen 18
+ {0}, // 134 -
+ {0}, // 135 -
+ {0}, // 136 -
+ {0}, // 137 -
+ {0}, // 138 -
+ {0}, // 139 -
+ {0}, // 140 -
+ {0}, // 141 -
+ {0}, // 142 -
+ {0}, // 143 -
+ {0}, // 144 -
+ {ENGLISH145, FRENCH145, GERMAN145, ITALIAN145, SPANISH145, CZECH145, PORT145}, // 145 MOUE CD1 - used in screens 1 & 18
+ {ENGLISH146, FRENCH146, GERMAN146, ITALIAN146, SPANISH146, CZECH146, PORT146}, // 146 ALBERT CD1 - used in screens 4 & 5
+ {0}, // 147 -
+ {0}, // 148 -
+ {0}, // 149 -
+};
+
+
+RoomDef Screen::_roomDefTable[TOTAL_ROOMS] = { // these are NOT const
+ {
+ 0, //total_layers --- room 0 NOT USED
+ 0, //size_x = width
+ 0, //size_y = height
+ 0, //grid_width = width/16 + 16
+ {0,0,0,0}, //layers
+ {0,0,0}, //grids
+ {0,0}, //palettes { background palette [0..183], sprite palette [184..255] }
+ {0,0}, //parallax layers
+ },
+
+ //------------------------------------------------------------------------
+ // PARIS 1
+
+ {
+ 3, //total_layers //room 1
+ 784, //size_x
+ 400, //size_y
+ 65, //grid_width
+ {room1_l0,room1_l1,room1_l2}, //layers
+ {room1_gd1,room1_gd2}, //grids
+ {room1_PAL,PARIS1_PAL}, //palettes
+ {room1_plx,0}, //parallax layers
+ },
+ {
+ 3, //total_layers //room 2
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {room2_l0,room2_l1,room2_l2,0}, //layers
+ {room2_gd1,room2_gd2,0}, //grids
+ {room2_PAL,PARIS1_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 3, //total_layers //room 3
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {room3_l0,room3_l1,room3_l2,0}, //layers
+ {room3_gd1,room3_gd2,0}, //grids
+ {room3_PAL,PARIS1_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 3, //total_layers //room 4
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {room4_l0,room4_l1,room4_l2,0}, //layers
+ {room4_gd1,room4_gd2,0}, //grids
+ {room4_PAL,PARIS1_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 3, //total_layers //room 5
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {room5_l0,room5_l1,room5_l2,0}, //layers
+ {room5_gd1,room5_gd2,0}, //grids
+ {room5_PAL,PARIS1_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 2, //total_layers //room 6
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {room6_l0,room6_l1,0,0}, //layers
+ {room6_gd1,0,0}, //grids
+ {room6_PAL,SEWER_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 3, //total_layers //room 7
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {room7_l0,room7_l1,room7_l2,0}, //layers
+ {room7_gd1,room7_gd2,0}, //grids
+ {room7_PAL,SEWER_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 3, //total_layers //room 8
+ 784, //size_x
+ 400, //size_y
+ 65, //grid_width
+ {room8_l0,room8_l1,room8_l2,0}, //layers
+ {room8_gd1,room8_gd2,0}, //grids
+ {room8_PAL,PARIS1_PAL}, //palettes
+ {room8_plx,0}, //parallax layers
+ },
+
+ //------------------------------------------------------------------------
+ // PARIS 2
+
+ {
+ 3, //total_layers //room 9
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {room9_l0,room9_l1,room9_l2,0}, //layers
+ {room9_gd1,room9_gd2,0}, //grids
+ {room9_PAL,PARIS2_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 2, //total_layers //room 10
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {room10_l0,room10_l1,0,0}, //layers
+ {room10_gd1,0,0}, //grids
+ {room10_PAL,R10SPRPAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 3, //total_layers //room 11
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {room11_l0,room11_l1,room11_l2,0}, //layers
+ {room11_gd1,room11_gd2,0}, //grids
+ {room11_PAL,PARIS2_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 2, //total_layers //room 12
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {room12_l0,room12_l1,0,0}, //layers
+ {room12_gd1,0,0}, //grids
+ {room12_PAL,PARIS2_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 3, //total_layers //room 13
+ 976, //size_x
+ 400, //size_y
+ 77, //grid_width
+ {room13_l0,room13_l1,room13_l2,0}, //layers
+ {room13_gd1,room13_gd2,0}, //grids
+ {room13_PAL,R13SPRPAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 2, //total_layers //room 14
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {room14_l0,room14_l1,0,0}, //layers
+ {room14_gd1,0,0}, //grids
+ {room14_PAL,PARIS2_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 3, //total_layers //room 15
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {room15_l0,room15_l1,room15_l2,0}, //layers
+ {room15_gd1,room15_gd2,0}, //grids
+ {room15_PAL,PARIS2_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 2, //total_layers //room 16
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {R16L0,R16L1,0,0}, //layers
+ {R16G1,0,0}, //grids
+ {room16_PAL,PARIS2_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 3, //total_layers //room 17
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {room17_l0,room17_l1,room17_l2,0}, //layers
+ {room17_gd1,room17_gd2,0}, //grids
+ {room17_PAL,PARIS2_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 3, //total_layers //room 18
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {room18_l0,room18_l1,room18_l2,0}, //layers
+ {room18_gd1,room18_gd2,0}, //grids
+ {room18_PAL,R18SPRPAL}, //palettes
+ {0,0}, //parallax layers
+ },
+
+ //------------------------------------------------------------------------
+ // IRELAND
+
+ {
+ 3, //total_layers //room 19 - Ireland Street
+ 848, //size_x
+ 864, //size_y
+ 69, //grid_width
+ {R19L0,R19L1,R19L2,0}, //layers
+ {R19G1,R19G2,0}, //grids
+ {R19PAL,R19SPRPAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 4, //total_layers //room 20 - Macdevitts
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {R20L0,R20L1,R20L2,R20L3}, //layers
+ {R20G1,R20G2,R20G3}, //grids
+ {R20PAL,R20SPRPAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 3, //total_layers //room 21 - Pub Cellar
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {R21L0,R21L1,R21L2,0}, //layers
+ {R21G1,R21G2,0}, //grids
+ {R21PAL,SPRITE_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 2, //total_layers //room 22 - Castle Gate
+ 784, //size_x
+ 400, //size_y
+ 65, //grid_width
+ {R22L0,R22L1,0,0}, //layers
+ {R22G1,0,0}, //grids
+ {R22PAL,R22SPRPAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 1, //total_layers //room 23 - Castle Hay Top
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {R23L0,0,0,0}, //layers
+ {0,0,0}, //grids
+ {R23PAL,SPRITE_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 2, //total_layers //room 24 - Castle Yard
+ 880, //size_x
+ 400, //size_y
+ 71, //grid_width
+ {R24L0,R24L1,0,0}, //layers
+ {R24G1,0,0}, //grids
+ {R24PAL,SPRITE_PAL}, //palettes
+ {R24PLX,0}, //parallax layers
+ },
+ {
+ 2, //total_layers //room 25 - Castle Dig
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {R25L0,R25L1,0,0}, //layers
+ {R25G1,0,0}, //grids
+ {R25PAL,R25SPRPAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 3, //total_layers //room 26 - Cellar Dark
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {R26L0,R26L1,R26L2,0}, //layers
+ {R26G1,R26G2,0}, //grids
+ {R26PAL,R26SPRPAL}, //palettes
+ {0,0}, //parallax layers
+ },
+
+ //------------------------------------------------------------------------
+ // PARIS 3
+
+ {
+ 3, //total_layers //room 27
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {R27L0,R27L1,R27L2,0}, //layers
+ {R27G1,R27G2,0}, //grids
+ {room27_PAL,SPRITE_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 3, //total_layers //room 28
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {R28L0,R28L1,R28L2,0}, //layers
+ {R28G1,R28G2,0}, //grids
+ {R28PAL,R28SPRPAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 2, //total_layers //room 29
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {R29L0,R29L1,0,0}, //layers
+ {R29G1,0,0}, //grids
+ {R29PAL,R29SPRPAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 1, //total_layers //room 30 - for MONITOR seen while player in rm34
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {MONITOR,0,0,0}, //layers
+ {0,0,0}, //grids
+ {MONITOR_PAL,PARIS3_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 1, //total_layers //room 31
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {room31_l0,0,0,0}, //layers
+ {0,0,0}, //grids
+ {room31_PAL,PARIS3_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 3, //total_layers //room 32
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {room32_l0,room32_l1,room32_l2,0}, //layers
+ {room32_gd1,room32_gd2,0}, //grids
+ {room32_PAL,PARIS3_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 3, //total_layers //room 33
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {room33_l0,room33_l1,room33_l2,0}, //layers
+ {room33_gd1,room33_gd2,0}, //grids
+ {room33_PAL,PARIS3_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 4, //total_layers //room 34
+ 1120, //size_x
+ 400, //size_y
+ 86, //grid_width
+ {room34_l0,room34_l1,room34_l2,room34_l3}, //layers
+ {room34_gd1,room34_gd2,room34_gd3}, //grids
+ {room34_PAL,PARIS3_PAL}, //palettes
+ {R34PLX,0}, //parallax layers
+ },
+ {
+ 2, //total_layers //room 35
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {room35_l0,room35_l1,0}, //layers
+ {room35_gd1,0}, //grids
+ {room35_PAL,PARIS3_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+
+ //------------------------------------------------------------------------
+ // PARIS 4
+
+ {
+ 2, //total_layers //room 36
+ 960, //size_x
+ 400, //size_y
+ 76, //grid_width
+ {R36L0,R36L1,0,0}, //layers
+ {R36G1,0,0}, //grids
+ {room36_PAL,R36SPRPAL}, //palettes
+ {R36PLX,0}, //parallax layers
+ },
+ {
+ 2, //total_layers //room 37
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {R37L0,R37L1,0,0}, //layers
+ {R37G1,0,0}, //grids
+ {room37_PAL,SPRITE_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 2, //total_layers //room 38
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {R38L0,R38L1,0,0}, //layers
+ {R38G1,0,0}, //grids
+ {room38_PAL,R38SPRPAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 2, //total_layers //room 39
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {R39L0,R39L1,0,0}, //layers
+ {R39G1,0,0}, //grids
+ {room39_PAL,R39SPRPAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 1, //total_layers //room 40
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {R40L0,0,0,0}, //layers
+ {0,0,0}, //grids
+ {room40_PAL,SPRITE_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 2, //total_layers //room 41
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {R41L0,R41L1,0,0}, //layers
+ {R41G1,0,0}, //grids
+ {room41_PAL,SPRITE_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 3, //total_layers //room 42
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {R42L0,R42L1,R42L2,0}, //layers
+ {R42G1,R42G2,0}, //grids
+ {room42_PAL,SPRITE_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 2, //total_layers //room 43
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {R43L0,R43L1,0,0}, //layers
+ {R43G1,0,0}, //grids
+ {room43_PAL,SPRITE_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 0, //total_layers //room 44
+ 0, //size_x
+ 0, //size_y
+ 0, //grid_width
+ {0,0,0,0}, //layers
+ {0,0,0}, //grids
+ {0,0}, //palettes
+ {0,0}, //parallax layers
+ },
+
+ //------------------------------------------------------------------------
+ // SYRIA
+
+ {
+ 2, //total_layers //room 45 - Syria Stall
+ 1152, //size_x
+ 400, //size_y
+ 88, //grid_width
+ {R45L0,R45L1,0,0}, //layers
+ {R45G1,0,0}, //grids
+ {R45PAL,R45SPRPAL}, //palettes
+ {R45PLX,0}, //parallax layers
+ },
+ {
+ 3, //total_layers //room 46 (Hotel Alley, Paris 2)
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {room46_l0,room46_l1,room46_l2,0}, //layers
+ {room46_gd1,room46_gd2,0}, //grids
+ {room46_PAL,PARIS2_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 3, //total_layers //room 47 - Syria Carpet
+ 640, //size_x
+ 800, //size_y
+ 56, //grid_width
+ {R47L0,R47L1,R47L2,0}, //layers
+ {R47G1,R47G2,0}, //grids
+ {R47PAL,SYRIA_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 3, //total_layers //room 48 (Templar Church, Paris 4)
+ 1184, //size_x
+ 400, //size_y
+ 90, //grid_width
+ {R48L0,R48L1,R48L2,0}, //layers
+ {R48G1,R48G2,0}, //grids
+ {R48PAL,R48SPRPAL}, //palettes
+ {R48PLX,0}, //parallax layers
+ },
+ {
+ 3, //total_layers //room 49 - Syria Club
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {R49L0,R49L1,R49L2,0}, //layers
+ {R49G1,R49G2,0}, //grids
+ {R49PAL,SYRIA_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 4, //total_layers //room 50 - Syria Toilet
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {R50L0,R50L1,R50L2,R50L3}, //layers
+ {R50G1,R50G2,R50G3}, //grids
+ {R50PAL,SYRIA_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 0, //total_layers //room 51 - NOT USED
+ 0, //size_x
+ 0, //size_y
+ 0, //grid_width
+ {0,0,0,0}, //layers
+ {0,0,0}, //grids
+ {0,0}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 0, //total_layers //room 52 - NOT USED
+ 0, //size_x
+ 0, //size_y
+ 0, //grid_width
+ {0,0,0,0}, //layers
+ {0,0,0}, //grids
+ {0,0}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 1, //total_layers //room 53 - Bull Head Pan
+ 880, //size_x
+ 1736, //size_y
+ 71, //grid_width
+ {R53L0,0,0,0}, //layers
+ {0,0,0}, //grids
+ {R53PAL,R53SPRPAL}, //palettes
+ {FRONT53PLX,BACK53PLX}, //parallax layers
+ },
+ {
+ 2, //total_layers //room 54 - Bull Head
+ 896, //size_x
+ 1112, //size_y
+ 72, //grid_width
+ {R54L0,R54L1,0,0}, //layers
+ {R54G1,0,0}, //grids
+ {R54PAL,SYRIA_PAL}, //palettes
+ {R54PLX,0}, //parallax layers - SPECIAL BACKGROUND PARALLAX - MUST GO IN FIRST SLOT
+ },
+ {
+ 1, //total_layers //room 55 - Bull Secret
+ 1040, //size_x
+ 400, //size_y
+ 81, //grid_width
+ {R55L0,0,0,0}, //layers
+ {0,0,0}, //grids
+ {R55PAL,R55SPRPAL}, //palettes
+ {R55PLX,0}, //parallax layers
+ },
+
+ //------------------------------------------------------------------------
+ // SPAIN
+
+ {
+ 3, //total_layers //room 56 - Countess' room
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {R56L0,R56L1,R56L2,0}, //layers
+ {R56G1,R56G2,0}, //grids
+ {R56PAL,SPAIN_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 2, //total_layers //room 57 - Spain Drive
+ 1760, //size_x
+ 400, //size_y
+ 126, //grid_width
+ {R57L0,R57L1,0,0}, //layers
+ {R57G1,0,0}, //grids
+ {R57PAL,SPAIN_PAL}, //palettes
+ {R57PLX,0}, //parallax layers
+ },
+ {
+ 2, //total_layers //room 58 - Mausoleum Exterior
+ 864, //size_x
+ 400, //size_y
+ 70, //grid_width
+ {R58L0,R58L1,0,0}, //layers
+ {R58G1,0,0}, //grids
+ {R58PAL,SPAIN_PAL}, //palettes
+ {R58PLX,0}, //parallax layers
+ },
+ {
+ 3, //total_layers //room 59 - Mausoleum Interior
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {R59L0,R59L1,R59L2,0}, //layers
+ {R59G1,R59G2,0}, //grids
+ {R59PAL,SPAIN_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 3, //total_layers //room 60 - Spain Reception
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {R60L0,R60L1,R60L2,0}, //layers
+ {R60G1,R60G2,0}, //grids
+ {R60PAL,SPAIN_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 2, //total_layers //room 61 - Spain Well
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {R61L0,R61L1,0,0}, //layers
+ {R61G1,0,0}, //grids
+ {R61PAL,SPAIN_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 1, //total_layers //room 62 - CHESS PUZZLE
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {R62L0,0,0,0}, //layers
+ {0,0,0}, //grids
+ {R62PAL,SPRITE_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+
+ //------------------------------------------------------------------------
+ // NIGHT TRAIN
+
+ {
+ 2, //total_layers //room 63 - train_one
+ 2160, //size_x
+ 400, //size_y
+ 151, //grid_width
+ {R63L0,R63L1,0,0}, //layers
+ {R63G1,0,0}, //grids
+ {R63PAL,TRAIN_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 0, //total_layers //room 64 - NOT USED
+ 0, //size_x
+ 0, //size_y
+ 0, //grid_width
+ {0,0,0,0}, //layers
+ {0,0,0}, //grids
+ {0,0}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 2, //total_layers //room 65 - compt_one
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {R65L0,R65L1,0,0}, //layers
+ {R65G1,0,0}, //grids
+ {R65PAL,TRAIN_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 1, //total_layers //room 66 - compt_two
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {R66L0,0,0,0}, //layers
+ {0,0,0}, //grids
+ {R66PAL,TRAIN_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 2, //total_layers //room 67 - compt_three
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {R67L0,R67L1,0,0}, //layers
+ {R67G1,0,0}, //grids
+ {R67PAL,TRAIN_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 0, //total_layers //room 68 - NOT USED
+ 0, //size_x
+ 0, //size_y
+ 0, //grid_width
+ {0,0,0,0}, //layers
+ {0,0,0}, //grids
+ {0,0}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 2, //total_layers //room 69 - train_guard
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {R69L0,R69L1,0,0}, //layers
+ {R69G1,0,0}, //grids
+ {R69PAL,R69SPRPAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 0, //total_layers //room 70 - NOT USED
+ 0, //size_x
+ 0, //size_y
+ 0, //grid_width
+ {0,0,0,0}, //layers
+ {0,0,0}, //grids
+ {0,0}, //palettes
+ {0,0}, //parallax layers
+ },
+
+ //------------------------------------------------------------------------
+ // SCOTLAND
+
+ {
+ 2, //total_layers //room 71 - churchyard
+ 1760, //size_x
+ 400, //size_y
+ 126, //grid_width
+ {R71L0,R71L1,0,0}, //layers
+ {R71G1,0,0}, //grids
+ {R71PAL,SPRITE_PAL}, //palettes
+ {R71PLX,0}, //parallax layers
+ },
+ {
+ 2, //total_layers //room 72 - church_tower
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {R72L0,R72L1,0,0}, //layers
+ {R72G1,0,0}, //grids
+ {R72PAL,SPRITE_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 3, //total_layers //room 73 - crypt
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {R73L0,R73L1,R73L2,0}, //layers
+ {R73G1,R73G2,0}, //grids
+ {R73PAL,R73SPRPAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 2, //total_layers //room 74 - secret_crypt
+ 1136, //size_x
+ 400, //size_y
+ 87, //grid_width
+ {R74L0,R74L1,0,0}, //layers
+ {R74G1,0,0}, //grids
+ {R74PAL,ENDSPRPAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 1, //total_layers //room 75 - secret_crypt
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {R75L0,0,0,0}, //layers
+ {0,0,0}, //grids
+ {R75PAL,ENDSPRPAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 1, //total_layers //room 76 - secret_crypt
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {R76L0,0,0,0}, //layers
+ {0,0,0}, //grids
+ {R76PAL,ENDSPRPAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 1, //total_layers //room 77 - secret_crypt
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {R77L0,0,0,0}, //layers
+ {0,0,0}, //grids
+ {R77PAL,ENDSPRPAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 1, //total_layers //room 78 - secret_crypt
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {R78L0,0,0,0}, //layers
+ {0,0,0}, //grids
+ {R78PAL,ENDSPRPAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 1, //total_layers //room 79 - secret_crypt
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {R79L0,0,0,0}, //layers
+ {0,0,0}, //grids
+ {R79PAL,ENDSPRPAL}, //palettes
+ {0,0}, //parallax layers
+ },
+
+ //------------------------------------------------------------------------
+ // MAPS
+
+ {
+ 1, //total_layers //room 80 - paris map
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {room80_l0,0,0,0}, //layers
+ {0,0,0}, //grids
+ {room80_PAL,SPRITE_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 1, //total_layers //room 81 - for sequence of Assassin coming up stairs to rm17
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {ASSTAIR2,0,0,0}, //layers
+ {0,0,0}, //grids
+ {ASSTAIR2_PAL,SPRITE_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 1, //total_layers //room 82 - Map of Britain, viewed frrom sc55 (Syria Cave)
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {BRITMAP,0,0,0}, //layers
+ {0,0,0}, //grids
+ {BRITMAP_PAL,SPRITE_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 0, //total_layers //room 83 - NOT USED
+ 0, //size_x
+ 0, //size_y
+ 0, //grid_width
+ {0,0,0,0}, //layers
+ {0,0,0}, //grids
+ {0,0}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 0, //total_layers //room 84 - NOT USED
+ 0, //size_x
+ 0, //size_y
+ 0, //grid_width
+ {0,0,0,0}, //layers
+ {0,0,0}, //grids
+ {0,0}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 0, //total_layers //room 85 - NOT USED
+ 0, //size_x
+ 0, //size_y
+ 0, //grid_width
+ {0,0,0,0}, //layers
+ {0,0,0}, //grids
+ {0,0}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 1, //total_layers //room 86 - europe map
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {room86_l0,0,0,0}, //layers
+ {0,0,0}, //grids
+ {room86_PAL,SPRITE_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 1, //total_layers //room 87 - normal window in sc48
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {WINDOW1,0,0,0}, //layers
+ {0,0,0}, //grids
+ {WINDOW1_PAL,SPRITE_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 1, //total_layers //room 88 - filtered window in sc48
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {WINDOW2,0,0,0}, //layers
+ {0,0,0}, //grids
+ {WINDOW2_PAL,SPRITE_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 0, //total_layers //room 89 - NOT USED
+ 0, //size_x
+ 0, //size_y
+ 0, //grid_width
+ {0,0,0,0}, //layers
+ {0,0,0}, //grids
+ {0,0}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 1, //total_layers //room 90 - phone screen
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {R90L0,0,0,0}, //layers
+ {0,0,0}, //grids
+ {R90PAL,PHONE_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 1, //total_layers //room 91 - envelope screen
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {R91L0,0,0,0}, //layers
+ {0,0,0}, //grids
+ {R91PAL,SPRITE_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 1, //total_layers //room 92 - for close up of George surprised in wardrobe in sc17
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {SBACK17,0,0,0}, //layers
+ {0,0,0}, //grids
+ {SBACK17PAL,SPRITE_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 1, //total_layers //room 93 - for close up of George inquisitive in wardrobe in sc17
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {IBACK17,0,0,0}, //layers
+ {0,0,0}, //grids
+ {IBACK17PAL,SPRITE_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 1, //total_layers //room 94 - for close up of George in sarcophagus in sc29
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {BBACK29,0,0,0}, //layers
+ {0,0,0}, //grids
+ {BBACK29PAL,BBACK29SPRPAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 1, //total_layers //room 95 - for close up of George during templar meeting, in sc38
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {BBACK38,0,0,0}, //layers
+ {0,0,0}, //grids
+ {BBACK38PAL,SPRITE_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 1, //total_layers //room 96 - close up of chalice projection
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {CHALICE42,0,0,0}, //layers
+ {0,0,0}, //grids
+ {CHALICE42_PAL,SPRITE_PAL}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 0, //total_layers //room 97 - NOT USED
+ 0, //size_x
+ 0, //size_y
+ 0, //grid_width
+ {0,0,0,0}, //layers
+ {0,0,0}, //grids
+ {0,0}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 0, //total_layers //room 98 - NOT USED
+ 0, //size_x
+ 0, //size_y
+ 0, //grid_width
+ {0,0,0,0}, //layers
+ {0,0,0}, //grids
+ {0,0}, //palettes
+ {0,0}, //parallax layers
+ },
+ {
+ 1, //total_layers //room 99 - blank screen
+ 640, //size_x
+ 400, //size_y
+ 56, //grid_width
+ {room99_l0,0,0,0}, //layers
+ {0,0,0}, //grids
+ {room99_PAL,SPRITE_PAL}, //palettes
+ {0,0}, //parallax layers
+ }
+};
+
+const char Music::_tuneList[TOTAL_TUNES][8] = {
+ "", // 0 SPARE
+ "1m2", // DONE 1 George picks up the newspaper
+ "1m3", // DONE 2 In the alley for the first time
+ "1m4", // DONE 3 Alleycat surprises George
+ "1m6", // DONE 4 George fails to remove manhole cover. Even numbered attempts
+ "1m7", // !!!! 5 George fails to remove manhole cover. Odd numbered attempts
+ "1m8", // DONE 6 George leaves alley
+ "1m9", // DONE 7 George enters cafe for the first time
+ "1m10", // DONE 8 Waitress
+ "1m11", // DONE 9 Lying doctor
+
+ "1m12", // DONE 10 Truthful George
+ "1m13", // DONE 11 Yes, drink brandy
+ "1m14", // DONE 12 Yes, he's dead (Maybe 1m14a)
+ "1m15", // DONE 13 From, "...clown entered?"
+ "1m16", // DONE 14 From, "How did the old man behave?"
+ "1m17", // DONE 15 Salah-eh-Din
+ "1m18", // DONE 16 From, "Stay here, mademoiselle"
+ "1m19", // DONE 17 Leaving the cafe
+ "1m20", // DONE 18 Stick-up on Moue's gun
+ "1m21", // DONE 19 From, "Stop that, monsieur"
+
+ "1m22", // DONE 20 From, "If you can"
+ "1m23", // DONE 21 From, "Yeah,...clown"
+ "1m24", // DONE 22 From, he claimed to be a doctor
+ "1m25", // DONE 23 First time George meets Nico
+ "1m26", // DONE 24 From, "Oh God, him again." (Read notes on list)
+ "1m27", // DONE 25 From, "He's inside"
+ "1m28", // DONE 26 From, "You speak very good English"
+ "1m29", // DONE 27 From, "Why won't you tell me about this clown?"
+ "1m28a", // DONE 28 Costumed killers from, "How did Plantard get your name?"
+ "1m30", // DONE 29 From, "I really did see the clown" when talking to Moue at cafe doorway
+
+ "1m31", // DONE 30 From, "I found this (paper) in the street" (talking to Moue)
+ "1m32", // DONE 31 From, "What's the difference?"
+ "1m34", // DONE 32 Roadworker "Did you see a clown?"
+ "1m35", // DONE 33 Worker re: explosion, "I guess not"
+ "2m1", // DONE 34 From, "What about the waitress?"
+ "2m2", // DONE 35 From, "Did you see the old guy with the briefcase?"
+ "2m4", // DONE 36 "Would you like to read my newspaper?" (2M3 is at position 144)
+ "2m5", // DONE 37 From, "Ah, what's this Saleh-eh-Din?"
+ "2m6", // DONE 38 From, "It was a battered old tool box".
+ "2m7", // DONE 39 George "borrows" the lifting key
+
+ "2m8", // DONE 40 From 'phone page. Call Nico
+ "2m9", // DONE 41 Leaving the workman's tent
+ "2m10", // DONE 42 Use lifting keys on manhole
+ "2m11", // DONE 43 Into sewer no.1 from George on his knees (Alternative: 2m12)
+ "2m12", // DONE 44 Into sewer (alternative to 2m11)
+ "2m13", // DONE 45 George bends to pick up the red nose
+ "2m14", // DONE 46 Paper tissue, "It was a soggy..."
+ "2m15", // DONE 47 Cloth, as George picks it up. (Alternative: 2m16)
+ "2m16", // !!!! 48 Alternative cloth music
+ "2m17", // DONE 49 George climbs out of sewer.
+
+ "2m18", // DONE 50 From, "The man I chased..."
+ "2m19", // DONE 51 Spooky music for sewers.
+ "2m20", // DONE 52 "She isn't hurt, is she?"
+ "2m21", // DONE 53 Click on material icon
+ "2m22", // DONE 54 Spooky music for sewers.
+ "2m23", // DONE 55 From, "So you don't want to hear my experiences in the desert?"
+ "2m24", // DONE 56 On the material icon with Albert (suit icon instead, because material icon done)
+ "2m25", // DONE 57 After "What was on the label?" i.e. the 'phone number.
+ "2m26", // DONE 58 Leaving yard, after, "I hope you catch that killer soon." Also for the Musee Crune icon on the map (5M7).
+ "2m27", // DONE 59 As George starts to 'phone Todryk. (Repeated every time he calls him). Also, when the aeroport is clicked on (5M21).
+
+ "2m28", // DONE 60 Todryk conversation after, "Truth and justice"
+ "2m29", // DONE 61 'Phoning Nico from the roadworks. Also, 'phoning her from Ireland, ideally looping and fading on finish (6M10).
+ "2m30", // DONE 62 First time on Paris map
+ "2m31", // DONE 63 Click on Rue d'Alfred Jarry
+ "2m32", // DONE 64 From, "Will you tell me my fortune?"
+ "2m33", // DONE 65 After "Can you really tell my future?"
+ "1m28", // DONE 66 "What about the tall yellow ones?" Copy from 1M28.
+ "2m24", // DONE 67 Material Icon. Copy from 2M24
+ "2m6", // DONE 68 Exit icon on "See you later". Copy from 2M6.
+ "1m25", // DONE 69 On opening the front foor to Nico's. Copy from 1M25. .
+
+ "2m38", // DONE 70 Victim 1: From, "Tell me more about the clown's previous victims."
+ "2m39", // DONE 71 Victim 2: After, "What about the clown's second victim?"
+ "2m40", // DONE 72 Victim 3: On clown icon for 3rd victim.
+ "3m1", // DONE 73 George passes Nico the nose.
+ "3m2", // DONE 74 With Nico. From, "I found a piece of material..."
+ "3m3", // DONE 75 After George says, "... or clowns?"
+ "3m4", // DONE 76 After, "Did you live with your father?"
+ "1m28", // DONE 77 After, "Do you have a boyfriend?". Copy from 1M28.
+ "2m26", // DONE 78 After, "Good idea" (about going to costumier's). Copy from 2M26.
+ "3m7", // DONE 79 On costumier's icon on map.
+
+ "3m8", // DONE 80 Costumier's, after, "Come in, welcome."
+ "3m9", // DONE 81 On entering costumier's on later visits
+ "3m10", // DONE 82 After, "A description, perhaps."
+ "2m13", // DONE 83 Red nose icon at costumier's. Copy 2M13.
+ "3m12", // DONE 84 Tissue icon. Also, after Nico's "No, I write it (the magazine) 5M19.
+ "3m13", // DONE 85 Photo icon over, "Do you recognise this man?"
+ "3m14", // DONE 86 Exit icon, over, "Thanks for your help, buddy."
+ "2m9", // DONE 87 Clicking on police station on the map.
+ "3m17", // DONE 88 Police station on, "I've tracked down the clown's movements."
+ "3m18", // DONE 89 "One moment, m'sieur," as Moue turns.
+
+ "3m19", // DONE 90 G. on Rosso. "If he was trying to impress me..."
+ "3m20", // DONE 91 G. thinks, "He looked at me as if I'd farted."
+ "3m21", // DONE 92 Over Rosso's, "I've washed my hands of the whole affair."
+ "3m22", // DONE 93 Played over, "So long, inspector."
+ "3m24", // DONE 94 Conversation with Todrk, "He bought a suit from you, remember?"
+ "3m26", // !!!! 95 This piece is a problem. Don't worry about it for present.
+ "3m27", // DONE 96 George to Nico (in the flat): "Have you found out anymore?" [about the murders? or about the templars? JEL]
+ "2m26", // DONE 97 After, "Don't worry, I will." on leaving Nico's.
+ "3m29", // DONE 98 Ubu icon on the map.
+ "3m30", // DONE 99 G and Flap. After, "I love the clowns. Don't you?" AND "after "Not if you see me first" (3M31)
+
+ "3m32", // DONE 100 Source music for Lady Piermont.
+ "3m33", // DONE 101 More music for Lady P.
+ "2m13", // DONE 102 Red Nose music Copy 2M13
+ "4m3", // DONE 103 On photo, "Do you recognise the man in this photograph"
+ "4m4", // DONE 104 With Lady P. After, "Hi there, ma'am."
+ "4m5", // DONE 105 After, "I think the word you're looking for is...dick"
+ "4m6", // DONE 106 After, "English arrogance might do the trick." Also for "More English arrogance" (4M27)
+ "4m8", // !!!! 107 As George grabs key.
+ "4m9", // DONE 108 Room 21, on "Maybe it wasn't the right room"
+ "4m10", // DONE 109 On coming into 21 on subsequent occasions.
+
+ "4m11", // DONE 110 As George steps upto window.
+ "4m12", // DONE 111 Alternative times he steps up to the window.
+ "4m13", // DONE 112 In Moerlin's room
+ "4m14", // DONE 113 Sees "Moerlin" on the Stairs
+ "4m15", // DONE 114 George closing wardrobe door aftre Moerlin's gone.
+ "4m17", // DONE 115 After, "take your mind off the inquest"
+ "4m18", // DONE 116 "It was just as I'd imagined."
+ "4m19", // DONE 117 Show photo to Lady P
+ "4m20", // DONE 118 Lady P is "shocked" after the name "Khan".
+ "4m21", // DONE 119 After, "A bundle of papers, perhaps".
+
+ "4m22", // DONE 120 After, "Plantard's briefcase"
+ "4m24", // DONE 121 On fade to black as George leaves the hotel (prior to being searched)
+ "4m25", // DONE 122 After, "I break your fingers"
+ "4m28", // DONE 123 After clerk says, "Voila, m'sieur. Le manuscript..."
+ "4m29", // DONE 124 Onto the window sill after getting the manuscript.
+ "4m31", // DONE 125 Searched after he's dumped the manuscript in the alleyway.
+ "4m32", // DONE 126 Recovering the manuscript in the alley, "If the manuscript was..."
+ "5m1", // DONE 127 The manuscript, just after, "It's worth enough to kill for."
+ "5m2", // !SMK 128 The Templars after, "...over 800 years ago."
+ "5m3", // DONE 129 After, "Let's take another look at that manuscript"
+
+ "5m4", // DONE 130 On "Knight with a crystal ball" icon
+ "5m5", // DONE 131 On Nico's, "Patience"
+ "5m6", // DONE 132 After "I'm sure it will come in useful" when George leaves. Also, George leaving Nico after, "Keep me informed if you find anything new" (5M20). + "just take care of yourself"
+ "5m8", // DONE 133 Entering the museum for the first time on the fade.
+ "5m9", // DONE 134 George with guard after, "park their cars." Guard saying "No, no, no"
+ "5m10", // DONE 135 Incidental looking around the museum music. + fading from map to museum street, when lobineau is in museum
+ "5m11", // DONE 136 From "In the case was a spindly tripod, blackened with age and pitted with rust...". George answers Tripod ((?)That's what the cue list says). Also 5M15 and 5M16)
+ "5m12", // DONE 137 More looking around music.
+ "5m13", // DONE 138 Opening the mummy case.
+ "5m14", // DONE 139 High above me was a window
+
+ "5m17", // DONE 140 "As I reached toward the display case" (5M18 is in slot 165)
+ "5m22", // !SMK 141 From Ireland on the Europe map.
+ "5m23", // !!!! 142 IN front of the pub, searching.
+ "5m24", // DONE 143 Cheeky Maguire, "Wait 'til I get back"
+ "2m3", // DONE 144 Before, "Did anybody at the village work at the dig?" Loop and fade.
+ "6m1", // DONE 145 After, "You know something ... not telling me, don't you?"
+ "6m2", // DONE 146 On, "Mister, I seen it with my own eyes."
+ "6m3", // DONE 147 After, "Did you get to see the ghost" + On George's, "As soon as I saw the flickering torches..." in SCR_SC73.txt.
+ "6m4", // DONE 148 "the bloody place is haunted", just after G's "rational explanation... the castle"
+ "6m5", // DONE 149 Pub fiddler 1. Please programme stops between numbers - about 20" and a longer one every four or five minutes.
+
+ "6m6", // DONE 150 Pub fiddler 2.
+ "6m7", // DONE 151 Pub fiddler 3.
+ "6m8", // DONE 152 Pub fiddler 4.
+ "6m12", // DONE 153 Exit pub (as door opens). Copy from 2M6.
+ "2m6", // DONE 154 Going to the castle, start on the path blackout.
+ "5m1", // DONE 155 On, "Where was the Templar preceptory?" Copy 5M1
+ "6m15", // DONE 156 "On, "Do you mind if I climb up your hay stack..."
+ "7m1", // DONE 157 On plastic box, "It was a featureless..."
+ "7m2", // DONE 158 On tapping the plastic box with the sewer key
+ "7m4", // !!!! 159 "Shame on you, Patrick!" Fitzgerald was at the dig
+
+ "7m5", // !!!! 160 On the icon that leads to, "Maguire says that he saw you at the dig"
+ "7m6", // !!!! 161 On "The man from Paris"
+ "7m7", // !!!! 162 On, "I wish I'd never heard of..."
+ "7m8", // DONE 163 Exit pub
+ "7m11", // DONE 164 George picks up gem.
+ "7m14", // DONE 165 On George's icon, "the driver of the Ferrari..."
+ "7m15", // DONE 166 After George, "His name is Sean Fitzgerald"
+ "5m18", // DONE 167 Leaving museum after discovering tripod.
+ "6m11", // !!!! 168 With Fitz. On G's, "Did you work at...?". This is triggered here and on each subsequent question, fading at the end.
+ "7m17", // DONE 169 "You don't have to demolish the haystack"
+
+ "7m18", // DONE 170 George begins to climb the haystack.
+ "7m19", // DONE 171 Alternative climbing haystack music. These two tracks can be rotated with an ascent with FX only).
+ "7m20", // DONE 172 Attempting to get over the wall.
+ "7m21", // DONE 173 Descending the haystack
+ "7m22", // !!!! 174 Useful general purpose walking about music.
+ "7m23", // DONE 175 "Plastic cover" The exposed box, LB and RB.
+ "7m28", // !!!! 176 "No return"
+ "7m30", // !!!! 177 Picking up drink music (This will definitely clash with the fiddle music. We'll use it for something else). *
+ "7m31", // !!!! 178 Showing the landlord the electrician's ID.
+ "7m32", // !!!! 179 Stealing the wire (Probable clash again) *
+
+ "7m33", // DONE 180 On fade to black before going down into dark cellar.
+ "7m34", // DONE 181 On opening the grate, as George says, "I lifted the..." Khan's entrance.
+ "8m1", // DONE 182 Going down into the light cellar, starting as he goes through bar door.
+ "8m2", // DONE 183 General cellar music on, "It was an empty carton".
+ "8m4", // !!!! 184 Trying to get the bar towel. On, "The man's arm lay across..." *
+ "8m7", // DONE 185 Squeeze towel into drain. On, "Silly boy..."
+ "8m10", // DONE 186 Entering the castle as he places his foot on the tool embedded into the wall.
+ "8m11", // DONE 187 On, "Hey, billy." Goat confrontation music.
+ "8m12", // DONE 188 First butt from goat at moment of impact.
+ "8m13", // DONE 189 On examining the plough.
+
+ "8m14", // DONE 190 Second butt from goat.
+ "8m15", // DONE 191 Third butt from goat.
+ "8m16", // DONE 192 All subsequent butts, alternating with no music.
+ "8m18", // DONE 193 Poking around in the excavation music. I'd trigger it as he starts to descend the ladder into the dig.
+ "8m19", // DONE 194 "There was a pattern..." The five holes.
+ "8m20", // DONE 195 George actually touches the stone. Cooling carving (?)
+ "8m21", // DONE 196 "As I swung the stone upright" coming in on "Upright"
+ "8m22", // DONE 197 "The sack contained"
+ "8m24", // DONE 198 Down wall. As screen goes black. George over wall to haystack.
+ "8m26", // DONE 199 Wetting the towel
+
+ "8m28", // DONE 200 Wetting plaster. As George reaches for the towel prior to wringing water onto the plaster.
+ "8m29", // DONE 201 Mould in "The hardened plaster..."
+ "8m30", // DONE 202 Entering castle. As George steps in.
+ "8m31", // DONE 203 After George, "Hardly - he was dead." in nico_scr.txt
+ "8m37", // !!!! 204 Talking to Lobineau about the Templars. 5M2Keep looping and fade at the end.
+ // The problem is that it's an enormous sample and will have to be reduced in volume.
+ // I suggest forgetting about this one for the time being.
+ // If there's room when the rest of the game's in, then I'll re-record it more quietly and call it 8M37, okay?
+ "8m38", // DONE 205 "A female friend"
+ "8m39", // DONE 206 "Public toilet"
+ "8m40", // DONE 207 When George asks, "Where was the site at Montfaucon?" (to Lobineau, I suppose)
+ "8m41", // DONE 208 On matchbox icon. "Does this matchbook mean anything to you?"
+ "9m1", // DONE 209 On George, "It was the king of France" in ross_scr.txt
+
+ "9m2", // DONE 210 George, "Why do you get wound up...?" in ross_scr.txt
+ "9m3", // DONE 211 Ever heard of a guy called Marquet? Jacques Marquet?
+ "9m5", // DONE 212 On fade up at the hospital drive
+ "9m6", // DONE 213 On fade up inside the hospital
+ "9m7", // DONE 214 With Eva talking about Marquet. Before, "I'm conducting a private investigation."
+ "9m8", // DONE 215 With Eva, showing her the ID card.
+ "9m9", // DONE 216 With Eva, second NURSE click, "If nurse Grendel is that bad..."
+ "9m10", // DONE 217 Saying goodbye to Eva on the conversation where he discovers Marquet's location + on fade up on Sam's screen after being kicked off the ward
+ "9m11", // DONE 218 Talking to Sam. On, "Oh - hiya!" + first click on MR_SHINY
+ "9m13", // DONE 219 When George drinks from the cooler.
+
+ "9m14", // DONE 220 To Grendel, third MARQUET click. On "Do you know who paid for Marquet's room?"
+ "9m15", // DONE 221 To Grendel on first CLOWN click, "Do you have any clowns on the ward?"
+ "9m17", // DONE 222 When George pulls Shiny's plug the first time, on "As I tugged the plug..."
+ "9m18", // DONE 223 On subsequent plug tuggings if George has failed to get the white coat.
+ "9m19", // DONE 224 With the consultant, on "Excuse me, sir..."
+ "9m20", // DONE 225 Talking to Grendel. Launch immediately after she gives him the long metal box and "a stunning smile"
+ "9m21", // DONE 226 On Eric's, "Doctor!" when George is trying to get by for the first time, i.e. ward_stop_flag==0.
+ "9m22", // DONE 227 On Eric's, "Oh, Doctor!" when George is trying to get by for the second time, i.e. ward_stop_flag==1.
+ "9m23", // DONE 228 On Eric's, "You haven't finished taking my blood pressure!" when George is trying to get by for the third+ time, i.e. ward_stop_flag>1.
+ "9m24", // DONE 229 Giving the pressure gauge to Benoir, on, "Here, take this pressure gauge."
+
+ "9m25", // DONE 230 With Benoir, suggesting he use the gauge on the nurse. On, "Use it on Nurse Grendel."
+ "10m1", // DONE 231 Immediately after Marquet's, "Well, what are you waiting for? Get it over with!"
+ "10m2", // DONE 232 When George pulls open the sarcophagus lid prior to his successful hiding before the raid.
+ "10m3", // DONE 233 On fade to black as George spies on the Neo-Templars.
+ "10m4", // DONE 234 On second peer through the hole at the "Templars"
+ "11m1", // DONE 235 On clicking on the Marib button.
+ "11m3", // DONE 236 Loop in the Club Alamut, alternating with...
+ "11m4", // DONE 237 Loop in the Club Alamut.
+ "11m7", // DONE 238 When the door in the Bull's Mouth closes on George.
+ "11m8", // DONE 239 When the door opens to reveal Khan, immediately after, "You!" in KHAN_55.TXT.
+
+ "11m9", // !SMK 240 Over the "Going to the Bull's Head" smacker. Probably.
+ "12m1", // DONE 241 Clicking on the Spain icon from the aeroport. (AFTER CHANGING CD!)
+ "11m2", // DONE 242 Loop in the marketplace of Marib.
+ "spm2", // DONE 243 On fade up in the Countess' room for the first time.
+ "spm3", // DONE 244 At the end of VAS1SC56, triggered immediately before the Countess says, "Senor Stobbart, if I find that you are wasting my time..."
+ "spm4", // DONE 245 Immediately before Lopez enters the mausoleum with the chess set.
+ "spm5", // DONE 246 (This is actually 5m2 copied for CD2) Played through the chess puzzle. Ideally, when it finsishes, give it a couple of seconds and then launch 12m1. When that finishes, a couple of seconds and then back to this and so on and so forth.
+ "spm6", // DONE 247 On fade up from completing the chess puzzle. The climax is now "spm6b"
+ "scm1", // DONE 248 This is used whenever George goes out of a carriage and onto the corridor.
+ "scm2", // DONE 249 As George climbs out of the train window.
+
+ "scm3", // DONE 250 As George lands inside the guard's van.
+ "scm4", // DONE 251 On Khan's death speech, "A noble foe..."
+ "scm5", // DONE 252 George to Khan. On, "You're talking in riddles!"
+ "scm6", // DONE 253 Before, "He's dead"
+ "scm7", // DONE 254 Kissing Nico. After, "Where do you think you're going?"
+ "scm8", // DONE 255 In the churchyard after Nico's, "I rather hope it did"
+ "scm11", // DONE 256 Click on the opened secret door.
+ "rm3a", // DONE 257 Immediately they fade up in the great cave.
+ "rm3b", // DONE 258 The scene change immediately after Eklund says, "If you wish to live much longer..."
+ "scm16", // DONE 259 The big end sequence from when the torch hits the gunpowder. Cross fade with the shortened version that fits on the Smacker.
+
+ "scm1b", // DONE 260 When George passes the trigger point toward the back of the train and he sees Guido.
+ "spm6b", // DONE 261 The climax of "spm6", which should coincide with the Countess holding up the chalice.
+ "marquet", // DONE 262 Starts at the fade down when George is asked to leave Jacques' room
+ "rm4", // DONE 263 "On crystal stand icon. As George walks to the centre of the cavern." I'd do this on the first LMB on the stump.
+ "rm5", // DONE 264 "On icon. As George places the crystal on top of the stand." When the player places the gem luggage on the emplaced tripod.
+ "rm6", // DONE 265 "Chalice reflection. On icon as George places Chalice on floor of Church" i.e. the mosaic in the Baphomet dig. It's over thirty seconds long so it had best start running when the chalice luggage is placed on the mosaic so it runs through the big screen of the reflection.
+ "rm7", // DONE 266 "Burning candle. On icon as George sets about lighting candle." One minute forty-eight, this one. I've no idea how long the burning candle Smacker is but the cue description seems to indicate it should run from the moment the burning tissue successfully lights the candle, i.e. the window is shut.
+ "rm8", // DONE 267 "Down well. George descends into circus trap well." I think the circus reference refers to the lion. Run it from the moment that George gets off the rope and has a look around. Run it once only.
+
+ "rm3c", // DONE 268 On the scene change to the Grand Master standing between the pillars as the earth power whomps him.
+ "rm3d", // DONE 269 ONe the scene change after the Grand Master says, "George, we have watched you..." This one might need a bit of fiddling to get it to match to the fisticuffs.
+};
+
+#ifdef PALMOS_68K
+const FxDef *Sound::_fxList;
+#else
+const FxDef Sound::_fxList[312] = {
+ // 0
+ {
+ 0, // sampleId
+ 0, // type (FX_LOOP, FX_RANDOM or FX_SPOT)
+ 0, // delay (random chance for FX_RANDOM sound fx)
+ { // roomVolList
+ {0,0,0}, // {roomNo,leftVol,rightVol}
+ },
+ },
+ //------------------------
+ // 1 Newton's cradle. Anim=NEWTON.
+ {
+ FX_NEWTON, // sampleId
+ FX_SPOT, // type
+ 7, // delay (or random chance)
+ { // roomVolList
+ {45,4,2}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 2
+ {
+ FX_TRAFFIC2, // sampleId
+ FX_LOOP, // type
+ 0, // delay (or random chance)
+ { // roomVolList
+ {1,12,12}, // {roomNo,leftVol,rightVol}
+ {2,1,1},
+ {3,1,1},
+ {4,13,13},
+ {5,1,1},
+ {8,7,7},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 3
+ {
+ FX_HORN1, // sampleId
+ FX_RANDOM, // type
+ 1200, // delay (or random chance)
+ { // roomVolList
+ {1,3,3}, // {roomNo,leftVol,rightVol}
+ {3,1,1},
+ {4,1,1},
+ {5,2,2},
+ {8,4,4},
+ {18,2,3},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 4
+ {
+ FX_HORN2, // sampleId
+ FX_RANDOM, // type
+ 1200, // delay (or random chance)
+ { // roomVolList
+ {1,4,4}, // {roomNo,leftVol,rightVol}
+ {3,2,2},
+ {4,3,3},
+ {5,2,2},
+ {8,4,4},
+ {18,1,1},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 5
+ {
+ FX_HORN3, // sampleId
+ FX_RANDOM, // type
+ 1200, // delay (or random chance)
+ { // roomVolList
+ {1,4,4}, // {roomNo,leftVol,rightVol}
+ {2,4,4},
+ {3,2,2},
+ {4,3,3},
+ {5,2,2},
+ {8,4,4},
+ {18,1,1},
+ },
+ },
+ //------------------------
+ // 6
+ {
+ FX_CAMERA1, // sampleId
+ FX_SPOT, // type
+ 25, // delay (or random chance)
+ { // roomVolList
+ {1,8,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 7
+ {
+ FX_CAMERA2, // sampleId
+ FX_SPOT, // type
+ 25, // delay (or random chance)
+ { // roomVolList
+ {1,8,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 8
+ {
+ FX_CAMERA3, // sampleId
+ FX_SPOT, // type
+ 25, // delay (or random chance)
+ { // roomVolList
+ {1,8,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 9
+ {
+ FX_SWATER1, // sampleId
+ FX_LOOP, // type
+ 0, // delay (or random chance)
+ { // roomVolList
+ {7,12,12}, // {roomNo,leftVol,rightVol}
+ {6,12,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 10 Mad dogs in Spain, triggered by George going around the corner in the villa hall.
+ // In 56 and 57, the dogs will continue barking after George has either been ejected or sneaked up stairs
+ // for a couple of loops before stopping.
+ {
+ FX_DOGS56, // sampleId
+ FX_LOOP, // type
+ 0, // delay (or random chance)
+ { // roomVolList
+ {60,16,16}, // {roomNo,leftVol,rightVol}
+ {0,0,0} // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 11
+ {
+ FX_DRIP1, // sampleId
+ FX_RANDOM, // type
+ 20, // delay (or random chance)
+ { // roomVolList
+ {7,15,15}, // {roomNo,leftVol,rightVol}
+ {6,8,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 12
+ {
+ FX_DRIP2, // sampleId
+ FX_RANDOM, // type
+ 30, // delay (or random chance)
+ { // roomVolList
+ {7,15,15}, // {roomNo,leftVol,rightVol}
+ {6,8,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 13
+ {
+ FX_DRIP3, // sampleId
+ FX_RANDOM, // type
+ 40, // delay (or random chance)
+ { // roomVolList
+ {7,15,15}, // {roomNo,leftVol,rightVol}
+ {6,8,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 14
+ {
+ FX_TWEET1, // sampleId
+ FX_SPOT, // type
+ 10, // delay (or random chance)
+ { // roomVolList
+ {1,5,5}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 15
+ {
+ FX_TWEET2, // sampleId
+ FX_SPOT, // type
+ 10, // delay (or random chance)
+ { // roomVolList
+ {1,5,5}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 16
+ {
+ FX_TWEET3, // sampleId
+ FX_SPOT, // type
+ 10, // delay (or random chance)
+ { // roomVolList
+ {1,5,5}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 17
+ {
+ FX_TWEET4, // sampleId
+ FX_SPOT, // type
+ 10, // delay (or random chance)
+ { // roomVolList
+ {1,5,5}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 18
+ {
+ FX_TWEET5, // sampleId
+ FX_SPOT, // type
+ 10, // delay (or random chance)
+ { // roomVolList
+ {1,5,5}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 19 Tied to large bird flying up screen anim
+ {
+ FX_CAW1, // sampleId
+ FX_SPOT, // type
+ 20, // delay (or random chance)
+ { // roomVolList
+ {1,5,5}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ //------------------------
+ // 20 George picking the canopy up: GEOCAN
+ {
+ FX_CANUP, // sampleId
+ FX_SPOT, // type
+ 5, // delay (or random chance) *
+ { // roomVolList
+ {1,10,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 21 George dropping the canopy: GEOCAN
+ {
+ FX_CANDO, // sampleId
+ FX_SPOT, // type
+ 52, // delay (or random chance) *
+ { // roomVolList
+ {1,10,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 22 George dusts himself down: GEOCAN
+ {
+ FX_DUST, // sampleId
+ FX_SPOT, // type
+ 58, // delay (or random chance) *
+ { // roomVolList
+ {1,10,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 23 George picks up the paper and opens it: GEOPAP
+ {
+ FX_PAP1, // sampleId
+ FX_SPOT, // type
+ 23, // delay (or random chance) *
+ { // roomVolList
+ {1,10,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 24 George puts the paper away: GEOPAP2
+ {
+ FX_PAP2, // sampleId
+ FX_SPOT, // type
+ 3, // delay (or random chance) *
+ { // roomVolList
+ {1,10,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 25 George gives the paper away: GEOWRK8
+ {
+ FX_PAP3, // sampleId
+ FX_SPOT, // type
+ 13, // delay (or random chance) *
+ { // roomVolList
+ {4,14,12}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 26 Workman examines paper: WRKOPN - it's now just WRKPPR
+ {
+ FX_PAP4, // sampleId
+ FX_SPOT, // type
+ 15, // delay (or random chance) *
+ { // roomVolList
+ {4,14,12}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 27 Workman puts paper down: WRKOPN (REVERSED) - now just WRKCLM
+ {
+ FX_PAP5, // sampleId
+ FX_SPOT, // type
+ 2, // delay (or random chance)*
+ { // roomVolList
+ {4,14,12}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 28 Pickaxe sound 1:, Screen 4 - WRKDIG
+ {
+ FX_PICK1, // sampleId
+ FX_SPOT, // type
+ 11, // delay (or random chance) *
+ { // roomVolList
+ {4,10,10},
+ {0,0,0} // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 29 Pickaxe sound 2:, Screen 4 - WRKDIG
+ {
+ FX_PICK2, // sampleId
+ FX_SPOT, // type
+ 11, // delay (or random chance) *
+ { // roomVolList
+ {4,10,10},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ //------------------------
+ // 30 Pickaxe sound 3:, Screen 4 - WRKDIG
+ {
+ FX_PICK3, // sampleId
+ FX_SPOT, // type
+ 11, // delay (or random chance) *
+ { // roomVolList
+ {4,10,10},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 31 Pickaxe sound 4:, Screen 4 - WRKDIG
+ {
+ FX_PICK4, // sampleId
+ FX_SPOT, // type
+ 11, // delay (or random chance) *
+ { // roomVolList
+ {4,10,10},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 32 Shorting light: FLICKER
+ {
+ FX_LIGHT, // sampleId
+ FX_SPOT, // type
+ 1, // delay (or random chance) *
+ { // roomVolList
+ {3,15,15}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 33 Cat leaps out of bin and runs: CATJMP!
+ {
+ FX_CAT, // sampleId
+ FX_SPOT, // type
+ 20, // delay (or random chance) *
+ { // roomVolList
+ {2,10,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 34 George rocks plastic crate: GEOCRT
+ {
+ FX_CRATE, // sampleId
+ FX_SPOT, // type
+ 10, // delay (or random chance) *
+ { // roomVolList
+ {2,8,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 35 George tries to climb drainpipe: GEOCLM02
+ {
+ FX_DRAIN, // sampleId
+ FX_SPOT, // type
+ 9, // delay (or random chance) *
+ { // roomVolList
+ {2,10,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 36 George removes manhole cover: GEOMAN8
+ {
+ FX_HOLE, // sampleId
+ FX_SPOT, // type
+ 19, // delay (or random chance) ?
+ { // roomVolList
+ {2,12,11}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 37 Brandy bottle put down: CHNDRN
+ {
+ FX_BOTDN, // sampleId
+ FX_SPOT, // type
+ 43, // delay (or random chance) *
+ { // roomVolList
+ {3,8,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 38 Brandy bottle picked up: GEOBOT3
+ {
+ FX_BOTUP, // sampleId
+ FX_SPOT, // type
+ 9, // delay (or random chance) *
+ { // roomVolList
+ {3,10,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 39 Chantelle gulps on brandy: CHNDRN
+ {
+ FX_GULP, // sampleId
+ FX_SPOT, // type
+ 23, // delay (or random chance) *
+ { // roomVolList
+ {3,4,3}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 40 Chantelle picked up off the floor: GEOCHN
+ {
+ FX_PIKUP, // sampleId
+ FX_SPOT, // type
+ 28, // delay (or random chance) *
+ { // roomVolList
+ {3,11,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 41 George searches Plantard's body: GEOCPS
+ {
+ FX_BODY, // sampleId
+ FX_SPOT, // type
+ 10, // delay (or random chance) *
+ { // roomVolList
+ {3,10,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 42 Moue cocks handgun. MOUENT
+ {
+ FX_PISTOL, // sampleId
+ FX_SPOT, // type
+ 23, // delay (or random chance) *
+ { // roomVolList
+ {4,4,7}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 43 George rummages in toolbox: GEOTBX
+ {
+ FX_TBOX, // sampleId
+ FX_SPOT, // type
+ 12, // delay (or random chance) *
+ { // roomVolList
+ {4,12,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 44 rat squeak 1
+ {
+ FX_RAT1, // sampleId
+ FX_RANDOM, // type
+ 193, // delay (or random chance)
+ { // roomVolList
+ {6,5,7}, // {roomNo,leftVol,rightVol}
+ {7,5,3},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 45 rat squeak 2
+ {
+ FX_RAT2, // sampleId
+ FX_RANDOM, // type
+ 201, // delay (or random chance)
+ { // roomVolList
+ {6,3,5}, // {roomNo,leftVol,rightVol}
+ {7,4,6},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 46 George climbs down ladder:
+ {
+ FX_LADD1, // sampleId
+ FX_SPOT, // type
+ 10, // delay (or random chance)
+ { // roomVolList
+ {6,10,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 47 Rushing water loop
+ {
+ FX_SWATER3, // sampleId
+ FX_LOOP, // type
+ 0, // delay (or random chance)
+ { // roomVolList
+ {6,10,11}, // {roomNo,leftVol,rightVol}
+ {7,12,11},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 48 Left hand bin being opened: GEOCAT?
+ {
+ FX_BIN3, // sampleId
+ FX_SPOT, // type
+ 12, // delay (or random chance)
+ { // roomVolList
+ {2,12,11}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 49 Middle bin being opened: GEOBIN
+ {
+ FX_BIN2, // sampleId
+ FX_SPOT, // type
+ 12, // delay (or random chance)
+ { // roomVolList
+ {2,11,11}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 50 Right hand bin being opened: GEOLID?
+ {
+ FX_BIN1, // sampleId
+ FX_SPOT, // type
+ 12, // delay (or random chance)
+ { // roomVolList
+ {2,10,11}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 51 Passing car sound
+ {
+ FX_CARS, // sampleId
+ FX_RANDOM, // type
+ 120, // delay (or random chance)
+ { // roomVolList
+ {10,8,1},
+ {12,7,7},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 52 Passing car sound
+ {
+ FX_FIESTA, // sampleId
+ FX_RANDOM, // type
+ 127, // delay (or random chance)
+ { // roomVolList
+ {10,8,1},
+ {12,7,7},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 53 Passing car sound
+ {
+ FX_CARLTON , // sampleId
+ FX_RANDOM, // type
+ 119, // delay (or random chance)
+ { // roomVolList
+ {10,8,1},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 54 Bird
+ {
+ FX_BIRD, // sampleId
+ FX_RANDOM, // type
+ 500, // delay (or random chance)
+ { // roomVolList
+ {9,10,10}, // {roomNo,leftVol,rightVol}
+ {10,2,1},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 55 George tries the door: GEOTRY
+ {
+ FX_DOORTRY, // sampleId
+ FX_SPOT, // type
+ 7, // delay (or random chance)
+ { // roomVolList
+ {9,9,9}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 56 George opens the door: GEODOOR9
+ {
+ FX_FLATDOOR, // sampleId
+ FX_SPOT, // type
+ 10, // delay (or random chance)
+ { // roomVolList
+ {9,9,9}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 57 George picks the 'phone up: GEOPHN10
+ {
+ FX_FONEUP, // sampleId
+ FX_SPOT, // type
+ 15, // delay (or random chance)
+ { // roomVolList
+ {10,9,9}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 58 George puts the 'phone down: GEPDWN10
+ {
+ FX_FONEDN, // sampleId
+ FX_SPOT, // type
+ 4, // delay (or random chance)
+ { // roomVolList
+ {10,9,9}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 59 Albert opens the door: ALBOPEN
+ {
+ FX_ALBOP, // sampleId
+ FX_SPOT, // type
+ 13, // delay (or random chance)
+ { // roomVolList
+ {5,10,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ //------------------------
+ // 60 Albert closes the door: ALBCLOSE
+ {
+ FX_ALBCLO, // sampleId
+ FX_SPOT, // type
+ 20, // delay (or random chance)
+ { // roomVolList
+ {5,9,9}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 61 George enter Nico's flat. GEOENT10
+ {
+ FX_NICOPEN, // sampleId
+ FX_SPOT, // type
+ 1, // delay (or random chance)
+ { // roomVolList
+ {10,7,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 62 George leaves Nico's. GEOLVS10
+ {
+ FX_NICLOSE, // sampleId
+ FX_SPOT, // type
+ 13, // delay (or random chance)
+ { // roomVolList
+ {10,7,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 63 Another bird for the street.
+ {
+ FX_BIRD2, // sampleId
+ FX_RANDOM, // type
+ 500, // WAS 15 (TOO LATE)
+ { // roomVolList
+ {9,10,10}, // {roomNo,leftVol,rightVol}
+ {10,2,1},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 64 George sits in the chair: GEOCHR
+ {
+ FX_GEOCHAIR, // sampleId
+ FX_SPOT, // type
+ 14, // delay (or random chance)
+ { // roomVolList
+ {10,5,5}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 65 George sits on the couch: GEOCCH
+ {
+ FX_GEOCCH, // sampleId
+ FX_SPOT, // type
+ 14, // delay (or random chance)
+ { // roomVolList
+ {10,5,5}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 66 George gets up from the chair: GEOCHR9
+ {
+ FX_GEOCHR9, // sampleId
+ FX_SPOT, // type
+ 5, // delay (or random chance)
+ { // roomVolList
+ {10,3,3}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 67 George is electrocuted: COSSHK
+ {
+ FX_SHOCK1, // sampleId
+ FX_SPOT, // type
+ 19, // delay (or random chance)
+ { // roomVolList
+ {11,10,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 68 George plays record: GEOWIND
+ {
+ FX_GRAMOFON, // sampleId
+ FX_SPOT, // type
+ 0, // delay (or random chance)
+ { // roomVolList
+ {11,11,13}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 69 George is frisked: GORFRK
+ {
+ FX_FRISK, // sampleId
+ FX_SPOT, // type
+ 6, // delay (or random chance)
+ { // roomVolList
+ {12,8,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 70 Traffic sound
+ {
+ FX_TRAFFIC3, // sampleId
+ FX_LOOP, // type
+ 0, // delay (or random chance)
+ { // roomVolList
+ {11,5,4},
+ {12,1,1},
+ {16,4,4},
+ {18,2,3},
+ {46,4,3},
+ {0,0,0}, // NULL-TERMINATOR
+ }
+ },
+ //------------------------
+ // 71 Latvian reading: LATRDS
+ {
+ FX_PAPER6, // sampleId
+ FX_SPOT, // type
+ 8, // delay (or random chance)
+ { // roomVolList
+ {13,8,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 72 Deskbell
+ {
+ FX_DESKBELL, // sampleId
+ FX_SPOT, // type
+ 0, // delay (or random chance)
+ { // roomVolList
+ {13,10,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 73 George picks up hotel 'phone: GEOTEL
+ {
+ FX_PHONEUP2, // sampleId
+ FX_SPOT, // type
+ 10, // delay (or random chance)
+ { // roomVolList
+ {13,8,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 74 George puts down hotel 'phone: GEOTEL9
+ {
+ FX_PHONEDN2, // sampleId
+ FX_SPOT, // type
+ 10, // delay (or random chance)
+ { // roomVolList
+ {13,8,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 75 George tries doors in corridor: GEODOR
+ {
+ FX_TRYDOR14, // sampleId
+ FX_SPOT, // type
+ 10, // delay (or random chance)
+ { // roomVolList
+ {14,8,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 76 George opens bedside cabinet: BEDDOR
+ {
+ FX_CABOPEN, // sampleId
+ FX_SPOT, // type
+ 11, // delay (or random chance)
+ { // roomVolList
+ {15,10,14}, // {roomNo,leftVol,rightVol}
+ {17,10,14},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 77 George closes bedside cabinet: BEDDOR (reversed)
+ {
+ FX_CABCLOSE, // sampleId
+ FX_SPOT, // type
+ 5, // delay (or random chance)
+ { // roomVolList
+ {15,10,14}, // {roomNo,leftVol,rightVol}
+ {17,10,14},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 78 George opens the window: WINDOW
+ {
+ FX_WINDOPEN, // sampleId
+ FX_SPOT, // type
+ 19, // delay (or random chance)
+ { // roomVolList
+ {15,8,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 79 George goes right along the ledge: GEOIRW
+ {
+ FX_LEDGE1, // sampleId
+ FX_SPOT, // type
+ 1, // delay (or random chance)
+ { // roomVolList
+ {16,12,12}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ //------------------------
+ // 80 George goes left along the ledge: GEOILW
+ {
+ FX_LEDGE2, // sampleId
+ FX_SPOT, // type
+ 1, // delay (or random chance)
+ { // roomVolList
+ {16,12,12}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 81 Pigeon noises
+ {
+ FX_COO, // sampleId
+ FX_RANDOM, // type
+ 80, // delay (or random chance)
+ { // roomVolList
+ {16,7,9}, // {roomNo,leftVol,rightVol}
+ {46,5,4},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 82 Pigeon noises
+ {
+ FX_COO2, // sampleId
+ FX_RANDOM, // type
+ 60, // delay (or random chance)
+ { // roomVolList
+ {15,3,4}, // {roomNo,leftVol,rightVol}
+ {16,8,5}, // {roomNo,leftVol,rightVol}
+ {17,3,4},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 83 George picks up and opens case: GEOBFC
+ {
+ FX_BRIEFON, // sampleId
+ FX_SPOT, // type
+ 16, // delay (or random chance)
+ { // roomVolList
+ {17,12,12}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 84 George closes and puts down case: GEOBFC (reversed)
+ {
+ FX_BRIEFOFF, // sampleId
+ FX_SPOT, // type
+ 12, // delay (or random chance)
+ { // roomVolList
+ {17,12,12}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 85 George gets into wardrobe. GEOWRB2 Attention, James. This is new as of 15/7/96
+ {
+ FX_WARDIN, // sampleId
+ FX_SPOT, // type
+ 6, // delay (or random chance)
+ { // roomVolList
+ {17,4,4}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 86 George gets out of wardrobe. GEOWRB2 (Reversed). Attention, James. This is new as of 15/7/96
+ {
+ FX_WARDOUT, // sampleId
+ FX_SPOT, // type
+ 41, // delay (or random chance)
+ { // roomVolList
+ {17,4,4}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 87 George jumps in through window: GEOWIN2
+ {
+ FX_JUMPIN, // sampleId
+ FX_SPOT, // type
+ 7, // delay (or random chance)
+ { // roomVolList
+ {15,8,10},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 88 George climbs in: GEOWIN2/GEOWIN8
+ {
+ FX_CLIMBIN, // sampleId
+ FX_SPOT, // type
+ 0, // delay (or random chance)
+ { // roomVolList
+ {17,8,16}, // {roomNo,leftVol,rightVol}
+ {15,8,16},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 89 George climbs out: GEOWIN1/GEOWIN9
+ {
+ FX_CLIMBOUT, // sampleId
+ FX_SPOT, // type
+ 17, // delay (or random chance)
+ { // roomVolList
+ {17,9,10}, // {roomNo,leftVol,rightVol}
+ {15,9,10},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 90 George picks the 'phone up: GEOTEL18
+ {
+ FX_FONEUP, // sampleId
+ FX_SPOT, // type
+ 10, // delay (or random chance)
+ { // roomVolList
+ {18,4,3}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 91 George puts the 'phone down: GEOTL18A
+ {
+ FX_FONEDN, // sampleId
+ FX_SPOT, // type
+ 11, // delay (or random chance)
+ { // roomVolList
+ {18,4,3}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 92 George tries to get keys. GEOKEY
+ {
+ FX_KEY13, // sampleId
+ FX_SPOT, // type
+ 8, // delay (or random chance)
+ { // roomVolList
+ {13,3,2}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 93 George manages to get keys. GEOKEY13
+ {
+ FX_KEY13, // sampleId
+ FX_SPOT, // type
+ 9, // delay (or random chance)
+ { // roomVolList
+ {13,3,2}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 94 George electrocutes Maguire: MAGSHK
+ {
+ FX_SHOCK2, // sampleId
+ FX_SPOT, // type
+ 8, // delay (or random chance)
+ { // roomVolList
+ {19,9,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 95 George opens dray door : GEOTRP8
+ {
+ FX_TRAPOPEN, // sampleId
+ FX_SPOT, // type
+ 20, // delay (or random chance)
+ { // roomVolList
+ {19,10,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 96 George breaks switch : Which anim?
+ {
+ FX_SWITCH19, // sampleId
+ FX_SPOT, // type
+ 10, // delay (or random chance)
+ { // roomVolList
+ {19,10,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 97 Leary pulls pint: LESPMP
+ {
+ FX_PULLPINT, // sampleId
+ FX_SPOT, // type
+ 6, // delay (or random chance)
+ { // roomVolList
+ {20,10,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 98 Glasswasher fuse blows (and the glass washer grinds to a halt)
+ {
+ FX_FUSE20, // sampleId
+ FX_SPOT, // type
+ 0, // delay (or random chance)
+ { // roomVolList
+ {20,8,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 99 Fitz leaps to his feet: FTZSTD
+ {
+ FX_FITZUP, // sampleId
+ FX_SPOT, // type
+ 5, // delay (or random chance)
+ { // roomVolList
+ {20,8,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ //------------------------
+ // 100 Fitz runs for it: FTZRUN
+ {
+ FX_FITZRUN, // sampleId
+ FX_SPOT, // type
+ 15, // delay (or random chance)
+ { // roomVolList
+ {20,12,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 101 George pulls lever: GEOLVR & GEOLVR26
+ {
+ FX_LEVER, // sampleId
+ FX_SPOT, // type
+ 26, // delay (or random chance)
+ { // roomVolList
+ {21,8,10}, // {roomNo,leftVol,rightVol}
+ {26,8,10},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 102 George pulls lever: GEOLVR8 & GEOLVR08
+ {
+ FX_LEVER2, // sampleId
+ FX_SPOT, // type
+ 9, // delay (or random chance)
+ { // roomVolList
+ {21,8,10}, // {roomNo,leftVol,rightVol}
+ {26,8,10},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 103 George opens tap: No idea what the anim is
+ {
+ FX_TAP, // sampleId
+ FX_SPOT, // type
+ 10, // delay (or random chance)
+ { // roomVolList
+ {21,8,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 104 George closes tap: No idea what this anim is either
+ {
+ FX_TAP2, // sampleId
+ FX_SPOT, // type
+ 10, // delay (or random chance)
+ { // roomVolList
+ {21,8,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 105 Bar flap: FLPOPN
+ {
+ FX_BARFLAP, // sampleId
+ FX_SPOT, // type
+ 1, // delay (or random chance)
+ { // roomVolList
+ {20,6,6}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 106 Farmer leaves: FRMWLK
+ {
+ FX_FARMERGO, // sampleId
+ FX_SPOT, // type
+ 11, // delay (or random chance)
+ { // roomVolList
+ {22,6,9}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 107 George climbs haystack: GEOCLM
+ {
+ FX_CLIMBHAY, // sampleId
+ FX_SPOT, // type
+ 11, // delay (or random chance)
+ { // roomVolList
+ {22,14,14}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 108 George drives sewer key into wall: GEOKEY23
+ {
+ FX_KEYSTEP, // sampleId
+ FX_SPOT, // type
+ 39, // delay (or random chance)
+ { // roomVolList
+ {23,8,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 109 George climbs over wall: GEOCLM23
+ {
+ FX_CASTLWAL, // sampleId
+ FX_SPOT, // type
+ 17, // delay (or random chance)
+ { // roomVolList
+ {23,8,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ //------------------------
+ // 110 George falls from wall: GEOTRY23
+ {
+ FX_CLIMBFAL, // sampleId
+ FX_SPOT, // type
+ 43, // delay (or random chance)
+ { // roomVolList
+ {23,12,12}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 111 Goat chewing: GOTEAT
+ {
+ FX_GOATCHEW, // sampleId
+ FX_SPOT, // type
+ 1, // delay (or random chance)
+ { // roomVolList
+ {24,10,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 112 George moves plough: GEOPLW
+ {
+ FX_PLOUGH, // sampleId
+ FX_SPOT, // type
+ 8, // delay (or random chance)
+ { // roomVolList
+ {24,10,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 113 George drops slab: STNFALL
+ {
+ FX_SLABFALL, // sampleId
+ FX_SPOT, // type
+ 6, // delay (or random chance)
+ { // roomVolList
+ {25,10,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 114 George picks up slab: GEOSTN8
+ {
+ FX_SLABUP, // sampleId
+ FX_SPOT, // type
+ 29, // delay (or random chance)
+ { // roomVolList
+ {25,10,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 115 Secret door opens: ALTOPN
+ {
+ FX_SECDOR25, // sampleId
+ FX_SPOT, // type
+ 17, // delay (or random chance)
+ { // roomVolList
+ {25,10,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 116 George wrings out cloth: GEOTWL25
+ {
+ FX_WRING, // sampleId
+ FX_SPOT, // type
+ 24, // delay (or random chance)
+ { // roomVolList
+ {25,10,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 117 Rat running across barrels: RATJMP
+ {
+ FX_RAT3A, // sampleId
+ FX_SPOT, // type
+ 1, // delay (or random chance)
+ { // roomVolList
+ {26,8,5}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 118 Rat running across barrels: RATJMP
+ {
+ FX_RAT3B, // sampleId
+ FX_SPOT, // type
+ 8, // delay (or random chance)
+ { // roomVolList
+ {26,7,6}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 119 Rat running across barrels: RATJMP
+ {
+ FX_RAT3C, // sampleId
+ FX_SPOT, // type
+ 26, // delay (or random chance)
+ { // roomVolList
+ {26,8,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ //------------------------
+ // 120 Irish bird song 1:
+ {
+ FX_EIRBIRD1, // sampleId
+ FX_RANDOM, // type
+ 720, // delay (or random chance)
+ { // roomVolList
+ {19,6,8}, // {roomNo,leftVol,rightVol}
+ {21,2,3},
+ {22,8,5},
+ {23,6,5},
+ {24,8,8},
+ {0,0,0}, // NULL-TERMINATOR
+ }
+ },
+ //------------------------
+ // 121 Irish bird song 2:
+ {
+ FX_EIRBIRD2, // sampleId
+ FX_RANDOM, // type
+ 720, // delay (or random chance)
+ { // roomVolList
+ {19,8,6}, // {roomNo,leftVol,rightVol}
+ {21,2,3},
+ {22,6,8},
+ {23,5,5},
+ {24,8,8},
+ {0,0,0}, // NULL-TERMINATOR
+ }
+ },
+ //------------------------
+ // 122 Irish bird song 3:
+ {
+ FX_EIRBIRD3, // sampleId
+ FX_RANDOM, // type
+ 720, // delay (or random chance)
+ { // roomVolList
+ {19,8,8}, // {roomNo,leftVol,rightVol}
+ {21,3,4},
+ {22,8,8},
+ {23,5,6},
+ {24,6,8},
+ {0,0,0}, // NULL-TERMINATOR
+ }
+ },
+ //------------------------
+ // 123 Rat 3D:
+ {
+ FX_RAT3D, // sampleId
+ FX_RANDOM, // type
+ 600, // delay (or random chance)
+ { // roomVolList
+ {26,2,3}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ }
+ },
+ //------------------------
+ // 124 Wind atop the battlements
+ {
+ FX_WIND, // sampleId
+ FX_LOOP, // type
+ 0, // delay (or random chance)
+ { // roomVolList
+ {23,6,6}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ }
+ },
+ //------------------------
+ // 125 Glasswasher in the pub (Room 20) *JEL* Stops after fuse blows and starts when george fixes it.
+ {
+ FX_WASHER, // sampleId
+ FX_LOOP, // type
+ 0, // delay (or random chance)
+ { // roomVolList
+ {20,4,4}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ }
+ },
+ //------------------------
+ // 126 Running tap in the cellar: (Room 21) *JEL* Only when the tap is on.
+ {
+ FX_CELTAP, // sampleId
+ FX_LOOP, // type
+ 0, // delay (or random chance)
+ { // roomVolList
+ {21,3,3}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ }
+ },
+ //------------------------
+ // 127 Lopez's hose. Basically a loop but stops when George cuts the water supply. Replaces MUTTER1.
+ {
+ FX_HOSE57, // sampleId
+ FX_LOOP, // type
+ 0, // delay (or random chance)
+ { // roomVolList
+ {57,3,1}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ }
+ },
+ //------------------------
+ // 128 Lopez's hose being switched off. Anim GARD05. Replaces MUTTER2.
+ {
+ FX_HOSE57B, // sampleId
+ FX_SPOT, // type
+ 1, // delay (or random chance)
+ { // roomVolList
+ {57,3,2}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ }
+ },
+ //------------------------
+ // 129 Nejo bouncing the ball off the door. NEJ8
+ {
+ FX_BALLPLAY, // sampleId
+ FX_SPOT, // type
+ 13, // delay (or random chance)
+ { // roomVolList
+ {45,5,1}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ }
+ },
+ //------------------------
+ //------------------------
+ // 130 Cricket loop for Syrian desert Only audible in 55 when the cave door is open.
+ {
+ FX_CRICKET, // sampleId
+ FX_LOOP, // type
+ 0, // delay (or random chance)
+ { // roomVolList
+ {54,8,8}, // {roomNo,leftVol,rightVol}
+ {55,3,5},
+ {0,0,0}, // NULL-TERMINATOR
+ }
+ },
+ //------------------------
+ // 131 Display case shatters: GEOTOTB
+ {
+ FX_SMASHGLA, // sampleId
+ FX_SPOT, // type
+ 35, // delay (or random chance)
+ { // roomVolList
+ {29,16,12}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ }
+ },
+ //------------------------
+ // 132 Burglar alarm: Once the case is smashed (see 131)
+ {
+ FX_ALARM, // sampleId
+ FX_LOOP, // type
+ 0, // delay (or random chance)
+ { // roomVolList
+ {28,12,12}, // {roomNo,leftVol,rightVol}
+ {29,16,16}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ }
+ },
+ //------------------------
+ // 133 Guido fires: GUIGUN
+ {
+ FX_GUN1, // sampleId
+ FX_SPOT, // type
+ 7, // delay (or random chance)
+ { // roomVolList
+ {29,16,16}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ }
+ },
+ //------------------------
+ // 134 Guido knocked down: NICPUS1
+ {
+ FX_GUI_HIT, // sampleId
+ FX_SPOT, // type
+ 40, // delay (or random chance)
+ { // roomVolList
+ {29,10,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ }
+ },
+ //------------------------
+ // 135 Museum exterior ambience
+ {
+ FX_MUESEXT, // sampleId
+ FX_LOOP, // type
+ 0, // delay (or random chance)
+ { // roomVolList
+ {27,10,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ }
+ },
+ //------------------------
+ // 136 Cat gets nowty: CAT3
+ {
+ FX_STALLCAT, // sampleId
+ FX_SPOT, // type
+ 1, // delay (or random chance)
+ { // roomVolList
+ {45,10,6}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ }
+ },
+ //------------------------
+ // 137 Cat gets very nowty: CAT5
+ {
+ FX_CATHIT, // sampleId
+ FX_SPOT, // type
+ 4, // delay (or random chance)
+ { // roomVolList
+ {45,10,6}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ }
+ },
+ //------------------------
+ // 138 Desert wind: Only audible in 55 when the cave door is open.
+ {
+ FX_SYRIWIND, // sampleId
+ FX_RANDOM, // type
+ 720, // delay (or random chance)
+ { // roomVolList
+ {54,10,10}, // {roomNo,leftVol,rightVol}
+ {55,5,7},
+ {0,0,0}, // NULL-TERMINATOR
+ }
+ },
+ //------------------------
+ // 139 Bell on Nejo's stall: GEOSYR7
+ {
+ FX_STALLBEL, // sampleId
+ FX_SPOT, // type
+ 7, // delay (or random chance)
+ { // roomVolList
+ {45,10,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ }
+ },
+ //------------------------
+ //------------------------
+ // 140 George electrocutes Khan: GEOSYR40
+ {
+ FX_SHOCK3, // sampleId
+ FX_SPOT, // type
+ 6, // delay (or random chance)
+ { // roomVolList
+ {54,10,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 141 George thumps Khan: GEOSYR40
+ {
+ FX_THUMP1, // sampleId
+ FX_SPOT, // type
+ 22, // delay (or random chance)
+ { // roomVolList
+ {54,12,12}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 142 Khan hits the floor: KHS9
+ {
+ FX_KHANDOWN, // sampleId
+ FX_SPOT, // type
+ 24, // delay (or random chance)
+ { // roomVolList
+ {54,8,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 143 Hospital ambience
+ {
+ FX_HOSPNOIS, // sampleId
+ FX_LOOP, // type
+ 0, // delay (or random chance)
+ { // roomVolList
+ {32,6,4}, // {roomNo,leftVol,rightVol}
+ {33,7,7},
+ {34,3,4},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 144 Mr Shiny switched on: DOMPLG (Start FX_SHINY)
+ {
+ FX_SHINYON, // sampleId
+ FX_SPOT, // type
+ 0, // delay (or random chance)
+ { // roomVolList
+ {33,12,14}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 145 Mr Shiny running
+ {
+ FX_SHINY, // sampleId
+ FX_LOOP, // type
+ 0, // delay (or random chance)
+ { // roomVolList
+ {32,4,3}, // {roomNo,leftVol,rightVol}
+ {33,12,14},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 146 Mr Shiny switched off: GEOPLG33 (Turn off FX_SHINY at the same time)
+ {
+ FX_SHINYOFF, // sampleId
+ FX_SPOT, // type
+ 0, // delay (or random chance)
+ { // roomVolList
+ {33,12,16}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 147 Benoir takes blood pressure: BENBP1 or BENBP2
+ {
+ FX_BLOODPRE, // sampleId
+ FX_SPOT, // type
+ 39, // delay (or random chance)
+ { // roomVolList
+ {34,14,16}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 148 George takes blood pressure: GEOBP1 or GEOBP2
+ {
+ FX_BLOODPRE, // sampleId
+ FX_SPOT, // type
+ 62, // delay (or random chance)
+ { // roomVolList
+ {34,14,16}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 149 Goat baas as it attacks: GOTCR and GOTCL
+ {
+ FX_GOATBAA, // sampleId
+ FX_SPOT, // type
+ 1, // delay (or random chance)
+ { // roomVolList
+ {24,12,12}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ //------------------------
+ // 150 Goat peeved at being trapped: GOTPLW (I'd advise triggering this anim randomly if you haven't done that)
+ {
+ FX_GOATDOH, // sampleId
+ FX_SPOT, // type
+ 7, // delay (or random chance)
+ { // roomVolList
+ {24,7,6}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 151 George triggers the Irish secret door: GEOPUT
+ {
+ FX_TRIGER25, // sampleId
+ FX_SPOT, // type
+ 35, // delay (or random chance)
+ { // roomVolList
+ {25,6,5}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 152 George winds up gramophone: GEOWIND
+ {
+ FX_WINDUP11, // sampleId
+ FX_SPOT, // type
+ 16, // delay (or random chance)
+ { // roomVolList
+ {11,7,7}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 153 Marib ambience
+ {
+ FX_MARIB, // sampleId
+ FX_LOOP, // type
+ 0, // delay (or random chance)
+ { // roomVolList
+ {45,7,7}, // {roomNo,leftVol,rightVol}
+ {47,5,5},
+ {50,5,4},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 154 Statuette breaks: STA2
+ {
+ FX_STATBREK, // sampleId
+ FX_SPOT, // type
+ 10, // delay (or random chance)
+ { // roomVolList
+ {45,7,4}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 155 George opens toilet door: CUBDOR50
+ {
+ FX_CUBDOR, // sampleId
+ FX_SPOT, // type
+ 6, // delay (or random chance)
+ { // roomVolList
+ {50,6,6}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 156 Crowd goes, "Ooh!": CRO36APP
+ {
+ FX_OOH, // sampleId
+ FX_SPOT, // type
+ 1, // delay (or random chance)
+ { // roomVolList
+ {36,6,7}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 157 Phone rings: When Nico calls back in room 41. Loops until the guard answers it.
+ {
+ FX_PHONCALL, // sampleId
+ FX_LOOP, // type
+ 0, // delay (or random chance)
+ { // roomVolList
+ {41,16,16}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 158 Phone picked up in 41: GUA41ANS
+ {
+ FX_FONEUP41, // sampleId
+ FX_SPOT, // type
+ 18, // delay (or random chance)
+ { // roomVolList
+ {41,5,6}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 159 George turns thermostat: GEO41THE (another dummy). Also used on the reverse.
+ {
+ FX_THERMO1, // sampleId
+ FX_SPOT, // type
+ 10, // delay (or random chance)
+ { // roomVolList
+ {41,6,5}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 160 Low echoing rumble of large church
+ {
+ FX_CHURCHFX, // sampleId
+ FX_LOOP, // type
+ 0, // delay (or random chance)
+ { // roomVolList
+ {38,5,5}, // {roomNo,leftVol,rightVol}
+ {48,5,5}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 161 George drys hand: GEO43HAN
+ {
+ FX_DRIER1, // sampleId
+ FX_SPOT, // type
+ 9, // delay (or random chance)
+ { // roomVolList
+ {43,16,16}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 162 George jumps in through window: GEOWIN8
+ {
+ FX_JUMPIN, // sampleId
+ FX_SPOT, // type
+ 49, // delay (or random chance)
+ { // roomVolList
+ {17,8,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 163 Khan fires: KHS12
+ {
+ FX_SHOTKHAN, // sampleId
+ FX_SPOT, // type
+ 30, // delay (or random chance)
+ { // roomVolList
+ {54,5,5}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 164 Khan fires: KHS5
+ {
+ FX_SHOTKHAN, // sampleId
+ FX_SPOT, // type
+ 5, // delay (or random chance)
+ { // roomVolList
+ {54,5,5}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 165 George falls: GEOSYR37
+ {
+ FX_GEOFAL54, // sampleId
+ FX_SPOT, // type
+ 25, // delay (or random chance)
+ { // roomVolList
+ {54,5,5}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 166 George falls after going for the gun (GEOSYR42)
+ {
+ FX_GEOFAL54, // sampleId
+ FX_SPOT, // type
+ 46, // delay (or random chance)
+ { // roomVolList
+ {54,5,5}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 167 Pickaxe sound 5: Screen 1 - WRKDIG01
+ {
+ FX_PICK5, // sampleId
+ FX_SPOT, // type
+ 9, // delay (or random chance) *
+ { // roomVolList
+ {1,3,3}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 168 George climbs ladder in 7: GEOASC07
+ {
+ FX_SEWLADU7, // sampleId
+ FX_SPOT, // type
+ 7, // delay (or random chance) *
+ { // roomVolList
+ {7,8,9}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 169 George picks keys up in Alamut: GEOKEYS1
+ {
+ FX_KEYS49, // sampleId
+ FX_SPOT, // type
+ 9, // delay (or random chance) *
+ { // roomVolList
+ {49,8,7}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ //------------------------
+ // 170 George puts down keys up in Alamut: GEOKEYS2
+ {
+ FX_KEYS49, // sampleId
+ FX_SPOT, // type
+ 7, // delay (or random chance) *
+ { // roomVolList
+ {49,8,7}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 171 George unlocks toilet door: GEOSYR43
+ {
+ FX_UNLOCK49, // sampleId
+ FX_SPOT, // type
+ 16, // delay (or random chance) *
+ { // roomVolList
+ {49,6,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 172 George breaks the toilet chain. GEOSYR48
+ {
+ FX_WCCHAIN, // sampleId
+ FX_SPOT, // type
+ 10, // delay (or random chance) *
+ { // roomVolList
+ {50,6,7}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 173 George breaks the branch of the cliff edge tree. GEOSYR20
+ {
+ FX_BREKSTIK, // sampleId
+ FX_SPOT, // type
+ 16, // delay (or random chance) *
+ { // roomVolList
+ {54,6,6}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 174 George climbs down the cliff face. GEOSYR23
+ {
+ FX_CLIMBDWN, // sampleId
+ FX_SPOT, // type
+ 6, // delay (or random chance) *
+ { // roomVolList
+ {54,6,7}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 175 George pulls ring: GEOSYR26
+ {
+ FX_RINGPULL, // sampleId
+ FX_SPOT, // type
+ 1, // delay (or random chance) *
+ { // roomVolList
+ {54,7,4}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 176 Bull's Head door opens: SECDOR
+ {
+ FX_SECDOR54, // sampleId
+ FX_SPOT, // type
+ 1, // delay (or random chance) *
+ { // roomVolList
+ {54,7,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 177 Inside Bull's Head door opens: DOOR55 (and its reverse).
+ {
+ FX_SECDOR55, // sampleId
+ FX_SPOT, // type
+ 1, // delay (or random chance) *
+ { // roomVolList
+ {55,4,12}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 178 Ayub opens door. AYU1
+ {
+ FX_AYUBDOOR, // sampleId
+ FX_SPOT, // type
+ 1, // delay (or random chance) *
+ { // roomVolList
+ {45,8,3}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 179 George knocks at the door in location 4: GEONOK followed by reverse of GEONOK
+ {
+ FX_KNOKKNOK, // sampleId
+ FX_SPOT, // type
+ 13, // delay (or random chance) *
+ { // roomVolList
+ {4,16,16}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 180 George knocks at the door in location 5: GEONOK05
+ {
+ FX_KNOKKNOK, // sampleId
+ FX_SPOT, // type
+ 8, // delay (or random chance) *
+ { // roomVolList
+ {5,8,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 181 Those pesky Irish birds turn up in Spain, too.
+ {
+ FX_SPNBIRD1, // sampleId
+ FX_RANDOM, // type
+ 720, // delay (or random chance) *
+ { // roomVolList
+ {57,1,4},
+ {58,8,4},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 182 Those pesky Irish birds turn up in Spain, too.
+ {
+ FX_SPNBIRD2, // sampleId
+ FX_RANDOM, // type
+ 697, // delay (or random chance) *
+ { // roomVolList
+ {57,4,8}, // {roomNo,leftVol,rightVol}
+ {58,4,1},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 183 The secret door in the well: SECDOR61 anim
+ {
+ FX_SECDOR61, // sampleId
+ FX_SPOT, // type
+ 1, // delay (or random chance) *
+ { // roomVolList
+ {61,4,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 184 Spanish countryside ambience
+ {
+ FX_SPAIN, // sampleId
+ FX_LOOP, // type
+ 0, // delay (or random chance) *
+ { // roomVolList
+ {57,1,2}, //
+ {58,2,2}, //
+ {60,1,1}, //
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 185 Spanish well ambience
+ {
+ FX_WELLDRIP, // sampleId
+ FX_LOOP, // type
+ 0, // delay (or random chance) *
+ { // roomVolList
+ {61,4,4}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 186 Fish falls on George's head: GEOTOT29
+ {
+ FX_FISHFALL, // sampleId
+ FX_SPOT, // type
+ 60, // delay (or random chance) *
+ { // roomVolList
+ {29,10,16}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 187 Hospital exterior ambience
+ {
+ FX_HOSPEXT, // sampleId
+ FX_LOOP, // type
+ 0, // delay (or random chance) *
+ { // roomVolList
+ {31,3,4}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 188 Hospital exterior gravel footstep #1
+ {
+ FX_GRAVEL1, // sampleId
+ FX_SPOT, // type
+ 0, // delay (or random chance) *
+ { // roomVolList
+ {31,16,16}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 189 Hospital exterior gravel footstep #2
+ {
+ FX_GRAVEL2, // sampleId
+ FX_SPOT, // type
+ 0, // delay (or random chance) *
+ { // roomVolList
+ {31,16,16}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ //------------------------
+ // 190 George opens sarcophagus: GEOSAR
+ {
+ FX_SARCO28A, // sampleId
+ FX_SPOT, // type
+ 26, // delay (or random chance) *
+ { // roomVolList
+ {28,6,6}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 191 George closes sarcophagus: GEOSAR2
+ {
+ FX_SARCO28B, // sampleId
+ FX_SPOT, // type
+ 24, // delay (or random chance) *
+ { // roomVolList
+ {28,3,3}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 192 Guard opens sarcophagus: MUSOPN
+ {
+ FX_SARCO28C, // sampleId
+ FX_SPOT, // type
+ 14, // delay (or random chance) *
+ { // roomVolList
+ {28,3,3}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 193 George peeks out of sarcophagus: GEOPEEK
+ {
+ FX_SARCO29, // sampleId
+ FX_SPOT, // type
+ 4, // delay (or random chance) *
+ { // roomVolList
+ {29,5,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 194 The rope drops into the room: ROPE29
+ {
+ FX_ROPEDOWN, // sampleId
+ FX_SPOT, // type
+ 3, // delay (or random chance) *
+ { // roomVolList
+ {29,3,3}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 195 George pushes the totem pole: GEOTOT29
+ {
+ FX_TOTEM29A, // sampleId
+ FX_SPOT, // type
+ 30, // delay (or random chance) *
+ { // roomVolList
+ {29,12,12}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 196 George pushes the totem pole over: GEOTOTB
+ {
+ FX_TOTEM29B, // sampleId
+ FX_SPOT, // type
+ 1, // delay (or random chance) *
+ { // roomVolList
+ {29,16,16}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 197 George rocks the totem pole in museum hours: TOTEM28
+ {
+ FX_TOTEM28A, // sampleId
+ FX_SPOT, // type
+ 8, // delay (or random chance) *
+ { // roomVolList
+ {28,4,4}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 198 Ambient sound for Montfauçon Square
+ {
+ FX_MONTAMB, // sampleId
+ FX_LOOP, // type
+ 0, // delay (or random chance) *
+ { // roomVolList
+ {36,6,6}, // {roomNo,leftVol,rightVol}
+ {40,6,6},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 199 Ambient sound churchyard.
+ {
+ FX_WIND71, // sampleId
+ FX_RANDOM, // type
+ 720, // delay (or random chance) *
+ { // roomVolList
+ {71,10,10}, // {roomNo,leftVol,rightVol}
+ {72,7,7},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 200 Owl cry #1 in churchyard
+ {
+ FX_OWL71A, // sampleId
+ FX_RANDOM, // type
+ 720, // delay (or random chance) *
+ { // roomVolList
+ {71,8,8}, // {roomNo,leftVol,rightVol}
+ {72,6,4},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 201 Owl cry #2 in churchyard
+ {
+ FX_OWL71B, // sampleId
+ FX_RANDOM, // type
+ 1080, // delay (or random chance) *
+ { // roomVolList
+ {71,8,8}, // {roomNo,leftVol,rightVol}
+ {72,7,6},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 202 Air conditioner in the museum
+ {
+ FX_AIRCON28, // sampleId
+ FX_LOOP, // type
+ 0, // delay (or random chance) *
+ { // roomVolList
+ {28,6,6}, // {roomNo,leftVol,rightVol}
+ {29,3,3},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 203 George breaks the handle off in the church tower. GEOWND72
+ {
+ FX_COG72A, // sampleId
+ FX_SPOT, // type
+ 5, // delay (or random chance) *
+ { // roomVolList
+ {72,10,10},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 204 Countess' room ambience
+ {
+ FX_AMBIEN56, // sampleId
+ FX_LOOP, // type
+ 0, // delay (or random chance) *
+ { // roomVolList
+ {56,3,2}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 205 Musical effect for George drinking beer. GEODRN20
+ {
+ FX_DRINK, // sampleId
+ FX_SPOT, // type
+ 17, // delay (or random chance) *
+ { // roomVolList
+ {20,12,12}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 206 Torch thrown through the air. GEOTHROW
+ {
+ FX_TORCH73, // sampleId
+ FX_SPOT, // type
+ 14, // delay (or random chance) *
+ { // roomVolList
+ {73,16,16}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 207 Internal train ambience.
+ {
+ FX_TRAININT, // sampleId
+ FX_LOOP, // type
+ 0, // delay (or random chance) *
+ { // roomVolList
+ {63,3,3}, // {roomNo,leftVol,rightVol}
+ {65,2,2},
+ {66,2,2},
+ {67,2,2},
+ {69,2,2},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 208 Countess' clock. PENDULUM. Note: Trigger the sound effect on alternate runs of the pendulum animation.
+ {
+ FX_PENDULUM, // sampleId
+ FX_SPOT, // type
+ 6, // delay (or random chance) *
+ { // roomVolList
+ {56,2,2}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 209 Compartment door. DOOR65
+ {
+ FX_DOOR65, // sampleId
+ FX_SPOT, // type
+ 1, // delay (or random chance) *
+ { // roomVolList
+ {65,3,3}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ //------------------------
+ // 210 Opening window. GEOOPN1
+ {
+ FX_WINDOW66, // sampleId
+ FX_SPOT, // type
+ 8, // delay (or random chance) *
+ { // roomVolList
+ {66,5,5}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 211 Wind rip by the open window. Triggered at the end of effect 210.
+ {
+ FX_WIND66, // sampleId
+ FX_LOOP, // type
+ 0, // delay (or random chance) *
+ { // roomVolList
+ {66,5,5}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 212 George electrocutes himself on the pantograph. Fool. GEOSHK64
+ {
+ FX_SHOCK63, // sampleId
+ FX_SPOT, // type
+ 11, // delay (or random chance) *
+ { // roomVolList
+ {63,12,14}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 213 The train brakes violently. GEOSTP69
+ {
+ FX_BRAKES, // sampleId
+ FX_SPOT, // type
+ 13, // delay (or random chance) *
+ { // roomVolList
+ {69,16,16}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 214 The train ticks over. From the end of BRAKE.
+ {
+ FX_TICK69, // sampleId
+ FX_LOOP, // type
+ 0, // delay (or random chance) *
+ { // roomVolList
+ {69,8,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 215 Eklund shoot Khan. FIGHT69
+ {
+ FX_EKSHOOT, // sampleId
+ FX_SPOT, // type
+ 120, // delay (or random chance) *
+ { // roomVolList
+ {69,12,12}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 216 Eklund shoots George. GEODIE69
+ {
+ FX_EKSHOOT, // sampleId
+ FX_SPOT, // type
+ 21, // delay (or random chance) *
+ { // roomVolList
+ {69,12,12}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 217 Khan pulls the door open. FIGHT69
+ {
+ FX_DOOR69, // sampleId
+ FX_SPOT, // type
+ 42, // delay (or random chance) *
+ { // roomVolList
+ {69,8,12}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 218 Wind shriek. Loops from the end of DOOR69 wav to the beginning of BRAKES.
+ {
+ FX_WIND66, // sampleId
+ FX_LOOP, // type
+ 0, // delay (or random chance) *
+ { // roomVolList
+ {69,8,12}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 219 Brakes releasing pressure. Only after BRAKE has been run.
+ {
+ FX_PNEUMO69, // sampleId
+ FX_RANDOM, // type
+ 720, // delay (or random chance) *
+ { // roomVolList
+ {69,8,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 220 External train sound. Played while George is on the top of the train.
+ {
+ FX_TRAINEXT, // sampleId
+ FX_LOOP, // type
+ 0, // delay (or random chance) *
+ { // roomVolList
+ {63,8,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 221 The passing train. FIGHT69
+ {
+ FX_TRNPASS, // sampleId
+ FX_SPOT, // type
+ 102, // delay (or random chance) *
+ { // roomVolList
+ {69,4,16}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 222 George descends into sewer. GEODESO6
+ {
+ FX_LADD2, // sampleId
+ FX_SPOT, // type
+ 1, // delay (or random chance) *
+ { // roomVolList
+ {6,4,4}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 223 George ascends into alley. GEOASC06
+ {
+ FX_LADD3, // sampleId
+ FX_SPOT, // type
+ 10, // delay (or random chance) *
+ { // roomVolList
+ {6,4,4}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 224 George replaces manhole cover. GEOMAN9
+ {
+ FX_COVERON2, // sampleId
+ FX_SPOT, // type
+ 19, // delay (or random chance) *
+ { // roomVolList
+ {2,12,11}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 225 Montfaucon sewer ambience.
+ {
+ FX_AMBIEN37, // sampleId
+ FX_LOOP, // type
+ 0, // delay (or random chance) *
+ { // roomVolList
+ {37,5,5}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 226 George's winning smile. GEOJMP72.
+ {
+ FX_PING, // sampleId
+ FX_SPOT, // type
+ 26, // delay (or random chance) *
+ { // roomVolList
+ {72,10,14}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 227 George starts to open the manhole. GEO36KNE
+ {
+ FX_MANOP36, // sampleId
+ FX_SPOT, // type
+ 19, // delay (or random chance) *
+ { // roomVolList
+ {36,4,6}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 228 George opens the manhole. GEO36OPE
+ {
+ FX_PULLUP36, // sampleId
+ FX_SPOT, // type
+ 9, // delay (or random chance) *
+ { // roomVolList
+ {36,4,6}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 229 George replaces the manhole cover. GEO36CLO
+ {
+ FX_REPLCE36, // sampleId
+ FX_SPOT, // type
+ 20, // delay (or random chance) *
+ { // roomVolList
+ {36,4,6}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ //------------------------
+ // 230 George knocks at righthand arch. GEO37TA3
+ {
+ FX_KNOCK37, // sampleId
+ FX_SPOT, // type
+ 20, // delay (or random chance) *
+ { // roomVolList
+ {37,6,12}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 231 George knocks at middle or lefthand arch. GEO37TA1 or GEO37TA2.
+ {
+ FX_KNOCK37B, // sampleId
+ FX_SPOT, // type
+ 20, // delay (or random chance) *
+ { // roomVolList
+ {37,4,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 232 George winds the chain down HOO37LBO
+ {
+ FX_CHAIN37, // sampleId
+ FX_SPOT, // type
+ 14, // delay (or random chance) *
+ { // roomVolList
+ {37,6,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 233 George winds the chain up. HOO37LBO (In reverse)
+ {
+ FX_CHAIN37B, // sampleId
+ FX_SPOT, // type
+ 1, // delay (or random chance) *
+ { // roomVolList
+ {37,6,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 234 George breaks hole in door. GEO37TA4
+ {
+ FX_HOLE37, // sampleId
+ FX_SPOT, // type
+ 11, // delay (or random chance) *
+ { // roomVolList
+ {37,6,12}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 235 Plaster door collapses. DOR37COL
+ {
+ FX_DOOR37, // sampleId
+ FX_SPOT, // type
+ 23, // delay (or random chance) *
+ { // roomVolList
+ {37,8,15}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 236 Barge winch. GEO37TUL (If it runs more than once, trigger the effect on frame one. Incidentally, this is a reversible so the effect must launch on frame one of the .cdr version as well. )
+ {
+ FX_WINCH37, // sampleId
+ FX_SPOT, // type
+ 1, // delay (or random chance) *
+ { // roomVolList
+ {37,16,16}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 237 George places chess piece. GEOSPA17
+ {
+ FX_CHESS, // sampleId
+ FX_SPOT, // type
+ 23, // delay (or random chance) *
+ { // roomVolList
+ {59,4,4}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 238 Piano loop for the upstairs hotel corridor.
+ {
+ FX_PIANO14, // sampleId
+ FX_LOOP, // type
+ 0, // delay (or random chance) *
+ { // roomVolList
+ {14,2,2}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 239 Door opens in church tower. PANEL72
+ {
+ FX_SECDOR72, // sampleId
+ FX_SPOT, // type
+ 1, // delay (or random chance) *
+ { // roomVolList
+ {72,8,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ //------------------------
+ // 240 George rummages through debris. Tied to the end of the whichever crouch is used. Use either this one or RUMMAGE2 alternatively or randomly. Same kind of schtick as the pick axe noises, I suppose.
+ {
+ FX_RUMMAGE1, // sampleId
+ FX_SPOT, // type
+ 9, // delay (or random chance) *
+ { // roomVolList
+ {72,8,6}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 241 George rummages through debris. See above for notes.
+ {
+ FX_RUMMAGE2, // sampleId
+ FX_SPOT, // type
+ 9, // delay (or random chance) *
+ { // roomVolList
+ {72,8,6}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 242 Gust of wind in the graveyard.
+ {
+ FX_GUST71, // sampleId
+ FX_RANDOM, // type
+ 1080, // delay (or random chance) *
+ { // roomVolList
+ {71,3,3}, // {roomNo,leftVol,rightVol}
+ {72,2,1},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 243 Violin ambience for Ireland.
+ {
+ FX_VIOLIN19, // sampleId
+ FX_LOOP, // type
+ 0, // delay (or random chance) *
+ { // roomVolList
+ {19,3,3}, // {roomNo,leftVol,rightVol}
+ {21,2,2},
+ {26,2,2},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 244 Footstep #1 for underground locations. Same schtick as for 188 and 189.
+ {
+ FX_SEWSTEP1, // sampleId
+ FX_SPOT, // type
+ 0, // delay (or random chance) *
+ { // roomVolList
+ {6,8,8}, // {roomNo,leftVol,rightVol}
+ {7,8,8},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 245 Footstep #2 for underground locations. Same schtick as for 188 and 189.
+ {
+ FX_SEWSTEP2, // sampleId
+ FX_SPOT, // type
+ 0, // delay (or random chance) *
+ { // roomVolList
+ {6,16,16}, // {roomNo,leftVol,rightVol}
+ {7,16,16},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 246 Nico's carabiner as she descends into the museum. NICPUS1
+ {
+ FX_CARABINE, // sampleId
+ FX_SPOT, // type
+ 4, // delay (or random chance) *
+ { // roomVolList
+ {29,8,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 247 Rosso is shot (with a piece of field artillery). ROSSHOT
+ {
+ FX_GUN79, // sampleId
+ FX_SPOT, // type
+ 2, // delay (or random chance) *
+ { // roomVolList
+ {79,16,16}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 248 George is hit by the thrown stilletto. GEODIE1
+ {
+ FX_DAGGER1, // sampleId
+ FX_SPOT, // type
+ 2, // delay (or random chance) *
+ { // roomVolList
+ {73,12,12}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 249 George is hit by the thrown stilletto after walking forward. GEODIE2
+ {
+ FX_DAGGER1, // sampleId
+ FX_SPOT, // type
+ 9, // delay (or random chance) *
+ { // roomVolList
+ {73,12,12}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ //------------------------
+ // 250 Can hits the well water. The cue is in GAR2SC57.TXT immediately after the line, "over: Lopez threw the can away. It seemed to fall an awfully long way."
+ {
+ FX_CANFALL, // sampleId
+ FX_SPOT, // type
+ 4, // delay (or random chance) *
+ { // roomVolList
+ {57,16,16}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 251 Mad, fizzing damp and ancient gunpowder after the application of a torch.
+ {
+ FX_GUNPOWDR, // sampleId
+ FX_LOOP, // type
+ 0, // delay (or random chance) *
+ { // roomVolList
+ {73,12,12}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 252 Maguire whistling. MAGSLK. Plays while Maguire is idling, stops abruptly when he does something else.
+ {
+ FX_WHISTLE, // sampleId
+ FX_LOOP, // type
+ 0, // delay (or random chance) *
+ { // roomVolList
+ {19,2,5}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 253 George is hit by the goat. GEOHITR and GEOHITL.
+ {
+ FX_GEOGOAT, // sampleId
+ FX_SPOT, // type
+ 11, // delay (or random chance) *
+ { // roomVolList
+ {24,10,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 254 Manager says, "Hello". MAN2
+ {
+ FX_MANG1, // sampleId
+ FX_SPOT, // type
+ 7, // delay (or random chance) *
+ { // roomVolList
+ {49,6,5}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 255 Manager says, Don't go in there!" MAN3
+ {
+ FX_MANG2, // sampleId
+ FX_SPOT, // type
+ 11, // delay (or random chance) *
+ { // roomVolList
+ {49,6,5}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 256 Manager says, "Here are the keys." MAN4
+ {
+ FX_MANG3, // sampleId
+ FX_SPOT, // type
+ 6, // delay (or random chance) *
+ { // roomVolList
+ {49,6,5}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 257 George pulls the lion's tooth. GEOSPA26
+ {
+ FX_TOOTHPUL, // sampleId
+ FX_SPOT, // type
+ 19, // delay (or random chance) *
+ { // roomVolList
+ {61,8,16}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 258 George escapes the lion. LION1
+ {
+ FX_LIONFALL, // sampleId
+ FX_SPOT, // type
+ 7, // delay (or random chance) *
+ { // roomVolList
+ {61,8,16}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 259 George gets flattened. LION2
+ {
+ FX_LIONFAL2, // sampleId
+ FX_SPOT, // type
+ 4, // delay (or random chance) *
+ { // roomVolList
+ {61,8,16}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 260 Rosso dies. ROSSFALL
+ {
+ FX_ROSSODIE, // sampleId
+ FX_SPOT, // type
+ 1, // delay (or random chance) *
+ { // roomVolList
+ {74,16,16}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 261 Eklund chokes George. FIGHT79
+ {
+ FX_CHOKE1, // sampleId
+ FX_SPOT, // type
+ 9, // delay (or random chance) *
+ { // roomVolList
+ {79,16,16}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 262 Eklund chokes George some more. FIGHT79
+ {
+ FX_CHOKE2, // sampleId
+ FX_SPOT, // type
+ 54, // delay (or random chance) *
+ { // roomVolList
+ {79,16,16}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 263 Eklund dies. FIGHT79
+ {
+ FX_FIGHT2, // sampleId
+ FX_SPOT, // type
+ 44, // delay (or random chance) *
+ { // roomVolList
+ {79,16,16}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 264 George hears museum break-in. GEOSUR29
+ {
+ FX_DOOR29, // sampleId
+ FX_SPOT, // type
+ 10, // delay (or random chance) *
+ { // roomVolList
+ {94,14,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 265 George hits the floor having been shot. GEODED.
+ {
+ FX_GDROP29, // sampleId
+ FX_SPOT, // type
+ 27, // delay (or random chance) *
+ { // roomVolList
+ {29,10,16}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 266 George hits the floor having been stunned. GEOFISH
+ {
+ FX_GDROP29, // sampleId
+ FX_SPOT, // type
+ 27, // delay (or random chance) *
+ { // roomVolList
+ {29,10,16}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 267 Fitz being knocked down as heard from inside the pub. Triggered from the script, I think. This is just a stopgap until Hackenbacker do the full version for the Smacker, then I'll sample the requisite bit and put it in here.
+ {
+ FX_FITZHIT, // sampleId
+ FX_SPOT, // type
+ 1, // delay (or random chance) *
+ { // roomVolList
+ {20,16,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 268 Gendarme shoots lock off. GENSHOT
+ {
+ FX_GUN34, // sampleId
+ FX_SPOT, // type
+ 1, // delay (or random chance) *
+ { // roomVolList
+ {34,16,16}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 269 ECG alarm, Marquet in trouble. Start looping imeediately before George says, "Thanks, Bunny".
+ // Incidentally, James, please switch off Mr Shiney permanently when George first gets into Marquet's room. He gets in the way when they're figuring out that Eklund's an imposter.
+ {
+ FX_PULSE2, // sampleId
+ FX_LOOP, // type
+ 1, // delay (or random chance) *
+ { // roomVolList
+ {30,16,16}, // {roomNo,leftVol,rightVol}
+ {34,12,12}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ //------------------------
+ // 270 ECG alarm, Marquet dead. Switch off the previous effect and replace with this immediately before the gendarme says, "Stand back, messieurs."
+ {
+ FX_PULSE3, // sampleId
+ FX_LOOP, // type
+ 1, // delay (or random chance) *
+ { // roomVolList
+ {30,16,16}, // {roomNo,leftVol,rightVol}
+ {34,13,13},
+ {35,13,13},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 271 Door closing. GEOENT15
+ {
+ FX_DORCLOSE, // sampleId
+ FX_SPOT, // type
+ 4, // delay (or random chance) *
+ { // roomVolList
+ {15,12,12}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 272 Cupboard opening. GEOCOT
+ {
+ FX_CUPBOPEN, // sampleId
+ FX_SPOT, // type
+ 8, // delay (or random chance) *
+ { // roomVolList
+ {33,12,12}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 273 Cupboard closing. GEOCOT
+ {
+ FX_CUPBCLOS, // sampleId
+ FX_SPOT, // type
+ 33, // delay (or random chance) *
+ { // roomVolList
+ {33,12,12}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 274 Closing door when George leaves hotel room. GEOLVS15 and GEODOR17 (they're identical).
+ {
+ FX_DORCLOSE, // sampleId
+ FX_SPOT, // type
+ 44, // delay (or random chance) *
+ { // roomVolList
+ {15,12,12}, // {roomNo,leftVol,rightVol}
+ {17,12,12},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 275 Closing door when George leaves the pub. DOROPN20 (Reversed)
+ {
+ FX_DORCLOSE20,// sampleId
+ FX_SPOT, // type
+ 11, // delay (or random chance) *
+ { // roomVolList
+ {20,12,12}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 276 Nico call for a cab. NICPHN10
+ {
+ FX_PHONICO1, // sampleId
+ FX_SPOT, // type
+ 15, // delay (or random chance) *
+ { // roomVolList
+ {10,12,12}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 277 Nico puts down the phone. NICDWN10
+ {
+ FX_FONEDN, // sampleId
+ FX_SPOT, // type
+ 6, // delay (or random chance) *
+ { // roomVolList
+ {10,12,12}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 278 Painter puts down the phone. PAI41HAN
+ {
+ FX_FONEDN41, // sampleId
+ FX_SPOT, // type
+ 5, // delay (or random chance) *
+ { // roomVolList
+ {41,12,12}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 279 Mechanical hum of heating system in the dig lobby.
+ {
+ FX_AIRCON41, // sampleId
+ FX_LOOP, // type
+ 0, // delay (or random chance) *
+ { // roomVolList
+ {41,6,6}, // {roomNo,leftVol,rightVol}
+ {43,8,8},
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ //------------------------
+ // 280 The Sword is Reforged (Grandmaster gets zapped) GMPOWER
+ {
+ FX_REFORGE1, // sampleId
+ FX_SPOT, // type
+ 1, // delay (or random chance) *
+ { // roomVolList
+ {78,16,16}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 281 The Sword is Reforged (G&N gawp at the spectacle) There's no anim I know of to tie it to unless the flickering blue light is one.
+ {
+ FX_REFORGE2, // sampleId
+ FX_SPOT, // type
+ 1, // delay (or random chance) *
+ { // roomVolList
+ {75,12,12}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 282 The Sword is Reforged (We watch over G&N's heads as the Grandmaster gets zapped) GMWRIT74
+ {
+ FX_REFORGE2, // sampleId
+ FX_SPOT, // type
+ 1, // delay (or random chance) *
+ { // roomVolList
+ {74,14,14}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 283 The Sword is Reforged (Grandmaster finishes being zapped) GMWRITH
+ {
+ FX_REFORGE4, // sampleId
+ FX_SPOT, // type
+ 1, // delay (or random chance) *
+ { // roomVolList
+ {78,16,16}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 284 Baphomet Cavern Ambience
+ {
+ FX_BAPHAMB, // sampleId
+ FX_LOOP, // type
+ 0, // delay (or random chance) *
+ { // roomVolList
+ {74,6,8}, // {roomNo,leftVol,rightVol}
+ {75,7,8}, // {roomNo,leftVol,rightVol}
+ {76,8,8}, // {roomNo,leftVol,rightVol}
+ {77,8,8}, // {roomNo,leftVol,rightVol}
+ {78,8,8}, // {roomNo,leftVol,rightVol}
+ {79,7,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 285 Duane's Happy-Snappy Camera. XDNEPHO3 and XDNEPHO5.
+ {
+ FX_CAMERA45, // sampleId
+ FX_SPOT, // type
+ 30, // delay (or random chance) *
+ { // roomVolList
+ {45,4,4}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 286 Grand Master strikes the floor with his cane. GMENTER
+ {
+ FX_STAFF, // sampleId
+ FX_SPOT, // type
+ 28, // delay (or random chance) *
+ { // roomVolList
+ {73,8,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 287 George descends ladder in 7: GEOASC07 (Reversed) This used to be handled by effect #46 but it didn't fit at all.
+ {
+ FX_SEWLADD7, // sampleId
+ FX_SPOT, // type
+ 1, // delay (or random chance) *
+ { // roomVolList
+ {7,8,9}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 288 Sam kicks the recalcitrant Mr. Shiny. DOMKIK
+ {
+ FX_KIKSHINY, // sampleId
+ FX_SPOT, // type
+ 16, // delay (or random chance) *
+ { // roomVolList
+ {33,9,9}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 289 Gust of wind outside bombed cafe. LVSFLY
+ {
+ FX_LVSFLY, // sampleId
+ FX_SPOT, // type
+ 1, // delay (or random chance) *
+ { // roomVolList
+ {1,16,16}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 290 Ron's disgusting No.1 Sneeze. Either this or the next effect (randomly chosen) is used for the following animations, RONSNZ & RONSNZ2
+ {
+ FX_SNEEZE1, // sampleId
+ FX_SPOT, // type
+ 11, // delay (or random chance) *
+ { // roomVolList
+ {20,10,16}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 291 Ron's disgusting No.2 Sneeze. Either this or the previous effect (randomly chosen) is used for the following animations, RONSNZ & RONSNZ2
+ {
+ FX_SNEEZE2, // sampleId
+ FX_SPOT, // type
+ 11, // delay (or random chance) *
+ { // roomVolList
+ {20,10,16}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 292 Dripping tap in the pub cellar. TAPDRP
+ {
+ FX_DRIPIRE, // sampleId
+ FX_SPOT, // type
+ 9, // delay (or random chance) *
+ { // roomVolList
+ {21,4,4}, // {roomNo,leftVol,rightVol}
+ {26,4,4}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 293 Dripping tap in the pub cellar. TAPDRP
+ {
+ FX_DRIPIRE2, // sampleId
+ FX_SPOT, // type
+ 9, // delay (or random chance) *
+ { // roomVolList
+ {21,4,4}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 294 Dripping tap in the excavation toilet. (see WATER43 - but it's looped anyway, not triggered with anim)
+ {
+ FX_TAPDRIP, // sampleId
+ FX_SPOT, // type
+ 6, // delay (or random chance) *
+ { // roomVolList
+ {43,8,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 295 George closes the mausoleum window. GEOSPA23
+ {
+ FX_WINDOW59, // sampleId
+ FX_SPOT, // type
+ 24, // delay (or random chance) *
+ { // roomVolList
+ {59,10,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 296 George opens the mausoleum window, the feebleminded loon. GEOSPA23 reversed.
+ {
+ FX_WINDOW59, // sampleId
+ FX_SPOT, // type
+ 14, // delay (or random chance) *
+ { // roomVolList
+ {59,10,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 297 When George & Nico hear chanting from sc73
+ {
+ FX_CHANT, // sampleId
+ FX_SPOT, // type
+ 10, // delay (or random chance) *
+ { // roomVolList
+ {73,2,4}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 298 EKFIGHT
+ {
+ FX_FIGHT1, // sampleId
+ FX_SPOT, // type
+ 31, // delay (or random chance) *
+ { // roomVolList
+ {74,16,16}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 299 Small van passes, left to right. CARA9 and CARC9
+ {
+ FX_LITEVEHR, // sampleId
+ FX_SPOT, // type
+ 1, // delay (or random chance) *
+ { // roomVolList
+ {9,16,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 300 Small van passes, right to left to right. CARB9
+ {
+ FX_LITEVEHL, // sampleId
+ FX_SPOT, // type
+ 1, // delay (or random chance) *
+ { // roomVolList
+ {9,16,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 301 Truck passes, left to right. TRUCKA9 and TRUCKB9
+ {
+ FX_HVYVEHR, // sampleId
+ FX_SPOT, // type
+ 1, // delay (or random chance) *
+ { // roomVolList
+ {9,14,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 302 Truck passes, right to left. TRUCKC9
+ {
+ FX_HVYVEHL, // sampleId
+ FX_SPOT, // type
+ 1, // delay (or random chance) *
+ { // roomVolList
+ {9,14,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 303 With anim FIGHT69
+ {
+ FX_FIGHT69, // sampleId
+ FX_SPOT, // type
+ 78, // delay (or random chance) *
+ { // roomVolList
+ {69,12,16}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 304 With anim GEODIE1 in sc73
+ {
+ FX_GDROP73, // sampleId
+ FX_SPOT, // type
+ 14, // delay (or random chance) *
+ { // roomVolList
+ {73,12,16}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 305 With anim GEODIE2 in sc73
+ {
+ FX_GDROP73, // sampleId
+ FX_SPOT, // type
+ 21, // delay (or random chance) *
+ { // roomVolList
+ {73,12,16}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 306 With anim GEODES25
+ {
+ FX_LADDWN25, // sampleId
+ FX_SPOT, // type
+ 0, // delay (or random chance) *
+ { // roomVolList
+ {25,12,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 307 With anim GEOASC25
+ {
+ FX_LADDUP25, // sampleId
+ FX_SPOT, // type
+ 8, // delay (or random chance) *
+ { // roomVolList
+ {25,12,8}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 308 With anim GKSWORD in sc76
+ {
+ FX_GKSWORD, // sampleId
+ FX_SPOT, // type
+ 9, // delay (or random chance) *
+ { // roomVolList
+ {76,10,10}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 309 With anim GEO36KNE in sc36
+ {
+ FX_KEYIN, // sampleId
+ FX_SPOT, // type
+ 18, // delay (or random chance) *
+ { // roomVolList
+ {36,14,14}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 310 With anim GEO36ENT in sc36
+ {
+ FX_COVDWN, // sampleId
+ FX_SPOT, // type
+ 85, // delay (or random chance) *
+ { // roomVolList
+ {36,14,14}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+ // 311 With anim SECDOR59 in sc59
+ {
+ FX_SECDOR59, // sampleId
+ FX_SPOT, // type
+ 0, // delay (or random chance) *
+ { // roomVolList
+ {59,16,16}, // {roomNo,leftVol,rightVol}
+ {0,0,0}, // NULL-TERMINATOR
+ },
+ },
+ //------------------------
+};
+#endif
+//--------------------------------------------------------------------------------------
+// Continuous & random background sound effects for each location
+
+// NB. There must be a list for each room number, even if location doesn't exist in game
+
+const uint16 Sound::_roomsFixedFx[TOTAL_ROOMS][TOTAL_FX_PER_ROOM] =
+{
+ {0}, // 0
+
+ // PARIS 1
+ {2,3,4,5,0}, // 1
+ {2,0}, // 2
+ {2,3,4,5,32,0}, // 3
+ {2,3,4,5,0}, // 4
+ {2,3,4,5,0}, // 5
+ {9,11,12,13,44,45,47}, // 6
+ {9,11,12,13,44,45,47}, // 7
+ {2,3,4,5,0}, // 8
+
+ // PARIS 2
+ {54,63,0}, // 9
+ {51,52,53,54,63,0}, // 10
+ {70,0}, // 11
+ {51,52,70,0}, // 12
+ {0}, // 13
+ {238,0}, // 14
+ {82,0}, // 15
+ {70,81,82,0}, // 16
+ {82,0}, // 17
+ {3,4,5,70,0}, // 18
+
+ // IRELAND
+ {120,121,122,243,0}, // 19
+ {0}, // 20 Violin makes the ambience..
+ {120,121,122,243,0}, // 21
+ {120,121,122,0}, // 22
+ {120,121,122,124,0}, // 23
+ {120,121,122,0}, // 24
+ {0}, // 25
+ {123,243,0}, // 26
+
+ // PARIS 3
+ {135,0}, // 27
+ {202,0}, // 28
+ {202,0}, // 29
+ {0}, // 30
+ {187,0}, // 31
+ {143,145,0}, // 32
+ {143,0}, // 33
+ {143,0}, // 34
+ {0}, // 35
+
+ // PARIS 4
+ {198,0}, // 36
+ {225,0}, // 37
+ {160,0}, // 38
+ {0}, // 39
+ {198,0}, // 40
+ {279,0}, // 41
+ {0}, // 42
+ {279,0}, // 43
+ {0}, // 44 Doesn't exist
+
+ // SYRIA
+ {153,0}, // 45
+ {70,81,0}, // 46 - PARIS 2
+ {153,0}, // 47
+ {160,0}, // 48 - PARIS 4
+ {0}, // 49
+ {153,0}, // 50
+ {0}, // 51
+ {0}, // 52
+ {0}, // 53
+ {130,138,0}, // 54
+ {0}, // 55
+
+ // SPAIN
+ {204,0}, // 56
+ {181,182,184,0}, // 57
+ {181,182,184,0}, // 58
+ {0}, // 59
+ {184,0}, // 60
+ {185,0}, // 61
+ {0}, // 62 Just music
+
+ // NIGHT TRAIN
+ {207,0,0}, // 63
+ {0}, // 64 Doesn't exist
+ {207,0}, // 65
+ {207,0}, // 66
+ {207,0}, // 67
+ {0}, // 68 Disnae exist
+ {0}, // 69
+
+ // SCOTLAND + FINALE
+ {0}, // 70 Disnae exist
+ {199,200,201,242,0}, // 71
+ {199,200,201,242,0}, // 72
+ {0}, // 73
+ {284,0}, // 74
+ {284,0}, // 75
+ {284,0}, // 76
+ {284,0}, // 77
+ {284,0}, // 78
+ {284,0}, // 79
+ {0}, // 80
+ {0}, // 81
+ {0}, // 82
+ {0}, // 83
+ {0}, // 84
+ {0}, // 85
+ {0}, // 86
+ {0}, // 87
+ {0}, // 88
+ {0}, // 89
+ {0}, // 90
+ {0}, // 91
+ {0}, // 92
+ {0}, // 93
+ {0}, // 94
+ {0}, // 95
+ {0}, // 96
+ {0}, // 97
+ {0}, // 98
+ {0}, // 99
+};
+
+#define ENCODE8(VAL) \
+ (uint8)(VAL & 0xFF)
+#define ENCODE16(VAL) \
+ (uint8)(VAL & 0xFF), (uint8)(VAL >> 8)
+#define ENCODE24(VAL) \
+ (uint8)(VAL & 0xFF), (uint8)((VAL >> 8) & 0xFF), (uint8)(VAL >> 16)
+#define ENCODE32(VAL) \
+ (uint8)(VAL & 0xFF), (uint8)((VAL >> 8) & 0xFF), (uint8)((VAL >> 16) & 0xFF), (uint8)(VAL >> 24)
+
+#define LOGIC_CALL_FN(FN_ID, PARAM) \
+ opcCallFn, ENCODE8(FN_ID), ENCODE8(PARAM)
+#define LOGIC_CALL_FN_LONG(FN_ID, PARAM1, PARAM2, PARAM3) \
+ opcCallFnLong, ENCODE8(FN_ID), ENCODE32(PARAM1), ENCODE32(PARAM2), ENCODE32(PARAM3)
+#define LOGIC_SET_VAR8(VAR_ID, VAL) \
+ opcSetVar8, ENCODE16(VAR_ID), ENCODE8(VAL)
+#define LOGIC_SET_VAR16(VAR_ID, VAL) \
+ opcSetVar16, ENCODE16(VAR_ID), ENCODE16(VAL)
+#define LOGIC_SET_VAR32(VAR_ID, VAL) \
+ opcSetVar32, ENCODE16(VAR_ID), ENCODE32(VAL)
+#define GEORGE_POS(POS_X, POS_Y, DIR, PLACE) \
+ opcGeorge, ENCODE16(POS_X), ENCODE16(POS_Y), DIR, ENCODE24(PLACE)
+
+#define INIT_SEQ_END \
+ opcSeqEnd
+#define RUN_START_SCRIPT(SCR_ID) \
+ opcRunStart, ENCODE8(SCR_ID)
+#define RUN_HELPER_SCRIPT(SCR_ID) \
+ opcRunHelper, ENCODE8(SCR_ID)
+
+const uint8 g_startPos0[] = { // Intro with sequence
+ LOGIC_CALL_FN(opcPlaySequence, 4),
+ GEORGE_POS(481, 413, DOWN, FLOOR_1),
+ INIT_SEQ_END
+};
+
+const uint8 g_startPos1[] = { // Intro without sequence
+ GEORGE_POS(481, 413, DOWN, FLOOR_1),
+ INIT_SEQ_END
+};
+
+const uint8 g_startPos2[] = { // blind alley
+ GEORGE_POS(480, 388, DOWN_LEFT, FLOOR_2),
+ LOGIC_CALL_FN(opcAddObject, LIFTING_KEYS),
+ LOGIC_CALL_FN(opcAddObject, ROSSO_CARD),
+ INIT_SEQ_END
+};
+
+const uint8 g_startPos3[] = { // cafe
+ GEORGE_POS(660, 368, DOWN_LEFT, FLOOR_3),
+ INIT_SEQ_END
+};
+
+const uint8 g_startPos4[] = { // ready to use the phone
+ GEORGE_POS(463, 391, DOWN, FLOOR_4),
+ LOGIC_SET_VAR8(MOUE_TEXT, 1),
+ LOGIC_SET_VAR8(MOUE_NICO_FLAG, 1),
+ LOGIC_SET_VAR8(PARIS_FLAG, 5),
+ LOGIC_SET_VAR8(NICO_PHONE_FLAG, 1),
+ LOGIC_SET_VAR8(TAILOR_PHONE_FLAG, 1),
+ LOGIC_SET_VAR8(WORKMAN_GONE_FLAG, 1),
+ LOGIC_SET_VAR8(ALBERT_INFO_FLAG, 1),
+ LOGIC_SET_VAR8(SEEN_SEWERS_FLAG, 1),
+ // item stuff missing
+ INIT_SEQ_END
+};
+
+const uint8 g_startPos5[] = { // court yard
+ GEORGE_POS(400, 400, DOWN_LEFT, FLOOR_5),
+ INIT_SEQ_END
+};
+
+const uint8 g_startPos7[] = { // sewer two
+ GEORGE_POS(520, 310, DOWN_LEFT, FLOOR_7),
+ INIT_SEQ_END
+};
+
+const uint8 g_startPos8[] = { // cafe repaired
+ GEORGE_POS(481, 413, DOWN, FLOOR_8),
+ INIT_SEQ_END
+};
+
+const uint8 g_startPos11[] = { // costumier
+ GEORGE_POS(264, 436, DOWN_RIGHT, FLOOR_11),
+ LOGIC_CALL_FN(opcAddObject, TISSUE),
+ LOGIC_CALL_FN(opcAddObject, PHOTOGRAPH),
+ INIT_SEQ_END
+};
+
+const uint8 g_startPos12[] = { // hotel street
+ GEORGE_POS(730, 460, LEFT, FLOOR_12),
+ LOGIC_SET_VAR8(NICO_ADDRESS_FLAG, 1),
+ LOGIC_SET_VAR8(NICO_PHONE_FLAG, 1),
+ LOGIC_SET_VAR8(COSTUMES_ADDRESS_FLAG, 1),
+ LOGIC_SET_VAR8(HOTEL_ADDRESS_FLAG, 1),
+ LOGIC_SET_VAR8(AEROPORT_ADDRESS_FLAG, 1),
+ LOGIC_SET_VAR8(TAILOR_PHONE_FLAG, 1),
+ INIT_SEQ_END
+};
+
+const uint8 g_startPos14[] = { // hotel corridor
+ GEORGE_POS(528, 484, UP, FLOOR_14),
+ LOGIC_CALL_FN(opcAddObject, HOTEL_KEY),
+ LOGIC_CALL_FN(opcAddObject, MANUSCRIPT),
+ INIT_SEQ_END
+};
+
+const uint8 g_startPos17[] = { // hotel assassin
+ GEORGE_POS(714, 484, LEFT, FLOOR_17),
+ INIT_SEQ_END
+};
+
+const uint8 g_startPos18[] = { // gendarmerie
+ GEORGE_POS(446, 408, DOWN_LEFT, FLOOR_18),
+ LOGIC_SET_VAR8(PARIS_FLAG, 5),
+ INIT_SEQ_END
+};
+
+const uint8 g_startPos19[] = { // ireland street
+ GEORGE_POS(256, 966, UP_RIGHT, FLOOR_19),
+ RUN_HELPER_SCRIPT(HELP_IRELAND)
+};
+
+const uint8 g_startPos20[] = { // macdevitts
+ GEORGE_POS(194, 417, DOWN_RIGHT, FLOOR_20),
+ LOGIC_SET_VAR8(FARMER_MOVED_FLAG, 1),
+ LOGIC_SET_VAR8(FARMER_SEAN_FLAG, 5),
+ LOGIC_SET_VAR8(PUB_FLAP_FLAG, 1),
+ LOGIC_SET_VAR8(PUB_TRAP_DOOR, 2),
+ LOGIC_SET_VAR8(KNOWS_PEAGRAM_FLAG, 1),
+ RUN_HELPER_SCRIPT(HELP_IRELAND)
+};
+
+const uint8 g_startPos21[] = { // pub cellar
+ GEORGE_POS(291, 444, DOWN_RIGHT, FLOOR_21),
+ LOGIC_CALL_FN(opcAddObject, BEER_TOWEL),
+ LOGIC_SET_VAR8(FARMER_MOVED_FLAG, 1),
+ LOGIC_SET_VAR8(FLEECY_STUCK, 1),
+ LOGIC_SET_VAR8(LIFTING_KEYS_IN_HOLE_23, 1),
+ RUN_HELPER_SCRIPT(HELP_IRELAND)
+};
+
+const uint8 g_startPos22[] = { // castle gate
+ GEORGE_POS(547, 500, UP_LEFT, FLOOR_22),
+ LOGIC_SET_VAR8(IRELAND_FLAG, 4),
+ RUN_HELPER_SCRIPT(HELP_IRELAND)
+};
+
+const uint8 g_startPos23[] = { // castle hay top
+ GEORGE_POS(535, 510, UP, FLOOR_23),
+ RUN_HELPER_SCRIPT(HELP_IRELAND)
+};
+
+const uint8 g_startPos24[] = { // castle yard
+ GEORGE_POS(815, 446, DOWN_LEFT, FLOOR_24),
+ RUN_HELPER_SCRIPT(HELP_IRELAND)
+};
+
+const uint8 g_startPos25[] = { // castle dig
+ GEORGE_POS(369, 492, LEFT, FLOOR_25),
+ LOGIC_CALL_FN(opcAddObject, BEER_TOWEL),
+ LOGIC_SET_VAR8(BEER_TOWEL_BEEN_WET, 1),
+ LOGIC_SET_VAR16(WET_BEER_TOWEL_TIMER, 1000),
+ RUN_HELPER_SCRIPT(HELP_IRELAND)
+};
+
+const uint8 g_startPos26[] = { // cellar dark
+ GEORGE_POS(291, 444, DOWN_RIGHT, FLOOR_26),
+ RUN_HELPER_SCRIPT(HELP_IRELAND)
+};
+
+const uint8 g_startPos27[] = { // museum street
+ GEORGE_POS(300, 510, UP_RIGHT, FLOOR_27),
+ LOGIC_SET_VAR8(PARIS_FLAG, 12),
+ LOGIC_SET_VAR8(MANUSCRIPT_ON_TABLE_10_FLAG, 1),
+ INIT_SEQ_END
+};
+
+const uint8 g_startPos31[] = { // hospital street
+ GEORGE_POS(400, 500, UP_RIGHT, FLOOR_31),
+ LOGIC_SET_VAR8(PARIS_FLAG, 11),
+ LOGIC_CALL_FN(opcAddObject, PHOTOGRAPH),
+ LOGIC_CALL_FN(opcAddObject, LAB_PASS),
+ INIT_SEQ_END
+};
+
+const uint8 g_startPos32[] = { // hospital desk (after we've found out where Marquet is)
+ GEORGE_POS(405, 446, UP_RIGHT, FLOOR_32),
+ LOGIC_SET_VAR8(GOT_BENOIR_FLAG, 1),
+ LOGIC_CALL_FN(opcAddObject, PHOTOGRAPH),
+ LOGIC_CALL_FN(opcAddObject, LAB_PASS),
+ RUN_HELPER_SCRIPT(HELP_WHITECOAT)
+};
+
+const uint8 g_startPos35[] = { // hospital jacques
+ GEORGE_POS(640, 500, LEFT, FLOOR_35),
+ LOGIC_SET_VAR8(DOOR_34_OPEN, 1),
+ LOGIC_SET_VAR8(GOT_BENOIR_FLAG, 2),
+ LOGIC_SET_VAR8(HOS_POS_FLAG, 26),
+ LOGIC_SET_VAR8(BENOIR_FLAG, 24),
+ RUN_HELPER_SCRIPT(HELP_WHITECOAT)
+};
+
+const uint8 g_startPos36[] = { // montfaucon
+ GEORGE_POS(300, 480, RIGHT, FLOOR_36),
+ LOGIC_CALL_FN(opcAddObject, LENS),
+ LOGIC_CALL_FN(opcAddObject, RED_NOSE),
+ LOGIC_CALL_FN(opcAddObject, LIFTING_KEYS),
+ LOGIC_SET_VAR8(MONTFAUCON_CONTROL_FLAG, 1),
+ INIT_SEQ_END
+};
+
+const uint8 g_startPos37[] = { // catacomb sewer
+ GEORGE_POS(592, 386, RIGHT, FLOOR_37),
+ LOGIC_CALL_FN(opcAddObject, LIFTING_KEYS),
+ LOGIC_CALL_FN(opcAddObject, TRIPOD),
+ LOGIC_CALL_FN(opcAddObject, GEM),
+ INIT_SEQ_END
+};
+
+const uint8 g_startPos38[] = { // catacomb room
+ GEORGE_POS(200, 390, RIGHT, FLOOR_38),
+ LOGIC_CALL_FN(opcAddObject, TRIPOD),
+ LOGIC_CALL_FN(opcAddObject, GEM),
+ INIT_SEQ_END
+};
+
+const uint8 g_startPos39[] = { // catacomb meeting
+ GEORGE_POS(636, 413, DOWN_LEFT, FLOOR_39),
+ LOGIC_SET_VAR8(MEETING_FLAG, 3), // meeting finished
+ LOGIC_CALL_FN(opcAddObject, TRIPOD),
+ LOGIC_CALL_FN(opcAddObject, GEM),
+ INIT_SEQ_END
+};
+
+const uint8 g_startPos40[] = { // excavation exterior
+ GEORGE_POS(648, 492, LEFT, FLOOR_40),
+ LOGIC_SET_VAR8(NICO_PHONE_FLAG, 1),
+ LOGIC_SET_VAR8(PARIS_FLAG, 16),
+ LOGIC_CALL_FN(opcAddObject, PLASTER),
+ LOGIC_CALL_FN(opcAddObject, POLISHED_CHALICE),
+ INIT_SEQ_END
+};
+
+const uint8 g_startPos45[] = { // syria stall
+ GEORGE_POS(410, 490, DOWN_RIGHT, FLOOR_45),
+ RUN_HELPER_SCRIPT(HELP_SYRIA)
+};
+
+const uint8 g_startPos47[] = { // syria carpet
+ GEORGE_POS(225, 775, RIGHT, FLOOR_47),
+ RUN_HELPER_SCRIPT(HELP_SYRIA)
+};
+
+const uint8 g_startPos48[] = { // templar church
+ GEORGE_POS(315, 392, DOWN, FLOOR_48),
+ LOGIC_SET_VAR8(CHALICE_FLAG, 2),
+ LOGIC_SET_VAR8(NEJO_TEXT, 1),
+ LOGIC_CALL_FN(opcAddObject, CHALICE),
+ LOGIC_CALL_FN(opcAddObject, LENS),
+ INIT_SEQ_END
+};
+
+const uint8 g_startPos49[] = { // syria club
+ GEORGE_POS(438, 400, DOWN_RIGHT, FLOOR_49),
+ LOGIC_CALL_FN(opcAddObject, TOILET_BRUSH),
+ RUN_HELPER_SCRIPT(HELP_SYRIA)
+};
+
+const uint8 g_startPos50[] = { // syria toilet
+ GEORGE_POS(313, 440, DOWN_RIGHT, FLOOR_50),
+ LOGIC_CALL_FN(opcAddObject, TOILET_KEY),
+ RUN_HELPER_SCRIPT(HELP_SYRIA)
+};
+
+const uint8 g_startPos53[] = { // bull's head pan
+ LOGIC_SET_VAR32(CHANGE_PLACE, FLOOR_53),
+ LOGIC_CALL_FN(opcAddObject, TOWEL_CUT),
+ RUN_HELPER_SCRIPT(HELP_SYRIA)
+};
+
+const uint8 g_startPos54[] = { // bull's head
+ GEORGE_POS(680, 425, DOWN_LEFT, FLOOR_54),
+ LOGIC_CALL_FN(opcAddObject, TOWEL_CUT),
+ RUN_HELPER_SCRIPT(HELP_SYRIA)
+};
+
+const uint8 g_startPos55[] = { // bull secret
+ GEORGE_POS(825, 373, DOWN_LEFT, FLOOR_55),
+ RUN_HELPER_SCRIPT(HELP_SYRIA)
+};
+
+const uint8 g_startPos56[] = { // contess' room
+ GEORGE_POS(572, 443, LEFT, FLOOR_56),
+ RUN_HELPER_SCRIPT(HELP_SPAIN)
+};
+
+const uint8 g_startPos57[] = { // Spain drive
+ GEORGE_POS(1630, 460, DOWN_LEFT, FLOOR_57),
+ RUN_HELPER_SCRIPT(HELP_SPAIN)
+};
+
+const uint8 g_startPos58[] = { // Mausoleum Exterior
+ GEORGE_POS(SC58_PATH_X, SC58_PATH_Y, UP_RIGHT, FLOOR_58),
+ RUN_HELPER_SCRIPT(HELP_SPAIN)
+};
+
+const uint8 g_startPos59[] = { // Mausoleum interior
+ GEORGE_POS(750, 455, LEFT, FLOOR_59),
+ RUN_HELPER_SCRIPT(HELP_SPAIN)
+};
+
+const uint8 g_startPos60[] = { // Spain reception
+ GEORGE_POS(750, 475, DOWN_LEFT, FLOOR_60),
+ RUN_HELPER_SCRIPT(HELP_SPAIN)
+};
+
+const uint8 g_startPos61[] = { // Spain well
+ GEORGE_POS(400, 345, DOWN, LEFT_FLOOR_61),
+ LOGIC_CALL_FN(opcAddObject, STONE_KEY),
+ LOGIC_CALL_FN(opcAddObject, MIRROR),
+ RUN_HELPER_SCRIPT(HELP_SPAIN)
+};
+
+const uint8 g_startPos62[] = { // chess puzzle
+ LOGIC_SET_VAR32(CHANGE_PLACE, FLOOR_62),
+ LOGIC_SET_VAR8(TOP_MENU_DISABLED, 1),
+ LOGIC_SET_VAR8(GEORGE_ALLOWED_REST_ANIMS, 0),
+ LOGIC_CALL_FN_LONG(opcNoSprite, PLAYER, 0, 0),
+ RUN_HELPER_SCRIPT(HELP_SPAIN)
+};
+
+const uint8 g_startPos63[] = { // train one
+ GEORGE_POS(710, 450, LEFT, FLOOR_63),
+ LOGIC_SET_VAR8(DOOR_SC65_FLAG, 2),
+ LOGIC_SET_VAR8(DOOR_ONE_63_OPEN, 0),
+ LOGIC_SET_VAR8(DOOR_65_OPEN, 1),
+ LOGIC_SET_VAR8(VAIL_TEXT, 1),
+ RUN_HELPER_SCRIPT(HELP_NIGHTTRAIN)
+};
+
+const uint8 g_startPos65[] = { // compt one
+ GEORGE_POS(460, 430, DOWN, FLOOR_65),
+ RUN_HELPER_SCRIPT(HELP_NIGHTTRAIN)
+};
+
+const uint8 g_startPos66[] = { // compt two
+ GEORGE_POS(460, 430, DOWN, FLOOR_66),
+ RUN_HELPER_SCRIPT(HELP_NIGHTTRAIN)
+};
+
+const uint8 g_startPos67[] = { // compt three
+ GEORGE_POS(460, 430, DOWN, FLOOR_67),
+ RUN_HELPER_SCRIPT(HELP_NIGHTTRAIN)
+};
+
+const uint8 g_startPos69[] = { // train_guard
+ GEORGE_POS(310, 430, DOWN, FLOOR_69),
+ RUN_HELPER_SCRIPT(HELP_NIGHTTRAIN)
+};
+
+const uint8 g_startPos71[] = { // churchyard
+ GEORGE_POS(1638, 444, LEFT, RIGHT_FLOOR_71),
+ LOGIC_SET_VAR8(NICO_SCOT_SCREEN, 71),
+ LOGIC_SET_VAR8(NICO_POSITION_71, 1),
+ RUN_HELPER_SCRIPT(HELP_SCOTLAND)
+};
+
+const uint8 g_startPos72[] = { // church tower
+ GEORGE_POS(150, 503, RIGHT, FLOOR_72),
+ LOGIC_SET_VAR8(NICO_SCOT_SCREEN, 72),
+ RUN_HELPER_SCRIPT(HELP_SCOTLAND)
+};
+
+const uint8 g_startPos73[] = { // crypt
+ GEORGE_POS(250, 390, DOWN_RIGHT, FLOOR_73),
+ LOGIC_SET_VAR8(NICO_SCOT_SCREEN, 73),
+ LOGIC_SET_VAR8(NICO_POSITION_73, 1)
+};
+
+const uint8 g_startPos80[] = { // Paris map
+ GEORGE_POS(645, 160, DOWN, FLOOR_80),
+ LOGIC_SET_VAR8(PARIS_FLAG, 3),
+ LOGIC_SET_VAR8(NICO_CLOWN_FLAG, 3),
+ LOGIC_SET_VAR8(NICO_DOOR_FLAG, 2),
+
+ LOGIC_CALL_FN(opcAddObject, RED_NOSE),
+ LOGIC_CALL_FN(opcAddObject, PHOTOGRAPH),
+ LOGIC_CALL_FN(opcAddObject, PLASTER),
+ LOGIC_CALL_FN(opcAddObject, LAB_PASS),
+
+ LOGIC_SET_VAR8(MANUSCRIPT_FLAG, 1),
+ LOGIC_SET_VAR8(NICO_ADDRESS_FLAG, 1),
+ LOGIC_SET_VAR8(NICO_PHONE_FLAG, 1),
+ LOGIC_SET_VAR8(COSTUMES_ADDRESS_FLAG, 1),
+ LOGIC_SET_VAR8(HOTEL_ADDRESS_FLAG, 1),
+ LOGIC_SET_VAR8(MUSEUM_ADDRESS_FLAG, 1),
+ LOGIC_SET_VAR8(HOSPITAL_ADDRESS_FLAG, 1),
+ LOGIC_SET_VAR8(MONTFACN_ADDRESS_FLAG, 1),
+ LOGIC_SET_VAR8(AEROPORT_ADDRESS_FLAG, 1),
+ LOGIC_SET_VAR8(NERVAL_ADDRESS_FLAG, 1),
+
+ LOGIC_SET_VAR8(IRELAND_MAP_FLAG, 1),
+ LOGIC_SET_VAR8(SPAIN_MAP_FLAG, 1),
+ LOGIC_SET_VAR8(SYRIA_FLAG, 2),
+
+ LOGIC_SET_VAR8(TAILOR_PHONE_FLAG, 1),
+ INIT_SEQ_END
+};
+
+const uint8 g_genIreland[] = {
+ LOGIC_SET_VAR8(PARIS_FLAG, 9),
+ LOGIC_CALL_FN(opcAddObject, RED_NOSE),
+ LOGIC_CALL_FN(opcAddObject, PHOTOGRAPH),
+ LOGIC_CALL_FN(opcAddObject, LAB_PASS),
+ LOGIC_CALL_FN(opcAddObject, LIFTING_KEYS),
+ LOGIC_CALL_FN(opcAddObject, MATCHBOOK),
+ LOGIC_CALL_FN(opcAddObject, BUZZER),
+ LOGIC_CALL_FN(opcAddObject, TISSUE),
+ INIT_SEQ_END
+};
+
+const uint8 g_genSyria[] = {
+ LOGIC_SET_VAR8(PARIS_FLAG, 1),
+ LOGIC_CALL_FN(opcAddObject, BALL),
+ LOGIC_CALL_FN(opcAddObject, RED_NOSE),
+ LOGIC_CALL_FN(opcAddObject, PHOTOGRAPH),
+ LOGIC_CALL_FN(opcAddObject, LIFTING_KEYS),
+ LOGIC_CALL_FN(opcAddObject, MATCHBOOK),
+ LOGIC_CALL_FN(opcAddObject, BUZZER),
+ LOGIC_CALL_FN(opcAddObject, TISSUE),
+ LOGIC_SET_VAR8(CHANGE_STANCE, STAND),
+ INIT_SEQ_END
+};
+
+const uint8 g_genSpain[] = {
+ LOGIC_SET_VAR8(PARIS_FLAG, 1),
+ LOGIC_SET_VAR8(SPAIN_VISIT, 1), // default to 1st spain visit, may get overwritten later
+ LOGIC_CALL_FN(opcAddObject, RED_NOSE),
+ LOGIC_CALL_FN(opcAddObject, PHOTOGRAPH),
+ LOGIC_CALL_FN(opcAddObject, LAB_PASS),
+ LOGIC_CALL_FN(opcAddObject, LIFTING_KEYS),
+ LOGIC_CALL_FN(opcAddObject, BUZZER),
+ LOGIC_CALL_FN(opcAddObject, TISSUE),
+ LOGIC_CALL_FN(opcAddObject, BALL),
+ LOGIC_CALL_FN(opcAddObject, MATCHBOOK),
+ LOGIC_CALL_FN(opcAddObject, PRESSURE_GAUGE),
+ INIT_SEQ_END
+};
+
+const uint8 g_genSpain2[] = { // 2nd spain visit
+ LOGIC_SET_VAR8(SPAIN_VISIT, 2),
+ LOGIC_CALL_FN(opcRemoveObject, PRESSURE_GAUGE),
+ LOGIC_CALL_FN(opcAddObject, POLISHED_CHALICE),
+ INIT_SEQ_END
+};
+
+const uint8 g_genNightTrain[] = {
+ LOGIC_SET_VAR8(PARIS_FLAG, 18),
+ INIT_SEQ_END
+};
+
+const uint8 g_genScotland[] = {
+ LOGIC_SET_VAR8(PARIS_FLAG, 1),
+ LOGIC_CALL_FN(opcAddObject, RED_NOSE),
+ LOGIC_CALL_FN(opcAddObject, PHOTOGRAPH),
+ LOGIC_CALL_FN(opcAddObject, LAB_PASS),
+ LOGIC_CALL_FN(opcAddObject, LIFTING_KEYS),
+ LOGIC_CALL_FN(opcAddObject, BUZZER),
+ INIT_SEQ_END
+};
+
+const uint8 g_genWhiteCoat[] = {
+ LOGIC_SET_VAR8(PARIS_FLAG, 11),
+ LOGIC_SET_VAR8(EVA_TEXT, 1),
+ LOGIC_SET_VAR8(EVA_MARQUET_FLAG, 2),
+ LOGIC_SET_VAR8(EVA_NURSE_FLAG, 4),
+ LOGIC_SET_VAR8(FOUND_WARD_FLAG, 1),
+ LOGIC_SET_VAR8(CONSULTANT_HERE, 1),
+
+ LOGIC_CALL_FN_LONG(opcMegaSet, PLAYER, GEORGE_WLK, MEGA_WHITE),
+
+ LOGIC_SET_VAR32(GEORGE_CDT_FLAG, WHT_TLK_TABLE),
+ LOGIC_SET_VAR8(GEORGE_TALK_FLAG, 0),
+ LOGIC_SET_VAR8(WHITE_COAT_FLAG, 1),
+ LOGIC_SET_VAR8(GEORGE_ALLOWED_REST_ANIMS, 0),
+ INIT_SEQ_END
+};
+
+const uint8 *Logic::_startData[] = {
+ g_startPos0,
+ g_startPos1,
+ g_startPos2,
+ g_startPos3,
+ g_startPos4,
+ g_startPos5,
+ NULL, //g_startPos6,
+ g_startPos7,
+ g_startPos8,
+ NULL, //g_startPos9,
+ NULL, //g_startPos10,
+ g_startPos11,
+ g_startPos12,
+ NULL, //g_startPos13,
+ g_startPos14,
+ NULL, //g_startPos15,
+ NULL, //g_startPos16,
+ g_startPos17,
+ g_startPos18,
+ g_startPos19,
+ g_startPos20,
+ g_startPos21,
+ g_startPos22,
+ g_startPos23,
+ g_startPos24,
+ g_startPos25,
+ g_startPos26,
+ g_startPos27,
+ NULL, //g_startPos28,
+ NULL, //g_startPos29,
+ NULL, //g_startPos30,
+ g_startPos31,
+ g_startPos32,
+ NULL, //g_startPos33,
+ NULL, //g_startPos34,
+ g_startPos35,
+ g_startPos36,
+ g_startPos37,
+ g_startPos38,
+ g_startPos39,
+ g_startPos40,
+ NULL, //g_startPos41,
+ NULL, //g_startPos42,
+ NULL, //g_startPos43,
+ NULL, //g_startPos44,
+ g_startPos45,
+ NULL, //g_startPos46,
+ g_startPos47,
+ g_startPos48,
+ g_startPos49,
+ g_startPos50,
+ NULL, //g_startPos51,
+ NULL, //g_startPos52,
+ g_startPos53,
+ g_startPos54,
+ g_startPos55,
+ g_startPos56,
+ g_startPos57,
+ g_startPos58,
+ g_startPos59,
+ g_startPos60,
+ g_startPos61,
+ g_startPos62,
+ g_startPos63,
+ NULL, //g_startPos64,
+ g_startPos65,
+ g_startPos66,
+ g_startPos67,
+ NULL, //g_startPos68,
+ g_startPos69,
+ NULL, //g_startPos70,
+ g_startPos71,
+ g_startPos72,
+ g_startPos73,
+ NULL, //g_startPos74,
+ NULL, //g_startPos75,
+ NULL, //g_startPos76
+ NULL, //g_startPos77
+ NULL, //g_startPos78
+ NULL, //g_startPos79
+ g_startPos80
+};
+
+const uint8 *Logic::_helperData[] = {
+ g_genIreland,
+ g_genSyria,
+ g_genSpain,
+ g_genNightTrain,
+ g_genScotland,
+ g_genWhiteCoat,
+ g_genSpain2
+};
+
+} // End of namespace Sword1
+
+#ifdef PALMOS_68K
+#include "scumm_globals.h"
+
+_GINIT(Sword1_fxList)
+_GSETPTR(Sword1::Sound::_fxList, GBVARS_FXLIST_INDEX, Sword1::FxDef, GBVARS_SWORD1)
+_GEND
+
+_GRELEASE(Sword1_fxList)
+_GRELEASEPTR(GBVARS_FXLIST_INDEX, GBVARS_SWORD1)
+_GEND
+
+#endif
diff --git a/engines/sword1/sword1.cpp b/engines/sword1/sword1.cpp
new file mode 100644
index 0000000000..1f49426262
--- /dev/null
+++ b/engines/sword1/sword1.cpp
@@ -0,0 +1,615 @@
+/* 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 "sword1/sword1.h"
+
+#include "backends/fs/fs.h"
+
+#include "base/plugins.h"
+#include "common/config-manager.h"
+#include "common/file.h"
+#include "common/timer.h"
+#include "common/system.h"
+
+#include "sword1/resman.h"
+#include "sword1/objectman.h"
+#include "sword1/mouse.h"
+#include "sword1/logic.h"
+#include "sword1/sound.h"
+#include "sword1/screen.h"
+#include "sword1/swordres.h"
+#include "sword1/menu.h"
+#include "sword1/music.h"
+#include "sword1/control.h"
+
+#include "gui/message.h"
+#include "gui/newgui.h"
+
+using namespace Sword1;
+
+/* Broken Sword 1 */
+static const GameSettings sword1FullSettings =
+ {"sword1", "Broken Sword 1: The Shadow of the Templars", GF_DEFAULT_TO_1X_SCALER};
+static const GameSettings sword1DemoSettings =
+ {"sword1demo", "Broken Sword 1: The Shadow of the Templars (Demo)", GF_DEFAULT_TO_1X_SCALER | Sword1::GF_DEMO };
+
+// check these subdirectories (if present)
+static const char *g_dirNames[] = { "clusters", "speech" };
+
+#define NUM_FILES_TO_CHECK 5
+static const char *g_filesToCheck[NUM_FILES_TO_CHECK] = { // these files have to be found
+ "swordres.rif",
+ "general.clu",
+ "compacts.clu",
+ "scripts.clu",
+ "cows.mad", // this one should only exist in the demo version
+ // the engine needs several more files to work, but checking these should be sufficient
+};
+
+GameList Engine_SWORD1_gameList() {
+ GameList games;
+ games.push_back(sword1FullSettings);
+ games.push_back(sword1DemoSettings);
+ return games;
+}
+
+void Sword1CheckDirectory(const FSList &fslist, bool *filesFound) {
+ for (FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
+ if (!file->isDirectory()) {
+ const char *fileName = file->displayName().c_str();
+ for (int cnt = 0; cnt < NUM_FILES_TO_CHECK; cnt++)
+ if (scumm_stricmp(fileName, g_filesToCheck[cnt]) == 0)
+ filesFound[cnt] = true;
+ } else {
+ for (int cnt = 0; cnt < ARRAYSIZE(g_dirNames); cnt++)
+ if (scumm_stricmp(file->displayName().c_str(), g_dirNames[cnt]) == 0)
+ Sword1CheckDirectory(file->listDir(AbstractFilesystemNode::kListFilesOnly), filesFound);
+ }
+ }
+}
+
+DetectedGameList Engine_SWORD1_detectGames(const FSList &fslist) {
+ int i;
+ DetectedGameList detectedGames;
+ bool filesFound[NUM_FILES_TO_CHECK];
+ for (i = 0; i < NUM_FILES_TO_CHECK; i++)
+ filesFound[i] = false;
+
+ Sword1CheckDirectory(fslist, filesFound);
+ bool mainFilesFound = true;
+ for (i = 0; i < NUM_FILES_TO_CHECK -1; i++)
+ if (!filesFound[i])
+ mainFilesFound = false;
+
+ if (mainFilesFound && filesFound[NUM_FILES_TO_CHECK - 1])
+ detectedGames.push_back(sword1DemoSettings);
+ else if (mainFilesFound)
+ detectedGames.push_back(sword1FullSettings);
+
+ return detectedGames;
+}
+
+Engine *Engine_SWORD1_create(GameDetector *detector, OSystem *syst) {
+ return new SwordEngine(detector, syst);
+}
+
+REGISTER_PLUGIN(SWORD1, "Broken Sword")
+
+namespace Sword1 {
+
+SystemVars SwordEngine::_systemVars;
+
+void SwordEngine::errorString(const char *buf1, char *buf2) {
+ strcpy(buf2, buf1);
+}
+
+SwordEngine::SwordEngine(GameDetector *detector, OSystem *syst)
+ : Engine(syst) {
+
+ _features = detector->_game.features;
+
+ if (!_mixer->isReady())
+ warning("Sound initialization failed");
+
+ // Add default file directories
+ Common::File::addDefaultDirectory(_gameDataPath + "CLUSTERS/");
+ Common::File::addDefaultDirectory(_gameDataPath + "MUSIC/");
+ Common::File::addDefaultDirectory(_gameDataPath + "SPEECH/");
+ Common::File::addDefaultDirectory(_gameDataPath + "VIDEO/");
+ Common::File::addDefaultDirectory(_gameDataPath + "clusters/");
+ Common::File::addDefaultDirectory(_gameDataPath + "music/");
+ Common::File::addDefaultDirectory(_gameDataPath + "speech/");
+ Common::File::addDefaultDirectory(_gameDataPath + "video/");
+}
+
+SwordEngine::~SwordEngine() {
+ delete _control;
+ delete _logic;
+ delete _menu;
+ delete _sound;
+ delete _music;
+ delete _screen;
+ delete _mouse;
+ delete _objectMan;
+ delete _resMan;
+}
+
+int SwordEngine::init(GameDetector &detector) {
+
+ _system->beginGFXTransaction();
+ initCommonGFX(detector);
+ _system->initSize(640, 480);
+ _system->endGFXTransaction();
+
+ checkCdFiles();
+
+ debug(5, "Starting resource manager");
+ _resMan = new ResMan("swordres.rif");
+ debug(5, "Starting object manager");
+ _objectMan = new ObjectMan(_resMan);
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, Audio::Mixer::kMaxMixerVolume);
+ _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, Audio::Mixer::kMaxMixerVolume);
+ _mouse = new Mouse(_system, _resMan, _objectMan);
+ _screen = new Screen(_system, _resMan, _objectMan);
+ _music = new Music(_mixer);
+ _sound = new Sound("", _mixer, _resMan);
+ _menu = new Menu(_screen, _mouse);
+ _logic = new Logic(_objectMan, _resMan, _screen, _mouse, _sound, _music, _menu, _system, _mixer);
+ _mouse->useLogicAndMenu(_logic, _menu);
+
+ uint musicVol = ConfMan.getInt("music_volume");
+ uint speechVol = ConfMan.getInt("speech_volume");
+ uint sfxVol = ConfMan.getInt("sfx_volume");
+ if (musicVol > 255)
+ musicVol = 255;
+ if (speechVol > 255)
+ speechVol = 255;
+ if (sfxVol > 255)
+ sfxVol = 255;
+
+ _music->setVolume(musicVol, musicVol); // these routines expect left and right volume,
+ _sound->setSpeechVol(speechVol, speechVol); // but our config manager doesn't support it.
+ _sound->setSfxVol(sfxVol, sfxVol);
+
+ _systemVars.justRestoredGame = 0;
+ _systemVars.currentCD = 0;
+ _systemVars.controlPanelMode = CP_NEWGAME;
+ _systemVars.forceRestart = false;
+ _systemVars.wantFade = true;
+ _systemVars.engineQuit = false;
+
+ switch (Common::parseLanguage(ConfMan.get("language"))) {
+ case Common::DE_DEU:
+ _systemVars.language = BS1_GERMAN;
+ break;
+ case Common::FR_FRA:
+ _systemVars.language = BS1_FRENCH;
+ break;
+ case Common::IT_ITA:
+ _systemVars.language = BS1_ITALIAN;
+ break;
+ case Common::ES_ESP:
+ _systemVars.language = BS1_SPANISH;
+ break;
+ case Common::PT_BRA:
+ _systemVars.language = BS1_PORT;
+ break;
+ case Common::CZ_CZE:
+ _systemVars.language = BS1_CZECH;
+ break;
+ default:
+ _systemVars.language = BS1_ENGLISH;
+ }
+
+ _systemVars.showText = ConfMan.getBool("subtitles");
+
+ _systemVars.playSpeech = 1;
+ _mouseState = 0;
+
+ _logic->initialize();
+ _objectMan->initialize();
+ _mouse->initialize();
+ _control = new Control(_saveFileMan, _resMan, _objectMan, _system, _mouse, _sound, _music);
+
+ return 0;
+}
+
+void SwordEngine::reinitialize(void) {
+ _resMan->flush(); // free everything that's currently alloced and opened. (*evil*)
+
+ _logic->initialize(); // now reinitialize these objects as they (may) have locked
+ _objectMan->initialize(); // resources which have just been wiped.
+ _mouse->initialize();
+ _system->warpMouse(320, 240);
+ _systemVars.wantFade = true;
+}
+
+void SwordEngine::flagsToBool(bool *dest, uint8 flags) {
+ uint8 bitPos = 0;
+ while (flags) {
+ if (flags & 1)
+ dest[bitPos] = true;
+ flags >>= 1;
+ bitPos++;
+ }
+}
+
+static const char *errorMsgs[] = {
+ "The file \"%s\" is missing and the game doesn't work without it.\n"
+ "Please copy it from CD %d and try starting the game again.\n"
+ "The Readme file also contains further information.",
+
+ "%d important files are missing, the game can't start without them.\n"
+ "Please copy these files from their corresponding CDs:\n",
+
+ "The file \"%s\" is missing.\n"
+ "Even though the game may initially seem to\n"
+ "work fine, it will crash when it needs the\n"
+ "data from this file and you will be thrown back to your last savegame.\n"
+ "Please copy the file from CD %d and start the game again.",
+
+ "%d files are missing.\n"
+ "Even though the game may initially seem to\n"
+ "work fine, it will crash when it needs the\n"
+ "data from these files and you will be thrown back to your last savegame.\n"
+ "Please copy these files from their corresponding CDs:\n"
+};
+
+const CdFile SwordEngine::_cdFileList[] = {
+ { "paris2.clu", FLAG_CD1 },
+ { "ireland.clu", FLAG_CD2 },
+ { "paris3.clu", FLAG_CD1 },
+ { "paris4.clu", FLAG_CD1 },
+ { "scotland.clu", FLAG_CD2 },
+ { "spain.clu", FLAG_CD2 },
+ { "syria.clu", FLAG_CD2 },
+ { "train.clu", FLAG_CD2 },
+ { "compacts.clu", FLAG_CD1 | FLAG_DEMO | FLAG_IMMED },
+ { "general.clu", FLAG_CD1 | FLAG_DEMO | FLAG_IMMED },
+ { "maps.clu", FLAG_CD1 | FLAG_DEMO },
+ { "paris1.clu", FLAG_CD1 | FLAG_DEMO },
+ { "scripts.clu", FLAG_CD1 | FLAG_DEMO | FLAG_IMMED },
+ { "swordres.rif", FLAG_CD1 | FLAG_DEMO | FLAG_IMMED },
+ { "text.clu", FLAG_CD1 | FLAG_DEMO },
+ { "cows.mad", FLAG_DEMO },
+ { "speech1.clu", FLAG_SPEECH1 },
+ { "speech2.clu", FLAG_SPEECH2 }
+#ifdef USE_MAD
+ ,{ "speech1.cl3", FLAG_SPEECH1 },
+ { "speech2.cl3", FLAG_SPEECH2 }
+#endif
+#ifdef USE_VORBIS
+ ,{ "speech1.clv", FLAG_SPEECH1 },
+ { "speech2.clv", FLAG_SPEECH2 }
+#endif
+};
+
+void SwordEngine::showFileErrorMsg(uint8 type, bool *fileExists) {
+ char msg[1024];
+ int missCnt = 0, missNum = 0;
+ for (int i = 0; i < ARRAYSIZE(_cdFileList); i++)
+ if (!fileExists[i]) {
+ missCnt++;
+ missNum = i;
+ }
+ assert(missCnt > 0); // this function shouldn't get called if there's nothing missing.
+ warning("%d files missing", missCnt);
+ int msgId = (type == TYPE_IMMED) ? 0 : 2;
+ if (missCnt == 1) {
+ sprintf(msg, errorMsgs[msgId],
+ _cdFileList[missNum].name, (_cdFileList[missNum].flags & FLAG_CD2) ? 2 : 1);
+ warning(msg);
+ } else {
+ char *pos = msg + sprintf(msg, errorMsgs[msgId + 1], missCnt);
+ warning(msg);
+ for (int i = 0; i < ARRAYSIZE(_cdFileList); i++)
+ if (!fileExists[i]) {
+ warning("\"%s\" (CD %d)", _cdFileList[i].name, (_cdFileList[i].flags & FLAG_CD2) ? 2 : 1);
+ pos += sprintf(pos, "\"%s\" (CD %d)\n", _cdFileList[i].name, (_cdFileList[i].flags & FLAG_CD2) ? 2 : 1);
+ }
+ }
+ GUI::MessageDialog dialog(msg);
+ dialog.runModal();
+ if (type == TYPE_IMMED) // we can't start without this file, so error() out.
+ error(msg);
+}
+
+void SwordEngine::checkCdFiles(void) { // check if we're running from cd, hdd or what...
+ Common::File test;
+ bool fileExists[30];
+ bool isFullVersion = false; // default to demo version
+ bool missingTypes[8] = { false, false, false, false, false, false, false, false };
+ bool foundTypes[8] = { false, false, false, false, false, false, false, false };
+ bool cd2FilesFound = false;
+ _systemVars.runningFromCd = false;
+ _systemVars.playSpeech = true;
+
+ // check all files and look out if we can find a file that wouldn't exist if this was the demo version
+ for (int fcnt = 0; fcnt < ARRAYSIZE(_cdFileList); fcnt++) {
+ if (test.open(_cdFileList[fcnt].name)) {
+ test.close();
+ fileExists[fcnt] = true;
+ flagsToBool(foundTypes, _cdFileList[fcnt].flags);
+ if (!(_cdFileList[fcnt].flags & FLAG_DEMO))
+ isFullVersion = true;
+ if (_cdFileList[fcnt].flags & FLAG_CD2)
+ cd2FilesFound = true;
+ } else {
+ flagsToBool(missingTypes, _cdFileList[fcnt].flags);
+ fileExists[fcnt] = false;
+ }
+ }
+
+ if (((_features & GF_DEMO) == 0) != isFullVersion) // shouldn't happen...
+ warning("Your Broken Sword 1 version looks like a %s version but you are starting it as a %s version", isFullVersion ? "full" : "demo", (_features & GF_DEMO) ? "demo" : "full");
+
+ if (foundTypes[TYPE_SPEECH1]) // we found some kind of speech1 file (.clu, .cl3, .clv)
+ missingTypes[TYPE_SPEECH1] = false; // so we don't care if there's a different kind missing
+ if (foundTypes[TYPE_SPEECH2]) // same for speech2
+ missingTypes[TYPE_SPEECH2] = false;
+
+ if (isFullVersion) // if this is the full version...
+ missingTypes[TYPE_DEMO] = false; // then we don't need demo files...
+ else // and vice versa
+ missingTypes[TYPE_SPEECH1] = missingTypes[TYPE_SPEECH2] = missingTypes[TYPE_CD1] = missingTypes[TYPE_CD2] = false;
+
+ bool somethingMissing = false;
+ for (int i = 0; i < 8; i++)
+ somethingMissing |= missingTypes[i];
+ if (somethingMissing) { // okay, there *are* files missing
+ // first, update the fileExists[] array depending on our changed missingTypes
+ for (int fileCnt = 0; fileCnt < ARRAYSIZE(_cdFileList); fileCnt++)
+ if (!fileExists[fileCnt]) {
+ fileExists[fileCnt] = true;
+ for (int flagCnt = 0; flagCnt < 8; flagCnt++)
+ if (missingTypes[flagCnt] && ((_cdFileList[fileCnt].flags & (1 << flagCnt)) != 0))
+ fileExists[fileCnt] = false; // this is one of the files we were looking for
+ }
+ if (missingTypes[TYPE_IMMED]) {
+ // important files missing, can't start the game without them
+ showFileErrorMsg(TYPE_IMMED, fileExists);
+ } else if ((!missingTypes[TYPE_CD1]) && !cd2FilesFound) {
+ /* we have all the data from cd one, but not a single one from CD2.
+ I'm not sure how we should handle this, for now I'll just assume that the
+ user has set up the extrapath correctly and copied the necessary files to HDD.
+ A quite optimistic assumption, I'd say. Maybe we should change this for the release
+ to warn the user? */
+ warning("CD2 data files not found. I hope you know what you're doing and that\n"
+ "you have set up the extrapath and additional data correctly.\n"
+ "If you didn't, you should better read the ScummVM readme file");
+ _systemVars.runningFromCd = true;
+ _systemVars.playSpeech = true;
+ } else if (missingTypes[TYPE_CD1] || missingTypes[TYPE_CD2]) {
+ // several files from CD1 both CDs are missing. we can probably start, but it'll crash sooner or later
+ showFileErrorMsg(TYPE_CD1, fileExists);
+ } else if (missingTypes[TYPE_SPEECH1] || missingTypes[TYPE_SPEECH2]) {
+ // not so important, but there won't be any voices
+ if (missingTypes[TYPE_SPEECH1] && missingTypes[TYPE_SPEECH2])
+ warning("Unable to find the speech files. The game will work, but you won't hear any voice output.\n"
+ "Please copy the SPEECH.CLU files from both CDs and rename them to SPEECH1.CLU and SPEECH2.CLU,\n"
+ "corresponding to the CD number.\n"
+ "Please read the ScummVM Readme file for more information");
+ else
+ warning("Unable to find the speech file from CD %d.\n"
+ "You won't hear any voice output in that part of the game.\n"
+ "Please read the ScummVM Readme file for more information", missingTypes[TYPE_SPEECH1] ? 1 : 2);
+ } else if (missingTypes[TYPE_DEMO]) {
+ // for the demo version, we simply expect to have all files immediately
+ showFileErrorMsg(TYPE_IMMED, fileExists);
+ }
+ } // everything's fine, let's play.
+ /*if (!isFullVersion)
+ _systemVars.isDemo = true;
+ */
+ // make the demo flag depend on the Gamesettings for now, and not on what the datafiles look like
+ _systemVars.isDemo = (_features & GF_DEMO) != 0;
+ _systemVars.cutscenePackVersion = 0;
+#ifdef USE_MPEG2
+ if (test.open("intro.snd")) {
+ _systemVars.cutscenePackVersion = 1;
+ test.close();
+ }
+#endif
+}
+
+int SwordEngine::go() {
+
+ uint16 startPos = ConfMan.getInt("boot_param");
+ if (startPos)
+ _logic->startPositions(startPos);
+ else {
+ if (_control->savegamesExist()) {
+ _systemVars.controlPanelMode = CP_NEWGAME;
+ if (_control->runPanel() == CONTROL_GAME_RESTORED)
+ _control->doRestore();
+ else if (!_systemVars.engineQuit)
+ _logic->startPositions(0);
+ } else // no savegames, start new game.
+ _logic->startPositions(0);
+ }
+ _systemVars.controlPanelMode = CP_NORMAL;
+
+ while (!_systemVars.engineQuit) {
+ uint8 action = mainLoop();
+
+ if (!_systemVars.engineQuit) {
+ // the mainloop was left, we have to reinitialize.
+ reinitialize();
+ if (action == CONTROL_GAME_RESTORED)
+ _control->doRestore();
+ else if (action == CONTROL_RESTART_GAME)
+ _logic->startPositions(1);
+ _systemVars.forceRestart = false;
+ _systemVars.controlPanelMode = CP_NORMAL;
+ }
+ }
+
+ return 0;
+}
+
+void SwordEngine::checkCd(void) {
+ uint8 needCd = _cdList[Logic::_scriptVars[NEW_SCREEN]];
+ if (_systemVars.runningFromCd) { // are we running from cd?
+ if (needCd == 0) { // needCd == 0 means we can use either CD1 or CD2.
+ if (_systemVars.currentCD == 0) {
+ _systemVars.currentCD = 1; // if there is no CD currently inserted, ask for CD1.
+ _control->askForCd();
+ } // else: there is already a cd inserted and we don't care if it's cd1 or cd2.
+ } else if (needCd != _systemVars.currentCD) { // we need a different CD than the one in drive.
+ _music->startMusic(0, 0); //
+ _sound->closeCowSystem(); // close music and sound files before changing CDs
+ _systemVars.currentCD = needCd; // askForCd will ask the player to insert _systemVars.currentCd,
+ _control->askForCd(); // so it has to be updated before calling it.
+ }
+ } else { // we're running from HDD, we don't have to care about music files and Sound will take care of
+ if (needCd) // switching sound.clu files on Sound::newScreen by itself, so there's nothing to be done.
+ _systemVars.currentCD = needCd;
+ else if (_systemVars.currentCD == 0)
+ _systemVars.currentCD = 1;
+ }
+}
+
+uint8 SwordEngine::mainLoop(void) {
+ uint8 retCode = 0;
+ _keyPressed = 0;
+
+ while ((retCode == 0) && (!_systemVars.engineQuit)) {
+ // do we need the section45-hack from sword.c here?
+ checkCd();
+
+ _screen->newScreen(Logic::_scriptVars[NEW_SCREEN]);
+ _logic->newScreen(Logic::_scriptVars[NEW_SCREEN]);
+ _sound->newScreen(Logic::_scriptVars[NEW_SCREEN]);
+ Logic::_scriptVars[SCREEN] = Logic::_scriptVars[NEW_SCREEN];
+
+ do {
+ uint32 newTime;
+ bool scrollFrameShown = false;
+
+ uint32 frameTime = _system->getMillis();
+ _logic->engine();
+ _logic->updateScreenParams(); // sets scrolling
+
+ _screen->draw();
+ _mouse->animate();
+ _sound->engine();
+ _menu->refresh(MENU_TOP);
+ _menu->refresh(MENU_BOT);
+
+ newTime = _system->getMillis();
+ if (newTime - frameTime < 1000 / FRAME_RATE) {
+ scrollFrameShown = _screen->showScrollFrame();
+ delay((1000 / (FRAME_RATE * 2)) - (_system->getMillis() - frameTime));
+ }
+
+ newTime = _system->getMillis();
+ if ((newTime - frameTime < 1000 / FRAME_RATE) || (!scrollFrameShown))
+ _screen->updateScreen();
+ delay((1000 / FRAME_RATE) - (_system->getMillis() - frameTime));
+
+ _mouse->engine( _mouseX, _mouseY, _mouseState);
+
+ if (_systemVars.forceRestart)
+ retCode = CONTROL_RESTART_GAME;
+
+ // The control panel is triggered by F5 or ESC.
+ // FIXME: This is a very strange way of detecting F5...
+ else if (((_keyPressed == 63 || _keyPressed == 27) && (Logic::_scriptVars[MOUSE_STATUS] & 1)) || (_systemVars.controlPanelMode)) {
+ retCode = _control->runPanel();
+ if (!retCode)
+ _screen->fullRefresh();
+ }
+ _mouseState = _keyPressed = 0;
+ } while ((Logic::_scriptVars[SCREEN] == Logic::_scriptVars[NEW_SCREEN]) && (retCode == 0) && (!_systemVars.engineQuit));
+
+ if ((retCode == 0) && (Logic::_scriptVars[SCREEN] != 53) && _systemVars.wantFade && (!_systemVars.engineQuit)) {
+ _screen->fadeDownPalette();
+ int32 relDelay = (int32)_system->getMillis();
+ while (_screen->stillFading()) {
+ relDelay += (1000 / FRAME_RATE);
+ _screen->updateScreen();
+ delay(relDelay - (int32)_system->getMillis());
+ }
+ }
+
+ _sound->quitScreen();
+ _screen->quitScreen(); // close graphic resources
+ _objectMan->closeSection(Logic::_scriptVars[SCREEN]); // close the section that PLAYER has just left, if it's empty now
+ }
+ return retCode;
+}
+
+void SwordEngine::delay(int32 amount) { //copied and mutilated from sky.cpp
+
+ OSystem::Event event;
+ uint32 start = _system->getMillis();
+
+ 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 = (uint8)event.kbd.ascii;
+ break;
+ case OSystem::EVENT_MOUSEMOVE:
+ _mouseX = event.mouse.x;
+ _mouseY = event.mouse.y;
+ break;
+ case OSystem::EVENT_LBUTTONDOWN:
+ _mouseState |= BS1L_BUTTON_DOWN;
+#if defined(_WIN32_WCE) || defined(PALMOS_MODE)
+ _mouseX = event.mouse.x;
+ _mouseY = event.mouse.y;
+#endif
+ break;
+ case OSystem::EVENT_RBUTTONDOWN:
+ _mouseState |= BS1R_BUTTON_DOWN;
+#if defined(_WIN32_WCE) || defined(PALMOS_MODE)
+ _mouseX = event.mouse.x;
+ _mouseY = event.mouse.y;
+#endif
+ break;
+ case OSystem::EVENT_LBUTTONUP:
+ _mouseState |= BS1L_BUTTON_UP;
+ break;
+ case OSystem::EVENT_RBUTTONUP:
+ _mouseState |= BS1R_BUTTON_UP;
+ break;
+ case OSystem::EVENT_QUIT:
+ _systemVars.engineQuit = true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (amount > 0)
+ _system->delayMillis(10);
+
+ } while (_system->getMillis() < start + amount);
+}
+
+} // End of namespace Sword1
diff --git a/engines/sword1/sword1.h b/engines/sword1/sword1.h
new file mode 100644
index 0000000000..a41685ad75
--- /dev/null
+++ b/engines/sword1/sword1.h
@@ -0,0 +1,110 @@
+/* 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 BSSWORD1_H
+#define BSSWORD1_H
+
+#include "base/engine.h"
+#include "common/util.h"
+#include "base/gameDetector.h"
+#include "sword1/sworddefs.h"
+
+namespace Sword1 {
+
+enum {
+ GF_DEMO = 1 << 0
+};
+
+enum ControlPanelMode {
+ CP_NORMAL = 0,
+ CP_DEATHSCREEN,
+ CP_THEEND,
+ CP_NEWGAME
+};
+
+class Screen;
+class Sound;
+class Logic;
+class Mouse;
+class ResMan;
+class ObjectMan;
+class Menu;
+class Music;
+class Control;
+
+struct SystemVars {
+ bool runningFromCd;
+ uint32 currentCD; // starts at zero, then either 1 or 2 depending on section being played
+ uint32 justRestoredGame; // see main() in sword.c & New_screen() in gtm_core.c
+ bool engineQuit;
+
+ uint8 controlPanelMode; // 1 death screen version of the control panel, 2 = successful end of game, 3 = force restart
+ bool forceRestart;
+ bool wantFade; // when true => fade during scene change, else cut.
+ uint8 playSpeech;
+ uint8 showText;
+ uint8 language;
+ bool isDemo;
+
+ uint8 cutscenePackVersion;
+};
+
+class SwordEngine : public Engine {
+ void errorString(const char *buf_input, char *buf_output);
+public:
+ SwordEngine(GameDetector *detector, OSystem *syst);
+ virtual ~SwordEngine();
+ static SystemVars _systemVars;
+ void reinitialize(void);
+
+ uint32 _features;
+protected:
+ int go();
+ int init(GameDetector &detector);
+private:
+ void delay(int32 amount);
+
+ void checkCdFiles(void);
+ void checkCd(void);
+ void showFileErrorMsg(uint8 type, bool *fileExists);
+ void flagsToBool(bool *dest, uint8 flags);
+ uint8 mainLoop(void);
+
+ uint16 _mouseX, _mouseY, _mouseState;
+ uint8 _keyPressed;
+
+ ResMan *_resMan;
+ ObjectMan *_objectMan;
+ Screen *_screen;
+ Mouse *_mouse;
+ Logic *_logic;
+ Sound *_sound;
+ Menu *_menu;
+ Music *_music;
+ Control *_control;
+ static const uint8 _cdList[TOTAL_SECTIONS];
+ static const CdFile _cdFileList[];
+};
+
+} // End of namespace Sword1
+
+#endif //BSSWORD1_H
diff --git a/engines/sword1/sworddefs.h b/engines/sword1/sworddefs.h
new file mode 100644
index 0000000000..4b057245c5
--- /dev/null
+++ b/engines/sword1/sworddefs.h
@@ -0,0 +1,1606 @@
+/* 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 SWORDDEFS_H
+#define SWORDDEFS_H
+
+#include "common/scummsys.h"
+
+namespace Sword1 {
+
+#define LOOPED 1
+
+#define FRAME_RATE 12 // number of frames per second (max rate)
+#define SCREEN_WIDTH 640
+#define SCREEN_DEPTH 400
+#define SCREEN_LEFT_EDGE 128
+#define SCREEN_RIGHT_EDGE (128+SCREEN_WIDTH-1)
+#define SCREEN_TOP_EDGE 128
+#define SCREEN_BOTTOM_EDGE (128+SCREEN_DEPTH-1)
+#define TYPE_FLOOR 1
+#define TYPE_MOUSE 2
+#define TYPE_SPRITE 3
+#define TYPE_NON_MEGA 4
+#define TYPE_MEGA 5
+#define TYPE_PLAYER 6
+#define TYPE_TEXT 7
+#define STAT_MOUSE 1
+#define STAT_LOGIC 2
+#define STAT_EVENTS 4
+#define STAT_FORE 8
+#define STAT_BACK 16
+#define STAT_SORT 32
+#define STAT_SHRINK 64
+#define STAT_BOOKMARK 128
+#define STAT_TALK_WAIT 256
+#define STAT_OVERRIDE 512
+
+#define LOGIC_idle 0
+#define LOGIC_script 1
+#define LOGIC_AR_animate 2
+#define LOGIC_interaction 3
+#define LOGIC_speech 4
+#define LOGIC_full_anim 5
+#define LOGIC_anim 6
+#define LOGIC_pause 7
+#define LOGIC_wait_for_sync 8
+#define LOGIC_quit 9
+#define LOGIC_restart 10
+#define LOGIC_bookmark 11
+#define LOGIC_wait_for_talk 12
+#define LOGIC_start_talk 13
+#define LOGIC_choose 14
+#define LOGIC_new_script 15
+#define LOGIC_pause_for_event 16
+
+#define SCRIPT_CONT 1
+#define SCRIPT_STOP 0
+
+#define INS_talk 1
+
+#define TOTAL_pockets 52
+#define TOTAL_subjects (375-256+1)
+#define BASE_SUBJECT 256
+
+#define TOTAL_SECTIONS 150 //number of sections, rooms + mega sections
+#define TOTAL_ROOMS 100 //total number of rooms
+#define ITM_PER_SEC 0x10000 //65536 items per section -> was originally called "SIZE"
+#define ITM_ID 0xFFFF //& with this -> originally "NuSIZE"
+
+#define MAX_text_obs 2 //text compacts
+#define TEXT_sect 149 //text compacts exist in section 149, probably after all the megas
+
+#if !defined(__GNUC__)
+ #pragma START_PACK_STRUCTS
+#endif
+
+struct Header {
+ char type[6];
+ uint16 version;
+ uint32 comp_length;
+ char compression[4];
+ uint32 decomp_length;
+} GCC_PACK;
+
+struct FrameHeader {
+ uint8 runTimeComp[4];
+ uint32 compSize;
+ uint16 width;
+ uint16 height;
+ int16 offsetX;
+ int16 offsetY;
+} GCC_PACK;
+
+struct ParallaxHeader {
+ char type[16];
+ uint16 sizeX;
+ uint16 sizeY;
+} GCC_PACK;
+
+struct AnimUnit {
+ uint32 animX;
+ uint32 animY;
+ uint32 animFrame;
+} GCC_PACK;
+
+struct AnimSet {
+ uint32 cdt;
+ uint32 spr;
+} GCC_PACK;
+
+struct WalkGridHeader {
+ int32 scaleA;
+ int32 scaleB;
+ int32 numBars;
+ int32 numNodes;
+} GCC_PACK;
+
+#if !defined(__GNUC__)
+ #pragma END_PACK_STRUCTS
+#endif
+
+enum fileTypes {
+ TYPE_CD1 = 0,
+ TYPE_CD2,
+ TYPE_DEMO,
+ TYPE_IMMED,
+ TYPE_SPEECH1,
+ TYPE_SPEECH2
+};
+
+enum fileFlags {
+ FLAG_CD1 = (1 << TYPE_CD1), // this file is on cd1
+ FLAG_CD2 = (1 << TYPE_CD2), // this file is on cd2
+ FLAG_DEMO = (1 << TYPE_DEMO), // file for the demo version
+ FLAG_IMMED = (1 << TYPE_IMMED), // this file is needed immediately, game won't start without it
+ FLAG_SPEECH1 = (1 << TYPE_SPEECH1),
+ FLAG_SPEECH2 = (1 << TYPE_SPEECH2)
+};
+
+struct CdFile {
+ const char *name;
+ uint8 flags;
+};
+
+enum Language {
+ BS1_ENGLISH = 0,
+ BS1_FRENCH,
+ BS1_GERMAN,
+ BS1_ITALIAN,
+ BS1_SPANISH,
+ BS1_CZECH,
+ BS1_PORT
+};
+
+#define SAM 2162689
+#define PLAYER 8388608
+#define GEORGE 8388608
+#define NICO 8454144
+#define BENOIR 8585216
+#define ROSSO 8716288
+#define DUANE 8781824
+#define MOUE 9502720
+#define ALBERT 9568256
+
+#define STAND 0
+#define UP 0
+#define UP_RIGHT 1
+#define U_R 1
+#define RIGHT 2
+#define DOWN_RIGHT 3
+#define D_R 3
+#define DOWN 4
+#define DOWN_LEFT 5
+#define D_L 5
+#define LEFT 6
+#define UP_LEFT 7
+#define U_L 7
+
+#define BEER_TOWEL 3
+#define HOTEL_KEY 4
+#define BALL 5
+#define RED_NOSE 7
+#define POLISHED_CHALICE 8
+#define PHOTOGRAPH 10
+#define GEM 13
+#define LAB_PASS 17
+#define LIFTING_KEYS 18
+#define MANUSCRIPT 19
+#define PLASTER 23
+#define ROSSO_CARD 27
+#define TISSUE 32
+#define LENS 37
+#define TRIPOD 36
+#define CHALICE 31
+#define MATCHBOOK 20
+#define PRESSURE_GAUGE 24
+#define BUZZER 26
+#define TOILET_KEY 28
+#define STONE_KEY 30
+#define TOILET_BRUSH 33
+#define MIRROR 38
+#define TOWEL_CUT 39
+
+#define SC58_PATH_X 225
+#define SC58_PATH_Y 369
+
+#define FLOOR_1 65536
+#define FLOOR_2 131072
+#define FLOOR_3 196608
+#define FLOOR_4 262144
+#define FLOOR_5 327680
+#define FLOOR_6 393216
+#define FLOOR_7 458752
+#define FLOOR_8 524288
+#define FLOOR_9 589824
+#define FLOOR_10 655360
+#define FLOOR_11 720896
+#define FLOOR_12 786432
+#define FLOOR_13 851968
+#define FLOOR_14 917504
+#define FLOOR_15 983040
+#define FLOOR_16 1048576
+#define FLOOR_17 1114112
+#define FLOOR_18 1179648
+#define FLOOR_19 1245184
+#define FLOOR_20 1310720
+#define FLOOR_21 1376256
+#define FLOOR_22 1441792
+#define FLOOR_23 1507328
+#define FLOOR_24 1572864
+#define FLOOR_25 1638400
+#define FLOOR_26 1703936
+#define FLOOR_27 1769472
+#define FLOOR_28 1835008
+#define FLOOR_29 1900544
+#define FLOOR_31 2031616
+#define FLOOR_32 2097152
+#define FLOOR_33 2162688
+#define FLOOR_34 2228224
+#define FLOOR_35 2293760
+#define FLOOR_36 2359296
+#define FLOOR_37 2424832
+#define FLOOR_38 2490368
+#define FLOOR_39 2555904
+#define FLOOR_40 2621440
+#define FLOOR_41 2686976
+#define FLOOR_42 2752512
+#define FLOOR_43 2818048
+#define FLOOR_45 2949120
+#define FLOOR_46 3014656
+#define FLOOR_47 3080192
+#define FLOOR_48 3145728
+#define FLOOR_49 3211264
+#define FLOOR_50 3276800
+#define FLOOR_53 3473408
+#define FLOOR_54 3538944
+#define FLOOR_55 3604480
+#define FLOOR_56 3670016
+#define FLOOR_57 3735552
+#define FLOOR_58 3801088
+#define FLOOR_59 3866624
+#define FLOOR_60 3932160
+#define LEFT_FLOOR_61 3997697
+#define FLOOR_62 4063232
+#define FLOOR_63 4128768
+#define FLOOR_65 4259840
+#define FLOOR_66 4325376
+#define FLOOR_67 4390912
+#define FLOOR_69 4521984
+#define RIGHT_FLOOR_71 4653060
+#define FLOOR_72 4718592
+#define FLOOR_73 4784128
+#define FLOOR_74 4849664
+#define FLOOR_75 4915200
+#define FLOOR_76 4980736
+#define FLOOR_77 5046272
+#define FLOOR_78 5111808
+#define FLOOR_79 5177344
+#define FLOOR_80 5242880
+#define FLOOR_86 5636096
+#define FLOOR_91 5963776
+#define FLOOR_99 6488064
+
+
+#define menu_bible 69
+#define menu_newspaper 1
+#define menu_hazel_wand 2
+#define menu_beer_towel 68
+#define menu_beer_towel_wet 4
+#define menu_beer_towel_damp 5
+#define menu_beer_towel_dried 6
+#define menu_hotel_key 7
+#define menu_ball 8
+#define menu_statuette 9
+#define menu_red_nose_first 10
+#define menu_red_nose_second 11
+#define menu_polished_chalice 12
+#define menu_dollar_bill 13
+#define menu_photograph 14
+#define menu_keyring_first 15
+#define menu_keyring_second 70
+#define menu_keyring_third 17
+#define menu_fuse_wire 18
+#define menu_gem 19
+#define menu_statuette_paint 20
+#define menu_stick 21
+#define menu_excav_key 71
+#define menu_false_key 72
+#define menu_painted_key 73
+#define menu_lab_pass 25
+#define menu_lifting_keys 26
+#define menu_manuscript 27
+#define menu_match_book 28
+#define menu_suit_material 29
+#define menu_stick_towel 30
+#define menu_plaster 31
+#define menu_pressure_gauge 32
+#define menu_railway_ticket 33
+#define menu_buzzer 74
+#define menu_rosso_card 75
+#define menu_toilet_key 36
+#define menu_soap 76
+#define menu_soap_imp 77
+#define menu_soap_plas 78
+#define menu_stone_key 79
+#define menu_chalice 41
+#define menu_tissue 42
+#define menu_toilet_brush 80
+#define menu_toilet_chain 44
+#define menu_towel 45
+#define menu_tripod 46
+#define menu_lens 81
+#define menu_towel_cut 48
+#define menu_mirror 82
+#define menu_tissue_charred 50
+#define menu_cog_1 51
+#define menu_cog_2 52
+#define menu_handle 83
+#define menu_coin 84
+#define menu_biro 55
+#define menu_pipe 56
+#define menu_flashlight 57
+
+#define IT_MCODE 1 // Call an mcode routine
+#define IT_PUSHNUMBER 2 // push a number on the stack
+#define IT_PUSHVARIABLE 3 // push a variable on the stack
+
+#define IT_FIRSTOPERATOR 4 // Operators come after this and must stay in the same order for precedence table
+
+#define IT_NOTEQUAL 4
+#define IT_ISEQUAL 5
+#define IT_PLUS 6
+#define IT_TIMES 7
+#define IT_ANDAND 8
+#define IT_OROR 9
+#define IT_LESSTHAN 10
+#define IT_NOT 11
+#define IT_MINUS 12
+#define IT_AND 13
+#define IT_OR 14
+#define IT_GTE 15 // >=
+#define IT_LTE 16 // <=
+#define IT_DEVIDE 17 // <=
+#define IT_GT 18 // >
+
+#define IT_SCRIPTEND 20
+#define IT_POPVAR 21
+#define IT_POPLONGOFFSET 22
+#define IT_PUSHLONGOFFSET 23
+#define IT_SKIPONFALSE 24
+#define IT_SKIP 25
+#define IT_SWITCH 26
+#define IT_SKIPONTRUE 27
+#define IT_PRINTF 28
+#define IT_RESTARTSCRIPT 30
+#define IT_POPWORDOFFSET 31
+#define IT_PUSHWORDOFFSET 32
+
+enum ScriptVariableNames {
+ RETURN_VALUE = 0,
+ RETURN_VALUE_2,
+ RETURN_VALUE_3,
+ RETURN_VALUE_4,
+ DEFAULT_ICON_TEXT,
+ MENU_LOOKING,
+ TOP_MENU_DISABLED,
+ GEORGE_DOING_REST_ANIM,
+ GEORGE_WALKING,
+ ADVISOR_188_FLAG,
+ MEGA_ON_GRID,
+ REROUTE_GEORGE,
+ WALK_FLAG,
+ WALK_ATTEMPT,
+ TARGET_X,
+ TARGET_Y,
+ DISTANCE_APART,
+ ID_LOW_FLOOR,
+ NEW_SCREEN,
+ CUR_ID,
+ MOUSE_STATUS,
+ PALETTE,
+ NEW_PALETTE,
+ MOUSE_X,
+ MOUSE_Y,
+ SPECIAL_ITEM,
+ CLICK_ID,
+ MOUSE_BUTTON,
+ BUTTON,
+ BOTH_BUTTONS, // not used anymore
+ SAFE_X,
+ SAFE_Y,
+ CHANGE_X,
+ CHANGE_Y,
+ CHANGE_PLACE,
+ CHANGE_DIR,
+ CHANGE_STANCE,
+ SCROLL_FLAG,
+ SCROLL_OFFSET_X,
+ SCROLL_OFFSET_Y,
+ MAX_SCROLL_OFFSET_X,
+ MAX_SCROLL_OFFSET_Y,
+ FEET_X,
+ FEET_Y,
+ SECOND_ITEM, //SECOND_ICON,
+ SUBJECT_CHOSEN,
+ IN_SUBJECT,
+ DEBUG_FLAG_1,
+ DEBUG_FLAG_2,
+ DEBUG_FLAG_3,
+ FIRST_WATCH,
+ GEORGE_ALLOWED_REST_ANIMS,
+ CURRENT_MUSIC,
+ TESTLINENO,
+ LASTLINENO,
+ WANTPREVIOUSLINE,
+ PLAYINGDEMO,
+ TEMP_FLAG,
+ PHOTOS_FLAG,
+ PHONE_FLOOR_FLAG,
+ PHONE_ROOM_FLAG,
+ BENOIR_FLAG,
+ GUARD_FLAG,
+ MOUE_DOOR_FLAG,
+ CANOPY_FLAG,
+ GOT_NEWSPAPER_FLAG,
+ DEMO_NICO_FLAG,
+ NICO_TARGET,
+ NICO_DIR,
+ BEEN_TO_ALLEY,
+ DUSTBIN_FLAG,
+ DUSTBIN_2_FLAG,
+ TRIED_MANHOLE_FLAG,
+ MANHOLE_FLAG,
+ DRAINPIPE_FLAG,
+ OPENED_MANHOLE_2_BEFORE,
+ SEARCHED_PLANTARD_FLAG,
+ ENTERED_CAFE_ONCE,
+ BOTTLE_3_FLAG,
+ TOOLBOX_4_FLAG,
+ CALL_ALB_FLAG,
+ CALL_ALBERT_FLAG,
+ GOT_NOSE_FLAG,
+ GOT_MATERIAL_FLAG,
+ GOT_TISSUE_FLAG,
+ RAILING_7_FLAG,
+ SEEN_FLOWERS_FLAG,
+ SEEN_DRESS_SHOP_FLAG,
+ DOOR_9_FLAG,
+ PHONE_10_FLAG,
+ MANUSCRIPT_ON_TABLE_10_FLAG,
+ DOG_TURD_FLAG,
+ PIERMONT_AT_PIANO_FLAG,
+ GOT_KEY_FLAG,
+ USED_HOTEL_KEY_ONCE,
+ WINDOW_15_OPEN,
+ CLIMBED_OUT_15_FLAG,
+ WINDOW_16_FLAG,
+ HOTEL_ASSASSIN_BEEN,
+ WARDROBE_17_OPEN,
+ SEARCHED_TROUSERS_17,
+ ENTERED_17_FLAG,
+ WINDOW_27_FLAG,
+ CASE_1_LOCKED_FLAG,
+ CASE_2_LOCKED_FLAG,
+ CASE_3_LOCKED_FLAG,
+ CASE_4_LOCKED_FLAG,
+ SEEN_ARMOUR_28_FLAG,
+ CLOSED_WINDOW_28_FLAG,
+ WINDOW_28_FLAG,
+ WINDOW_DRAUGHT_FLAG,
+ SEEN_WINDOW_28_FLAG,
+ FACING_WINDOW_FLAG,
+ CLOSING_WINDOW_FLAG,
+ SARCOPHAGUS_FLAG,
+ ENTERED_MUSEUM_28_FLAG,
+ SARCOPHAGUS_DOOR_29_OPEN,
+ AMBULANCE_31_FLAG,
+ CONSULTANT_HERE,
+ SEEN_MR_SHINY_FLAG,
+ SEEN_CUPBOARD_FLAG,
+ PLUG_33_UNPLUGGED,
+ SAM_RETURNING,
+ PULLED_PLUG_33,
+ PULSE_34_FLAG,
+ DOOR_34_OPEN,
+ MARQUET_AWAKE_FLAG,
+ JUGGLER_FLAG,
+ JUGGLE_FLAG,
+ CROWD_FLAG,
+ MANHOLE_36_FLAG,
+ DOOR_37_FLAG,
+ IN_BOAT_FLAG,
+ GOT_HOOK_FLAG,
+ HOOK_FLAG,
+ STEPS_38_FLAG,
+ TRIPOD_PUZZLE_FLAG,
+ SOAP_43_FLAG,
+ SEEN_WASHBASIN_43,
+ HOSPITAL_FLAG,
+ SEEN_PARIS_MAP,
+ PHONE_SCREEN_FLAG,
+ PHONE_PLACE_FLAG,
+ SEAN_DEAD,
+ SPAIN_VISIT,
+ WET_BEER_TOWEL_TIMER,
+ BEER_TOWEL_BEEN_WET,
+ NICO_SCOT_SCREEN,
+ NICO_AT_PANEL_72,
+ NICO_POSITION_71,
+ SEEN_DRAIN_19,
+ SEEN_MENU_19,
+ PUB_TRAP_DOOR,
+ ASSASSIN_EIRE_DONE,
+ BAR_TOWEL_TAKEN,
+ GLASS_WASH_FLAG,
+ PUB_DOOR_FLAG,
+ PUB_FLAP_FLAG,
+ DOYLE_DRINKING,
+ RON_SNEEZING,
+ FUSE_WIRE_TAKEN,
+ FUSE_WIRE_ON_TABLE,
+ GLASS_20_FLAG,
+ MAGUIRE_PUB_DONE,
+ PINT_LEVEL_FLAG,
+ GEM_21_TAKEN,
+ MAGUIRE_CEL_DONE,
+ TORCH_21_TAKEN,
+ BEEN_UP_HAYBAILS,
+ LIFTING_KEYS_IN_HOLE_23,
+ SEEN_STEPS_SEQUENCE,
+ SEEN_GOAT_24,
+ FLEECY_TANGLED,
+ FLEECY_STUCK,
+ FLEECY_BACKING_OFF,
+ SEEN_LADDER_SEQUENCE,
+ BUTT_COUNT_24,
+ KEYSTONE_FLAG,
+ PANEL_25_MOVED,
+ SACK_25_FLAG,
+ SAND_FLAG,
+ SEEN_HOLES_25,
+ REPLICA_IN_CAVITY,
+ SEEN_RAT_26,
+ ENTERED_CELLAR_BEFORE,
+ CAT_ON_SHELF,
+ CAT_RAN_OFF,
+ CAT_TIMER,
+ STATUETTE_FLAG,
+ SEEN_TOP_SHELF_45,
+ DUANE_TARGET,
+ AYUB_OPENING_DOOR,
+ GEORGE_TALKING_TO_PEARL,
+ CARPET_DOOR_47_OPEN,
+ TOILET_KEYS_ON_BAR,
+ EXPLAINED_RETURNING_KEYS,
+ DOOR_49_OPEN,
+ TOILET_CHAIN_50_TAKEN,
+ TOWEL_DISPENSER_50_OPEN,
+ TOWEL_50_TAKEN,
+ CUBICLE_DOOR_50_OPEN,
+ DOOR_50_OPEN,
+ MAX_ITERATION,
+ ITERATION,
+ STICK_54_FLAG,
+ TOWEL_IN_CRACK_54,
+ CAVE_54_OPEN,
+ GUN_54_FLAG,
+ KHAN_54_HERE,
+ DOOR_55_OPEN,
+ READ_INSCRIPTION_55,
+ SEEN_STATUE_55,
+ VISITED_COUNTESS_56_AGAIN,
+ CHALICE_56_GIVEN,
+ CHESS_PIECE_56_GIVEN,
+ GARDENER_57_HERE,
+ PRESSURE_GAUGE_57_FLAG,
+ FOUND_WELL_57,
+ DOOR_58_OPEN,
+ COUNTESS_58_HERE,
+ GARDENER_58_HERE,
+ COUNTESS_59_HERE,
+ BIBLE_59_FLAG,
+ WINDOW_59_SHUT,
+ CHALICE_59_TAKEN,
+ SECRET_DOOR_59_OPEN,
+ HOLDING_SNUFFER,
+ TISSUE_ON_SNUFFER,
+ TISSUE_59_CHARRED,
+ TISSUE_59_BURNING,
+ CANDLE_59_BURNT,
+ LECTERN_CANDLES_59_LIT,
+ TISSUE_FLAME_59_ON,
+ GARDENER_60_POSITION,
+ GARDENER_60_CHECKING_DOGS,
+ DOGS_DISTURBED,
+ MIRROR_60_TAKEN,
+ SEEN_LEFT_ROCKFALL_61,
+ LION_HEAD_FALLING,
+ LION_FANG_FLAG,
+ DOOR_61_FLAG,
+ GEORGE_HOLDING_PIECE,
+ CHESS_SQUARE_1_FLAG,
+ CHESS_SQUARE_2_FLAG,
+ CHESS_SQUARE_3_FLAG,
+ CHESS_SQUARE_4_FLAG,
+ CHESS_SQUARE_5_FLAG,
+ DOOR_ONE_63_OPEN,
+ DOOR_TWO_63_OPEN,
+ DOOR_THREE_63_OPEN,
+ GEORGE_ON_ROOF,
+ SEEN_EKLUND_63,
+ DOOR_65_OPEN,
+ DOOR_67_OPEN,
+ WINDOW_66_OPEN,
+ SEQUENCE_69_FLAG,
+ SC69_TIMER,
+ LEFT_TREE_POINTER_71_FLAG,
+ RIGHT_TREE_POINTER_71_FLAG,
+ RUBBLE_72_FLAG,
+ MACHINERY_HANDLE_FLAG,
+ MACHINERY_COG_FLAG,
+ DEMON_RB_FLAG,
+ DEMON_LB_FLAG,
+ DEMON_COGS_FLAG,
+ DEMON_PIPE_FLAG,
+ DEMON_NOSE_FLAG,
+ DEMON_LEFT_COG_FLAG,
+ DEMON_RIGHT_COG_FLAG,
+ PANEL_72_FLAG,
+ SEEN_CRYPT_73,
+ SEEN_GUNPOWDER_73,
+ GUIDO_73_HERE,
+ NICO_POSITION_73,
+ ALBERT_ANNOYED_FLAG,
+ ALBERT_BRIEFCASE_FLAG,
+ ALBERT_BUZZER_FLAG,
+ ALBERT_CDT_FLAG,
+ ALBERT_CHANTELLE_FLAG,
+ ALBERT_CHAT_FLAG,
+ ALBERT_CLOWN_FLAG,
+ ALBERT_JACKET_FLAG,
+ ALBERT_KEYS_FLAG,
+ ALBERT_NOSE_FLAG,
+ ALBERT_PLANTARD_FLAG,
+ ALBERT_POLICE_FLAG,
+ ALBERT_POS_FLAG,
+ ALBERT_TALK_FLAG,
+ ALBERT_TISSUE_FLAG,
+ ALBERT_TEXT,
+ ALBERT_INFO_FLAG,
+ ARTO_BULL_FLAG,
+ ARTO_BRUSH_FLAG,
+ ARTO_IRRITATION_FLAG,
+ ARTO_KLAUSNER_FLAG,
+ ARTO_LOOM_FLAG,
+ ARTO_OBJECT_FLAG,
+ ARTO_PHRASE_FLAG,
+ ARTO_TEXT,
+ ASSASSIN_BOOK_FLAG,
+ ASSASSIN_BULL_FLAG,
+ ASSASSIN_CHURCH_FLAG,
+ ASSASSIN_EIRE_TEXT,
+ ASSASSIN_SWORD_FLAG,
+ ASSASSIN_TEMPLAR_FLAG,
+ ASSASSIN_TEXT,
+ AYUB_BULL_FLAG,
+ AYUB_KLAUSNER_FLAG,
+ AYUB_LOOM_FLAG,
+ AYUB_ULTAR_FLAG,
+ AYUB_TEXT,
+ BASHER_BEER_FLAG,
+ BASHER_COMPLAIN_FLAG,
+ BASHER_EKLUND_FLAG,
+ BASHER_HELP_FLAG,
+ BASHER_NICO_FLAG,
+ BASHER_STOP_FLAG,
+ BASHER_WEASEL_FLAG,
+ BASHER_WINDOW_FLAG,
+ BASHER_TEXT,
+ BENOIR_BUZZER_FLAG,
+ BENOIR_GAUGE_FLAG,
+ BENOIR_MARQUET_FLAG,
+ BENOIR_NURSE_FLAG,
+ BENOIR_RENEE_FLAG,
+ BENOIR_TEXT,
+ CARPET_TEXT,
+ CARPET_OBJECT_FLAG,
+ CHANTELLE_BRIEFCASE_FLAG,
+ CHANTELLE_CLOWN_FLAG,
+ CHANTELLE_DOCTOR_FLAG,
+ CHANTELLE_EYE_FLAG,
+ CHANTELLE_FAINT_FLAG,
+ CHANTELLE_NEWSPAPER_FLAG,
+ CHANTELLE_PLANTARD_FLAG,
+ CHANTELLE_TEXT,
+ CHANTELLE_WAKE_COUNTER,
+ CLERK_ASSASSIN_FLAG,
+ CLERK_BUZZER_FLAG,
+ CLERK_CLOWN_FLAG,
+ CLERK_ENOUGH_FLAG,
+ CLERK_HKEY_FLAG,
+ CLERK_KEY_FLAG,
+ CLERK_KEY_STOP_FLAG,
+ CLERK_NOSE_FLAG,
+ CLERK_PASS_FLAG,
+ CLERK_PHOTO_FLAG,
+ CLERK_PIERMONT_FLAG,
+ CLERK_PLANTARD_FLAG,
+ CLERK_POLITE_FLAG,
+ CLERK_SAFE_FLAG,
+ CLERK_TEMPLAR_FLAG,
+ CLERK_TEXT,
+ CLERK_TISSUE_FLAG,
+ CLERK_WEASEL_FLAG,
+ CONSULT_CHALICE_FLAG,
+ CONSULT_GAUGE_FLAG,
+ CONSULT_GEM_FLAG,
+ CONSULT_LIFTKEY_FLAG,
+ CONSULT_MARQUET_FLAG,
+ CONSULT_NOSE_FLAG,
+ CONSULT_PHOTO_FLAG,
+ CONSULT_TEXT,
+ CONSULT_TISSUE_FLAG,
+ COSTUMIER_BALL_FLAG,
+ COSTUMIER_BUZZER_FLAG,
+ COSTUMIER_CLOWN_FLAG,
+ COSTUMIER_PHOTO_FLAG,
+ COSTUMIER_PLANTARD_FLAG,
+ COSTUMIER_TISSUE_FLAG,
+ COSTUMIER_TEXT,
+ DOYLE_BEER_FLAG,
+ DOYLE_BUZZER_FLAG,
+ DOYLE_CASTLE_FLAG,
+ DOYLE_DIG_FLAG,
+ DOYLE_FLASHLIGHT_FLAG,
+ DOYLE_GEM_FLAG,
+ DOYLE_JEWEL_FLAG,
+ DOYLE_JOB_FLAG,
+ DOYLE_KEYS_FLAG,
+ DOYLE_LEPRECHAUN_FLAG,
+ DOYLE_NOSE_FLAG,
+ DOYLE_PEAGRAM_FLAG,
+ DOYLE_PHOTOGRAPH_FLAG,
+ DOYLE_SEAN_FLAG,
+ DOYLE_TEMPLAR_FLAG,
+ DOYLE_TEXT,
+ DOYLE_TISSUE_FLAG,
+ DOYLE_TOWEL_FLAG,
+ DUANE_ARTO_FLAG,
+ DUANE_BULL_FLAG,
+ DUANE_CLEVE_FLAG,
+ DUANE_DUANE_FLAG,
+ DUANE_PEARL_FLAG,
+ DUANE_PHOTO_FLAG,
+ DUANE_KEYS_FLAG,
+ DUANE_MANUSCRIPT_FLAG,
+ DUANE_NEJO_FLAG,
+ DUANE_PHRASE_FLAG,
+ DUANE_QUEEN_FLAG,
+ DUANE_STATUETTE_FLAG,
+ DUANE_TEMPLAR_FLAG,
+ DUANE_TEXT,
+ DUANE_ULTAR_FLAG,
+ ERIC_MARQUET_FLAG,
+ ERIC_NURSE_FLAG,
+ ERIC_PHOTO_FLAG,
+ EVA_CLOWN_FLAG,
+ EVA_LENS_FLAG,
+ EVA_MARQUET_FLAG,
+ EVA_MOB_FLAG,
+ EVA_NURSE_FLAG,
+ EVA_TEXT,
+ FARMER_BEER_FLAG,
+ FARMER_BOOK_FLAG,
+ FARMER_BUZZER_FLAG,
+ FARMER_CAR_FLAG,
+ FARMER_CASTLE_FLAG,
+ FARMER_FLASHLIGHT_FLAG,
+ FARMER_GEM_FLAG,
+ FARMER_GHOST_FLAG,
+ FARMER_LAST_STRAW,
+ FARMER_LIFTKEYS_FLAG,
+ FARMER_MOVED_FLAG,
+ FARMER_NOSE_FLAG,
+ FARMER_PASS_FLAG,
+ FARMER_PEAGRAM_FLAG,
+ FARMER_PHOTO_FLAG,
+ FARMER_SEAN_FLAG,
+ FARMER_TEMPLAR_FLAG,
+ FARMER_TEXT,
+ FARMER_TISSUE_FLAG,
+ FARMER_WIRE_FLAG,
+ FLEECY_TEXT,
+ FLOWER_FLOWER_FLAG,
+ FLOWER_FORTUNE_FLAG,
+ FLOWER_GAUGE_FLAG,
+ FLOWER_GEM_FLAG,
+ FLOWER_LIFTKEYS_FLAG,
+ FLOWER_NICO_FLAG,
+ FLOWER_PASS_FLAG,
+ FLOWER_PHOTO_FLAG,
+ FLOWER_TEXT,
+ GARD_ATTEMPT,
+ GARD_BY_WELL,
+ GARDENER_COUNTESS_FLAG,
+ GARDENER_CHALICE_FLAG,
+ GARDENER_FLOPPO_FLAG,
+ GARDENER_GOODBYE_FLAG,
+ GARDENER_HOSE_FLAG,
+ GARDENER_IRRITATION,
+ GARDENER_SPEECH_FLAG,
+ GARDENER_TEMPLAR_FLAG,
+ GARDENER_TEXT,
+ GATEKEEPER_TALK_FLAG,
+ GATEKEEPER_CDT_FLAG,
+ GMASTER_TALK_FLAG,
+ GMASTER_CDT_FLAG,
+ GENDARME_CARD_FLAG,
+ GENDARME_CLOWN_FLAG,
+ GENDARME_MOUE_FLAG,
+ GENDARME_NOSE_FLAG,
+ GEND_PAPER_FLAG,
+ GENDARME_PHOTO_FLAG,
+ GENDARME_ROSSO_FLAG,
+ GENDARME_TEXT,
+ GENDARME_TISSUE_FLAG,
+ GENDARME_WEASEL_FLAG,
+ GOINFRE_ALARM_FLAG,
+ GOINFRE_EXHIBIT_FLAG,
+ GOINFRE_GEM_FLAG,
+ GOINFRE_KEYS_FLAG,
+ GOINFRE_LOBINEAU_FLAG,
+ GOINFRE_MS_FLAG,
+ GOINFRE_SARCOPHAGUS_FLAG,
+ GOINFRE_SCOLD_FLAG,
+ GOINFRE_TEMPLAR_FLAG,
+ GOINFRE_TEXT,
+ GOINFRE_TISSUE_FLAG,
+ GOINFRE_TRIPOD_FLAG,
+ GOINFRE_WINDOW_FLAG,
+ GORILLA_CLOWN_FLAG,
+ GORILLA_KHAN_FLAG,
+ GORILLA_PASS_FLAG,
+ GORILLA_PLANTARD_FLAG,
+ GORILLA_SEARCH_FLAG,
+ GORILLA_TEXT,
+ GORILLA_TISSUE_FLAG,
+ GORILLA_WEASEL_FLAG,
+ HOSCOP_ALERT_FLAG,
+ HOSCOP_MARQUET_FLAG,
+ HOSCOP_MOB_FLAG,
+ HOSCOP_TEXT,
+ JUGGLER_JUGGLER_FLAG,
+ JUGGLER_TEMPLAR_FLAG,
+ JUGGLER_GEM_FLAG,
+ JUGGLER_TEXT,
+ KHAN_SUBJECT_FLAG,
+ KHAN_PREAMBLE_FLAG,
+ LATVIAN_CLOWN_FLAG,
+ LATVIAN_EYE_FLAG,
+ LATVIAN_LIFTKEYS_FLAG,
+ LATVIAN_MATCHBOOK_FLAG,
+ LATVIAN_MS_FLAG,
+ LATVIAN_NOSE_FLAG,
+ LATVIAN_PHOTO_FLAG,
+ LATVIAN_PLANTARD_FLAG,
+ LATVIAN_TEXT,
+ LEARY_BEER_FLAG,
+ LEARY_BUZZER_FLAG,
+ LEARY_CASTLE_FLAG,
+ LEARY_CLOWN_FLAG,
+ LEARY_FISH_FLAG,
+ LEARY_FLAP_FLAG,
+ LEARY_FLAPALERT_FLAG,
+ LEARY_KEYS_FLAG,
+ LEARY_NOSE_FLAG,
+ LEARY_PASS_FLAG,
+ LEARY_PEAGRAM_FLAG,
+ LEARY_PHONE_FLAG,
+ LEARY_PHOTO_FLAG,
+ LEARY_PLASTER_FLAG,
+ LEARY_PLUG_FLAG,
+ LEARY_SEAN_FLAG,
+ LEARY_SNARE_FLAG,
+ LEARY_TEMPLAR_FLAG,
+ LEARY_TEXT,
+ LEARY_TISSUE_FLAG,
+ LEARY_TOWEL_FLAG,
+ LEARY_WASHER_FLAG,
+ LEARY_WILD_FLAG,
+ LEARY_WIRE_FLAG,
+ LOBINEAU_ARTEFACT_FLAG,
+ LOBINEAU_BALL_FLAG,
+ LOBINEAU_BEL_FLAG,
+ LOBINEAU_GEM_FLAG,
+ LOBINEAU_HASH_FLAG,
+ LOBINEAU_KEYS_FLAG,
+ LOBINEAU_MANUSCRIPT_FLAG,
+ LOBINEAU_MATCHBOOK_FLAG,
+ LOBINEAU_MONTFAUCON_FLAG,
+ LOBINEAU_NICO_FLAG,
+ LOBINEAU_PANTS_FLAG,
+ LOBINEAU_PEAGRAM_FLAG,
+ LOBINEAU_STATUE_FLAG,
+ LOBINEAU_SYRIA_FLAG,
+ LOBINEAU_TEMPLAR_FLAG,
+ LOBINEAU_TEXT,
+ LOBINEAU_TRIPOD_FLAG,
+ MAGUIRE_CAR_FLAG,
+ MAGUIRE_CASTLE_FLAG,
+ MAGUIRE_CDT_FLAG,
+ MAGUIRE_CLOWN_FLAG,
+ MAGUIRE_COP_FLAG,
+ MAGUIRE_DIG_FLAG,
+ MAGUIRE_GEM_FLAG,
+ MAGUIRE_GHOST_FLAG,
+ MAGUIRE_JEWEL_FLAG,
+ MAGUIRE_KEYS_FLAG,
+ MAGUIRE_LEPRECHAUN_FLAG,
+ MAGUIRE_NOSE_FLAG,
+ MAGUIRE_PEAGRAM_FLAG,
+ MAGUIRE_SEAN_FLAG,
+ MAGUIRE_SHOCK_FLAG,
+ MAGUIRE_TALK_FLAG,
+ MAGUIRE_TEXT,
+ MAGUIRE_WIRE_FLAG,
+ MANAGER_TEXT,
+ MANAGER_BRUSH_FLAG,
+ MANAGER_SPEECH_FLAG,
+ MOUE_BALL_FLAG,
+ MOUE_BRIEFCASE_FLAG,
+ MOUE_CARD_FLAG,
+ MOUE_CDT_FLAG,
+ MOUE_CLOWN_FLAG,
+ MOUE_EYE_FLAG,
+ MOUE_FETCH_FLAG,
+ MOUE_HASH_FLAG,
+ MOUE_KEY_FLAG,
+ MOUE_MARQUET_FLAG,
+ MOUE_MATCHBOOK_FLAG,
+ MOUE_MATERIAL_FLAG,
+ MOUE_MOB_FLAG,
+ MOUE_NEWSPAPER_FLAG,
+ MOUE_NICO_FLAG,
+ MOUE_NOSE_FLAG,
+ MOUE_PHOTO_FLAG,
+ MOUE_PLANTARD_FLAG,
+ MOUE_ROSSO_FLAG,
+ MOUE_STOP_FLAG,
+ MOUE_TALK_FLAG,
+ MOUE_TEXT,
+ MOUE_TISSUE_FLAG,
+ NEJO_ARTO_FLAG,
+ NEJO_AYUB_FLAG,
+ NEJO_BALL_FLAG,
+ NEJO_BALL_TALK,
+ NEJO_BULL_FLAG,
+ NEJO_CAT_FLAG,
+ NEJO_CHALICE_FLAG,
+ NEJO_DOLLAR_FLAG,
+ NEJO_GOODBYE_FLAG,
+ NEJO_HENDERSONS_FLAG,
+ NEJO_LOOM_FLAG,
+ NEJO_NEJO_FLAG,
+ NEJO_PHRASE_FLAG,
+ NEJO_PLASTER_FLAG,
+ NEJO_PRESSURE_GAUGE_FLAG,
+ NEJO_STALL_FLAG,
+ NEJO_STATUE_FLAG,
+ NEJO_TEMPLAR_FLAG,
+ NEJO_TEXT,
+ NEJO_ULTAR_FLAG,
+ NICO_ALBERT_FLAG,
+ NICO_ASSASSIN_FLAG,
+ NICO_BALL_FLAG,
+ NICO_BRIEFCASE_FLAG,
+ NICO_BULL_FLAG,
+ NICO_BUZZER_FLAG,
+ NICO_CHALICE_FLAG,
+ NICO_CDT_FLAG,
+ NICO_CLOWN_FLAG,
+ NICO_EKLUND_FLAG,
+ NICO_GAUGE_FLAG,
+ NICO_GEM_FLAG,
+ NICO_GOODBYE_FLAG,
+ NICO_GUIDO_FLAG,
+ NICO_HASH_FLAG,
+ NICO_IRELAND_FLAG,
+ NICO_KNIGHT_FLAG,
+ NICO_LIFTKEYS_FLAG,
+ NICO_LENS_FLAG,
+ NICO_LOBINEAU_FLAG,
+ NICO_MANUSCRIPT_FLAG,
+ NICO_MARQUET_FLAG,
+ NICO_MATCHBOOK_FLAG,
+ NICO_MATERIAL_FLAG,
+ NICO_NEWSPAPER_FLAG,
+ NICO_NICO_FLAG,
+ NICO_NOSE_FLAG,
+ NICO_PASS_FLAG,
+ NICO_PEAGRAM_FLAG,
+ NICO_PLANTARD_FLAG,
+ NICO_PLASTER_FLAG,
+ NICO_PHOTO_FLAG,
+ NICO_PHONE_TEXT,
+ NICO_POS_FLAG,
+ NICO_QUEEN_FLAG,
+ NICO_RINGING_BACK_FLAG,
+ NICO_ROSSO_FLAG,
+ NICO_SEWER_FLAG,
+ NICO_SPAIN_FLAG,
+ NICO_SYRIA_FLAG,
+ NICO_TALK_FLAG,
+ NICO_TEMPLAR_FLAG,
+ NICO_TEXT,
+ NICO_TISSUE_FLAG,
+ NICO_TRAIN_FLAG,
+ NICO_TRIPOD_FLAG,
+ NICO_WEAVER_FLAG,
+ NIC_BAG_TALK_FLAG,
+ NIC_BAG_CDT_FLAG,
+ NICO_LEAVING_CAFE_SCREEN,
+ NURSE_BENOIR_FLAG,
+ NURSE_CLOWN_FLAG,
+ NURSE_GAUGE_FLAG,
+ NURSE_MARQUET_FLAG,
+ NURSE_INTERRUPTION_FLAG,
+ NURSE_TEXT,
+ OBRIEN_BUZZER_FLAG,
+ OBRIEN_CASTLE_FLAG,
+ OBRIEN_FLASHLIGHT_FLAG,
+ OBRIEN_GEM_FLAG,
+ OBRIEN_JEWEL_FLAG,
+ OBRIEN_JOB_FLAG,
+ OBRIEN_KEYS_FLAG,
+ OBRIEN_LEARY_FLAG,
+ OBRIEN_MAGUIRE_FLAG,
+ OBRIEN_NOSE_FLAG,
+ OBRIEN_PEAGRAM_FLAG,
+ OBRIEN_SEAN_FLAG,
+ OBRIEN_TEMPLAR_FLAG,
+ OBRIEN_TEXT,
+ OBRIEN_TISSUE_FLAG,
+ OBRIEN_TOWEL_FLAG,
+ OLD_NOSE_FLAG,
+ OLD_PHOTO_FLAG,
+ OLD_LIFT_FLAG,
+ OLD_BUZZER_FLAG,
+ PAINTER_DIG_FLAG,
+ PAINTER_DISTRACTION_FLAG,
+ PAINTER_PAINTER_FLAG,
+ PAINTER_TEMPLAR_FLAG,
+ PAINTER_CONTROL_FLAG,
+ PAINTER_TEXT,
+ PEARL_AKRON_FLAG,
+ PEARL_ARTO_FLAG,
+ PEARL_BULL_FLAG,
+ PEARL_DUANE_FLAG,
+ PEARL_NEJO_FLAG,
+ PEARL_PEARL_FLAG,
+ PEARL_PHRASE_FLAG,
+ PEARL_POEMS_FLAG,
+ PEARL_STATUE_FLAG,
+ PEARL_TEMPLAR_FLAG,
+ PEARL_TEXT,
+ PEARL_ULTAR_FLAG,
+ PEARL_TALK_FLAG,
+ PEARL_CDT_FLAG,
+ PEARL_STALL_FLAG,
+ PEARL_WEAVER_FLAG,
+ PIERMONT_ASSASSIN_FLAG,
+ PIERMONT_BUZZER_FLAG,
+ PIERMONT_CLOWN_FLAG,
+ PIERMONT_GEM_FLAG,
+ PIERMONT_HKEY_FLAG,
+ PIERMONT_KEY_FLAG,
+ PIERMONT_KEY_ALERT_FLAG,
+ PIERMONT_MS_FLAG,
+ PIERMONT_NOSE_FLAG,
+ PIERMONT_PASS_FLAG,
+ PIERMONT_PHOTO_FLAG,
+ PIERMONT_PIERMONT_FLAG,
+ PIERMONT_TEMPLAR_FLAG,
+ PIERMONT_TEXT,
+ PIERMONT_TISSUE_FLAG,
+ PIERMONT_WEASEL_FLAG,
+ PRIEST_TEXT,
+ PRIEST_CHALICE_FLAG,
+ PRIEST_CHALICE2_FLAG,
+ PRIEST_TEMPLAR_FLAG,
+ PRIEST_PRIEST_FLAG,
+ PRIEST_WINDO1_FLAG,
+ PRIEST_WINDO2_FLAG,
+ PRIEST_WINDO3_FLAG,
+ RENEE_MARQUET_FLAG,
+ RENEE_PHOTO_FLAG,
+ RENEE_RENEE_FLAG,
+ RENEE_TEXT,
+ RON_ALERT_FLAG,
+ RON_BEER_FLAG,
+ RON_CASTLE_FLAG,
+ RON_DIG_FLAG,
+ RON_FLASHLIGHT_FLAG,
+ RON_GHOST_FLAG,
+ RON_NOSE_FLAG,
+ RON_PASS_FLAG,
+ RON_PEAGRAM_FLAG,
+ RON_PHOTO_FLAG,
+ RON_POLICE_FLAG,
+ RON_SEAN_FLAG,
+ RON_SNARE_FLAG,
+ RON_STOP_FLAG,
+ RON_TEXT,
+ RON_UPSET_FLAG,
+ ROSSO_CDT_FLAG,
+ ROSSO_CLOWN_FLAG,
+ ROSSO_DOCTOR_FLAG,
+ ROSSO_FORTUNE_FLAG,
+ ROSSO_GEM_FLAG,
+ ROSSO_MARQUET_FLAG,
+ ROSSO_MATCHBOOK_FLAG,
+ ROSSO_MOUE_FLAG,
+ ROSSO_OPINION_FLAG,
+ ROSSO_PASS_FLAG,
+ ROSSO_PEAGRAM_FLAG,
+ ROSSO_PHOTO_FLAG,
+ ROSSO_PLANTARD_FLAG,
+ ROSSO_ROSSO_FLAG,
+ ROSSO_TALK_FLAG,
+ ROSSO_TEMPLAR_FLAG,
+ ROSSO_TEXT,
+ ROSSO_THUGS_FLAG,
+ ROZZER_36_FLAG,
+ ROZZER_JUGGLER_FLAG,
+ ROZZER_MANHOLE_FLAG,
+ ROZZER_PLASTER_FLAG,
+ ROZZER_ROZZER_FLAG,
+ ROZZER_TEMPLAR_FLAG,
+ ROZZER_TEXT,
+ SAM_BREAKDOWN_FLAG,
+ SAM_BUZZER_FLAG,
+ SAM_CUPBOARD_FLAG,
+ SAM_GEM_FLAG,
+ SAM_MARQUET_FLAG,
+ SAM_MATCHBOOK_FLAG,
+ SAM_MOB_FLAG,
+ SAM_NOSE_FLAG,
+ SAM_NURSE_FLAG,
+ SAM_PHOTO_FLAG,
+ SAM_PLASTER_FLAG,
+ SAM_SHINY_FLAG,
+ SAM_SOCKET_FLAG,
+ SAM_STOP_FLAG,
+ SAM_TEXT,
+ SEAN_ASSASSIN_FLAG,
+ SEAN_BEER_FLAG,
+ SEAN_CASTLE_FLAG,
+ SEAN_DIG_FLAG,
+ SEAN_GEM_FLAG,
+ SEAN_LKEYS_FLAG,
+ SEAN_NOSE_FLAG,
+ SEAN_OPINION,
+ SEAN_PACKAGE_FLAG,
+ SEAN_PEAGRAM_FLAG,
+ SEAN_SELF_FLAG,
+ SEAN_SNAP_FLAG,
+ SEAN_TEXT,
+ STATUE_GUARD_CONTROL_FLAG,
+ STATUE_GUARD_FLAG,
+ STATUE_GUARD_GUARD_FLAG,
+ STATUE_GUARD_KEY,
+ GUARD_GLOVE_FLAG,
+ STATUE_GUARD_TEMPLAR_FLAG,
+ STATUE_GUARD_THERMO_FLAG,
+ STATUE_GUARD_TEXT,
+ STATUE_GUARD_TALK_FLAG,
+ STATUE_GUARD_CDT_FLAG,
+ TCLERK_PIERMONT_FLAG,
+ TNIC_ENQUIRY_FLAG,
+ TODRYK_CLOWN_FLAG,
+ TODRYK_EYE_FLAG,
+ TODRYK_GEORGE_FLAG,
+ TODRYK_OPINION_FLAG,
+ TODRYK_PHOTO_FLAG,
+ TODRYK_PLANTARD_FLAG,
+ TODRYK_ROSSO_FLAG,
+ TODRYK_TEXT,
+ ULTAR_ARTO_FLAG,
+ ULTAR_BALL_FLAG,
+ ULTAR_BULL_FLAG,
+ ULTAR_BUZZER_FLAG,
+ ULTAR_CHALICE_FLAG,
+ ULTAR_CLUB_FLAG,
+ ULTAR_DOLLARS_FLAG,
+ ULTAR_GOODBYE_FLAG,
+ ULTAR_HENDERSONS_FLAG,
+ ULTAR_KLAUSNER_FLAG,
+ ULTAR_LAB_PASS_FLAG,
+ ULTAR_LIFTING_KEYS_FLAG,
+ ULTAR_LOOM_FLAG,
+ ULTAR_NEJO_FLAG,
+ ULTAR_PHOTOGRAPH_FLAG,
+ ULTAR_PHRASE_FLAG,
+ ULTAR_PRESSURE_GAUGE_FLAG,
+ ULTAR_RED_NOSE_FLAG,
+ ULTAR_SIGN_FLAG,
+ ULTAR_STATUETTE_FLAG,
+ ULTAR_STATUETTE_PAINT_FLAG,
+ ULTAR_TISSUE_FLAG,
+ ULTAR_TEMPLAR_FLAG,
+ ULTAR_TAXI_FLAG,
+ ULTAR_TOILET_BRUSH_FLAG,
+ ULTAR_TOILET_CHAIN_FLAG,
+ ULTAR_TOILET_KEY_FLAG,
+ ULTAR_TOWEL_FLAG,
+ ULTAR_PLASTER_FLAG,
+ ULTAR_TEXT,
+ COUNTESS_56A_SUBJECT_FLAG,
+ COUNTESS_56A_GOODBYE_FLAG,
+ COUNTESS_56B_GOODBYE_FLAG,
+ COUNTESS_TALK_FLAG,
+ COUNTESS_CDT_FLAG,
+ VAS_BALL_FLAG,
+ VAS_COUNTESS_FLAG,
+ VAS_GOODBYE_FLAG,
+ VAS_KEY_FLAG,
+ VAS_PHOTO_FLAG,
+ VAS_TALK,
+ VAS_TEXT,
+ VAS_TEXT_TOGGLE,
+ VAS_TEMPLAR_FLAG,
+ VAS_CURSE_FLAG,
+ VAS_PCHALICE_FLAG,
+ GEORGE59A,
+ VAIL_TEXT,
+ VAIL_TALK_FLAG,
+ VAIL_CDT_FLAG,
+ WEASEL_CLOWN_FLAG,
+ WEASEL_KHAN_FLAG,
+ WEASEL_GUIDO_FLAG,
+ WEASEL_PLANTARD_FLAG,
+ WEASEL_ROSSO_FLAG,
+ WEASEL_STOP_FLAG,
+ WEASEL_TEXT,
+ WORKMAN_CLOWN_FLAG,
+ WORKMAN_COP_FLAG,
+ WORKMAN_PHONE_ALERT_FLAG,
+ WORKMAN_PLANTARD_FLAG,
+ WORKMAN_ROSSO_CARD,
+ WORKMAN_STOP_FLAG,
+ WORKMAN_TOOL_FLAG,
+ WORKMAN_TOOLBOX_FLAG,
+ WORKMAN_TEXT,
+ GEORGE_TALK_FLAG,
+ GEORGE_CDT_FLAG,
+ CHOOSER_COUNT_FLAG,
+ HURRY_FLAG,
+ IRELAND_FLAG,
+ IRELAND_MAP_FLAG,
+ KNOWS_PEAGRAM_FLAG,
+ KNOWS_PHILIP_FLAG,
+ MANUSCRIPT_FLAG,
+ OBJECT_HELD,
+ OBJECT_ICON,
+ OBJECT_TALK,
+ PARIS_FLAG,
+ RESPONSERECEIVED,
+ SCENE_FLAG,
+ SCREEN,
+ SCORE_FLAG,
+ SCOTLAND_MAP_FLAG,
+ SPAIN_MAP_FLAG,
+ SYRIA_FLAG,
+ TALK_FLAG,
+ WEIRD_ZONE,
+ TARGET_MEGA,
+ CHURCH_ARRIVAL_FLAG,
+ SHH_ALERT_FLAG,
+ AEROPORT_ADDRESS_FLAG,
+ CHANTELLE_BRANDY_FLAG,
+ CHURCH_FLAG,
+ CHOOSE_GAUGE_FLAG,
+ CLERK_AT_DESK_FLAG,
+ CONSULTANT_STOP_FLAG,
+ COSTUMES_ADDRESS_FLAG,
+ COSTUMES_PHONE_FLAG,
+ FOUND_WARD_FLAG,
+ GEORGE_POS_FLAG,
+ GOT_BENOIR_FLAG,
+ HOLE_FLAG,
+ HOSPITAL_ADDRESS_FLAG,
+ HOSPITAL_VISIT_FLAG,
+ HOS_POS_FLAG,
+ HOTEL_ADDRESS_FLAG,
+ IRELAND_ALERT_FLAG,
+ KEY_ALERT_FLAG,
+ KEYRING_FLAG,
+ KEY_TALK,
+ KNOWS_MOERLIN_FLAG,
+ LENS_FLAG,
+ MACDEVITTS_PHONE_FLAG,
+ MANUSCRIPT_ALERT_FLAG,
+ MANUSCRIPT_VIEW_FLAG,
+ MEETING_FLAG,
+ MESSAGE_FLAG,
+ MONTFACN_ADDRESS_FLAG,
+ MONTFAUCON_CONTROL_FLAG,
+ MUSEUM_ADDRESS_FLAG,
+ MUSEUM_CLOSING_FLAG,
+ MUSEUM_PHONE_FLAG,
+ NERVAL_ADDRESS_FLAG,
+ NICO_ADDRESS_FLAG,
+ NICO_APT_FLAG,
+ NICO_DOOR_FLAG,
+ NICO_GONE_HOME_FLAG,
+ NICO_PHONE_FLAG,
+ NICO_VISIT_FLAG,
+ NURSE_TELEPHONE_FLAG,
+ PAINT_TALK,
+ PAINTPOT_FLAG,
+ PARIS_STATUE_FLAG,
+ PHONE_CHECK,
+ PHONE_REQUEST,
+ POLICE_ADDRESS_FLAG,
+ POLICE_PHONE_FLAG,
+ POLISHER_PLUG_FLAG,
+ POS_FLAG,
+ RADIO_ALERT_FLAG,
+ READ_NEWSPAPER,
+ READ_NOSE_FLAG,
+ SARCOPHAGUS_ALERT_FLAG,
+ SC28_COIN_FLAG,
+ SC28_POTTERY_FLAG,
+ SC48_SCROLL_FLAG,
+ SEEN_BRIEFCASE_FLAG,
+ SEEN_DOOR22_FLAG,
+ SEEN_KEY_FLAG,
+ SEEN_MANHOLE_FLAG,
+ SEEN_PLANTARD_FLAG,
+ SEEN_REGISTER_FLAG,
+ SEEN_SEWERS_FLAG,
+ SEEN_TRIPOD_FLAG,
+ SEWER_EXIT_FLAG,
+ SKIP_TALK,
+ SOAP_FLAG,
+ ERIC_TEXT,
+ TAILOR_PHONE_FLAG,
+ THERMO_FLAG,
+ TOILET_TALK,
+ TOMB_FLAG,
+ TORCH_ALERT_FLAG,
+ TOTEM_ALERT_FLAG,
+ TRIPOD_FLAG,
+ TRIPOD_ALERT_FLAG,
+ TRIPOD_STOLEN_FLAG,
+ WARD_STOP_FLAG,
+ WHITE_COAT_FLAG,
+ WINDOW_ALERT_FLAG,
+ WORKMAN_GONE_FLAG,
+ CLIMBING_CART_FLAG,
+ FIDDLER_TEXT,
+ PEAGRAM_GONE_FLAG,
+ PINT_FLAG,
+ PUB_ELEC_FLAG,
+ PUB_INTERRUPTION_FLAG,
+ PUB_TAP_FLAG,
+ SEEN_GOAT_FLAG,
+ SYRIA_BOOK_FLAG,
+ SEEN_BRUSH_FLAG,
+ SEEN_STATUE_FLAG,
+ SYRIA_DEAD_FLAG,
+ SYRIA_NICHE_FLAG,
+ ARMOUR_HIDE_FLAG,
+ CANDLE59_FLAG,
+ CANDLE_BURNT,
+ CHALICE_FLAG,
+ CHESSET_FLAG,
+ CHESSBOARD_FLAG,
+ DOOR_REVEALED,
+ DOWSE_FLAG,
+ GEORGE_POSITION,
+ GEORGE_SAFE,
+ GEORGE_WELL_FLAG,
+ HAZEL_FLAG,
+ INTRO_FLAG,
+ LION_FANG,
+ LOGS_56_FLAG,
+ MARY_FLAG,
+ MIRROR_HINT,
+ ROCKFALL_1,
+ ROCKFALL_2,
+ SECOND_CURSE_FLAG,
+ SPAIN_CODA,
+ TOMBS59_FLAG,
+ ASSASSIN_KILLED_FLAG,
+ AXE_ALERT_FLAG,
+ DOOR_SC69_ALERT_FLAG,
+ DOOR_SC65_FLAG,
+ EKLUND_KILLED,
+ FINALE_OPTION_FLAG,
+ NICO_GONE_FLAG,
+ NICO_TIED_FLAG,
+ PIPE_ALERT_FLAG,
+ SEEN_GUIDO_63,
+ END_SCENE,
+ MASTER_39_TALK_FLAG,
+ MASTER_39_CDT_FLAG,
+ COLONEL_TALK_FLAG,
+ COLONEL_CDT_FLAG,
+ EXEC_TALK_FLAG,
+ EXEC_CDT_FLAG,
+ CIVIL_TALK_FLAG,
+ CIVIL_CDT_FLAG,
+ LATVIAN_39_TALK_FLAG,
+ LATVIAN_39_CDT_FLAG,
+ EKLUND_39_TALK_FLAG,
+ EKLUND_39_CDT_FLAG,
+ CAFE_BOMBED,
+ BLIND_ALLEY,
+ CAFE_INTERIOR,
+ ROAD_WORKS,
+ COURT_YARD,
+ SEWER_ONE,
+ SEWER_TWO,
+ CAFE_REPAIRED,
+ APT_STREET,
+ APT_NICO,
+ COSTUME_SHOP,
+ HOTEL_STREET,
+ HOTEL_DESK,
+ HOTEL_CORRIDOR,
+ HOTEL_EMPTY,
+ HOTEL_LEDGE,
+ HOTEL_ASSASSIN,
+ GENDARMERIE,
+ IRELAND_STREET,
+ MACDEVITTS,
+ PUB_CELLAR,
+ CASTLE_GATE,
+ CASTLE_HAY_TOP,
+ CASTLE_YARD,
+ CASTLE_DIG,
+ CELLAR_DARK,
+ MUSEUM_STREET,
+ MUSEUM_ONE,
+ MUSEUM_TWO,
+ MUSEUM_HIDING,
+ HOSPITAL_STREET,
+ HOSPITAL_DESK,
+ HOSPITAL_CORRIDOR,
+ HOSPITAL_WARD,
+ HOSPITAL_JACQUES,
+ MONTFAUCON,
+ CATACOMB_SEWER,
+ CATACOMB_ROOM,
+ CATACOMB_MEETING,
+ EXCAVATION_EXT,
+ EXCAVATION_LOBBY,
+ EXCAVATION_DIG,
+ EXCAVATION_TOILET,
+ EXCAVATION_SECRET,
+ TEMPLAR_CHURCH,
+ SYRIA_STALL,
+ SYRIA_CARPET,
+ SYRIA_CLUB,
+ SYRIA_TOILET,
+ BULL_CLIFF,
+ BULL_INTERIOR,
+ MAUSOLEUM_EXT,
+ SPAIN_DRIVE,
+ SPAIN_GARDEN,
+ MAUSOLEUM_INT,
+ SPAIN_RECEPTION,
+ SPAIN_WELL,
+ SPAIN_SECRET,
+ TRAIN_ONE,
+ TRAIN_TWO,
+ COMPT_ONE,
+ COMPT_TWO,
+ COMPT_THREE,
+ COMPT_FOUR,
+ TRAIN_GUARD,
+ CHURCHYARD,
+ CHURCH_TOWER,
+ CRYPT,
+ SECRET_CRYPT,
+ POCKET_1,
+ POCKET_2,
+ POCKET_3,
+ POCKET_4,
+ POCKET_5,
+ POCKET_6,
+ POCKET_7,
+ POCKET_8,
+ POCKET_9,
+ POCKET_10,
+ POCKET_11,
+ POCKET_12,
+ POCKET_13,
+ POCKET_14,
+ POCKET_15,
+ POCKET_16,
+ POCKET_17,
+ POCKET_18,
+ POCKET_19,
+ POCKET_20,
+ POCKET_21,
+ POCKET_22,
+ POCKET_23,
+ POCKET_24,
+ POCKET_25,
+ POCKET_26,
+ POCKET_27,
+ POCKET_28,
+ POCKET_29,
+ POCKET_30,
+ POCKET_31,
+ POCKET_32,
+ POCKET_33,
+ POCKET_34,
+ POCKET_35,
+ POCKET_36,
+ POCKET_37,
+ POCKET_38,
+ POCKET_39,
+ POCKET_40,
+ POCKET_41,
+ POCKET_42,
+ POCKET_43,
+ POCKET_44,
+ POCKET_45,
+ POCKET_46,
+ POCKET_47,
+ POCKET_48,
+ POCKET_49,
+ POCKET_50,
+ POCKET_51,
+ POCKET_52
+};
+
+#define SAND_25 1638407
+#define HOLDING_REPLICA_25 1638408
+#define GMASTER_79 5177345
+#define SCR_std_off (0*0x10000 + 6)
+#define SCR_exit0 (0*0x10000 + 7)
+#define SCR_exit1 (0*0x10000 + 8)
+#define SCR_exit2 (0*0x10000 + 9)
+#define SCR_exit3 (0*0x10000 + 10)
+#define SCR_exit4 (0*0x10000 + 11)
+#define SCR_exit5 (0*0x10000 + 12)
+#define SCR_exit6 (0*0x10000 + 13)
+#define SCR_exit7 (0*0x10000 + 14)
+#define SCR_exit8 (0*0x10000 + 15)
+#define SCR_exit9 (0*0x10000 + 16)
+#define LEFT_SCROLL_POINTER 8388610
+#define RIGHT_SCROLL_POINTER 8388611
+#define FLOOR_63 4128768
+#define ROOF_63 4128779
+#define GUARD_ROOF_63 4128781
+#define LEFT_TREE_POINTER_71 4653058
+#define RIGHT_TREE_POINTER_71 4653059
+#define SCR_menu_look (0*0x10000 + 24)
+#define SCR_icon_combine_script (0*0x10000 + 25)
+
+} // End of namespace Sword1
+
+#endif //SWORDDEFS_H
diff --git a/engines/sword1/swordres.h b/engines/sword1/swordres.h
new file mode 100644
index 0000000000..dca5330350
--- /dev/null
+++ b/engines/sword1/swordres.h
@@ -0,0 +1,5223 @@
+/* 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 SWORDRES_H
+#define SWORDRES_H
+
+namespace Sword1 {
+
+// scripts
+ // standard
+#define SCRIPT0 0x01000000
+ // 1 entities in TXTs, 1 in datafiles.
+ // megas
+#define SCRIPT128 0x01010000
+#define SCRIPT129 0x01010001
+#define SCRIPT130 0x01010002
+#define SCRIPT131 0x01010003
+#define SCRIPT133 0x01010004
+#define SCRIPT134 0x01010005
+#define SCRIPT145 0x01010006
+#define SCRIPT146 0x01010007
+ // 8 entities in TXTs, 8 in datafiles.
+ // maps
+#define SCRIPT80 0x01020000
+#define SCRIPT86 0x01020001
+#define SCRIPT90 0x01020002
+ // 3 entities in TXTs, 3 in datafiles.
+ // paris1
+#define SCRIPT1 0x01030000
+#define SCRIPT2 0x01030001
+#define SCRIPT3 0x01030002
+#define SCRIPT4 0x01030003
+#define SCRIPT5 0x01030004
+#define SCRIPT6 0x01030005
+#define SCRIPT7 0x01030006
+#define SCRIPT8 0x01030007
+ // 8 entities in TXTs, 8 in datafiles.
+ // paris2
+#define SCRIPT9 0x01040000
+#define SCRIPT10 0x01040001
+#define SCRIPT11 0x01040002
+#define SCRIPT12 0x01040003
+#define SCRIPT13 0x01040004
+#define SCRIPT14 0x01040005
+#define SCRIPT15 0x01040006
+#define SCRIPT16 0x01040007
+#define SCRIPT17 0x01040008
+#define SCRIPT18 0x01040009
+#define SCRIPT46 0x0104000A
+ // 11 entities in TXTs, 11 in datafiles.
+ // paris3
+#define SCRIPT27 0x01050000
+#define SCRIPT28 0x01050001
+#define SCRIPT29 0x01050002
+#define SCRIPT31 0x01050003
+#define SCRIPT32 0x01050004
+#define SCRIPT33 0x01050005
+#define SCRIPT34 0x01050006
+#define SCRIPT35 0x01050007
+ // 8 entities in TXTs, 8 in datafiles.
+ // paris4
+#define SCRIPT36 0x01060000
+#define SCRIPT37 0x01060001
+#define SCRIPT38 0x01060002
+#define SCRIPT39 0x01060003
+#define SCRIPT40 0x01060004
+#define SCRIPT41 0x01060005
+#define SCRIPT42 0x01060006
+#define SCRIPT43 0x01060007
+#define SCRIPT48 0x01060008
+ // 9 entities in TXTs, 9 in datafiles.
+ // ireland
+#define SCRIPT19 0x01070000
+#define SCRIPT20 0x01070001
+#define SCRIPT21 0x01070002
+#define SCRIPT22 0x01070003
+#define SCRIPT23 0x01070004
+#define SCRIPT24 0x01070005
+#define SCRIPT25 0x01070006
+#define SCRIPT26 0x01070007
+ // 8 entities in TXTs, 8 in datafiles.
+ // spain
+#define SCRIPT56 0x01080000
+#define SCRIPT57 0x01080001
+#define SCRIPT58 0x01080002
+#define SCRIPT59 0x01080003
+#define SCRIPT60 0x01080004
+#define SCRIPT61 0x01080005
+#define SCRIPT62 0x01080006
+ // 7 entities in TXTs, 7 in datafiles.
+ // syria
+#define SCRIPT45 0x01090000
+#define SCRIPT47 0x01090001
+#define SCRIPT49 0x01090002
+#define SCRIPT50 0x01090003
+#define SCRIPT54 0x01090004
+#define SCRIPT55 0x01090005
+ // 6 entities in TXTs, 6 in datafiles.
+ // train
+#define SCRIPT63 0x010A0000
+#define SCRIPT65 0x010A0001
+#define SCRIPT66 0x010A0002
+#define SCRIPT67 0x010A0003
+#define SCRIPT69 0x010A0004
+ // 5 entities in TXTs, 5 in datafiles.
+ // scotland
+#define SCRIPT71 0x010B0000
+#define SCRIPT72 0x010B0001
+#define SCRIPT73 0x010B0002
+#define SCRIPT74 0x010B0003
+ // 4 entities in TXTs, 4 in datafiles.
+// compacts
+ // standard
+#define TEXT_OBS 0x02000000
+ // 1 entities in TXTs, 1 in datafiles.
+ // megas
+#define MEGA_GEO 0x02010000
+#define GEO_TLK_TABLE 0x02010001
+#define WHT_TLK_TABLE 0x02010002
+#define GEO_SHRUG_TABLE 0x02010003
+#define GEO_GIVE_TABLE 0x02010004
+#define GEO_GIVER_TABLE 0x02010005
+#define GEO_CROUCH_TABLE 0x02010006
+#define GEO_CROUCHR_TABLE 0x02010007
+#define GEO_PICKUP_TABLE 0x02010008
+#define GEO_RELAX_TABLE 0x02010009
+#define GEO_RELAXR_TABLE 0x0201000A
+#define GEO_HAIR_TABLE 0x0201000B
+#define GEO_BLINK_TABLE 0x0201000C
+#define GEOPHN_TABLE 0x0201000D
+#define GEO_GAUGE_TABLE 0x0201000E
+#define GEO_SHOW_TABLE 0x0201000F
+#define GEO_SHOWR_TABLE 0x02010010
+#define GEOSTA_TABLE 0x02010011
+#define GEOMON_TABLE 0x02010012
+#define MEGA_DUANE 0x02010013
+#define DUA5_TABLE 0x02010014
+#define DUA6_TABLE 0x02010015
+#define DUA7_TABLE 0x02010016
+#define DUA8_TABLE 0x02010017
+#define DUA9_TABLE 0x02010018
+#define MEGA_NICO 0x02010019
+#define NIC_TLK_TABLE 0x0201001A
+#define NIC_PHOTO_TABLE 0x0201001B
+#define NICPHN_TABLE 0x0201001C
+#define MEGA_MUS 0x0201001D
+#define MUS_TLK_TABLE 0x0201001E
+#define MEGA_BENOIR 0x0201001F
+#define BEN_GAUGE_TABLE 0x02010020
+#define BEN_TLK_TABLE 0x02010021
+#define MEGA_ROSSO 0x02010022
+#define MEGA_MOUE 0x02010023
+#define MEGA_ALBERT 0x02010024
+ // 37 entities in TXTs, 37 in datafiles.
+ // maps
+#define COMP80 0x02020000
+#define COMP86 0x02020001
+#define COMP90 0x02020002
+#define COMP91 0x02020003
+#define COMP99 0x02020004
+ // 5 entities in TXTs, 5 in datafiles.
+ // paris1
+#define COMP1 0x02030000
+#define COMP2 0x02030001
+#define COMP3 0x02030002
+#define COMP4 0x02030003
+#define COMP5 0x02030004
+#define COMP6 0x02030005
+#define COMP7 0x02030006
+#define COMP8 0x02030007
+ // 8 entities in TXTs, 8 in datafiles.
+ // paris2
+#define COMP9 0x02040000
+#define COMP10 0x02040001
+#define COMP11 0x02040002
+#define COMP12 0x02040003
+#define COMP13 0x02040004
+#define COMP14 0x02040005
+#define COMP15 0x02040006
+#define COMP16 0x02040007
+#define COMP17 0x02040008
+#define COMP18 0x02040009
+#define COMP81 0x0204000A
+#define COMP46 0x0204000B
+ // 12 entities in TXTs, 12 in datafiles.
+ // paris3
+#define COMP27 0x02050000
+#define COMP28 0x02050001
+#define COMP29 0x02050002
+#define COMP30 0x02050003
+#define COMP31 0x02050004
+#define COMP32 0x02050005
+#define COMP33 0x02050006
+#define COMP34 0x02050007
+#define COMP35 0x02050008
+ // 9 entities in TXTs, 9 in datafiles.
+ // paris4
+#define COMP36 0x02060000
+#define COMP37 0x02060001
+#define COMP38 0x02060002
+#define COMP39 0x02060003
+#define COMP40 0x02060004
+#define COMP41 0x02060005
+#define COMP42 0x02060006
+#define COMP43 0x02060007
+#define COMP48 0x02060008
+ // 9 entities in TXTs, 9 in datafiles.
+ // ireland
+#define COMP19 0x02070000
+#define COMP20 0x02070001
+#define COMP21 0x02070002
+#define COMP22 0x02070003
+#define COMP23 0x02070004
+#define COMP24 0x02070005
+#define COMP25 0x02070006
+#define COMP26 0x02070007
+ // 8 entities in TXTs, 8 in datafiles.
+ // spain
+#define COMP56 0x02080000
+#define COMP57 0x02080001
+#define COMP58 0x02080002
+#define COMP59 0x02080003
+#define COMP60 0x02080004
+#define COMP61 0x02080005
+#define COMP62 0x02080006
+ // 7 entities in TXTs, 7 in datafiles.
+ // syria
+#define COMP45 0x02090000
+#define COMP47 0x02090001
+#define COMP49 0x02090002
+#define COMP50 0x02090003
+#define COMP53 0x02090004
+#define COMP54 0x02090005
+#define COMP55 0x02090006
+ // 7 entities in TXTs, 7 in datafiles.
+ // train
+#define COMP63 0x020A0000
+#define COMP65 0x020A0001
+#define COMP66 0x020A0002
+#define COMP67 0x020A0003
+#define COMP69 0x020A0004
+ // 5 entities in TXTs, 5 in datafiles.
+ // scotland
+#define COMP71 0x020B0000
+#define COMP72 0x020B0001
+#define COMP73 0x020B0002
+#define COMP74 0x020B0003
+#define COMP75 0x020B0004
+#define COMP76 0x020B0005
+#define COMP77 0x020B0006
+#define COMP78 0x020B0007
+#define COMP79 0x020B0008
+ // 9 entities in TXTs, 9 in datafiles.
+// text
+ // english
+#define ENGLISH0 0x03000000
+#define ENGLISH1 0x03000001
+#define ENGLISH2 0x03000002
+#define ENGLISH3 0x03000003
+#define ENGLISH4 0x03000004
+#define ENGLISH5 0x03000005
+#define ENGLISH6 0x03000006
+#define ENGLISH7 0x03000007
+#define ENGLISH9 0x03000008
+#define ENGLISH11 0x03000009
+#define ENGLISH12 0x0300000A
+#define ENGLISH13 0x0300000B
+#define ENGLISH14 0x0300000C
+#define ENGLISH15 0x0300000D
+#define ENGLISH16 0x0300000E
+#define ENGLISH17 0x0300000F
+#define ENGLISH18 0x03000010
+#define ENGLISH19 0x03000011
+#define ENGLISH20 0x03000012
+#define ENGLISH21 0x03000013
+#define ENGLISH22 0x03000014
+#define ENGLISH23 0x03000015
+#define ENGLISH24 0x03000016
+#define ENGLISH25 0x03000017
+#define ENGLISH27 0x03000018
+#define ENGLISH28 0x03000019
+#define ENGLISH29 0x0300001A
+#define ENGLISH31 0x0300001B
+#define ENGLISH32 0x0300001C
+#define ENGLISH33 0x0300001D
+#define ENGLISH34 0x0300001E
+#define ENGLISH35 0x0300001F
+#define ENGLISH36 0x03000020
+#define ENGLISH37 0x03000021
+#define ENGLISH38 0x03000022
+#define ENGLISH39 0x03000023
+#define ENGLISH40 0x03000024
+#define ENGLISH41 0x03000025
+#define ENGLISH42 0x03000026
+#define ENGLISH43 0x03000027
+#define ENGLISH45 0x03000028
+#define ENGLISH47 0x03000029
+#define ENGLISH48 0x0300002A
+#define ENGLISH49 0x0300002B
+#define ENGLISH50 0x0300002C
+#define ENGLISH54 0x0300002D
+#define ENGLISH55 0x0300002E
+#define ENGLISH56 0x0300002F
+#define ENGLISH57 0x03000030
+#define ENGLISH58 0x03000031
+#define ENGLISH59 0x03000032
+#define ENGLISH60 0x03000033
+#define ENGLISH61 0x03000034
+#define ENGLISH63 0x03000035
+#define ENGLISH65 0x03000036
+#define ENGLISH66 0x03000037
+#define ENGLISH69 0x03000038
+#define ENGLISH71 0x03000039
+#define ENGLISH72 0x0300003A
+#define ENGLISH73 0x0300003B
+#define ENGLISH74 0x0300003C
+#define ENGLISH90 0x0300003D
+#define ENGLISH99 0x0300003E
+#define ENGLISH129 0x0300003F
+#define ENGLISH131 0x03000040
+#define ENGLISH133 0x03000041
+#define ENGLISH145 0x03000042
+#define ENGLISH146 0x03000043
+ // 68 entities in TXTs, 68 in datafiles.
+ // french
+#define FRENCH0 0x03010000
+#define FRENCH1 0x03010001
+#define FRENCH2 0x03010002
+#define FRENCH3 0x03010003
+#define FRENCH4 0x03010004
+#define FRENCH5 0x03010005
+#define FRENCH6 0x03010006
+#define FRENCH7 0x03010007
+#define FRENCH9 0x03010008
+#define FRENCH11 0x03010009
+#define FRENCH12 0x0301000A
+#define FRENCH13 0x0301000B
+#define FRENCH14 0x0301000C
+#define FRENCH15 0x0301000D
+#define FRENCH16 0x0301000E
+#define FRENCH17 0x0301000F
+#define FRENCH18 0x03010010
+#define FRENCH19 0x03010011
+#define FRENCH20 0x03010012
+#define FRENCH21 0x03010013
+#define FRENCH22 0x03010014
+#define FRENCH23 0x03010015
+#define FRENCH24 0x03010016
+#define FRENCH25 0x03010017
+#define FRENCH27 0x03010018
+#define FRENCH28 0x03010019
+#define FRENCH29 0x0301001A
+#define FRENCH31 0x0301001B
+#define FRENCH32 0x0301001C
+#define FRENCH33 0x0301001D
+#define FRENCH34 0x0301001E
+#define FRENCH35 0x0301001F
+#define FRENCH36 0x03010020
+#define FRENCH37 0x03010021
+#define FRENCH38 0x03010022
+#define FRENCH39 0x03010023
+#define FRENCH40 0x03010024
+#define FRENCH41 0x03010025
+#define FRENCH42 0x03010026
+#define FRENCH43 0x03010027
+#define FRENCH45 0x03010028
+#define FRENCH47 0x03010029
+#define FRENCH48 0x0301002A
+#define FRENCH49 0x0301002B
+#define FRENCH50 0x0301002C
+#define FRENCH54 0x0301002D
+#define FRENCH55 0x0301002E
+#define FRENCH56 0x0301002F
+#define FRENCH57 0x03010030
+#define FRENCH58 0x03010031
+#define FRENCH59 0x03010032
+#define FRENCH60 0x03010033
+#define FRENCH61 0x03010034
+#define FRENCH63 0x03010035
+#define FRENCH65 0x03010036
+#define FRENCH66 0x03010037
+#define FRENCH69 0x03010038
+#define FRENCH71 0x03010039
+#define FRENCH72 0x0301003A
+#define FRENCH73 0x0301003B
+#define FRENCH74 0x0301003C
+#define FRENCH90 0x0301003D
+#define FRENCH99 0x0301003E
+#define FRENCH129 0x0301003F
+#define FRENCH131 0x03010040
+#define FRENCH133 0x03010041
+#define FRENCH145 0x03010042
+#define FRENCH146 0x03010043
+ // 68 entities in TXTs, 68 in datafiles.
+ // german
+#define GERMAN0 0x03020000
+#define GERMAN1 0x03020001
+#define GERMAN2 0x03020002
+#define GERMAN3 0x03020003
+#define GERMAN4 0x03020004
+#define GERMAN5 0x03020005
+#define GERMAN6 0x03020006
+#define GERMAN7 0x03020007
+#define GERMAN9 0x03020008
+#define GERMAN11 0x03020009
+#define GERMAN12 0x0302000A
+#define GERMAN13 0x0302000B
+#define GERMAN14 0x0302000C
+#define GERMAN15 0x0302000D
+#define GERMAN16 0x0302000E
+#define GERMAN17 0x0302000F
+#define GERMAN18 0x03020010
+#define GERMAN19 0x03020011
+#define GERMAN20 0x03020012
+#define GERMAN21 0x03020013
+#define GERMAN22 0x03020014
+#define GERMAN23 0x03020015
+#define GERMAN24 0x03020016
+#define GERMAN25 0x03020017
+#define GERMAN27 0x03020018
+#define GERMAN28 0x03020019
+#define GERMAN29 0x0302001A
+#define GERMAN31 0x0302001B
+#define GERMAN32 0x0302001C
+#define GERMAN33 0x0302001D
+#define GERMAN34 0x0302001E
+#define GERMAN35 0x0302001F
+#define GERMAN36 0x03020020
+#define GERMAN37 0x03020021
+#define GERMAN38 0x03020022
+#define GERMAN39 0x03020023
+#define GERMAN40 0x03020024
+#define GERMAN41 0x03020025
+#define GERMAN42 0x03020026
+#define GERMAN43 0x03020027
+#define GERMAN45 0x03020028
+#define GERMAN47 0x03020029
+#define GERMAN48 0x0302002A
+#define GERMAN49 0x0302002B
+#define GERMAN50 0x0302002C
+#define GERMAN54 0x0302002D
+#define GERMAN55 0x0302002E
+#define GERMAN56 0x0302002F
+#define GERMAN57 0x03020030
+#define GERMAN58 0x03020031
+#define GERMAN59 0x03020032
+#define GERMAN60 0x03020033
+#define GERMAN61 0x03020034
+#define GERMAN63 0x03020035
+#define GERMAN65 0x03020036
+#define GERMAN66 0x03020037
+#define GERMAN69 0x03020038
+#define GERMAN71 0x03020039
+#define GERMAN72 0x0302003A
+#define GERMAN73 0x0302003B
+#define GERMAN74 0x0302003C
+#define GERMAN90 0x0302003D
+#define GERMAN99 0x0302003E
+#define GERMAN129 0x0302003F
+#define GERMAN131 0x03020040
+#define GERMAN133 0x03020041
+#define GERMAN145 0x03020042
+#define GERMAN146 0x03020043
+ // 68 entities in TXTs, 68 in datafiles.
+ // italian
+#define ITALIAN0 0x03030000
+#define ITALIAN1 0x03030001
+#define ITALIAN2 0x03030002
+#define ITALIAN3 0x03030003
+#define ITALIAN4 0x03030004
+#define ITALIAN5 0x03030005
+#define ITALIAN6 0x03030006
+#define ITALIAN7 0x03030007
+#define ITALIAN9 0x03030008
+#define ITALIAN11 0x03030009
+#define ITALIAN12 0x0303000A
+#define ITALIAN13 0x0303000B
+#define ITALIAN14 0x0303000C
+#define ITALIAN15 0x0303000D
+#define ITALIAN16 0x0303000E
+#define ITALIAN17 0x0303000F
+#define ITALIAN18 0x03030010
+#define ITALIAN19 0x03030011
+#define ITALIAN20 0x03030012
+#define ITALIAN21 0x03030013
+#define ITALIAN22 0x03030014
+#define ITALIAN23 0x03030015
+#define ITALIAN24 0x03030016
+#define ITALIAN25 0x03030017
+#define ITALIAN27 0x03030018
+#define ITALIAN28 0x03030019
+#define ITALIAN29 0x0303001A
+#define ITALIAN31 0x0303001B
+#define ITALIAN32 0x0303001C
+#define ITALIAN33 0x0303001D
+#define ITALIAN34 0x0303001E
+#define ITALIAN35 0x0303001F
+#define ITALIAN36 0x03030020
+#define ITALIAN37 0x03030021
+#define ITALIAN38 0x03030022
+#define ITALIAN39 0x03030023
+#define ITALIAN40 0x03030024
+#define ITALIAN41 0x03030025
+#define ITALIAN42 0x03030026
+#define ITALIAN43 0x03030027
+#define ITALIAN45 0x03030028
+#define ITALIAN47 0x03030029
+#define ITALIAN48 0x0303002A
+#define ITALIAN49 0x0303002B
+#define ITALIAN50 0x0303002C
+#define ITALIAN54 0x0303002D
+#define ITALIAN55 0x0303002E
+#define ITALIAN56 0x0303002F
+#define ITALIAN57 0x03030030
+#define ITALIAN58 0x03030031
+#define ITALIAN59 0x03030032
+#define ITALIAN60 0x03030033
+#define ITALIAN61 0x03030034
+#define ITALIAN63 0x03030035
+#define ITALIAN65 0x03030036
+#define ITALIAN66 0x03030037
+#define ITALIAN69 0x03030038
+#define ITALIAN71 0x03030039
+#define ITALIAN72 0x0303003A
+#define ITALIAN73 0x0303003B
+#define ITALIAN74 0x0303003C
+#define ITALIAN90 0x0303003D
+#define ITALIAN99 0x0303003E
+#define ITALIAN129 0x0303003F
+#define ITALIAN131 0x03030040
+#define ITALIAN133 0x03030041
+#define ITALIAN145 0x03030042
+#define ITALIAN146 0x03030043
+ // 68 entities in TXTs, 68 in datafiles.
+ // spanish
+#define SPANISH0 0x03040000
+#define SPANISH1 0x03040001
+#define SPANISH2 0x03040002
+#define SPANISH3 0x03040003
+#define SPANISH4 0x03040004
+#define SPANISH5 0x03040005
+#define SPANISH6 0x03040006
+#define SPANISH7 0x03040007
+#define SPANISH9 0x03040008
+#define SPANISH11 0x03040009
+#define SPANISH12 0x0304000A
+#define SPANISH13 0x0304000B
+#define SPANISH14 0x0304000C
+#define SPANISH15 0x0304000D
+#define SPANISH16 0x0304000E
+#define SPANISH17 0x0304000F
+#define SPANISH18 0x03040010
+#define SPANISH19 0x03040011
+#define SPANISH20 0x03040012
+#define SPANISH21 0x03040013
+#define SPANISH22 0x03040014
+#define SPANISH23 0x03040015
+#define SPANISH24 0x03040016
+#define SPANISH25 0x03040017
+#define SPANISH27 0x03040018
+#define SPANISH28 0x03040019
+#define SPANISH29 0x0304001A
+#define SPANISH31 0x0304001B
+#define SPANISH32 0x0304001C
+#define SPANISH33 0x0304001D
+#define SPANISH34 0x0304001E
+#define SPANISH35 0x0304001F
+#define SPANISH36 0x03040020
+#define SPANISH37 0x03040021
+#define SPANISH38 0x03040022
+#define SPANISH39 0x03040023
+#define SPANISH40 0x03040024
+#define SPANISH41 0x03040025
+#define SPANISH42 0x03040026
+#define SPANISH43 0x03040027
+#define SPANISH45 0x03040028
+#define SPANISH47 0x03040029
+#define SPANISH48 0x0304002A
+#define SPANISH49 0x0304002B
+#define SPANISH50 0x0304002C
+#define SPANISH54 0x0304002D
+#define SPANISH55 0x0304002E
+#define SPANISH56 0x0304002F
+#define SPANISH57 0x03040030
+#define SPANISH58 0x03040031
+#define SPANISH59 0x03040032
+#define SPANISH60 0x03040033
+#define SPANISH61 0x03040034
+#define SPANISH63 0x03040035
+#define SPANISH65 0x03040036
+#define SPANISH66 0x03040037
+#define SPANISH69 0x03040038
+#define SPANISH71 0x03040039
+#define SPANISH72 0x0304003A
+#define SPANISH73 0x0304003B
+#define SPANISH74 0x0304003C
+#define SPANISH90 0x0304003D
+#define SPANISH99 0x0304003E
+#define SPANISH129 0x0304003F
+#define SPANISH131 0x03040040
+#define SPANISH133 0x03040041
+#define SPANISH145 0x03040042
+#define SPANISH146 0x03040043
+ // 68 entities in TXTs, 68 in datafiles.
+ // czech
+#define CZECH0 0x03050000
+#define CZECH1 0x03050001
+#define CZECH2 0x03050002
+#define CZECH3 0x03050003
+#define CZECH4 0x03050004
+#define CZECH5 0x03050005
+#define CZECH6 0x03050006
+#define CZECH7 0x03050007
+#define CZECH9 0x03050008
+#define CZECH11 0x03050009
+#define CZECH12 0x0305000A
+#define CZECH13 0x0305000B
+#define CZECH14 0x0305000C
+#define CZECH15 0x0305000D
+#define CZECH16 0x0305000E
+#define CZECH17 0x0305000F
+#define CZECH18 0x03050010
+#define CZECH19 0x03050011
+#define CZECH20 0x03050012
+#define CZECH21 0x03050013
+#define CZECH22 0x03050014
+#define CZECH23 0x03050015
+#define CZECH24 0x03050016
+#define CZECH25 0x03050017
+#define CZECH27 0x03050018
+#define CZECH28 0x03050019
+#define CZECH29 0x0305001A
+#define CZECH31 0x0305001B
+#define CZECH32 0x0305001C
+#define CZECH33 0x0305001D
+#define CZECH34 0x0305001E
+#define CZECH35 0x0305001F
+#define CZECH36 0x03050020
+#define CZECH37 0x03050021
+#define CZECH38 0x03050022
+#define CZECH39 0x03050023
+#define CZECH40 0x03050024
+#define CZECH41 0x03050025
+#define CZECH42 0x03050026
+#define CZECH43 0x03050027
+#define CZECH45 0x03050028
+#define CZECH47 0x03050029
+#define CZECH48 0x0305002A
+#define CZECH49 0x0305002B
+#define CZECH50 0x0305002C
+#define CZECH54 0x0305002D
+#define CZECH55 0x0305002E
+#define CZECH56 0x0305002F
+#define CZECH57 0x03050030
+#define CZECH58 0x03050031
+#define CZECH59 0x03050032
+#define CZECH60 0x03050033
+#define CZECH61 0x03050034
+#define CZECH63 0x03050035
+#define CZECH65 0x03050036
+#define CZECH66 0x03050037
+#define CZECH69 0x03050038
+#define CZECH71 0x03050039
+#define CZECH72 0x0305003A
+#define CZECH73 0x0305003B
+#define CZECH74 0x0305003C
+#define CZECH90 0x0305003D
+#define CZECH99 0x0305003E
+#define CZECH129 0x0305003F
+#define CZECH131 0x03050040
+#define CZECH133 0x03050041
+#define CZECH145 0x03050042
+#define CZECH146 0x03050043
+ // 68 entities in TXTs, ??? in datafiles.
+ // portugese
+#define PORT0 0x03060000
+#define PORT1 0x03060001
+#define PORT2 0x03060002
+#define PORT3 0x03060003
+#define PORT4 0x03060004
+#define PORT5 0x03060005
+#define PORT6 0x03060006
+#define PORT7 0x03060007
+#define PORT9 0x03060008
+#define PORT11 0x03060009
+#define PORT12 0x0306000A
+#define PORT13 0x0306000B
+#define PORT14 0x0306000C
+#define PORT15 0x0306000D
+#define PORT16 0x0306000E
+#define PORT17 0x0306000F
+#define PORT18 0x03060010
+#define PORT19 0x03060011
+#define PORT20 0x03060012
+#define PORT21 0x03060013
+#define PORT22 0x03060014
+#define PORT23 0x03060015
+#define PORT24 0x03060016
+#define PORT25 0x03060017
+#define PORT27 0x03060018
+#define PORT28 0x03060019
+#define PORT29 0x0306001A
+#define PORT31 0x0306001B
+#define PORT32 0x0306001C
+#define PORT33 0x0306001D
+#define PORT34 0x0306001E
+#define PORT35 0x0306001F
+#define PORT36 0x03060020
+#define PORT37 0x03060021
+#define PORT38 0x03060022
+#define PORT39 0x03060023
+#define PORT40 0x03060024
+#define PORT41 0x03060025
+#define PORT42 0x03060026
+#define PORT43 0x03060027
+#define PORT45 0x03060028
+#define PORT47 0x03060029
+#define PORT48 0x0306002A
+#define PORT49 0x0306002B
+#define PORT50 0x0306002C
+#define PORT54 0x0306002D
+#define PORT55 0x0306002E
+#define PORT56 0x0306002F
+#define PORT57 0x03060030
+#define PORT58 0x03060031
+#define PORT59 0x03060032
+#define PORT60 0x03060033
+#define PORT61 0x03060034
+#define PORT63 0x03060035
+#define PORT65 0x03060036
+#define PORT66 0x03060037
+#define PORT69 0x03060038
+#define PORT71 0x03060039
+#define PORT72 0x0306003A
+#define PORT73 0x0306003B
+#define PORT74 0x0306003C
+#define PORT90 0x0306003D
+#define PORT99 0x0306003E
+#define PORT129 0x0306003F
+#define PORT131 0x03060040
+#define PORT133 0x03060041
+#define PORT145 0x03060042
+#define PORT146 0x03060043
+ // 68 entities in TXTs, ??? in datafiles.
+// general
+ // fonts
+#define GAME_FONT 0x04000000
+#define OTHER_SR_FONT 0x04000001
+#define OTHER_SR_REDFONT 0x04000002
+#define SR_DEATHFONT 0x04000003
+#define CZECH_GAME_FONT 0x04000004
+#define CZECH_SR_FONT 0x04000005
+#define CZECH_SR_REDFONT 0x04000006
+#define CZECH_SR_DEATHFONT 0x04000007
+ // 8 entities in TXTs, 1 in datafiles.
+ // pointers
+#define MSE_POINTER 0x04010000
+#define MSE_OPERATE 0x04010001
+#define MSE_PICKUP 0x04010002
+#define MSE_EXAMINE 0x04010003
+#define MSE_MOUTH 0x04010004
+#define MSE_BECKON_L 0x04010005
+#define MSE_BECKON_R 0x04010006
+#define MSE_ARROW0 0x04010007
+#define MSE_ARROW1 0x04010008
+#define MSE_ARROW2 0x04010009
+#define MSE_ARROW3 0x0401000A
+#define MSE_ARROW4 0x0401000B
+#define MSE_ARROW5 0x0401000C
+#define MSE_ARROW6 0x0401000D
+#define MSE_ARROW7 0x0401000E
+#define MSE_ARROW8 0x0401000F
+#define MSE_ARROW9 0x04010010
+ // 17 entities in TXTs, 17 in datafiles.
+ // luggage
+#define LUGG_NEWSPAPER 0x04020000
+#define LUGG_HAZEL_WAND 0x04020001
+#define LUGG_BEER_TOWEL 0x04020002
+#define LUGG_HOTEL_KEY 0x04020003
+#define LUGG_BALL 0x04020004
+#define LUGG_STATUETTE 0x04020005
+#define LUGG_RED_NOSE 0x04020006
+#define LUGG_POLISHED_CHALICE 0x04020007
+#define LUGG_DOLLAR_BILL 0x04020008
+#define LUGG_PHOTOGRAPH 0x04020009
+#define LUGG_FLASHLIGHT 0x0402000A
+#define LUGG_FUSE_WIRE 0x0402000B
+#define LUGG_GEM 0x0402000C
+#define LUGG_STATUETTE_PAINT 0x0402000D
+#define LUGG_STICK 0x0402000E
+#define LUGG_EXCAV_KEY 0x0402000F
+#define LUGG_LAB_PASS 0x04020010
+#define LUGG_LIFTING_KEYS 0x04020011
+#define LUGG_MANUSCRIPT 0x04020012
+#define LUGG_MATCHBOOK 0x04020013
+#define LUGG_SUIT_MATERIAL 0x04020014
+#define LUGG_STICK_TOWEL 0x04020015
+#define LUGG_PLASTER 0x04020016
+#define LUGG_PRESSURE_GAUGE 0x04020017
+#define LUGG_RAILWAY_TICKET 0x04020018
+#define LUGG_BUZZER 0x04020019
+#define LUGG_ROSSO_CARD 0x0402001A
+#define LUGG_TOILET_KEY 0x0402001B
+#define LUGG_SOAP 0x0402001C
+#define LUGG_STONE_KEY 0x0402001D
+#define LUGG_CHALICE 0x0402001E
+#define LUGG_TISSUE 0x0402001F
+#define LUGG_TOILET_BRUSH 0x04020020
+#define LUGG_TOILET_CHAIN 0x04020021
+#define LUGG_TOWEL 0x04020022
+#define LUGG_TRIPOD 0x04020023
+#define LUGG_LENS 0x04020024
+#define LUGG_MIRROR 0x04020025
+#define LUGG_TOWEL_CUT 0x04020026
+#define LUGG_BIBLE 0x04020027
+#define LUGG_TISSUE_CHARRED 0x04020028
+#define LUGG_FALSE_KEY 0x04020029
+#define LUGG_KEYRING 0x0402002A
+#define LUGG_SOAP_IMP 0x0402002B
+#define LUGG_SOAP_PLAS 0x0402002C
+#define LUGG_COG_1 0x0402002D
+#define LUGG_COG_2 0x0402002E
+#define LUGG_HANDLE 0x0402002F
+#define LUGG_COIN 0x04020030
+#define LUGG_BIRO 0x04020031
+#define LUGG_PIPE 0x04020032
+#define LUGG_KING 0x04020033
+#define LUGG_KNIGHT 0x04020034
+#define LUGG_BISHOP 0x04020035
+ // 54 entities in TXTs, 54 in datafiles.
+ // object_icons
+#define ICON_LEFT_ARROW 0x04030000
+#define ICON_RIGHT_ARROW 0x04030001
+#define ICON_NEWSPAPER 0x04030002
+#define ICON_HAZEL_WAND 0x04030003
+#define ICON_BEER_TOWEL 0x04030004
+#define ICON_HOTEL_KEY 0x04030005
+#define ICON_BALL 0x04030006
+#define ICON_STATUETTE 0x04030007
+#define ICON_RED_NOSE 0x04030008
+#define ICON_POLISHED_CHALICE 0x04030009
+#define ICON_DOLLAR_BILL 0x0403000A
+#define ICON_PHOTOGRAPH 0x0403000B
+#define ICON_FLASHLIGHT 0x0403000C
+#define ICON_FUSE_WIRE 0x0403000D
+#define ICON_GEM 0x0403000E
+#define ICON_STATUETTE_PAINT 0x0403000F
+#define ICON_STICK 0x04030010
+#define ICON_EXCAV_KEY 0x04030011
+#define ICON_LAB_PASS 0x04030012
+#define ICON_LIFTING_KEYS 0x04030013
+#define ICON_MANUSCRIPT 0x04030014
+#define ICON_MATCHBOOK 0x04030015
+#define ICON_SUIT_MATERIAL 0x04030016
+#define ICON_STICK_TOWEL 0x04030017
+#define ICON_PLASTER 0x04030018
+#define ICON_PRESSURE_GAUGE 0x04030019
+#define ICON_RAILWAY_TICKET 0x0403001A
+#define ICON_BUZZER 0x0403001B
+#define ICON_ROSSO_CARD 0x0403001C
+#define ICON_TOILET_KEY 0x0403001D
+#define ICON_SOAP 0x0403001E
+#define ICON_STONE_KEY 0x0403001F
+#define ICON_CHALICE 0x04030020
+#define ICON_TISSUE 0x04030021
+#define ICON_TOILET_BRUSH 0x04030022
+#define ICON_TOILET_CHAIN 0x04030023
+#define ICON_TOWEL 0x04030024
+#define ICON_TRIPOD 0x04030025
+#define ICON_LENS 0x04030026
+#define ICON_MIRROR 0x04030027
+#define ICON_TOWEL_CUT 0x04030028
+#define ICON_BIBLE 0x04030029
+#define ICON_TISSUE_CHARRED 0x0403002A
+#define ICON_FALSE_KEY 0x0403002B
+#define ICON_KEYRING 0x0403002C
+#define ICON_SOAP_IMP 0x0403002D
+#define ICON_SOAP_PLAS 0x0403002E
+#define ICON_COG_1 0x0403002F
+#define ICON_COG_2 0x04030030
+#define ICON_HANDLE 0x04030031
+#define ICON_COIN 0x04030032
+#define ICON_BIRO 0x04030033
+#define ICON_PIPE 0x04030034
+ // 53 entities in TXTs, 53 in datafiles.
+ // subject_icons
+#define ICON_ALARM 0x04040000
+#define ICON_ARTO 0x04040001
+#define ICON_ASSASSIN 0x04040002
+#define ICON_AYUB 0x04040003
+#define ICON_BANANA 0x04040004
+#define ICON_BAPHOMET 0x04040005
+#define ICON_BEER 0x04040006
+#define ICON_BOOK 0x04040007
+#define ICON_BRIEFCASE 0x04040008
+#define ICON_BULL 0x04040009
+#define ICON_BULLS_HEAD 0x0404000A
+#define ICON_BUST 0x0404000B
+#define ICON_CANDLE 0x0404000C
+#define ICON_CAR 0x0404000D
+#define ICON_CASTLE 0x0404000E
+#define ICON_CAT 0x0404000F
+#define ICON_CHANTELLE 0x04040010
+#define ICON_CHESSBOARD 0x04040011
+#define ICON_CHESS_SET 0x04040012
+#define ICON_CHURCH 0x04040013
+#define ICON_CLOWN 0x04040014
+#define ICON_CLUB 0x04040015
+#define ICON_COINS 0x04040016
+#define ICON_COUNTESS 0x04040017
+#define ICON_CREST 0x04040018
+#define ICON_DIG 0x04040019
+#define ICON_DOG 0x0404001A
+#define ICON_DUANE 0x0404001B
+#define ICON_EKLUND 0x0404001C
+#define ICON_ERIC 0x0404001D
+#define ICON_FISH 0x0404001E
+#define ICON_FLOWERS 0x0404001F
+#define ICON_FORTUNE 0x04040020
+#define ICON_GEORGE 0x04040021
+#define ICON_GHOST 0x04040022
+#define ICON_GLASS_EYE 0x04040023
+#define ICON_GOAT 0x04040024
+#define ICON_GOODBYE 0x04040025
+#define ICON_GUARD 0x04040026
+#define ICON_HASH 0x04040027
+#define ICON_HENDERSONS 0x04040028
+#define ICON_JACKET 0x04040029
+#define ICON_JUGGLER 0x0404002A
+#define ICON_KLAUSNER 0x0404002B
+#define ICON_KNIGHT 0x0404002C
+#define ICON_LADDER 0x0404002D
+#define ICON_LEARY 0x0404002E
+#define ICON_LEPRECHAUN 0x0404002F
+#define ICON_LIE 0x04040030
+#define ICON_LOBINEAU 0x04040031
+#define ICON_MARQUET 0x04040032
+#define ICON_MARY 0x04040033
+#define ICON_MOB 0x04040034
+#define ICON_MONTFAUCON 0x04040035
+#define ICON_MOUE 0x04040036
+#define ICON_MR_SHINY 0x04040037
+#define ICON_NEJO 0x04040038
+#define ICON_NEJO_STALL 0x04040039
+#define ICON_NICO 0x0404003A
+#define ICON_NO 0x0404003B
+#define ICON_NURSE 0x0404003C
+#define ICON_PACKAGE 0x0404003D
+#define ICON_PAINTER 0x0404003E
+#define ICON_PEAGRAM 0x0404003F
+#define ICON_PEARL 0x04040040
+#define ICON_PHILIPPE 0x04040041
+#define ICON_PHONE 0x04040042
+#define ICON_PHRASE 0x04040043
+#define ICON_PIERMONT 0x04040044
+#define ICON_PLANTARD 0x04040045
+#define ICON_POTS 0x04040046
+#define ICON_PRIEST 0x04040047
+#define ICON_QUEEN 0x04040048
+#define ICON_RENEE 0x04040049
+#define ICON_ROSSO 0x0404004A
+#define ICON_ROZZER 0x0404004B
+#define ICON_SAFE 0x0404004C
+#define ICON_SCROLL 0x0404004D
+#define ICON_SEAN 0x0404004E
+#define ICON_SIGN 0x0404004F
+#define ICON_TAXI 0x04040050
+#define ICON_TEMPLARS 0x04040051
+#define ICON_THERMOSTAT 0x04040052
+#define ICON_TOILET 0x04040053
+#define ICON_TOMB 0x04040054
+#define ICON_TOOLBOX 0x04040055
+#define ICON_TRUTH 0x04040056
+#define ICON_ULTAR 0x04040057
+#define ICON_WEASEL 0x04040058
+#define ICON_WEAVER 0x04040059
+#define ICON_WELL 0x0404005A
+#define ICON_WELL2 0x0404005B
+#define ICON_WINDOW 0x0404005C
+#define ICON_YES 0x0404005D
+ // 94 entities in TXTs, 94 in datafiles.
+ // save_menu
+#define SR_FONT 0x04050000
+#define SR_BUTTON 0x04050001
+#define SR_REDFONT 0x04050002
+#define SR_PALETTE 0x04050003
+#define SR_PANEL_ENGLISH 0x04050004
+#define SR_PANEL_FRENCH 0x04050005
+#define SR_PANEL_GERMAN 0x04050006
+#define SR_PANEL_ITALIAN 0x04050007
+#define SR_PANEL_SPANISH 0x04050008
+#define SR_PANEL_AMERICAN 0x04050009
+#define SR_TEXT_BUTTON 0x0405000A
+#define SR_SPEED 0x0405000B
+#define SR_SCROLL1 0x0405000C
+#define SR_SCROLL2 0x0405000D
+#define SR_CONFIRM 0x0405000E
+#define SR_VOLUME 0x0405000F
+#define SR_VLIGHT 0x04050010
+#define SR_VKNOB 0x04050011
+#define SR_WINDOW 0x04050012
+#define SR_SLAB1 0x04050013
+#define SR_SLAB2 0x04050014
+#define SR_SLAB3 0x04050015
+#define SR_SLAB4 0x04050016
+#define SR_BUTUF 0x04050017
+#define SR_BUTUS 0x04050018
+#define SR_BUTDS 0x04050019
+#define SR_BUTDF 0x0405001A
+#define SR_DEATHPANEL 0x0405001B // 0x04050019
+ // 26 entities in TXTs, 29 in datafiles.
+ // george
+#define GEORGE_MEGA 0x04060000
+#define GEORGE_WLK 0x04060001
+#define GEOSHO1 0x04060002
+#define GEOSHO1CDT 0x04060003
+#define GEOSHO1CDR 0x04060004
+#define GEOSHO2 0x04060005
+#define GEOSHO2CDT 0x04060006
+#define GEOSHO2CDR 0x04060007
+#define GEOSHO3 0x04060008
+#define GEOSHO3CDT 0x04060009
+#define GEOSHO3CDR 0x0406000A
+#define GEOSHO5 0x0406000B
+#define GEOSHO5CDT 0x0406000C
+#define GEOSHO5CDR 0x0406000D
+#define GEOSHO6 0x0406000E
+#define GEOSHO6CDT 0x0406000F
+#define GEOSHO6CDR 0x04060010
+#define GEOSHO7 0x04060011
+#define GEOSHO7CDT 0x04060012
+#define GEOSHO7CDR 0x04060013
+#define GEOTLK0 0x04060014
+#define GEOTLK0CDT 0x04060015
+#define GEOTLK1 0x04060016
+#define GEOTLK1CDT 0x04060017
+#define GEOTLK2 0x04060018
+#define GEOTLK2CDT 0x04060019
+#define GEOTLK3 0x0406001A
+#define GEOTLK3CDT 0x0406001B
+#define GEOTLK4 0x0406001C
+#define GEOTLK4CDT 0x0406001D
+#define GEOTLK5 0x0406001E
+#define GEOTLK5CDT 0x0406001F
+#define GEOTLK6 0x04060020
+#define GEOTLK6CDT 0x04060021
+#define GEOTLK7 0x04060022
+#define GEOTLK7CDT 0x04060023
+#define XGEOCRW0 0x04060024
+#define XGEOCRW0CDT 0x04060025
+#define XGEOCRW0CDR 0x04060026
+#define XGEOCRW1 0x04060027
+#define XGEOCRW1CDT 0x04060028
+#define XGEOCRW1CDR 0x04060029
+#define XGEOCRW2 0x0406002A
+#define XGEOCRW2CDT 0x0406002B
+#define XGEOCRW2CDR 0x0406002C
+#define XGEOCRW3 0x0406002D
+#define XGEOCRW3CDT 0x0406002E
+#define XGEOCRW3CDR 0x0406002F
+#define XGEOCRW4 0x04060030
+#define XGEOCRW4CDT 0x04060031
+#define XGEOCRW4CDR 0x04060032
+#define XGEOCRW5 0x04060033
+#define XGEOCRW5CDT 0x04060034
+#define XGEOCRW5CDR 0x04060035
+#define XGEOCRW6 0x04060036
+#define XGEOCRW6CDT 0x04060037
+#define XGEOCRW6CDR 0x04060038
+#define XGEOCRW7 0x04060039
+#define XGEOCRW7CDT 0x0406003A
+#define XGEOCRW7CDR 0x0406003B
+#define XGEOGIV0 0x0406003C
+#define XGEOGIV0CDT 0x0406003D
+#define XGEOGIV0CDR 0x0406003E
+#define XGEOGIV1 0x0406003F
+#define XGEOGIV1CDT 0x04060040
+#define XGEOGIV1CDR 0x04060041
+#define XGEOGIV2 0x04060042
+#define XGEOGIV2CDT 0x04060043
+#define XGEOGIV2CDR 0x04060044
+#define XGEOGIV3 0x04060045
+#define XGEOGIV3CDT 0x04060046
+#define XGEOGIV3CDR 0x04060047
+#define XGEOGIV4 0x04060048
+#define XGEOGIV4CDT 0x04060049
+#define XGEOGIV4CDR 0x0406004A
+#define XGEOGIV5 0x0406004B
+#define XGEOGIV5CDT 0x0406004C
+#define XGEOGIV5CDR 0x0406004D
+#define XGEOGIV6 0x0406004E
+#define XGEOGIV6CDT 0x0406004F
+#define XGEOGIV6CDR 0x04060050
+#define XGEOGIV7 0x04060051
+#define XGEOGIV7CDT 0x04060052
+#define XGEOGIV7CDR 0x04060053
+#define XGEOLUK3 0x04060054
+#define XGEOLUK3CDT 0x04060055
+#define XGEOLUK5 0x04060056
+#define XGEOLUK5CDT 0x04060057
+#define XGEOPIC0 0x04060058
+#define XGEOPIC0CDT 0x04060059
+#define XGEOPIC1 0x0406005A
+#define XGEOPIC1CDT 0x0406005B
+#define XGEOPIC2 0x0406005C
+#define XGEOPIC2CDT 0x0406005D
+#define XGEOPIC3 0x0406005E
+#define XGEOPIC3CDT 0x0406005F
+#define XGEOPIC4 0x04060060
+#define XGEOPIC4CDT 0x04060061
+#define XGEOPIC5 0x04060062
+#define XGEOPIC5CDT 0x04060063
+#define XGEOPIC6 0x04060064
+#define XGEOPIC6CDT 0x04060065
+#define XGEOPIC7 0x04060066
+#define XGEOPIC7CDT 0x04060067
+#define XGEOSHG0 0x04060068
+#define XGEOSHG0CDT 0x04060069
+#define XGEOSHG1 0x0406006A
+#define XGEOSHG1CDT 0x0406006B
+#define XGEOSHG2 0x0406006C
+#define XGEOSHG2CDT 0x0406006D
+#define XGEOSHG3 0x0406006E
+#define XGEOSHG3CDT 0x0406006F
+#define XGEOSHG4 0x04060070
+#define XGEOSHG4CDT 0x04060071
+#define XGEOSHG5 0x04060072
+#define XGEOSHG5CDT 0x04060073
+#define XGEOSHG6 0x04060074
+#define XGEOSHG6CDT 0x04060075
+#define XGEOSHG7 0x04060076
+#define XGEOSHG7CDT 0x04060077
+#define XGHAIR2 0x04060078
+#define XGHAIR2CDT 0x04060079
+#define XGHAIR6 0x0406007A
+#define XGHAIR6CDT 0x0406007B
+#define GEOBLNK2 0x0406007C
+#define GEOBLNK2CDT 0x0406007D
+#define GEOBLNK3 0x0406007E
+#define GEOBLNK3CDT 0x0406007F
+#define GEOBLNK4 0x04060080
+#define GEOBLNK4CDT 0x04060081
+#define GEOBLNK5 0x04060082
+#define GEOBLNK5CDT 0x04060083
+#define GEOBLNK6 0x04060084
+#define GEOBLNK6CDT 0x04060085
+#define XGRELAX0 0x04060086
+#define XGRELAX0CDT 0x04060087
+#define XGRELAX0CDR 0x04060088
+#define XGRELAX1 0x04060089
+#define XGRELAX1CDT 0x0406008A
+#define XGRELAX1CDR 0x0406008B
+#define XGRELAX2 0x0406008C
+#define XGRELAX2CDT 0x0406008D
+#define XGRELAX2CDR 0x0406008E
+#define XGRELAX3 0x0406008F
+#define XGRELAX3CDT 0x04060090
+#define XGRELAX3CDR 0x04060091
+#define XGRELAX4 0x04060092
+#define XGRELAX4CDT 0x04060093
+#define XGRELAX4CDR 0x04060094
+#define XGRELAX5 0x04060095
+#define XGRELAX5CDT 0x04060096
+#define XGRELAX5CDR 0x04060097
+#define XGRELAX6 0x04060098
+#define XGRELAX6CDT 0x04060099
+#define XGRELAX6CDR 0x0406009A
+#define XGRELAX7 0x0406009B
+#define XGRELAX7CDT 0x0406009C
+#define XGRELAX7CDR 0x0406009D
+ // 158 entities in TXTs, 158 in datafiles.
+ // nico
+#define MEGANICO 0x04070000
+#define NICO_WLK 0x04070001
+#define NICTLK0 0x04070002
+#define NICTLK0CDT 0x04070003
+#define NICTLK1 0x04070004
+#define NICTLK1CDT 0x04070005
+#define NICTLK2 0x04070006
+#define NICTLK2CDT 0x04070007
+#define NICTLK3 0x04070008
+#define NICTLK3CDT 0x04070009
+#define NICTLK4 0x0407000A
+#define NICTLK4CDT 0x0407000B
+#define NICTLK5 0x0407000C
+#define NICTLK5CDT 0x0407000D
+#define NICTLK6 0x0407000E
+#define NICTLK6CDT 0x0407000F
+#define NICTLK7 0x04070010
+#define NICTLK7CDT 0x04070011
+ // 18 entities in TXTs, 18 in datafiles.
+// maps
+ // room80
+#define room80_PAL 0x05000000
+#define room80_l0 0x05000001
+#define TEST_FLR 0x05000002
+#define SPRITE_PAL 0x05000003
+#define AEROPORTCDT 0x05000004
+#define AEROPORT 0x05000005
+#define APRTSTRTCDT 0x05000006
+#define APRTSTRT 0x05000007
+#define BAPHOMETCDT 0x05000008
+#define BAPHOMET 0x05000009
+#define CAFECDT 0x0500000A
+#define CAFE 0x0500000B
+#define COSTUMESCDT 0x0500000C
+#define COSTUMES 0x0500000D
+#define HOSPITALCDT 0x0500000E
+#define HOSPITAL 0x0500000F
+#define HOTELCDT 0x05000010
+#define HOTEL 0x05000011
+#define MONTFACNCDT 0x05000012
+#define MONTFACN 0x05000013
+#define MUSEUMCDT 0x05000014
+#define MUSEUM 0x05000015
+#define POLICECDT 0x05000016
+#define POLICE 0x05000017
+ // 24 entities in TXTs, 24 in datafiles.
+ // room86
+#define room86_PAL 0x05010000
+#define room86_l0 0x05010001
+#define BANNOCKCDT 0x05010002
+#define BANNOCK 0x05010003
+#define MARIBCDT 0x05010004
+#define MARIB 0x05010005
+#define LOCHMARNCDT 0x05010006
+#define LOCHMARN 0x05010007
+#define PARISCDT 0x05010008
+#define PARIS 0x05010009
+#define VILLAVASCDT 0x0501000A
+#define VILLAVAS 0x0501000B
+ // 12 entities in TXTs, 12 in datafiles.
+ // room90
+#define R90L0 0x05020000
+#define R90PAL 0x05020001
+#define PHONE_PAL 0x05020002
+#define GBLINK 0x05020003
+#define GBLINKCDT 0x05020004
+#define GRISE 0x05020005
+#define GRISECDT 0x05020006
+#define GRISECDR 0x05020007
+#define GTALK 0x05020008
+#define GTALKCDT 0x05020009
+#define NBLINK 0x0502000A
+#define NBLINKCDT 0x0502000B
+#define NRISE 0x0502000C
+#define NRISECDT 0x0502000D
+#define NRISECDR 0x0502000E
+#define NTALK 0x0502000F
+#define NTALKCDT 0x05020010
+#define TODTALK 0x05020011
+#define TODTALKCDT 0x05020012
+ // 19 entities in TXTs, 19 in datafiles.
+ // room91
+#define R91L0 0x05030000
+#define R91PAL 0x05030001
+#define CLOWN 0x05030002
+#define CLOWNCDT 0x05030003
+#define DESVAS 0x05030004
+#define DESVASCDT 0x05030005
+#define EIFTOWER 0x05030006
+#define EIFTOWERCDT 0x05030007
+#define HORSETIP 0x05030008
+#define HORSETIPCDT 0x05030009
+#define LOBIN91 0x0503000A
+#define LOBIN91CDT 0x0503000B
+#define MONTFCON 0x0503000C
+#define MONTFCONCDT 0x0503000D
+#define NICOADD 0x0503000E
+#define NICOADDCDT 0x0503000F
+#define NICOPHN 0x05030010
+#define NICOPHNCDT 0x05030011
+#define TAILOR 0x05030012
+#define TAILORCDT 0x05030013
+ // 20 entities in TXTs, 20 in datafiles.
+ // room99
+#define room99_PAL 0x05040000
+#define room99_l0 0x05040001
+ // 2 entities in TXTs, 2 in datafiles.
+// paris_1
+ // sound_fx
+#define FX_CAMERA1 0x06000000
+#define FX_CAMERA2 0x06000001
+#define FX_CAMERA3 0x06000002
+#define FX_CANDO 0x06000003
+#define FX_CANUP 0x06000004
+#define FX_CAW1 0x06000005
+#define FX_DUST 0x06000006
+#define FX_HORN1 0x06000007
+#define FX_HORN2 0x06000008
+#define FX_HORN3 0x06000009
+#define FX_LVSFLY 0x0600000A
+#define FX_PAP1 0x0600000B
+#define FX_PAP2 0x0600000C
+#define FX_PICK1 0x0600000D
+#define FX_PICK2 0x0600000E
+#define FX_PICK3 0x0600000F
+#define FX_PICK4 0x06000010
+#define FX_PICK5 0x06000011
+#define FX_TRAFFIC2 0x06000012
+#define FX_TWEET1 0x06000013
+#define FX_TWEET2 0x06000014
+#define FX_TWEET3 0x06000015
+#define FX_TWEET4 0x06000016
+#define FX_TWEET5 0x06000017
+#define FX_BIN1 0x06000018
+#define FX_BIN2 0x06000019
+#define FX_BIN3 0x0600001A
+#define FX_CAT 0x0600001B
+#define FX_COVERON2 0x0600001C
+#define FX_CRATE 0x0600001D
+#define FX_DRAIN 0x0600001E
+#define FX_HOLE 0x0600001F
+#define FX_BODY 0x06000020
+#define FX_BOTDN 0x06000021
+#define FX_BOTUP 0x06000022
+#define FX_GULP 0x06000023
+#define FX_LIGHT 0x06000024
+#define FX_PIKUP 0x06000025
+#define FX_PAP3 0x06000026
+#define FX_PAP4 0x06000027
+#define FX_PAP5 0x06000028
+#define FX_PISTOL 0x06000029
+#define FX_TBOX 0x0600002A
+#define FX_KNOKKNOK 0x0600002B
+#define FX_ALBCLO 0x0600002C
+#define FX_ALBOP 0x0600002D
+#define FX_LADD1 0x0600002E
+#define FX_LADD2 0x0600002F
+#define FX_LADD3 0x06000030
+#define FX_RAT1 0x06000031
+#define FX_RAT2 0x06000032
+#define FX_SEWSTEP1 0x06000033
+#define FX_SEWSTEP2 0x06000034
+#define FX_SWATER3 0x06000035
+#define FX_DRIP1 0x06000036
+#define FX_DRIP2 0x06000037
+#define FX_DRIP3 0x06000038
+#define FX_SWATER1 0x06000039
+#define FX_SEWLADD7 0x0600003A
+#define FX_SEWLADU7 0x0600003B
+ // 60 entities in TXTs, 60 in datafiles.
+ // room1
+#define PARIS1_PAL 0x06010000
+#define room1_PAL 0x06010001
+#define room1_l0 0x06010002
+#define room1_l1 0x06010003
+#define room1_l2 0x06010004
+#define room1_gd1 0x06010005
+#define room1_gd2 0x06010006
+#define room1_flr 0x06010007
+#define room1_plx 0x06010008
+#define BIRDS 0x06010009
+#define BIRDSCDT 0x0601000A
+#define BIRDSA 0x0601000B
+#define BIRDSACDT 0x0601000C
+#define BIRDSB 0x0601000D
+#define BIRDSBCDT 0x0601000E
+#define BIRDSC 0x0601000F
+#define BIRDSCCDT 0x06010010
+#define BIRDSD 0x06010011
+#define BIRDSDCDT 0x06010012
+#define BIRDSE 0x06010013
+#define BIRDSECDT 0x06010014
+#define BIRDSF 0x06010015
+#define BIRDSFCDT 0x06010016
+#define BIRDSG 0x06010017
+#define BIRDSGCDT 0x06010018
+#define BIRDSH 0x06010019
+#define BIRDSHCDT 0x0601001A
+#define BIRDSI 0x0601001B
+#define BIRDSICDT 0x0601001C
+#define CANOPY 0x0601001D
+#define CANOPYCDT 0x0601001E
+#define GEOCAN 0x0601001F
+#define GEOCANCDT 0x06010020
+#define GEONIC 0x06010021
+#define GEONICCDT 0x06010022
+#define GEOPAP 0x06010023
+#define GEOPAPCDT 0x06010024
+#define GEOPAP2 0x06010025
+#define GEOPAP2CDT 0x06010026
+#define LVSFLY 0x06010027
+#define LVSFLYCDT 0x06010028
+#define MOUGRD 0x06010029
+#define MOUGRDCDT 0x0601002A
+#define MOUTLK01 0x0601002B
+#define MOUTLK01CDT 0x0601002C
+#define MOUWLK01 0x0601002D
+#define MOUWLK01CDT 0x0601002E
+#define NICPHT1CDT 0x0601002F
+#define NICPHT1 0x06010030
+#define NICPHT2CDT 0x06010031
+#define NICPHT2 0x06010032
+#define NICPHT3CDT 0x06010033
+#define NICPHT3 0x06010034
+#define NICPHT5CDT 0x06010035
+#define NICPHT5 0x06010036
+#define NICPHT6CDT 0x06010037
+#define NICPHT6 0x06010038
+#define NICPHT7CDT 0x06010039
+#define NICPHT7 0x0601003A
+#define NICWLK01 0x0601003B
+#define NICWLK01CDT 0x0601003C
+#define NWPAPER 0x0601003D
+#define NWPAPERCDT 0x0601003E
+#define WRKDIG01 0x0601003F
+#define WRKDIG01CDT 0x06010040
+#define XGEOPHN3 0x06010041
+#define XGEOPHN3CDT 0x06010042
+#define XGEOPHN5 0x06010043
+#define XGEOPHN5CDT 0x06010044
+#define XNICPHN3CDT 0x06010045
+#define XNICPHN3 0x06010046
+#define XNICPHN5CDT 0x06010047
+#define XNICPHN5 0x06010048
+ // 73 entities in TXTs, 73 in datafiles.
+ // room2
+#define room2_PAL 0x06020000
+#define room2_l0 0x06020001
+#define room2_l1 0x06020002
+#define room2_l2 0x06020003
+#define room2_gd1 0x06020004
+#define room2_gd2 0x06020005
+#define room2_flr 0x06020006
+#define BIN1 0x06020007
+#define BIN1CDT 0x06020008
+#define BIN2 0x06020009
+#define BIN2CDT 0x0602000A
+#define BIN3 0x0602000B
+#define BIN3CDT 0x0602000C
+#define CATJMP 0x0602000D
+#define CATJMPCDT 0x0602000E
+#define CRATE 0x0602000F
+#define CRATECDT 0x06020010
+#define DRNBRK 0x06020011
+#define DRNBRKCDT 0x06020012
+#define GEOBIN 0x06020013
+#define GEOBINCDT 0x06020014
+#define GEOBOX 0x06020015
+#define GEOBOXCDT 0x06020016
+#define GEOBRS 0x06020017
+#define GEOBRSCDT 0x06020018
+#define GEOCAT 0x06020019
+#define GEOCATCDT 0x0602001A
+#define GEOCATE 0x0602001B
+#define GEOCATECDT 0x0602001C
+#define GEOCLM02 0x0602001D
+#define GEOCLM02CDT 0x0602001E
+#define GEOCRT 0x0602001F
+#define GEOCRTCDT 0x06020020
+#define GEODWN 0x06020021
+#define GEODWNCDT 0x06020022
+#define GEOLID 0x06020023
+#define GEOLIDCDT 0x06020024
+#define GEOLIDCDR 0x06020025
+#define GEOMAN8 0x06020026
+#define GEOMAN8CDT 0x06020027
+#define GEOMAN9 0x06020028
+#define GEOMAN9CDT 0x06020029
+#define GEOOUT 0x0602002A
+#define GEOOUTCDT 0x0602002B
+#define GEOPLL02 0x0602002C
+#define GEOPLL02CDT 0x0602002D
+#define GEOTRY02 0x0602002E
+#define GEOTRY02CDT 0x0602002F
+#define MANCOV 0x06020030
+#define MANCOVCDT 0x06020031
+#define MANCVOFF 0x06020032
+#define MANCVOFFCDT 0x06020033
+ // 52 entities in TXTs, 52 in datafiles.
+ // room3
+#define room3_PAL 0x06030000
+#define room3_l0 0x06030001
+#define room3_l1 0x06030002
+#define room3_l2 0x06030003
+#define room3_gd1 0x06030004
+#define room3_gd2 0x06030005
+#define room3_flr 0x06030006
+#define BOTTLE 0x06030007
+#define BOTTLECDT 0x06030008
+#define BOTTLE1 0x06030009
+#define BOTTLE1CDT 0x0603000A
+#define CHNDRN 0x0603000B
+#define CHNDRNCDT 0x0603000C
+#define CHNFNT 0x0603000D
+#define CHNFNTCDT 0x0603000E
+#define CHNSITA 0x0603000F
+#define CHNSITACDT 0x06030010
+#define CHNSIT 0x06030011
+#define CHNSITCDT 0x06030012
+#define CHNTLK 0x06030013
+#define CHNTLKCDT 0x06030014
+#define CHNUPP 0x06030015
+#define CHNUPPCDT 0x06030016
+#define CHNUPPCDR 0x06030017
+#define CORPSE 0x06030018
+#define CORPSECDT 0x06030019
+#define FLICKER 0x0603001A
+#define FLICKERCDT 0x0603001B
+#define GEOBOT3 0x0603001C
+#define GEOBOT3CDT 0x0603001D
+#define GEOCARD3 0x0603001E
+#define GEOCARD3CDT 0x0603001F
+#define GEOCHN 0x06030020
+#define GEOCHNCDT 0x06030021
+#define GEOCPS 0x06030022
+#define GEOCPSCDT 0x06030023
+#define GEOCPSCDR 0x06030024
+#define MOUCHN 0x06030025
+#define MOUCHNCDT 0x06030026
+#define MOUCHN8 0x06030027
+#define MOUCHN8CDT 0x06030028
+#define MOUCPS 0x06030029
+#define MOUCPSCDT 0x0603002A
+#define MOUCPSTK 0x0603002B
+#define MOUCPSTKCDT 0x0603002C
+#define MOUDOR03 0x0603002D
+#define MOUDOR03CDT 0x0603002E
+#define MOUROS 0x0603002F
+#define MOUROSCDT 0x06030030
+#define MOUROS1 0x06030031
+#define MOUROS1CDT 0x06030032
+#define MOUROS1CDR 0x06030033
+#define MOUROS2 0x06030034
+#define MOUROS2CDT 0x06030035
+#define MOUSTD 0x06030036
+#define MOUSTDCDT 0x06030037
+#define MOUTALK 0x06030038
+#define MOUTALKCDT 0x06030039
+#define MOUTLK1 0x0603003A
+#define MOUTLK1CDT 0x0603003B
+#define MOUTRN03 0x0603003C
+#define MOUTRN03CDT 0x0603003D
+#define MOUTRN03CDR 0x0603003E
+#define MOUTRN2 0x0603003F
+#define MOUTRN2CDT 0x06030040
+#define MOUTRN2CDR 0x06030041
+#define MOUWLK 0x06030042
+#define MOUWLKCDT 0x06030043
+#define MOUWLK03 0x06030044
+#define MOUWLK03CDT 0x06030045
+#define ROSCARD 0x06030046
+#define ROSCARDCDT 0x06030047
+#define ROSCHN 0x06030048
+#define ROSCHNCDT 0x06030049
+#define ROSCHNCDR 0x0603004A
+#define ROSGEO 0x0603004B
+#define ROSGEOCDT 0x0603004C
+#define ROSGEOA 0x0603004D
+#define ROSGEOACDT 0x0603004E
+#define ROSGEOB 0x0603004F
+#define ROSGEOBCDT 0x06030050
+#define ROSGEOC 0x06030051
+#define ROSGEOCCDT 0x06030052
+#define ROSLIK 0x06030053
+#define ROSLIKCDT 0x06030054
+#define ROSLUK 0x06030055
+#define ROSLUKCDT 0x06030056
+#define ROSMOU 0x06030057
+#define ROSMOUCDT 0x06030058
+#define ROSNBK 0x06030059
+#define ROSNBKCDT 0x0603005A
+#define ROSNBK8 0x0603005B
+#define ROSNBK8CDT 0x0603005C
+#define ROSPKT 0x0603005D
+#define ROSPKTCDT 0x0603005E
+#define ROSTMP 0x0603005F
+#define ROSTMPCDT 0x06030060
+#define ROSTMP8 0x06030061
+#define ROSTMP8CDT 0x06030062
+#define ROSTURNA 0x06030063
+#define ROSTURNACDT 0x06030064
+#define ROSTURNB 0x06030065
+#define ROSTURNBCDT 0x06030066
+#define ROSTRN2 0x06030067
+#define ROSTRN2CDT 0x06030068
+#define ROSWRT 0x06030069
+#define ROSWRTCDT 0x0603006A
+ // 107 entities in TXTs, 107 in datafiles.
+ // room4
+#define room4_PAL 0x06040000
+#define room4_l0 0x06040001
+#define room4_l1 0x06040002
+#define room4_l2 0x06040003
+#define room4_gd1 0x06040004
+#define room4_gd2 0x06040005
+#define room4_flr 0x06040006
+#define ALBDOR 0x06040007
+#define ALBDORCDR 0x06040008
+#define ALBDORCDT 0x06040009
+#define ALBDOR8 0x0604000A
+#define ALBDOR8CDT 0x0604000B
+#define GEONOK 0x0604000C
+#define GEONOKCDT 0x0604000D
+#define GEONOKCDR 0x0604000E
+#define GEOTBX 0x0604000F
+#define GEOTBXCDT 0x06040010
+#define GEOWRK 0x06040011
+#define GEOWRKCDT 0x06040012
+#define GEOWRK8 0x06040013
+#define GEOWRK8CDT 0x06040014
+#define MOUENT 0x06040015
+#define MOUENTCDT 0x06040016
+#define MOUSHG 0x06040017
+#define MOUSHGCDT 0x06040018
+#define MOUSTR 0x06040019
+#define MOUSTRCDT 0x0604001A
+#define MOUTLK04 0x0604001B
+#define MOUTLK04CDT 0x0604001C
+#define MOUWLK04 0x0604001D
+#define MOUWLK04CDT 0x0604001E
+#define ROSENT 0x0604001F
+#define ROSENTCDT 0x06040020
+#define ROSTLK04 0x06040021
+#define ROSTLK04CDT 0x06040022
+#define ROSWLK 0x06040023
+#define ROSWLKCDT 0x06040024
+#define PHONE4 0x06040025
+#define PHONE4CDT 0x06040026
+#define WRKAXE 0x06040027
+#define WRKAXECDT 0x06040028
+#define WRKBLINK 0x06040029
+#define WRKBLINKCDT 0x0604002A
+#define WRKCLM 0x0604002B
+#define WRKCLMCDT 0x0604002C
+#define WRKDIG 0x0604002D
+#define WRKDIGCDT 0x0604002E
+#define WRKPPR 0x0604002F
+#define WRKPPRCDT 0x06040030
+#define WRKTLK 0x06040031
+#define WRKTLKCDT 0x06040032
+#define WRKTLK8 0x06040033
+#define WRKTLK8CDT 0x06040034
+#define WRKTLK9 0x06040035
+#define WRKTLK9CDT 0x06040036
+#define WRKTRN 0x06040037
+#define WRKTRNCDR 0x06040038
+#define WRKTRNCDT 0x06040039
+#define WRKXIT 0x0604003A
+#define WRKXITCDT 0x0604003B
+ // 60 entities in TXTs, 60 in datafiles.
+ // room5
+#define room5_PAL 0x06050000
+#define room5_l0 0x06050001
+#define room5_l1 0x06050002
+#define room5_l2 0x06050003
+#define room5_gd1 0x06050004
+#define room5_gd2 0x06050005
+#define room5_flr 0x06050006
+#define ALBAPT 0x06050007
+#define ALBAPTCDT 0x06050008
+#define ALBAPTCDR 0x06050009
+#define ALBCLOSECDT 0x0605000A
+#define ALBCLOSE 0x0605000B
+#define ALBCRD8 0x0605000C
+#define ALBCRD8CDT 0x0605000D
+#define ALBDORTKCDT 0x0605000E
+#define ALBDORTK 0x0605000F
+#define ALBDRTK2CDT 0x06050010
+#define ALBDRTK2 0x06050011
+#define ALBHND 0x06050012
+#define ALBHNDCDT 0x06050013
+#define ALBOBJ 0x06050014
+#define ALBOBJCDT 0x06050015
+#define ALBOPENCDT 0x06050016
+#define ALBOPEN 0x06050017
+#define ALBPKT 0x06050018
+#define ALBPKTCDT 0x06050019
+#define ALBTLK 0x0605001A
+#define ALBTLKCDT 0x0605001B
+#define ALBWLK9CDT 0x0605001C
+#define ALBWLK9 0x0605001D
+#define GEOCRD05 0x0605001E
+#define GEOCRD05CDT 0x0605001F
+#define GEODOR05CDT 0x06050020
+#define GEODOR05 0x06050021
+#define GEOEMG 0x06050022
+#define GEOEMGCDT 0x06050023
+#define GEOEMGCDR 0x06050024
+#define GEOEMGA 0x06050025
+#define GEOEMGACDT 0x06050026
+#define GEOEMGACDR 0x06050027
+#define GEOEMGB 0x06050028
+#define GEOEMGBCDT 0x06050029
+#define GEOEMGBCDR 0x0605002A
+#define GEOEXITCDT 0x0605002B
+#define GEOEXIT 0x0605002C
+#define GEOHND05 0x0605002D
+#define GEOHND05CDT 0x0605002E
+#define GEONOK05CDT 0x0605002F
+#define GEONOK05 0x06050030
+#define GEOTLK05 0x06050031
+#define GEOTLK05CDT 0x06050032
+ // 51 entities in TXTs, 51 in datafiles.
+ // room6
+#define SEWER_PAL 0x06060000
+#define room6_PAL 0x06060001
+#define room6_l0 0x06060002
+#define room6_l1 0x06060003
+#define room6_gd1 0x06060004
+#define room6_flr 0x06060005
+#define GEOASC06 0x06060006
+#define GEOASC06CDT 0x06060007
+#define GEODES06 0x06060008
+#define GEODES06CDT 0x06060009
+#define GEONOSE 0x0606000A
+#define GEONOSECDT 0x0606000B
+#define REDNOSE 0x0606000C
+#define REDNOSECDT 0x0606000D
+#define WATER06 0x0606000E
+#define WATER06CDT 0x0606000F
+ // 16 entities in TXTs, 16 in datafiles.
+ // room7
+#define room7_PAL 0x06070000
+#define room7_l0 0x06070001
+#define room7_l1 0x06070002
+#define room7_l2 0x06070003
+#define room7_gd1 0x06070004
+#define room7_gd2 0x06070005
+#define room7_flr 0x06070006
+#define GEOASC07 0x06070007
+#define GEOASC07CDT 0x06070008
+#define GEOASC07CDR 0x06070009
+#define GEOPLL07 0x0607000A
+#define GEOPLL07CDT 0x0607000B
+#define GEOPLL07CDR 0x0607000C
+#define GEOSPK 0x0607000D
+#define GEOSPKCDT 0x0607000E
+#define GEOTIS 0x0607000F
+#define GEOTISCDT 0x06070010
+#define MATERIAL 0x06070011
+#define MATERIALCDT 0x06070012
+#define TISSUE7 0x06070013
+#define TISSUE7CDT 0x06070014
+#define WATER07 0x06070015
+#define WATER07CDT 0x06070016
+ // 23 entities in TXTs, 23 in datafiles.
+ // room8
+#define room8_PAL 0x06080000
+#define room8_l0 0x06080001
+#define room8_l1 0x06080002
+#define room8_l2 0x06080003
+#define room8_gd1 0x06080004
+#define room8_gd2 0x06080005
+#define room8_flr 0x06080006
+#define room8_plx 0x06080007
+ // 8 entities in TXTs, 8 in datafiles.
+// paris_2
+ // sound_fx
+#define FX_BIRD 0x07000000
+#define FX_BIRD2 0x07000001
+#define FX_CARLTON 0x07000002
+#define FX_CARS 0x07000003
+#define FX_DOORTRY 0x07000004
+#define FX_FIESTA 0x07000005
+#define FX_FLATDOOR 0x07000006
+#define FX_HVYVEHL 0x07000007
+#define FX_HVYVEHR 0x07000008
+#define FX_LITEVEHL 0x07000009
+#define FX_LITEVEHR 0x0700000A
+#define FX_FONEUP 0x0700000B
+#define FX_FONEDN 0x0700000C
+#define FX_GEOCCH 0x0700000D
+#define FX_GEOCHAIR 0x0700000E
+#define FX_GEOCHR9 0x0700000F
+#define FX_NICOPEN 0x07000010
+#define FX_NICLOSE 0x07000011
+#define FX_PHONICO1 0x07000012
+#define FX_GRAMOFON 0x07000013
+#define FX_SHOCK1 0x07000014
+#define FX_WINDUP11 0x07000015
+#define FX_FRISK 0x07000016
+#define FX_TRAFFIC3 0x07000017
+#define FX_DESKBELL 0x07000018
+#define FX_KEY13 0x07000019
+#define FX_PAPER6 0x0700001A
+#define FX_PHONEDN2 0x0700001B
+#define FX_PHONEUP2 0x0700001C
+#define FX_PIANO14 0x0700001D
+#define FX_TRYDOR14 0x0700001E
+#define FX_CABCLOSE 0x0700001F
+#define FX_CABOPEN 0x07000020
+#define FX_DORCLOSE 0x07000021
+#define FX_WINDOPEN 0x07000022
+#define FX_COO 0x07000023
+#define FX_COO2 0x07000024
+#define FX_LEDGE1 0x07000025
+#define FX_LEDGE2 0x07000026
+#define FX_BRIEFOFF 0x07000027
+#define FX_BRIEFON 0x07000028
+#define FX_JUMPIN 0x07000029
+#define FX_WARDIN 0x0700002A
+#define FX_WARDOUT 0x0700002B
+#define FX_CLIMBIN 0x0700002C
+#define FX_CLIMBOUT 0x0700002D
+ // 46 entities in TXTs, 46 in datafiles.
+ // room9
+#define PARIS2_PAL 0x07010000
+#define room9_PAL 0x07010001
+#define room9_l0 0x07010002
+#define room9_l1 0x07010003
+#define room9_l2 0x07010004
+#define room9_gd1 0x07010005
+#define room9_gd2 0x07010006
+#define room9_flr 0x07010007
+#define CARA9CDT 0x07010008
+#define CARA9 0x07010009
+#define CARB9CDT 0x0701000A
+#define CARB9 0x0701000B
+#define CARC9CDT 0x0701000C
+#define CARC9 0x0701000D
+#define DOROPN09CDR 0x0701000E
+#define DOROPN09CDT 0x0701000F
+#define DOROPN09 0x07010010
+#define FLWLUKCDR 0x07010011
+#define FLWLUKCDT 0x07010012
+#define FLWLUK 0x07010013
+#define FLWNITCDT 0x07010014
+#define FLWNIT 0x07010015
+#define FLWTLKCDT 0x07010016
+#define FLWTLK 0x07010017
+#define GEODOOR9 0x07010018
+#define GEODOOR9CDT 0x07010019
+#define GEOSTPCDT 0x0701001A
+#define GEOSTP 0x0701001B
+#define GEOSTP8CDT 0x0701001C
+#define GEOSTP8 0x0701001D
+#define GEOTRY 0x0701001E
+#define GEOTRYCDT 0x0701001F
+#define TRUCKA9CDT 0x07010020
+#define TRUCKA9 0x07010021
+#define TRUCKB9CDT 0x07010022
+#define TRUCKB9 0x07010023
+#define TRUCKC9CDT 0x07010024
+#define TRUCKC9 0x07010025
+ // 38 entities in TXTs, 38 in datafiles.
+ // room10
+#define R10SPRPAL 0x07020000
+#define room10_PAL 0x07020001
+#define room10_l0 0x07020002
+#define room10_l1 0x07020003
+#define room10_gd1 0x07020004
+#define room10_flr 0x07020005
+#define DOORCDT 0x07020006
+#define DOOR 0x07020007
+#define GEOCCHCDT 0x07020008
+#define GEOCCHCDR 0x07020009
+#define GEOCCH 0x0702000A
+#define GEOCCH8CDT 0x0702000B
+#define GEOCCH8 0x0702000C
+#define GEOCCH9CDT 0x0702000D
+#define GEOCCH9 0x0702000E
+#define GEOCHRCDT 0x0702000F
+#define GEOCHR 0x07020010
+#define GEOCHR8CDT 0x07020011
+#define GEOCHR8 0x07020012
+#define GEOCHR9CDT 0x07020013
+#define GEOCHR9 0x07020014
+#define GEODWN10CDT 0x07020015
+#define GEODWN10 0x07020016
+#define GEOENT10CDT 0x07020017
+#define GEOENT10 0x07020018
+#define GEOGEM10CDT 0x07020019
+#define GEOGEM10 0x0702001A
+#define GEOGEMBCDT 0x0702001B
+#define GEOGEMB 0x0702001C
+#define GEOLUK10CDT 0x0702001D
+#define GEOLUK10 0x0702001E
+#define GEOLVS10CDT 0x0702001F
+#define GEOLVS10 0x07020020
+#define GEOMAGTKCDT 0x07020021
+#define GEOMAGTK 0x07020022
+#define GEOMAT10CDT 0x07020023
+#define GEOMAT10 0x07020024
+#define GEOMATBCDT 0x07020025
+#define GEOMATB 0x07020026
+#define GEOMATCCDT 0x07020027
+#define GEOMATC 0x07020028
+#define GEONIC10CDR 0x07020029
+#define GEONIC10CDT 0x0702002A
+#define GEONIC10 0x0702002B
+#define GEONOSCDT 0x0702002C
+#define GEONOS 0x0702002D
+#define GEONOS10CDT 0x0702002E
+#define GEONOS10 0x0702002F
+#define GEONWPAPCDT 0x07020030
+#define GEONWPAP 0x07020031
+#define GEOPHN10CDT 0x07020032
+#define GEOPHN10 0x07020033
+#define GEOPHTCDT 0x07020034
+#define GEOPHT 0x07020035
+#define GEOPHT10CDT 0x07020036
+#define GEOPHT10 0x07020037
+#define GEOPHTLKCDT 0x07020038
+#define GEOPHTLK 0x07020039
+#define GEOPPR10CDT 0x0702003A
+#define GEOPPR10 0x0702003B
+#define GEOPRDCDT 0x0702003C
+#define GEOPRD 0x0702003D
+#define GEOREDCDT 0x0702003E
+#define GEORED 0x0702003F
+#define GEORELCDR 0x07020040
+#define GEORELCDT 0x07020041
+#define GEOREL 0x07020042
+#define GEORXTCDT 0x07020043
+#define GEORXT 0x07020044
+#define GEOTIS10CDT 0x07020045
+#define GEOTIS10 0x07020046
+#define GEOTISBCDT 0x07020047
+#define GEOTISB 0x07020048
+#define GEOTRIP1CDT 0x07020049
+#define GEOTRIP1 0x0702004A
+#define GEOTRIP2CDT 0x0702004B
+#define GEOTRIP2 0x0702004C
+#define LOBTLK10CDT 0x0702004D
+#define LOBTLK10 0x0702004E
+#define MANUCDT 0x0702004F
+#define MANU 0x07020050
+#define NICCHR9CDR 0x07020051
+#define NICCHR9CDT 0x07020052
+#define NICCHR9 0x07020053
+#define NICDWN10CDT 0x07020054
+#define NICDWN10 0x07020055
+#define NICLUK10CDT 0x07020056
+#define NICLUK10 0x07020057
+#define NICMAGCDR 0x07020058
+#define NICMAGCDT 0x07020059
+#define NICMAG 0x0702005A
+#define NICNOSCDT 0x0702005B
+#define NICNOS 0x0702005C
+#define NICNOS10CDT 0x0702005D
+#define NICNOS10 0x0702005E
+#define NICNOSBCDT 0x0702005F
+#define NICNOSB 0x07020060
+#define NICPHN10CDT 0x07020061
+#define NICPHN10 0x07020062
+#define NICPHT10CDT 0x07020063
+#define NICPHT10 0x07020064
+#define NICPPRCDT 0x07020065
+#define NICPPR 0x07020066
+#define NICPPR2CDT 0x07020067
+#define NICPPR2 0x07020068
+#define NICREDCDT 0x07020069
+#define NICRED 0x0702006A
+#define NICRED2CDR 0x0702006B
+#define NICRED2CDT 0x0702006C
+#define NICRED2 0x0702006D
+#define NICSIT 0x0702006E
+#define NICSITCDT 0x0702006F
+#define NICTLK10CDT 0x07020070
+#define NICTLK10 0x07020071
+#define NICTLKL 0x07020072
+#define NICTLKLCDT 0x07020073
+#define NICTLKR 0x07020074
+#define NICTLKRCDT 0x07020075
+#define NICTLKX 0x07020076
+#define NICTLKXCDT 0x07020077
+#define NICTLKXCDR 0x07020078
+#define NICTRIPCDT 0x07020079
+#define NICTRIP 0x0702007A
+#define NICTURN 0x0702007B
+#define NICTURNCDT 0x0702007C
+#define NICTURNCDR 0x0702007D
+#define NICWRT 0x0702007E
+#define NICWRTCDT 0x0702007F
+#define PHONE10CDT 0x07020080
+#define PHONE10 0x07020081
+#define PEAPAGECDT 0x07020082
+#define PEAPAGE 0x07020083
+#define PEAPAGE_PAL 0x07020084
+#define MANUSCRPCDT 0x07020085
+#define MANUSCRP 0x07020086
+#define MANUSCRP_PAL 0x07020087
+#define TRIPOD10CDT 0x07020088
+#define TRIPOD10 0x07020089
+ // 138 entities in TXTs, 138 in datafiles.
+ // room11
+#define room11_PAL 0x07030000
+#define room11_l0 0x07030001
+#define room11_l1 0x07030002
+#define room11_l2 0x07030003
+#define room11_gd1 0x07030004
+#define room11_gd2 0x07030005
+#define room11_flr 0x07030006
+#define COSGIVCDR 0x07030007
+#define COSGIVCDT 0x07030008
+#define COSGIV 0x07030009
+#define COSLOOPCDT 0x0703000A
+#define COSLOOP 0x0703000B
+#define COSSHKCDT 0x0703000C
+#define COSSHK 0x0703000D
+#define COSSNFCDT 0x0703000E
+#define COSSNF 0x0703000F
+#define COSTLKCDT 0x07030010
+#define COSTLK 0x07030011
+#define DISCSPINCDT 0x07030012
+#define DISCSPIN 0x07030013
+#define GEOPIC11CDR 0x07030014
+#define GEOPIC11CDT 0x07030015
+#define GEOPIC11 0x07030016
+#define GEOSHK11CDT 0x07030017
+#define GEOSHK11 0x07030018
+#define GEOTURDCDT 0x07030019
+#define GEOTURD 0x0703001A
+#define GEOTIS11CDT 0x0703001B
+#define GEOTIS11 0x0703001C
+#define GEOWINDCDT 0x0703001D
+#define GEOWIND 0x0703001E
+#define WINDUPCDT 0x0703001F
+#define WINDUP 0x07030020
+ // 33 entities in TXTs, 33 in datafiles.
+ // room12
+#define room12_PAL 0x07040000
+#define room12_l0 0x07040001
+#define room12_l1 0x07040002
+#define room12_gd1 0x07040003
+#define room12_flr 0x07040004
+#define FLAGSCDT 0x07040005
+#define FLAGS 0x07040006
+#define GEOAPPCDT 0x07040007
+#define GEOAPP 0x07040008
+#define GEOARMCDT 0x07040009
+#define GEOARM 0x0704000A
+#define GEOASC12CDT 0x0704000B
+#define GEOASC12 0x0704000C
+#define GEODES12CDT 0x0704000D
+#define GEODES12 0x0704000E
+#define GORCOINCDT 0x0704000F
+#define GORCOIN 0x07040010
+#define GORFRKCDT 0x07040011
+#define GORFRK 0x07040012
+#define GORMANCDT 0x07040013
+#define GORMAN 0x07040014
+#define GORTALKCDT 0x07040015
+#define GORTALK 0x07040016
+#define GORTLKCDT 0x07040017
+#define GORTLK 0x07040018
+#define GORTURNCDR 0x07040019
+#define GORTURNCDT 0x0704001A
+#define GORTURN 0x0704001B
+#define LATVIAN12CDT 0x0704001C
+#define LATVIAN12 0x0704001D
+#define WEABAKCDT 0x0704001E
+#define WEABAK 0x0704001F
+#define WEASMKCDT 0x07040020
+#define WEASMK 0x07040021
+#define WEATLKCDT 0x07040022
+#define WEATLK 0x07040023
+#define WEATLK12CDT 0x07040024
+#define WEATLK12 0x07040025
+#define WEATRNCDR 0x07040026
+#define WEATRNCDT 0x07040027
+#define WEATRN 0x07040028
+ // 41 entities in TXTs, 41 in datafiles.
+ // room13
+#define R13SPRPAL 0x07050000
+#define room13_PAL 0x07050001
+#define room13_l0 0x07050002
+#define room13_l1 0x07050003
+#define room13_l2 0x07050004
+#define room13_gd1 0x07050005
+#define room13_gd2 0x07050006
+#define room13_flr 0x07050007
+#define CLKIDLCDT 0x07050008
+#define CLKIDL 0x07050009
+#define CLKMANCDT 0x0705000A
+#define CLKMAN 0x0705000B
+#define CLKTAKCDT 0x0705000C
+#define CLKTAK 0x0705000D
+#define CLKTLKCDT 0x0705000E
+#define CLKTLK 0x0705000F
+#define CLKTLK2CDT 0x07050010
+#define CLKTLK2 0x07050011
+#define CLKTLK3CDT 0x07050012
+#define CLKTLK3 0x07050013
+#define CLKTURNCDR 0x07050014
+#define CLKTURNCDT 0x07050015
+#define CLKTURN 0x07050016
+#define CLKWLKCDT 0x07050017
+#define CLKWLK 0x07050018
+#define CLKWLK2CDT 0x07050019
+#define CLKWLK2 0x0705001A
+#define CLKWLK3CDT 0x0705001B
+#define CLKWLK3 0x0705001C
+#define CLKWULCDT 0x0705001D
+#define CLKWUL 0x0705001E
+#define GEOASC13CDT 0x0705001F
+#define GEOASC13 0x07050020
+#define GEODES13CDT 0x07050021
+#define GEODES13 0x07050022
+#define GEOKEYCDT 0x07050023
+#define GEOKEY 0x07050024
+#define GEOKEY13CDT 0x07050025
+#define GEOKEY13 0x07050026
+#define GEOMAN13CDT 0x07050027
+#define GEOMAN13 0x07050028
+#define GEOTELCDT 0x07050029
+#define GEOTEL 0x0705002A
+#define GEOTEL9CDT 0x0705002B
+#define GEOTEL9 0x0705002C
+#define KEY13CDT 0x0705002D
+#define KEY13 0x0705002E
+#define LATLUKCDR 0x0705002F
+#define LATLUKCDT 0x07050030
+#define LATLUK 0x07050031
+#define LATRDSCDT 0x07050032
+#define LATRDS 0x07050033
+#define LATTLKCDT 0x07050034
+#define LATTLK 0x07050035
+#define PMTGIVCDT 0x07050036
+#define PMTGIV 0x07050037
+#define PMTPNOCDT 0x07050038
+#define PMTPNO 0x07050039
+#define PMTSTDCDT 0x0705003A
+#define PMTSTD 0x0705003B
+#define PMTTLKCDT 0x0705003C
+#define PMTTLK 0x0705003D
+#define PMTTLK8CDT 0x0705003E
+#define PMTTLK8 0x0705003F
+#define PMTTLK9CDT 0x07050040
+#define PMTTLK9 0x07050041
+#define PMTTOTLKCDR 0x07050042
+#define PMTTOTLKCDT 0x07050043
+#define PMTTOTLK 0x07050044
+#define PMTTURNCDR 0x07050045
+#define PMTTURNCDT 0x07050046
+#define PMTTURN 0x07050047
+#define PMTWLK1CDT 0x07050048
+#define PMTWLK1 0x07050049
+#define PMTWLK2CDT 0x0705004A
+#define PMTWLK2 0x0705004B
+ // 76 entities in TXTs, 76 in datafiles.
+ // room14
+#define room14_PAL 0x07060000
+#define room14_l0 0x07060001
+#define room14_l1 0x07060002
+#define room14_gd1 0x07060003
+#define room14_flr 0x07060004
+#define GEOASC14CDT 0x07060005
+#define GEOASC14 0x07060006
+#define GEODES14CDT 0x07060007
+#define GEODES14 0x07060008
+#define GEODORCDR 0x07060009
+#define GEODORCDT 0x0706000A
+#define GEODOR 0x0706000B
+ // 12 entities in TXTs, 12 in datafiles.
+ // room15
+#define room15_PAL 0x07070000
+#define room15_l0 0x07070001
+#define room15_l1 0x07070002
+#define room15_l2 0x07070003
+#define room15_gd1 0x07070004
+#define room15_gd2 0x07070005
+#define room15_flr 0x07070006
+#define DOROPN15CDT 0x07070007
+#define DOROPN15 0x07070008
+#define GEOBEDCDR 0x07070009
+#define GEOBEDCDT 0x0707000A
+#define GEOBED 0x0707000B
+#define GEODOR15CDT 0x0707000C
+#define GEODOR15 0x0707000D
+#define GEOENT15CDT 0x0707000E
+#define GEOENT15 0x0707000F
+#define GEOWIN1CDT 0x07070010
+#define GEOWIN1 0x07070011
+#define GEOWIN15CDT 0x07070012
+#define GEOWIN15 0x07070013
+#define GEOWIN2CDT 0x07070014
+#define GEOWIN2 0x07070015
+#define GEOWRBCDR 0x07070016
+#define GEOWRBCDT 0x07070017
+#define GEOWRB 0x07070018
+#define WINDOWCDT 0x07070019
+#define WINDOW 0x0707001A
+ // 27 entities in TXTs, 27 in datafiles.
+ // room16
+#define room16_PAL 0x07080000
+#define R16L0 0x07080001
+#define R16L1 0x07080002
+#define R16G1 0x07080003
+#define GEOILWCDT 0x07080004
+#define GEOILW 0x07080005
+#define GEOIRWCDT 0x07080006
+#define GEOIRW 0x07080007
+#define GEOMANLCDT 0x07080008
+#define GEOMANL 0x07080009
+#define GEOMANRCDT 0x0708000A
+#define GEOMANR 0x0708000B
+#define GEOMLWCDT 0x0708000C
+#define GEOMLW 0x0708000D
+#define GEOMRWCDT 0x0708000E
+#define GEOMRW 0x0708000F
+#define GEOOLWCDT 0x07080010
+#define GEOOLWCDR 0x07080011
+#define GEOOLW 0x07080012
+#define GEOORWCDT 0x07080013
+#define GEOORWCDR 0x07080014
+#define GEOORW 0x07080015
+#define MANLCDT 0x07080016
+#define MANL 0x07080017
+#define MANRCDT 0x07080018
+#define MANR 0x07080019
+ // 26 entities in TXTs, 26 in datafiles.
+ // room17
+#define room17_PAL 0x07090000
+#define room17_l0 0x07090001
+#define room17_l1 0x07090002
+#define room17_l2 0x07090003
+#define room17_gd1 0x07090004
+#define room17_gd2 0x07090005
+#define room17_flr 0x07090006
+#define IBACK17 0x07090007
+#define IBACK17PAL 0x07090008
+#define GEOINQ17 0x07090009
+#define GEOINQ17CDT 0x0709000A
+#define SBACK17 0x0709000B
+#define SBACK17PAL 0x0709000C
+#define GEOSUR17 0x0709000D
+#define GEOSUR17CDT 0x0709000E
+#define ASSTAIR2_PAL 0x0709000F
+#define ASSTAIR2 0x07090010
+#define ASSTAIRCDT 0x07090011
+#define ASSTAIR 0x07090012
+#define ASSDORCDT 0x07090013
+#define ASSDOR 0x07090014
+#define ASSDOR2CDT 0x07090015
+#define ASSDOR2 0x07090016
+#define ASSTRWCDT 0x07090017
+#define ASSTRW 0x07090018
+#define ASSWRBCDT 0x07090019
+#define ASSWRB 0x0709001A
+#define ASWLK17CDT 0x0709001B
+#define ASWLK17 0x0709001C
+#define BRFCASECDT 0x0709001D
+#define BRFCASE 0x0709001E
+#define GEOBCBCDR 0x0709001F
+#define GEOBCBCDT 0x07090020
+#define GEOBCB 0x07090021
+#define GEOBED17CDT 0x07090022
+#define GEOBED17 0x07090023
+#define GEOBFCCDR 0x07090024
+#define GEOBFCCDT 0x07090025
+#define GEOBFC 0x07090026
+#define GEODOR17CDT 0x07090027
+#define GEODOR17 0x07090028
+#define GEODOR2CDR 0x07090029
+#define GEODOR2CDT 0x0709002A
+#define GEODOR2 0x0709002B
+#define GEOPANTSCDT 0x0709002C
+#define GEOPANTS 0x0709002D
+#define GEOWIN8CDT 0x0709002E
+#define GEOWIN8 0x0709002F
+#define GEOWIN9CDT 0x07090030
+#define GEOWIN9 0x07090031
+#define GEOWRB1CDR 0x07090032
+#define GEOWRB1CDT 0x07090033
+#define GEOWRB1 0x07090034
+#define GEOWRB2CDT 0x07090035
+#define GEOWRB2 0x07090036
+#define GEOWRB3CDR 0x07090037
+#define GEOWRB3CDT 0x07090038
+#define GEOWRB3 0x07090039
+#define GEOWRB4CDT 0x0709003A
+#define GEOWRB4 0x0709003B
+#define PANTS2CDT 0x0709003C
+#define PANTS2 0x0709003D
+#define PANTWRBCDT 0x0709003E
+#define PANTWRB 0x0709003F
+#define STATDOORCDT 0x07090040
+#define STATDOOR 0x07090041
+#define WRBDOR17CDT 0x07090042
+#define WRBDOR17 0x07090043
+ // 68 entities in TXTs, 68 in datafiles.
+ // room18
+#define R18SPRPAL 0x070A0000
+#define room18_PAL 0x070A0001
+#define room18_l0 0x070A0002
+#define room18_l1 0x070A0003
+#define room18_l2 0x070A0004
+#define room18_gd1 0x070A0005
+#define room18_gd2 0x070A0006
+#define room18_flr 0x070A0007
+#define FAN18CDT 0x070A0008
+#define FAN18 0x070A0009
+#define GENBNDCDT 0x070A000A
+#define GENBND 0x070A000B
+#define GENSTRCDT 0x070A000C
+#define GENSTR 0x070A000D
+#define GENTLK18CDT 0x070A000E
+#define GENTLK18 0x070A000F
+#define GEOLVE18CDT 0x070A0010
+#define GEOLVE18 0x070A0011
+#define MOUBAK18CDT 0x070A0012
+#define MOUBAK18 0x070A0013
+#define MOUBUSYCDT 0x070A0014
+#define MOUBUSY 0x070A0015
+#define MOUTKROSCDT 0x070A0016
+#define MOUTKROS 0x070A0017
+#define MOUTLK18CDT 0x070A0018
+#define MOUTLK18 0x070A0019
+#define MOUWLK18CDT 0x070A001A
+#define MOUWLK18 0x070A001B
+#define ROSBAK18CDT 0x070A001C
+#define ROSBAK18 0x070A001D
+#define ROSBUSYCDT 0x070A001E
+#define ROSBUSY 0x070A001F
+#define ROSSTDCDT 0x070A0020
+#define ROSSTD 0x070A0021
+#define ROSTLK18CDT 0x070A0022
+#define ROSTLK18 0x070A0023
+#define ROSTLKXCDT 0x070A0024
+#define ROSTLKX 0x070A0025
+#define ROSTURNCDR 0x070A0026
+#define ROSTURNCDT 0x070A0027
+#define ROSTURN 0x070A0028
+#define ROSWLK18CDT 0x070A0029
+#define ROSWLK18 0x070A002A
+ // 43 entities in TXTs, 43 in datafiles.
+ // room46
+#define room46_PAL 0x070B0000
+#define room46_l0 0x070B0001
+#define room46_l1 0x070B0002
+#define room46_l2 0x070B0003
+#define room46_gd1 0x070B0004
+#define room46_gd2 0x070B0005
+#define room46_flr 0x070B0006
+#define MANU46CDT 0x070B0007
+#define MANU46 0x070B0008
+ // 9 entities in TXTs, 9 in datafiles.
+// paris_3
+ // sound_fx
+#define FX_MUESEXT 0x08000000
+#define FX_AIRCON28 0x08000001
+#define FX_SARCO28A 0x08000002
+#define FX_SARCO28B 0x08000003
+#define FX_SARCO28C 0x08000004
+#define FX_TOTEM28A 0x08000005
+#define FX_ALARM 0x08000006
+#define FX_CARABINE 0x08000007
+#define FX_DOOR29 0x08000008
+#define FX_FISHFALL 0x08000009
+#define FX_GDROP29 0x0800000A
+#define FX_GUI_HIT 0x0800000B
+#define FX_GUN1 0x0800000C
+#define FX_ROPEDOWN 0x0800000D
+#define FX_SARCO29 0x0800000E
+#define FX_SMASHGLA 0x0800000F
+#define FX_TOTEM29A 0x08000010
+#define FX_TOTEM29B 0x08000011
+#define FX_HOSPEXT 0x08000012
+#define FX_GRAVEL1 0x08000013
+#define FX_GRAVEL2 0x08000014
+#define FX_HOSPNOIS 0x08000015
+#define FX_CUPBOPEN 0x08000016
+#define FX_CUPBCLOS 0x08000017
+#define FX_KIKSHINY 0x08000018
+#define FX_SHINY 0x08000019
+#define FX_SHINYOFF 0x0800001A
+#define FX_SHINYON 0x0800001B
+#define FX_BLOODPRE 0x0800001C
+#define FX_GUN34 0x0800001D
+#define FX_PULSE2 0x0800001E
+#define FX_PULSE3 0x0800001F
+ // 32 entities in TXTs, 32 in datafiles.
+ // benoir
+#define MEGABEN 0x08010000
+#define BEN_WLK 0x08010001
+#define STDTAL1 0x08010002
+#define STDTAL1CDT 0x08010003
+#define STDTAL3 0x08010004
+#define STDTAL3CDT 0x08010005
+#define STDTAL5 0x08010006
+#define STDTAL5CDT 0x08010007
+#define XBENPG3 0x08010008
+#define XBENPG3CDT 0x08010009
+#define XBENPG5 0x0801000A
+#define XBENPG5CDT 0x0801000B
+ // 12 entities in TXTs, 12 in datafiles.
+ // mus
+#define MEGAMUS 0x08020000
+#define MUS_WLK 0x08020001
+#define MUSTLK0 0x08020002
+#define MUSTLK0CDT 0x08020003
+#define MUSTLK1 0x08020004
+#define MUSTLK1CDT 0x08020005
+#define MUSTLK2 0x08020006
+#define MUSTLK2CDT 0x08020007
+#define MUSTLK3 0x08020008
+#define MUSTLK3CDT 0x08020009
+#define MUSTLK4 0x0802000A
+#define MUSTLK4CDT 0x0802000B
+#define MUSTLK5 0x0802000C
+#define MUSTLK5CDT 0x0802000D
+#define MUSTLK6 0x0802000E
+#define MUSTLK6CDT 0x0802000F
+#define MUSTLK7 0x08020010
+#define MUSTLK7CDT 0x08020011
+ // 18 entities in TXTs, 18 in datafiles.
+ // white
+#define MEGA_WHITE 0x08030000
+#define WHTTLK0 0x08030001
+#define WHTTLK0CDT 0x08030002
+#define WHTTLK1 0x08030003
+#define WHTTLK1CDT 0x08030004
+#define WHTTLK2 0x08030005
+#define WHTTLK2CDT 0x08030006
+#define WHTTLK3 0x08030007
+#define WHTTLK3CDT 0x08030008
+#define WHTTLK4 0x08030009
+#define WHTTLK4CDT 0x0803000A
+#define WHTTLK5 0x0803000B
+#define WHTTLK5CDT 0x0803000C
+#define WHTTLK6 0x0803000D
+#define WHTTLK6CDT 0x0803000E
+#define WHTTLK7 0x0803000F
+#define WHTTLK7CDT 0x08030010
+#define WHTSHRUG 0x08030011
+#define WHTSHRUGCDT 0x08030012
+#define XGEOPG3 0x08030013
+#define XGEOPG3CDT 0x08030014
+#define XGEOPG5 0x08030015
+#define XGEOPG5CDT 0x08030016
+ // 23 entities in TXTs, 23 in datafiles.
+ // room27
+#define PARIS3_PAL 0x08040000
+#define room27_PAL 0x08040001
+#define R27L0 0x08040002
+#define R27L1 0x08040003
+#define R27L2 0x08040004
+#define R27G1 0x08040005
+#define R27G2 0x08040006
+#define room27_flr 0x08040007
+#define GEOWIN27CDR 0x08040008
+#define GEOWIN27CDT 0x08040009
+#define GEOWIN27 0x0804000A
+ // 11 entities in TXTs, 11 in datafiles.
+ // room28
+#define R28SPRPAL 0x08050000
+#define R28PAL 0x08050001
+#define R28L0 0x08050002
+#define R28L1 0x08050003
+#define R28L2 0x08050004
+#define R28G1 0x08050005
+#define R28G2 0x08050006
+#define room28_flr 0x08050007
+#define GEOALMCDT 0x08050008
+#define GEOALM 0x08050009
+#define GEOSARCDT 0x0805000A
+#define GEOSAR 0x0805000B
+#define GEOSAR1CDT 0x0805000C
+#define GEOSAR1 0x0805000D
+#define GEOSAR2CDR 0x0805000E
+#define GEOSAR2CDT 0x0805000F
+#define GEOSAR2 0x08050010
+#define GEOSHK28CDT 0x08050011
+#define GEOSHK28 0x08050012
+#define GEOTOTCDT 0x08050013
+#define GEOTOT 0x08050014
+#define GEOWINCDT 0x08050015
+#define GEOWIN 0x08050016
+#define GUAWINCDT 0x08050017
+#define GUAWIN 0x08050018
+#define LOBEXITCDT 0x08050019
+#define LOBEXIT 0x0805001A
+#define LOBMANCDT 0x0805001B
+#define LOBMAN 0x0805001C
+#define LOBSTUCDT 0x0805001D
+#define LOBSTU 0x0805001E
+#define LOBTLKCDT 0x0805001F
+#define LOBTLK 0x08050020
+#define LOBTURN1CDT 0x08050021
+#define LOBTURN1 0x08050022
+#define LOBTURN2CDT 0x08050023
+#define LOBTURN2 0x08050024
+#define MUSOPNCDT 0x08050025
+#define MUSOPN 0x08050026
+#define SARDOR28CDT 0x08050027
+#define SARDOR28 0x08050028
+#define TOTEM28CDT 0x08050029
+#define TOTEM28 0x0805002A
+#define TRIPOD28CDT 0x0805002B
+#define TRIPOD28 0x0805002C
+#define WINDO28CDR 0x0805002D
+#define WINDO28CDT 0x0805002E
+#define WINDO28 0x0805002F
+#define WINROD28CDT 0x08050030
+#define WINROD28 0x08050031
+ // 50 entities in TXTs, 50 in datafiles.
+ // room29
+#define R29SPRPAL 0x08060000
+#define BBACK29SPRPAL 0x08060001
+#define R29PAL 0x08060002
+#define R29L0 0x08060003
+#define R29L1 0x08060004
+#define R29G1 0x08060005
+#define room29_flr 0x08060006
+#define BBACK29 0x08060007
+#define BBACK29PAL 0x08060008
+#define GEOSUR29CDT 0x08060009
+#define GEOSUR29 0x0806000A
+#define CASECDT 0x0806000B
+#define CASE 0x0806000C
+#define DOOR29CDT 0x0806000D
+#define DOOR29 0x0806000E
+#define FISH29CDT 0x0806000F
+#define FISH29 0x08060010
+#define FLAPENTCDT 0x08060011
+#define FLAPENT 0x08060012
+#define FLAPTLK1CDT 0x08060013
+#define FLAPTLK1 0x08060014
+#define FLAPTLK3CDT 0x08060015
+#define FLAPTLK3 0x08060016
+#define FLAPTOR1CDR 0x08060017
+#define FLAPTOR1CDT 0x08060018
+#define FLAPTOR1 0x08060019
+#define FLAPTOR4CDT 0x0806001A
+#define FLAPTOR4 0x0806001B
+#define FLAPWLKCDT 0x0806001C
+#define FLAPWLK 0x0806001D
+#define GEODEDCDT 0x0806001E
+#define GEODED 0x0806001F
+#define GEOFISHCDT 0x08060020
+#define GEOFISH 0x08060021
+#define GEOFWDCDT 0x08060022
+#define GEOFWD 0x08060023
+#define GEOPEEKCDT 0x08060024
+#define GEOPEEK 0x08060025
+#define GEOSAR6CDT 0x08060026
+#define GEOSAR6 0x08060027
+#define GEOTOT29CDT 0x08060028
+#define GEOTOT29 0x08060029
+#define GEOTOTBCDT 0x0806002A
+#define GEOTOTB 0x0806002B
+#define GEOTPTOCDT 0x0806002C
+#define GEOTPTO 0x0806002D
+#define GUIENTCDT 0x0806002E
+#define GUIENT 0x0806002F
+#define GUIGUNCDT 0x08060030
+#define GUIGUN 0x08060031
+#define GUIKNECDT 0x08060032
+#define GUIKNE 0x08060033
+#define GUIKNE1CDT 0x08060034
+#define GUIKNE1 0x08060035
+#define GUITLK1CDT 0x08060036
+#define GUITLK1 0x08060037
+#define GUITLK3CDT 0x08060038
+#define GUITLK3 0x08060039
+#define GUITLK4CDT 0x0806003A
+#define GUITLK4 0x0806003B
+#define GUIWLKCDT 0x0806003C
+#define GUIWLK 0x0806003D
+#define NICPUS1CDT 0x0806003E
+#define NICPUS1 0x0806003F
+#define ROPE29CDT 0x08060040
+#define ROPE29 0x08060041
+#define SARDOORCDT 0x08060042
+#define SARDOOR 0x08060043
+#define TOR1CDT 0x08060044
+#define TOR1 0x08060045
+#define TOR3CDR 0x08060046
+#define TOR3CDT 0x08060047
+#define TOR3 0x08060048
+#define TOR4CDT 0x08060049
+#define TOR4 0x0806004A
+#define TOR6CDT 0x0806004B
+#define TOR6 0x0806004C
+#define TOR7CDT 0x0806004D
+#define TOR7 0x0806004E
+#define TOTFALLCDT 0x0806004F
+#define TOTFALL 0x08060050
+ // 81 entities in TXTs, 81 in datafiles.
+ // room31
+#define room31_PAL 0x08070000
+#define room31_l0 0x08070001
+#define room31_flr 0x08070002
+#define GEOAMBCDT 0x08070003
+#define GEOAMB 0x08070004
+#define GEODOR31CDT 0x08070005
+#define GEODOR31 0x08070006
+ // 7 entities in TXTs, 7 in datafiles.
+ // room32
+#define room32_PAL 0x08080000
+#define room32_l0 0x08080001
+#define room32_l1 0x08080002
+#define room32_l2 0x08080003
+#define room32_gd1 0x08080004
+#define room32_gd2 0x08080005
+#define room32_flr 0x08080006
+#define CONSTPCDT 0x08080007
+#define CONSTP 0x08080008
+#define CONTLKCDT 0x08080009
+#define CONTLK 0x0808000A
+#define CONTLK2CDT 0x0808000B
+#define CONTLK2 0x0808000C
+#define CONWLKCDT 0x0808000D
+#define CONWLK 0x0808000E
+#define RECCOMCDT 0x0808000F
+#define RECCOM 0x08080010
+#define RECKEYCDT 0x08080011
+#define RECKEY 0x08080012
+#define RECTLKCDT 0x08080013
+#define RECTLK 0x08080014
+#define RECTLK2CDT 0x08080015
+#define RECTLK2 0x08080016
+#define RECTRNCDT 0x08080017
+#define RECTRN 0x08080018
+ // 25 entities in TXTs, 25 in datafiles.
+ // room33
+#define room33_PAL 0x08090000
+#define room33_l0 0x08090001
+#define room33_l1 0x08090002
+#define room33_l2 0x08090003
+#define room33_gd1 0x08090004
+#define room33_gd2 0x08090005
+#define room33_flr 0x08090006
+#define DOMDRNCDT 0x08090007
+#define DOMDRN 0x08090008
+#define DOMDUHCDT 0x08090009
+#define DOMDUH 0x0809000A
+#define DOMKIKCDT 0x0809000B
+#define DOMKIK 0x0809000C
+#define DOMPLGCDT 0x0809000D
+#define DOMPLG 0x0809000E
+#define DOMTLKCDT 0x0809000F
+#define DOMTLK 0x08090010
+#define DOMVACCDT 0x08090011
+#define DOMVAC 0x08090012
+#define DOMWLKCDT 0x08090013
+#define DOMWLK 0x08090014
+#define DOMWLK2CDT 0x08090015
+#define DOMWLK2 0x08090016
+#define DOMWLK3CDT 0x08090017
+#define DOMWLK3 0x08090018
+#define DOMWLK4CDT 0x08090019
+#define DOMWLK4 0x0809001A
+#define GEOCOTCDT 0x0809001B
+#define GEOCOT 0x0809001C
+#define GEOPLG33CDT 0x0809001D
+#define GEOPLG33 0x0809001E
+#define GEOWATCDT 0x0809001F
+#define GEOWAT 0x08090020
+#define GEOWWATCDT 0x08090021
+#define GEOWWAT 0x08090022
+#define LEAD1CDT 0x08090023
+#define LEAD1 0x08090024
+#define LEAD2CDT 0x08090025
+#define LEAD2 0x08090026
+#define SHINY33CDT 0x08090027
+#define SHINY33 0x08090028
+ // 41 entities in TXTs, 41 in datafiles.
+ // room34
+#define room34_PAL 0x080A0000
+#define room34_l0 0x080A0001
+#define room34_l1 0x080A0002
+#define room34_l2 0x080A0003
+#define room34_l3 0x080A0004
+#define room34_gd1 0x080A0005
+#define room34_gd2 0x080A0006
+#define room34_gd3 0x080A0007
+#define room34_flr 0x080A0008
+#define R34PLX 0x080A0009
+#define BENBP1CDT 0x080A000A
+#define BENBP1 0x080A000B
+#define BENBP2CDT 0x080A000C
+#define BENBP2 0x080A000D
+#define DOOR34CDR 0x080A000E
+#define DOOR34CDT 0x080A000F
+#define DOOR34 0x080A0010
+#define GENDTLKCDT 0x080A0011
+#define GENDTLK 0x080A0012
+#define GENENTCDT 0x080A0013
+#define GENENT 0x080A0014
+#define GENSHOTCDT 0x080A0015
+#define GENSHOT 0x080A0016
+#define GENSTLKCDT 0x080A0017
+#define GENSTLK 0x080A0018
+#define GENSUPCDT 0x080A0019
+#define GENSUP 0x080A001A
+#define GENTRNCDT 0x080A001B
+#define GENTRN 0x080A001C
+#define GEOBAKCDT 0x080A001D
+#define GEOBAK 0x080A001E
+#define GEOBP2CDT 0x080A001F
+#define GEOBP2 0x080A0020
+#define GEOCH1CDR 0x080A0021
+#define GEOCH1CDT 0x080A0022
+#define GEOCH1 0x080A0023
+#define GEOCH2CDR 0x080A0024
+#define GEOCH2CDT 0x080A0025
+#define GEOCH2 0x080A0026
+#define GEOCH3CDR 0x080A0027
+#define GEOCH3CDT 0x080A0028
+#define GEOCH3 0x080A0029
+#define GEODOR34CDT 0x080A002A
+#define GEODOR34 0x080A002B
+#define GEOENT34CDT 0x080A002C
+#define GEOENT34 0x080A002D
+#define GEONURBPCDT 0x080A002E
+#define GEONURBP 0x080A002F
+#define GEOTAKCDT 0x080A0030
+#define GEOTAK 0x080A0031
+#define GEOTRYDCDT 0x080A0032
+#define GEOTRYD 0x080A0033
+#define GEOTRYTKCDT 0x080A0034
+#define GEOTRYTK 0x080A0035
+#define HATGIVCDT 0x080A0036
+#define HATGIV 0x080A0037
+#define HATSTPCDT 0x080A0038
+#define HATSTP 0x080A0039
+#define HATTLKCDT 0x080A003A
+#define HATTLK 0x080A003B
+#define HATWLKCDT 0x080A003C
+#define HATWLK 0x080A003D
+#define HATWLK2CDT 0x080A003E
+#define HATWLK2 0x080A003F
+#define MONITOR 0x080A0040
+#define MONITOR_PAL 0x080A0041
+#define PULSE1CDT 0x080A0042
+#define PULSE1 0x080A0043
+#define PULSE2CDT 0x080A0044
+#define PULSE2 0x080A0045
+#define PULSE3CDT 0x080A0046
+#define PULSE3 0x080A0047
+#define RENTLKCDT 0x080A0048
+#define RENTLK 0x080A0049
+#define SMARMCDR 0x080A004A
+#define SMARMCDT 0x080A004B
+#define SMARM 0x080A004C
+#define SMSTPCDR 0x080A004D
+#define SMSTPCDT 0x080A004E
+#define SMSTP 0x080A004F
+#define SMTALKCDT 0x080A0050
+#define SMTALK 0x080A0051
+#define SMTALK2CDT 0x080A0052
+#define SMTALK2 0x080A0053
+#define STUDENTCDT 0x080A0054
+#define STUDENT 0x080A0055
+#define STUDGIVCDT 0x080A0056
+#define STUDGIV 0x080A0057
+#define STUDMOVCDT 0x080A0058
+#define STUDMOV 0x080A0059
+ // 90 entities in TXTs, 90 in datafiles.
+ // room35
+#define room35_PAL 0x080B0000
+#define room35_l0 0x080B0001
+#define room35_l1 0x080B0002
+#define room35_gd1 0x080B0003
+#define room35_flr 0x080B0004
+#define ALSHOCKCDT 0x080B0005
+#define ALSHOCK 0x080B0006
+#define CURFLATCDT 0x080B0007
+#define CURFLAT 0x080B0008
+#define EKLBED35CDT 0x080B0009
+#define EKLBED35 0x080B000A
+#define EKLTLK35CDT 0x080B000B
+#define EKLTLK35 0x080B000C
+#define EKLWLK35CDT 0x080B000D
+#define EKLWLK35 0x080B000E
+#define GEORCT35CDT 0x080B000F
+#define GEORCT35 0x080B0010
+#define GEOSIT35CDR 0x080B0011
+#define GEOSIT35CDT 0x080B0012
+#define GEOSIT35 0x080B0013
+#define GEOTLKCDT 0x080B0014
+#define GEOTLK 0x080B0015
+#define GEOTLK35CDT 0x080B0016
+#define GEOTLK35 0x080B0017
+#define GEOTRN35CDT 0x080B0018
+#define GEOTRN35 0x080B0019
+#define JAQTLK1CDT 0x080B001A
+#define JAQTLK1 0x080B001B
+#define JAQTLK2CDT 0x080B001C
+#define JAQTLK2 0x080B001D
+ // 30 entities in TXTs, 30 in datafiles.
+// paris_4
+ // sound_fx
+#define FX_COVDWN 0x09000000
+#define FX_KEYIN 0x09000001
+#define FX_MANOP36 0x09000002
+#define FX_MONTAMB 0x09000003
+#define FX_OOH 0x09000004
+#define FX_PULLUP36 0x09000005
+#define FX_REPLCE36 0x09000006
+#define FX_AMBIEN37 0x09000007
+#define FX_CHAIN37 0x09000008
+#define FX_CHAIN37B 0x09000009
+#define FX_DOOR37 0x0900000A
+#define FX_HOLE37 0x0900000B
+#define FX_KNOCK37 0x0900000C
+#define FX_KNOCK37B 0x0900000D
+#define FX_WINCH37 0x0900000E
+#define FX_AIRCON41 0x0900000F
+#define FX_FONEDN41 0x09000010
+#define FX_FONEUP41 0x09000011
+#define FX_PHONCALL 0x09000012
+#define FX_THERMO1 0x09000013
+#define FX_TAPDRIP 0x09000014
+#define FX_DRIER1 0x09000015
+#define FX_CHURCHFX 0x09000016
+ // 23 entities in TXTs, 23 in datafiles.
+ // room36
+#define R36SPRPAL 0x09010000
+#define R36L0 0x09010001
+#define R36L1 0x09010002
+#define R36G1 0x09010003
+#define room36_PAL 0x09010004
+#define room36_flr 0x09010005
+#define R36PLX 0x09010006
+#define BAL36CDT 0x09010007
+#define BAL36 0x09010008
+#define CRO36APPCDT 0x09010009
+#define CRO36APP 0x0901000A
+#define CRO36GEOCDT 0x0901000B
+#define CRO36GEO 0x0901000C
+#define CRO36IDLCDT 0x0901000D
+#define CRO36IDL 0x0901000E
+#define CRO36JUGCDT 0x0901000F
+#define CRO36JUG 0x09010010
+#define CRO36UNICDT 0x09010011
+#define CRO36UNI 0x09010012
+#define GEN36DRICDT 0x09010013
+#define GEN36DRI 0x09010014
+#define GEN36FEHCDT 0x09010015
+#define GEN36FEH 0x09010016
+#define GEN36HURCDT 0x09010017
+#define GEN36HUR 0x09010018
+#define GEN36LEACDT 0x09010019
+#define GEN36LEA 0x0901001A
+#define GEN36POICDR 0x0901001B
+#define GEN36POICDT 0x0901001C
+#define GEN36POI 0x0901001D
+#define GEN36SPECDT 0x0901001E
+#define GEN36SPE 0x0901001F
+#define GEN36TALCDT 0x09010020
+#define GEN36TAL 0x09010021
+#define GEO36CLOCDT 0x09010022
+#define GEO36CLO 0x09010023
+#define GEO36ENTCDT 0x09010024
+#define GEO36ENT 0x09010025
+#define GEO36EXTCDT 0x09010026
+#define GEO36EXT 0x09010027
+#define GEO36JUGCDT 0x09010028
+#define GEO36JUG 0x09010029
+#define GEO36KNECDR 0x0901002A
+#define GEO36KNECDT 0x0901002B
+#define GEO36KNE 0x0901002C
+#define GEO36LUKCDR 0x0901002D
+#define GEO36LUKCDT 0x0901002E
+#define GEO36LUK 0x0901002F
+#define GEO36NOSCDT 0x09010030
+#define GEO36NOS 0x09010031
+#define GEO36OPECDT 0x09010032
+#define GEO36OPE 0x09010033
+#define GEO36POPCDT 0x09010034
+#define GEO36POP 0x09010035
+#define GEO36SHOCDR 0x09010036
+#define GEO36SHOCDT 0x09010037
+#define GEO36SHO 0x09010038
+#define GEO36SNTCDT 0x09010039
+#define GEO36SNT 0x0901003A
+#define GEO36STDCDT 0x0901003B
+#define GEO36STD 0x0901003C
+#define GEO36STUCDT 0x0901003D
+#define GEO36STU 0x0901003E
+#define GEO36TAKCDT 0x0901003F
+#define GEO36TAK 0x09010040
+#define HAT36CDT 0x09010041
+#define HAT36 0x09010042
+#define JUG36FINCDT 0x09010043
+#define JUG36FIN 0x09010044
+#define JUG36FURCDT 0x09010045
+#define JUG36FUR 0x09010046
+#define JUG36GIVCDT 0x09010047
+#define JUG36GIV 0x09010048
+#define JUG36GOCDT 0x09010049
+#define JUG36GO 0x0901004A
+#define JUG36JUGCDT 0x0901004B
+#define JUG36JUG 0x0901004C
+#define JUG36LAFCDT 0x0901004D
+#define JUG36LAF 0x0901004E
+#define JUG36STACDT 0x0901004F
+#define JUG36STA 0x09010050
+#define JUG36TAKCDT 0x09010051
+#define JUG36TAK 0x09010052
+#define JUG36TALCDT 0x09010053
+#define JUG36TAL 0x09010054
+#define MANCOV36CDT 0x09010055
+#define MANCOV36 0x09010056
+#define MANOFF36CDT 0x09010057
+#define MANOFF36 0x09010058
+#define VIN36CDT 0x09010059
+#define VIN36 0x0901005A
+ // 91 entities in TXTs, 91 in datafiles.
+ // room37
+#define room37_PAL 0x09020000
+#define R37L0 0x09020001
+#define R37L1 0x09020002
+#define R37G1 0x09020003
+#define room37_flr 0x09020004
+#define DOR37COLCDT 0x09020005
+#define DOR37COL 0x09020006
+#define GEO37ASCCDT 0x09020007
+#define GEO37ASC 0x09020008
+#define GEO37COGCDT 0x09020009
+#define GEO37COG 0x0902000A
+#define GEO37DESCDT 0x0902000B
+#define GEO37DES 0x0902000C
+#define GEO37HUKCDR 0x0902000D
+#define GEO37HUKCDT 0x0902000E
+#define GEO37HUK 0x0902000F
+#define GEO37INBCDT 0x09020010
+#define GEO37INB 0x09020011
+#define GEO37LEVCDT 0x09020012
+#define GEO37LEV 0x09020013
+#define GEO37OUTCDT 0x09020014
+#define GEO37OUT 0x09020015
+#define GEO37RUNCDT 0x09020016
+#define GEO37RUN 0x09020017
+#define GEO37TA1CDT 0x09020018
+#define GEO37TA1 0x09020019
+#define GEO37TA2CDT 0x0902001A
+#define GEO37TA2 0x0902001B
+#define GEO37TA3CDT 0x0902001C
+#define GEO37TA3 0x0902001D
+#define GEO37TA4CDT 0x0902001E
+#define GEO37TA4 0x0902001F
+#define GEO37TU1CDR 0x09020020
+#define GEO37TU1CDT 0x09020021
+#define GEO37TU1 0x09020022
+#define GEO37TU2CDT 0x09020023
+#define GEO37TU2 0x09020024
+#define GEO37WLCDR 0x09020025
+#define GEO37WLCDT 0x09020026
+#define GEO37WL 0x09020027
+#define HOO37LBOCDR 0x09020028
+#define HOO37LBOCDT 0x09020029
+#define HOO37LBO 0x0902002A
+#define HOO37PULCDT 0x0902002B
+#define HOO37PUL 0x0902002C
+#define ROCKS1CDT 0x0902002D
+#define ROCKS1 0x0902002E
+#define WAL37BRECDT 0x0902002F
+#define WAL37BRE 0x09020030
+#define WAL37SLICDT 0x09020031
+#define WAL37SLI 0x09020032
+#define WATER37CDT 0x09020033
+#define WATER37 0x09020034
+#define WATER37ACDT 0x09020035
+#define WATER37A 0x09020036
+#define WHEEL37CDT 0x09020037
+#define WHEEL37 0x09020038
+ // 57 entities in TXTs, 57 in datafiles.
+ // room38
+#define R38SPRPAL 0x09030000
+#define room38_PAL 0x09030001
+#define R38L0 0x09030002
+#define R38L1 0x09030003
+#define R38G1 0x09030004
+#define room38_flr 0x09030005
+#define BBACK38 0x09030006
+#define BBACK38PAL 0x09030007
+#define GEOINQ38CDT 0x09030008
+#define GEOINQ38 0x09030009
+#define GEO38AS1CDT 0x0903000A
+#define GEO38AS1 0x0903000B
+#define GEO38AS2CDT 0x0903000C
+#define GEO38AS2 0x0903000D
+#define GEO38DE1CDT 0x0903000E
+#define GEO38DE1 0x0903000F
+#define GEO38DE2CDT 0x09030010
+#define GEO38DE2 0x09030011
+#define GEO38LUKCDR 0x09030012
+#define GEO38LUKCDT 0x09030013
+#define GEO38LUK 0x09030014
+ // 21 entities in TXTs, 21 in datafiles.
+ // room39
+#define R39SPRPAL 0x09040000
+#define R39L0 0x09040001
+#define R39L1 0x09040002
+#define R39G1 0x09040003
+#define room39_PAL 0x09040004
+#define room39_flr 0x09040005
+#define R39PLX 0x09040006
+#define BOA39GOACDT 0x09040007
+#define BOA39GOA 0x09040008
+#define BOA39SPRCDT 0x09040009
+#define BOA39SPR 0x0904000A
+#define CIV391T2CDR 0x0904000B
+#define CIV391T2CDT 0x0904000C
+#define CIV391T2 0x0904000D
+#define CIV391T3CDR 0x0904000E
+#define CIV391T3CDT 0x0904000F
+#define CIV391T3 0x09040010
+#define CIV392T3CDR 0x09040011
+#define CIV392T3CDT 0x09040012
+#define CIV392T3 0x09040013
+#define CIV39T1CDT 0x09040014
+#define CIV39T1 0x09040015
+#define CIV39T2CDT 0x09040016
+#define CIV39T2 0x09040017
+#define CIV39T3CDT 0x09040018
+#define CIV39T3 0x09040019
+#define CIVLIST1CDT 0x0904001A
+#define CIVLIST1 0x0904001B
+#define CIVLIST2CDT 0x0904001C
+#define CIVLIST2 0x0904001D
+#define CIVLIST3CDT 0x0904001E
+#define CIVLIST3 0x0904001F
+#define COL391T2CDR 0x09040020
+#define COL391T2CDT 0x09040021
+#define COL391T2 0x09040022
+#define COL391T3CDR 0x09040023
+#define COL391T3CDT 0x09040024
+#define COL391T3 0x09040025
+#define COL392T3CDR 0x09040026
+#define COL392T3CDT 0x09040027
+#define COL392T3 0x09040028
+#define COL39T1CDT 0x09040029
+#define COL39T1 0x0904002A
+#define COL39T2CDT 0x0904002B
+#define COL39T2 0x0904002C
+#define COL39T3CDT 0x0904002D
+#define COL39T3 0x0904002E
+#define COLLIST2CDT 0x0904002F
+#define COLLIST2 0x09040030
+#define COLLIST3CDT 0x09040031
+#define COLLIST3 0x09040032
+#define CON39TALCDT 0x09040033
+#define CON39TAL 0x09040034
+#define EKL391T2CDR 0x09040035
+#define EKL391T2CDT 0x09040036
+#define EKL391T2 0x09040037
+#define EKL391T3CDR 0x09040038
+#define EKL391T3CDT 0x09040039
+#define EKL391T3 0x0904003A
+#define EKL392T3CDR 0x0904003B
+#define EKL392T3CDT 0x0904003C
+#define EKL392T3 0x0904003D
+#define EKL39T1CDT 0x0904003E
+#define EKL39T1 0x0904003F
+#define EKL39T2CDT 0x09040040
+#define EKL39T2 0x09040041
+#define EKL39T3CDT 0x09040042
+#define EKL39T3 0x09040043
+#define EKLLIST1CDT 0x09040044
+#define EKLLIST1 0x09040045
+#define EKLLIST2CDT 0x09040046
+#define EKLLIST2 0x09040047
+#define EKLLIST3CDT 0x09040048
+#define EKLLIST3 0x09040049
+#define EXE391T2CDR 0x0904004A
+#define EXE391T2CDT 0x0904004B
+#define EXE391T2 0x0904004C
+#define EXE391T3CDR 0x0904004D
+#define EXE391T3CDT 0x0904004E
+#define EXE391T3 0x0904004F
+#define EXE392T3CDR 0x09040050
+#define EXE392T3CDT 0x09040051
+#define EXE392T3 0x09040052
+#define EXE39T1CDT 0x09040053
+#define EXE39T1 0x09040054
+#define EXE39T2CDT 0x09040055
+#define EXE39T2 0x09040056
+#define EXE39T3CDT 0x09040057
+#define EXE39T3 0x09040058
+#define GEO39ENTCDT 0x09040059
+#define GEO39ENT 0x0904005A
+#define GEO39EXTCDT 0x0904005B
+#define GEO39EXT 0x0904005C
+#define GEO39GEMCDR 0x0904005D
+#define GEO39GEMCDT 0x0904005E
+#define GEO39GEM 0x0904005F
+#define GEO39TRICDR 0x09040060
+#define GEO39TRICDT 0x09040061
+#define GEO39TRI 0x09040062
+#define LAT391T2CDR 0x09040063
+#define LAT391T2CDT 0x09040064
+#define LAT391T2 0x09040065
+#define LAT391T3CDR 0x09040066
+#define LAT391T3CDT 0x09040067
+#define LAT391T3 0x09040068
+#define LAT392T3CDR 0x09040069
+#define LAT392T3CDT 0x0904006A
+#define LAT392T3 0x0904006B
+#define LAT39T1CDT 0x0904006C
+#define LAT39T1 0x0904006D
+#define LAT39T2CDT 0x0904006E
+#define LAT39T2 0x0904006F
+#define LAT39T3CDT 0x09040070
+#define LAT39T3 0x09040071
+#define LATLIST1CDT 0x09040072
+#define LATLIST1 0x09040073
+#define LATLIST2CDT 0x09040074
+#define LATLIST2 0x09040075
+#define LATLIST3CDT 0x09040076
+#define LATLIST3 0x09040077
+#define MAS391T2CDR 0x09040078
+#define MAS391T2CDT 0x09040079
+#define MAS391T2 0x0904007A
+#define MAS391T3CDR 0x0904007B
+#define MAS391T3CDT 0x0904007C
+#define MAS391T3 0x0904007D
+#define MAS392T3CDR 0x0904007E
+#define MAS392T3CDT 0x0904007F
+#define MAS392T3 0x09040080
+#define MAS39T1CDT 0x09040081
+#define MAS39T1 0x09040082
+#define MAS39T2CDT 0x09040083
+#define MAS39T2 0x09040084
+#define MAS39T3CDT 0x09040085
+#define MAS39T3 0x09040086
+#define MASLIST1CDT 0x09040087
+#define MASLIST1 0x09040088
+#define MASLIST2CDT 0x09040089
+#define MASLIST2 0x0904008A
+#define MASLIST3CDT 0x0904008B
+#define MASLIST3 0x0904008C
+#define RAYS39CDT 0x0904008D
+#define RAYS39 0x0904008E
+#define TRI39ALOCDT 0x0904008F
+#define TRI39ALO 0x09040090
+#define TRI39GEMCDT 0x09040091
+#define TRI39GEM 0x09040092
+ // 147 entities in TXTs, 147 in datafiles.
+ // room40
+#define R40L0 0x09050000
+#define room40_PAL 0x09050001
+#define room40_flr 0x09050002
+#define GEO40ASCCDT 0x09050003
+#define GEO40ASC 0x09050004
+#define GEO40DESCDT 0x09050005
+#define GEO40DES 0x09050006
+#define GEO40DIPCDT 0x09050007
+#define GEO40DIP 0x09050008
+#define GUA40ENTCDT 0x09050009
+#define GUA40ENT 0x0905000A
+#define GUA40STACDT 0x0905000B
+#define GUA40STA 0x0905000C
+#define GUA40TALCDT 0x0905000D
+#define GUA40TAL 0x0905000E
+#define PAI40FAGCDT 0x0905000F
+#define PAI40FAG 0x09050010
+#define PAI40IDLCDT 0x09050011
+#define PAI40IDL 0x09050012
+#define PAI40LEACDT 0x09050013
+#define PAI40LEA 0x09050014
+#define PAI40STACDR 0x09050015
+#define PAI40STACDT 0x09050016
+#define PAI40STA 0x09050017
+#define PAI40TALCDT 0x09050018
+#define PAI40TAL 0x09050019
+ // 26 entities in TXTs, 26 in datafiles.
+ // room41
+#define R41L0 0x09060000
+#define R41L1 0x09060001
+#define R41G1 0x09060002
+#define room41_PAL 0x09060003
+#define room41_flr 0x09060004
+#define GEO41ENTCDT 0x09060005
+#define GEO41ENT 0x09060006
+#define GEO41OP2CDT 0x09060007
+#define GEO41OP2 0x09060008
+#define GEO41OPECDT 0x09060009
+#define GEO41OPE 0x0906000A
+#define GEO41THECDR 0x0906000B
+#define GEO41THECDT 0x0906000C
+#define GEO41THE 0x0906000D
+#define GLO41IDLCDT 0x0906000E
+#define GLO41IDL 0x0906000F
+#define GLO41KEYCDR 0x09060010
+#define GLO41KEYCDT 0x09060011
+#define GLO41KEY 0x09060012
+#define GLO41TALCDT 0x09060013
+#define GLO41TAL 0x09060014
+#define GUA41ANSCDT 0x09060015
+#define GUA41ANS 0x09060016
+#define GUA41GLOCDT 0x09060017
+#define GUA41GLO 0x09060018
+#define GUA41IDLCDT 0x09060019
+#define GUA41IDL 0x0906001A
+#define GUA41KEYCDR 0x0906001B
+#define GUA41KEYCDT 0x0906001C
+#define GUA41KEY 0x0906001D
+#define GUA41PHOCDT 0x0906001E
+#define GUA41PHO 0x0906001F
+#define GUA41TALCDT 0x09060020
+#define GUA41TAL 0x09060021
+#define PAI41HANCDT 0x09060022
+#define PAI41HAN 0x09060023
+#define PAI41LEACDT 0x09060024
+#define PAI41LEA 0x09060025
+#define PAI41TALCDT 0x09060026
+#define PAI41TAL 0x09060027
+#define PHONE41CDT 0x09060028
+#define PHONE41 0x09060029
+ // 42 entities in TXTs, 42 in datafiles.
+ // room42
+#define room42_PAL 0x09070000
+#define R42L0 0x09070001
+#define R42L1 0x09070002
+#define R42L2 0x09070003
+#define R42G1 0x09070004
+#define R42G2 0x09070005
+#define room42_flr 0x09070006
+#define CHALICE42 0x09070007
+#define CHALICE42_PAL 0x09070008
+#define GEO42CHACDT 0x09070009
+#define GEO42CHA 0x0907000A
+#define GEO42DESCDR 0x0907000B
+#define GEO42DESCDT 0x0907000C
+#define GEO42DES 0x0907000D
+ // 14 entities in TXTs, 14 in datafiles.
+ // room43
+#define room43_PAL 0x09080000
+#define R43L0 0x09080001
+#define R43L1 0x09080002
+#define R43G1 0x09080003
+#define room43_flr 0x09080004
+#define GEO43DR2CDT 0x09080005
+#define GEO43DR2 0x09080006
+#define GEO43DRYCDT 0x09080007
+#define GEO43DRY 0x09080008
+#define GEO43HAN 0x09080009
+#define GEO43HANCDT 0x0908000A
+#define GEO43KEYCDT 0x0908000B
+#define GEO43KEY 0x0908000C
+#define GEO43PLACDT 0x0908000D
+#define GEO43PLA 0x0908000E
+#define GEO43PRECDT 0x0908000F
+#define GEO43PRE 0x09080010
+#define GEO43SOACDT 0x09080011
+#define GEO43SOA 0x09080012
+#define GEO43SWPCDT 0x09080013
+#define GEO43SWP 0x09080014
+#define GEO43WATCDT 0x09080015
+#define GEO43WAT 0x09080016
+#define SOAP43CDT 0x09080017
+#define SOAP43 0x09080018
+#define WATER43CDT 0x09080019
+#define WATER43 0x0908001A
+ // 27 entities in TXTs, 27 in datafiles.
+ // room48
+#define R48SPRPAL 0x09090000
+#define R48L0 0x09090001
+#define R48L1 0x09090002
+#define R48L2 0x09090003
+#define R48G1 0x09090004
+#define R48G2 0x09090005
+#define R48PAL 0x09090006
+#define room48_flr 0x09090007
+#define R48PLX 0x09090008
+#define GEO48BENCDR 0x09090009
+#define GEO48BENCDT 0x0909000A
+#define GEO48BEN 0x0909000B
+#define GEO48GIVCDR 0x0909000C
+#define GEO48GIVCDT 0x0909000D
+#define GEO48GIV 0x0909000E
+#define GEO48LENCDT 0x0909000F
+#define GEO48LEN 0x09090010
+#define PRI48CANCDR 0x09090011
+#define PRI48CANCDT 0x09090012
+#define PRI48CAN 0x09090013
+#define PRI48IDLCDT 0x09090014
+#define PRI48IDL 0x09090015
+#define PRI48PO1CDT 0x09090016
+#define PRI48PO1 0x09090017
+#define PRI48PO2CDT 0x09090018
+#define PRI48PO2 0x09090019
+#define PRI48RETCDT 0x0909001A
+#define PRI48RET 0x0909001B
+#define PRI48TAKCDT 0x0909001C
+#define PRI48TAK 0x0909001D
+#define PRI48TALCDT 0x0909001E
+#define PRI48TAL 0x0909001F
+#define PRI48TURCDR 0x09090020
+#define PRI48TURCDT 0x09090021
+#define PRI48TUR 0x09090022
+#define WINDOW1 0x09090023
+#define WINDOW1_PAL 0x09090024
+#define WINDOW2 0x09090025
+#define WINDOW2_PAL 0x09090026
+ // 39 entities in TXTs, 39 in datafiles.
+// ireland
+ // sound_fx
+#define FX_EIRBIRD3 0x0A000000
+#define FX_SHOCK2 0x0A000001
+#define FX_EIRBIRD1 0x0A000002
+#define FX_EIRBIRD2 0x0A000003
+#define FX_SWITCH19 0x0A000004
+#define FX_TRAPOPEN 0x0A000005
+#define FX_VIOLIN19 0x0A000006
+#define FX_WHISTLE 0x0A000007
+#define FX_BARFLAP 0x0A000008
+#define FX_DORCLOSE20 0x0A000009
+#define FX_DRINK 0x0A00000A
+#define FX_FITZHIT 0x0A00000B
+#define FX_FITZRUN 0x0A00000C
+#define FX_FITZUP 0x0A00000D
+#define FX_FUSE20 0x0A00000E
+#define FX_PULLPINT 0x0A00000F
+#define FX_SNEEZE1 0x0A000010
+#define FX_SNEEZE2 0x0A000011
+#define FX_WASHER 0x0A000012
+#define FX_CELTAP 0x0A000013
+#define FX_DRIPIRE 0x0A000014
+#define FX_DRIPIRE2 0x0A000015
+#define FX_TAP 0x0A000016
+#define FX_TAP2 0x0A000017
+#define FX_CLIMBHAY 0x0A000018
+#define FX_FARMERGO 0x0A000019
+#define FX_CASTLWAL 0x0A00001A
+#define FX_CLIMBFAL 0x0A00001B
+#define FX_KEYSTEP 0x0A00001C
+#define FX_WIND 0x0A00001D
+#define FX_GEOGOAT 0x0A00001E
+#define FX_GOATBAA 0x0A00001F
+#define FX_GOATCHEW 0x0A000020
+#define FX_GOATDOH 0x0A000021
+#define FX_PLOUGH 0x0A000022
+#define FX_EIRDRIP1 0x0A000023
+#define FX_EIRDRIP2 0x0A000024
+#define FX_LADDWN25 0x0A000025
+#define FX_LADDUP25 0x0A000026
+#define FX_SECDOR25 0x0A000027
+#define FX_SLABFALL 0x0A000028
+#define FX_SLABUP 0x0A000029
+#define FX_TRIGER25 0x0A00002A
+#define FX_WRING 0x0A00002B
+#define FX_LEVER 0x0A00002C
+#define FX_LEVER2 0x0A00002D
+#define FX_RAT3A 0x0A00002E
+#define FX_RAT3B 0x0A00002F
+#define FX_RAT3C 0x0A000030
+#define FX_RAT3D 0x0A000031
+ // 50 entities in TXTs, 50 in datafiles.
+ // room19
+#define R19SPRPAL 0x0A010000
+#define R19L0 0x0A010001
+#define R19L1 0x0A010002
+#define R19L2 0x0A010003
+#define R19G1 0x0A010004
+#define R19G2 0x0A010005
+#define R19PAL 0x0A010006
+#define R19FLR 0x0A010007
+#define ASSTAP 0x0A010008
+#define ASSTAPCDT 0x0A010009
+#define ASSTLK19 0x0A01000A
+#define ASSTLK19CDT 0x0A01000B
+#define ASSWLK2 0x0A01000C
+#define ASSWLK2CDT 0x0A01000D
+#define ASSWLK6 0x0A01000E
+#define ASSWLK6CDT 0x0A01000F
+#define BOXCVR 0x0A010010
+#define BOXCVRCDT 0x0A010011
+#define GEODRN 0x0A010012
+#define GEODRNCDT 0x0A010013
+#define GEOMAG 0x0A010014
+#define GEOMAGCDT 0x0A010015
+#define GEORCT 0x0A010016
+#define GEORCTCDT 0x0A010017
+#define GEOTRP 0x0A010018
+#define GEOTRPCDT 0x0A010019
+#define GEOTRP8 0x0A01001A
+#define GEOTRP8CDT 0x0A01001B
+#define GEOWRN 0x0A01001C
+#define GEOWRNCDT 0x0A01001D
+#define LID19 0x0A01001E
+#define LID19CDT 0x0A01001F
+#define MAGCON 0x0A010020
+#define MAGCONCDT 0x0A010021
+#define MAGCONCDR 0x0A010022
+#define MAGMOV 0x0A010023
+#define MAGMOVCDT 0x0A010024
+#define MAGMOVCDR 0x0A010025
+#define MAGSHK 0x0A010026
+#define MAGSHKCDT 0x0A010027
+#define MAGSHY 0x0A010028
+#define MAGSHYCDT 0x0A010029
+#define MAGSHYCDR 0x0A01002A
+#define MAGSLK 0x0A01002B
+#define MAGSLKCDT 0x0A01002C
+#define MAGTALK 0x0A01002D
+#define MAGTALKCDT 0x0A01002E
+#define MAGTLK 0x0A01002F
+#define MAGTLKCDT 0x0A010030
+#define MAGTLK8 0x0A010031
+#define MAGTLK8CDT 0x0A010032
+#define TRPOPN 0x0A010033
+#define TRPOPNCDT 0x0A010034
+ // 53 entities in TXTs, 53 in datafiles.
+ // room20
+#define R20SPRPAL 0x0A020000
+#define R20L0 0x0A020001
+#define R20L1 0x0A020002
+#define R20L2 0x0A020003
+#define R20L3 0x0A020004
+#define R20G1 0x0A020005
+#define R20G2 0x0A020006
+#define R20G3 0x0A020007
+#define R20PAL 0x0A020008
+#define R20FLR 0x0A020009
+#define BARTPS 0x0A02000A
+#define BARTPSCDT 0x0A02000B
+#define BARTWL 0x0A02000C
+#define BARTWLCDT 0x0A02000D
+#define BRIDRN 0x0A02000E
+#define BRIDRNCDT 0x0A02000F
+#define BRIDRNCDR 0x0A020010
+#define BRIFTZ 0x0A020011
+#define BRIFTZCDT 0x0A020012
+#define BRIFTZCDR 0x0A020013
+#define BRITLK 0x0A020014
+#define BRITLKCDT 0x0A020015
+#define BRITLK8 0x0A020016
+#define BRITLK8CDT 0x0A020017
+#define BRITLK9 0x0A020018
+#define BRITLK9CDT 0x0A020019
+#define BRITRN 0x0A02001A
+#define BRITRNCDT 0x0A02001B
+#define BRITRNCDR 0x0A02001C
+#define DOROPN20 0x0A02001D
+#define DOROPN20CDT 0x0A02001E
+#define DOROPN20CDR 0x0A02001F
+#define DOYDRN 0x0A020020
+#define DOYDRNCDT 0x0A020021
+#define DOYDRNCDR 0x0A020022
+#define DOYFTZ 0x0A020023
+#define DOYFTZCDT 0x0A020024
+#define DOYFTZCDR 0x0A020025
+#define DOYTLK 0x0A020026
+#define DOYTLKCDT 0x0A020027
+#define DOYTLK20 0x0A020028
+#define DOYTLK20CDT 0x0A020029
+#define DOYTLK8 0x0A02002A
+#define DOYTLK8CDT 0x0A02002B
+#define DOYTLK9 0x0A02002C
+#define DOYTLK9CDT 0x0A02002D
+#define DOYTRN 0x0A02002E
+#define DOYTRNCDT 0x0A02002F
+#define DOYTRNCDR 0x0A020030
+#define DOYTRN20 0x0A020031
+#define DOYTRN20CDT 0x0A020032
+#define DOYTRN20CDR 0x0A020033
+#define DOYTRN8 0x0A020034
+#define DOYTRN8CDT 0x0A020035
+#define DOYTRN8CDR 0x0A020036
+#define DOYTRN9 0x0A020037
+#define DOYTRN9CDT 0x0A020038
+#define DOYTRN9CDR 0x0A020039
+#define FIDPLY 0x0A02003A
+#define FIDPLYCDT 0x0A02003B
+#define FLPOPN 0x0A02003C
+#define FLPOPNCDT 0x0A02003D
+#define FRMTLK20 0x0A02003E
+#define FRMTLK20CDT 0x0A02003F
+#define FTZAGT 0x0A020040
+#define FTZAGTCDT 0x0A020041
+#define FTZGET 0x0A020042
+#define FTZGETCDT 0x0A020043
+#define FTZGETCDR 0x0A020044
+#define FTZRUN 0x0A020045
+#define FTZRUNCDT 0x0A020046
+#define FTZSTD 0x0A020047
+#define FTZSTDCDT 0x0A020048
+#define FTZTALK 0x0A020049
+#define FTZTALKCDT 0x0A02004A
+#define FTZTLK 0x0A02004B
+#define FTZTLKCDT 0x0A02004C
+#define FTZTLK8 0x0A02004D
+#define FTZTLK8CDT 0x0A02004E
+#define GEODRN20 0x0A02004F
+#define GEODRN20CDT 0x0A020050
+#define GEOPHN20 0x0A020051
+#define GEOPHN20CDT 0x0A020052
+#define GEOPHN20CDR 0x0A020053
+#define GEOPLG 0x0A020054
+#define GEOPLGCDT 0x0A020055
+#define GEOPLG8 0x0A020056
+#define GEOPLG8CDT 0x0A020057
+#define GEOSEE 0x0A020058
+#define GEOSEECDT 0x0A020059
+#define GEOSNR 0x0A02005A
+#define GEOSNRCDT 0x0A02005B
+#define GEOSNR8 0x0A02005C
+#define GEOSNR8CDT 0x0A02005D
+#define GEOTWL20 0x0A02005E
+#define GEOTWL20CDT 0x0A02005F
+#define GEOXIT20 0x0A020060
+#define GEOXIT20CDT 0x0A020061
+#define GLSGEO 0x0A020062
+#define GLSGEOCDT 0x0A020063
+#define GLSWSH 0x0A020064
+#define GLSWSHCDT 0x0A020065
+#define LESDOR 0x0A020066
+#define LESDORCDT 0x0A020067
+#define LESDOY 0x0A020068
+#define LESDOYCDT 0x0A020069
+#define LESFLP 0x0A02006A
+#define LESFLPCDT 0x0A02006B
+#define LESFTZ 0x0A02006C
+#define LESFTZCDT 0x0A02006D
+#define LESFTZCDR 0x0A02006E
+#define LESGLS 0x0A02006F
+#define LESGLSCDT 0x0A020070
+#define LESGLSCDR 0x0A020071
+#define LESLNS 0x0A020072
+#define LESLNSCDT 0x0A020073
+#define LESLNSCDR 0x0A020074
+#define LESMOV 0x0A020075
+#define LESMOVCDT 0x0A020076
+#define LESMOVCDR 0x0A020077
+#define LESPMP 0x0A020078
+#define LESPMPCDT 0x0A020079
+#define LESPNT 0x0A02007A
+#define LESPNTCDT 0x0A02007B
+#define LESPNT20 0x0A02007C
+#define LESPNT20CDT 0x0A02007D
+#define LESPNT8 0x0A02007E
+#define LESPNT8CDT 0x0A02007F
+#define LESPNT8CDR 0x0A020080
+#define LESTALK 0x0A020081
+#define LESTALKCDT 0x0A020082
+#define LESTLK 0x0A020083
+#define LESTLKCDT 0x0A020084
+#define LESTLK20 0x0A020085
+#define LESTLK20CDT 0x0A020086
+#define LESTLK8 0x0A020087
+#define LESTLK8CDT 0x0A020088
+#define LESTLK9 0x0A020089
+#define LESTLK9CDT 0x0A02008A
+#define LESTURN 0x0A02008B
+#define LESTURNCDT 0x0A02008C
+#define LESTURNCDR 0x0A02008D
+#define LESWLK 0x0A02008E
+#define LESWLKCDT 0x0A02008F
+#define LESWLK8 0x0A020090
+#define LESWLK8CDT 0x0A020091
+#define LESWSH 0x0A020092
+#define LESWSHCDT 0x0A020093
+#define LESWSHCDR 0x0A020094
+#define MAGENT 0x0A020095
+#define MAGENTCDT 0x0A020096
+#define MAGEXIT 0x0A020097
+#define MAGEXITCDT 0x0A020098
+#define MAGMOV20 0x0A020099
+#define MAGMOV20CDT 0x0A02009A
+#define MAGTEST 0x0A02009B
+#define MAGTESTCDT 0x0A02009C
+#define MAGTLK20 0x0A02009D
+#define MAGTLK20CDT 0x0A02009E
+#define PLGWLL 0x0A02009F
+#define PLGWLLCDT 0x0A0200A0
+#define RONDRN 0x0A0200A1
+#define RONDRNCDT 0x0A0200A2
+#define RONDRNCDR 0x0A0200A3
+#define RONDRP 0x0A0200A4
+#define RONDRPCDT 0x0A0200A5
+#define RONFTZ 0x0A0200A6
+#define RONFTZCDT 0x0A0200A7
+#define RONFTZCDR 0x0A0200A8
+#define RONGEO 0x0A0200A9
+#define RONGEOCDT 0x0A0200AA
+#define RONGEOCDR 0x0A0200AB
+#define RONGLS 0x0A0200AC
+#define RONGLSCDT 0x0A0200AD
+#define RONGLSCDR 0x0A0200AE
+#define RONGLS8 0x0A0200AF
+#define RONGLS8CDT 0x0A0200B0
+#define RONPIK 0x0A0200B1
+#define RONPIKCDT 0x0A0200B2
+#define RONPKT 0x0A0200B3
+#define RONPKTCDT 0x0A0200B4
+#define RONPKTCDR 0x0A0200B5
+#define RONSNR 0x0A0200B6
+#define RONSNRCDT 0x0A0200B7
+#define RONSNZ 0x0A0200B8
+#define RONSNZCDT 0x0A0200B9
+#define RONSNZ2 0x0A0200BA
+#define RONSNZ2CDT 0x0A0200BB
+#define RONTLK 0x0A0200BC
+#define RONTLKCDT 0x0A0200BD
+#define RONTLK2 0x0A0200BE
+#define RONTLK2CDT 0x0A0200BF
+#define RONWIR 0x0A0200C0
+#define RONWIRCDT 0x0A0200C1
+#define RONWIRCDR 0x0A0200C2
+#define SNRTBL 0x0A0200C3
+#define SNRTBLCDT 0x0A0200C4
+ // 197 entities in TXTs, 197 in datafiles.
+ // room21
+#define R21L0 0x0A030000
+#define R21L1 0x0A030001
+#define R21L2 0x0A030002
+#define R21G1 0x0A030003
+#define R21G2 0x0A030004
+#define R21PAL 0x0A030005
+#define R21FLR 0x0A030006
+#define CALBLO 0x0A030007
+#define CALBLOCDT 0x0A030008
+#define GEMSHN 0x0A030009
+#define GEMSHNCDT 0x0A03000A
+#define GEOGEM 0x0A03000B
+#define GEOGEMCDT 0x0A03000C
+#define GEOGEM8 0x0A03000D
+#define GEOGEM8CDT 0x0A03000E
+#define GEOLVR 0x0A03000F
+#define GEOLVRCDT 0x0A030010
+#define GEOLVR21 0x0A030011
+#define GEOLVR21CDT 0x0A030012
+#define GEOLVR8 0x0A030013
+#define GEOLVR8CDT 0x0A030014
+#define GEOTAP 0x0A030015
+#define GEOTAPCDT 0x0A030016
+#define GEOTLK21 0x0A030017
+#define GEOTLK21CDT 0x0A030018
+#define GEOTORCH 0x0A030019
+#define GEOTORCHCDT 0x0A03001A
+#define GEOTRN21 0x0A03001B
+#define GEOTRN21CDT 0x0A03001C
+#define GEOTRN21CDR 0x0A03001D
+#define GEOTWL21 0x0A03001E
+#define GEOTWL21CDT 0x0A03001F
+#define LVRPSH 0x0A030020
+#define LVRPSHCDT 0x0A030021
+#define MAGCEL 0x0A030022
+#define MAGCELCDT 0x0A030023
+#define MAGCELCDR 0x0A030024
+#define MAGTLK21 0x0A030025
+#define MAGTLK21CDT 0x0A030026
+#define TAPDRP 0x0A030027
+#define TAPDRPCDT 0x0A030028
+#define TAPRUN 0x0A030029
+#define TAPRUNCDT 0x0A03002A
+#define TORCH21 0x0A03002B
+#define TORCH21CDT 0x0A03002C
+ // 45 entities in TXTs, 45 in datafiles.
+ // room22
+#define R22SPRPAL 0x0A040000
+#define R22L0 0x0A040001
+#define R22L1 0x0A040002
+#define R22G1 0x0A040003
+#define R22PAL 0x0A040004
+#define R22FLR 0x0A040005
+#define FRMBUK 0x0A040006
+#define FRMBUKCDT 0x0A040007
+#define FRMSTD 0x0A040008
+#define FRMSTDCDT 0x0A040009
+#define FRMTLK 0x0A04000A
+#define FRMTLKCDT 0x0A04000B
+#define FRMWLK 0x0A04000C
+#define FRMWLKCDT 0x0A04000D
+#define GEOCLM 0x0A04000E
+#define GEOCLMCDT 0x0A04000F
+#define GEOCLMCDR 0x0A040010
+#define GEOPSH22 0x0A040011
+#define GEOPSH22CDT 0x0A040012
+ // 19 entities in TXTs, 19 in datafiles.
+ // room23
+#define R23L0 0x0A050000
+#define R23PAL 0x0A050001
+#define GEOCLM23 0x0A050002
+#define GEOCLM23CDT 0x0A050003
+#define GEOCLM23CDR 0x0A050004
+#define GEOKEY23 0x0A050005
+#define GEOKEY23CDT 0x0A050006
+#define GEOTOP 0x0A050007
+#define GEOTOPCDT 0x0A050008
+#define GEOTOPCDR 0x0A050009
+#define GEOTRY23 0x0A05000A
+#define GEOTRY23CDT 0x0A05000B
+#define GEOTUG23 0x0A05000C
+#define GEOTUG23CDT 0x0A05000D
+#define LFTKEY23 0x0A05000E
+#define LFTKEY23CDT 0x0A05000F
+ // 16 entities in TXTs, 16 in datafiles.
+ // room24
+#define R24L0 0x0A060000
+#define R24L1 0x0A060001
+#define R24G1 0x0A060002
+#define R24PLX 0x0A060003
+#define R24PAL 0x0A060004
+#define R24FLR 0x0A060005
+#define GEOASC24 0x0A060006
+#define GEOASC24CDT 0x0A060007
+#define GEODES24 0x0A060008
+#define GEODES24CDT 0x0A060009
+#define GEOHITL 0x0A06000A
+#define GEOHITLCDT 0x0A06000B
+#define GEOHITR 0x0A06000C
+#define GEOHITRCDT 0x0A06000D
+#define GEOLAD 0x0A06000E
+#define GEOLADCDT 0x0A06000F
+#define GEOLAD8 0x0A060010
+#define GEOLAD8CDT 0x0A060011
+#define GEOPLW 0x0A060012
+#define GEOPLWCDT 0x0A060013
+#define GEORUN 0x0A060014
+#define GEORUNCDT 0x0A060015
+#define GEOUPL24 0x0A060016
+#define GEOUPL24CDT 0x0A060017
+#define GEOUPR24 0x0A060018
+#define GEOUPR24CDT 0x0A060019
+#define GOTBAKL 0x0A06001A
+#define GOTBAKLCDT 0x0A06001B
+#define GOTBAKR 0x0A06001C
+#define GOTBAKRCDT 0x0A06001D
+#define GOTCL 0x0A06001E
+#define GOTCLCDT 0x0A06001F
+#define GOTCR 0x0A060020
+#define GOTCRCDT 0x0A060021
+#define GOTEAT 0x0A060022
+#define GOTEATCDT 0x0A060023
+#define GOTPLW 0x0A060024
+#define GOTPLWCDT 0x0A060025
+#define GOTPLW1 0x0A060026
+#define GOTPLW1CDT 0x0A060027
+#define GOTRIS 0x0A060028
+#define GOTRISCDT 0x0A060029
+#define GOTRISCDR 0x0A06002A
+#define PLWMOV 0x0A06002B
+#define PLWMOVCDT 0x0A06002C
+ // 45 entities in TXTs, 45 in datafiles.
+ // room25
+#define R25SPRPAL 0x0A070000
+#define R25L0 0x0A070001
+#define R25L1 0x0A070002
+#define R25G1 0x0A070003
+#define R25PAL 0x0A070004
+#define R25FLR 0x0A070005
+#define ALTOPN 0x0A070006
+#define ALTOPNCDT 0x0A070007
+#define GEOASC25 0x0A070008
+#define GEOASC25CDT 0x0A070009
+#define GEOCLM25 0x0A07000A
+#define GEOCLM25CDT 0x0A07000B
+#define GEODES25 0x0A07000C
+#define GEODES25CDT 0x0A07000D
+#define GEODRY25 0x0A07000E
+#define GEODRY25CDT 0x0A07000F
+#define GEOFIN25 0x0A070010
+#define GEOFIN25CDT 0x0A070011
+#define GEOPLAS 0x0A070012
+#define GEOPLASCDT 0x0A070013
+#define GEOPLASCDR 0x0A070014
+#define GEOPLS 0x0A070015
+#define GEOPLSCDT 0x0A070016
+#define GEOPSH25 0x0A070017
+#define GEOPSH25CDT 0x0A070018
+#define GEOPUT 0x0A070019
+#define GEOPUTCDT 0x0A07001A
+#define GEOSAC 0x0A07001B
+#define GEOSACCDT 0x0A07001C
+#define GEOSAC25 0x0A07001D
+#define GEOSAC25CDT 0x0A07001E
+#define GEOSTD25 0x0A07001F
+#define GEOSTD25CDT 0x0A070020
+#define GEOSTN 0x0A070021
+#define GEOSTNCDT 0x0A070022
+#define GEOSTN8 0x0A070023
+#define GEOSTN8CDT 0x0A070024
+#define GEOTWL25 0x0A070025
+#define GEOTWL25CDT 0x0A070026
+#define GEOWALF2 0x0A070027
+#define GEOWALF2CDT 0x0A070028
+#define IMPFLR 0x0A070029
+#define IMPFLRCDT 0x0A07002A
+#define IMPPLS 0x0A07002B
+#define IMPPLSCDT 0x0A07002C
+#define PLASWALL 0x0A07002D
+#define PLASWALLCDT 0x0A07002E
+#define STNFALL 0x0A07002F
+#define STNFALLCDT 0x0A070030
+ // 49 entities in TXTs, 49 in datafiles.
+ // room26
+#define R26SPRPAL 0x0A080000
+#define R26L0 0x0A080001
+#define R26L1 0x0A080002
+#define R26L2 0x0A080003
+#define R26G1 0x0A080004
+#define R26G2 0x0A080005
+#define R26PAL 0x0A080006
+#define R26FLR 0x0A080007
+#define GEOLVR08 0x0A080008
+#define GEOLVR08CDT 0x0A080009
+#define GEOLVR26 0x0A08000A
+#define GEOLVR26CDT 0x0A08000B
+#define LVRDRK 0x0A08000C
+#define LVRDRKCDT 0x0A08000D
+#define RATJMP 0x0A08000E
+#define RATJMPCDT 0x0A08000F
+ // 16 entities in TXTs, 16 in datafiles.
+// spain
+ // sound_fx
+#define FX_SPNBIRD1 0x0B000000
+#define FX_SPNBIRD2 0x0B000001
+#define FX_AMBIEN56 0x0B000002
+#define FX_DOGS56 0x0B000003
+#define FX_PENDULUM 0x0B000004
+#define FX_CANFALL 0x0B000005
+#define FX_HOSE57 0x0B000006
+#define FX_HOSE57B 0x0B000007
+#define FX_SPAIN 0x0B000008
+#define FX_CHESS 0x0B000009
+#define FX_SECDOR59 0x0B00000A
+#define FX_WINDOW59 0x0B00000B
+#define FX_LIONFALL 0x0B00000C
+#define FX_LIONFAL2 0x0B00000D
+#define FX_TOOTHPUL 0x0B00000E
+#define FX_SECDOR61 0x0B00000F
+#define FX_WELLDRIP 0x0B000010
+ // 17 entities in TXTs, 17 in datafiles.
+ // room56
+#define SPAIN_PAL 0x0B010000
+#define R56L0 0x0B010001
+#define R56L1 0x0B010002
+#define R56L2 0x0B010003
+#define R56G1 0x0B010004
+#define R56G2 0x0B010005
+#define R56PAL 0x0B010006
+#define R56FLR 0x0B010007
+#define CHALIC56 0x0B010008
+#define CHALIC56CDT 0x0B010009
+#define GARD20 0x0B01000A
+#define GARD20CDT 0x0B01000B
+#define GARD21 0x0B01000C
+#define GARD21CDT 0x0B01000D
+#define GARD22 0x0B01000E
+#define GARD22CDT 0x0B01000F
+#define GEOSPA10 0x0B010010
+#define GEOSPA10CDT 0x0B010011
+#define GEOSPA10CDR 0x0B010012
+#define GEOSPA11 0x0B010013
+#define GEOSPA11CDT 0x0B010014
+#define GEOSPA13 0x0B010015
+#define GEOSPA13CDT 0x0B010016
+#define GEOSPA13CDR 0x0B010017
+#define GEOSPA19 0x0B010018
+#define GEOSPA19CDT 0x0B010019
+#define GEOSPA44 0x0B01001A
+#define GEOSPA44CDT 0x0B01001B
+#define GEOSPA48 0x0B01001C
+#define GEOSPA48CDT 0x0B01001D
+#define PENDULUM 0x0B01001E
+#define PENDULUMCDT 0x0B01001F
+#define PIECE56 0x0B010020
+#define PIECE56CDT 0x0B010021
+#define VASC01 0x0B010022
+#define VASC01CDT 0x0B010023
+#define VASC02 0x0B010024
+#define VASC02CDT 0x0B010025
+#define VASC04 0x0B010026
+#define VASC04CDT 0x0B010027
+#define VASC05 0x0B010028
+#define VASC05CDT 0x0B010029
+#define VASC05CDR 0x0B01002A
+#define VASC06 0x0B01002B
+#define VASC06CDT 0x0B01002C
+#define VASC26 0x0B01002D
+#define VASC26CDT 0x0B01002E
+#define VASC26CDR 0x0B01002F
+#define VASC27 0x0B010030
+#define VASC27CDT 0x0B010031
+#define VASC28 0x0B010032
+#define VASC28CDT 0x0B010033
+#define VASC29 0x0B010034
+#define VASC29CDT 0x0B010035
+#define VASC29CDR 0x0B010036
+#define VASC30 0x0B010037
+#define VASC30CDT 0x0B010038
+#define VASC30CDR 0x0B010039
+#define VASC32 0x0B01003A
+#define VASC32CDT 0x0B01003B
+ // 60 entities in TXTs, 60 in datafiles.
+ // room57
+#define R57L0 0x0B020000
+#define R57L1 0x0B020001
+#define R57G1 0x0B020002
+#define R57PAL 0x0B020003
+#define R57FLR 0x0B020004
+#define R57PLX 0x0B020005
+#define MEGA_DOWSE 0x0B020006
+#define GAR57GOB 0x0B020007
+#define GAR57GOBCDT 0x0B020008
+#define GARD01 0x0B020009
+#define GARD01CDT 0x0B02000A
+#define GARD02 0x0B02000B
+#define GARD02CDT 0x0B02000C
+#define GARD03 0x0B02000D
+#define GARD03CDT 0x0B02000E
+#define GARD04 0x0B02000F
+#define GARD04CDT 0x0B020010
+#define GARD04CDR 0x0B020011
+#define GARD05 0x0B020012
+#define GARD05CDT 0x0B020013
+#define GARD06 0x0B020014
+#define GARD06CDT 0x0B020015
+#define GARD07 0x0B020016
+#define GARD07CDT 0x0B020017
+#define GARD07CDR 0x0B020018
+#define GARD08 0x0B020019
+#define GARD08CDT 0x0B02001A
+#define GARD09 0x0B02001B
+#define GARD09CDT 0x0B02001C
+#define GARD17 0x0B02001D
+#define GARD17CDT 0x0B02001E
+#define GARD17CDR 0x0B02001F
+#define GARD18 0x0B020020
+#define GARD18CDT 0x0B020021
+#define GARD31 0x0B020022
+#define GARD31CDT 0x0B020023
+#define GARD31CDR 0x0B020024
+#define GARD32 0x0B020025
+#define GARD32CDT 0x0B020026
+#define GARD34 0x0B020027
+#define GARD34CDT 0x0B020028
+#define GARD35 0x0B020029
+#define GARD35CDT 0x0B02002A
+#define GARD36 0x0B02002B
+#define GARD36CDT 0x0B02002C
+#define GARD37 0x0B02002D
+#define GARD37CDT 0x0B02002E
+#define GARD38 0x0B02002F
+#define GARD38CDT 0x0B020030
+#define GARD39 0x0B020031
+#define GARD39CDT 0x0B020032
+#define GARD40 0x0B020033
+#define GARD40CDT 0x0B020034
+#define GARD40CDR 0x0B020035
+#define GARD41 0x0B020036
+#define GARD41CDT 0x0B020037
+#define GARD42 0x0B020038
+#define GARD42CDT 0x0B020039
+#define GARD43 0x0B02003A
+#define GARD43CDT 0x0B02003B
+#define GARD44 0x0B02003C
+#define GARD44CDT 0x0B02003D
+#define GARD44CDR 0x0B02003E
+#define GARD45 0x0B02003F
+#define GARD45CDT 0x0B020040
+#define GARDKNE 0x0B020041
+#define GARDKNECDT 0x0B020042
+#define GAUGE57 0x0B020043
+#define GAUGE57CDT 0x0B020044
+#define GEOSPA01 0x0B020045
+#define GEOSPA01CDT 0x0B020046
+#define GEOSPA20 0x0B020047
+#define GEOSPA20CDT 0x0B020048
+#define GEOSPA22 0x0B020049
+#define GEOSPA22CDT 0x0B02004A
+#define GEOSPA42 0x0B02004B
+#define GEOSPA42CDT 0x0B02004C
+#define GEOSPA47 0x0B02004D
+#define GEOSPA47CDT 0x0B02004E
+#define HOLE57 0x0B02004F
+#define HOLE57CDT 0x0B020050
+#define HOSE57 0x0B020051
+#define HOSE57CDT 0x0B020052
+ // 83 entities in TXTs, 83 in datafiles.
+ // room58
+#define R58L0 0x0B030000
+#define R58L1 0x0B030001
+#define R58G1 0x0B030002
+#define R58PAL 0x0B030003
+#define R58FLR 0x0B030004
+#define R58PLX 0x0B030005
+#define GARD24 0x0B030006
+#define GARD24CDT 0x0B030007
+#define GARD25 0x0B030008
+#define GARD25CDT 0x0B030009
+#define GARD26 0x0B03000A
+#define GARD26CDT 0x0B03000B
+#define MAUSDOOR 0x0B03000C
+#define MAUSDOORCDT 0x0B03000D
+#define VASC07 0x0B03000E
+#define VASC07CDT 0x0B03000F
+#define VASC08 0x0B030010
+#define VASC08CDT 0x0B030011
+#define VASC09 0x0B030012
+#define VASC09CDT 0x0B030013
+#define VASC10 0x0B030014
+#define VASC10CDT 0x0B030015
+#define VASC11 0x0B030016
+#define VASC11CDT 0x0B030017
+#define VASC12 0x0B030018
+#define VASC12CDT 0x0B030019
+ // 26 entities in TXTs, 26 in datafiles.
+ // room59
+#define R59L0 0x0B040000
+#define R59L1 0x0B040001
+#define R59L2 0x0B040002
+#define R59G1 0x0B040003
+#define R59G2 0x0B040004
+#define R59PAL 0x0B040005
+#define R59FLR 0x0B040006
+#define BIBLE59 0x0B040007
+#define BIBLE59CDT 0x0B040008
+#define BLOWOUT 0x0B040009
+#define BLOWOUTCDT 0x0B04000A
+#define CANDLE59 0x0B04000B
+#define CANDLE59CDT 0x0B04000C
+#define CHAL59 0x0B04000D
+#define CHAL59CDT 0x0B04000E
+#define FLAMEL59 0x0B04000F
+#define FLAMEL59CDT 0x0B040010
+#define FLAMER59 0x0B040011
+#define FLAMER59CDT 0x0B040012
+#define FLAMET59 0x0B040013
+#define FLAMET59CDT 0x0B040014
+#define GARD27 0x0B040015
+#define GARD27CDT 0x0B040016
+#define GARD28 0x0B040017
+#define GARD28CDT 0x0B040018
+#define GARD29 0x0B040019
+#define GARD29CDT 0x0B04001A
+#define GARD30 0x0B04001B
+#define GARD30CDT 0x0B04001C
+#define GEOBIBLE 0x0B04001D
+#define GEOBIBLECDT 0x0B04001E
+#define GEOSPA12 0x0B04001F
+#define GEOSPA12CDT 0x0B040020
+#define GEOSPA16 0x0B040021
+#define GEOSPA16CDT 0x0B040022
+#define GEOSPA17 0x0B040023
+#define GEOSPA17CDT 0x0B040024
+#define GEOSPA18 0x0B040025
+#define GEOSPA18CDT 0x0B040026
+#define GEOSPA18CDR 0x0B040027
+#define GEOSPA23 0x0B040028
+#define GEOSPA23CDT 0x0B040029
+#define GEOSPA23CDR 0x0B04002A
+#define GEOSPA37 0x0B04002B
+#define GEOSPA37CDT 0x0B04002C
+#define GEOSPA37CDR 0x0B04002D
+#define GEOSPA38 0x0B04002E
+#define GEOSPA38CDT 0x0B04002F
+#define GEOSPA39 0x0B040030
+#define GEOSPA39CDT 0x0B040031
+#define GEOSPA40 0x0B040032
+#define GEOSPA40CDT 0x0B040033
+#define GEOSPA41 0x0B040034
+#define GEOSPA41CDT 0x0B040035
+#define GEOSPA43 0x0B040036
+#define GEOSPA43CDT 0x0B040037
+#define GEOSPA45 0x0B040038
+#define GEOSPA45CDT 0x0B040039
+#define GEOSPA46 0x0B04003A
+#define GEOSPA46CDT 0x0B04003B
+#define SECDOR59 0x0B04003C
+#define SECDOR59CDT 0x0B04003D
+#define SNUFF59 0x0B04003E
+#define SNUFF59CDT 0x0B04003F
+#define TISSUE59 0x0B040040
+#define TISSUE59CDT 0x0B040041
+#define VASC13 0x0B040042
+#define VASC13CDT 0x0B040043
+#define VASC14 0x0B040044
+#define VASC14CDT 0x0B040045
+#define VASC15 0x0B040046
+#define VASC15CDT 0x0B040047
+#define VASC16 0x0B040048
+#define VASC16CDT 0x0B040049
+#define VASC17 0x0B04004A
+#define VASC17CDT 0x0B04004B
+#define VASC18 0x0B04004C
+#define VASC18CDT 0x0B04004D
+#define VASC19 0x0B04004E
+#define VASC19CDT 0x0B04004F
+#define VASC20 0x0B040050
+#define VASC20CDT 0x0B040051
+#define VASC20CDR 0x0B040052
+#define VASC21 0x0B040053
+#define VASC21CDT 0x0B040054
+#define VASC22 0x0B040055
+#define VASC22CDT 0x0B040056
+#define VASC23 0x0B040057
+#define VASC23CDT 0x0B040058
+#define VASC24 0x0B040059
+#define VASC24CDT 0x0B04005A
+#define VASC25 0x0B04005B
+#define VASC25CDT 0x0B04005C
+#define VASC31 0x0B04005D
+#define VASC31CDT 0x0B04005E
+#define WINDSHUT 0x0B04005F
+#define WINDSHUTCDT 0x0B040060
+#define WINDSHUTCDR 0x0B040061
+ // 98 entities in TXTs, 98 in datafiles.
+ // room60
+#define R60L0 0x0B050000
+#define R60L1 0x0B050001
+#define R60L2 0x0B050002
+#define R60G1 0x0B050003
+#define R60G2 0x0B050004
+#define R60PAL 0x0B050005
+#define R60FLR 0x0B050006
+#define GARD10 0x0B050007
+#define GARD10CDT 0x0B050008
+#define GARD11 0x0B050009
+#define GARD11CDT 0x0B05000A
+#define GARD13 0x0B05000B
+#define GARD13CDT 0x0B05000C
+#define GARD16 0x0B05000D
+#define GARD16CDT 0x0B05000E
+#define GARD19 0x0B05000F
+#define GARD19CDT 0x0B050010
+#define GEOSPA05 0x0B050011
+#define GEOSPA05CDT 0x0B050012
+#define GEOSPA05CDR 0x0B050013
+#define GEOSPA08 0x0B050014
+#define GEOSPA08CDT 0x0B050015
+#define GEOSPA09 0x0B050016
+#define GEOSPA09CDT 0x0B050017
+#define GEOSPA09CDR 0x0B050018
+#define GEOSPA21 0x0B050019
+#define GEOSPA21CDT 0x0B05001A
+#define MIRROR60 0x0B05001B
+#define MIRROR60CDT 0x0B05001C
+ // 29 entities in TXTs, 29 in datafiles.
+ // room61
+#define R61L0 0x0B060000
+#define R61L1 0x0B060001
+#define R61G1 0x0B060002
+#define R61PAL 0x0B060003
+#define R61FLR 0x0B060004
+#define DUST 0x0B060005
+#define DUSTCDT 0x0B060006
+#define GEOSPA24 0x0B060007
+#define GEOSPA24CDT 0x0B060008
+#define GEOSPA25 0x0B060009
+#define GEOSPA25CDT 0x0B06000A
+#define GEOSPA26 0x0B06000B
+#define GEOSPA26CDT 0x0B06000C
+#define GEOSPA27 0x0B06000D
+#define GEOSPA27CDT 0x0B06000E
+#define GEOSPA30 0x0B06000F
+#define GEOSPA30CDT 0x0B060010
+#define GEOSPA31 0x0B060011
+#define GEOSPA31CDT 0x0B060012
+#define GEOSPA32 0x0B060013
+#define GEOSPA32CDT 0x0B060014
+#define GEOSPA33 0x0B060015
+#define GEOSPA33CDT 0x0B060016
+#define GEOSPA35 0x0B060017
+#define GEOSPA35CDT 0x0B060018
+#define LION1 0x0B060019
+#define LION1CDT 0x0B06001A
+#define LION2 0x0B06001B
+#define LION2CDT 0x0B06001C
+#define LIONDOOR 0x0B06001D
+#define LIONDOORCDT 0x0B06001E
+#define LIONFLOR 0x0B06001F
+#define LIONFLORCDT 0x0B060020
+#define ROPE61 0x0B060021
+#define ROPE61CDT 0x0B060022
+#define SECDOR61 0x0B060023
+#define SECDOR61CDT 0x0B060024
+ // 37 entities in TXTs, 37 in datafiles.
+ // room62
+#define R62L0 0x0B070000
+#define R62PAL 0x0B070001
+#define BISHOP62 0x0B070002
+#define BISHOP62CDT 0x0B070003
+#define KING62 0x0B070004
+#define KING62CDT 0x0B070005
+#define KNIGHT62 0x0B070006
+#define KNIGHT62CDT 0x0B070007
+ // 8 entities in TXTs, 8 in datafiles.
+// syria
+ // sound_fx
+#define FX_CAMERA45 0x0C000000
+#define FX_SHOCK3 0x0C000001
+#define FX_STALLBEL 0x0C000002
+#define FX_AYUBDOOR 0x0C000003
+#define FX_BALLPLAY 0x0C000004
+#define FX_CATHIT 0x0C000005
+#define FX_MARIB 0x0C000006
+#define FX_NEWTON 0x0C000007
+#define FX_STALLCAT 0x0C000008
+#define FX_STATBREK 0x0C000009
+#define FX_KEYS49 0x0C00000A
+#define FX_MANG1 0x0C00000B
+#define FX_MANG2 0x0C00000C
+#define FX_MANG3 0x0C00000D
+#define FX_UNLOCK49 0x0C00000E
+#define FX_WCCHAIN 0x0C00000F
+#define FX_CUBDOR 0x0C000010
+#define FX_BREKSTIK 0x0C000011
+#define FX_CLIMBDWN 0x0C000012
+#define FX_CRICKET 0x0C000013
+#define FX_GEOFAL54 0x0C000014
+#define FX_KHANDOWN 0x0C000015
+#define FX_RINGPULL 0x0C000016
+#define FX_SECDOR54 0x0C000017
+#define FX_SHOTKHAN 0x0C000018
+#define FX_SYRIWIND 0x0C000019
+#define FX_THUMP1 0x0C00001A
+#define FX_SECDOR55 0x0C00001B
+ // 28 entities in TXTs, 28 in datafiles.
+ // duane
+#define DUANE_MEGA 0x0C010000
+#define DUANE_WLK 0x0C010001
+#define DNETLK3 0x0C010002
+#define DNETLK3CDT 0x0C010003
+#define DNETLK5 0x0C010004
+#define DNETLK5CDT 0x0C010005
+#define XDNEMON3 0x0C010006
+#define XDNEMON3CDT 0x0C010007
+#define XDNEMON5 0x0C010008
+#define XDNEMON5CDT 0x0C010009
+#define XDNESTA3 0x0C01000A
+#define XDNESTA3CDT 0x0C01000B
+#define XDNESTA5 0x0C01000C
+#define XDNESTA5CDT 0x0C01000D
+#define XDNEPHO3 0x0C01000E
+#define XDNEPHO3CDT 0x0C01000F
+#define XDNEPHO5 0x0C010010
+#define XDNEPHO5CDT 0x0C010011
+ // 18 entities in TXTs, 18 in datafiles.
+ // room45
+#define SYRIA_PAL 0x0C020000
+#define R45SPRPAL 0x0C020001
+#define R45L0 0x0C020002
+#define R45L1 0x0C020003
+#define R45G1 0x0C020004
+#define R45PAL 0x0C020005
+#define R45FLR 0x0C020006
+#define R45PLX 0x0C020007
+#define ART1 0x0C020008
+#define ART1CDT 0x0C020009
+#define ART2 0x0C02000A
+#define ART2CDT 0x0C02000B
+#define ART3A 0x0C02000C
+#define ART3ACDT 0x0C02000D
+#define ART3ACDR 0x0C02000E
+#define ART4 0x0C02000F
+#define ART4CDT 0x0C020010
+#define ART5 0x0C020011
+#define ART5CDT 0x0C020012
+#define ART6 0x0C020013
+#define ART6CDT 0x0C020014
+#define ART7 0x0C020015
+#define ART7CDT 0x0C020016
+#define AYU1 0x0C020017
+#define AYU1CDT 0x0C020018
+#define AYU1A 0x0C020019
+#define AYU1ACDT 0x0C02001A
+#define AYU1B 0x0C02001B
+#define AYU1BCDT 0x0C02001C
+#define AYU5 0x0C02001D
+#define AYU5CDT 0x0C02001E
+#define BRUSH 0x0C02001F
+#define BRUSHCDT 0x0C020020
+#define CAT1 0x0C020021
+#define CAT1CDT 0x0C020022
+#define CAT3 0x0C020023
+#define CAT3CDT 0x0C020024
+#define CAT4 0x0C020025
+#define CAT4CDT 0x0C020026
+#define CAT5 0x0C020027
+#define CAT5CDT 0x0C020028
+#define GEOCHA 0x0C020029
+#define GEOCHACDT 0x0C02002A
+#define GEOSYR1 0x0C02002B
+#define GEOSYR1CDT 0x0C02002C
+#define GEOSYR10 0x0C02002D
+#define GEOSYR10CDT 0x0C02002E
+#define GEOSYR10CDR 0x0C02002F
+#define GEOSYR18 0x0C020030
+#define GEOSYR18CDT 0x0C020031
+#define GEOSYR2 0x0C020032
+#define GEOSYR2CDT 0x0C020033
+#define GEOSYR5 0x0C020034
+#define GEOSYR5CDT 0x0C020035
+#define GEOSYR6 0x0C020036
+#define GEOSYR6CDT 0x0C020037
+#define GEOSYR7 0x0C020038
+#define GEOSYR7CDT 0x0C020039
+#define NEJ1 0x0C02003A
+#define NEJ1CDT 0x0C02003B
+#define NEJ10 0x0C02003C
+#define NEJ10CDT 0x0C02003D
+#define NEJ12 0x0C02003E
+#define NEJ12CDT 0x0C02003F
+#define NEJ13 0x0C020040
+#define NEJ13CDT 0x0C020041
+#define NEJ13CDR 0x0C020042
+#define NEJ2 0x0C020043
+#define NEJ2CDT 0x0C020044
+#define NEJ2B 0x0C020045
+#define NEJ2BCDT 0x0C020046
+#define NEJ4 0x0C020047
+#define NEJ4CDT 0x0C020048
+#define NEJ6 0x0C020049
+#define NEJ6CDT 0x0C02004A
+#define NEJ7 0x0C02004B
+#define NEJ7CDT 0x0C02004C
+#define NEJ7B 0x0C02004D
+#define NEJ7BCDT 0x0C02004E
+#define NEJ8 0x0C02004F
+#define NEJ8CDT 0x0C020050
+#define NEJ9 0x0C020051
+#define NEJ9CDT 0x0C020052
+#define NEWTON 0x0C020053
+#define NEWTONCDT 0x0C020054
+#define PRL1 0x0C020055
+#define PRL1CDT 0x0C020056
+#define PRL2 0x0C020057
+#define PRL2CDT 0x0C020058
+#define PRL6 0x0C020059
+#define PRL6CDT 0x0C02005A
+#define PRL7 0x0C02005B
+#define PRL7CDT 0x0C02005C
+#define PRL8 0x0C02005D
+#define PRL8CDT 0x0C02005E
+#define SHO1 0x0C02005F
+#define SHO1CDT 0x0C020060
+#define SHO2 0x0C020061
+#define SHO2CDT 0x0C020062
+#define SHT1 0x0C020063
+#define SHT1CDT 0x0C020064
+#define SHT2 0x0C020065
+#define SHT2CDT 0x0C020066
+#define SHT3 0x0C020067
+#define SHT3CDT 0x0C020068
+#define STA2 0x0C020069
+#define STA2CDT 0x0C02006A
+#define STEAM45 0x0C02006B
+#define STEAM45CDT 0x0C02006C
+#define TRUCK45 0x0C02006D
+#define TRUCK45CDT 0x0C02006E
+#define TRUCKEMP 0x0C02006F
+#define TRUCKEMPCDT 0x0C020070
+#define ULT6 0x0C020071
+#define ULT6CDT 0x0C020072
+#define ULT7 0x0C020073
+#define ULT7CDT 0x0C020074
+#define ULT8 0x0C020075
+#define ULT8CDT 0x0C020076
+#define ULT9 0x0C020077
+#define ULT9CDT 0x0C020078
+#define XGEOMON3 0x0C020079
+#define XGEOMON3CDT 0x0C02007A
+#define XGEOMON5 0x0C02007B
+#define XGEOMON5CDT 0x0C02007C
+#define XGEOSTA3 0x0C02007D
+#define XGEOSTA3CDT 0x0C02007E
+#define XGEOSTA5 0x0C02007F
+#define XGEOSTA5CDT 0x0C020080
+#define XGEOSTAT 0x0C020081
+#define XGEOSTATCDT 0x0C020082
+ // 131 entities in TXTs, 131 in datafiles.
+ // room47
+#define R47L0 0x0C030000
+#define R47L1 0x0C030001
+#define R47L2 0x0C030002
+#define R47G1 0x0C030003
+#define R47G2 0x0C030004
+#define R47PAL 0x0C030005
+#define R47FLR 0x0C030006
+#define CAR1 0x0C030007
+#define CAR1CDT 0x0C030008
+#define CAR2 0x0C030009
+#define CAR2CDT 0x0C03000A
+#define CAR3 0x0C03000B
+#define CAR3CDT 0x0C03000C
+#define CAR4 0x0C03000D
+#define CAR4CDT 0x0C03000E
+#define CAR5 0x0C03000F
+#define CAR5CDT 0x0C030010
+#define CAR6 0x0C030011
+#define CAR6CDT 0x0C030012
+#define CRPMOV 0x0C030013
+#define CRPMOVCDT 0x0C030014
+#define GEOSYR3 0x0C030015
+#define GEOSYR3CDT 0x0C030016
+#define GEOSYR3A 0x0C030017
+#define GEOSYR3ACDT 0x0C030018
+#define GEOSYR4 0x0C030019
+#define GEOSYR4CDT 0x0C03001A
+#define GEOSYR4A 0x0C03001B
+#define GEOSYR4ACDT 0x0C03001C
+ // 29 entities in TXTs, 29 in datafiles.
+ // room49
+#define R49L0 0x0C040000
+#define R49L1 0x0C040001
+#define R49L2 0x0C040002
+#define R49G1 0x0C040003
+#define R49G2 0x0C040004
+#define R49PAL 0x0C040005
+#define R49FLR 0x0C040006
+#define DOOR49 0x0C040007
+#define DOOR49CDT 0x0C040008
+#define DOOR49CDR 0x0C040009
+#define GEOKEYS1 0x0C04000A
+#define GEOKEYS1CDT 0x0C04000B
+#define GEOSYR43 0x0C04000C
+#define GEOSYR43CDT 0x0C04000D
+#define KEYS 0x0C04000E
+#define KEYSCDT 0x0C04000F
+#define MAN1 0x0C040010
+#define MAN1CDT 0x0C040011
+#define MAN2 0x0C040012
+#define MAN2CDT 0x0C040013
+#define MAN3 0x0C040014
+#define MAN3CDT 0x0C040015
+#define MAN4 0x0C040016
+#define MAN4CDT 0x0C040017
+#define MAN4A 0x0C040018
+#define MAN4ACDT 0x0C040019
+#define ULT10 0x0C04001A
+#define ULT10CDT 0x0C04001B
+#define ULT15 0x0C04001C
+#define ULT15CDT 0x0C04001D
+#define ULT3 0x0C04001E
+#define ULT3CDT 0x0C04001F
+#define ULTTAK 0x0C040020
+#define ULTTAKCDT 0x0C040021
+ // 34 entities in TXTs, 34 in datafiles.
+ // room50
+#define R50L0 0x0C050000
+#define R50L1 0x0C050001
+#define R50L2 0x0C050002
+#define R50L3 0x0C050003
+#define R50G1 0x0C050004
+#define R50G2 0x0C050005
+#define R50G3 0x0C050006
+#define R50PAL 0x0C050007
+#define R50FLR 0x0C050008
+#define CHAIN50 0x0C050009
+#define CHAIN50CDT 0x0C05000A
+#define CUBDOR50 0x0C05000B
+#define CUBDOR50CDT 0x0C05000C
+#define DOOR50 0x0C05000D
+#define DOOR50CDT 0x0C05000E
+#define DOOR50CDR 0x0C05000F
+#define GEOSYR48 0x0C050010
+#define GEOSYR48CDT 0x0C050011
+#define GEOSYR49 0x0C050012
+#define GEOSYR49CDT 0x0C050013
+#define GEOSYR50 0x0C050014
+#define GEOSYR50CDT 0x0C050015
+#define GEOSYR51 0x0C050016
+#define GEOSYR51CDT 0x0C050017
+#define GEOSYR51CDR 0x0C050018
+#define GEOSYR52 0x0C050019
+#define GEOSYR52CDT 0x0C05001A
+#define GEOSYR53 0x0C05001B
+#define GEOSYR53CDT 0x0C05001C
+#define GEOSYR54 0x0C05001D
+#define GEOSYR54CDT 0x0C05001E
+#define TOWEL1 0x0C05001F
+#define TOWEL1CDT 0x0C050020
+#define TOWEL4 0x0C050021
+#define TOWEL4CDT 0x0C050022
+ // 35 entities in TXTs, 35 in datafiles.
+ // room53
+#define R53L0 0x0C060000
+#define R53PAL 0x0C060001
+#define BACK53PLX 0x0C060002
+#define FRONT53PLX 0x0C060003
+#define R53SPRPAL 0x0C060004
+ // 5 entities in TXTs, 5 in datafiles.
+ // room54
+#define R54L0 0x0C070000
+#define R54L1 0x0C070001
+#define R54G1 0x0C070002
+#define R54PAL 0x0C070003
+#define R54FLR 0x0C070004
+#define R54PLX 0x0C070005
+#define GEOSYR19 0x0C070006
+#define GEOSYR19CDT 0x0C070007
+#define GEOSYR20 0x0C070008
+#define GEOSYR20CDT 0x0C070009
+#define GEOSYR22 0x0C07000A
+#define GEOSYR22CDT 0x0C07000B
+#define GEOSYR23 0x0C07000C
+#define GEOSYR23CDT 0x0C07000D
+#define GEOSYR25 0x0C07000E
+#define GEOSYR25CDT 0x0C07000F
+#define GEOSYR26 0x0C070010
+#define GEOSYR26CDT 0x0C070011
+#define GEOSYR27 0x0C070012
+#define GEOSYR27CDT 0x0C070013
+#define GEOSYR37 0x0C070014
+#define GEOSYR37CDT 0x0C070015
+#define GEOSYR39 0x0C070016
+#define GEOSYR39CDT 0x0C070017
+#define GEOSYR40 0x0C070018
+#define GEOSYR40CDT 0x0C070019
+#define GEOSYR41 0x0C07001A
+#define GEOSYR41CDT 0x0C07001B
+#define GEOSYR42 0x0C07001C
+#define GEOSYR42CDT 0x0C07001D
+#define GEOSYR99 0x0C07001E
+#define GEOSYR99CDT 0x0C07001F
+#define GUN54 0x0C070020
+#define GUN54CDT 0x0C070021
+#define KHS10 0x0C070022
+#define KHS10CDT 0x0C070023
+#define KHS12 0x0C070024
+#define KHS12CDT 0x0C070025
+#define KHS5 0x0C070026
+#define KHS5CDT 0x0C070027
+#define KHS7 0x0C070028
+#define KHS7CDT 0x0C070029
+#define KHS8 0x0C07002A
+#define KHS8CDT 0x0C07002B
+#define KHS9 0x0C07002C
+#define KHS9CDT 0x0C07002D
+#define KHSTLK54 0x0C07002E
+#define KHSTLK54CDT 0x0C07002F
+#define SECDOR 0x0C070030
+#define SECDORCDT 0x0C070031
+#define STCKTREE 0x0C070032
+#define STCKTREECDT 0x0C070033
+#define STICKIN 0x0C070034
+#define STICKINCDT 0x0C070035
+#define XGEOSY21 0x0C070036
+#define XGEOSY21CDT 0x0C070037
+ // 56 entities in TXTs, 56 in datafiles.
+ // room55
+#define R55SPRPAL 0x0C080000
+#define R55L0 0x0C080001
+#define R55PAL 0x0C080002
+#define R55FLR 0x0C080003
+#define R55PLX 0x0C080004
+#define BODY55 0x0C080005
+#define BODY55CDT 0x0C080006
+#define BRITMAP 0x0C080007
+#define BRITMAP_PAL 0x0C080008
+#define DOOR55 0x0C080009
+#define DOOR55CDT 0x0C08000A
+#define DOOR55CDR 0x0C08000B
+#define GEOSY30T 0x0C08000C
+#define GEOSY30TCDT 0x0C08000D
+#define GEOSY30U 0x0C08000E
+#define GEOSY30UCDT 0x0C08000F
+#define GEOSYR29 0x0C080010
+#define GEOSYR29CDT 0x0C080011
+#define GEOSYR30 0x0C080012
+#define GEOSYR30CDT 0x0C080013
+#define GEOSYR31 0x0C080014
+#define GEOSYR31CDT 0x0C080015
+#define GEOSYR33 0x0C080016
+#define GEOSYR33CDT 0x0C080017
+#define GEOSYR34 0x0C080018
+#define GEOSYR34CDT 0x0C080019
+#define GEOSYR34CDR 0x0C08001A
+#define GEOSYR35 0x0C08001B
+#define GEOSYR35CDT 0x0C08001C
+#define GEOSYR56 0x0C08001D
+#define GEOSYR56CDT 0x0C08001E
+#define KHS2 0x0C08001F
+#define KHS2CDT 0x0C080020
+#define KHS3 0x0C080021
+#define KHS3CDT 0x0C080022
+#define KHS6 0x0C080023
+#define KHS6CDT 0x0C080024
+ // 37 entities in TXTs, 37 in datafiles.
+// train
+ // sound_fx
+#define FX_SHOCK63 0x0D000000
+#define FX_TRAINEXT 0x0D000001
+#define FX_TRAININT 0x0D000002
+#define FX_DOOR65 0x0D000003
+#define FX_WIND66 0x0D000004
+#define FX_WINDOW66 0x0D000005
+#define FX_BRAKES 0x0D000006
+#define FX_DOOR69 0x0D000007
+#define FX_EKSHOOT 0x0D000008
+#define FX_FIGHT69 0x0D000009
+#define FX_PNEUMO69 0x0D00000A
+#define FX_TICK69 0x0D00000B
+#define FX_TRNPASS 0x0D00000C
+ // 13 entities in TXTs, 13 in datafiles.
+ // room63
+#define TRAIN_PAL 0x0D010000
+#define R63L0 0x0D010001
+#define R63L1 0x0D010002
+#define R63G1 0x0D010003
+#define R63PAL 0x0D010004
+#define R63FLR 0x0D010005
+#define GEOTRAIN_MEGA 0x0D010006
+#define GEOTRAIN_WLK 0x0D010007
+#define BASHER63 0x0D010008
+#define BASHER63CDT 0x0D010009
+#define BOXDOR64 0x0D01000A
+#define BOXDOR64CDT 0x0D01000B
+#define BUSHA63 0x0D01000C
+#define BUSHA63CDT 0x0D01000D
+#define BUSHB63 0x0D01000E
+#define BUSHB63CDT 0x0D01000F
+#define BUSHC63 0x0D010010
+#define BUSHC63CDT 0x0D010011
+#define DOOR63C1 0x0D010012
+#define DOOR63C1CDT 0x0D010013
+#define DOOR63C1CDR 0x0D010014
+#define DOOR63C2 0x0D010015
+#define DOOR63C2CDT 0x0D010016
+#define DOOR63C2CDR 0x0D010017
+#define DOOR63C3 0x0D010018
+#define DOOR63C3CDT 0x0D010019
+#define DOOR63C3CDR 0x0D01001A
+#define GEOCLI64 0x0D01001B
+#define GEOCLI64CDT 0x0D01001C
+#define GEOJGL64 0x0D01001D
+#define GEOJGL64CDT 0x0D01001E
+#define GEOJGR64 0x0D01001F
+#define GEOJGR64CDT 0x0D010020
+#define GEOLAD64 0x0D010021
+#define GEOLAD64CDT 0x0D010022
+#define GEOSHK64 0x0D010023
+#define GEOSHK64CDT 0x0D010024
+#define GEOSTDL 0x0D010025
+#define GEOSTDLCDT 0x0D010026
+#define GEOSTDR 0x0D010027
+#define GEOSTDRCDT 0x0D010028
+#define GUIDOR63 0x0D010029
+#define GUIDOR63CDT 0x0D01002A
+#define GUIDSM63 0x0D01002B
+#define GUIDSM63CDT 0x0D01002C
+#define LADY63 0x0D01002D
+#define LADY63CDT 0x0D01002E
+#define LIGHT63A 0x0D01002F
+#define LIGHT63ACDT 0x0D010030
+#define LIGHT63B 0x0D010031
+#define LIGHT63BCDT 0x0D010032
+#define LIGHT63C 0x0D010033
+#define LIGHT63CCDT 0x0D010034
+#define LIGHT63D 0x0D010035
+#define LIGHT63DCDT 0x0D010036
+#define LIGHT63E 0x0D010037
+#define LIGHT63ECDT 0x0D010038
+#define NICO63 0x0D010039
+#define NICO63CDT 0x0D01003A
+#define POLE63 0x0D01003B
+#define POLE63CDT 0x0D01003C
+#define WHEELA63 0x0D01003D
+#define WHEELA63CDT 0x0D01003E
+#define WHEELB63 0x0D01003F
+#define WHEELB63CDT 0x0D010040
+#define WHEELC63 0x0D010041
+#define WHEELC63CDT 0x0D010042
+#define WHEELD63 0x0D010043
+#define WHEELD63CDT 0x0D010044
+#define WHEELE63 0x0D010045
+#define WHEELE63CDT 0x0D010046
+#define WHEELF63 0x0D010047
+#define WHEELF63CDT 0x0D010048
+ // 73 entities in TXTs, 73 in datafiles.
+ // room65
+#define R65L0 0x0D020000
+#define R65L1 0x0D020001
+#define R65G1 0x0D020002
+#define R65PAL 0x0D020003
+#define R65FLR 0x0D020004
+#define DOOR65 0x0D020005
+#define DOOR65CDT 0x0D020006
+#define DOOR65CDR 0x0D020007
+#define GEOGUA 0x0D020008
+#define GEOGUACDT 0x0D020009
+#define GEOLNK3 0x0D02000A
+#define GEOLNK3CDT 0x0D02000B
+#define GEONIC65 0x0D02000C
+#define GEONIC65CDT 0x0D02000D
+#define GEOSIT 0x0D02000E
+#define GEOSITCDT 0x0D02000F
+#define GEOSIT65 0x0D020010
+#define GEOSIT65CDT 0x0D020011
+#define GEOSTD65 0x0D020012
+#define GEOSTD65CDT 0x0D020013
+#define GEOSTD65CDR 0x0D020014
+#define GEOTIK 0x0D020015
+#define GEOTIKCDT 0x0D020016
+#define GEOTN652 0x0D020017
+#define GEOTN652CDT 0x0D020018
+#define GEOTN652CDR 0x0D020019
+#define GEOTRN65 0x0D02001A
+#define GEOTRN65CDT 0x0D02001B
+#define GEOTRN65CDR 0x0D02001C
+#define GUADOR65 0x0D02001D
+#define GUADOR65CDT 0x0D02001E
+#define GUALEA65 0x0D02001F
+#define GUALEA65CDT 0x0D020020
+#define GUATGN 0x0D020021
+#define GUATGNCDT 0x0D020022
+#define GUATGNCDR 0x0D020023
+#define GUATIK1 0x0D020024
+#define GUATIK1CDT 0x0D020025
+#define GUATIK2 0x0D020026
+#define GUATIK2CDT 0x0D020027
+#define GUATLK1 0x0D020028
+#define GUATLK1CDT 0x0D020029
+#define GUATLK2 0x0D02002A
+#define GUATLK2CDT 0x0D02002B
+#define NICGEO65 0x0D02002C
+#define NICGEO65CDT 0x0D02002D
+#define NICSIT65 0x0D02002E
+#define NICSIT65CDT 0x0D02002F
+#define NICTRN65 0x0D020030
+#define NICTRN65CDT 0x0D020031
+#define NICTRN65CDR 0x0D020032
+#define OLDREAD 0x0D020033
+#define OLDREADCDT 0x0D020034
+#define OLDREADCDR 0x0D020035
+#define OLDTIK1 0x0D020036
+#define OLDTIK1CDT 0x0D020037
+#define OLDTLK1 0x0D020038
+#define OLDTLK1CDT 0x0D020039
+ // 58 entities in TXTs, 58 in datafiles.
+ // room66
+#define R66L0 0x0D030000
+#define R66PAL 0x0D030001
+#define R66FLR 0x0D030002
+#define BASHBURP 0x0D030003
+#define BASHBURPCDT 0x0D030004
+#define BASHCAN 0x0D030005
+#define BASHCANCDT 0x0D030006
+#define BASHCLA 0x0D030007
+#define BASHCLACDT 0x0D030008
+#define BASHDRI 0x0D030009
+#define BASHDRICDT 0x0D03000A
+#define BASHSTD 0x0D03000B
+#define BASHSTDCDT 0x0D03000C
+#define BASHTLK1 0x0D03000D
+#define BASHTLK1CDT 0x0D03000E
+#define CAN66 0x0D03000F
+#define CAN66CDT 0x0D030010
+#define GEOLEA 0x0D030011
+#define GEOLEACDT 0x0D030012
+#define GEOOPN1 0x0D030013
+#define GEOOPN1CDT 0x0D030014
+#define GEOOUT66 0x0D030015
+#define GEOOUT66CDT 0x0D030016
+#define SLEEPY1 0x0D030017
+#define SLEEPY1CDT 0x0D030018
+#define SLEEPY1CDR 0x0D030019
+#define SLEEPY2 0x0D03001A
+#define SLEEPY2CDT 0x0D03001B
+ // 28 entities in TXTs, 28 in datafiles.
+ // room67
+#define R67L0 0x0D040000
+#define R67L1 0x0D040001
+#define R67G1 0x0D040002
+#define R67PAL 0x0D040003
+#define R67FLR 0x0D040004
+#define DOOR67 0x0D040005
+#define DOOR67CDT 0x0D040006
+#define DOOR67CDR 0x0D040007
+ // 8 entities in TXTs, 8 in datafiles.
+ // room69
+#define R69SPRPAL 0x0D050000
+#define R69L0 0x0D050001
+#define R69L1 0x0D050002
+#define R69G1 0x0D050003
+#define R69PAL 0x0D050004
+#define R69FLR 0x0D050005
+#define ASSDIE69 0x0D050006
+#define ASSDIE69CDT 0x0D050007
+#define ASSDWN69 0x0D050008
+#define ASSDWN69CDT 0x0D050009
+#define ASSLIFT 0x0D05000A
+#define ASSLIFTCDT 0x0D05000B
+#define ASSTLK69 0x0D05000C
+#define ASSTLK69CDT 0x0D05000D
+#define BOXES69 0x0D05000E
+#define BOXES69CDT 0x0D05000F
+#define EKLBOX69 0x0D050010
+#define EKLBOX69CDT 0x0D050011
+#define EKLGUN 0x0D050012
+#define EKLGUNCDT 0x0D050013
+#define EKLGUN69 0x0D050014
+#define EKLGUN69CDT 0x0D050015
+#define EKLTLK69 0x0D050016
+#define EKLTLK69CDT 0x0D050017
+#define EKLFIGHT 0x0D050018
+#define EKLFIGHTCDT 0x0D050019
+#define FIGHT69 0x0D05001A
+#define FIGHT69CDT 0x0D05001B
+#define GEODIE69 0x0D05001C
+#define GEODIE69CDT 0x0D05001D
+#define GEOENT69 0x0D05001E
+#define GEOENT69CDT 0x0D05001F
+#define GEOSTD69 0x0D050020
+#define GEOSTD69CDT 0x0D050021
+#define GEOSTP69 0x0D050022
+#define GEOSTP69CDT 0x0D050023
+#define GEOTLK69 0x0D050024
+#define GEOTLK69CDT 0x0D050025
+#define GEOUNTIE 0x0D050026
+#define GEOUNTIECDT 0x0D050027
+#define GEOXIT69 0x0D050028
+#define GEOXIT69CDT 0x0D050029
+#define NICTKB69 0x0D05002A
+#define NICTKB69CDT 0x0D05002B
+#define NICTLK69 0x0D05002C
+#define NICTLK69CDT 0x0D05002D
+#define NICTRN69 0x0D05002E
+#define NICTRN69CDT 0x0D05002F
+#define NICTRN69CDR 0x0D050030
+#define NICTUG69 0x0D050031
+#define NICTUG69CDT 0x0D050032
+#define NICWLK69 0x0D050033
+#define NICWLK69CDT 0x0D050034
+#define NICXIT69 0x0D050035
+#define NICXIT69CDT 0x0D050036
+#define RGTDOR69 0x0D050037
+#define RGTDOR69CDT 0x0D050038
+ // 57 entities in TXTs, 57 in datafiles.
+// scotland
+ // sound_fx
+#define FX_WIND71 0x0E000000
+#define FX_GUST71 0x0E000001
+#define FX_OWL71A 0x0E000002
+#define FX_OWL71B 0x0E000003
+#define FX_COG72A 0x0E000004
+#define FX_PING 0x0E000005
+#define FX_RUMMAGE1 0x0E000006
+#define FX_RUMMAGE2 0x0E000007
+#define FX_SECDOR72 0x0E000008
+#define FX_CHANT 0x0E000009
+#define FX_DAGGER1 0x0E00000A
+#define FX_GDROP73 0x0E00000B
+#define FX_GUNPOWDR 0x0E00000C
+#define FX_STAFF 0x0E00000D
+#define FX_TORCH73 0x0E00000E
+#define FX_BAPHAMB 0x0E00000F
+#define FX_FIGHT1 0x0E000010
+#define FX_REFORGE2 0x0E000011
+#define FX_ROSSODIE 0x0E000012
+#define FX_GKSWORD 0x0E000013
+#define FX_REFORGE1 0x0E000014
+#define FX_REFORGE4 0x0E000015
+#define FX_CHOKE1 0x0E000016
+#define FX_CHOKE2 0x0E000017
+#define FX_EKDIES 0x0E000018
+#define FX_FIGHT2 0x0E000019
+#define FX_GUN79 0x0E00001A
+ // 27 entities in TXTs, 27 in datafiles.
+ // room71
+#define R71L0 0x0E010000
+#define R71L1 0x0E010001
+#define R71G1 0x0E010002
+#define R71PAL 0x0E010003
+#define R71FLR 0x0E010004
+#define R71PLX 0x0E010005
+ // 6 entities in TXTs, 6 in datafiles.
+ // room72
+#define R72L0 0x0E020000
+#define R72L1 0x0E020001
+#define R72G1 0x0E020002
+#define R72PAL 0x0E020003
+#define R72FLR 0x0E020004
+#define COGL72 0x0E020005
+#define COGL72CDT 0x0E020006
+#define COGR72 0x0E020007
+#define COGR72CDT 0x0E020008
+#define GEOJMP72 0x0E020009
+#define GEOJMP72CDT 0x0E02000A
+#define GEOPIPE 0x0E02000B
+#define GEOPIPECDT 0x0E02000C
+#define GEOPIPECDR 0x0E02000D
+#define GEOPSH72 0x0E02000E
+#define GEOPSH72CDT 0x0E02000F
+#define GEOPUT72 0x0E020010
+#define GEOPUT72CDT 0x0E020011
+#define GEOTAK72 0x0E020012
+#define GEOTAK72CDT 0x0E020013
+#define GEOTAK72CDR 0x0E020014
+#define GEOTRY72 0x0E020015
+#define GEOTRY72CDT 0x0E020016
+#define GEOWIND2 0x0E020017
+#define GEOWIND2CDT 0x0E020018
+#define GEOWIND3 0x0E020019
+#define GEOWIND3CDT 0x0E02001A
+#define GEOWIND4 0x0E02001B
+#define GEOWIND4CDT 0x0E02001C
+#define GEOWND72 0x0E02001D
+#define GEOWND72CDT 0x0E02001E
+#define HANDLE72 0x0E02001F
+#define HANDLE72CDT 0x0E020020
+#define NICGEO72 0x0E020021
+#define NICGEO72CDT 0x0E020022
+#define NICJMP72 0x0E020023
+#define NICJMP72CDT 0x0E020024
+#define NICLNK72 0x0E020025
+#define NICLNK72CDT 0x0E020026
+#define NICLNK72CDR 0x0E020027
+#define NICOPY72 0x0E020028
+#define NICOPY72CDT 0x0E020029
+#define NICOPY72CDR 0x0E02002A
+#define NICTLK72 0x0E02002B
+#define NICTLK72CDT 0x0E02002C
+#define NOSE72 0x0E02002D
+#define NOSE72CDT 0x0E02002E
+#define PANEL72 0x0E02002F
+#define PANEL72CDT 0x0E020030
+#define PIPE72 0x0E020031
+#define PIPE72CDT 0x0E020032
+#define SPINDL72 0x0E020033
+#define SPINDL72CDT 0x0E020034
+#define WHEEL72 0x0E020035
+#define WHEEL72CDT 0x0E020036
+ // 55 entities in TXTs, 55 in datafiles.
+ // room73
+#define R73SPRPAL 0x0E030000
+#define R73L0 0x0E030001
+#define R73L1 0x0E030002
+#define R73L2 0x0E030003
+#define R73G1 0x0E030004
+#define R73G2 0x0E030005
+#define R73PAL 0x0E030006
+#define R73FLR 0x0E030007
+#define DAGGER1 0x0E030008
+#define DAGGER1CDT 0x0E030009
+#define DAGGER2 0x0E03000A
+#define DAGGER2CDT 0x0E03000B
+#define DARKWALL 0x0E03000C
+#define DARKWALLCDT 0x0E03000D
+#define FLAME73 0x0E03000E
+#define FLAME73CDT 0x0E03000F
+#define GEOCRCH 0x0E030010
+#define GEOCRCHCDT 0x0E030011
+#define GEOCREEP 0x0E030012
+#define GEOCREEPCDT 0x0E030013
+#define GEODIE1 0x0E030014
+#define GEODIE1CDT 0x0E030015
+#define GEODIE2 0x0E030016
+#define GEODIE2CDT 0x0E030017
+#define GEOTHROW 0x0E030018
+#define GEOTHROWCDT 0x0E030019
+#define GEOTLK73 0x0E03001A
+#define GEOTLK73CDT 0x0E03001B
+#define GEOTN73 0x0E03001C
+#define GEOTN73CDT 0x0E03001D
+#define GEOTN73CDR 0x0E03001E
+#define GMENTER 0x0E03001F
+#define GMENTERCDT 0x0E030020
+#define GMSPEAK 0x0E030021
+#define GMSPEAKCDT 0x0E030022
+#define GUIDLE 0x0E030023
+#define GUIDLECDT 0x0E030024
+#define GUITALK 0x0E030025
+#define GUITALKCDT 0x0E030026
+#define GUITHROW 0x0E030027
+#define GUITHROWCDT 0x0E030028
+#define GUITURN7 0x0E030029
+#define GUITURN7CDT 0x0E03002A
+#define GUITURN7CDR 0x0E03002B
+#define NICENT73 0x0E03002C
+#define NICENT73CDT 0x0E03002D
+#define NICEX73 0x0E03002E
+#define NICEX73CDT 0x0E03002F
+#define NICOTHRO 0x0E030030
+#define NICOTHROCDT 0x0E030031
+#define NICPANIC 0x0E030032
+#define NICPANICCDT 0x0E030033
+#define NICTLK73 0x0E030034
+#define NICTLK73CDT 0x0E030035
+#define NICTRN73 0x0E030036
+#define NICTRN73CDT 0x0E030037
+#define NICTRN73CDR 0x0E030038
+#define NITALK73 0x0E030039
+#define NITALK73CDT 0x0E03003A
+#define SPARKING 0x0E03003B
+#define SPARKINGCDT 0x0E03003C
+#define TORCH1 0x0E03003D
+#define TORCH1CDT 0x0E03003E
+#define TORCH2 0x0E03003F
+#define TORCH2CDT 0x0E030040
+#define TORCH3 0x0E030041
+#define TORCH3CDT 0x0E030042
+ // 67 entities in TXTs, 67 in datafiles.
+ // room74
+#define ENDSPRPAL 0x0E040000
+#define R74L0 0x0E040001
+#define R74L1 0x0E040002
+#define R74G1 0x0E040003
+#define R74PAL 0x0E040004
+#define R74APAL 0x0E040005
+#define R74BPAL 0x0E040006
+#define R74CPAL 0x0E040007
+#define R74DPAL 0x0E040008
+#define CHANT74 0x0E040009
+#define CHANT74CDT 0x0E04000A
+#define EKFIGHT 0x0E04000B
+#define EKFIGHTCDT 0x0E04000C
+#define EKGUN74 0x0E04000D
+#define EKGUN74CDT 0x0E04000E
+#define GEOFIGHT 0x0E04000F
+#define GEOFIGHTCDT 0x0E040010
+#define GEOLUK74 0x0E040011
+#define GEOLUK74CDT 0x0E040012
+#define GEOLUK74CDR 0x0E040013
+#define GEORCT74 0x0E040014
+#define GEORCT74CDT 0x0E040015
+#define GEORUN74 0x0E040016
+#define GEORUN74CDT 0x0E040017
+#define GEOSTND 0x0E040018
+#define GEOSTNDCDT 0x0E040019
+#define GEOTLK74 0x0E04001A
+#define GEOTLK74CDT 0x0E04001B
+#define GKKNEE 0x0E04001C
+#define GKKNEECDT 0x0E04001D
+#define GMGUN 0x0E04001E
+#define GMGUNCDT 0x0E04001F
+#define GMMOV1 0x0E040020
+#define GMMOV1CDT 0x0E040021
+#define GMMOV2 0x0E040022
+#define GMMOV2CDT 0x0E040023
+#define GMMOV3 0x0E040024
+#define GMMOV3CDT 0x0E040025
+#define GMMOV4 0x0E040026
+#define GMMOV4CDT 0x0E040027
+#define GMMOV5 0x0E040028
+#define GMMOV5CDT 0x0E040029
+#define GMMOV6 0x0E04002A
+#define GMMOV6CDT 0x0E04002B
+#define GMTLK1 0x0E04002C
+#define GMTLK1CDT 0x0E04002D
+#define GMTLK2 0x0E04002E
+#define GMTLK2CDT 0x0E04002F
+#define GMTLK3 0x0E040030
+#define GMTLK3CDT 0x0E040031
+#define GMTLK4 0x0E040032
+#define GMTLK4CDT 0x0E040033
+#define GMTLK5 0x0E040034
+#define GMTLK5CDT 0x0E040035
+#define GMTLK6 0x0E040036
+#define GMTLK6CDT 0x0E040037
+#define GMTLK7 0x0E040038
+#define GMTLK7CDT 0x0E040039
+#define GMTLK74 0x0E04003A
+#define GMTLK74CDT 0x0E04003B
+#define GMWLK 0x0E04003C
+#define GMWLKCDT 0x0E04003D
+#define GMWRIT74 0x0E04003E
+#define GMWRIT74CDT 0x0E04003F
+#define MONKFALL 0x0E040040
+#define MONKFALLCDT 0x0E040041
+#define MONKRISE 0x0E040042
+#define MONKRISECDT 0x0E040043
+#define MONKSTRS 0x0E040044
+#define MONKSTRSCDT 0x0E040045
+#define MONKTURN 0x0E040046
+#define MONKTURNCDT 0x0E040047
+#define NICFIGHT 0x0E040048
+#define NICFIGHTCDT 0x0E040049
+#define NICLUK74 0x0E04004A
+#define NICLUK74CDT 0x0E04004B
+#define NICLUK74CDR 0x0E04004C
+#define NICRCVR 0x0E04004D
+#define NICRCVRCDT 0x0E04004E
+#define NICRUN74 0x0E04004F
+#define NICRUN74CDT 0x0E040050
+#define NICSTND 0x0E040051
+#define NICSTNDCDT 0x0E040052
+#define NICTLK74 0x0E040053
+#define NICTLK74CDT 0x0E040054
+#define ROSSFALL 0x0E040055
+#define ROSSFALLCDT 0x0E040056
+#define ROSSTAIR 0x0E040057
+#define ROSSTAIRCDT 0x0E040058
+#define ROSSTND 0x0E040059
+#define ROSSTNDCDT 0x0E04005A
+#define ROSSWLK 0x0E04005B
+#define ROSSWLKCDT 0x0E04005C
+#define RUBBLE 0x0E04005D
+#define RUBBLECDT 0x0E04005E
+#define STONLIT1 0x0E04005F
+#define STONLIT1CDT 0x0E040060
+#define STONLIT2 0x0E040061
+#define STONLIT2CDT 0x0E040062
+#define STONWHT1 0x0E040063
+#define STONWHT1CDT 0x0E040064
+#define STONWHT2 0x0E040065
+#define STONWHT2CDT 0x0E040066
+ // 103 entities in TXTs, 103 in datafiles.
+ // room75
+#define R75L0 0x0E050000
+#define R75PAL 0x0E050001
+#define R75APAL 0x0E050002
+#define R75BPAL 0x0E050003
+#define R75CPAL 0x0E050004
+#define R75DPAL 0x0E050005
+#define EKGUN 0x0E050006
+#define EKGUNCDT 0x0E050007
+#define EKGUN2 0x0E050008
+#define EKGUN2CDT 0x0E050009
+#define EKLITE 0x0E05000A
+#define EKLITECDT 0x0E05000B
+#define EKRELAX 0x0E05000C
+#define EKRELAXCDT 0x0E05000D
+#define EKTLK75 0x0E05000E
+#define EKTLK75CDT 0x0E05000F
+#define GEOLUK75 0x0E050010
+#define GEOLUK75CDT 0x0E050011
+#define GEOLUK75CDR 0x0E050012
+#define GTMP 0x0E050013
+#define GTMPCDT 0x0E050014
+#define NICLUK75 0x0E050015
+#define NICLUK75CDT 0x0E050016
+#define NICLUK75CDR 0x0E050017
+#define NTMP 0x0E050018
+#define NTMPCDT 0x0E050019
+#define TORCH75 0x0E05001A
+#define TORCH75CDT 0x0E05001B
+ // 28 entities in TXTs, 28 in datafiles.
+ // room76
+#define R76L0 0x0E060000
+#define R76PAL 0x0E060001
+#define CHANT76 0x0E060002
+#define CHANT76CDT 0x0E060003
+#define EKGUN76 0x0E060004
+#define EKGUN76CDT 0x0E060005
+#define GKBAK 0x0E060006
+#define GKBAKCDT 0x0E060007
+#define GKKNEE76 0x0E060008
+#define GKKNEE76CDT 0x0E060009
+#define GKLOWER 0x0E06000A
+#define GKLOWERCDT 0x0E06000B
+#define GKSWORD 0x0E06000C
+#define GKSWORDCDT 0x0E06000D
+#define GKTLK 0x0E06000E
+#define GKTLKCDT 0x0E06000F
+#define GKTLK2 0x0E060010
+#define GKTLK2CDT 0x0E060011
+#define GMARMS 0x0E060012
+#define GMARMSCDT 0x0E060013
+#define GMSTONES 0x0E060014
+#define GMSTONESCDT 0x0E060015
+#define GMTLK76 0x0E060016
+#define GMTLK76CDT 0x0E060017
+#define GMTRN76 0x0E060018
+#define GMTRN76CDT 0x0E060019
+#define LSTONE76 0x0E06001A
+#define LSTONE76CDT 0x0E06001B
+#define MONKNEE 0x0E06001C
+#define MONKNEECDT 0x0E06001D
+#define ROSSTND76 0x0E06001E
+#define ROSSTND76CDT 0x0E06001F
+#define RSTONE76 0x0E060020
+#define RSTONE76CDT 0x0E060021
+ // 34 entities in TXTs, 34 in datafiles.
+ // room77
+#define R77L0 0x0E070000
+#define R77PAL 0x0E070001
+#define CHANT77 0x0E070002
+#define CHANT77CDT 0x0E070003
+#define GEOPEER 0x0E070004
+#define GEOPEERCDT 0x0E070005
+#define GMHEAD 0x0E070006
+#define GMHEADCDT 0x0E070007
+#define NICPEER 0x0E070008
+#define NICPEERCDT 0x0E070009
+#define NICTLK77 0x0E07000A
+#define NICTLK77CDT 0x0E07000B
+#define ROSLUK77 0x0E07000C
+#define ROSLUK77CDT 0x0E07000D
+ // 14 entities in TXTs, 14 in datafiles.
+ // room78
+#define R78L0 0x0E080000
+#define R78PAL 0x0E080001
+#define R78APAL 0x0E080002
+#define R78BPAL 0x0E080003
+#define R78CPAL 0x0E080004
+#define R78DPAL 0x0E080005
+#define R78EPAL 0x0E080006
+#define R78FPAL 0x0E080007
+#define LSTONE78 0x0E080008
+#define LSTONE78CDT 0x0E080009
+#define LSTONE78CDR 0x0E08000A
+#define GMPOWER 0x0E08000B
+#define GMPOWERCDT 0x0E08000C
+#define GMWRITH 0x0E08000D
+#define GMWRITHCDT 0x0E08000E
+#define RSTONE78 0x0E08000F
+#define RSTONE78CDT 0x0E080010
+#define RSTONE78CDR 0x0E080011
+ // 18 entities in TXTs, 18 in datafiles.
+ // room79
+#define R79L0 0x0E090000
+#define R79PAL 0x0E090001
+#define EKSTD79 0x0E090002
+#define EKSTD79CDT 0x0E090003
+#define FIGHT79 0x0E090004
+#define FIGHT79CDT 0x0E090005
+#define GEOANG79 0x0E090006
+#define GEOANG79CDT 0x0E090007
+#define GEOTLK79 0x0E090008
+#define GEOTLK79CDT 0x0E090009
+#define NICSTD79 0x0E09000A
+#define NICSTD79CDT 0x0E09000B
+#define ROSENT79 0x0E09000C
+#define ROSENT79CDT 0x0E09000D
+#define ROSSHOT 0x0E09000E
+#define ROSSHOTCDT 0x0E09000F
+#define ROSTLK79 0x0E090010
+#define ROSTLK79CDT 0x0E090011
+ // 18 entities in TXTs, 18 in datafiles.
+
+} // End of namespace Sword1
+
+#endif //SWORDRES_H
diff --git a/engines/sword1/text.cpp b/engines/sword1/text.cpp
new file mode 100644
index 0000000000..d7e14073e9
--- /dev/null
+++ b/engines/sword1/text.cpp
@@ -0,0 +1,191 @@
+/* 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 "sword1/text.h"
+#include "sword1/resman.h"
+#include "sword1/objectman.h"
+#include "common/util.h"
+#include "sword1/swordres.h"
+#include "sword1/sworddefs.h"
+
+namespace Sword1 {
+
+#define OVERLAP 3
+#define SPACE ' '
+#define BORDER_COL 200
+#define LETTER_COL 193
+#define NO_COL 0 // sprite background - 0 for transparency
+#define MAX_LINES 30
+
+
+Text::Text(ObjectMan *pObjMan, ResMan *pResMan, bool czechVersion) {
+ _objMan = pObjMan;
+ _resMan = pResMan;
+ _textCount = 0;
+ _fontId = (czechVersion) ? CZECH_GAME_FONT : GAME_FONT;
+ _font = (uint8*)_resMan->openFetchRes(_fontId);
+
+ _joinWidth = charWidth( SPACE ) - 2 * OVERLAP;
+ _charHeight = FROM_LE_16(_resMan->fetchFrame(_font, 0)->height); // all chars have the same height
+ _textBlocks[0] = _textBlocks[1] = NULL;
+}
+
+Text::~Text(void) {
+ if (_textBlocks[0])
+ free(_textBlocks[0]);
+ if (_textBlocks[1])
+ free(_textBlocks[1]);
+ //_resMan->resClose(_fontId); => wiped automatically by _resMan->flush();
+}
+
+uint32 Text::lowTextManager(uint8 *ascii, int32 width, uint8 pen) {
+ _textCount++;
+ if (_textCount > MAX_TEXT_OBS)
+ error("Text::lowTextManager: MAX_TEXT_OBS exceeded!");
+ uint32 textObjId = (TEXT_sect * ITM_PER_SEC) - 1;
+ do {
+ textObjId++;
+ } while (_objMan->fetchObject(textObjId)->o_status);
+ // okay, found a free text object
+
+ _objMan->fetchObject(textObjId)->o_status = STAT_FORE;
+ makeTextSprite((uint8)textObjId, ascii, (uint16)width, pen);
+
+ return textObjId;
+}
+
+void Text::makeTextSprite(uint8 slot, uint8 *text, uint16 maxWidth, uint8 pen) {
+ LineInfo lines[MAX_LINES];
+ uint16 numLines = analyzeSentence(text, maxWidth, lines);
+
+ uint16 sprWidth = 0;
+ uint16 lineCnt;
+ for (lineCnt = 0; lineCnt < numLines; lineCnt++)
+ if (lines[lineCnt].width > sprWidth)
+ sprWidth = lines[lineCnt].width;
+ uint16 sprHeight = _charHeight * numLines;
+ uint32 sprSize = sprWidth * sprHeight;
+ assert(!_textBlocks[slot]); // if this triggers, the speechDriver failed to call Text::releaseText.
+ _textBlocks[slot] = (FrameHeader*)malloc(sprSize + sizeof(FrameHeader));
+
+ memcpy( _textBlocks[slot]->runTimeComp, "Nu ", 4);
+ _textBlocks[slot]->compSize = 0;
+ _textBlocks[slot]->width = TO_LE_16(sprWidth);
+ _textBlocks[slot]->height = TO_LE_16(sprHeight);
+ _textBlocks[slot]->offsetX = 0;
+ _textBlocks[slot]->offsetY = 0;
+
+ uint8 *linePtr = ((uint8*)_textBlocks[slot]) + sizeof(FrameHeader);
+ memset(linePtr, NO_COL, sprSize);
+ for (lineCnt = 0; lineCnt < numLines; lineCnt++) {
+ uint8 *sprPtr = linePtr + (sprWidth - lines[lineCnt].width) / 2; // center the text
+ for (uint16 pos = 0; pos < lines[lineCnt].length; pos++)
+ sprPtr += copyChar(*text++, sprPtr, sprWidth, pen) - OVERLAP;
+ text++; // skip space at the end of the line
+ linePtr += _charHeight * sprWidth;
+ }
+}
+
+uint16 Text::charWidth(uint8 ch) {
+ if (ch < SPACE)
+ ch = 64;
+ return FROM_LE_16(_resMan->fetchFrame(_font, ch - SPACE)->width);
+}
+
+uint16 Text::analyzeSentence(uint8 *text, uint16 maxWidth, LineInfo *line) {
+ uint16 lineNo = 0;
+
+ bool firstWord = true;
+ while (*text) {
+ uint16 wordWidth = 0;
+ uint16 wordLength = 0;
+
+ while ((*text != SPACE) && *text) {
+ wordWidth += charWidth(*text) - OVERLAP;
+ wordLength++;
+ text++;
+ }
+ if (*text == SPACE)
+ text++;
+
+ wordWidth += OVERLAP; // no overlap on final letter of word!
+ if ( firstWord ) { // first word on first line, so no separating SPACE needed
+ line[0].width = wordWidth;
+ line[0].length = wordLength;
+ firstWord = false;
+ } else {
+ // see how much extra space this word will need to fit on current line
+ // (with a separating space character - also overlapped)
+ uint16 spaceNeeded = _joinWidth + wordWidth;
+
+ if (line[lineNo].width + spaceNeeded <= maxWidth ) {
+ line[lineNo].width += spaceNeeded;
+ line[lineNo].length += 1 + wordLength; // NB. space+word characters
+ } else { // put word (without separating SPACE) at start of next line
+ lineNo++;
+ assert( lineNo < MAX_LINES );
+ line[lineNo].width = wordWidth;
+ line[lineNo].length = wordLength;
+ }
+ }
+ }
+ return lineNo+1; // return no of lines
+}
+
+uint16 Text::copyChar(uint8 ch, uint8 *sprPtr, uint16 sprWidth, uint8 pen) {
+ FrameHeader *chFrame = _resMan->fetchFrame(_font, ch - SPACE);
+ uint8 *chData = ((uint8*)chFrame) + sizeof(FrameHeader);
+ uint8 *dest = sprPtr;
+ for (uint16 cnty = 0; cnty < FROM_LE_16(chFrame->height); cnty++) {
+ for (uint16 cntx = 0; cntx < FROM_LE_16(chFrame->width); cntx++) {
+ if (*chData == LETTER_COL)
+ dest[cntx] = pen;
+ else if ((*chData == BORDER_COL) && (!dest[cntx])) // don't do a border if there's already a color underneath (chars can overlap)
+ dest[cntx] = BORDER_COL;
+ chData++;
+ }
+ dest += sprWidth;
+ }
+ return FROM_LE_16(chFrame->width);
+}
+
+FrameHeader *Text::giveSpriteData(uint32 textTarget) {
+ // textTarget is the resource ID of the Compact linking the textdata.
+ // that's 0x950000 for slot 0 and 0x950001 for slot 1. easy, huh? :)
+ textTarget &= ITM_ID;
+ assert(textTarget <= 1);
+
+ return _textBlocks[textTarget];
+}
+
+void Text::releaseText(uint32 id) {
+ id &= ITM_ID;
+ assert(id <= 1);
+ if (_textBlocks[id]) {
+ free(_textBlocks[id]);
+ _textBlocks[id] = NULL;
+ _textCount--;
+ }
+}
+
+} // End of namespace Sword1
diff --git a/engines/sword1/text.h b/engines/sword1/text.h
new file mode 100644
index 0000000000..34b106518a
--- /dev/null
+++ b/engines/sword1/text.h
@@ -0,0 +1,65 @@
+/* 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 BSTEXT_H
+#define BSTEXT_H
+
+#include "sword1/object.h"
+#include "sword1/sworddefs.h"
+
+namespace Sword1 {
+
+#define MAX_TEXT_OBS 2
+
+class ObjectMan;
+class ResMan;
+
+struct LineInfo {
+ uint16 width; // width of line in pixels
+ uint16 length; // length of line in characters
+};
+
+class Text {
+public:
+ Text(ObjectMan *pObjMan, ResMan *pResMan, bool czechVersion);
+ ~Text(void);
+ FrameHeader *giveSpriteData(uint32 textTarget);
+ uint32 lowTextManager(uint8 *text, int32 width, uint8 pen);
+ void releaseText(uint32 id);
+
+private:
+ void makeTextSprite(uint8 slot, uint8 *text, uint16 maxWidth, uint8 pen);
+ uint16 analyzeSentence(uint8 *text, uint16 maxWidth, LineInfo *info);
+ uint16 charWidth(uint8 ch);
+ uint16 copyChar(uint8 ch, uint8 *sprPtr, uint16 sprWidth, uint8 pen);
+ uint8 *_font;
+ uint8 _textCount;
+ uint16 _charHeight, _joinWidth;
+ ObjectMan *_objMan;
+ ResMan *_resMan;
+ FrameHeader *_textBlocks[MAX_TEXT_OBS];
+ uint32 _fontId;
+};
+
+} // End of namespace Sword1
+
+#endif //BSTEXT_H