aboutsummaryrefslogtreecommitdiff
path: root/engines/agos
diff options
context:
space:
mode:
Diffstat (limited to 'engines/agos')
-rw-r--r--engines/agos/animation.cpp406
-rw-r--r--engines/agos/animation.h71
-rw-r--r--engines/agos/charset.cpp1629
-rw-r--r--engines/agos/cursor.cpp495
-rw-r--r--engines/agos/debug.cpp473
-rw-r--r--engines/agos/debug.h1855
-rw-r--r--engines/agos/debugger.cpp179
-rw-r--r--engines/agos/debugger.h55
-rw-r--r--engines/agos/draw.cpp512
-rw-r--r--engines/agos/event.cpp376
-rw-r--r--engines/agos/game.cpp1704
-rw-r--r--engines/agos/icons.cpp571
-rw-r--r--engines/agos/intern.h262
-rw-r--r--engines/agos/items.cpp2552
-rw-r--r--engines/agos/midi.cpp574
-rw-r--r--engines/agos/midi.h128
-rw-r--r--engines/agos/midiparser_s1d.cpp155
-rw-r--r--engines/agos/module.mk34
-rw-r--r--engines/agos/oracle.cpp432
-rw-r--r--engines/agos/res.cpp1055
-rw-r--r--engines/agos/rooms.cpp114
-rw-r--r--engines/agos/saveload.cpp821
-rw-r--r--engines/agos/simon.cpp2292
-rw-r--r--engines/agos/simon.h1191
-rw-r--r--engines/agos/sound.cpp714
-rw-r--r--engines/agos/sound.h98
-rw-r--r--engines/agos/string.cpp470
-rw-r--r--engines/agos/subroutine.cpp479
-rw-r--r--engines/agos/verb.cpp906
-rw-r--r--engines/agos/vga.cpp2788
-rw-r--r--engines/agos/vga.h167
-rw-r--r--engines/agos/window.cpp185
32 files changed, 23743 insertions, 0 deletions
diff --git a/engines/agos/animation.cpp b/engines/agos/animation.cpp
new file mode 100644
index 0000000000..9302055241
--- /dev/null
+++ b/engines/agos/animation.cpp
@@ -0,0 +1,406 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-2006 The ScummVM project
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/stdafx.h"
+
+#include "common/endian.h"
+#include "common/system.h"
+
+#include "graphics/cursorman.h"
+
+#include "agos/animation.h"
+#include "agos/intern.h"
+#include "agos/agos.h"
+
+#include "sound/audiostream.h"
+#include "sound/wave.h"
+
+namespace Simon {
+
+MoviePlayer::MoviePlayer(SimonEngine *vm, Audio::Mixer *mixer)
+ : DXAPlayer(), _vm(vm), _mixer(mixer) {
+ _omniTV = false;
+
+ _leftButtonDown = false;
+ _rightButtonDown = false;
+
+ memset(baseName, 0, sizeof(baseName));
+
+ _sequenceNum = 0;
+ _ticks = 0;
+}
+
+bool MoviePlayer::load(const char *filename) {
+ char videoName[20];
+ uint i;
+
+ int baseLen = strlen(filename) - 4;
+ memset(baseName, 0, sizeof(baseName));
+ memcpy(baseName, filename, baseLen);
+
+ // Change file extension to dxa
+ sprintf(videoName, "%s.dxa", baseName);
+
+ if (!loadFile(videoName)) {
+ // Check short filename to work around
+ // bug in a German Windows 2CD version.
+ if (baseLen >= 8) {
+ char shortName[20];
+ memset(shortName, 0, sizeof(shortName));
+ memcpy(shortName, filename, 6);
+
+ sprintf(shortName, "%s~1", shortName);
+
+ if (!loadFile(shortName))
+ error("Failed to load video file %s or %s", videoName, shortName);
+
+ memset(baseName, 0, sizeof(baseName));
+ memcpy(baseName, shortName, 8);
+ debug(0, "Playing video %s", shortName);
+ } else {
+ error("Failed to load video file %s", videoName);
+ }
+ } else {
+ debug(0, "Playing video %s", videoName);
+ }
+
+ CursorMan.showMouse(false);
+
+ if ((_vm->getPlatform() == Common::kPlatformAmiga || _vm->getPlatform() == Common::kPlatformMacintosh) &&
+ _vm->_language != Common::EN_ANY) {
+ _sequenceNum = 0;
+ for (i = 0; i < 90; i++) {
+ if (!scumm_stricmp(baseName, _sequenceList[i]))
+ _sequenceNum = i;
+ }
+ }
+
+ return true;
+}
+
+void MoviePlayer::playOmniTV() {
+ // Load OmniTV video
+ if (!_fd.isOpen()) {
+ _vm->_variableArray[254] = 6747;
+ return;
+ } else {
+ _vm->setBitFlag(42, false);
+ _omniTV = true;
+ startSound();
+ return;
+ }
+}
+
+void MoviePlayer::play() {
+ // The OmniTV videos were not included with Amiga and Macintosh versions.
+ if (_vm->getPlatform() == Common::kPlatformWindows && _vm->getBitFlag(40)) {
+ playOmniTV();
+ return;
+ }
+
+ if (!_fd.isOpen()) {
+ return;
+ }
+
+ _leftButtonDown = false;
+ _rightButtonDown = false;
+
+ _mixer->stopAll();
+
+ // Resolution is smaller in Amiga verison so always clear screen
+ if (_width == 384 && _height == 280) {
+ memset(_vm->_frontBuf, 0, _vm->_screenHeight * _vm->_screenWidth);
+ }
+
+ _ticks = _vm->_system->getMillis();
+
+ startSound();
+
+ while (_frameNum < _framesCount)
+ handleNextFrame();
+
+ closeFile();
+
+ _vm->o_killAnimate();
+
+ if (_vm->getBitFlag(41)) {
+ memcpy(_vm->_backBuf, _vm->_frontBuf, _frameSize);
+ } else {
+ uint8 palette[1024];
+ memset(palette, 0, sizeof(palette));
+ _vm->dx_clear_surfaces(480);
+ _vm->_system->setPalette(palette, 0, 256);
+ }
+
+ _vm->_fastFadeOutFlag = true;
+}
+
+void MoviePlayer::startSound() {
+ byte *buffer;
+ uint32 offset, size, tag;
+
+ tag = _fd.readUint32BE();
+ if (tag == MKID_BE('WAVE')) {
+ size = _fd.readUint32BE();
+
+ if (_sequenceNum) {
+ Common::File in;
+
+ _fd.seek(size, SEEK_CUR);
+
+ in.open((const char *)"audio.wav");
+ if (!in.isOpen()) {
+ error("Can't read offset file 'audio.wav'");
+ }
+
+ in.seek(_sequenceNum * 8, SEEK_SET);
+ offset = in.readUint32LE();
+ size = in.readUint32LE();
+
+ buffer = (byte *)malloc(size);
+ in.seek(offset, SEEK_SET);
+ in.read(buffer, size);
+ in.close();
+ } else {
+ buffer = (byte *)malloc(size);
+ _fd.read(buffer, size);
+ }
+
+ Common::MemoryReadStream stream(buffer, size);
+ _bgSoundStream = Audio::makeWAVStream(stream);
+ free(buffer);
+ } else {
+ _bgSoundStream = Audio::AudioStream::openStreamFile(baseName);
+ }
+
+ if (_bgSoundStream != NULL) {
+ _mixer->stopHandle(_bgSound);
+ _mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_bgSound, _bgSoundStream);
+ }
+}
+
+void MoviePlayer::nextFrame() {
+ if (!_omniTV)
+ return;
+
+ if (_vm->getBitFlag(42)) {
+ _omniTV = false;
+ closeFile();
+ return;
+ }
+
+ if (_mixer->isSoundHandleActive(_bgSound) && (_mixer->getSoundElapsedTime(_bgSound) * _framesPerSec) / 1000 < _frameNum) {
+ copyFrameToBuffer(_vm->getBackBuf(), 465, 222, _vm->_screenWidth);
+ return;
+ }
+
+ if (_frameNum < _framesCount) {
+ decodeNextFrame();
+ copyFrameToBuffer(_vm->getBackBuf(), 465, 222, _vm->_screenWidth);
+ _frameNum++;
+ } else {
+ _omniTV = false;
+ closeFile();
+ _vm->_variableArray[254] = 6747;
+ }
+}
+
+void MoviePlayer::handleNextFrame() {
+ decodeNextFrame();
+ processFrame();
+
+ _vm->_system->updateScreen();
+ _frameNum++;
+
+ OSystem::Event event;
+ while (_vm->_system->pollEvent(event)) {
+ switch (event.type) {
+ case OSystem::EVENT_KEYDOWN:
+ if (event.kbd.ascii == 27) {
+ _leftButtonDown = true;
+ _rightButtonDown = true;
+ }
+ break;
+ case OSystem::EVENT_LBUTTONDOWN:
+ _leftButtonDown = true;
+ break;
+ case OSystem::EVENT_RBUTTONDOWN:
+ _rightButtonDown = true;
+ break;
+ case OSystem::EVENT_LBUTTONUP:
+ _leftButtonDown = false;
+ break;
+ case OSystem::EVENT_RBUTTONUP:
+ _rightButtonDown = false;
+ break;
+ case OSystem::EVENT_QUIT:
+ _vm->_system->quit();
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (_leftButtonDown && _rightButtonDown && !_vm->getBitFlag(41)) {
+ _frameNum = _framesCount;
+ }
+}
+
+void MoviePlayer::setPalette(byte *pal) {
+ byte palette[1024];
+ byte *p = palette;
+
+ for (int i = 0; i < 256; i++) {
+ *p++ = *pal++;
+ *p++ = *pal++;
+ *p++ = *pal++;
+ *p++ = 0;
+ }
+
+ _vm->_system->setPalette(palette, 0, 256);
+}
+
+void MoviePlayer::processFrame() {
+ copyFrameToBuffer(_vm->getFrontBuf(), (_vm->_screenWidth - _width) / 2, (_vm->_screenHeight - _height) / 2, _vm->_screenWidth);
+ _vm->_system->copyRectToScreen(_vm->getFrontBuf(), _vm->_screenWidth, 0, 0, _vm->_screenWidth, _vm->_screenHeight);
+
+ if ((_bgSoundStream == NULL) || ((int)(_mixer->getSoundElapsedTime(_bgSound) * _framesPerSec) / 1000 < _frameNum + 1) ||
+ _frameSkipped > _framesPerSec) {
+ if (_frameSkipped > _framesPerSec) {
+ warning("force frame %i redraw", _frameNum);
+ _frameSkipped = 0;
+ }
+
+ if (_bgSoundStream && _mixer->isSoundHandleActive(_bgSound)) {
+ while (_mixer->isSoundHandleActive(_bgSound) && (_mixer->getSoundElapsedTime(_bgSound) * _framesPerSec) / 1000 < _frameNum) {
+ _vm->_system->delayMillis(10);
+ }
+ // In case the background sound ends prematurely, update
+ // _ticks so that we can still fall back on the no-sound
+ // sync case for the subsequent frames.
+ _ticks = _vm->_system->getMillis();
+ } else {
+ _ticks += _frameTicks;
+ while (_vm->_system->getMillis() < _ticks)
+ _vm->_system->delayMillis(10);
+ }
+ } else {
+ warning("dropped frame %i", _frameNum);
+ _frameSkipped++;
+ }
+}
+
+const char * MoviePlayer::_sequenceList[90] = {
+ "agent32",
+ "Airlock",
+ "Badluck",
+ "bentalk1",
+ "bentalk2",
+ "bentalk3",
+ "BigFight",
+ "BLOWLAB",
+ "breakdown",
+ "bridge",
+ "button2",
+ "cargo",
+ "COACH",
+ "Colatalk",
+ "cygnus2",
+ "dream",
+ "escape2",
+ "FASALL",
+ "fbikewurb",
+ "feebdel",
+ "Feebohno",
+ "feebpump",
+ "feefone1",
+ "feefone2",
+ "founder2",
+ "founder3",
+ "founder4",
+ "fxmadsam",
+ "fxwakeup",
+ "gate",
+ "Get Car",
+ "getaxe",
+ "getlift",
+ "icetrench",
+ "intomb1",
+ "intomb2",
+ "Jackpot",
+ "knockout",
+ "labocto",
+ "longfeeb",
+ "Mainmin",
+ "maznat",
+ "meetsquid",
+ "mflirt",
+ "mfxHappy",
+ "Mix_Feeb1",
+ "Mix_Feeb2",
+ "Mix_Feeb3",
+ "Mix_Guardscn",
+ "Mlights1",
+ "MLights2",
+ "MProtest",
+ "mudman",
+ "munlock",
+ "MUS5P2",
+ "MUSOSP1",
+ "Omenter",
+ "Omnicofe",
+ "OUTMIN~1",
+ "Readbook",
+ "Rebelhq",
+ "RebelHQ2",
+ "Reedin",
+ "rescue1",
+ "rescue2",
+ "samcar",
+ "Samdead",
+ "scanner",
+ "Sleepy",
+ "spitbrai",
+ "statue1",
+ "statue2",
+ "sva1",
+ "sva2",
+ "Teeter",
+ "Temple2",
+ "Temple3",
+ "Temple4",
+ "Temple5",
+ "Temple6",
+ "Temple7",
+ "Temple8",
+ "Tic-tac2",
+ "torture",
+ "transmit",
+ "Typey",
+ "ventfall",
+ "ventoff",
+ "wasting",
+ "wurbatak"
+};
+
+} // End of namespace Simon
diff --git a/engines/agos/animation.h b/engines/agos/animation.h
new file mode 100644
index 0000000000..782cea87a9
--- /dev/null
+++ b/engines/agos/animation.h
@@ -0,0 +1,71 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-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 "common/file.h"
+#include "common/stream.h"
+
+#include "graphics/dxa_player.h"
+#include "sound/mixer.h"
+
+namespace Simon {
+
+class SimonEngine;
+
+class MoviePlayer : public Graphics::DXAPlayer {
+ SimonEngine *_vm;
+
+ Audio::Mixer *_mixer;
+
+ Audio::SoundHandle _bgSound;
+ Audio::AudioStream *_bgSoundStream;
+
+ bool _omniTV;
+ bool _leftButtonDown;
+ bool _rightButtonDown;
+ uint32 _ticks;
+
+ char baseName[40];
+ static const char *_sequenceList[90];
+ uint8 _sequenceNum;
+public:
+ MoviePlayer(SimonEngine *vm, Audio::Mixer *mixer);
+
+ bool load(const char *filename);
+ void play();
+ void nextFrame();
+protected:
+ virtual void setPalette(byte *pal);
+private:
+ void playOmniTV();
+
+ void handleNextFrame();
+ void processFrame();
+ void startSound();
+};
+
+} // End of namespace Simon
+
+#endif
diff --git a/engines/agos/charset.cpp b/engines/agos/charset.cpp
new file mode 100644
index 0000000000..f051197d4b
--- /dev/null
+++ b/engines/agos/charset.cpp
@@ -0,0 +1,1629 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-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 "agos/agos.h"
+#include "agos/intern.h"
+
+namespace Simon {
+
+void SimonEngine::print_char_helper_1(const byte *src, uint len) {
+ uint idx;
+
+ if (_textWindow == NULL)
+ return;
+
+ while (len-- != 0) {
+ if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ if (getBitFlag(93)) {
+ if (_curWindow == 3) {
+ if ((_newLines >= _textWindow->scrollY) && (_newLines < (_textWindow->scrollY + 3)))
+ windowPutChar(*src);
+ if (*src == '\n') // Do two top lines of text only
+ _newLines++;
+ src++;
+ }
+ } else {
+ if (getBitFlag(94)) {
+ if (_curWindow == 3) {
+ if (_newLines == (_textWindow->scrollY + 7))
+ windowPutChar(*src);
+ if (*src == '\n') // Do two top lines of text only
+ _newLines++;
+ src++;
+ }
+ } else {
+ if (getBitFlag(92))
+ delay(50);
+ windowPutChar(*src++);
+ }
+ }
+ } else {
+ if (*src != 12 && _textWindow->iconPtr != NULL &&
+ _fcsData1[idx = getWindowNum(_textWindow)] != 2) {
+
+ _fcsData1[idx] = 2;
+ _fcsData2[idx] = 1;
+ }
+
+ windowPutChar(*src++);
+ }
+ }
+}
+
+void SimonEngine::print_char_helper_5(WindowBlock *window) {
+ uint index = getWindowNum(window);
+ tidyIconArray(index);
+ _fcsData1[index] = 0;
+}
+
+void SimonEngine::tidyIconArray(uint i) {
+ WindowBlock *window;
+
+ if (_fcsData2[i]) {
+ mouseOff();
+ window = _windowArray[i];
+ drawIconArray(i, window->iconPtr->itemRef, window->iconPtr->line, window->iconPtr->classMask);
+ _fcsData2[i] = 0;
+ mouseOn();
+ }
+}
+
+void SimonEngine::renderStringAmiga(uint vga_sprite_id, uint color, uint width, uint height, const char *txt) {
+ VgaPointersEntry *vpe = &_vgaBufferPointers[2];
+ byte *src, *dst, *dst_org, chr;
+ uint count;
+
+ if (vga_sprite_id >= 100) {
+ vga_sprite_id -= 100;
+ vpe++;
+ }
+
+ src = dst = vpe->vgaFile2;
+
+ count = 499;
+ if (vga_sprite_id == 1)
+ count *= 2;
+
+ src += vga_sprite_id * 8;
+ dst += READ_BE_UINT32(src);
+ WRITE_BE_UINT16(dst + 4, height);
+ WRITE_BE_UINT16(dst + 6, width);
+
+ uint charsize = width/8 * height;
+ memset(dst, 0, count);
+ dst_org = dst;
+ int delta = 0;
+ while ((chr = *txt++) != 0) {
+ int tmp = chr;
+ if (chr == 10) {
+ dst_org += width * 10;
+ dst = dst_org;
+ delta = 0;
+ } else if ((tmp -= '!') < 0) {
+ delta += 6;
+ if (delta > 8)
+ {
+ delta -= 8;
+ dst_org++;
+ }
+ } else {
+ byte *img = src + chr * 41;
+ int CTR = img[40];
+ int D3 = 8 - delta;
+ for (int D2 = 9; D2 != 0; D2--)
+ {
+ byte *cur_dst = dst_org;
+ for (int D7 = 2; D7 != 0; D7--)
+ {
+ chr = *img >> delta;
+ if (chr)
+ {
+ if (color & 1) *(cur_dst + charsize * 0) |= chr;
+ if (color & 2) *(cur_dst + charsize * 1) |= chr;
+ if (color & 4) *(cur_dst + charsize * 2) |= chr;
+ if (color & 8) *(cur_dst + charsize * 3) |= chr;
+ }
+ if ((D3 >= CTR) && (chr = *img++ << (D3)))
+ {
+ if (color & 1) *(cur_dst + charsize * 0) |= chr;
+ if (color & 2) *(cur_dst + charsize * 1) |= chr;
+ if (color & 4) *(cur_dst + charsize * 2) |= chr;
+ if (color & 8) *(cur_dst + charsize * 3) |= chr;
+ }
+ color++;
+ }
+ chr = *img >> delta;
+ if (chr)
+ {
+ *(cur_dst + charsize * 0) |= chr;
+ *(cur_dst + charsize * 1) |= chr;
+ *(cur_dst + charsize * 2) |= chr;
+ *(cur_dst + charsize * 3) |= chr;
+ }
+ if ((D3 >= CTR) && (chr = *img++ << (D3)))
+ {
+ *(cur_dst + charsize * 0) |= chr;
+ *(cur_dst + charsize * 1) |= chr;
+ *(cur_dst + charsize * 2) |= chr;
+ *(cur_dst + charsize * 3) |= chr;
+ }
+ cur_dst += width/8;
+ }
+ delta += CTR;
+ if (delta > 8)
+ {
+ delta -= 8;
+ dst_org++;
+ }
+ }
+ }
+}
+
+void SimonEngine::renderString(uint vga_sprite_id, uint color, uint width, uint height, const char *txt) {
+ VgaPointersEntry *vpe = &_vgaBufferPointers[2];
+ byte *src, *dst, *p, *dst_org, chr;
+ const int textHeight = (getGameType() == GType_FF || getGameType() == GType_PP) ? 15: 10;
+ uint count = 0;
+
+ if (vga_sprite_id >= 100) {
+ vga_sprite_id -= 100;
+ vpe++;
+ }
+
+ src = dst = vpe->vgaFile2;
+
+ if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ if (vga_sprite_id == 1)
+ count = 45000;
+ } else {
+ count = 4000;
+ if (vga_sprite_id == 1)
+ count *= 2;
+ }
+
+ p = dst + vga_sprite_id * 8;
+
+ if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ WRITE_LE_UINT16(p + 4, height);
+ WRITE_LE_UINT16(p + 6, width);
+ // We need to adjust the offset to the next buffer to be right
+ // after this one. By default, each buffer is only 9000 bytes
+ // long. A two-line string can very well be more than twice
+ // that size!
+ //
+ // The original seems to make an exception for sprite id 1, but
+ // even the first conversation option can be a long line. For
+ // some reason, I cannot reproduce the text corruption with the
+ // original interpreter, though, so maybe we're missing some
+ // detail here. Let's hope it's safe to always adjust the
+ // buffer size anyway.
+ WRITE_LE_UINT16(p + 8, READ_LE_UINT32(p) + width * height);
+ } else {
+ WRITE_BE_UINT16(p + 4, height);
+ WRITE_BE_UINT16(p + 6, width);
+ }
+ dst += readUint32Wrapper(p);
+
+ if (count != 0)
+ memset(dst, 0, count);
+
+ if (_language == Common::HB_ISR)
+ dst += width - 1; // For Hebrew, start at the right edge, not the left.
+
+ dst_org = dst;
+ while ((chr = *txt++) != 0) {
+ if (chr == 10) {
+ dst_org += width * textHeight;
+ dst = dst_org;
+ } else if ((chr -= ' ') == 0) {
+ dst += (_language == Common::HB_ISR ? -6 : 6); // Hebrew moves to the left, all others to the right
+ } else {
+ byte *img_hdr, *img;
+ uint i, img_width, img_height;
+
+ if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ img_hdr = src + 96 + chr * 8;
+ img_height = READ_LE_UINT16(img_hdr + 4);
+ img_width = READ_LE_UINT16(img_hdr + 6);
+ img = src + READ_LE_UINT32(img_hdr);
+ } else {
+ img_hdr = src + 48 + chr * 4;
+ img_height = img_hdr[2];
+ img_width = img_hdr[3];
+ img = src + READ_LE_UINT16(img_hdr);
+ }
+
+ if (_language == Common::HB_ISR)
+ dst -= img_width - 1; // For Hebrew, move from right edge to left edge of image.
+ byte *cur_dst = dst;
+
+ assert(img_width > 0 && img_width < 50 && img_height > 0 && img_height < 50);
+
+ do {
+ for (i = 0; i != img_width; i++) {
+ chr = *img++;
+ if (chr) {
+ if (chr == 0xF)
+ chr = 207;
+ else
+ chr += color;
+ cur_dst[i] = chr;
+ }
+ }
+ cur_dst += width;
+ } while (--img_height);
+
+ if (_language != Common::HB_ISR) // Hebrew character movement is done higher up
+ dst += img_width - 1;
+ }
+ }
+}
+
+static const byte feebleFontSize[208] = {
+ 8, 2, 5, 7, 8, 8, 8, 2, 4, 4, 8, 8, 3, 8, 2, 9,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 2, 3, 5, 8, 5, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 4, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 4, 9, 4, 4, 9,
+ 4, 8, 8, 8, 8, 8, 7, 8, 8, 4, 5, 7, 3, 8, 8, 8,
+ 8, 8, 8, 7, 7, 8, 8, 8, 8, 8, 8, 5, 2, 5, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 4, 4, 4, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 4, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 2, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+};
+
+uint SimonEngine::getFeebleFontSize(byte chr) {
+ return feebleFontSize[chr - 32];
+}
+
+void SimonEngine::showMessageFormat(const char *s, ...) {
+ char buf[STRINGBUFLEN];
+ char *str;
+ va_list va;
+
+ va_start(va, s);
+ vsnprintf(buf, STRINGBUFLEN, s, va);
+ va_end(va);
+
+ if (!_fcsData1[_curWindow]) {
+ openTextWindow();
+ if (!_showMessageFlag) {
+ _windowArray[0] = _textWindow;
+ if (getGameType() == GType_FF || getGameType() == GType_PP)
+ showmessage_helper_3(_textWindow->textColumn, _textWindow->width);
+ else
+ showmessage_helper_3(_textWindow->textLength, _textWindow->textMaxLength);
+ }
+ _showMessageFlag = true;
+ _fcsData1[_curWindow] = 1;
+ }
+
+ for (str = buf; *str; str++)
+ showmessage_print_char(*str);
+}
+
+void SimonEngine::showmessage_print_char(byte chr) {
+ if (chr == 12) {
+ _numLettersToPrint = 0;
+ _printCharCurPos = 0;
+ _printCharPixelCount = 0;
+ print_char_helper_1(&chr, 1);
+ print_char_helper_5(_textWindow);
+ } else if (chr == 0 || chr == ' ' || chr == 10) {
+ bool fit;
+
+ // Note that in FF, _printCharCurPos may be greater than
+ // _printCharMaxPos. In Simon, that is probably prevented by
+ // testing if _printCharCurPos == _printCharMaxPos below.
+
+ if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ fit = _printCharMaxPos > _printCharCurPos + _printCharPixelCount;
+ } else {
+ fit = _printCharMaxPos - _printCharCurPos >= _printCharPixelCount;
+ }
+
+ if (fit) {
+ _printCharCurPos += _printCharPixelCount;
+ print_char_helper_1(_lettersToPrintBuf, _numLettersToPrint);
+
+ if (_printCharCurPos == _printCharMaxPos) {
+ _printCharCurPos = 0;
+ } else {
+ if (chr)
+ print_char_helper_1(&chr, 1);
+ if (chr == 10)
+ _printCharCurPos = 0;
+ else if (chr != 0)
+ _printCharCurPos += (getGameType() == GType_FF || getGameType() == GType_PP) ? feebleFontSize[chr - 32] : 1;
+ }
+ } else {
+ const byte newline_character = 10;
+ _printCharCurPos = _printCharPixelCount;
+ print_char_helper_1(&newline_character, 1);
+ print_char_helper_1(_lettersToPrintBuf, _numLettersToPrint);
+ if (chr == ' ') {
+ print_char_helper_1(&chr, 1);
+ _printCharCurPos += (getGameType() == GType_FF || getGameType() == GType_PP) ? feebleFontSize[chr - 32] : 1;
+ } else {
+ print_char_helper_1(&chr, 1);
+ _printCharCurPos = 0;
+ }
+ }
+ _numLettersToPrint = 0;
+ _printCharPixelCount = 0;
+ } else {
+ _lettersToPrintBuf[_numLettersToPrint++] = chr;
+ _printCharPixelCount += (getGameType() == GType_FF || getGameType() == GType_PP) ? feebleFontSize[chr - 32] : 1;
+ }
+}
+
+void SimonEngine::openTextWindow() {
+ if (_textWindow)
+ return;
+
+ if (getGameType() == GType_FF || getGameType() == GType_PP)
+ _textWindow = openWindow(64, 96, 384, 172, 1, 0, 15);
+ else
+ _textWindow = openWindow(8, 144, 24, 6, 1, 0, 15);
+}
+
+void SimonEngine::showmessage_helper_3(uint a, uint b) {
+ _printCharCurPos = a;
+ _printCharMaxPos = b;
+ _printCharPixelCount = 0;
+ _numLettersToPrint = 0;
+ _newLines = 0;
+}
+
+void SimonEngine::windowPutChar(WindowBlock *window, byte c, byte b) {
+ byte width = 6;
+
+ if (c == 12) {
+ clearWindow(window);
+ } else if (c == 13 || c == 10) {
+ video_putchar_newline(window);
+ } else if ((c == 1 && _language != Common::HB_ISR) || (c == 8)) {
+ if (_language == Common::HB_ISR) {
+ if (b >= 64 && b < 91)
+ width = _hebrewCharWidths [b - 64];
+
+ if (window->textLength != 0) {
+ window->textLength--;
+ window->textColumnOffset += width;
+ if (window->textColumnOffset >= 8) {
+ window->textColumnOffset -= 8;
+ window->textColumn--;
+ }
+ }
+ } else {
+ int8 val = (c == 8) ? 6 : 4;
+
+ if (window->textLength != 0) {
+ window->textLength--;
+ window->textColumnOffset -= val;
+ if ((int8)window->textColumnOffset < val) {
+ window->textColumnOffset += 8;
+ window->textColumn--;
+ }
+ }
+ }
+ } else if (c >= 32) {
+ if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ video_putchar_drawchar(window, window->textColumn + window->x, window->textRow + window->y, c);
+ window->textColumn += feebleFontSize[c - 32];
+ return;
+ }
+
+ if (window->textLength == window->textMaxLength) {
+ video_putchar_newline(window);
+ } else if (window->textRow == window->height) {
+ video_putchar_newline(window);
+ window->textRow--;
+ }
+
+ if (_language == Common::HB_ISR) {
+ if (c >= 64 && c < 91)
+ width = _hebrewCharWidths [c - 64];
+ window->textColumnOffset -= width;
+ if (window->textColumnOffset >= width) {
+ window->textColumnOffset += 8;
+ window->textColumn++;
+ }
+ video_putchar_drawchar(window, (window->width + window->x - window->textColumn) * 8, window->textRow * 8 + window->y, c);
+ window->textLength++;
+ } else {
+ video_putchar_drawchar(window, (window->textColumn + window->x) * 8, window->textRow * 8 + window->y, c);
+
+ window->textLength++;
+ window->textColumnOffset += 6;
+ if (c == 'i' || c == 'l')
+ window->textColumnOffset -= 2;
+
+ if (window->textColumnOffset >= 8) {
+ window->textColumnOffset -= 8;
+ window->textColumn++;
+ }
+ }
+ }
+}
+
+void SimonEngine::video_putchar_newline(WindowBlock *window) {
+ if (getGameType() == GType_FF) {
+ if (_noOracleScroll == 0) {
+ if (window->height < window->textRow + 30) {
+ if (!getBitFlag(94)) {
+ _noOracleScroll = 1;
+ if (getBitFlag(92)) {
+ _noOracleScroll = 0;
+ checkLinkBox();
+ scrollOracle();
+ linksUp();
+ window->scrollY++;
+ _oracleMaxScrollY++;
+ } else {
+ _oracleMaxScrollY++;
+ checkLinkBox();
+ }
+ }
+ } else {
+ window->textRow += 15;
+ checkLinkBox();
+ }
+ } else {
+ _oracleMaxScrollY++;
+ checkLinkBox();
+ }
+ } else {
+ if (window->textRow != window->height)
+ window->textRow++;
+ }
+
+ window->textColumn = 0;
+ window->textColumnOffset = 0;
+ window->textLength = 0;
+}
+
+#ifdef PALMOS_68K
+static const byte *russian_video_font;
+static const byte *polish_video_font;
+static const byte *french_video_font;
+static const byte *german_video_font;
+static const byte *hebrew_video_font;
+static const byte *italian_video_font;
+static const byte *spanish_video_font;
+static const byte *video_font;
+#else
+static const byte russian_video_font[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 32, 112, 112, 32, 32, 0, 32, 0,
+ 48, 48, 96, 0, 0, 0, 0, 0,
+ 0, 0, 100, 40, 48, 40, 100, 0,
+ 0, 0, 96, 48, 40, 40, 112, 0,
+ 60, 68, 68, 60, 36, 68, 68, 0,
+ 0, 16, 40, 16, 42, 68, 58, 0,
+ 48, 48, 96, 0, 0, 0, 0, 0,
+ 0, 4, 8, 8, 8, 8, 4, 0,
+ 0, 32, 16, 16, 16, 16, 32, 0,
+ 72, 84, 84, 116, 84, 84, 72, 0,
+ 0, 0, 60, 68, 60, 36, 100, 0,
+ 0, 0, 0, 0, 0, 48, 48, 96,
+ 0, 0, 0, 240, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 48, 48, 0,
+ 16, 32, 0, 120, 112, 64, 56, 0,
+ 112, 136, 152, 168, 200, 136, 112, 0,
+ 32, 96, 32, 32, 32, 32, 112, 0,
+ 112, 136, 8, 48, 64, 136, 248, 0,
+ 112, 136, 8, 48, 8, 136, 112, 0,
+ 16, 48, 80, 144, 248, 16, 56, 0,
+ 248, 128, 240, 8, 8, 136, 112, 0,
+ 48, 64, 128, 240, 136, 136, 112, 0,
+ 248, 136, 8, 16, 32, 32, 32, 0,
+ 112, 136, 136, 112, 136, 136, 112, 0,
+ 112, 136, 136, 120, 8, 16, 96, 0,
+ 0, 0, 48, 48, 0, 48, 48, 0,
+ 32, 16, 0, 112, 8, 248, 120, 0,
+ 0, 0, 96, 48, 40, 40, 112, 0,
+ 0, 0, 112, 88, 20, 20, 56, 0,
+ 0, 0, 120, 4, 28, 4, 120, 0,
+ 112, 136, 8, 16, 32, 0, 32, 0,
+ 0, 0, 84, 84, 84, 84, 56, 4,
+ 56, 68, 68, 124, 68, 68, 68, 0,
+ 124, 36, 32, 56, 36, 36, 120, 0,
+ 120, 36, 36, 56, 36, 36, 120, 0,
+ 124, 36, 32, 32, 32, 32, 112, 0,
+ 56, 40, 40, 40, 40, 40, 124, 68,
+ 124, 36, 32, 56, 32, 36, 124, 0,
+ 84, 84, 84, 56, 84, 84, 84, 0,
+ 56, 68, 4, 24, 4, 68, 56, 0,
+ 68, 68, 76, 84, 100, 68, 68, 0,
+ 100, 40, 40, 48, 40, 36, 100, 0,
+ 28, 36, 36, 36, 36, 36, 100, 0,
+ 68, 108, 84, 68, 68, 68, 68, 0,
+ 68, 68, 68, 124, 68, 68, 68, 0,
+ 56, 68, 68, 68, 68, 68, 56, 0,
+ 124, 68, 68, 68, 68, 68, 68, 0,
+ 120, 36, 36, 56, 32, 32, 112, 0,
+ 56, 68, 64, 64, 64, 68, 56, 0,
+ 124, 84, 16, 16, 16, 16, 56, 0,
+ 100, 36, 36, 28, 4, 4, 56, 0,
+ 56, 84, 84, 84, 56, 16, 56, 0,
+ 108, 40, 16, 16, 40, 40, 108, 0,
+ 72, 72, 72, 72, 72, 72, 60, 4,
+ 76, 72, 72, 56, 8, 8, 28, 0,
+ 84, 84, 84, 84, 84, 84, 60, 0,
+ 84, 84, 84, 84, 84, 84, 56, 4,
+ 56, 68, 4, 28, 4, 68, 56, 0,
+ 0, 0, 68, 100, 84, 84, 100, 0,
+ 0, 0, 72, 84, 116, 84, 72, 0,
+ 0, 0, 60, 68, 60, 36, 100, 0,
+ 0, 0, 120, 4, 24, 4, 120, 0,
+ 0, 0, 100, 40, 48, 40, 100, 0,
+ 60, 68, 68, 60, 36, 68, 68, 0,
+ 0, 0, 56, 4, 60, 68, 60, 0,
+ 60, 64, 32, 56, 68, 68, 56, 0,
+ 48, 72, 80, 120, 68, 68, 56, 0,
+ 0, 0, 120, 4, 56, 64, 60, 0,
+ 56, 4, 4, 60, 68, 68, 56, 0,
+ 0, 0, 56, 68, 120, 64, 56, 0,
+ 40, 0, 56, 68, 120, 64, 56, 0,
+ 0, 0, 84, 84, 56, 84, 84, 0,
+ 64, 0, 192, 64, 64, 64, 224, 0,
+ 0, 0, 68, 68, 68, 68, 60, 0,
+ 56, 0, 68, 68, 68, 68, 60, 0,
+ 192, 64, 64, 64, 64, 64, 224, 0,
+ 0, 0, 28, 36, 36, 36, 100, 0,
+ 0, 0, 68, 108, 84, 68, 68, 0,
+ 0, 0, 56, 68, 68, 68, 56, 0,
+ 0, 0, 68, 68, 124, 68, 68, 0,
+ 0, 0, 124, 68, 68, 68, 68, 0,
+ 0, 0, 120, 36, 36, 56, 32, 112,
+ 0, 0, 60, 64, 64, 64, 60, 0,
+ 0, 0, 124, 84, 16, 16, 56, 0,
+ 0, 0, 68, 68, 60, 4, 56, 0,
+ 48, 16, 56, 84, 84, 56, 16, 56,
+ 0, 0, 68, 40, 16, 40, 68, 0,
+ 0, 0, 72, 72, 72, 72, 60, 4,
+ 0, 0, 76, 72, 72, 56, 8, 28,
+ 0, 0, 84, 84, 84, 84, 60, 0,
+ 32, 80, 0, 96, 144, 144, 96, 0,
+ 0, 14, 8, 48, 8, 8, 14, 0,
+ 0, 8, 8, 8, 8, 8, 8, 0,
+ 0, 112, 16, 12, 16, 16, 112, 0,
+ 0, 0, 0, 0, 0, 0, 248, 0,
+ 252, 252, 252, 252, 252, 252, 252, 252,
+ 240, 240, 240, 240, 240, 240, 240, 240,
+};
+
+static const byte polish_video_font[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 32, 112, 112, 32, 32, 0, 32, 0,
+ 48, 48, 96, 0, 0, 0, 0, 0,
+ 0, 0, 112, 136, 248, 128, 112, 8,
+ 0, 16, 120, 128, 112, 8, 240, 0,
+ 192, 64, 64, 96, 192, 64, 224, 0,
+ 0, 16, 40, 16, 42, 68, 58, 0,
+ 48, 48, 96, 0, 0, 0, 0, 0,
+ 0, 4, 8, 8, 8, 8, 4, 0,
+ 0, 32, 16, 16, 16, 16, 32, 0,
+ 0, 0, 20, 8, 62, 8, 20, 0,
+ 0, 32, 112, 136, 136, 136, 112, 0,
+ 0, 0, 0, 0, 0, 48, 48, 96,
+ 0, 0, 0, 240, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 48, 48, 0,
+ 0, 32, 112, 136, 128, 136, 112, 0,
+ 112, 136, 152, 168, 200, 136, 112, 0,
+ 32, 96, 32, 32, 32, 32, 112, 0,
+ 112, 136, 8, 48, 64, 136, 248, 0,
+ 112, 136, 8, 48, 8, 136, 112, 0,
+ 16, 48, 80, 144, 248, 16, 56, 0,
+ 248, 128, 240, 8, 8, 136, 112, 0,
+ 48, 64, 128, 240, 136, 136, 112, 0,
+ 248, 136, 8, 16, 32, 32, 32, 0,
+ 112, 136, 136, 112, 136, 136, 112, 0,
+ 112, 136, 136, 120, 8, 16, 96, 0,
+ 0, 0, 48, 48, 0, 48, 48, 0,
+ 0, 32, 240, 136, 136, 136, 136, 0,
+ 80, 0, 136, 136, 136, 136, 112, 0,
+ 0, 32, 248, 144, 32, 72, 248, 0,
+ 8, 32, 248, 144, 32, 72, 248, 0,
+ 112, 136, 8, 16, 32, 0, 32, 0,
+ 0, 0, 112, 8, 120, 136, 120, 4,
+ 112, 136, 136, 248, 136, 136, 136, 0,
+ 240, 72, 72, 112, 72, 72, 240, 0,
+ 48, 72, 128, 128, 128, 72, 48, 0,
+ 224, 80, 72, 72, 72, 80, 224, 0,
+ 248, 72, 64, 112, 64, 72, 248, 0,
+ 248, 72, 64, 112, 64, 64, 224, 0,
+ 48, 72, 128, 152, 136, 72, 56, 0,
+ 136, 136, 136, 248, 136, 136, 136, 0,
+ 248, 32, 32, 32, 32, 32, 248, 0,
+ 24, 8, 8, 8, 136, 136, 112, 0,
+ 200, 72, 80, 96, 80, 72, 200, 0,
+ 224, 64, 64, 64, 64, 72, 248, 0,
+ 136, 216, 168, 168, 136, 136, 136, 0,
+ 136, 200, 168, 152, 136, 136, 136, 0,
+ 112, 136, 136, 136, 136, 136, 112, 0,
+ 240, 72, 72, 112, 64, 64, 224, 0,
+ 112, 136, 136, 136, 136, 168, 112, 8,
+ 240, 72, 72, 112, 72, 72, 200, 0,
+ 112, 136, 128, 112, 8, 136, 112, 0,
+ 248, 168, 32, 32, 32, 32, 112, 0,
+ 136, 136, 136, 136, 136, 136, 120, 0,
+ 136, 136, 136, 80, 80, 32, 32, 0,
+ 136, 136, 136, 136, 168, 216, 136, 0,
+ 136, 136, 80, 32, 80, 136, 136, 0,
+ 136, 136, 136, 112, 32, 32, 112, 0,
+ 248, 136, 16, 32, 64, 136, 248, 0,
+ 0, 14, 8, 8, 8, 8, 14, 0,
+ 0, 128, 64, 32, 16, 8, 4, 0,
+ 224, 64, 64, 96, 192, 72, 248, 0,
+ 16, 120, 128, 112, 8, 136, 112, 0,
+ 248, 72, 64, 112, 64, 72, 248, 16,
+ 32, 248, 16, 32, 64, 136, 248, 0,
+ 0, 0, 112, 8, 120, 136, 120, 0,
+ 192, 64, 80, 104, 72, 72, 112, 0,
+ 0, 0, 112, 136, 128, 136, 112, 0,
+ 24, 16, 80, 176, 144, 144, 112, 0,
+ 0, 0, 112, 136, 248, 128, 112, 0,
+ 48, 72, 64, 224, 64, 64, 224, 0,
+ 0, 0, 104, 144, 144, 112, 136, 112,
+ 192, 64, 80, 104, 72, 72, 200, 0,
+ 64, 0, 192, 64, 64, 64, 224, 0,
+ 8, 0, 8, 8, 8, 8, 136, 112,
+ 192, 64, 72, 80, 96, 80, 200, 0,
+ 192, 64, 64, 64, 64, 64, 224, 0,
+ 0, 0, 144, 216, 168, 136, 136, 0,
+ 0, 0, 240, 136, 136, 136, 136, 0,
+ 0, 0, 112, 136, 136, 136, 112, 0,
+ 0, 0, 176, 72, 72, 112, 64, 224,
+ 0, 0, 104, 144, 144, 112, 16, 56,
+ 0, 0, 176, 72, 72, 64, 224, 0,
+ 0, 0, 120, 128, 112, 8, 240, 0,
+ 64, 64, 240, 64, 64, 72, 48, 0,
+ 0, 0, 144, 144, 144, 144, 104, 0,
+ 0, 0, 136, 136, 136, 80, 32, 0,
+ 0, 0, 136, 136, 168, 216, 144, 0,
+ 0, 0, 136, 80, 32, 80, 136, 0,
+ 0, 0, 136, 136, 136, 112, 32, 192,
+ 0, 0, 248, 144, 32, 72, 248, 0,
+ 32, 80, 0, 96, 144, 144, 96, 0,
+ 0, 14, 8, 48, 8, 8, 14, 0,
+ 0, 8, 8, 8, 8, 8, 8, 0,
+ 0, 112, 16, 12, 16, 16, 112, 0,
+ 0, 0, 0, 0, 0, 0, 248, 0,
+ 252, 252, 252, 252, 252, 252, 252, 252,
+ 240, 240, 240, 240, 240, 240, 240, 240,
+};
+
+static const byte french_video_font[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 32, 112, 112, 32, 32, 0, 32, 0,
+ 48, 48, 96, 0, 0, 0, 0, 0,
+ 32, 80, 0, 112, 136, 136, 112, 0,
+ 32, 80, 0, 112, 8, 248, 120, 0,
+ 112, 136, 128, 128, 136, 112, 32, 96,
+ 0, 16, 40, 16, 42, 68, 58, 0,
+ 48, 48, 96, 0, 0, 0, 0, 0,
+ 0, 4, 8, 8, 8, 8, 4, 0,
+ 0, 32, 16, 16, 16, 16, 32, 0,
+ 0, 0, 20, 8, 62, 8, 20, 0,
+ 112, 136, 128, 128, 136, 112, 32, 96,
+ 0, 0, 0, 0, 0, 48, 48, 96,
+ 0, 0, 0, 240, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 48, 48, 0,
+ 32, 64, 0, 112, 248, 128, 112, 0,
+ 112, 136, 152, 168, 200, 136, 112, 0,
+ 32, 96, 32, 32, 32, 32, 112, 0,
+ 112, 136, 8, 48, 64, 136, 248, 0,
+ 112, 136, 8, 48, 8, 136, 112, 0,
+ 16, 48, 80, 144, 248, 16, 56, 0,
+ 248, 128, 240, 8, 8, 136, 112, 0,
+ 48, 64, 128, 240, 136, 136, 112, 0,
+ 248, 136, 8, 16, 32, 32, 32, 0,
+ 112, 136, 136, 112, 136, 136, 112, 0,
+ 112, 136, 136, 120, 8, 16, 96, 0,
+ 0, 0, 48, 48, 0, 48, 48, 0,
+ 32, 16, 0, 112, 8, 248, 120, 0,
+ 32, 80, 0, 144, 144, 144, 104, 0,
+ 32, 16, 0, 112, 248, 128, 112, 0,
+ 32, 80, 0, 112, 248, 128, 112, 0,
+ 112, 136, 8, 16, 32, 0, 32, 0,
+ 32, 80, 0, 192, 64, 64, 224, 0,
+ 112, 136, 136, 248, 136, 136, 136, 0,
+ 240, 72, 72, 112, 72, 72, 240, 0,
+ 48, 72, 128, 128, 128, 72, 48, 0,
+ 224, 80, 72, 72, 72, 80, 224, 0,
+ 248, 72, 64, 112, 64, 72, 248, 0,
+ 248, 72, 64, 112, 64, 64, 224, 0,
+ 48, 72, 128, 152, 136, 72, 56, 0,
+ 136, 136, 136, 248, 136, 136, 136, 0,
+ 248, 32, 32, 32, 32, 32, 248, 0,
+ 24, 8, 8, 8, 136, 136, 112, 0,
+ 200, 72, 80, 96, 80, 72, 200, 0,
+ 224, 64, 64, 64, 64, 72, 248, 0,
+ 136, 216, 168, 168, 136, 136, 136, 0,
+ 136, 200, 168, 152, 136, 136, 136, 0,
+ 112, 136, 136, 136, 136, 136, 112, 0,
+ 240, 72, 72, 112, 64, 64, 224, 0,
+ 112, 136, 136, 136, 136, 168, 112, 8,
+ 240, 72, 72, 112, 72, 72, 200, 0,
+ 112, 136, 128, 112, 8, 136, 112, 0,
+ 248, 168, 32, 32, 32, 32, 112, 0,
+ 136, 136, 136, 136, 136, 136, 120, 0,
+ 136, 136, 136, 80, 80, 32, 32, 0,
+ 136, 136, 136, 136, 168, 216, 136, 0,
+ 136, 136, 80, 32, 80, 136, 136, 0,
+ 136, 136, 136, 112, 32, 32, 112, 0,
+ 248, 136, 16, 32, 64, 136, 248, 0,
+ 0, 14, 8, 8, 8, 8, 14, 0,
+ 0, 128, 64, 32, 16, 8, 4, 0,
+ 0, 112, 16, 16, 16, 16, 112, 0,
+ 0, 0, 112, 136, 128, 112, 32, 96,
+ 160, 0, 192, 64, 64, 64, 224, 0,
+ 32, 16, 0, 144, 144, 144, 104, 0,
+ 0, 0, 112, 8, 120, 136, 120, 0,
+ 192, 64, 80, 104, 72, 72, 112, 0,
+ 0, 0, 112, 136, 128, 136, 112, 0,
+ 24, 16, 80, 176, 144, 144, 112, 0,
+ 0, 0, 112, 136, 248, 128, 112, 0,
+ 48, 72, 64, 224, 64, 64, 224, 0,
+ 0, 0, 104, 144, 144, 112, 136, 112,
+ 192, 64, 80, 104, 72, 72, 200, 0,
+ 64, 0, 192, 64, 64, 64, 224, 0,
+ 8, 0, 8, 8, 8, 8, 136, 112,
+ 192, 64, 72, 80, 96, 80, 200, 0,
+ 192, 64, 64, 64, 64, 64, 224, 0,
+ 0, 0, 144, 216, 168, 136, 136, 0,
+ 0, 0, 240, 136, 136, 136, 136, 0,
+ 0, 0, 112, 136, 136, 136, 112, 0,
+ 0, 0, 176, 72, 72, 112, 64, 224,
+ 0, 0, 104, 144, 144, 112, 16, 56,
+ 0, 0, 176, 72, 72, 64, 224, 0,
+ 0, 0, 120, 128, 112, 8, 240, 0,
+ 64, 64, 240, 64, 64, 72, 48, 0,
+ 0, 0, 144, 144, 144, 144, 104, 0,
+ 0, 0, 136, 136, 136, 80, 32, 0,
+ 0, 0, 136, 136, 168, 216, 144, 0,
+ 0, 0, 136, 80, 32, 80, 136, 0,
+ 0, 0, 136, 136, 136, 112, 32, 192,
+ 0, 0, 248, 144, 32, 72, 248, 0,
+ 32, 80, 0, 96, 144, 144, 96, 0,
+ 0, 14, 8, 48, 8, 8, 14, 0,
+ 0, 8, 8, 8, 8, 8, 8, 0,
+ 0, 112, 16, 12, 16, 16, 112, 0,
+ 0, 0, 0, 0, 0, 0, 248, 0,
+ 252, 252, 252, 252, 252, 252, 252, 252,
+ 240, 240, 240, 240, 240, 240, 240, 240,
+};
+
+static const byte german_video_font[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 32, 112, 112, 32, 32, 0, 32, 0,
+ 48, 48, 96, 0, 0, 0, 0, 0,
+ 80, 0, 112, 8, 120, 136, 120, 0,
+ 80, 0, 112, 136, 136, 136, 112, 0,
+ 80, 0, 144, 144, 144, 144, 104, 0,
+ 0, 16, 40, 16, 42, 68, 58, 0,
+ 48, 48, 96, 0, 0, 0, 0, 0,
+ 0, 4, 8, 8, 8, 8, 4, 0,
+ 0, 32, 16, 16, 16, 16, 32, 0,
+ 0, 0, 20, 8, 62, 8, 20, 0,
+ 96, 144, 144, 160, 144, 144, 160, 128,
+ 0, 0, 0, 0, 0, 48, 48, 96,
+ 0, 0, 0, 240, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 48, 48, 0,
+ 80, 0, 112, 136, 248, 136, 136, 0,
+ 112, 136, 152, 168, 200, 136, 112, 0,
+ 32, 96, 32, 32, 32, 32, 112, 0,
+ 112, 136, 8, 48, 64, 136, 248, 0,
+ 112, 136, 8, 48, 8, 136, 112, 0,
+ 16, 48, 80, 144, 248, 16, 56, 0,
+ 248, 128, 240, 8, 8, 136, 112, 0,
+ 48, 64, 128, 240, 136, 136, 112, 0,
+ 248, 136, 8, 16, 32, 32, 32, 0,
+ 112, 136, 136, 112, 136, 136, 112, 0,
+ 112, 136, 136, 120, 8, 16, 96, 0,
+ 0, 0, 48, 48, 0, 48, 48, 0,
+ 136, 112, 136, 136, 136, 136, 112, 0,
+ 80, 0, 136, 136, 136, 136, 112, 0,
+ 80, 0, 144, 144, 144, 144, 104, 0,
+ 32, 64, 0, 112, 248, 128, 112, 0,
+ 112, 136, 8, 16, 32, 0, 32, 0,
+ 32, 80, 0, 192, 64, 64, 224, 0,
+ 112, 136, 136, 248, 136, 136, 136, 0,
+ 240, 72, 72, 112, 72, 72, 240, 0,
+ 48, 72, 128, 128, 128, 72, 48, 0,
+ 224, 80, 72, 72, 72, 80, 224, 0,
+ 248, 72, 64, 112, 64, 72, 248, 0,
+ 248, 72, 64, 112, 64, 64, 224, 0,
+ 48, 72, 128, 152, 136, 72, 56, 0,
+ 136, 136, 136, 248, 136, 136, 136, 0,
+ 248, 32, 32, 32, 32, 32, 248, 0,
+ 24, 8, 8, 8, 136, 136, 112, 0,
+ 200, 72, 80, 96, 80, 72, 200, 0,
+ 224, 64, 64, 64, 64, 72, 248, 0,
+ 136, 216, 168, 168, 136, 136, 136, 0,
+ 136, 200, 168, 152, 136, 136, 136, 0,
+ 112, 136, 136, 136, 136, 136, 112, 0,
+ 240, 72, 72, 112, 64, 64, 224, 0,
+ 112, 136, 136, 136, 136, 168, 112, 8,
+ 240, 72, 72, 112, 72, 72, 200, 0,
+ 112, 136, 128, 112, 8, 136, 112, 0,
+ 248, 168, 32, 32, 32, 32, 112, 0,
+ 136, 136, 136, 136, 136, 136, 120, 0,
+ 136, 136, 136, 80, 80, 32, 32, 0,
+ 136, 136, 136, 136, 168, 216, 136, 0,
+ 136, 136, 80, 32, 80, 136, 136, 0,
+ 136, 136, 136, 112, 32, 32, 112, 0,
+ 248, 136, 16, 32, 64, 136, 248, 0,
+ 0, 14, 8, 8, 8, 8, 14, 0,
+ 0, 128, 64, 32, 16, 8, 4, 0,
+ 0, 112, 16, 16, 16, 16, 112, 0,
+ 0, 48, 72, 64, 72, 48, 16, 48,
+ 0, 80, 0, 96, 32, 40, 48, 0,
+ 32, 16, 0, 152, 144, 144, 232, 0,
+ 0, 0, 112, 8, 120, 136, 120, 0,
+ 192, 64, 80, 104, 72, 72, 112, 0,
+ 0, 0, 112, 136, 128, 136, 112, 0,
+ 24, 16, 80, 176, 144, 144, 112, 0,
+ 0, 0, 112, 136, 248, 128, 112, 0,
+ 48, 72, 64, 224, 64, 64, 224, 0,
+ 0, 0, 104, 144, 144, 112, 136, 112,
+ 192, 64, 80, 104, 72, 72, 200, 0,
+ 64, 0, 192, 64, 64, 64, 224, 0,
+ 8, 0, 8, 8, 8, 8, 136, 112,
+ 192, 64, 72, 80, 96, 80, 200, 0,
+ 192, 64, 64, 64, 64, 64, 224, 0,
+ 0, 0, 144, 216, 168, 136, 136, 0,
+ 0, 0, 240, 136, 136, 136, 136, 0,
+ 0, 0, 112, 136, 136, 136, 112, 0,
+ 0, 0, 176, 72, 72, 112, 64, 224,
+ 0, 0, 104, 144, 144, 112, 16, 56,
+ 0, 0, 176, 72, 72, 64, 224, 0,
+ 0, 0, 120, 128, 112, 8, 240, 0,
+ 64, 64, 240, 64, 64, 72, 48, 0,
+ 0, 0, 144, 144, 144, 144, 104, 0,
+ 0, 0, 136, 136, 136, 80, 32, 0,
+ 0, 0, 136, 136, 168, 216, 144, 0,
+ 0, 0, 136, 80, 32, 80, 136, 0,
+ 0, 0, 136, 136, 136, 112, 32, 192,
+ 0, 0, 248, 144, 32, 72, 248, 0,
+ 32, 80, 0, 96, 144, 144, 96, 0,
+ 0, 14, 8, 48, 8, 8, 14, 0,
+ 0, 8, 8, 8, 8, 8, 8, 0,
+ 0, 112, 16, 12, 16, 16, 112, 0,
+ 0, 0, 0, 0, 0, 0, 248, 0,
+ 252, 252, 252, 252, 252, 252, 252, 252,
+ 240, 240, 240, 240, 240, 240, 240, 240,
+};
+
+static const byte hebrew_video_font[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 32, 112, 112, 32, 32, 0, 32, 0,
+ 48, 48, 96, 0, 0, 0, 0, 0,
+ 0, 144, 0, 96, 144, 144, 104, 0,
+ 0, 144, 0, 96, 144, 144, 96, 0,
+ 0, 144, 0, 144, 144, 144, 96, 0,
+ 0, 16, 40, 16, 42, 68, 58, 0,
+ 48, 48, 96, 0, 0, 0, 0, 0,
+ 0, 4, 8, 8, 8, 8, 4, 0,
+ 0, 32, 16, 16, 16, 16, 32, 0,
+ 0, 0, 20, 8, 62, 8, 20, 0,
+ 0, 112, 136, 240, 136, 136, 240, 0,
+ 0, 0, 0, 0, 0, 48, 48, 96,
+ 0, 0, 0, 240, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 48, 48, 0,
+ 16, 32, 0, 120, 112, 64, 56, 0,
+ 112, 136, 152, 168, 200, 136, 112, 0,
+ 32, 96, 32, 32, 32, 32, 112, 0,
+ 112, 136, 8, 48, 64, 136, 248, 0,
+ 112, 136, 8, 48, 8, 136, 112, 0,
+ 16, 48, 80, 144, 248, 16, 56, 0,
+ 248, 128, 240, 8, 8, 136, 112, 0,
+ 48, 64, 128, 240, 136, 136, 112, 0,
+ 248, 136, 8, 16, 32, 32, 32, 0,
+ 112, 136, 136, 112, 136, 136, 112, 0,
+ 112, 136, 136, 120, 8, 16, 96, 0,
+ 0, 0, 48, 48, 0, 48, 48, 0,
+ 5, 5, 4, 6, 5, 3, 4, 5,
+ 6, 3, 5, 5, 4, 6, 5, 3,
+ 4, 6, 5, 6, 6, 6, 5, 5,
+ 5, 6, 5, 6, 6, 6, 6, 6,
+ 112, 136, 8, 16, 32, 0, 32, 0,
+ 0, 0, 144, 80, 160, 144, 144, 0,
+ 0, 0, 224, 32, 32, 32, 240, 0,
+ 0, 0, 224, 32, 96, 160, 160, 0,
+ 0, 0, 248, 16, 16, 16, 16, 0,
+ 0, 0, 240, 16, 16, 144, 144, 0,
+ 0, 0, 192, 64, 64, 64, 64, 0,
+ 0, 0, 224, 64, 32, 64, 64, 0,
+ 0, 0, 240, 144, 144, 144, 144, 0,
+ 0, 0, 184, 168, 136, 136, 112, 0,
+ 0, 0, 192, 64, 0, 0, 0, 0,
+ 0, 0, 240, 16, 16, 16, 16, 16,
+ 0, 0, 224, 16, 16, 16, 224, 0,
+ 128, 128, 224, 32, 32, 32, 192, 0,
+ 0, 0, 248, 72, 72, 72, 120, 0,
+ 0, 0, 176, 208, 144, 144, 176, 0,
+ 0, 0, 192, 64, 64, 64, 64, 64,
+ 0, 0, 96, 32, 32, 32, 224, 0,
+ 0, 0, 248, 72, 72, 72, 48, 0,
+ 0, 0, 80, 80, 80, 80, 224, 0,
+ 0, 0, 248, 72, 104, 8, 8, 8,
+ 0, 0, 248, 72, 104, 8, 248, 0,
+ 0, 0, 216, 72, 48, 16, 16, 16,
+ 0, 0, 144, 80, 32, 16, 240, 0,
+ 0, 0, 240, 16, 144, 160, 128, 128,
+ 0, 0, 240, 16, 16, 16, 16, 0,
+ 0, 0, 168, 168, 200, 136, 112, 0,
+ 0, 0, 240, 80, 80, 80, 208, 0,
+ 0, 14, 8, 8, 8, 8, 14, 0,
+ 0, 128, 64, 32, 16, 8, 4, 0,
+ 0, 112, 16, 16, 16, 16, 112, 0,
+ 0, 48, 72, 64, 72, 48, 16, 48,
+ 0, 80, 0, 96, 32, 40, 48, 0,
+ 32, 16, 0, 152, 144, 144, 232, 0,
+ 0, 0, 112, 8, 120, 136, 120, 0,
+ 192, 64, 80, 104, 72, 72, 112, 0,
+ 0, 0, 112, 136, 128, 136, 112, 0,
+ 24, 16, 80, 176, 144, 144, 112, 0,
+ 0, 0, 112, 136, 248, 128, 112, 0,
+ 48, 72, 64, 224, 64, 64, 224, 0,
+ 0, 0, 104, 144, 144, 112, 136, 112,
+ 192, 64, 80, 104, 72, 72, 200, 0,
+ 64, 0, 192, 64, 64, 64, 224, 0,
+ 8, 0, 8, 8, 8, 8, 136, 112,
+ 192, 64, 72, 80, 96, 80, 200, 0,
+ 192, 64, 64, 64, 64, 64, 224, 0,
+ 0, 0, 144, 216, 168, 136, 136, 0,
+ 0, 0, 240, 136, 136, 136, 136, 0,
+ 0, 0, 112, 136, 136, 136, 112, 0,
+ 0, 0, 176, 72, 72, 112, 64, 224,
+ 0, 0, 104, 144, 144, 112, 16, 56,
+ 0, 0, 176, 72, 72, 64, 224, 0,
+ 0, 0, 120, 128, 112, 8, 240, 0,
+ 64, 64, 240, 64, 64, 72, 48, 0,
+ 0, 0, 144, 144, 144, 144, 104, 0,
+ 0, 0, 136, 136, 136, 80, 32, 0,
+ 0, 0, 136, 136, 168, 216, 144, 0,
+ 0, 0, 136, 80, 32, 80, 136, 0,
+ 0, 0, 136, 136, 136, 112, 32, 192,
+ 0, 0, 248, 144, 32, 72, 248, 0,
+ 32, 80, 0, 96, 144, 144, 96, 0,
+ 0, 14, 8, 48, 8, 8, 14, 0,
+ 0, 8, 8, 8, 8, 8, 8, 0,
+ 0, 112, 16, 12, 16, 16, 112, 0,
+ 0, 0, 0, 0, 0, 0, 248, 0,
+ 252, 252, 252, 252, 252, 252, 252, 252,
+ 240, 240, 240, 240, 240, 240, 240, 240,
+};
+
+static const byte italian_video_font[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 32, 112, 112, 32, 32, 0, 32, 0,
+ 48, 48, 96, 0, 0, 0, 0, 0,
+ 80, 0, 112, 8, 120, 136, 120, 0,
+ 80, 0, 112, 136, 136, 136, 112, 0,
+ 32, 16, 0, 112, 136, 136, 112, 0,
+ 0, 16, 40, 16, 42, 68, 58, 0,
+ 48, 48, 96, 0, 0, 0, 0, 0,
+ 0, 4, 8, 8, 8, 8, 4, 0,
+ 0, 32, 16, 16, 16, 16, 32, 0,
+ 0, 0, 20, 8, 62, 8, 20, 0,
+ 32, 16, 0, 192, 64, 64, 224, 0,
+ 0, 0, 0, 0, 0, 48, 48, 96,
+ 0, 0, 0, 240, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 48, 48, 0,
+ 32, 64, 0, 112, 248, 128, 112, 0,
+ 112, 136, 152, 168, 200, 136, 112, 0,
+ 32, 96, 32, 32, 32, 32, 112, 0,
+ 112, 136, 8, 48, 64, 136, 248, 0,
+ 112, 136, 8, 48, 8, 136, 112, 0,
+ 16, 48, 80, 144, 248, 16, 56, 0,
+ 248, 128, 240, 8, 8, 136, 112, 0,
+ 48, 64, 128, 240, 136, 136, 112, 0,
+ 248, 136, 8, 16, 32, 32, 32, 0,
+ 112, 136, 136, 112, 136, 136, 112, 0,
+ 112, 136, 136, 120, 8, 16, 96, 0,
+ 0, 0, 48, 48, 0, 48, 48, 0,
+ 32, 16, 0, 112, 8, 248, 120, 0,
+ 32, 16, 0, 112, 136, 136, 112, 0,
+ 32, 16, 0, 112, 248, 128, 112, 0,
+ 32, 80, 0, 112, 248, 128, 112, 0,
+ 112, 136, 8, 16, 32, 0, 32, 0,
+ 32, 80, 0, 96, 32, 40, 48, 0,
+ 112, 136, 136, 248, 136, 136, 136, 0,
+ 240, 72, 72, 112, 72, 72, 240, 0,
+ 48, 72, 128, 128, 128, 72, 48, 0,
+ 224, 80, 72, 72, 72, 80, 224, 0,
+ 248, 72, 64, 112, 64, 72, 248, 0,
+ 248, 72, 64, 112, 64, 64, 224, 0,
+ 48, 72, 128, 152, 136, 72, 56, 0,
+ 136, 136, 136, 248, 136, 136, 136, 0,
+ 248, 32, 32, 32, 32, 32, 248, 0,
+ 24, 8, 8, 8, 136, 136, 112, 0,
+ 200, 72, 80, 96, 80, 72, 200, 0,
+ 224, 64, 64, 64, 64, 72, 248, 0,
+ 136, 216, 168, 168, 136, 136, 136, 0,
+ 136, 200, 168, 152, 136, 136, 136, 0,
+ 112, 136, 136, 136, 136, 136, 112, 0,
+ 240, 72, 72, 112, 64, 64, 224, 0,
+ 112, 136, 136, 136, 136, 168, 112, 8,
+ 240, 72, 72, 112, 72, 72, 200, 0,
+ 112, 136, 128, 112, 8, 136, 112, 0,
+ 248, 168, 32, 32, 32, 32, 112, 0,
+ 136, 136, 136, 136, 136, 136, 120, 0,
+ 136, 136, 136, 80, 80, 32, 32, 0,
+ 136, 136, 136, 136, 168, 216, 136, 0,
+ 136, 136, 80, 32, 80, 136, 136, 0,
+ 136, 136, 136, 112, 32, 32, 112, 0,
+ 248, 136, 16, 32, 64, 136, 248, 0,
+ 0, 14, 8, 8, 8, 8, 14, 0,
+ 0, 128, 64, 32, 16, 8, 4, 0,
+ 0, 112, 16, 16, 16, 16, 112, 0,
+ 0, 0, 112, 136, 128, 112, 32, 96,
+ 160, 0, 192, 64, 64, 64, 224, 0,
+ 32, 16, 0, 144, 144, 144, 104, 0,
+ 0, 0, 112, 8, 120, 136, 120, 0,
+ 192, 64, 80, 104, 72, 72, 112, 0,
+ 0, 0, 112, 136, 128, 136, 112, 0,
+ 24, 16, 80, 176, 144, 144, 112, 0,
+ 0, 0, 112, 136, 248, 128, 112, 0,
+ 48, 72, 64, 224, 64, 64, 224, 0,
+ 0, 0, 104, 144, 144, 112, 136, 112,
+ 192, 64, 80, 104, 72, 72, 200, 0,
+ 64, 0, 192, 64, 64, 64, 224, 0,
+ 8, 0, 8, 8, 8, 8, 136, 112,
+ 192, 64, 72, 80, 96, 80, 200, 0,
+ 192, 64, 64, 64, 64, 64, 224, 0,
+ 0, 0, 144, 216, 168, 136, 136, 0,
+ 0, 0, 240, 136, 136, 136, 136, 0,
+ 0, 0, 112, 136, 136, 136, 112, 0,
+ 0, 0, 176, 72, 72, 112, 64, 224,
+ 0, 0, 104, 144, 144, 112, 16, 56,
+ 0, 0, 176, 72, 72, 64, 224, 0,
+ 0, 0, 120, 128, 112, 8, 240, 0,
+ 64, 64, 240, 64, 64, 72, 48, 0,
+ 0, 0, 144, 144, 144, 144, 104, 0,
+ 0, 0, 136, 136, 136, 80, 32, 0,
+ 0, 0, 136, 136, 168, 216, 144, 0,
+ 0, 0, 136, 80, 32, 80, 136, 0,
+ 0, 0, 136, 136, 136, 112, 32, 192,
+ 0, 0, 248, 144, 32, 72, 248, 0,
+ 32, 80, 0, 96, 144, 144, 96, 0,
+ 0, 14, 8, 48, 8, 8, 14, 0,
+ 0, 8, 8, 8, 8, 8, 8, 0,
+ 0, 112, 16, 12, 16, 16, 112, 0,
+ 0, 0, 0, 0, 0, 0, 248, 0,
+ 252, 252, 252, 252, 252, 252, 252, 252,
+ 240, 240, 240, 240, 240, 240, 240, 240,
+};
+
+static const byte spanish_video_font[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 32, 112, 112, 32, 32, 0, 32, 0,
+ 48, 48, 96, 0, 0, 0, 0, 0,
+ 80, 0, 112, 8, 120, 136, 120, 0,
+ 80, 0, 112, 136, 136, 136, 112, 0,
+ 80, 0, 144, 144, 144, 144, 104, 0,
+ 0, 16, 40, 16, 42, 68, 58, 0,
+ 48, 48, 96, 0, 0, 0, 0, 0,
+ 0, 4, 8, 8, 8, 8, 4, 0,
+ 0, 32, 16, 16, 16, 16, 32, 0,
+ 0, 0, 20, 8, 62, 8, 20, 0,
+ 96, 144, 144, 160, 144, 144, 160, 128,
+ 0, 0, 0, 0, 0, 48, 48, 96,
+ 0, 0, 0, 240, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 48, 48, 0,
+ 32, 64, 0, 112, 248, 128, 112, 0,
+ 112, 136, 152, 168, 200, 136, 112, 0,
+ 32, 96, 32, 32, 32, 32, 112, 0,
+ 112, 136, 8, 48, 64, 136, 248, 0,
+ 112, 136, 8, 48, 8, 136, 112, 0,
+ 16, 48, 80, 144, 248, 16, 56, 0,
+ 248, 128, 240, 8, 8, 136, 112, 0,
+ 48, 64, 128, 240, 136, 136, 112, 0,
+ 248, 136, 8, 16, 32, 32, 32, 0,
+ 112, 136, 136, 112, 136, 136, 112, 0,
+ 112, 136, 136, 120, 8, 16, 96, 0,
+ 0, 0, 48, 48, 0, 48, 48, 0,
+ 32, 64, 0, 112, 8, 248, 120, 0,
+ 32, 64, 0, 192, 64, 64, 224, 0,
+ 32, 64, 0, 112, 136, 136, 112, 0,
+ 32, 64, 0, 144, 144, 144, 104, 0,
+ 112, 136, 8, 16, 32, 0, 32, 0,
+ 80, 160, 0, 240, 136, 136, 136, 0,
+ 112, 136, 136, 248, 136, 136, 136, 0,
+ 240, 72, 72, 112, 72, 72, 240, 0,
+ 48, 72, 128, 128, 128, 72, 48, 0,
+ 224, 80, 72, 72, 72, 80, 224, 0,
+ 248, 72, 64, 112, 64, 72, 248, 0,
+ 248, 72, 64, 112, 64, 64, 224, 0,
+ 48, 72, 128, 152, 136, 72, 56, 0,
+ 136, 136, 136, 248, 136, 136, 136, 0,
+ 248, 32, 32, 32, 32, 32, 248, 0,
+ 24, 8, 8, 8, 136, 136, 112, 0,
+ 200, 72, 80, 96, 80, 72, 200, 0,
+ 224, 64, 64, 64, 64, 72, 248, 0,
+ 136, 216, 168, 168, 136, 136, 136, 0,
+ 136, 200, 168, 152, 136, 136, 136, 0,
+ 112, 136, 136, 136, 136, 136, 112, 0,
+ 240, 72, 72, 112, 64, 64, 224, 0,
+ 112, 136, 136, 136, 136, 168, 112, 8,
+ 240, 72, 72, 112, 72, 72, 200, 0,
+ 112, 136, 128, 112, 8, 136, 112, 0,
+ 248, 168, 32, 32, 32, 32, 112, 0,
+ 136, 136, 136, 136, 136, 136, 120, 0,
+ 136, 136, 136, 80, 80, 32, 32, 0,
+ 136, 136, 136, 136, 168, 216, 136, 0,
+ 136, 136, 80, 32, 80, 136, 136, 0,
+ 136, 136, 136, 112, 32, 32, 112, 0,
+ 248, 136, 16, 32, 64, 136, 248, 0,
+ 0, 14, 8, 8, 8, 8, 14, 0,
+ 0, 128, 64, 32, 16, 8, 4, 0,
+ 0, 112, 16, 16, 16, 16, 112, 0,
+ 32, 0, 32, 64, 128, 136, 112, 0,
+ 32, 0, 32, 32, 112, 112, 32, 0,
+ 80, 0, 144, 144, 144, 144, 104, 0,
+ 0, 0, 112, 8, 120, 136, 120, 0,
+ 192, 64, 80, 104, 72, 72, 112, 0,
+ 0, 0, 112, 136, 128, 136, 112, 0,
+ 24, 16, 80, 176, 144, 144, 112, 0,
+ 0, 0, 112, 136, 248, 128, 112, 0,
+ 48, 72, 64, 224, 64, 64, 224, 0,
+ 0, 0, 104, 144, 144, 112, 136, 112,
+ 192, 64, 80, 104, 72, 72, 200, 0,
+ 64, 0, 192, 64, 64, 64, 224, 0,
+ 8, 0, 8, 8, 8, 8, 136, 112,
+ 192, 64, 72, 80, 96, 80, 200, 0,
+ 192, 64, 64, 64, 64, 64, 224, 0,
+ 0, 0, 144, 216, 168, 136, 136, 0,
+ 0, 0, 240, 136, 136, 136, 136, 0,
+ 0, 0, 112, 136, 136, 136, 112, 0,
+ 0, 0, 176, 72, 72, 112, 64, 224,
+ 0, 0, 104, 144, 144, 112, 16, 56,
+ 0, 0, 176, 72, 72, 64, 224, 0,
+ 0, 0, 120, 128, 112, 8, 240, 0,
+ 64, 64, 240, 64, 64, 72, 48, 0,
+ 0, 0, 144, 144, 144, 144, 104, 0,
+ 0, 0, 136, 136, 136, 80, 32, 0,
+ 0, 0, 136, 136, 168, 216, 144, 0,
+ 0, 0, 136, 80, 32, 80, 136, 0,
+ 0, 0, 136, 136, 136, 112, 32, 192,
+ 0, 0, 248, 144, 32, 72, 248, 0,
+ 32, 80, 0, 96, 144, 144, 96, 0,
+ 0, 14, 8, 48, 8, 8, 14, 0,
+ 0, 8, 8, 8, 8, 8, 8, 0,
+ 0, 112, 16, 12, 16, 16, 112, 0,
+ 0, 0, 0, 0, 0, 0, 248, 0,
+ 252, 252, 252, 252, 252, 252, 252, 252,
+ 240, 240, 240, 240, 240, 240, 240, 240,
+};
+
+static const byte video_font[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 32, 112, 112, 32, 32, 0, 32, 0,
+ 48, 48, 96, 0, 0, 0, 0, 0,
+ 0, 144, 0, 96, 144, 144, 104, 0,
+ 0, 144, 0, 96, 144, 144, 96, 0,
+ 0, 144, 0, 144, 144, 144, 96, 0,
+ 0, 16, 40, 16, 42, 68, 58, 0,
+ 48, 48, 96, 0, 0, 0, 0, 0,
+ 0, 4, 8, 8, 8, 8, 4, 0,
+ 0, 32, 16, 16, 16, 16, 32, 0,
+ 0, 0, 20, 8, 62, 8, 20, 0,
+ 0, 112, 136, 240, 136, 136, 240, 0,
+ 0, 0, 0, 0, 0, 48, 48, 96,
+ 0, 0, 0, 240, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 48, 48, 0,
+ 16, 32, 0, 120, 112, 64, 56, 0,
+ 112, 136, 152, 168, 200, 136, 112, 0,
+ 32, 96, 32, 32, 32, 32, 112, 0,
+ 112, 136, 8, 48, 64, 136, 248, 0,
+ 112, 136, 8, 48, 8, 136, 112, 0,
+ 16, 48, 80, 144, 248, 16, 56, 0,
+ 248, 128, 240, 8, 8, 136, 112, 0,
+ 48, 64, 128, 240, 136, 136, 112, 0,
+ 248, 136, 8, 16, 32, 32, 32, 0,
+ 112, 136, 136, 112, 136, 136, 112, 0,
+ 112, 136, 136, 120, 8, 16, 96, 0,
+ 0, 0, 48, 48, 0, 48, 48, 0,
+ 32, 16, 0, 112, 8, 248, 120, 0,
+ 32, 80, 0, 144, 144, 144, 104, 0,
+ 80, 0, 144, 144, 144, 144, 104, 0,
+ 32, 80, 0, 112, 248, 128, 112, 0,
+ 112, 136, 8, 16, 32, 0, 32, 0,
+ 32, 80, 0, 192, 64, 64, 224, 0,
+ 112, 136, 136, 248, 136, 136, 136, 0,
+ 240, 72, 72, 112, 72, 72, 240, 0,
+ 48, 72, 128, 128, 128, 72, 48, 0,
+ 224, 80, 72, 72, 72, 80, 224, 0,
+ 248, 72, 64, 112, 64, 72, 248, 0,
+ 248, 72, 64, 112, 64, 64, 224, 0,
+ 48, 72, 128, 152, 136, 72, 56, 0,
+ 136, 136, 136, 248, 136, 136, 136, 0,
+ 248, 32, 32, 32, 32, 32, 248, 0,
+ 24, 8, 8, 8, 136, 136, 112, 0,
+ 200, 72, 80, 96, 80, 72, 200, 0,
+ 224, 64, 64, 64, 64, 72, 248, 0,
+ 136, 216, 168, 168, 136, 136, 136, 0,
+ 136, 200, 168, 152, 136, 136, 136, 0,
+ 112, 136, 136, 136, 136, 136, 112, 0,
+ 240, 72, 72, 112, 64, 64, 224, 0,
+ 112, 136, 136, 136, 136, 168, 112, 8,
+ 240, 72, 72, 112, 72, 72, 200, 0,
+ 112, 136, 128, 112, 8, 136, 112, 0,
+ 248, 168, 32, 32, 32, 32, 112, 0,
+ 136, 136, 136, 136, 136, 136, 120, 0,
+ 136, 136, 136, 80, 80, 32, 32, 0,
+ 136, 136, 136, 136, 168, 216, 136, 0,
+ 136, 136, 80, 32, 80, 136, 136, 0,
+ 136, 136, 136, 112, 32, 32, 112, 0,
+ 248, 136, 16, 32, 64, 136, 248, 0,
+ 0, 14, 8, 8, 8, 8, 14, 0,
+ 0, 128, 64, 32, 16, 8, 4, 0,
+ 0, 112, 16, 16, 16, 16, 112, 0,
+ 0, 48, 72, 64, 72, 48, 16, 48,
+ 0, 80, 0, 96, 32, 40, 48, 0,
+ 32, 16, 0, 152, 144, 144, 232, 0,
+ 0, 0, 112, 8, 120, 136, 120, 0,
+ 192, 64, 80, 104, 72, 72, 112, 0,
+ 0, 0, 112, 136, 128, 136, 112, 0,
+ 24, 16, 80, 176, 144, 144, 112, 0,
+ 0, 0, 112, 136, 248, 128, 112, 0,
+ 48, 72, 64, 224, 64, 64, 224, 0,
+ 0, 0, 104, 144, 144, 112, 136, 112,
+ 192, 64, 80, 104, 72, 72, 200, 0,
+ 64, 0, 192, 64, 64, 64, 224, 0,
+ 8, 0, 8, 8, 8, 8, 136, 112,
+ 192, 64, 72, 80, 96, 80, 200, 0,
+ 192, 64, 64, 64, 64, 64, 224, 0,
+ 0, 0, 144, 216, 168, 136, 136, 0,
+ 0, 0, 240, 136, 136, 136, 136, 0,
+ 0, 0, 112, 136, 136, 136, 112, 0,
+ 0, 0, 176, 72, 72, 112, 64, 224,
+ 0, 0, 104, 144, 144, 112, 16, 56,
+ 0, 0, 176, 72, 72, 64, 224, 0,
+ 0, 0, 120, 128, 112, 8, 240, 0,
+ 64, 64, 240, 64, 64, 72, 48, 0,
+ 0, 0, 144, 144, 144, 144, 104, 0,
+ 0, 0, 136, 136, 136, 80, 32, 0,
+ 0, 0, 136, 136, 168, 216, 144, 0,
+ 0, 0, 136, 80, 32, 80, 136, 0,
+ 0, 0, 136, 136, 136, 112, 32, 192,
+ 0, 0, 248, 144, 32, 72, 248, 0,
+ 32, 80, 0, 96, 144, 144, 96, 0,
+ 0, 14, 8, 48, 8, 8, 14, 0,
+ 0, 8, 8, 8, 8, 8, 8, 0,
+ 0, 112, 16, 12, 16, 16, 112, 0,
+ 0, 0, 0, 0, 0, 0, 248, 0,
+ 252, 252, 252, 252, 252, 252, 252, 252,
+ 240, 240, 240, 240, 240, 240, 240, 240,
+};
+#endif
+
+static const byte feeble_video_font[] = {
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 128,128,128,128,128,128,128,0,0,128,0,0,0,
+ 144,144,144,0,0,0,0,0,0,0,0,0,0,
+ 0,72,252,72,72,252,72,0,0,0,0,0,0,
+ 124,146,144,144,124,18,18,18,146,124,16,16,0,
+ 62,98,146,100,8,16,32,76,146,140,0,0,0,
+ 0,112,136,136,80,32,82,138,132,122,0,0,0,
+ 128,128,128,0,0,0,0,0,0,0,0,0,0,
+ 32,64,128,128,128,128,128,128,64,32,0,0,0,
+ 128,64,32,32,32,32,32,32,64,128,0,0,0,
+ 16,146,84,56,56,84,146,16,0,0,0,0,0,
+ 0,0,16,16,16,254,16,16,16,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,64,64,128,0,
+ 0,0,0,0,0,254,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,128,0,0,0,
+ 0,0,1,2,4,8,16,32,64,128,128,0,0,
+ 120,132,132,132,132,132,132,132,132,120,0,0,0,
+ 16,48,16,16,16,16,16,16,16,56,0,0,0,
+ 120,132,132,4,4,8,16,32,64,252,0,0,0,
+ 124,130,130,2,2,28,2,2,130,124,0,0,0,
+ 4,12,20,36,68,132,254,4,4,4,0,0,0,
+ 254,128,128,252,2,2,2,2,130,124,0,0,0,
+ 62,64,128,252,130,130,130,130,130,124,0,0,0,
+ 254,2,2,2,2,4,8,16,16,16,0,0,0,
+ 120,132,132,132,120,132,132,132,132,120,0,0,0,
+ 124,130,130,130,130,130,126,2,2,124,0,0,0,
+ 0,0,0,0,128,0,0,0,128,0,0,0,0,
+ 0,0,0,0,0,64,0,0,0,64,64,128,0,
+ 0,0,16,32,64,128,64,32,16,0,0,0,0,
+ 0,0,0,254,0,0,254,0,0,0,0,0,0,
+ 0,0,128,64,32,16,32,64,128,0,0,0,0,
+ 60,66,130,2,4,8,16,16,0,16,16,0,0,
+ 60,66,130,154,166,166,156,128,128,126,0,0,0,
+ 124,130,130,130,130,254,130,130,130,130,0,0,0,
+ 252,130,130,130,252,130,130,130,130,252,0,0,0,
+ 124,130,130,128,128,128,128,130,130,124,0,0,0,
+ 252,130,130,130,130,130,130,130,130,252,0,0,0,
+ 254,128,128,128,128,252,128,128,128,254,0,0,0,
+ 254,128,128,128,128,252,128,128,128,128,0,0,0,
+ 124,130,130,128,128,134,130,130,130,124,0,0,0,
+ 130,130,130,130,130,254,130,130,130,130,0,0,0,
+ 224,64,64,64,64,64,64,64,64,224,0,0,0,
+ 30,2,2,2,2,2,130,130,130,124,0,0,0,
+ 130,130,132,136,144,224,144,136,132,130,0,0,0,
+ 128,128,128,128,128,128,128,128,128,254,0,0,0,
+ 130,198,170,146,130,130,130,130,130,130,0,0,0,
+ 130,130,194,162,146,138,134,130,130,130,0,0,0,
+ 124,130,130,130,130,130,130,130,130,124,0,0,0,
+ 252,130,130,130,130,252,128,128,128,128,0,0,0,
+ 124,130,130,130,130,130,130,130,130,126,2,2,0,
+ 252,130,130,130,130,252,130,130,130,130,0,0,0,
+ 124,130,128,128,124,2,2,130,130,124,0,0,0,
+ 254,16,16,16,16,16,16,16,16,16,0,0,0,
+ 130,130,130,130,130,130,130,130,130,124,0,0,0,
+ 130,130,130,130,130,130,130,68,40,16,0,0,0,
+ 130,130,130,130,130,130,130,146,170,198,0,0,0,
+ 130,68,40,16,16,16,16,40,68,130,0,0,0,
+ 130,130,130,130,68,40,16,16,16,16,0,0,0,
+ 254,2,2,4,8,16,32,64,128,254,0,0,0,
+ 224,128,128,128,128,128,128,128,128,224,0,0,0,
+ 128,128,64,32,16,8,4,2,1,0,0,0,0,
+ 224,32,32,32,32,32,32,32,32,224,0,0,0,
+ 160,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,255,0,0,0,
+ 32,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,62,66,130,130,130,134,122,0,0,0,
+ 128,128,128,252,130,130,130,130,130,252,0,0,0,
+ 0,0,0,124,130,128,128,128,130,124,0,0,0,
+ 2,2,2,126,130,130,130,130,130,126,0,0,0,
+ 0,0,0,124,130,130,254,128,128,126,0,0,0,
+ 28,32,32,248,32,32,32,32,32,32,0,0,0,
+ 0,0,0,62,66,130,130,130,130,126,2,2,124,
+ 128,128,128,252,130,130,130,130,130,130,0,0,0,
+ 64,0,0,64,192,64,64,64,64,224,0,0,0,
+ 16,0,0,16,16,16,16,16,16,16,16,16,224,
+ 128,128,128,132,136,144,224,144,136,132,0,0,0,
+ 192,64,64,64,64,64,64,64,64,64,0,0,0,
+ 0,0,0,252,146,146,146,146,146,146,0,0,0,
+ 0,0,0,156,162,194,130,130,130,130,0,0,0,
+ 0,0,0,124,130,130,130,130,130,124,0,0,0,
+ 0,0,0,252,130,130,130,130,130,252,128,128,128,
+ 0,0,0,126,130,130,130,130,130,126,2,2,2,
+ 0,0,0,156,162,194,128,128,128,128,0,0,0,
+ 0,0,0,124,128,128,120,4,4,248,0,0,0,
+ 32,32,32,248,32,32,32,32,32,28,0,0,0,
+ 0,0,0,130,130,130,130,130,130,126,0,0,0,
+ 0,0,0,130,130,130,130,68,40,16,0,0,0,
+ 0,0,0,146,146,146,146,146,146,124,0,0,0,
+ 0,0,0,130,68,40,16,40,68,130,0,0,0,
+ 0,0,0,130,130,130,130,130,130,126,2,2,124,
+ 0,0,0,254,4,8,16,32,64,254,0,0,0,
+ 48,64,64,64,64,128,64,64,64,64,48,0,0,
+ 128,128,128,128,128,128,128,128,128,128,128,128,0,
+ 192,32,32,32,32,16,32,32,32,32,192,0,0,
+ 152,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,254,0,0,
+ 124,130,130,128,128,128,128,130,130,124,16,16,48,
+ 0,40,0,130,130,130,130,130,130,126,0,0,0,
+ 16,32,0,124,130,130,254,128,128,126,0,0,0,
+ 16,40,0,62,66,130,130,130,134,122,0,0,0,
+ 0,40,0,62,66,130,130,130,134,122,0,0,0,
+ 16,8,0,62,66,130,130,130,134,122,0,0,0,
+ 8,20,8,62,66,130,130,130,134,122,0,0,0,
+ 0,0,0,124,130,128,128,128,130,124,16,16,48,
+ 16,40,0,124,130,130,254,128,128,126,0,0,0,
+ 0,40,0,124,130,130,254,128,128,126,0,0,0,
+ 16,8,0,124,130,130,254,128,128,126,0,0,0,
+ 0,160,0,64,192,64,64,64,64,224,0,0,0,
+ 64,160,0,64,192,64,64,64,64,224,0,0,0,
+ 128,64,0,64,192,64,64,64,64,224,0,0,0,
+ 40,0,124,130,130,130,254,130,130,130,0,0,0,
+ 16,40,124,130,130,130,254,130,130,130,0,0,0,
+ 40,0,254,128,128,252,128,128,128,254,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 16,40,0,124,130,130,130,130,130,124,0,0,0,
+ 0,40,0,124,130,130,130,130,130,124,0,0,0,
+ 32,16,0,124,130,130,130,130,130,124,0,0,0,
+ 16,40,0,130,130,130,130,130,130,126,0,0,0,
+ 16,8,0,130,130,130,130,130,130,126,0,0,0,
+ 0,40,0,130,130,130,130,130,130,126,2,2,124,
+ 40,0,124,130,130,130,130,130,130,124,0,0,0,
+ 40,0,130,130,130,130,130,130,130,124,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 8,16,0,62,66,130,130,130,134,122,0,0,0,
+ 64,128,0,64,192,64,64,64,64,224,0,0,0,
+ 16,32,0,124,130,130,130,130,130,124,0,0,0,
+ 8,16,0,130,130,130,130,130,130,126,0,0,0,
+ 20,40,0,156,162,194,130,130,130,130,0,0,0,
+ 20,40,130,194,162,146,138,134,130,130,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 16,16,0,16,16,32,64,128,130,132,120,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 128,0,0,128,128,128,128,128,128,128,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 60,66,130,130,130,132,132,130,130,130,156,128,128,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,
+};
+
+void SimonEngine::video_putchar_drawchar(WindowBlock *window, uint x, uint y, byte chr) {
+ const byte *src;
+ byte color, *dst;
+ uint h, w, i;
+
+ if (_noOracleScroll)
+ return;
+
+ _lockWord |= 0x8000;
+
+ dst = getFrontBuf() + y * _dxSurfacePitch + x + window->textColumnOffset;
+
+ if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ h = 13;
+ w = feebleFontSize[chr - 0x20];
+
+ src = feeble_video_font + (chr - 0x20) * 13;
+ } else {
+ h = 8;
+ w = 6;
+
+ switch (_language) {
+ case Common::RU_RUS:
+ src = russian_video_font + (chr - 0x20) * 8;
+ break;
+ case Common::PL_POL:
+ src = polish_video_font + (chr - 0x20) * 8;
+ break;
+ case Common::HB_ISR:
+ src = hebrew_video_font + (chr - 0x20) * 8;
+ break;
+ case Common::ES_ESP:
+ src = spanish_video_font + (chr - 0x20) * 8;
+ break;
+ case Common::IT_ITA:
+ src = italian_video_font + (chr - 0x20) * 8;
+ break;
+ case Common::FR_FRA:
+ src = french_video_font + (chr - 0x20) * 8;
+ break;
+ case Common::DE_DEU:
+ src = german_video_font + (chr - 0x20) * 8;
+ break;
+ case Common::EN_ANY:
+ src = video_font + (chr - 0x20) * 8;
+ break;
+ default:
+ error("video_putchar_drawchar: Unknown language %d\n", _language);
+ }
+ }
+
+ color = window->text_color;
+
+ do {
+ int8 b = *src++;
+ i = 0;
+ do {
+ if (b < 0) {
+ if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ if (dst[i] == 0)
+ dst[i] = color;
+ } else {
+ dst[i] = color;
+ }
+ }
+
+ b <<= 1;
+ } while (++i != w);
+ dst += _dxSurfacePitch;
+ } while (--h);
+
+ _lockWord &= ~0x8000;
+}
+
+} // End of namespace Simon
+
+#ifdef PALMOS_68K
+#include "scumm_globals.h"
+
+_GINIT(AGOS_Charset)
+_GSETPTR(Simon::russian_video_font, GBVARS_RUSSIANVIDEOFONT_INDEX, byte, GBVARS_SIMON)
+//_GSETPTR(Simon::polish_video_font, GBVARS_POLISHVIDEOFONT_INDEX, byte, GBVARS_SIMON)
+_GSETPTR(Simon::french_video_font, GBVARS_FRENCHVIDEOFONT_INDEX, byte, GBVARS_SIMON)
+_GSETPTR(Simon::german_video_font, GBVARS_GERMANVIDEOFONT_INDEX, byte, GBVARS_SIMON)
+_GSETPTR(Simon::hebrew_video_font, GBVARS_HEBREWVIDEOFONT_INDEX, byte, GBVARS_SIMON)
+_GSETPTR(Simon::italian_video_font, GBVARS_ITALIANVIDEOFONT_INDEX, byte, GBVARS_SIMON)
+_GSETPTR(Simon::spanish_video_font, GBVARS_SPANISHVIDEOFONT_INDEX, byte, GBVARS_SIMON)
+_GSETPTR(Simon::video_font, GBVARS_VIDEOFONT_INDEX, byte, GBVARS_SIMON)
+_GEND
+
+_GRELEASE(AGOS_Charset)
+_GRELEASEPTR(GBVARS_RUSSIANVIDEOFONT_INDEX, GBVARS_SIMON)
+//_GRELEASEPTR(GBVARS_POLISHVIDEOFONT_INDEX, GBVARS_SIMON)
+_GRELEASEPTR(GBVARS_FRENCHVIDEOFONT_INDEX, GBVARS_SIMON)
+_GRELEASEPTR(GBVARS_GERMANVIDEOFONT_INDEX, GBVARS_SIMON)
+_GRELEASEPTR(GBVARS_HEBREWVIDEOFONT_INDEX, GBVARS_SIMON)
+_GRELEASEPTR(GBVARS_ITALIANVIDEOFONT_INDEX, GBVARS_SIMON)
+_GRELEASEPTR(GBVARS_SPANISHVIDEOFONT_INDEX, GBVARS_SIMON)
+_GRELEASEPTR(GBVARS_VIDEOFONT_INDEX, GBVARS_SIMON)
+_GEND
+
+#endif
diff --git a/engines/agos/cursor.cpp b/engines/agos/cursor.cpp
new file mode 100644
index 0000000000..fe342f635d
--- /dev/null
+++ b/engines/agos/cursor.cpp
@@ -0,0 +1,495 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-2006 The ScummVM project
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/stdafx.h"
+
+#include "common/system.h"
+
+#include "graphics/cursorman.h"
+
+#include "agos/agos.h"
+
+namespace Simon {
+
+#ifdef PALMOS_68K
+static const byte *_simon1_cursor;
+#else
+static const byte _simon1_cursor[256] = {
+ 0xe1,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xe1,0xe1,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xe1,0xe1,0xe1,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xe1,0xe1,0xe1,0xe1,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xe1,0xe1,0xe1,0xe1,0xe1,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xe1,0xe1,0xe1,0xe1,0xe0,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xe1,0xff,0xff,0xe1,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xe1,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xe1,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xe1,0xe0,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+};
+#endif
+static const byte _simon2_cursors[10][256] = {
+ // cross hair
+ { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xec,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xec,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xec,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xec,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xec,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xec,0xec,0xec,0xec,0xec,0xef,0xff,0xea,0xff,0xef,0xec,0xec,0xec,0xec,0xec,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xec,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xec,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xec,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xec,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xec,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff },
+ // examine
+ { 0xff,0xff,0xef,0xef,0xef,0xef,0xef,0xef,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xef,0xee,0xeb,0xe4,0xe4,0xe4,0xee,0xef,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xef,0xee,0xeb,0xee,0xef,0xef,0xee,0xec,0xee,0xef,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xef,0xeb,0xee,0xef,0xee,0xee,0xef,0xee,0xe4,0xef,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xef,0xeb,0xef,0xef,0xef,0xec,0xee,0xef,0xe4,0xef,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xef,0xeb,0xef,0xef,0xee,0xef,0xef,0xef,0xe4,0xef,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xef,0xeb,0xee,0xef,0xef,0xef,0xef,0xee,0xe4,0xef,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xef,0xee,0xeb,0xee,0xef,0xef,0xee,0xe4,0xee,0xef,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xef,0xee,0xeb,0xeb,0xeb,0xeb,0xee,0xe4,0xec,0xef,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xef,0xef,0xef,0xef,0xef,0xef,0xeb,0xe4,0xee,0xef,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xee,0xe4,0xeb,0xef,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xeb,0xe4,0xeb,0xef,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xeb,0xec,0xeb,0xef,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xeb,0xe4,0xef,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xef,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff },
+ // pick up
+ { 0xff,0xff,0xff,0xff,0xff,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xe5,0xe6,0xe6,0xe7,0xe7,0xe6,0xe6,0xe5,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xe5,0xe7,0xe7,0xe7,0xe7,0xe8,0xe8,0xe8,0xe8,0xe5,0xff,0xff,0xff,
+ 0xff,0xff,0xe5,0xe6,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe8,0xe9,0xe7,0xe5,0xff,0xff,
+ 0xff,0xe5,0xe6,0xe7,0xe6,0xe5,0xff,0xff,0xff,0xff,0xe5,0xe6,0xe8,0xe6,0xe5,0xff,
+ 0xff,0xe5,0xe7,0xe7,0xe5,0xff,0xff,0xff,0xff,0xff,0xff,0xe5,0xe8,0xe7,0xe5,0xff,
+ 0xff,0xe5,0xe7,0xe7,0xe5,0xff,0xff,0xff,0xff,0xff,0xff,0xe5,0xe7,0xe7,0xe5,0xff,
+ 0xff,0xef,0xeb,0xeb,0xef,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xeb,0xeb,0xef,0xff,
+ 0xff,0xef,0xee,0xeb,0xee,0xef,0xff,0xff,0xff,0xff,0xef,0xee,0xeb,0xee,0xef,0xff,
+ 0xff,0xff,0xef,0xeb,0xeb,0xef,0xff,0xff,0xff,0xff,0xef,0xeb,0xeb,0xef,0xff,0xff,
+ 0xff,0xff,0xef,0xee,0xe4,0xee,0xef,0xff,0xff,0xef,0xee,0xe4,0xee,0xef,0xff,0xff,
+ 0xff,0xff,0xff,0xef,0xe4,0xeb,0xef,0xff,0xff,0xef,0xeb,0xe4,0xef,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xeb,0xeb,0xeb,0xef,0xef,0xeb,0xeb,0xeb,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xef,0xee,0xee,0xee,0xee,0xe1,0xe1,0xef,0xff,0xff,0xff,0xe4,
+ 0xef,0xee,0xeb,0xeb,0xeb,0xeb,0xeb,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xe4,0xeb,0xec,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe4 },
+ // give
+ { 0xff,0xff,0xff,0xff,0xff,0xe5,0xe7,0xe5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xe5,0xe7,0xe8,0xe7,0xe5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xe9,0xe7,0xe8,0xe8,0xe8,0xe7,0xe9,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xe5,0xe7,0xea,0xe8,0xe8,0xe8,0xea,0xe7,0xe5,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xe5,0xe7,0xe8,0xe8,0xea,0xe9,0xea,0xe8,0xe8,0xe7,0xe5,0xff,0xff,0xff,0xff,
+ 0xe5,0xe7,0xe9,0xe8,0xe8,0xe9,0xec,0xe9,0xe8,0xe8,0xe8,0xe7,0xe5,0xff,0xff,0xff,
+ 0xe5,0xe7,0xe7,0xe9,0xe8,0xec,0xe9,0xec,0xe8,0xe9,0xe7,0xe6,0xe5,0xff,0xff,0xff,
+ 0xe5,0xe7,0xe7,0xe8,0xec,0xe9,0xe9,0xe9,0xec,0xe7,0xe6,0xe6,0xe5,0xff,0xff,0xff,
+ 0xe5,0xe7,0xe7,0xea,0xe8,0xe9,0xe9,0xe9,0xe7,0xec,0xec,0xe4,0xe5,0xff,0xff,0xff,
+ 0xe5,0xe7,0xe7,0xe9,0xe7,0xe8,0xe9,0xe7,0xe6,0xec,0xe4,0xec,0xe4,0xef,0xff,0xff,
+ 0xe5,0xe6,0xe7,0xe9,0xe7,0xe7,0xe8,0xe6,0xe6,0xe4,0xec,0xe4,0xec,0xe4,0xef,0xff,
+ 0xff,0xe5,0xe6,0xe9,0xe7,0xe7,0xe8,0xe6,0xe6,0xe8,0xe4,0xec,0xe4,0xec,0xeb,0xff,
+ 0xff,0xff,0xe5,0xe9,0xe7,0xe7,0xe8,0xe6,0xe6,0xe8,0xe6,0xe4,0xec,0xeb,0xef,0xff,
+ 0xff,0xff,0xff,0xe8,0xe7,0xe7,0xe8,0xe6,0xe6,0xe7,0xff,0xef,0xeb,0xef,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xe5,0xe7,0xe8,0xe6,0xe5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xe5,0xe6,0xe5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff },
+ // talk
+ { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xe5,0xe7,0xe8,0xe8,0xe8,0xe7,0xe6,0xe5,0xe5,0xe5,0xff,0xff,0xff,0xff,
+ 0xff,0xe5,0xe6,0xe9,0xea,0xe6,0xea,0xe9,0xe8,0xe9,0xe8,0xe7,0xe5,0xff,0xff,0xff,
+ 0xff,0xe5,0xe7,0xe5,0xef,0xe5,0xec,0xea,0xe5,0xea,0xec,0xe5,0xe9,0xe6,0xff,0xff,
+ 0xff,0xe5,0xe6,0xe5,0xef,0xef,0xef,0xe5,0xef,0xef,0xe5,0xef,0xef,0xe8,0xe5,0xff,
+ 0xff,0xe5,0xe9,0xea,0xe5,0xe8,0xe7,0xe6,0xe6,0xe8,0xe7,0xe5,0xec,0xe9,0xe5,0xff,
+ 0xff,0xe5,0xe9,0xe8,0xe5,0xe7,0xe8,0xe8,0xe9,0xe9,0xe8,0xe5,0xe9,0xe9,0xe5,0xff,
+ 0xff,0xe5,0xe6,0xec,0xea,0xe5,0xe6,0xe6,0xe7,0xe7,0xe6,0xe5,0xec,0xe8,0xe5,0xff,
+ 0xff,0xff,0xe5,0xe9,0xe8,0xe9,0xe5,0xe8,0xe5,0xe8,0xe5,0xe9,0xe9,0xe7,0xe5,0xff,
+ 0xff,0xff,0xe5,0xe7,0xe9,0xec,0xe8,0xec,0xe8,0xec,0xe8,0xec,0xe8,0xe5,0xff,0xff,
+ 0xff,0xff,0xff,0xe5,0xe6,0xe8,0xe9,0xe9,0xe9,0xe9,0xe9,0xe8,0xe5,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff },
+ // use
+ { 0xff,0xff,0xff,0xff,0xff,0xee,0xe1,0xeb,0xee,0xef,0xef,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xef,0xef,0xef,0xe4,0xeb,0xee,0xe5,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xeb,0xe4,0xe4,0xeb,0xe5,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xeb,0xe4,0xec,0xe4,0xef,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xeb,0xeb,0xe4,0xe4,0xee,0xef,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xee,0xeb,0xeb,0xeb,0xe1,0xef,0xee,0xef,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe5,0xe6,0xef,0xef,0xee,0xeb,0xeb,0xe4,0xee,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xe5,0xe6,0xff,0xff,0xff,0xef,0xeb,0xec,0xeb,0xef,
+ 0xff,0xff,0xff,0xff,0xff,0xe5,0xe6,0xe5,0xff,0xff,0xff,0xee,0xe4,0xeb,0xef,0xff,
+ 0xff,0xff,0xff,0xe5,0xe5,0xe6,0xe5,0xff,0xff,0xff,0xff,0xef,0xee,0xef,0xff,0xff,
+ 0xff,0xff,0xe5,0xe6,0xe8,0xe5,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0xff,0xff,0xff,
+ 0xff,0xe5,0xe6,0xe8,0xe6,0xe5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xe5,0xe6,0xe8,0xe6,0xe5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xe5,0xe6,0xe6,0xe5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xe5,0xe5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff },
+ // wear
+ { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xef,0xeb,0xed,0xe4,0xe2,0xeb,0xee,0xee,0xee,0xef,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xef,0xe2,0xec,0xe2,0xe1,0xee,0xef,0xef,0xee,0xef,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xef,0xeb,0xed,0xeb,0xee,0xef,0xef,0xef,0xee,0xef,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xef,0xee,0xe4,0xeb,0xee,0xef,0xef,0xee,0xef,0xef,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xef,0xe4,0xeb,0xee,0xef,0xef,0xee,0xef,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xef,0xe2,0xeb,0xee,0xef,0xef,0xee,0xef,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xef,0xeb,0xe1,0xee,0xef,0xef,0xee,0xef,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xef,0xeb,0xe1,0xee,0xef,0xef,0xef,0xef,0xff,0xff,0xff,0xff,
+ 0xff,0xef,0xef,0xef,0xe1,0xe4,0xe4,0xe4,0xe1,0xeb,0xee,0xef,0xef,0xef,0xff,0xff,
+ 0xef,0xee,0xee,0xef,0xee,0xee,0xee,0xee,0xee,0xef,0xef,0xef,0xee,0xee,0xef,0xff,
+ 0xff,0xef,0xef,0xee,0xe1,0xe2,0xe4,0xe4,0xe4,0xeb,0xe1,0xee,0xef,0xef,0xff,0xff,
+ 0xff,0xff,0xff,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xef,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff },
+ // move
+ { 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xff,
+ 0xff,0xe1,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe1,0xff,
+ 0xff,0xe1,0xe3,0xe3,0xe3,0xed,0xe3,0xe3,0xe3,0xe3,0xed,0xe3,0xe3,0xe3,0xe1,0xff,
+ 0xff,0xe1,0xe3,0xe3,0xed,0xec,0xe3,0xe3,0xe3,0xe3,0xec,0xed,0xe3,0xe3,0xe1,0xff,
+ 0xff,0xe1,0xe3,0xed,0xec,0xec,0xec,0xec,0xec,0xec,0xec,0xec,0xed,0xe3,0xe1,0xff,
+ 0xff,0xe1,0xed,0xec,0xec,0xec,0xec,0xec,0xec,0xec,0xec,0xec,0xec,0xed,0xe1,0xff,
+ 0xff,0xe1,0xe3,0xed,0xec,0xec,0xec,0xec,0xec,0xec,0xec,0xec,0xed,0xe3,0xe1,0xff,
+ 0xff,0xe1,0xe3,0xe3,0xed,0xec,0xe3,0xe3,0xe3,0xe3,0xec,0xed,0xe3,0xe3,0xe1,0xff,
+ 0xff,0xe1,0xe3,0xe3,0xe3,0xed,0xe3,0xe3,0xe3,0xe3,0xed,0xe3,0xe3,0xe3,0xe1,0xff,
+ 0xff,0xe1,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe2,0xe1,0xff,
+ 0xff,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xe1,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff },
+ // open
+ { 0xff,0xff,0xe5,0xe8,0xe8,0xe7,0xe5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xe5,0xe8,0xe7,0xe5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xe5,0xe7,0xe5,0xe7,0xe5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xe5,0xff,0xe5,0xe7,0xe6,0xe9,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xe6,0xea,0xe6,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xe6,0xea,0xe6,0xe7,0xe5,0xff,0xe5,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xe6,0xea,0xe6,0xff,0xe5,0xe7,0xe5,0xe7,0xe5,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xe6,0xea,0xe6,0xff,0xff,0xff,0xe5,0xe7,0xe8,0xe5,0xff,0xff,0xff,
+ 0xff,0xe5,0xe6,0xea,0xe6,0xff,0xff,0xff,0xe5,0xe7,0xe8,0xe8,0xe5,0xff,0xff,0xff,
+ 0xff,0xe5,0xe9,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xea,0xe5,0xff,0xff,0xff,0xff,
+ 0xff,0xe5,0xe9,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xe7,0xea,0xe5,0xff,0xff,0xff,0xff,
+ 0xff,0xe5,0xe9,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xe9,0xe5,0xff,0xff,0xff,0xff,
+ 0xff,0xe5,0xe9,0xe8,0xe8,0xe8,0xe8,0xe8,0xe7,0xe7,0xe9,0xe5,0xff,0xff,0xff,0xff,
+ 0xff,0xe5,0xe9,0xe6,0xe6,0xe6,0xe6,0xe6,0xe6,0xe5,0xe9,0xe5,0xff,0xff,0xff,0xff,
+ 0xff,0xe5,0xe9,0xe8,0xe8,0xe8,0xe8,0xe8,0xe8,0xe7,0xe9,0xe5,0xff,0xff,0xff,0xff,
+ 0xff,0xe5,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe9,0xe5,0xff,0xff,0xff,0xff },
+ // question mark
+ { 0xff,0xff,0xff,0xff,0xff,0xe5,0xe5,0xe5,0xe5,0xe5,0xe5,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xe5,0xe7,0xea,0xec,0xec,0xec,0xe9,0xe5,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xe5,0xe7,0xea,0xec,0xea,0xe9,0xea,0xec,0xe9,0xe5,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xe5,0xe9,0xec,0xe9,0xe8,0xe7,0xe8,0xea,0xec,0xe5,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xe5,0xe8,0xe9,0xe8,0xe5,0xe5,0xe8,0xe9,0xec,0xe5,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xe5,0xe5,0xe5,0xe5,0xe8,0xe9,0xec,0xe9,0xe5,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xe5,0xe9,0xec,0xec,0xe9,0xe5,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xe5,0xe8,0xec,0xea,0xe8,0xe5,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xe5,0xe9,0xec,0xe9,0xe5,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xe5,0xe9,0xea,0xe9,0xe5,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xe5,0xe7,0xe9,0xe7,0xe5,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xe5,0xe5,0xe5,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xe5,0xe8,0xe9,0xe8,0xe5,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xe5,0xe9,0xec,0xe9,0xe5,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xe5,0xe8,0xe9,0xe8,0xe5,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xe5,0xe5,0xe5,0xff,0xff,0xff,0xff,0xff,0xff,0xff },
+};
+
+void SimonEngine::drawMousePointer() {
+ if (getGameType() == GType_SIMON2) {
+ CursorMan.replaceCursor(_simon2_cursors[_mouseCursor], 16, 16, 7, 7);
+ } else {
+ CursorMan.replaceCursor(_simon1_cursor, 16, 16, 0, 0);
+ }
+}
+
+void SimonEngine::handleMouseMoved() {
+ uint x;
+
+ if (_mouseHideCount) {
+ CursorMan.showMouse(false);
+ return;
+ }
+
+ CursorMan.showMouse(true);
+ pollMouseXY();
+
+ if (_mouseX <= 0)
+ _mouseX = 0;
+ if (_mouseX >= _screenWidth - 1)
+ _mouseX = _screenWidth - 1;
+
+ if (_mouseY <= 0)
+ _mouseY = 0;
+ if (_mouseY >= _screenHeight - 1)
+ _mouseY = _screenHeight - 1;
+
+ if (_defaultVerb) {
+ uint id = 101;
+ if (_mouseY >= 136)
+ id = 102;
+ if (_defaultVerb != id)
+ resetVerbs();
+ }
+
+ if (getGameType() == GType_FF) {
+ if (getBitFlag(99)) { // Oracle
+ if (_mouseX >= 10 && _mouseX <= 635 && _mouseY >= 5 && _mouseY <= 475) {
+ setBitFlag(98, true);
+ } else {
+ if (getBitFlag(98)) {
+ _variableArray[254] = 63;
+ }
+ }
+ } else if (getBitFlag(88)) { // Close Up
+ if (_mouseX >= 10 && _mouseX <= 635 && _mouseY >= 5 && _mouseY <= 475) {
+ setBitFlag(87, true);
+ } else {
+ if (getBitFlag(87)) {
+ _variableArray[254] = 75;
+ }
+ }
+ }
+
+ if (_rightButtonDown) {
+ _rightButtonDown = 0;
+ setVerb(NULL);
+ }
+ }
+ if (getGameType() == GType_SIMON2) {
+ if (getBitFlag(79)) {
+ if (!_vgaVar9) {
+ if (_mouseX >= 315 || _mouseX < 9)
+ goto get_out2;
+ _vgaVar9 = 1;
+ }
+ if (_scrollCount == 0) {
+ if (_mouseX >= 315) {
+ if (_scrollX != _scrollXMax)
+ _scrollFlag = 1;
+ } else if (_mouseX < 8) {
+ if (_scrollX != 0)
+ _scrollFlag = -1;
+ }
+ }
+ } else {
+ get_out2:;
+ _vgaVar9 = 0;
+ }
+ }
+
+ if (_mouseX != _mouseXOld || _mouseY != _mouseYOld)
+ _needHitAreaRecalc++;
+
+ x = 0;
+ if (_lastHitArea3 == 0 && _leftButtonDown != 0) {
+ _leftButtonDown = 0;
+ x = 1;
+ } else {
+ if (_hitarea_unk_3 == 0 && _needHitAreaRecalc == 0)
+ goto get_out;
+ }
+
+ boxController(_mouseX, _mouseY, x);
+ _lastHitArea3 = _lastHitArea;
+ if (x == 1 && _lastHitArea == NULL)
+ _lastHitArea3 = (HitArea *) -1;
+
+get_out:
+ if (getGameType() == GType_FF)
+ drawMousePointer_FF();
+ else
+ drawMousePointer();
+
+ _needHitAreaRecalc = 0;
+}
+
+void SimonEngine::mouseOff() {
+ _mouseHideCount++;
+}
+
+void SimonEngine::mouseOn() {
+ _lockWord |= 1;
+
+ if (_mouseHideCount != 0)
+ _mouseHideCount--;
+
+ _lockWord &= ~1;
+}
+
+void SimonEngine::pollMouseXY() {
+ _mouseX = _sdlMouseX;
+ _mouseY = _sdlMouseY;
+}
+
+// Feeble Files specific
+static const byte _mouseOffs[29 * 32] = {
+ 6,0,15,21,16,21,14,21,15,21,16,21,16,21,16,21,15,21,15,21,15,21,14,21,12,21,12,21,12,21,12,21,
+ 6,2,10,12,9,12,8,11,7,10,6,9,4,8,3,7,1,7,0,6,3,7,4,8,6,9,7,10,8,11,9,12,
+ 0,0,0,0,0,0,0,0,0,1,0,3,0,3,0,4,1,4,1,3,2,3,2,2,1,3,0,4,0,3,0,0,
+
+ 0,0,5,16,4,19,2,21,1,21,1,21,1,21,1,18,3,9,6,2,6,0,3,6,4,12,4,13,4,13,4,14,
+ 0,0,6,13,5,15,4,16,3,19,2,19,2,19,2,18,1,16,4,10,7,3,7,0,4,2,4,6,0,0,0,0,
+
+ 0,0,7,0,7,1,8,1,11,1,13,1,9,1,6,1,6,0,6,0,6,0,7,0,11,0,13,0,9,0,7,0,
+
+ 0,0,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+// SAM icons
+ 0,0,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,2,3,
+ 0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+ 0,0,5,5,5,5,5,5,5,5,5,4,1,1,2,2,3,3,5,5,7,6,9,8,11,10,14,13,16,16,0,0,
+ 0,0,4,3,5,2,4,2,4,3,5,3,5,2,4,2,4,3,5,3,5,2,4,3,4,3,5,3,5,2,4,2,
+
+// Asteroid Map icons
+ 0,0,3,0,4,1,5,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,3,0,4,1,5,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,8,0,7,0,8,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+// Other icons
+ 0,0,9,9,9,10,8,11,7,11,7,11,8,11,9,10,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,10,7,10,6,10,5,10,4,10,3,10,4,10,5,10,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,7,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,7,3,4,3,2,4,0,5,0,7,0,7,0,5,2,4,4,3,7,3,0,0,0,0,0,0,0,0,0,0,
+ 0,0,12,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+// Vent icons
+ 0,0,8,3,7,3,6,3,5,3,4,3,3,3,2,3,1,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,2,3,3,3,4,3,8,3,10,3,12,3,14,3,17,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,3,14,4,12,5,10,6,9,7,8,7,7,8,6,9,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,2,3,3,2,3,4,3,4,3,5,3,4,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+
+ 0,0,7,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,9,9,9,10,8,11,7,11,7,11,8,11,9,10,9,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,10,7,10,6,10,5,10,4,10,3,10,4,10,5,10,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+};
+
+void SimonEngine::drawMousePointer_FF() {
+ uint cursor;
+ int image, offs;
+
+ if (_animatePointer != 0) {
+ if (getBitFlag(99)) {
+ _mouseToggle ^= 1;
+ if (_mouseToggle != 0)
+ _mouseAnim++;
+ } else {
+ _mouseAnim++;
+ }
+ if (_mouseAnim == _mouseAnimMax)
+ _mouseAnim = 1;
+ }
+
+ cursor = _mouseCursor;
+
+ if (_animatePointer == 0 && getBitFlag(99)) {
+ _mouseAnim = 1;
+ cursor = 6;
+ } else if (_mouseCursor != 5 && getBitFlag(72)) {
+ cursor += 7;
+ }
+
+ if (cursor != _currentMouseCursor || _mouseAnim != _currentMouseAnim) {
+ _currentMouseCursor = cursor;
+ _currentMouseAnim = _mouseAnim;
+
+ memset(_mouseData, 0, sizeof(_mouseData));
+
+ image = cursor * 16 + 1;
+ offs = cursor * 32;
+ drawMousePart(image, _mouseOffs[offs], _mouseOffs[offs + 1]);
+
+ image = cursor * 16 + 1 + _mouseAnim;
+ offs = cursor * 32 + _mouseAnim * 2;
+ drawMousePart(image, _mouseOffs[offs], _mouseOffs[offs + 1]);
+
+ int hotspotX = 19;
+ int hotspotY = 19;
+
+ if (_mouseCursor == 14) {
+ // Finger pointing away from screen. Not sure where
+ // this is used.
+ hotspotX += 4;
+ hotspotY -= 6;
+ } else if (_mouseCursor == 15) {
+ // Finger pointing down. Used for the oh-so-annoying
+ // Cygnus Alpha tile puzzle.
+ hotspotY += 18;
+ }
+
+ CursorMan.replaceCursor(_mouseData, kMaxCursorWidth, kMaxCursorHeight, hotspotX, hotspotY, 0);
+ }
+}
+
+void SimonEngine::drawMousePart(int image, byte x, byte y) {
+ VgaPointersEntry *vpe = &_vgaBufferPointers[7];
+ byte *src;
+ int width, height;
+
+ byte *dst = _mouseData + y * kMaxCursorWidth + x;
+
+ src = vpe->vgaFile2 + image * 8;
+ width = READ_LE_UINT16(src + 6);
+ height = READ_LE_UINT16(src + 4);
+
+ src = vpe->vgaFile2 + READ_LE_UINT32(src);
+
+ assert(width + x <= kMaxCursorWidth);
+ assert(height + y <= kMaxCursorWidth);
+
+ for (int h = 0; h < height; h++) {
+ for (int w = 0; w < width; w++) {
+ if (src[w] != 0)
+ dst[w] = src[w];
+ }
+ src += width;
+ dst += kMaxCursorWidth;
+ }
+}
+
+} // End of namespace Simon
+
+#ifdef PALMOS_68K
+#include "scumm_globals.h"
+
+_GINIT(AGOS_Cursor)
+_GSETPTR(Simon::_simon1_cursor, GBVARS_SIMON1CURSOR_INDEX, byte, GBVARS_SIMON)
+_GEND
+
+_GRELEASE(AGOS_Cursor)
+_GRELEASEPTR(GBVARS_SIMON1CURSOR_INDEX, GBVARS_SIMON)
+_GEND
+
+#endif
diff --git a/engines/agos/debug.cpp b/engines/agos/debug.cpp
new file mode 100644
index 0000000000..a0e980f807
--- /dev/null
+++ b/engines/agos/debug.cpp
@@ -0,0 +1,473 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-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$
+ *
+ */
+
+// AGOS debug functions
+#include "common/stdafx.h"
+
+#include "agos/debug.h"
+#include "agos/agos.h"
+#include "agos/intern.h"
+#include "agos/vga.h"
+
+#include <sys/stat.h>
+
+namespace Simon {
+
+const byte *SimonEngine::dumpOpcode(const byte *p) {
+ uint opcode;
+ const char *s, *st;
+
+ if (getGameType() == GType_ELVIRA || getGameType() == GType_ELVIRA2) {
+ opcode = READ_BE_UINT16(p);
+ p += 2;
+ if (opcode == 10000)
+ return NULL;
+ } else {
+ opcode = *p++;
+ if (opcode == 255)
+ return NULL;
+ }
+
+ if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ st = s = feeblefiles_opcode_name_table[opcode];
+ } else if (getGameType() == GType_SIMON2 && getFeatures() & GF_TALKIE) {
+ st = s = simon2talkie_opcode_name_table[opcode];
+ } else if (getFeatures() & GF_TALKIE) {
+ st = s = simon1talkie_opcode_name_table[opcode];
+ } else if (getGameType() == GType_SIMON2) {
+ st = s = simon2dos_opcode_name_table[opcode];
+ } else if (getGameType() == GType_SIMON1) {
+ st = s = simon1dos_opcode_name_table[opcode];
+ } else {
+ st = s = ww_opcode_name_table[opcode];
+ }
+ if (s == NULL) {
+ //error("INVALID OPCODE %d", opcode);
+ return NULL;
+ }
+ while (*st != '|')
+ st++;
+ printf("%s ", st + 1);
+
+ for (;;) {
+ switch (*s++) {
+ case 'x':
+ printf("\n");
+ return NULL;
+ case '|':
+ printf("\n");
+ return p;
+ case 'B':{
+ byte b = *p++;
+ if (b == 255)
+ printf("[%d] ", *p++);
+ else
+ printf("%d ", b);
+ break;
+ }
+ case 'V':{
+ byte b = *p++;
+ if (b == 255)
+ printf("[[%d]] ", *p++);
+ else
+ printf("[%d] ", b);
+ break;
+ }
+
+ case 'W':{
+ int n = (int16)((p[0] << 8) | p[1]);
+ p += 2;
+ if (n >= 30000 && n < 30512)
+ printf("[%d] ", n - 30000);
+ else
+ printf("%d ", n);
+ break;
+ }
+
+ case 'w':{
+ int n = (int16)((p[0] << 8) | p[1]);
+ p += 2;
+ printf("%d ", n);
+ break;
+ }
+
+ case 'I':{
+ int n = (int16)((p[0] << 8) | p[1]);;
+ p += 2;
+ if (n == -1)
+ printf("ITEM_M1 ");
+ else if (n == -3)
+ printf("ITEM_M3 ");
+ else if (n == -5)
+ printf("ITEM_1 ");
+ else if (n == -7)
+ printf("ITEM_0 ");
+ else if (n == -9)
+ printf("ITEM_A_PARENT ");
+ else
+ printf("<%d> ", n);
+ break;
+ }
+
+ case 'J':{
+ printf("-> ");
+ }
+ break;
+
+ case 'T':{
+ uint n = ((p[0] << 8) | p[1]);
+ p += 2;
+ if (n != 0xFFFF)
+ printf("\"%s\"(%d) ", getStringPtrByID(n), n);
+ else
+ printf("NULL_STRING ");
+ }
+ break;
+ }
+ }
+}
+
+void SimonEngine::dumpSubroutineLine(SubroutineLine *sl, Subroutine *sub) {
+ const byte *p;
+
+ printf("; ****\n");
+
+ p = (byte *)sl + SUBROUTINE_LINE_SMALL_SIZE;
+ if (sub->id == 0) {
+ printf("; verb=%d, noun1=%d, noun2=%d\n", sl->verb, sl->noun1, sl->noun2);
+ p = (byte *)sl + SUBROUTINE_LINE_BIG_SIZE;
+ }
+
+ for (;;) {
+ p = dumpOpcode(p);
+ if (p == NULL)
+ break;
+ }
+}
+
+void SimonEngine::dumpSubroutine(Subroutine *sub) {
+ SubroutineLine *sl;
+
+ printf("\n******************************************\n;Subroutine, ID=%d:\nSUB_%d:\n", sub->id, sub->id);
+ sl = (SubroutineLine *)((byte *)sub + sub->first);
+ for (; (byte *)sl != (byte *)sub; sl = (SubroutineLine *)((byte *)sub + sl->next)) {
+ dumpSubroutineLine(sl, sub);
+ }
+ printf("\nEND ******************************************\n");
+}
+
+void SimonEngine::dumpSubroutines() {
+ Subroutine *sub = _subroutineList;
+ for (; sub; sub = sub->next) {
+ dumpSubroutine(sub);
+ }
+}
+
+void SimonEngine::dump_video_script(const byte *src, bool one_opcode_only) {
+ uint opcode;
+ const char *str, *strn;
+
+ do {
+ if (getGameType() == GType_SIMON1 || getGameType() == GType_WW) {
+ opcode = READ_BE_UINT16(src);
+ src += 2;
+ } else {
+ opcode = *src++;
+ }
+
+ if (opcode >= _numVideoOpcodes) {
+ error("Invalid opcode %x\n", opcode);
+ return;
+ }
+
+ if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ strn = str = feeblefiles_video_opcode_name_table[opcode];
+ } else if (getGameType() == GType_SIMON2) {
+ strn = str = simon2_video_opcode_name_table[opcode];
+ } else if (getGameType() == GType_SIMON1) {
+ strn = str = simon1_video_opcode_name_table[opcode];
+ } else {
+ strn = str = ww_video_opcode_name_table[opcode];
+ }
+
+ while (*strn != '|')
+ strn++;
+ printf("%.2d: %s ", opcode, strn + 1);
+
+ int end = (getGameType() == GType_FF || getGameType() == GType_PP) ? 9999 : 999;
+ for (; *str != '|'; str++) {
+ switch (*str) {
+ case 'x':
+ printf("\n");
+ return;
+ case 'b':
+ printf("%d ", *src++);
+ break;
+ case 'd':
+ printf("%d ", (int16)readUint16Wrapper(src));
+ src += 2;
+ break;
+ case 'v':
+ printf("[%d] ", readUint16Wrapper(src));
+ src += 2;
+ break;
+ case 'i':
+ printf("%d ", (int16)readUint16Wrapper(src));
+ src += 2;
+ break;
+ case 'q':
+ while (readUint16Wrapper(src) != end) {
+ printf("(%d,%d) ", readUint16Wrapper(src),
+ readUint16Wrapper(src + 2));
+ src += 4;
+ }
+ src++;
+ break;
+ default:
+ error("Invalid fmt string '%c' in decompile VGA", *str);
+ }
+ }
+
+ printf("\n");
+ } while (!one_opcode_only);
+}
+
+void SimonEngine::dump_vga_file(const byte *vga) {
+ const byte *pp;
+ const byte *p;
+ int count;
+
+ pp = vga;
+ p = pp + READ_BE_UINT16(&((const VgaFileHeader_Simon *) pp)->hdr2_start);
+ count = READ_BE_UINT16(&((const VgaFileHeader2_Simon *) p)->animationCount);
+ p = pp + READ_BE_UINT16(&((const VgaFileHeader2_Simon *) p)->animationTable);
+ while (--count >= 0) {
+ int id = READ_BE_UINT16(&((const AnimationHeader_Simon *) p)->id);
+
+ dump_vga_script_always(vga + READ_BE_UINT16(&((const AnimationHeader_Simon *) p)->scriptOffs), id / 100, id);
+ p += sizeof(AnimationHeader_Simon);
+ }
+
+ pp = vga;
+ p = pp + READ_BE_UINT16(&((const VgaFileHeader_Simon *) pp)->hdr2_start);
+ count = READ_BE_UINT16(&((const VgaFileHeader2_Simon *) p)->imageCount);
+ p = pp + READ_BE_UINT16(&((const VgaFileHeader2_Simon *) p)->imageTable);
+
+ while (--count >= 0) {
+ int id = READ_BE_UINT16(&((const ImageHeader_Simon *) p)->id);
+
+ dump_vga_script_always(vga + READ_BE_UINT16(&((const ImageHeader_Simon *) p)->scriptOffs), id / 100, id);
+ p += sizeof(ImageHeader_Simon);
+ }
+}
+
+static const byte bmp_hdr[] = {
+ 0x42, 0x4D,
+ 0x9E, 0x14, 0x00, 0x00, /* offset 2, file size */
+ 0x00, 0x00, 0x00, 0x00,
+ 0x36, 0x04, 0x00, 0x00,
+ 0x28, 0x00, 0x00, 0x00,
+
+ 0x3C, 0x00, 0x00, 0x00, /* image width */
+ 0x46, 0x00, 0x00, 0x00, /* image height */
+ 0x01, 0x00, 0x08, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+
+ 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x01, 0x00, 0x00,
+};
+
+void dump_bmp(const char *filename, int w, int h, const byte *bytes, const uint32 *palette) {
+ FILE *out = fopen(filename, "wb");
+ byte my_hdr[sizeof(bmp_hdr)];
+ int i;
+
+ if (out == NULL) {
+ printf("DUMP ERROR\n");
+ return;
+ }
+
+ memcpy(my_hdr, bmp_hdr, sizeof(bmp_hdr));
+
+ *(uint32 *)(my_hdr + 2) = w * h + 1024 + sizeof(bmp_hdr);
+ *(uint32 *)(my_hdr + 18) = w;
+ *(uint32 *)(my_hdr + 22) = h;
+
+
+ fwrite(my_hdr, 1, sizeof(my_hdr), out);
+
+ for (i = 0; i != 256; i++, palette++) {
+ byte color[4];
+ color[0] = (byte)(*palette >> 16);
+ color[1] = (byte)(*palette >> 8);
+ color[2] = (byte)(*palette);
+ color[3] = 0;
+ fwrite(color, 1, 4, out);
+ }
+
+ while (--h >= 0) {
+ fwrite(bytes + h * ((w + 3) & ~3), ((w + 3) & ~3), 1, out);
+ }
+
+ fclose(out);
+}
+
+void SimonEngine::dump_bitmap(const char *filename, const byte *offs, int w, int h, int flags, const byte *palette,
+ byte base) {
+
+ if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2)
+ w *= 16;
+
+ /* allocate */
+ byte *b = (byte *)malloc(w * h);
+ int i, j;
+
+ VC10_state state;
+
+ state.depack_cont = -0x80;
+ state.depack_src = offs;
+ state.dh = h;
+ state.y_skip = 0;
+
+ if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ for (i = 0; i != w; i++) {
+ byte *c = vc10_depackColumn(&state);
+ for (j = 0; j != h; j++) {
+ byte pix = c[j];
+ b[j * w + i] = pix;
+ }
+ }
+ } else {
+ for (i = 0; i != w; i += 2) {
+ byte *c = vc10_depackColumn(&state);
+ for (j = 0; j != h; j++) {
+ byte pix = c[j];
+ b[j * w + i] = (pix >> 4) | base;
+ b[j * w + i + 1] = (pix & 0xF) | base;
+ }
+ }
+ }
+
+ dump_bmp(filename, w, h, b, (const uint32 *)palette);
+ free(b);
+}
+
+void SimonEngine::dump_single_bitmap(int file, int image, const byte *offs, int w, int h, byte base) {
+ char buf[40];
+#if !defined(PALMOS_MODE) && !defined(__DC__) && !defined(__PSP__) && !defined(__PLAYSTATION2__)
+ struct stat statbuf;
+#endif
+
+#if defined(MACOS_CARBON)
+ sprintf(buf, ":dumps:File%d_Image%d.bmp", file, image);
+#else
+ sprintf(buf, "dumps/File%d_Image%d.bmp", file, image);
+#endif
+
+#if !defined(PALMOS_MODE) && !defined(__DC__) && !defined(__PSP__) && !defined(__PLAYSTATION2__)
+ if (stat(buf, &statbuf) == 0)
+ return;
+#endif
+
+ dump_bitmap(buf, offs, w, h, 0, _displayPalette, base);
+}
+
+void pal_load(byte *pal, const byte *vga1, int a, int b) {
+ uint num = (a == 0) ? 0x20 : 0x10;
+ byte *palptr;
+ const byte *src;
+
+ palptr = (byte *)&pal[a << 4];
+ src = vga1 + 6 + b * 96;
+
+ do {
+ palptr[0] = src[0] << 2;
+ palptr[1] = src[1] << 2;
+ palptr[2] = src[2] << 2;
+ palptr[3] = 0;
+
+ palptr += 4;
+ src += 3;
+ } while (--num);
+}
+
+void SimonEngine::dump_vga_bitmaps(const byte *vga, byte *vga1, int res) {
+
+ int i;
+ uint32 offs;
+ const byte *p2;
+ byte pal[768];
+
+ memset(pal, 0, sizeof(pal));
+ pal_load(pal, vga1, 2, 0);
+ pal_load(pal, vga1, 3, 1);
+ pal_load(pal, vga1, 4, 2);
+ pal_load(pal, vga1, 5, 3);
+
+ int width, height, flags;
+
+ i = 538;
+
+ for (i = 1; ; i++) {
+ p2 = vga + i * 8;
+ offs = READ_BE_UINT32(p2);
+
+ /* try to detect end of images.
+ * assume the end when offset >= 200kb */
+ if (offs >= 200*1024)
+ return;
+
+ width = READ_BE_UINT16(p2 + 6);
+ height = p2[5];
+ flags = p2[4];
+
+ printf("Image %d. Width=%d, Height=%d, Flags=0x%X\n", i, width, height, flags);
+
+ /* dump bitmap */
+ char buf[40];
+#if defined(MACOS_CARBON)
+ sprintf(buf, ":dumps:Res%d_Image%d.bmp", res, i);
+#else
+ sprintf(buf, "dumps/Res%d_Image%d.bmp", res, i);
+#endif
+
+ dump_bitmap(buf, vga + offs, width, height, flags, pal, 0);
+
+ }
+}
+
+void SimonEngine::dump_vga_script_always(const byte *ptr, uint res, uint sprite_id) {
+ printf("; address=%x, vgafile=%d vgasprite=%d\n",
+ (unsigned int)(ptr - _vgaBufferPointers[res].vgaFile1), res, sprite_id);
+ dump_video_script(ptr, false);
+ printf("; end\n");
+}
+
+void SimonEngine::dump_vga_script(const byte *ptr, uint res, uint sprite_id) {
+ dump_vga_script_always(ptr, res, sprite_id);
+}
+
+} // End of namespace Simon
diff --git a/engines/agos/debug.h b/engines/agos/debug.h
new file mode 100644
index 0000000000..e6f478deee
--- /dev/null
+++ b/engines/agos/debug.h
@@ -0,0 +1,1855 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-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 AGOS_DEBUG_H
+#define AGOS_DEBUG_H
+
+namespace Simon {
+
+static const char *const ww_opcode_name_table[256] = {
+ /* 0 */
+ "|NOT",
+ "IJ|AT",
+ "IJ|NOT_AT",
+ NULL,
+ /* 4 */
+ NULL,
+ "IJ|CARRIED",
+ "IJ|NOT_CARRIED",
+ "IIJ|IS_AT",
+ /* 8 */
+ NULL,
+ NULL,
+ NULL,
+ "VJ|IS_ZERO",
+ /* 12 */
+ "VJ|ISNOT_ZERO",
+ "VWJ|IS_EQ",
+ "VWJ|IS_NEQ",
+ "VWJ|IS_LE",
+ /* 16 */
+ "VWJ|IS_GE",
+ "VVJ|IS_EQF",
+ "VVJ|IS_NEQF",
+ "VVJ|IS_LEF",
+ /* 20 */
+ "VVJ|IS_GEF",
+ NULL,
+ NULL,
+ "WJ|CHANCE",
+ /* 24 */
+ NULL,
+ "IJ|IS_ROOM",
+ "IJ|IS_OBJECT",
+ "IWJ|ITEM_STATE_IS",
+ /* 28 */
+ "IBJ|OBJECT_HAS_FLAG",
+ NULL,
+ NULL,
+ "I|SET_NO_PARENT",
+ /* 32 */
+ NULL,
+ "II|SET_PARENT",
+ NULL,
+ NULL,
+ /* 36 */
+ "VV|MOVE",
+ NULL,
+ NULL,
+ NULL,
+ /* 40 */
+ NULL,
+ "V|ZERO",
+ "VW|SET",
+ "VW|ADD",
+ /* 44 */
+ "VW|SUB",
+ "VV|ADDF",
+ "VV|SUBF",
+ "VW|MUL",
+ /* 48 */
+ "VW|DIV",
+ "VV|MULF",
+ "VV|DIVF",
+ "VW|MOD",
+ /* 52 */
+ "VV|MODF",
+ "VW|RANDOM",
+ NULL,
+ "I|SET_A_PARENT",
+ /* 56 */
+ "IB|SET_CHILD2_BIT",
+ "IB|CLEAR_CHILD2_BIT",
+ "II|MAKE_SIBLING",
+ "I|INC_STATE",
+ /* 60 */
+ "I|DEC_STATE",
+ "IW|SET_STATE",
+ "V|SHOW_INT",
+ "T|SHOW_STRING_NL",
+ /* 64 */
+ "T|SHOW_STRING",
+ "WWWWWB|ADD_TEXT_BOX",
+ "BT|SET_SHORT_TEXT",
+ "BT|SET_LONG_TEXT",
+ /* 68 */
+ "x|END",
+ "x|DONE",
+ "V|SHOW_STRING_AR3",
+ "W|START_SUB",
+ /* 72 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ /* 76 */
+ "WW|ADD_TIMEOUT",
+ "J|IS_M1_EMPTY",
+ "J|IS_M3_EMPTY",
+ "ITJ|CHILD_FR2_IS",
+ /* 80 */
+ "IIJ|IS_ITEM_EQ",
+ NULL,
+ "B|DEBUG",
+ "|RESCAN",
+ /* 84 */
+ NULL,
+ "IBB|WHERE_TO",
+ NULL,
+ "W|COMMENT",
+ /* 88 */
+ "|STOP_ANIMATION",
+ "|RESTART_ANIMATION",
+ "IB|GET_PARENT",
+ "IB|GET_NEXT",
+ /* 92 */
+ "IB|GET_CHILDREN",
+ NULL,
+ NULL,
+ NULL,
+ /* 96 */
+ "WB|PICTURE",
+ "W|LOAD_ZONE",
+ "WBWWW|ANIMATE",
+ "W|STOP_ANIMATE",
+ /* 100 */
+ "|KILL_ANIMATE",
+ "BWWWWWW|DEFINE_WINDOW",
+ "B|CHANGE_WINDOW",
+ "|CLS",
+ /* 104 */
+ "B|CLOSE_WINDOW",
+ "B|MENU",
+ "BB|TEXT_MENU",
+ "WWWWWIW|ADD_BOX",
+ /* 108 */
+ "W|DEL_BOX",
+ "W|ENABLE_BOX",
+ "W|DISABLE_BOX",
+ "WWW|MOVE_BOX",
+ /* 112 */
+ NULL,
+ NULL,
+ "IB|DO_ICONS",
+ "IBJ|IS_CLASS",
+ /* 116 */
+ "IB|SET_CLASS",
+ "IB|UNSET_CLASS",
+ NULL,
+ "W|WAIT_SYNC",
+ /* 120 */
+ "W|SYNC",
+ "BI|DEF_OBJ",
+ NULL,
+ NULL,
+ /* 124 */
+ NULL,
+ "IJ|IS_SIBLING_WITH_A",
+ "IBB|DO_CLASS_ICONS",
+ "WW|PLAY_TUNE",
+ /* 128 */
+ "W|WAIT_END_TUNE",
+ "W|IF_END_TUNE",
+ "Bww|SET_ADJ_NOUN",
+ NULL,
+ /* 132 */
+ "|SAVE_GAME",
+ "|LOAD_GAME",
+ "|DUMMYPROC_134",
+ "|QUIT_IF_USER_PRESSES_Y",
+ /* 136 */
+ "IV|COPY_SF",
+ "B|RESTORE_ICONS",
+ "|FREEZE_ZONES",
+ "II|SET_PARENT_SPECIAL",
+ /* 140 */
+ "|CLEAR_TIMERS",
+ "BI|SET_M1_OR_M3",
+ "WJ|IS_HITAREA_0x40_CLEAR",
+ "I|START_ITEM_SUB",
+ /* 144 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ /* 148 */
+ "IB|IF_DOOR_OPEN",
+ NULL,
+ NULL,
+ "BI|SET_ARRAY6_TO",
+ /* 152 */
+ "BB|SET_M1_M3_TO_ARRAY6",
+ "B|SET_BIT",
+ "B|CLEAR_BIT",
+ "BJ|IS_BIT_CLEAR",
+ /* 156 */
+ "BJ|IS_BIT_SET",
+ "IBB|GET_ITEM_PROP",
+ "IBW|SET_ITEM_PROP",
+ NULL,
+ /* 160 */
+ "B|SET_INK",
+ "BWBW|SETUP_TEXT",
+ "BBT|PRINT_STR",
+ "W|PLAY_EFFECT",
+ /* 164 */
+ "|getDollar2",
+ "IWWJ|IS_ADJ_NOUN",
+ "B|SET_BIT2",
+ "B|CLEAR_BIT2",
+ /* 168 */
+ "BJ|IS_BIT2_CLEAR",
+ "BJ|IS_BIT2_SET",
+ NULL,
+ NULL,
+ /* 172 */
+ NULL,
+ NULL,
+ NULL,
+ "|LOCK_ZONES",
+ /* 176 */
+ "|UNLOCK_ZONES",
+ "BBI|SCREEN_TEXT_POBJ",
+ "WWBB|GETPATHPOSN",
+ "IWWJ|IS_ADJ_NOUN",
+ /* 180 */
+ "B|SET_BIT2",
+ "B|CLEAR_BIT2",
+ "BJ|IS_BIT2_CLEAR",
+ "BJ|IS_BIT2_SET",
+ /* 184 */
+ "W|UNLOAD_ZONE",
+ "W|LOAD_SOUND_FILES",
+ "|UNFREEZE_ZONES",
+ "|FADE_TO_BLACK",
+};
+
+static const char *const simon1dos_opcode_name_table[256] = {
+ /* 0 */
+ "|NOT",
+ "IJ|AT",
+ "IJ|NOT_AT",
+ NULL,
+ /* 4 */
+ NULL,
+ "IJ|CARRIED",
+ "IJ|NOT_CARRIED",
+ "IIJ|IS_AT",
+ /* 8 */
+ NULL,
+ NULL,
+ NULL,
+ "VJ|IS_ZERO",
+ /* 12 */
+ "VJ|ISNOT_ZERO",
+ "VWJ|IS_EQ",
+ "VWJ|IS_NEQ",
+ "VWJ|IS_LE",
+ /* 16 */
+ "VWJ|IS_GE",
+ "VVJ|IS_EQF",
+ "VVJ|IS_NEQF",
+ "VVJ|IS_LEF",
+ /* 20 */
+ "VVJ|IS_GEF",
+ NULL,
+ NULL,
+ "WJ|CHANCE",
+ /* 24 */
+ NULL,
+ "IJ|IS_ROOM",
+ "IJ|IS_OBJECT",
+ "IWJ|ITEM_STATE_IS",
+ /* 28 */
+ "IBJ|OBJECT_HAS_FLAG",
+ NULL,
+ NULL,
+ "I|SET_NO_PARENT",
+ /* 32 */
+ NULL,
+ "II|SET_PARENT",
+ NULL,
+ NULL,
+ /* 36 */
+ "VV|MOVE",
+ NULL,
+ NULL,
+ NULL,
+ /* 40 */
+ NULL,
+ "V|ZERO",
+ "VW|SET",
+ "VW|ADD",
+ /* 44 */
+ "VW|SUB",
+ "VV|ADDF",
+ "VV|SUBF",
+ "VW|MUL",
+ /* 48 */
+ "VW|DIV",
+ "VV|MULF",
+ "VV|DIVF",
+ "VW|MOD",
+ /* 52 */
+ "VV|MODF",
+ "VW|RANDOM",
+ NULL,
+ "I|SET_A_PARENT",
+ /* 56 */
+ "IB|SET_CHILD2_BIT",
+ "IB|CLEAR_CHILD2_BIT",
+ "II|MAKE_SIBLING",
+ "I|INC_STATE",
+ /* 60 */
+ "I|DEC_STATE",
+ "IW|SET_STATE",
+ "V|SHOW_INT",
+ "T|SHOW_STRING_NL",
+ /* 64 */
+ "T|SHOW_STRING",
+ "WWWWWB|ADD_TEXT_BOX",
+ "BT|SET_SHORT_TEXT",
+ "BT|SET_LONG_TEXT",
+ /* 68 */
+ "x|END",
+ "x|DONE",
+ "V|SHOW_STRING_AR3",
+ "W|START_SUB",
+ /* 72 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ /* 76 */
+ "WW|ADD_TIMEOUT",
+ "J|IS_M1_EMPTY",
+ "J|IS_M3_EMPTY",
+ "ITJ|CHILD_FR2_IS",
+ /* 80 */
+ "IIJ|IS_ITEM_EQ",
+ NULL,
+ "B|DEBUG",
+ "|RESCAN",
+ /* 84 */
+ NULL,
+ NULL,
+ NULL,
+ "W|COMMENT",
+ /* 88 */
+ "|STOP_ANIMATION",
+ "|RESTART_ANIMATION",
+ "IB|GET_PARENT",
+ "IB|GET_NEXT",
+ /* 92 */
+ "IB|GET_CHILDREN",
+ NULL,
+ NULL,
+ NULL,
+ /* 96 */
+ "WB|PICTURE",
+ "W|LOAD_ZONE",
+ "WBWWW|ANIMATE",
+ "W|STOP_ANIMATE",
+ /* 100 */
+ "|KILL_ANIMATE",
+ "BWWWWWW|DEFINE_WINDOW",
+ "B|CHANGE_WINDOW",
+ "|CLS",
+ /* 104 */
+ "B|CLOSE_WINDOW",
+ NULL,
+ NULL,
+ "WWWWWIW|ADD_BOX",
+ /* 108 */
+ "W|DEL_BOX",
+ "W|ENABLE_BOX",
+ "W|DISABLE_BOX",
+ "WWW|MOVE_BOX",
+ /* 112 */
+ NULL,
+ NULL,
+ "IB|DO_ICONS",
+ "IBJ|IS_CLASS",
+ /* 116 */
+ "IB|SET_CLASS",
+ "IB|UNSET_CLASS",
+ NULL,
+ "W|WAIT_SYNC",
+ /* 120 */
+ "W|SYNC",
+ "BI|DEF_OBJ",
+ NULL,
+ NULL,
+ /* 124 */
+ NULL,
+ "IJ|IS_SIBLING_WITH_A",
+ "IBB|DO_CLASS_ICONS",
+ "WW|PLAY_TUNE",
+ /* 128 */
+ "W|WAIT_END_TUNE",
+ "W|IF_END_TUNE",
+ "Bww|SET_ADJ_NOUN",
+ NULL,
+ /* 132 */
+ "|SAVE_GAME",
+ "|LOAD_GAME",
+ "|DUMMYPROC_134",
+ "|QUIT_IF_USER_PRESSES_Y",
+ /* 136 */
+ "IV|COPY_SF",
+ "B|RESTORE_ICONS",
+ "|FREEZE_ZONES",
+ "II|SET_PARENT_SPECIAL",
+ /* 140 */
+ "|CLEAR_TIMERS",
+ "BI|SET_M1_OR_M3",
+ "WJ|IS_HITAREA_0x40_CLEAR",
+ "I|START_ITEM_SUB",
+ /* 144 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ /* 148 */
+ NULL,
+ NULL,
+ NULL,
+ "BI|SET_ARRAY6_TO",
+ /* 152 */
+ "BB|SET_M1_M3_TO_ARRAY6",
+ "B|SET_BIT",
+ "B|CLEAR_BIT",
+ "BJ|IS_BIT_CLEAR",
+ /* 156 */
+ "BJ|IS_BIT_SET",
+ "IBB|GET_ITEM_PROP",
+ "IBW|SET_ITEM_PROP",
+ NULL,
+ /* 160 */
+ "B|SET_INK",
+ "BWBW|SETUP_TEXT",
+ "BBT|PRINT_STR",
+ "W|PLAY_EFFECT",
+ /* 164 */
+ "|getDollar2",
+ "IWWJ|IS_ADJ_NOUN",
+ "B|SET_BIT2",
+ "B|CLEAR_BIT2",
+ /* 168 */
+ "BJ|IS_BIT2_CLEAR",
+ "BJ|IS_BIT2_SET",
+ NULL,
+ NULL,
+ /* 172 */
+ NULL,
+ NULL,
+ NULL,
+ "|LOCK_ZONES",
+ /* 176 */
+ "|UNLOCK_ZONES",
+ "BBI|SCREEN_TEXT_POBJ",
+ "WWBB|GETPATHPOSN",
+ "BBB|SCREEN_TEXT_LONG_TEXT",
+ /* 180 */
+ "|MOUSE_ON",
+ "|MOUSE_OFF",
+ "|LOAD_BEARD",
+ "|UNLOAD_BEARD",
+ /* 184 */
+ "W|UNLOAD_ZONE",
+ "W|LOAD_SOUND_FILES",
+ "|UNFREEZE_ZONES",
+ "|FADE_TO_BLACK",
+};
+
+static const char *const simon1talkie_opcode_name_table[256] = {
+ /* 0 */
+ "|NOT",
+ "IJ|AT",
+ "IJ|NOT_AT",
+ NULL,
+ /* 4 */
+ NULL,
+ "IJ|CARRIED",
+ "IJ|NOT_CARRIED",
+ "IIJ|IS_AT",
+ /* 8 */
+ NULL,
+ NULL,
+ NULL,
+ "VJ|IS_ZERO",
+ /* 12 */
+ "VJ|ISNOT_ZERO",
+ "VWJ|IS_EQ",
+ "VWJ|IS_NEQ",
+ "VWJ|IS_LE",
+ /* 16 */
+ "VWJ|IS_GE",
+ "VVJ|IS_EQF",
+ "VVJ|IS_NEQF",
+ "VVJ|IS_LEF",
+ /* 20 */
+ "VVJ|IS_GEF",
+ NULL,
+ NULL,
+ "WJ|CHANCE",
+ /* 24 */
+ NULL,
+ "IJ|IS_ROOM",
+ "IJ|IS_OBJECT",
+ "IWJ|ITEM_STATE_IS",
+ /* 28 */
+ "IBJ|OBJECT_HAS_FLAG",
+ NULL,
+ NULL,
+ "I|SET_NO_PARENT",
+ /* 32 */
+ NULL,
+ "II|SET_PARENT",
+ NULL,
+ NULL,
+ /* 36 */
+ "VV|MOVE",
+ NULL,
+ NULL,
+ NULL,
+ /* 40 */
+ NULL,
+ "V|ZERO",
+ "VW|SET",
+ "VW|ADD",
+ /* 44 */
+ "VW|SUB",
+ "VV|ADDF",
+ "VV|SUBF",
+ "VW|MUL",
+ /* 48 */
+ "VW|DIV",
+ "VV|MULF",
+ "VV|DIVF",
+ "VW|MOD",
+ /* 52 */
+ "VV|MODF",
+ "VW|RANDOM",
+ NULL,
+ "I|SET_A_PARENT",
+ /* 56 */
+ "IB|SET_CHILD2_BIT",
+ "IB|CLEAR_CHILD2_BIT",
+ "II|MAKE_SIBLING",
+ "I|INC_STATE",
+ /* 60 */
+ "I|DEC_STATE",
+ "IW|SET_STATE",
+ "V|SHOW_INT",
+ "T|SHOW_STRING_NL",
+ /* 64 */
+ "T|SHOW_STRING",
+ "WWWWWB|ADD_TEXT_BOX",
+ "BT|SET_SHORT_TEXT",
+ "BTw|SET_LONG_TEXT",
+ /* 68 */
+ "x|END",
+ "x|DONE",
+ "V|SHOW_STRING_AR3",
+ "W|START_SUB",
+ /* 72 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ /* 76 */
+ "WW|ADD_TIMEOUT",
+ "J|IS_M1_EMPTY",
+ "J|IS_M3_EMPTY",
+ "ITJ|CHILD_FR2_IS",
+ /* 80 */
+ "IIJ|IS_ITEM_EQ",
+ NULL,
+ "B|DEBUG",
+ "|RESCAN",
+ /* 84 */
+ NULL,
+ NULL,
+ NULL,
+ "W|COMMENT",
+ /* 88 */
+ "|STOP_ANIMATION",
+ "|RESTART_ANIMATION",
+ "IB|GET_PARENT",
+ "IB|GET_NEXT",
+ /* 92 */
+ "IB|GET_CHILDREN",
+ NULL,
+ NULL,
+ NULL,
+ /* 96 */
+ "WB|PICTURE",
+ "W|LOAD_ZONE",
+ "WBWWW|ANIMATE",
+ "W|STOP_ANIMATE",
+ /* 100 */
+ "|KILL_ANIMATE",
+ "BWWWWWW|DEFINE_WINDOW",
+ "B|CHANGE_WINDOW",
+ "|CLS",
+ /* 104 */
+ "B|CLOSE_WINDOW",
+ NULL,
+ NULL,
+ "WWWWWIW|ADD_BOX",
+ /* 108 */
+ "W|DEL_BOX",
+ "W|ENABLE_BOX",
+ "W|DISABLE_BOX",
+ "WWW|MOVE_BOX",
+ /* 112 */
+ NULL,
+ NULL,
+ "IB|DO_ICONS",
+ "IBJ|IS_CLASS",
+ /* 116 */
+ "IB|SET_CLASS",
+ "IB|UNSET_CLASS",
+ NULL,
+ "W|WAIT_SYNC",
+ /* 120 */
+ "W|SYNC",
+ "BI|DEF_OBJ",
+ NULL,
+ NULL,
+ /* 124 */
+ NULL,
+ "IJ|IS_SIBLING_WITH_A",
+ "IBB|DO_CLASS_ICONS",
+ "WW|PLAY_TUNE",
+ /* 128 */
+ "W|WAIT_END_TUNE",
+ "W|IF_END_TUNE",
+ "Bww|SET_ADJ_NOUN",
+ NULL,
+ /* 132 */
+ "|SAVE_GAME",
+ "|LOAD_GAME",
+ "|DUMMYPROC_134",
+ "|QUIT_IF_USER_PRESSES_Y",
+ /* 136 */
+ "IV|COPY_SF",
+ "B|RESTORE_ICONS",
+ "|FREEZE_ZONES",
+ "II|SET_PARENT_SPECIAL",
+ /* 140 */
+ "|CLEAR_TIMERS",
+ "BI|SET_M1_OR_M3",
+ "WJ|IS_HITAREA_0x40_CLEAR",
+ "I|START_ITEM_SUB",
+ /* 144 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ /* 148 */
+ NULL,
+ NULL,
+ NULL,
+ "BI|SET_ARRAY6_TO",
+ /* 152 */
+ "BB|SET_M1_M3_TO_ARRAY6",
+ "B|SET_BIT",
+ "B|CLEAR_BIT",
+ "BJ|IS_BIT_CLEAR",
+ /* 156 */
+ "BJ|IS_BIT_SET",
+ "IBB|GET_ITEM_PROP",
+ "IBW|SET_ITEM_PROP",
+ NULL,
+ /* 160 */
+ "B|SET_INK",
+ "BWBW|SETUP_TEXT",
+ "BBTW|PRINT_STR",
+ "W|PLAY_EFFECT",
+ /* 164 */
+ "|getDollar2",
+ "IWWJ|IS_ADJ_NOUN",
+ "B|SET_BIT2",
+ "B|CLEAR_BIT2",
+ /* 168 */
+ "BJ|IS_BIT2_CLEAR",
+ "BJ|IS_BIT2_SET",
+ NULL,
+ NULL,
+ /* 172 */
+ NULL,
+ NULL,
+ NULL,
+ "|LOCK_ZONES",
+ /* 176 */
+ "|UNLOCK_ZONES",
+ "BBI|SCREEN_TEXT_POBJ",
+ "WWBB|GETPATHPOSN",
+ "BBB|SCREEN_TEXT_LONG_TEXT",
+ /* 180 */
+ "|MOUSE_ON",
+ "|MOUSE_OFF",
+ "|LOAD_BEARD",
+ "|UNLOAD_BEARD",
+ /* 184 */
+ "W|UNLOAD_ZONE",
+ "W|LOAD_SOUND_FILES",
+ "|UNFREEZE_ZONES",
+ "|FADE_TO_BLACK",
+};
+
+static const char *const simon2dos_opcode_name_table[256] = {
+ /* 0 */
+ "|NOT",
+ "IJ|AT",
+ "IJ|NOT_AT",
+ NULL,
+ /* 4 */
+ NULL,
+ "IJ|CARRIED",
+ "IJ|NOT_CARRIED",
+ "IIJ|IS_AT",
+ /* 8 */
+ NULL,
+ NULL,
+ NULL,
+ "VJ|IS_ZERO",
+ /* 12 */
+ "VJ|ISNOT_ZERO",
+ "VWJ|IS_EQ",
+ "VWJ|IS_NEQ",
+ "VWJ|IS_LE",
+ /* 16 */
+ "VWJ|IS_GE",
+ "VVJ|IS_EQF",
+ "VVJ|IS_NEQF",
+ "VVJ|IS_LEF",
+ /* 20 */
+ "VVJ|IS_GEF",
+ NULL,
+ NULL,
+ "WJ|CHANCE",
+ /* 24 */
+ NULL,
+ "IJ|IS_ROOM",
+ "IJ|IS_OBJECT",
+ "IWJ|ITEM_STATE_IS",
+ /* 28 */
+ "IBJ|OBJECT_HAS_FLAG",
+ NULL,
+ NULL,
+ "I|SET_NO_PARENT",
+ /* 32 */
+ NULL,
+ "II|SET_PARENT",
+ NULL,
+ NULL,
+ /* 36 */
+ "VV|MOVE",
+ NULL,
+ NULL,
+ NULL,
+ /* 40 */
+ NULL,
+ "V|ZERO",
+ "VW|SET",
+ "VW|ADD",
+ /* 44 */
+ "VW|SUB",
+ "VV|ADDF",
+ "VV|SUBF",
+ "VW|MUL",
+ /* 48 */
+ "VW|DIV",
+ "VV|MULF",
+ "VV|DIVF",
+ "VW|MOD",
+ /* 52 */
+ "VV|MODF",
+ "VW|RANDOM",
+ NULL,
+ "I|SET_A_PARENT",
+ /* 56 */
+ "IB|SET_CHILD2_BIT",
+ "IB|CLEAR_CHILD2_BIT",
+ "II|MAKE_SIBLING",
+ "I|INC_STATE",
+ /* 60 */
+ "I|DEC_STATE",
+ "IW|SET_STATE",
+ "V|SHOW_INT",
+ "T|SHOW_STRING_NL",
+ /* 64 */
+ "T|SHOW_STRING",
+ "WWWWWB|ADD_TEXT_BOX",
+ "BT|SET_SHORT_TEXT",
+ "BT|SET_LONG_TEXT",
+ /* 68 */
+ "x|END",
+ "x|DONE",
+ "V|SHOW_STRING_AR3",
+ "W|START_SUB",
+ /* 72 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ /* 76 */
+ "WW|ADD_TIMEOUT",
+ "J|IS_M1_EMPTY",
+ "J|IS_M3_EMPTY",
+ "ITJ|CHILD_FR2_IS",
+ /* 80 */
+ "IIJ|IS_ITEM_EQ",
+ NULL,
+ "B|DEBUG",
+ "|RESCAN",
+ /* 84 */
+ NULL,
+ NULL,
+ NULL,
+ "W|COMMENT",
+ /* 88 */
+ "|STOP_ANIMATION",
+ "|RESTART_ANIMATION",
+ "IB|GET_PARENT",
+ "IB|GET_NEXT",
+ /* 92 */
+ "IB|GET_CHILDREN",
+ NULL,
+ NULL,
+ NULL,
+ /* 96 */
+ "WB|PICTURE",
+ "W|LOAD_ZONE",
+ "WWBWWW|ANIMATE",
+ "WW|STOP_ANIMATE",
+ /* 100 */
+ "|KILL_ANIMATE",
+ "BWWWWWW|DEFINE_WINDOW",
+ "B|CHANGE_WINDOW",
+ "|CLS",
+ /* 104 */
+ "B|CLOSE_WINDOW",
+ NULL,
+ NULL,
+ "WWWWWIW|ADD_BOX",
+ /* 108 */
+ "W|DEL_BOX",
+ "W|ENABLE_BOX",
+ "W|DISABLE_BOX",
+ "WWW|MOVE_BOX",
+ /* 112 */
+ NULL,
+ NULL,
+ "IB|DO_ICONS",
+ "IBJ|IS_CLASS",
+ /* 116 */
+ "IB|SET_CLASS",
+ "IB|UNSET_CLASS",
+ NULL,
+ "W|WAIT_SYNC",
+ /* 120 */
+ "W|SYNC",
+ "BI|DEF_OBJ",
+ NULL,
+ NULL,
+ /* 124 */
+ NULL,
+ "IJ|IS_SIBLING_WITH_A",
+ "IBB|DO_CLASS_ICONS",
+ "WWB|PLAY_TUNE",
+ /* 128 */
+ "W|WAIT_END_TUNE",
+ "W|IF_END_TUNE",
+ "Bww|SET_ADJ_NOUN",
+ NULL,
+ /* 132 */
+ "|SAVE_GAME",
+ "|LOAD_GAME",
+ "|DUMMYPROC_134",
+ "|QUIT_IF_USER_PRESSES_Y",
+ /* 136 */
+ "IV|COPY_SF",
+ "B|RESTORE_ICONS",
+ "|FREEZE_ZONES",
+ "II|SET_PARENT_SPECIAL",
+ /* 140 */
+ "|CLEAR_TIMERS",
+ "BI|SET_M1_OR_M3",
+ "WJ|IS_HITAREA_0x40_CLEAR",
+ "I|START_ITEM_SUB",
+ /* 144 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ /* 148 */
+ NULL,
+ NULL,
+ NULL,
+ "BI|SET_ARRAY6_TO",
+ /* 152 */
+ "BB|SET_M1_M3_TO_ARRAY6",
+ "B|SET_BIT",
+ "B|CLEAR_BIT",
+ "BJ|IS_BIT_CLEAR",
+ /* 156 */
+ "BJ|IS_BIT_SET",
+ "IBB|GET_ITEM_PROP",
+ "IBW|SET_ITEM_PROP",
+ NULL,
+ /* 160 */
+ "B|SET_INK",
+ "BWBW|SETUP_TEXT",
+ "BBT|PRINT_STR",
+ "W|PLAY_EFFECT",
+ /* 164 */
+ "|getDollar2",
+ "IWWJ|IS_ADJ_NOUN",
+ "B|SET_BIT2",
+ "B|CLEAR_BIT2",
+ /* 168 */
+ "BJ|IS_BIT2_CLEAR",
+ "BJ|IS_BIT2_SET",
+ NULL,
+ NULL,
+ /* 172 */
+ NULL,
+ NULL,
+ NULL,
+ "|LOCK_ZONES",
+ /* 176 */
+ "|UNLOCK_ZONES",
+ "BBI|SCREEN_TEXT_POBJ",
+ "WWBB|GETPATHPOSN",
+ "BBB|SCREEN_TEXT_LONG_TEXT",
+ /* 180 */
+ "|MOUSE_ON",
+ "|MOUSE_OFF",
+ NULL,
+ NULL,
+ /* 184 */
+ "W|UNLOAD_ZONE",
+ NULL,
+ "|UNFREEZE_ZONES",
+ NULL,
+ /* 188 */
+ "BSJ|STRING2_IS",
+ "|CLEAR_MARKS",
+ "B|WAIT_FOR_MARK",
+};
+
+static const char *const simon2talkie_opcode_name_table[256] = {
+ /* 0 */
+ "|NOT",
+ "IJ|AT",
+ "IJ|NOT_AT",
+ NULL,
+ /* 4 */
+ NULL,
+ "IJ|CARRIED",
+ "IJ|NOT_CARRIED",
+ "IIJ|IS_AT",
+ /* 8 */
+ NULL,
+ NULL,
+ NULL,
+ "VJ|IS_ZERO",
+ /* 12 */
+ "VJ|ISNOT_ZERO",
+ "VWJ|IS_EQ",
+ "VWJ|IS_NEQ",
+ "VWJ|IS_LE",
+ /* 16 */
+ "VWJ|IS_GE",
+ "VVJ|IS_EQF",
+ "VVJ|IS_NEQF",
+ "VVJ|IS_LEF",
+ /* 20 */
+ "VVJ|IS_GEF",
+ NULL,
+ NULL,
+ "WJ|CHANCE",
+ /* 24 */
+ NULL,
+ "IJ|IS_ROOM",
+ "IJ|IS_OBJECT",
+ "IWJ|ITEM_STATE_IS",
+ /* 28 */
+ "IBJ|OBJECT_HAS_FLAG",
+ NULL,
+ NULL,
+ "I|SET_NO_PARENT",
+ /* 32 */
+ NULL,
+ "II|SET_PARENT",
+ NULL,
+ NULL,
+ /* 36 */
+ "VV|MOVE",
+ NULL,
+ NULL,
+ NULL,
+ /* 40 */
+ NULL,
+ "V|ZERO",
+ "VW|SET",
+ "VW|ADD",
+ /* 44 */
+ "VW|SUB",
+ "VV|ADDF",
+ "VV|SUBF",
+ "VW|MUL",
+ /* 48 */
+ "VW|DIV",
+ "VV|MULF",
+ "VV|DIVF",
+ "VW|MOD",
+ /* 52 */
+ "VV|MODF",
+ "VW|RANDOM",
+ NULL,
+ "I|SET_A_PARENT",
+ /* 56 */
+ "IB|SET_CHILD2_BIT",
+ "IB|CLEAR_CHILD2_BIT",
+ "II|MAKE_SIBLING",
+ "I|INC_STATE",
+ /* 60 */
+ "I|DEC_STATE",
+ "IW|SET_STATE",
+ "V|SHOW_INT",
+ "T|SHOW_STRING_NL",
+ /* 64 */
+ "T|SHOW_STRING",
+ "WWWWWB|ADD_TEXT_BOX",
+ "BT|SET_SHORT_TEXT",
+ "BTw|SET_LONG_TEXT",
+ /* 68 */
+ "x|END",
+ "x|DONE",
+ "V|SHOW_STRING_AR3",
+ "W|START_SUB",
+ /* 72 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ /* 76 */
+ "WW|ADD_TIMEOUT",
+ "J|IS_M1_EMPTY",
+ "J|IS_M3_EMPTY",
+ "ITJ|CHILD_FR2_IS",
+ /* 80 */
+ "IIJ|IS_ITEM_EQ",
+ NULL,
+ "B|DEBUG",
+ "|RESCAN",
+ /* 84 */
+ NULL,
+ NULL,
+ NULL,
+ "W|COMMENT",
+ /* 88 */
+ "|STOP_ANIMATION",
+ "|RESTART_ANIMATION",
+ "IB|GET_PARENT",
+ "IB|GET_NEXT",
+ /* 92 */
+ "IB|GET_CHILDREN",
+ NULL,
+ NULL,
+ NULL,
+ /* 96 */
+ "WB|PICTURE",
+ "W|LOAD_ZONE",
+ "WWBWWW|ANIMATE",
+ "WW|STOP_ANIMATE",
+ /* 100 */
+ "|KILL_ANIMATE",
+ "BWWWWWW|DEFINE_WINDOW",
+ "B|CHANGE_WINDOW",
+ "|CLS",
+ /* 104 */
+ "B|CLOSE_WINDOW",
+ NULL,
+ NULL,
+ "WWWWWIW|ADD_BOX",
+ /* 108 */
+ "W|DEL_BOX",
+ "W|ENABLE_BOX",
+ "W|DISABLE_BOX",
+ "WWW|MOVE_BOX",
+ /* 112 */
+ NULL,
+ NULL,
+ "IB|DO_ICONS",
+ "IBJ|IS_CLASS",
+ /* 116 */
+ "IB|SET_CLASS",
+ "IB|UNSET_CLASS",
+ NULL,
+ "W|WAIT_SYNC",
+ /* 120 */
+ "W|SYNC",
+ "BI|DEF_OBJ",
+ NULL,
+ NULL,
+ /* 124 */
+ NULL,
+ "IJ|IS_SIBLING_WITH_A",
+ "IBB|DO_CLASS_ICONS",
+ "WWB|PLAY_TUNE",
+ /* 128 */
+ "W|WAIT_END_TUNE",
+ "W|IF_END_TUNE",
+ "Bww|SET_ADJ_NOUN",
+ NULL,
+ /* 132 */
+ "|SAVE_GAME",
+ "|LOAD_GAME",
+ "|DUMMYPROC_134",
+ "|QUIT_IF_USER_PRESSES_Y",
+ /* 136 */
+ "IV|COPY_SF",
+ "B|RESTORE_ICONS",
+ "|FREEZE_ZONES",
+ "II|SET_PARENT_SPECIAL",
+ /* 140 */
+ "|CLEAR_TIMERS",
+ "BI|SET_M1_OR_M3",
+ "WJ|IS_HITAREA_0x40_CLEAR",
+ "I|START_ITEM_SUB",
+ /* 144 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ /* 148 */
+ NULL,
+ NULL,
+ NULL,
+ "BI|SET_ARRAY6_TO",
+ /* 152 */
+ "BB|SET_M1_M3_TO_ARRAY6",
+ "B|SET_BIT",
+ "B|CLEAR_BIT",
+ "BJ|IS_BIT_CLEAR",
+ /* 156 */
+ "BJ|IS_BIT_SET",
+ "IBB|GET_ITEM_PROP",
+ "IBW|SET_ITEM_PROP",
+ NULL,
+ /* 160 */
+ "B|SET_INK",
+ "BWBW|SETUP_TEXT",
+ "BBTW|PRINT_STR",
+ "W|PLAY_EFFECT",
+ /* 164 */
+ "|getDollar2",
+ "IWWJ|IS_ADJ_NOUN",
+ "B|SET_BIT2",
+ "B|CLEAR_BIT2",
+ /* 168 */
+ "BJ|IS_BIT2_CLEAR",
+ "BJ|IS_BIT2_SET",
+ NULL,
+ NULL,
+ /* 172 */
+ NULL,
+ NULL,
+ NULL,
+ "|LOCK_ZONES",
+ /* 176 */
+ "|UNLOCK_ZONES",
+ "BBI|SCREEN_TEXT_POBJ",
+ "WWBB|GETPATHPOSN",
+ "BBB|SCREEN_TEXT_LONG_TEXT",
+ /* 180 */
+ "|MOUSE_ON",
+ "|MOUSE_OFF",
+ NULL,
+ NULL,
+ /* 184 */
+ "W|UNLOAD_ZONE",
+ NULL,
+ "|UNFREEZE_ZONES",
+ NULL,
+ /* 188 */
+ "BSJ|STRING2_IS",
+ "|CLEAR_MARKS",
+ "B|WAIT_FOR_MARK",
+};
+
+static const char *const feeblefiles_opcode_name_table[256] = {
+ /* 0 */
+ "|NOT",
+ "IJ|AT",
+ "IJ|NOT_AT",
+ NULL,
+ /* 4 */
+ NULL,
+ "IJ|CARRIED",
+ "IJ|NOT_CARRIED",
+ "IIJ|IS_AT",
+ /* 8 */
+ NULL,
+ NULL,
+ NULL,
+ "VJ|IS_ZERO",
+ /* 12 */
+ "VJ|ISNOT_ZERO",
+ "VWJ|IS_EQ",
+ "VWJ|IS_NEQ",
+ "VWJ|IS_LE",
+ /* 16 */
+ "VWJ|IS_GE",
+ "VVJ|IS_EQF",
+ "VVJ|IS_NEQF",
+ "VVJ|IS_LEF",
+ /* 20 */
+ "VVJ|IS_GEF",
+ NULL,
+ NULL,
+ "WJ|CHANCE",
+ /* 24 */
+ NULL,
+ "IJ|IS_ROOM",
+ "IJ|IS_OBJECT",
+ "IWJ|ITEM_STATE_IS",
+ /* 28 */
+ "IBJ|OBJECT_HAS_FLAG",
+ NULL,
+ NULL,
+ "I|SET_NO_PARENT",
+ /* 32 */
+ NULL,
+ "II|SET_PARENT",
+ NULL,
+ NULL,
+ /* 36 */
+ "VV|MOVE",
+ "|JUMP_OUT",
+ NULL,
+ NULL,
+ /* 40 */
+ NULL,
+ "V|ZERO",
+ "VW|SET",
+ "VW|ADD",
+ /* 44 */
+ "VW|SUB",
+ "VV|ADDF",
+ "VV|SUBF",
+ "VW|MUL",
+ /* 48 */
+ "VW|DIV",
+ "VV|MULF",
+ "VV|DIVF",
+ "VW|MOD",
+ /* 52 */
+ "VV|MODF",
+ "VW|RANDOM",
+ NULL,
+ "I|SET_A_PARENT",
+ /* 56 */
+ "IB|SET_CHILD2_BIT",
+ "IB|CLEAR_CHILD2_BIT",
+ "II|MAKE_SIBLING",
+ "I|INC_STATE",
+ /* 60 */
+ "I|DEC_STATE",
+ "IW|SET_STATE",
+ "V|SHOW_INT",
+ "T|SHOW_STRING_NL",
+ /* 64 */
+ "T|SHOW_STRING",
+ "WWWWWB|ADD_TEXT_BOX",
+ "BT|SET_SHORT_TEXT",
+ "BTw|SET_LONG_TEXT",
+ /* 68 */
+ "x|END",
+ "x|DONE",
+ "V|SHOW_STRING_AR3",
+ "W|START_SUB",
+ /* 72 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ /* 76 */
+ "WW|ADD_TIMEOUT",
+ "J|IS_M1_EMPTY",
+ "J|IS_M3_EMPTY",
+ "ITJ|CHILD_FR2_IS",
+ /* 80 */
+ "IIJ|IS_ITEM_EQ",
+ NULL,
+ "B|DEBUG",
+ "|RESCAN",
+ /* 84 */
+ NULL,
+ NULL,
+ NULL,
+ "W|COMMENT",
+ /* 88 */
+ "|STOP_ANIMATION",
+ "|RESTART_ANIMATION",
+ "IB|GET_PARENT",
+ "IB|GET_NEXT",
+ /* 92 */
+ "IB|GET_CHILDREN",
+ NULL,
+ NULL,
+ NULL,
+ /* 96 */
+ "WB|PICTURE",
+ "W|LOAD_ZONE",
+ "WWBWWW|ANIMATE",
+ "WW|STOP_ANIMATE",
+ /* 100 */
+ "|KILL_ANIMATE",
+ "BWWWWWW|DEFINE_WINDOW",
+ "B|CHANGE_WINDOW",
+ "|CLS",
+ /* 104 */
+ "B|CLOSE_WINDOW",
+ NULL,
+ NULL,
+ "WWWWWIW|ADD_BOX",
+ /* 108 */
+ "W|DEL_BOX",
+ "W|ENABLE_BOX",
+ "W|DISABLE_BOX",
+ "WWW|MOVE_BOX",
+ /* 112 */
+ NULL,
+ NULL,
+ "IB|DO_ICONS",
+ "IBJ|IS_CLASS",
+ /* 116 */
+ "IB|SET_CLASS",
+ "IB|UNSET_CLASS",
+ NULL,
+ "W|WAIT_SYNC",
+ /* 120 */
+ "W|SYNC",
+ "BI|DEF_OBJ",
+ "|ORACLE_TEXT_DOWN",
+ "|ORACLE_TEXT_UP",
+ /* 124 */
+ "WJ|IF_TIME",
+ "IJ|IS_SIBLING_WITH_A",
+ "IBB|DO_CLASS_ICONS",
+ "WWB|PLAY_TUNE",
+ /* 128 */
+ "W|WAIT_END_TUNE",
+ "W|IF_END_TUNE",
+ "Bww|SET_ADJ_NOUN",
+ "|SET_TIME",
+ /* 132 */
+ "|SAVE_GAME",
+ "|LOAD_GAME",
+ "|LIST_SAVED_GAMES",
+ "|SWITCH_CD",
+ /* 136 */
+ "IV|COPY_SF",
+ "B|RESTORE_ICONS",
+ "|FREEZE_ZONES",
+ "II|SET_PARENT_SPECIAL",
+ /* 140 */
+ "|CLEAR_TIMERS",
+ "BI|SET_M1_OR_M3",
+ "WJ|IS_HITAREA_0x40_CLEAR",
+ "I|START_ITEM_SUB",
+ /* 144 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ /* 148 */
+ NULL,
+ NULL,
+ NULL,
+ "BI|SET_ARRAY6_TO",
+ /* 152 */
+ "BB|SET_M1_M3_TO_ARRAY6",
+ "B|SET_BIT",
+ "B|CLEAR_BIT",
+ "BJ|IS_BIT_CLEAR",
+ /* 156 */
+ "BJ|IS_BIT_SET",
+ "IBB|GET_ITEM_PROP",
+ "IBW|SET_ITEM_PROP",
+ NULL,
+ /* 160 */
+ "B|SET_INK",
+ "BWWW|SETUP_TEXT",
+ "BBTW|PRINT_STR",
+ "W|PLAY_EFFECT",
+ /* 164 */
+ "|getDollar2",
+ "IWWJ|IS_ADJ_NOUN",
+ "B|SET_BIT2",
+ "B|CLEAR_BIT2",
+ /* 168 */
+ "BJ|IS_BIT2_CLEAR",
+ "BJ|IS_BIT2_SET",
+ NULL,
+ "W|HYPERLINK_ON",
+ /* 172 */
+ "|HYPERLINK_OFF",
+ "|CHECK_PATHS",
+ NULL,
+ "|LOCK_ZONES",
+ /* 176 */
+ "|UNLOCK_ZONES",
+ "BBI|SCREEN_TEXT_POBJ",
+ "WWBB|GETPATHPOSN",
+ "BBB|SCREEN_TEXT_LONG_TEXT",
+ /* 180 */
+ "|MOUSE_ON",
+ "|MOUSE_OFF",
+ "T|LOAD_VIDEO",
+ "|PLAY_VIDEO",
+ /* 184 */
+ "W|UNLOAD_ZONE",
+ NULL,
+ "|UNFREEZE_ZONES",
+ "|CENTRE_SCROLL",
+ /* 188 */
+ "BSJ|STRING2_IS",
+ "|CLEAR_MARKS",
+ "B|WAIT_FOR_MARK",
+ "|RESET_PV_COUNT",
+ /* 192 */
+ "BBBB|SET_PATH_VALUES",
+ "|STOP_CLOCK",
+ "|RESTART_CLOCK",
+ "BBBB|SET_COLOR",
+ /* 196 */
+ "B|B3_SET",
+ "B|B3_CLEAR",
+ "B|B3_ZERO",
+ "B|B3_NOT_ZERO",
+};
+
+const char *const ww_video_opcode_name_table[] = {
+ /* 0 */
+ "x|RET",
+ "ddd|FADEOUT",
+ "d|CALL",
+ "ddddd|NEW_SPRITE",
+ /* 4 */
+ "ddd|FADEIN",
+ "vd|SKIP_IF_NEQ",
+ "d|SKIP_IFN_SIB_WITH_A",
+ "d|SKIP_IF_SIB_WITH_A",
+ /* 8 */
+ "dd|SKIP_IF_PARENT_IS",
+ "dd|SKIP_IF_UNK3_IS",
+ "dddd|DRAW",
+ "d|VC_11",
+ /* 12 */
+ "d|DELAY",
+ "d|SET_SPRITE_OFFSET_X",
+ "d|SET_SPRITE_OFFSET_Y",
+ "d|IDENT_WAKEUP",
+ /* 16 */
+ "d|IDENT_SLEEP",
+ "d|VC_17",
+ "i|JUMP_REL",
+ "|CHAIN_TO",
+ /* 20 */
+ "dd|SET_REPEAT",
+ "i|END_REPEAT",
+ "d|SET_PALETTE",
+ "d|SET_PRIORITY",
+ /* 24 */
+ "diid|SET_SPRITE_XY",
+ "x|HALT_SPRITE",
+ "ddddd|SET_WINDOW",
+ "|RESET",
+ /* 28 */
+ "dddd|PLAY_SOUND",
+ "|STOP_ALL_SOUNDS",
+ "d|SET_FRAME_RATE",
+ "d|SET_WINDOW",
+ /* 32 */
+ "|VC_32",
+ "|MOUSE_ON",
+ "|MOUSE_OFF",
+ "dd|CLEAR_WINDOW",
+ /* 36 */
+ "dd|SAVELOAD_THING",
+ "dd|VC_37",
+ "v|SKIP_IF_VAR_ZERO",
+ "vd|SET_VAR",
+ /* 40 */
+ "vd|ADD_VAR",
+ "vd|SUB_VAR",
+ "vd|DELAY_IF_NOT_EQ",
+ "d|SKIP_IF_BIT_CLEAR",
+ /* 44 */
+ "d|SKIP_IF_BIT_SET",
+ "dd|VC_45",
+ "v|SET_SPRITE_Y",
+ "d|VC_47",
+ /* 48 */
+ "d|VC_48",
+ "d|SET_BIT",
+ "d|CLEAR_BIT",
+ "d|ENABLE_BOX",
+ /* 52 */
+ "d|PLAY_EFFECT",
+ "dd|DUMMY_53",
+ "ddd|DUMMY_54",
+ "ddd|MOVE_BOX",
+ /* 56 */
+ "|FULL_SCREEN",
+ "|BLACK_PALETTE",
+ "|SET_PRIORITIES",
+ "|SKIP_IF_NOT_EGA",
+ /* 60 */
+ "d|STOP_ANIMATE",
+ "d|VC_61",
+ "|FASTFADEOUT",
+ "|FASTFADEIN",
+};
+
+const char *const simon1_video_opcode_name_table[] = {
+ /* 0 */
+ "x|RET",
+ "ddd|FADEOUT",
+ "d|CALL",
+ "ddddd|NEW_SPRITE",
+ /* 4 */
+ "ddd|FADEIN",
+ "vd|SKIP_IF_NEQ",
+ "d|SKIP_IFN_SIB_WITH_A",
+ "d|SKIP_IF_SIB_WITH_A",
+ /* 8 */
+ "dd|SKIP_IF_PARENT_IS",
+ "dd|SKIP_IF_UNK3_IS",
+ "ddddd|DRAW",
+ "|CLEAR_PATHFIND_ARRAY",
+ /* 12 */
+ "d|DELAY",
+ "d|SET_SPRITE_OFFSET_X",
+ "d|SET_SPRITE_OFFSET_Y",
+ "d|IDENT_WAKEUP",
+ /* 16 */
+ "d|IDENT_SLEEP",
+ "dq|SET_PATHFIND_ITEM",
+ "i|JUMP_REL",
+ "|CHAIN_TO",
+ /* 20 */
+ "dd|SET_REPEAT",
+ "i|END_REPEAT",
+ "dd|SET_PALETTE",
+ "d|SET_PRIORITY",
+ /* 24 */
+ "diid|SET_SPRITE_XY",
+ "x|HALT_SPRITE",
+ "ddddd|SET_WINDOW",
+ "|RESET",
+ /* 28 */
+ "dddd|PLAY_SOUND",
+ "|STOP_ALL_SOUNDS",
+ "d|SET_FRAME_RATE",
+ "d|SET_WINDOW",
+ /* 32 */
+ "vv|COPY_VAR",
+ "|MOUSE_ON",
+ "|MOUSE_OFF",
+ "dd|CLEAR_WINDOW",
+ /* 36 */
+ "dd|SAVELOAD_THING",
+ "v|SET_SPRITE_OFFSET_Y",
+ "v|SKIP_IF_VAR_ZERO",
+ "vd|SET_VAR",
+ /* 40 */
+ "vd|ADD_VAR",
+ "vd|SUB_VAR",
+ "vd|DELAY_IF_NOT_EQ",
+ "d|SKIP_IF_BIT_CLEAR",
+ /* 44 */
+ "d|SKIP_IF_BIT_SET",
+ "v|SET_SPRITE_X",
+ "v|SET_SPRITE_Y",
+ "vv|ADD_VAR_F",
+ /* 48 */
+ "|COMPUTE_YOFS",
+ "d|SET_BIT",
+ "d|CLEAR_BIT",
+ "d|ENABLE_BOX",
+ /* 52 */
+ "d|PLAY_EFFECT",
+ "dd|DUMMY_53",
+ "ddd|DUMMY_54",
+ "ddd|MOVE_BOX",
+ /* 56 */
+ "|DUMMY_56",
+ "|BLACK_PALETTE",
+ "|SET_PRIORITIES",
+ "|SKIP_IF_VOICE",
+ /* 60 */
+ "d|STOP_ANIMATE",
+ "ddd|MASK",
+ "|FASTFADEOUT",
+ "|FASTFADEIN",
+};
+
+const char *const simon2_video_opcode_name_table[] = {
+ /* 0 */
+ "x|RET",
+ "ddd|FADEOUT",
+ "d|CALL",
+ "ddddd|NEW_SPRITE",
+ /* 4 */
+ "ddd|FADEIN",
+ "vd|SKIP_IF_NEQ",
+ "d|SKIP_IFN_SIB_WITH_A",
+ "d|SKIP_IF_SIB_WITH_A",
+ /* 8 */
+ "dd|SKIP_IF_PARENT_IS",
+ "dd|SKIP_IF_UNK3_IS",
+ "ddddb|DRAW",
+ "|CLEAR_PATHFIND_ARRAY",
+ /* 12 */
+ "b|DELAY",
+ "d|SET_SPRITE_OFFSET_X",
+ "d|SET_SPRITE_OFFSET_Y",
+ "d|IDENT_WAKEUP",
+ /* 16 */
+ "d|IDENT_SLEEP",
+ "dq|SET_PATHFIND_ITEM",
+ "i|JUMP_REL",
+ "|CHAIN_TO",
+ /* 20 */
+ "dd|SET_REPEAT",
+ "i|END_REPEAT",
+ "dd|SET_PALETTE",
+ "d|SET_PRIORITY",
+ /* 24 */
+ "diib|SET_SPRITE_XY",
+ "x|HALT_SPRITE",
+ "ddddd|SET_WINDOW",
+ "|RESET",
+ /* 28 */
+ "dddd|PLAY_SOUND",
+ "|STOP_ALL_SOUNDS",
+ "d|SET_FRAME_RATE",
+ "d|SET_WINDOW",
+ /* 32 */
+ "vv|COPY_VAR",
+ "|MOUSE_ON",
+ "|MOUSE_OFF",
+ "dd|CLEAR_WINDOW",
+ /* 36 */
+ "dd|SAVELOAD_THING",
+ "v|SET_SPRITE_OFFSET_Y",
+ "v|SKIP_IF_VAR_ZERO",
+ "vd|SET_VAR",
+ /* 40 */
+ "vd|ADD_VAR",
+ "vd|SUB_VAR",
+ "vd|DELAY_IF_NOT_EQ",
+ "d|SKIP_IF_BIT_CLEAR",
+ /* 44 */
+ "d|SKIP_IF_BIT_SET",
+ "v|SET_SPRITE_X",
+ "v|SET_SPRITE_Y",
+ "vv|ADD_VAR_F",
+ /* 48 */
+ "|COMPUTE_YOFS",
+ "d|SET_BIT",
+ "d|CLEAR_BIT",
+ "d|ENABLE_BOX",
+ /* 52 */
+ "d|PLAY_EFFECT",
+ "dd|DUMMY_53",
+ "ddd|DUMMY_54",
+ "ddd|MOVE_BOX",
+ /* 56 */
+ "i|WAIT_BIG",
+ "|BLACK_PALETTE",
+ "|SET_PRIORITIES",
+ "ddd|STOP_ANIMATIONS",
+ /* 60 */
+ "dd|STOP_ANIMATE",
+ "ddd|MASK",
+ "|FASTFADEOUT",
+ "|FASTFADEIN",
+ /* 64 */
+ "|SKIP_IF_VOICE",
+ "|SLOW_FADE_IN",
+ "|SKIP_IF_NZ",
+ "|SKIP_IF_GE",
+ /* 68 */
+ "|SKIP_IF_LE",
+ "dd|PLAY_TRACK",
+ "dd|QUEUE_MUSIC",
+ "|CHECK_MUSIC_QUEUE",
+ /* 72 */
+ "dd|PLAY_TRACK_2",
+ "bb|SET_MARK",
+ "bb|CLEAR_MARK",
+};
+
+const char *const feeblefiles_video_opcode_name_table[] = {
+ /* 0 */
+ "x|RET",
+ "ddd|FADEOUT",
+ "d|CALL",
+ "ddddd|NEW_SPRITE",
+ /* 4 */
+ "ddd|FADEIN",
+ "vd|SKIP_IF_NEQ",
+ "d|SKIP_IFN_SIB_WITH_A",
+ "d|SKIP_IF_SIB_WITH_A",
+ /* 8 */
+ "dd|SKIP_IF_PARENT_IS",
+ "dd|SKIP_IF_UNK3_IS",
+ "ddddb|DRAW",
+ "|CLEAR_PATHFIND_ARRAY",
+ /* 12 */
+ "b|DELAY",
+ "d|SET_SPRITE_OFFSET_X",
+ "d|SET_SPRITE_OFFSET_Y",
+ "d|IDENT_WAKEUP",
+ /* 16 */
+ "d|IDENT_SLEEP",
+ "dq|SET_PATHFIND_ITEM",
+ "i|JUMP_REL",
+ "|CHAIN_TO",
+ /* 20 */
+ "dd|SET_REPEAT",
+ "i|END_REPEAT",
+ "dd|SET_PALETTE",
+ "d|SET_PRIORITY",
+ /* 24 */
+ "diib|SET_SPRITE_XY",
+ "x|HALT_SPRITE",
+ "ddddd|SET_WINDOW",
+ "|RESET",
+ /* 28 */
+ "dddd|PLAY_SOUND",
+ "|STOP_ALL_SOUNDS",
+ "d|SET_FRAME_RATE",
+ "d|SET_WINDOW",
+ /* 32 */
+ "vv|COPY_VAR",
+ "|MOUSE_ON",
+ "|MOUSE_OFF",
+ "dd|CLEAR_WINDOW",
+ /* 36 */
+ "dd|SAVELOAD_THING",
+ "v|SET_SPRITE_OFFSET_Y",
+ "v|SKIP_IF_VAR_ZERO",
+ "vd|SET_VAR",
+ /* 40 */
+ "vd|ADD_VAR",
+ "vd|SUB_VAR",
+ "vd|DELAY_IF_NOT_EQ",
+ "d|SKIP_IF_BIT_CLEAR",
+ /* 44 */
+ "d|SKIP_IF_BIT_SET",
+ "v|SET_SPRITE_X",
+ "v|SET_SPRITE_Y",
+ "vv|ADD_VAR_F",
+ /* 48 */
+ "|COMPUTE_YOFS",
+ "d|SET_BIT",
+ "d|CLEAR_BIT",
+ "d|ENABLE_BOX",
+ /* 52 */
+ "ddd|PLAY_EFFECT",
+ "ddd|PAN_SFX",
+ "ddd|DUMMY_54",
+ "ddd|MOVE_BOX",
+ /* 56 */
+ "i|WAIT_BIG",
+ "|BLACK_PALETTE",
+ "|SET_PRIORITIES",
+ "ddd|STOP_ANIMATIONS",
+ /* 60 */
+ "dd|STOP_ANIMATE",
+ "ddd|MASK",
+ "|FASTFADEOUT",
+ "|FASTFADEIN",
+ /* 64 */
+ "|SKIP_IF_VOICE",
+ "|SLOW_FADE_IN",
+ "|SKIP_IF_NZ",
+ "|SKIP_IF_GE",
+ /* 68 */
+ "|SKIP_IF_LE",
+ "dd|PLAY_TRACK",
+ "dd|QUEUE_MUSIC",
+ "|CHECK_MUSIC_QUEUE",
+ /* 72 */
+ "dd|PLAY_TRACK_2",
+ "bb|SET_MARK",
+ "bb|CLEAR_MARK",
+ "dd|SETSCALE",
+ /* 76 */
+ "ddd|SETSCALEXOFFS",
+ "ddd|SETSCALEYOFFS",
+ "|COMPUTEXY",
+ "|COMPUTEPOSNUM",
+ /* 80 */
+ "ddd|SETOVERLAYIMAGE",
+ "dd|SETRANDOM",
+ "d|GETPATHVALUE",
+ "ddd|PLAYSOUNDLOOP",
+ "|STOPSOUNDLOOP",
+};
+
+} // End of namespace Simon
+
+#endif
+
diff --git a/engines/agos/debugger.cpp b/engines/agos/debugger.cpp
new file mode 100644
index 0000000000..8fc4702d1e
--- /dev/null
+++ b/engines/agos/debugger.cpp
@@ -0,0 +1,179 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-2006 The ScummVM project
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/stdafx.h"
+
+#include "common/config-manager.h"
+
+#include "agos/debugger.h"
+#include "agos/agos.h"
+
+namespace Simon {
+
+Debugger::Debugger(SimonEngine *vm)
+ : GUI::Debugger() {
+ _vm = vm;
+
+ DCmd_Register("continue", WRAP_METHOD(Debugger, Cmd_Exit));
+ DCmd_Register("level", WRAP_METHOD(Debugger, Cmd_DebugLevel));
+ DCmd_Register("music", WRAP_METHOD(Debugger, Cmd_PlayMusic));
+ DCmd_Register("sound", WRAP_METHOD(Debugger, Cmd_PlaySound));
+ DCmd_Register("voice", WRAP_METHOD(Debugger, Cmd_PlayVoice));
+ DCmd_Register("bit", WRAP_METHOD(Debugger, Cmd_SetBit));
+ DCmd_Register("var", WRAP_METHOD(Debugger, Cmd_SetVar));
+ DCmd_Register("sub", WRAP_METHOD(Debugger, Cmd_StartSubroutine));
+
+}
+
+
+void Debugger::preEnter() {
+ //_vm->midi.pause(1);
+}
+
+
+void Debugger::postEnter() {
+ //_vm->midi.pause(0);
+}
+
+
+bool Debugger::Cmd_DebugLevel(int argc, const char **argv) {
+ if (argc == 1) {
+ if (_vm->_debugMode == false)
+ DebugPrintf("Debugging is not enabled at this time\n");
+ else
+ DebugPrintf("Debugging is currently set at level %d\n", gDebugLevel);
+ } else { // set level
+ gDebugLevel = atoi(argv[1]);
+ if (gDebugLevel >= 0 && gDebugLevel < 10) {
+ _vm->_debugMode = true;
+ DebugPrintf("Debug level set to level %d\n", gDebugLevel);
+ } else if (gDebugLevel < 0) {
+ _vm->_debugMode = false;
+ DebugPrintf("Debugging is now disabled\n");
+ } else
+ DebugPrintf("Not a valid debug level (0 - 10)\n");
+ }
+
+ return true;
+}
+
+bool Debugger::Cmd_PlayMusic(int argc, const char **argv) {
+ if (argc > 1) {
+ uint music = atoi(argv[1]);
+ uint range = (_vm->getGameType() == GType_SIMON2) ? 93 : 34;
+ if (music <= range) {
+ _vm->loadMusic (music);
+ if (_vm->getGameType() == GType_SIMON2)
+ _vm->midi.startTrack (0);
+ } else
+ DebugPrintf("Music out of range (0 - %d)\n", range);
+ } else
+ DebugPrintf("Syntax: music <musicnum>\n");
+
+ return true;
+}
+
+bool Debugger::Cmd_PlaySound(int argc, const char **argv) {
+ if (argc > 1) {
+ uint sound = atoi(argv[1]);
+ uint range = (_vm->getGameType() == GType_SIMON2) ? 222 : 127;
+ if (sound <= range)
+ _vm->_sound->playEffects(sound);
+ else
+ DebugPrintf("Sound out of range (0 - %d)\n", range);
+ } else
+ DebugPrintf("Syntax: sound <soundnum>\n");
+
+ return true;
+}
+
+bool Debugger::Cmd_PlayVoice(int argc, const char **argv) {
+ if (argc > 1) {
+ uint voice = atoi(argv[1]);
+ uint range = (_vm->getGameType() == GType_SIMON2) ? 3632 : 1996;
+ if (voice <= range)
+ _vm->_sound->playVoice(voice);
+ else
+ DebugPrintf("Voice out of range (0 - %d)\n", range);
+ } else
+ DebugPrintf("Syntax: voice <voicenum>\n");
+
+ return true;
+}
+
+bool Debugger::Cmd_SetBit(int argc, const char **argv) {
+ uint bit, value;
+ if (argc > 2) {
+ bit = atoi(argv[1]);
+ value = atoi(argv[2]);
+ if (value <= 1) {
+ _vm->setBitFlag(bit, value != 0);
+ DebugPrintf("Set bit %d to %d\n", bit, value);
+ } else
+ DebugPrintf("Bit value out of range (0 - 1)\n");
+ } else if (argc > 1) {
+ bit = atoi(argv[1]);
+ value = _vm->getBitFlag(bit);
+ DebugPrintf("Bit %d is %d\n", bit, value);
+ } else
+ DebugPrintf("Syntax: bit <bitnum> <value>\n");
+
+ return true;
+}
+
+bool Debugger::Cmd_SetVar(int argc, const char **argv) {
+ uint var, value;
+ if (argc > 1) {
+ var = atoi(argv[1]);
+ if (var <= 254) {
+ if (argc > 2) {
+ value = atoi(argv[2]);
+ _vm->writeVariable(var, value);
+ DebugPrintf("Set var %d to %d\n", var, value);
+ } else {
+ value = _vm->readVariable(var);
+ DebugPrintf("Var %d is %d\n", var, value);
+ }
+ } else
+ DebugPrintf("Var out of range (0 - 254)\n");
+ } else
+ DebugPrintf("Syntax: var <varnum> <value>\n");
+
+ return true;
+}
+
+bool Debugger::Cmd_StartSubroutine(int argc, const char **argv) {
+ if (argc > 1) {
+ uint subroutine = atoi(argv[1]);
+ Subroutine *sub;
+ sub = _vm->getSubroutineByID(subroutine);
+ if (sub != NULL)
+ _vm->startSubroutine(sub);
+ } else
+ DebugPrintf("Subroutine %d\n", _vm->_subroutine);
+
+ return true;
+}
+
+} // End of namespace Simon
+
diff --git a/engines/agos/debugger.h b/engines/agos/debugger.h
new file mode 100644
index 0000000000..cd43f3e1eb
--- /dev/null
+++ b/engines/agos/debugger.h
@@ -0,0 +1,55 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-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 AGOS_DEBUGGER_H
+#define AGOS_DEBUGGER_H
+
+#include "gui/debugger.h"
+
+namespace Simon {
+
+class SimonEngine;
+
+class Debugger : public GUI::Debugger {
+public:
+ Debugger(SimonEngine *vm);
+ virtual ~Debugger() {} // we need this for __SYMBIAN32__ archaic gcc/UIQ
+
+protected:
+ SimonEngine *_vm;
+
+ virtual void preEnter();
+ virtual void postEnter();
+
+ bool Cmd_DebugLevel(int argc, const char **argv);
+ bool Cmd_PlayMusic(int argc, const char **argv);
+ bool Cmd_PlaySound(int argc, const char **argv);
+ bool Cmd_PlayVoice(int argc, const char **argv);
+ bool Cmd_SetBit(int argc, const char **argv);
+ bool Cmd_SetVar(int argc, const char **argv);
+ bool Cmd_StartSubroutine(int argc, const char **argv);
+};
+
+} // End of namespace Simon
+
+#endif
diff --git a/engines/agos/draw.cpp b/engines/agos/draw.cpp
new file mode 100644
index 0000000000..ab65cd0af2
--- /dev/null
+++ b/engines/agos/draw.cpp
@@ -0,0 +1,512 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-2006 The ScummVM project
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/stdafx.h"
+
+#include "common/system.h"
+
+#include "agos/agos.h"
+#include "agos/intern.h"
+
+namespace Simon {
+
+byte *SimonEngine::getFrontBuf() {
+ _dxSurfacePitch = _screenWidth;
+ return _frontBuf;
+}
+
+byte *SimonEngine::getBackBuf() {
+ _dxSurfacePitch = _screenWidth;
+ return _useBackGround ? _backGroundBuf : _backBuf;
+}
+
+byte *SimonEngine::getBackGround() {
+ _dxSurfacePitch = _screenWidth;
+ return _backGroundBuf;
+}
+
+byte *SimonEngine::getScaleBuf() {
+ _dxSurfacePitch = _screenWidth;
+ return _scaleBuf;
+}
+
+void SimonEngine::animateSprites() {
+ VgaSprite *vsp;
+ VgaPointersEntry *vpe;
+ const byte *vc_ptr_org = _vcPtr;
+ uint16 params[5]; // parameters to vc10
+
+ if (_paletteFlag == 2)
+ _paletteFlag = 1;
+
+ if (getGameType() == GType_FF && _scrollCount) {
+ scrollEvent();
+ }
+ if (getGameType() == GType_SIMON2 && _scrollFlag) {
+ scrollScreen();
+ }
+
+ if (getGameType() == GType_FF && getBitFlag(84)) {
+ animateSpritesByY();
+ return;
+ }
+
+ vsp = _vgaSprites;
+
+ while (vsp->id != 0) {
+ vsp->windowNum &= 0x7FFF;
+
+ vpe = &_vgaBufferPointers[vsp->zoneNum];
+ _curVgaFile1 = vpe->vgaFile1;
+ _curVgaFile2 = vpe->vgaFile2;
+ _curSfxFile = vpe->sfxFile;
+ _windowNum = vsp->windowNum;
+ _vgaCurSpriteId = vsp->id;
+ _vgaCurSpritePriority = vsp->priority;
+
+ params[0] = readUint16Wrapper(&vsp->image);
+ if (getGameType() == GType_WW) {
+ params[1] = readUint16Wrapper(&vsp->x);
+ params[2] = readUint16Wrapper(&vsp->y);
+ params[3] = READ_BE_UINT16(&vsp->flags);
+ } else {
+ params[1] = readUint16Wrapper(&vsp->palette);
+ params[2] = readUint16Wrapper(&vsp->x);
+ params[3] = readUint16Wrapper(&vsp->y);
+
+ if (getGameType() == GType_SIMON1) {
+ params[4] = READ_BE_UINT16(&vsp->flags);
+ } else {
+ *(byte *)(&params[4]) = (byte)vsp->flags;
+ }
+ }
+
+ _vcPtr = (const byte *)params;
+ vc10_draw();
+
+ vsp++;
+ }
+
+ if (_drawImagesDebug)
+ memset(_backBuf, 0, _screenWidth * _screenHeight);
+
+ _updateScreen = true;
+ _vcPtr = vc_ptr_org;
+}
+
+void SimonEngine::animateSpritesDebug() {
+ VgaSprite *vsp;
+ VgaPointersEntry *vpe;
+ const byte *vc_ptr_org = _vcPtr;
+ uint16 params[5]; // parameters to vc10_draw
+
+ if (_paletteFlag == 2)
+ _paletteFlag = 1;
+
+ vsp = _vgaSprites;
+ while (vsp->id != 0) {
+ vsp->windowNum &= 0x7FFF;
+
+ vpe = &_vgaBufferPointers[vsp->zoneNum];
+ _curVgaFile1 = vpe->vgaFile1;
+ _curVgaFile2 = vpe->vgaFile2;
+ _curSfxFile = vpe->sfxFile;
+ _windowNum = vsp->windowNum;
+ _vgaCurSpriteId = vsp->id;
+
+ if (vsp->image)
+ printf("id:%5d image:%3d base-color:%3d x:%3d y:%3d flags:%x\n",
+ vsp->id, vsp->image, vsp->palette, vsp->x, vsp->y, vsp->flags);
+ params[0] = readUint16Wrapper(&vsp->image);
+ if (getGameType() == GType_WW) {
+ params[1] = readUint16Wrapper(&vsp->x);
+ params[2] = readUint16Wrapper(&vsp->y);
+ params[3] = READ_BE_UINT16(&vsp->flags);
+ } else {
+ params[1] = readUint16Wrapper(&vsp->palette);
+ params[2] = readUint16Wrapper(&vsp->x);
+ params[3] = readUint16Wrapper(&vsp->y);
+
+ if (getGameType() == GType_SIMON1) {
+ params[4] = READ_BE_UINT16(&vsp->flags);
+ } else {
+ *(byte *)(&params[4]) = (byte)vsp->flags;
+ }
+ }
+
+ _vcPtr = (const byte *)params;
+ vc10_draw();
+
+ vsp++;
+ }
+
+ _updateScreen = true;
+ _vcPtr = vc_ptr_org;
+}
+
+void SimonEngine::animateSpritesByY() {
+ VgaSprite *vsp;
+ VgaPointersEntry *vpe;
+ const byte *vc_ptr_org = _vcPtr;
+ uint16 params[5]; // parameters to vc10
+ int16 spriteTable[180][2];
+
+ byte *src;
+ int height, slot, y;
+ uint i, numSprites = 0;
+
+ vsp = _vgaSprites;
+ while (vsp->id != 0) {
+ if (vsp->flags & kDFScaled) {
+ y = vsp->y;
+ } else if (vsp->flags & kDFMasked) {
+ vpe = &_vgaBufferPointers[vsp->zoneNum];
+ src = vpe->vgaFile2 + vsp->image * 8;
+ height = READ_LE_UINT16(src + 4) & 0x7FFF;
+ y = vsp->y + height;
+ } else {
+ y = vsp->priority;
+ }
+
+ spriteTable[numSprites][0] = y;
+ spriteTable[numSprites][1] = numSprites;
+ numSprites++;
+ vsp++;
+ }
+
+ while (1) {
+ y = spriteTable[0][0];
+ slot = spriteTable[0][1];
+
+ for (i = 0; i < numSprites; i++) {
+ if (y >= spriteTable[i][0]) {
+ y = spriteTable[i][0];
+ slot = spriteTable[i][1];
+ }
+ }
+
+ if (y == 9999)
+ break;
+
+ for (i = 0; i < numSprites; i++) {
+ if (slot == spriteTable[i][1]) {
+ spriteTable[i][0] = 9999;
+ break;
+ }
+ }
+
+ vsp = &_vgaSprites[slot];
+ vsp->windowNum &= 0x7FFF;
+
+ vpe = &_vgaBufferPointers[vsp->zoneNum];
+ _curVgaFile1 = vpe->vgaFile1;
+ _curVgaFile2 = vpe->vgaFile2;
+ _curSfxFile = vpe->sfxFile;
+ _windowNum = vsp->windowNum;
+ _vgaCurSpriteId = vsp->id;
+ _vgaCurSpritePriority = vsp->priority;
+
+ params[0] = readUint16Wrapper(&vsp->image);
+ params[1] = readUint16Wrapper(&vsp->palette);
+ params[2] = readUint16Wrapper(&vsp->x);
+ params[3] = readUint16Wrapper(&vsp->y);
+ *(byte *)(&params[4]) = (byte)vsp->flags;
+
+ _vcPtr = (const byte *)params;
+ vc10_draw();
+ }
+
+ _updateScreen = true;
+ _vcPtr = vc_ptr_org;
+}
+
+void SimonEngine::displayBoxStars() {
+ HitArea *ha, *dha;
+ uint count;
+ uint y_, x_;
+ byte *dst;
+ uint b, color;
+
+ _lockWord |= 0x8000;
+
+ if (getGameType() == GType_SIMON2)
+ color = 236;
+ else
+ color = 225;
+
+ uint limit = (getGameType() == GType_SIMON2) ? 200 : 134;
+
+ for (int i = 0; i < 5; i++) {
+ ha = _hitAreas;
+ count = ARRAYSIZE(_hitAreas);
+
+ animateSprites();
+
+ do {
+ if (ha->id != 0 && ha->flags & kBFBoxInUse && !(ha->flags & kBFBoxDead)) {
+
+ dha = _hitAreas;
+ if (ha->flags & kBFTextBox) {
+ while (dha != ha && dha->flags != ha->flags)
+ ++dha;
+ if (dha != ha && dha->flags == ha->flags)
+ continue;
+ } else {
+ dha = _hitAreas;
+ while (dha != ha && dha->item_ptr != ha->item_ptr)
+ ++dha;
+ if (dha != ha && dha->item_ptr == ha->item_ptr)
+ continue;
+ }
+
+ if (ha->y >= limit || ((getGameType() == GType_SIMON2) && ha->y >= _boxStarHeight))
+ continue;
+
+ y_ = (ha->height / 2) - 4 + ha->y;
+
+ x_ = (ha->width / 2) - 4 + ha->x - (_scrollX * 8);
+
+ if (x_ >= 311)
+ continue;
+
+ dst = getBackBuf();
+
+ dst += (((_dxSurfacePitch / 4) * y_) * 4) + x_;
+
+ b = _dxSurfacePitch;
+ dst[4] = color;
+ dst[b+1] = color;
+ dst[b+4] = color;
+ dst[b+7] = color;
+ b += _dxSurfacePitch;
+ dst[b+2] = color;
+ dst[b+4] = color;
+ dst[b+6] = color;
+ b += _dxSurfacePitch;
+ dst[b+3] = color;
+ dst[b+5] = color;
+ b += _dxSurfacePitch;
+ dst[b] = color;
+ dst[b+1] = color;
+ dst[b+2] = color;
+ dst[b+6] = color;
+ dst[b+7] = color;
+ dst[b+8] = color;
+ b += _dxSurfacePitch;
+ dst[b+3] = color;
+ dst[b+5] = color;
+ b += _dxSurfacePitch;
+ dst[b+2] = color;
+ dst[b+4] = color;
+ dst[b+6] = color;
+ b += _dxSurfacePitch;
+ dst[b+1] = color;
+ dst[b+4] = color;
+ dst[b+7] = color;
+ b += _dxSurfacePitch;
+ dst[b+4] = color;
+ }
+ } while (ha++, --count);
+
+ dx_update_screen_and_palette();
+ delay(100);
+ animateSprites();
+ dx_update_screen_and_palette();
+ delay(100);
+ }
+
+ _lockWord &= ~0x8000;
+}
+
+void SimonEngine::scrollScreen() {
+ byte *dst = getFrontBuf();
+ const byte *src;
+ uint x, y;
+
+ if (_scrollXMax == 0) {
+ uint screenSize = 8 * _screenWidth;
+ if (_scrollFlag < 0) {
+ memmove(dst + screenSize, dst, _scrollWidth * _screenHeight - screenSize);
+ } else {
+ memmove(dst, dst + screenSize, _scrollWidth * _screenHeight - screenSize);
+ }
+
+ y = _scrollY - 8;
+
+ if (_scrollFlag > 0) {
+ dst += _screenHeight * _screenWidth - screenSize;
+ y += 488;
+ }
+
+ src = _scrollImage + y / 2;
+ decodeRow(dst, src + readUint32Wrapper(src), _scrollWidth);
+
+ _scrollY += _scrollFlag;
+ vcWriteVar(250, _scrollY);
+
+ memcpy(_backBuf, _frontBuf, _screenWidth * _screenHeight);
+ memcpy(_backGroundBuf, _backBuf, _screenHeight * _scrollWidth);
+ } else {
+ if (_scrollFlag < 0) {
+ memmove(dst + 8, dst, _screenWidth * _scrollHeight - 8);
+ } else {
+ memmove(dst, dst + 8, _screenWidth * _scrollHeight - 8);
+ }
+
+ x = _scrollX;
+ x -= (getGameType() == GType_FF) ? 8 : 1;
+
+ if (_scrollFlag > 0) {
+ dst += _screenWidth - 8;
+ x += (getGameType() == GType_FF) ? 648 : 41;
+ }
+
+ if (getGameType() == GType_FF)
+ src = _scrollImage + x / 2;
+ else
+ src = _scrollImage + x * 4;
+ decodeColumn(dst, src + readUint32Wrapper(src), _scrollHeight);
+
+ _scrollX += _scrollFlag;
+ vcWriteVar(251, _scrollX);
+
+ memcpy(_backBuf, _frontBuf, _screenWidth * _screenHeight);
+ memcpy(_backGroundBuf, _backBuf, _scrollHeight * _screenWidth);
+ }
+
+ _scrollFlag = 0;
+}
+
+void SimonEngine::clearBackFromTop(uint lines) {
+ memset(_backBuf, 0, lines * _screenWidth);
+}
+
+void SimonEngine::dx_clear_surfaces(uint num_lines) {
+ memset(_backBuf, 0, num_lines * _screenWidth);
+
+ _system->copyRectToScreen(_backBuf, _screenWidth, 0, 0, _screenWidth, num_lines);
+
+ if (_useBackGround) {
+ memset(_frontBuf, 0, num_lines * _screenWidth);
+ memset(_backGroundBuf, 0, num_lines * _screenWidth);
+ }
+}
+
+void SimonEngine::fillFrontFromBack(uint x, uint y, uint w, uint h) {
+ uint offs = x + y * _screenWidth;
+ byte *s = _backBuf + offs;
+ byte *d = _frontBuf + offs;
+
+ do {
+ memcpy(d, s, w);
+ d += _screenWidth;
+ s += _screenWidth;
+ } while (--h);
+}
+
+void SimonEngine::fillBackFromFront(uint x, uint y, uint w, uint h) {
+ uint offs = x + y * _screenWidth;
+ byte *s = _frontBuf + offs;
+ byte *d = _backBuf + offs;
+
+ do {
+ memcpy(d, s, w);
+ d += _screenWidth;
+ s += _screenWidth;
+ } while (--h);
+}
+
+void SimonEngine::fillBackGroundFromBack(uint lines) {
+ memcpy(_backGroundBuf, _backBuf, lines * _screenWidth);
+}
+
+void SimonEngine::dx_update_screen_and_palette() {
+ if (_fastFadeInFlag == 0 && _paletteFlag == 1) {
+ _paletteFlag = 0;
+ if (memcmp(_displayPalette, _currentPalette, 1024)) {
+ memcpy(_currentPalette, _displayPalette, 1024);
+ _system->setPalette(_displayPalette, 0, 256);
+ }
+ }
+
+ _system->copyRectToScreen(_backBuf, _screenWidth, 0, 0, _screenWidth, _screenHeight);
+ _system->updateScreen();
+
+ memcpy(_backBuf, _frontBuf, _screenWidth * _screenHeight);
+
+ if (getGameType() == GType_FF && _scrollFlag) {
+ scrollScreen();
+ }
+
+ if (_fastFadeInFlag) {
+ if (getGameType() == GType_SIMON1 && _usePaletteDelay) {
+ delay(100);
+ _usePaletteDelay = false;
+ }
+ fastFadeIn();
+ }
+}
+
+void SimonEngine::fastFadeIn() {
+ if (_fastFadeInFlag & 0x8000) {
+ slowFadeIn();
+ } else {
+ _paletteFlag = false;
+ memcpy(_currentPalette, _displayPalette, 1024);
+ _system->setPalette(_displayPalette, 0, _fastFadeInFlag);
+ _fastFadeInFlag = 0;
+ }
+}
+
+void SimonEngine::slowFadeIn() {
+ uint8 *src, *dst;
+ int c, p;
+
+ _fastFadeInFlag &= 0x7fff;
+ _paletteFlag = false;
+
+ memset(_videoBuf1, 0, 1024);
+ memcpy(_currentPalette, _displayPalette, 1024);
+ memcpy(_videoBuf1 + 1024, _displayPalette, 1024);
+
+ for (c = 255; c >= 0; c -= 4) {
+ src = _videoBuf1 + 1024;
+ dst = _videoBuf1;
+
+ for (p = _fastFadeInFlag; p !=0 ; p -= 3) {
+ if (src[0] >= c)
+ dst[0] += 4;
+ if (src[1] >= c)
+ dst[1] += 4;
+ if (src[2] >= c)
+ dst[2] += 4;
+ src += 4;
+ dst += 4;
+ }
+ _system->setPalette(_videoBuf1, 0, _fastFadeCount);
+ delay(5);
+ }
+ _fastFadeInFlag = 0;
+}
+
+} // End of namespace Simon
diff --git a/engines/agos/event.cpp b/engines/agos/event.cpp
new file mode 100644
index 0000000000..4755dea987
--- /dev/null
+++ b/engines/agos/event.cpp
@@ -0,0 +1,376 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-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 "agos/agos.h"
+#include "agos/intern.h"
+
+namespace Simon {
+
+void SimonEngine::addTimeEvent(uint timeout, uint subroutine_id) {
+ TimeEvent *te = (TimeEvent *)malloc(sizeof(TimeEvent)), *first, *last = NULL;
+ time_t cur_time;
+
+ time(&cur_time);
+
+ te->time = cur_time + timeout - _gameStoppedClock;
+ if (_clockStopped)
+ te->time -= ((uint32)time(NULL) - _clockStopped);
+ te->subroutine_id = subroutine_id;
+
+ first = _firstTimeStruct;
+ while (first) {
+ if (te->time <= first->time) {
+ if (last) {
+ last->next = te;
+ te->next = first;
+ return;
+ }
+ te->next = _firstTimeStruct;
+ _firstTimeStruct = te;
+ return;
+ }
+
+ last = first;
+ first = first->next;
+ }
+
+ if (last) {
+ last->next = te;
+ te->next = NULL;
+ } else {
+ _firstTimeStruct = te;
+ te->next = NULL;
+ }
+}
+
+void SimonEngine::delTimeEvent(TimeEvent *te) {
+ TimeEvent *cur;
+
+ if (te == _pendingDeleteTimeEvent)
+ _pendingDeleteTimeEvent = NULL;
+
+ if (te == _firstTimeStruct) {
+ _firstTimeStruct = te->next;
+ free(te);
+ return;
+ }
+
+ cur = _firstTimeStruct;
+ if (cur == NULL)
+ error("delTimeEvent: none available");
+
+ for (;;) {
+ if (cur->next == NULL)
+ error("delTimeEvent: no such te");
+ if (te == cur->next) {
+ cur->next = te->next;
+ free(te);
+ return;
+ }
+ cur = cur->next;
+ }
+}
+
+void SimonEngine::invokeTimeEvent(TimeEvent *te) {
+ Subroutine *sub;
+
+ _scriptVerb = 0;
+
+ if (_runScriptReturn1)
+ return;
+
+ sub = getSubroutineByID(te->subroutine_id);
+ if (sub != NULL)
+ startSubroutineEx(sub);
+
+ _runScriptReturn1 = false;
+}
+
+void SimonEngine::killAllTimers() {
+ TimeEvent *cur, *next;
+
+ for (cur = _firstTimeStruct; cur; cur = next) {
+ next = cur->next;
+ delTimeEvent(cur);
+ }
+}
+
+bool SimonEngine::kickoffTimeEvents() {
+ time_t cur_time;
+ TimeEvent *te;
+ bool result = false;
+
+ if (_clockStopped)
+ return result;
+
+ time(&cur_time);
+ cur_time -= _gameStoppedClock;
+
+ while ((te = _firstTimeStruct) != NULL && te->time <= (uint32)cur_time) {
+ result = true;
+ _pendingDeleteTimeEvent = te;
+ invokeTimeEvent(te);
+ if (_pendingDeleteTimeEvent) {
+ _pendingDeleteTimeEvent = NULL;
+ delTimeEvent(te);
+ }
+ }
+
+ return result;
+}
+
+void SimonEngine::addVgaEvent(uint16 num, const byte *code_ptr, uint16 cur_sprite, uint16 curZoneNum, int32 param) {
+ VgaTimerEntry *vte;
+
+ // When Simon talks to the Golum about stew in French version of
+ // Simon the Sorcerer 1 the code_ptr is at wrong location for
+ // sprite 200. This was a bug in the original game, which
+ // caused several glitches in this scene.
+ // We work around the problem by correcting the code_ptr for sprite
+ // 200 in this scene, if it is wrong.
+ if (getGameType() == GType_SIMON1 && _language == Common::FR_FRA &&
+ (code_ptr - _vgaBufferPointers[curZoneNum].vgaFile1 == 4) && (cur_sprite == 200) && (curZoneNum == 2))
+ code_ptr += 0x66;
+
+ _lockWord |= 1;
+
+ for (vte = _vgaTimerList; vte->delay; vte++) {
+ }
+
+ vte->delay = num;
+ vte->script_pointer = code_ptr;
+ vte->sprite_id = cur_sprite;
+ vte->cur_vga_file = curZoneNum;
+ vte->param = param;
+
+ _lockWord &= ~1;
+}
+
+void SimonEngine::deleteVgaEvent(VgaTimerEntry * vte) {
+ _lockWord |= 1;
+
+ if (vte + 1 <= _nextVgaTimerToProcess) {
+ _nextVgaTimerToProcess--;
+ }
+
+ do {
+ memcpy(vte, vte + 1, sizeof(VgaTimerEntry));
+ vte++;
+ } while (vte->delay);
+
+ _lockWord &= ~1;
+}
+
+void SimonEngine::processVgaEvents() {
+ VgaTimerEntry *vte = _vgaTimerList;
+ uint timer = (getGameType() == GType_FF) ? 5 : 1;
+
+ _vgaTickCounter++;
+
+ while (vte->delay) {
+ vte->delay -= timer;
+ if (vte->delay <= 0) {
+ uint16 curZoneNum = vte->cur_vga_file;
+ uint16 cur_sprite = vte->sprite_id;
+ const byte *script_ptr = vte->script_pointer;
+ int32 param = vte->param;
+
+ _nextVgaTimerToProcess = vte + 1;
+ deleteVgaEvent(vte);
+
+ if (getGameType() == GType_FF && script_ptr == NULL) {
+ panEvent(curZoneNum, cur_sprite, param);
+ } else if (getGameType() == GType_SIMON2 && script_ptr == NULL) {
+ scrollEvent();
+ } else {
+ animateEvent(script_ptr, curZoneNum, cur_sprite);
+ }
+ vte = _nextVgaTimerToProcess;
+ } else {
+ vte++;
+ }
+ }
+}
+
+void SimonEngine::animateEvent(const byte *code_ptr, uint16 curZoneNum, uint16 cur_sprite) {
+ VgaPointersEntry *vpe;
+
+ _vgaCurSpriteId = cur_sprite;
+
+ _vgaCurZoneNum = curZoneNum;
+ _zoneNumber = curZoneNum;
+ vpe = &_vgaBufferPointers[curZoneNum];
+
+ _curVgaFile1 = vpe->vgaFile1;
+ _curVgaFile2 = vpe->vgaFile2;
+ _curSfxFile = vpe->sfxFile;
+
+ _vcPtr = code_ptr;
+
+ runVgaScript();
+}
+
+void SimonEngine::panEvent(uint16 curZoneNum, uint16 cur_sprite, int32 param) {
+ _vgaCurSpriteId = cur_sprite;
+ _vgaCurZoneNum = curZoneNum;
+
+ VgaSprite *vsp = findCurSprite();
+
+ param &= 0x10;
+
+ int32 pan = (vsp->x - _scrollX + param) * 8 - 2560;
+ if (pan < -10000)
+ pan = -10000;
+ if (pan > 10000)
+ pan = 10000;
+
+ //setSfxPan(param, pan);
+
+ if (pan != 0)
+ addVgaEvent(10, NULL, _vgaCurSpriteId, _vgaCurZoneNum); /* pan event */
+ debug(0, "panEvent: param %d pan %d", param, pan);
+}
+
+void SimonEngine::scrollEvent() {
+ if (_scrollCount == 0)
+ return;
+
+ if (getGameType() == GType_FF) {
+ if (_scrollCount < 0) {
+ if (_scrollFlag != -8) {
+ _scrollFlag = -8;
+ _scrollCount += 8;
+ }
+ } else {
+ if (_scrollFlag != 8) {
+ _scrollFlag = 8;
+ _scrollCount -= 8;
+ }
+ }
+ } else {
+ if (_scrollCount < 0) {
+ if (_scrollFlag != -1) {
+ _scrollFlag = -1;
+ if (++_scrollCount == 0)
+ return;
+ }
+ } else {
+ if (_scrollFlag != 1) {
+ _scrollFlag = 1;
+ if (--_scrollCount == 0)
+ return;
+ }
+ }
+
+ addVgaEvent(6, NULL, 0, 0); /* scroll event */
+ }
+}
+
+void SimonEngine::timer_callback() {
+ if (_timer5 != 0) {
+ _syncFlag2 = true;
+ _timer5--;
+ } else {
+ timer_proc1();
+ }
+}
+
+void SimonEngine::timer_proc1() {
+ _timer4++;
+
+ if (_lockWord & 0x80E9 || _lockWord & 2)
+ return;
+
+ _syncCount++;
+
+ _lockWord |= 2;
+
+ if (!(_lockWord & 0x10)) {
+ if (getGameType() == GType_FF) {
+ _syncFlag2 ^= 1;
+ if (!_syncFlag2) {
+ processVgaEvents();
+ } else {
+ // Double speed on Oracle
+ if (getBitFlag(99)) {
+ processVgaEvents();
+ } else if (_scrollCount == 0) {
+ _lockWord &= ~2;
+ return;
+ }
+ }
+ } else {
+ processVgaEvents();
+ processVgaEvents();
+ _syncFlag2 ^= 1;
+ _cepeFlag ^= 1;
+ if (!_cepeFlag)
+ processVgaEvents();
+
+ if (_mouseHideCount != 0 && _syncFlag2) {
+ _lockWord &= ~2;
+ return;
+ }
+ }
+ }
+
+ if (getGameType() == GType_FF)
+ _moviePlay->nextFrame();
+
+ animateSprites();
+ if (_drawImagesDebug)
+ animateSpritesDebug();
+
+ if (_copyPartialMode == 1) {
+ fillBackFromFront(80, 46, 208 - 80, 94 - 46);
+ }
+
+ if (_copyPartialMode == 2) {
+ if (getGameType() == GType_FF) {
+ fillFrontFromBack(0, 0, _screenWidth, _screenHeight);
+ } else {
+ fillFrontFromBack(176, 61, _screenWidth - 176, 134 - 61);
+ }
+ _copyPartialMode = 0;
+ }
+
+ if (_updateScreen) {
+ if (getGameType() == GType_FF) {
+ if (!getBitFlag(78)) {
+ oracleLogo();
+ }
+ if (getBitFlag(76)) {
+ swapCharacterLogo();
+ }
+ }
+ handleMouseMoved();
+ dx_update_screen_and_palette();
+ _updateScreen = false;
+ }
+
+ _lockWord &= ~2;
+}
+
+} // End of namespace Simon
diff --git a/engines/agos/game.cpp b/engines/agos/game.cpp
new file mode 100644
index 0000000000..f4997520ab
--- /dev/null
+++ b/engines/agos/game.cpp
@@ -0,0 +1,1704 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-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 "base/plugins.h"
+
+#include "common/config-manager.h"
+#include "common/file.h"
+#include "common/fs.h"
+#include "common/md5.h"
+#include "common/hashmap.h"
+#include "common/hash-str.h"
+
+#include "agos/agos.h"
+
+namespace Simon {
+static DetectedGameList GAME_detectGames(const FSList &fslist);
+}
+
+using Common::File;
+
+struct ObsoleteGameID {
+ const char *from;
+ const char *to;
+ Common::Platform platform;
+};
+
+/**
+ * Conversion table mapping old obsolete target names to the
+ * corresponding new target and platform combination.
+ *
+ */
+static const ObsoleteGameID obsoleteGameIDsTable[] = {
+ {"simon1acorn", "simon1", Common::kPlatformAcorn},
+ {"simon1amiga", "simon1", Common::kPlatformAmiga},
+ {"simon1cd32", "simon1", Common::kPlatformAmiga},
+ {"simon1demo", "simon1", Common::kPlatformPC},
+ {"simon1dos", "simon1", Common::kPlatformPC},
+ {"simon1talkie", "simon1", Common::kPlatformPC},
+ {"simon1win", "simon1", Common::kPlatformWindows},
+ {"simon2dos", "simon2", Common::kPlatformPC},
+ {"simon2talkie", "simon2", Common::kPlatformPC},
+ {"simon2mac", "simon2", Common::kPlatformMacintosh},
+ {"simon2win", "simon2", Common::kPlatformWindows},
+ {NULL, NULL, Common::kPlatformUnknown}
+};
+
+static const PlainGameDescriptor simonGames[] = {
+ {"elvira", "Elvira"},
+ {"elvira2", "Elvira 2"},
+ {"waxworks", "Waxworks"},
+ {"simon1", "Simon the Sorcerer 1"},
+ {"simon2", "Simon the Sorcerer 2"},
+ {"feeble", "The Feeble Files"},
+ {"dimp", "Demon in my Pocket"},
+ {"jumble", "Jumble"},
+ {"puzzle", "NoPatience"},
+ {"swampy", "Swampy Adventures"},
+ {NULL, NULL}
+};
+
+GameList Engine_AGOS_gameIDList() {
+ GameList games;
+ const PlainGameDescriptor *g = simonGames;
+ while (g->gameid) {
+ games.push_back(*g);
+ g++;
+ }
+
+ return games;
+}
+
+GameDescriptor Engine_AGOS_findGameID(const char *gameid) {
+ // First search the list of supported game IDs.
+ const PlainGameDescriptor *g = simonGames;
+ while (g->gameid) {
+ if (!scumm_stricmp(gameid, g->gameid))
+ return *g;
+ g++;
+ }
+
+ // If we didn't find the gameid in the main list, check if it
+ // is an obsolete game id.
+ GameDescriptor gs;
+ const ObsoleteGameID *o = obsoleteGameIDsTable;
+ while (o->from) {
+ if (0 == scumm_stricmp(gameid, o->from)) {
+ gs.gameid = gameid;
+ gs.description = "Obsolete game ID";
+ return gs;
+ }
+ o++;
+ }
+ return gs;
+}
+
+DetectedGameList Engine_AGOS_detectGames(const FSList &fslist) {
+ return Simon::GAME_detectGames(fslist);
+}
+
+PluginError Engine_AGOS_create(OSystem *syst, Engine **engine) {
+ assert(syst);
+ assert(engine);
+ const char *gameid = ConfMan.get("gameid").c_str();
+
+ for (const ObsoleteGameID *o = obsoleteGameIDsTable; o->from; ++o) {
+ if (!scumm_stricmp(gameid, o->from)) {
+ // Match found, perform upgrade
+ gameid = o->to;
+ ConfMan.set("gameid", o->to);
+
+ if (o->platform != Common::kPlatformUnknown)
+ ConfMan.set("platform", Common::getPlatformCode(o->platform));
+
+ warning("Target upgraded from %s to %s", o->from, o->to);
+ ConfMan.flushToDisk();
+ break;
+ }
+ }
+
+ FSList fslist;
+ FilesystemNode dir(ConfMan.get("path"));
+ if (!dir.listDir(fslist, FilesystemNode::kListFilesOnly)) {
+ warning("SimonEngine: invalid game path '%s'", dir.path().c_str());
+ return kInvalidPathError;
+ }
+
+ // Invoke the detector
+ DetectedGameList detectedGames = Engine_AGOS_detectGames(fslist);
+
+ for (uint i = 0; i < detectedGames.size(); i++) {
+ if (detectedGames[i].gameid == gameid) {
+ *engine = new Simon::SimonEngine(syst);
+ return kNoError;
+ }
+ }
+
+ warning("SimonEngine: Unable to locate game data at path '%s'", dir.path().c_str());
+ return kNoGameDataFoundError;
+}
+
+REGISTER_PLUGIN(AGOS, "AGOS", "AGOS (C) Adventure Soft");
+
+namespace Simon {
+
+#define FILE_MD5_BYTES 5000
+
+static GameFileDescription SIMON1ACORNDEMO_GameFiles[] = {
+ { "data", GAME_GMEFILE, "b4a7526ced425ba8ad0d548d0ec69900"},
+ { "gamebase", GAME_BASEFILE, "425c7d1957699d35abca7e12a08c7422"},
+ { "icondata", GAME_ICONFILE, "22107c24dfb31b66ac503c28a6e20b19"},
+ { "stripped", GAME_STRFILE, "d9de7542612d9f4e0819ad0df5eac56b"},
+ { "tbllist", GAME_TBLFILE, "d198a80de2c59e4a0cd24b98814849e8"},
+};
+
+static GameFileDescription SIMON1ACORN_GameFiles[] = {
+ { "data", GAME_GMEFILE, "64958b3a38afdcb85da1eeed85169806"},
+ { "gamebase", GAME_BASEFILE, "28261b99cd9da1242189b4f6f2841bd6"},
+ { "icondata", GAME_ICONFILE, "22107c24dfb31b66ac503c28a6e20b19"},
+ { "stripped", GAME_STRFILE, "f3b27a3fbb45dcd323a48159496e45e8"},
+ { "tbllist", GAME_TBLFILE, "d198a80de2c59e4a0cd24b98814849e8"},
+};
+
+static GameFileDescription SIMON1AMIGA_GameFiles[] = {
+ { "gameamiga", GAME_BASEFILE, "6c9ad2ff571d34a4cf0c696cf4e13500"},
+ { "icon.pkd", GAME_ICONFILE, "565ef7a98dcc21ef526a2bb10b6f42ed"},
+ { "stripped.txt", GAME_STRFILE, "c649fcc0439766810e5097ee7e81d4c8"},
+ { "tbllist", GAME_TBLFILE, "f9d5bf2ce09f82289c791c3ca26e1e4b"},
+};
+
+static GameFileDescription SIMON1AMIGA_FR_GameFiles[] = {
+ { "gameamiga", GAME_BASEFILE, "bd9828b9d4e5d89b50fe8c47a8e6bc07"},
+ { "icon.pkd", GAME_ICONFILE, "565ef7a98dcc21ef526a2bb10b6f42ed"},
+ { "stripped.txt", GAME_STRFILE, "2297baec985617d0d5612a0124bac359"},
+ { "tbllist", GAME_TBLFILE, "f9d5bf2ce09f82289c791c3ca26e1e4b"},
+};
+
+static GameFileDescription SIMON1AMIGA_DE_GameFiles[] = {
+ { "gameamiga", GAME_BASEFILE, "a2de9553f3b73064369948b5af38bb30"},
+ { "icon.pkd", GAME_ICONFILE, "565ef7a98dcc21ef526a2bb10b6f42ed"},
+ { "stripped.txt", GAME_STRFILE, "c649fcc0439766810e5097ee7e81d4c8"},
+ { "tbllist", GAME_TBLFILE, "f9d5bf2ce09f82289c791c3ca26e1e4b"},
+};
+
+static GameFileDescription SIMON1AMIGADEMO_GameFiles[] = {
+ { "gameamiga", GAME_BASEFILE, "a12b696170f14eca5ff75f1549829251"}, // Unpacked version
+ { "icon.pkd", GAME_ICONFILE, "ebc96af15bfaf75ba8210326b9260d2f"},
+ { "stripped.txt", GAME_STRFILE, "8edde5b9498dc9f31da1093028da467c"},
+ { "tbllist", GAME_TBLFILE, "1247e024e1f13ca54c1e354120c7519c"},
+};
+
+static GameFileDescription SIMON1CD32_GameFiles[] = {
+ { "gameamiga", GAME_BASEFILE, "bab7f19237cf7d7619b6c73631da1854"},
+ { "icon.pkd", GAME_ICONFILE, "565ef7a98dcc21ef526a2bb10b6f42ed"},
+ { "stripped.txt", GAME_STRFILE, "59be788020441e21861e284236fd08c1"},
+ { "tbllist", GAME_TBLFILE, "f9d5bf2ce09f82289c791c3ca26e1e4b"},
+};
+
+static GameFileDescription SIMON1CD32_2_GameFiles[] = {
+ { "gameamiga", GAME_BASEFILE, "ec5358680c117f29b128cbbb322111a4"},
+ { "icon.pkd", GAME_ICONFILE, "8ce5a46466a4f8f6d0f780b0ef00d5f5"},
+ { "stripped.txt", GAME_STRFILE, "59be788020441e21861e284236fd08c1"},
+ { "tbllist", GAME_TBLFILE, "f9d5bf2ce09f82289c791c3ca26e1e4b"},
+};
+
+static GameFileDescription SIMON1DOS_INF_GameFiles[] = {
+ { "gamepc", GAME_BASEFILE, "9f93d27432ce44a787eef10adb640870"},
+ { "icon.dat", GAME_ICONFILE, "22107c24dfb31b66ac503c28a6e20b19"},
+ { "stripped.txt", GAME_STRFILE, "2af9affc5981eec44b90d4c556145cb8"},
+ { "tbllist", GAME_TBLFILE, "d198a80de2c59e4a0cd24b98814849e8"},
+};
+
+static GameFileDescription SIMON1DOS_INF_RU_GameFiles[] = {
+ { "gamepc", GAME_BASEFILE, "605fb866e03ec1c41b10c6a518ddfa49"},
+ { "icon.dat", GAME_ICONFILE, "22107c24dfb31b66ac503c28a6e20b19"},
+ { "stripped.txt", GAME_STRFILE, "2af9affc5981eec44b90d4c556145cb8"},
+ { "tbllist", GAME_TBLFILE, "d198a80de2c59e4a0cd24b98814849e8"},
+};
+
+static GameFileDescription SIMON1DOS_GameFiles[] = {
+ { "gamepc", GAME_BASEFILE, "c392e494dcabed797b98cbcfc687b33a"},
+ { "icon.dat", GAME_ICONFILE, "22107c24dfb31b66ac503c28a6e20b19"},
+ { "stripped.txt", GAME_STRFILE, "c95a0a1ee973e19c2a1c5d12026c139f"},
+ { "tbllist", GAME_TBLFILE, "d198a80de2c59e4a0cd24b98814849e8"},
+};
+
+static GameFileDescription SIMON1DOS_RU_GameFiles[] = {
+ { "gamepc", GAME_BASEFILE, "605fb866e03ec1c41b10c6a518ddfa49"},
+ { "icon.dat", GAME_ICONFILE, "22107c24dfb31b66ac503c28a6e20b19"},
+ { "stripped.txt", GAME_STRFILE, "c95a0a1ee973e19c2a1c5d12026c139f"},
+ { "tbllist", GAME_TBLFILE, "d198a80de2c59e4a0cd24b98814849e8"},
+};
+
+static GameFileDescription SIMON1DOS_FR_GameFiles[] = {
+ { "gamepc", GAME_BASEFILE, "34759d0d4285a2f4b21b8e03b8fcefb3"},
+ { "icon.dat", GAME_ICONFILE, "22107c24dfb31b66ac503c28a6e20b19"},
+ { "stripped.txt", GAME_STRFILE, "aa01e7386057abc0c3e27dbaa9c4ba5b"},
+ { "tbllist", GAME_TBLFILE, "d198a80de2c59e4a0cd24b98814849e8"},
+};
+
+static GameFileDescription SIMON1DOS_DE_GameFiles[] = {
+ { "gamepc", GAME_BASEFILE, "063015e6ce7d90b570dbc21fe0c667b1"},
+ { "icon.dat", GAME_ICONFILE, "22107c24dfb31b66ac503c28a6e20b19"},
+ { "stripped.txt", GAME_STRFILE, "c95a0a1ee973e19c2a1c5d12026c139f"},
+ { "tbllist", GAME_TBLFILE, "d198a80de2c59e4a0cd24b98814849e8"},
+};
+
+static GameFileDescription SIMON1DOS_IT_GameFiles[] = {
+ { "gamepc", GAME_BASEFILE, "65c9b2dea57df84ef55d1eaf384ebd30"},
+ { "icon.dat", GAME_ICONFILE, "22107c24dfb31b66ac503c28a6e20b19"},
+ { "stripped.txt", GAME_STRFILE, "2af9affc5981eec44b90d4c556145cb8"},
+ { "tbllist", GAME_TBLFILE, "d198a80de2c59e4a0cd24b98814849e8"},
+};
+
+static GameFileDescription SIMON1DOS_ES_GameFiles[] = {
+ { "gamepc", GAME_BASEFILE, "5374fafdea2068134f33deab225feed3"},
+ { "icon.dat", GAME_ICONFILE, "22107c24dfb31b66ac503c28a6e20b19"},
+ { "stripped.txt", GAME_STRFILE, "2af9affc5981eec44b90d4c556145cb8"},
+ { "tbllist", GAME_TBLFILE, "d198a80de2c59e4a0cd24b98814849e8"},
+};
+
+static GameFileDescription SIMON1DEMO_GameFiles[] = {
+ { "gdemo", GAME_BASEFILE, "2be4a21bc76e2fdc071867c130651439"},
+ { "icon.dat", GAME_ICONFILE, "55af3b4d93972bc58bfee38a86b76c3f"},
+ { "stripped.txt", GAME_STRFILE, "33a2e329b97b2a349858d6a093159eb7"},
+ { "tbllist", GAME_TBLFILE, "1247e024e1f13ca54c1e354120c7519c"},
+};
+
+static GameFileDescription SIMON1TALKIE_GameFiles[] = {
+ { "gamepc", GAME_BASEFILE, "28261b99cd9da1242189b4f6f2841bd6"},
+ { "icon.dat", GAME_ICONFILE, "22107c24dfb31b66ac503c28a6e20b19"},
+ { "simon.gme", GAME_GMEFILE, "64958b3a38afdcb85da1eeed85169806"},
+ { "stripped.txt", GAME_STRFILE, "f3b27a3fbb45dcd323a48159496e45e8"},
+ { "tbllist", GAME_TBLFILE, "d198a80de2c59e4a0cd24b98814849e8"},
+};
+
+static GameFileDescription SIMON1TALKIE2_GameFiles[] = {
+ { "gamepc", GAME_BASEFILE, "c0b948b6821d2140f8b977144f21027a"},
+ { "icon.dat", GAME_ICONFILE, "22107c24dfb31b66ac503c28a6e20b19"},
+ { "simon.gme", GAME_GMEFILE, "64f73e94639b63af846ac4a8a94a23d8"},
+ { "stripped.txt", GAME_STRFILE, "f3b27a3fbb45dcd323a48159496e45e8"},
+ { "tbllist", GAME_TBLFILE, "d198a80de2c59e4a0cd24b98814849e8"},
+};
+
+static GameFileDescription SIMON1TALKIE_FR_GameFiles[] = {
+ { "gamepc", GAME_BASEFILE, "3cfb9d1ff4ec725af9924140126cf69f"},
+ { "icon.dat", GAME_ICONFILE, "22107c24dfb31b66ac503c28a6e20b19"},
+ { "simon.gme", GAME_GMEFILE, "638049fa5d41b81fb6fb11671721b871"},
+ { "stripped.txt", GAME_STRFILE, "ef51ac74c946881ae4d7ca66cc7a0d1e"},
+ { "tbllist", GAME_TBLFILE, "d198a80de2c59e4a0cd24b98814849e8"},
+};
+
+static GameFileDescription SIMON1TALKIE_DE_GameFiles[] = {
+ { "gamepc", GAME_BASEFILE, "48b1f3499e2e0d731047f4d481ff7817"},
+ { "icon.dat", GAME_ICONFILE, "22107c24dfb31b66ac503c28a6e20b19"},
+ { "simon.gme", GAME_GMEFILE, "7db9912acac4f1d965a64bdcfc370ba1"},
+ { "stripped.txt", GAME_STRFILE, "40d68bec54042ef930f084ad9a4342a1"},
+ { "tbllist", GAME_TBLFILE, "d198a80de2c59e4a0cd24b98814849e8"},
+};
+
+static GameFileDescription SIMON1TALKIE_HB_GameFiles[] = {
+ { "gamepc", GAME_BASEFILE, "bc66e9c0b296e1b155a246917133f71a"},
+ { "icon.dat", GAME_ICONFILE, "22107c24dfb31b66ac503c28a6e20b19"},
+ { "simon.gme", GAME_GMEFILE, "a34b2c8642f2e3676d7088b5c8b3e884"},
+ { "stripped.txt", GAME_STRFILE, "9d31bef42db1a8abe4e9f368014df1d5"},
+ { "tbllist", GAME_TBLFILE, "d198a80de2c59e4a0cd24b98814849e8"},
+};
+
+static GameFileDescription SIMON1TALKIE_IT_GameFiles[] = {
+ { "gamepc", GAME_BASEFILE, "8d3ca654e158c91b860c7eae31d65312"},
+ { "icon.dat", GAME_ICONFILE, "22107c24dfb31b66ac503c28a6e20b19"},
+ { "simon.gme", GAME_GMEFILE, "52e315e0e02feca86d15cc82e3306b6c"},
+ { "stripped.txt", GAME_STRFILE, "9d31bef42db1a8abe4e9f368014df1d5"},
+ { "tbllist", GAME_TBLFILE, "d198a80de2c59e4a0cd24b98814849e8"},
+};
+
+static GameFileDescription SIMON1TALKIE_IT2_GameFiles[] = {
+ { "gamepc", GAME_BASEFILE, "8d3ca654e158c91b860c7eae31d65312"},
+ { "icon.dat", GAME_ICONFILE, "22107c24dfb31b66ac503c28a6e20b19"},
+ { "simon.gme", GAME_GMEFILE, "104efd83c8f3edf545982e07d87f66ac"},
+ { "stripped.txt", GAME_STRFILE, "9d31bef42db1a8abe4e9f368014df1d5"},
+ { "tbllist", GAME_TBLFILE, "d198a80de2c59e4a0cd24b98814849e8"},
+};
+
+static GameFileDescription SIMON1TALKIE_ES_GameFiles[] = {
+ { "gamepc", GAME_BASEFILE, "439f801ba52c02c9d1844600d1ce0f5e"},
+ { "icon.dat", GAME_ICONFILE, "22107c24dfb31b66ac503c28a6e20b19"},
+ { "simon.gme", GAME_GMEFILE, "eff2774a73890b9eac533db90cd1afa1"},
+ { "stripped.txt", GAME_STRFILE, "9d31bef42db1a8abe4e9f368014df1d5"},
+ { "tbllist", GAME_TBLFILE, "d198a80de2c59e4a0cd24b98814849e8"},
+};
+
+static GameFileDescription SIMON1WIN_GameFiles[] = {
+ { "gamepc", GAME_BASEFILE, "c7c12fea7f6d0bfd22af5cdbc8166862"},
+ { "icon.dat", GAME_ICONFILE, "22107c24dfb31b66ac503c28a6e20b19"},
+ { "simon.gme", GAME_GMEFILE, "b1b18d0731b64c0738c5cc4a2ee792fc"},
+ { "stripped.txt", GAME_STRFILE, "a27e87a9ba21212d769804b3df47bfb2"},
+ { "tbllist", GAME_TBLFILE, "d198a80de2c59e4a0cd24b98814849e8"},
+};
+
+static GameFileDescription SIMON1WIN_RU_GameFiles[] = {
+ { "gamepc", GAME_BASEFILE, "4536a706412b36d628f12142bfa97af0"},
+ { "icon.dat", GAME_ICONFILE, "22107c24dfb31b66ac503c28a6e20b19"},
+ { "simon.gme", GAME_GMEFILE, "b1b18d0731b64c0738c5cc4a2ee792fc"},
+ { "stripped.txt", GAME_STRFILE, "a27e87a9ba21212d769804b3df47bfb2"},
+ { "tbllist", GAME_TBLFILE, "d198a80de2c59e4a0cd24b98814849e8"},
+};
+
+static GameFileDescription SIMON1WIN_DE_GameFiles[] = {
+ { "gamepc", GAME_BASEFILE, "48b1f3499e2e0d731047f4d481ff7817"},
+ { "icon.dat", GAME_ICONFILE, "22107c24dfb31b66ac503c28a6e20b19"},
+ { "simon.gme", GAME_GMEFILE, "acd9cc438525b142d93b15c77a6f551b"},
+ { "stripped.txt", GAME_STRFILE, "40d68bec54042ef930f084ad9a4342a1"},
+ { "tbllist", GAME_TBLFILE, "d198a80de2c59e4a0cd24b98814849e8"},
+};
+
+static GameFileDescription SIMON2DOS_GameFiles[] = {
+ { "game32", GAME_BASEFILE, "27c8e7feada80c75b70b9c2f6088d519"},
+ { "icon.dat", GAME_ICONFILE, "ee92d1f84893195a60449f2430d07285"},
+ { "simon2.gme", GAME_GMEFILE, "eefcc32b1f2c0482c1a59a963a146345"},
+ { "stripped.txt", GAME_STRFILE, "e229f84d46fa83f99b4a7115679f3fb6"},
+ { "tbllist", GAME_TBLFILE, "2082f8d02075e590300478853a91ffd9"},
+};
+
+static GameFileDescription SIMON2DOS_RU_GameFiles[] = {
+ { "game32", GAME_BASEFILE, "7edfc633dd50f8caa719c478443db70b"},
+ { "icon.dat", GAME_ICONFILE, "ee92d1f84893195a60449f2430d07285"},
+ { "simon2.gme", GAME_GMEFILE, "eefcc32b1f2c0482c1a59a963a146345"},
+ { "stripped.txt", GAME_STRFILE, "e229f84d46fa83f99b4a7115679f3fb6"},
+ { "tbllist", GAME_TBLFILE, "2082f8d02075e590300478853a91ffd9"},
+};
+
+static GameFileDescription SIMON2DOS2_GameFiles[] = {
+ { "game32", GAME_BASEFILE, "604d04315935e77624bd356ac926e068"},
+ { "icon.dat", GAME_ICONFILE, "72096a62d36e6034ea9fecc13b2dbdab"},
+ { "simon2.gme", GAME_GMEFILE, "aa6840420899a31874204f90bb214108"},
+ { "stripped.txt", GAME_STRFILE, "e229f84d46fa83f99b4a7115679f3fb6"},
+ { "tbllist", GAME_TBLFILE, "2082f8d02075e590300478853a91ffd9"},
+};
+
+static GameFileDescription SIMON2DOS2_RU_GameFiles[] = {
+ { "game32", GAME_BASEFILE, "eb8bde3685842a8fd38f60bc476ef8e9"},
+ { "icon.dat", GAME_ICONFILE, "72096a62d36e6034ea9fecc13b2dbdab"},
+ { "simon2.gme", GAME_GMEFILE, "aa6840420899a31874204f90bb214108"},
+ { "stripped.txt", GAME_STRFILE, "e229f84d46fa83f99b4a7115679f3fb6"},
+ { "tbllist", GAME_TBLFILE, "2082f8d02075e590300478853a91ffd9"},
+};
+
+static GameFileDescription SIMON2DOS_DE_GameFiles[] = {
+ { "game32", GAME_BASEFILE, "eb6e3e37fe52993f948d7e2d6b869828"},
+ { "icon.dat", GAME_ICONFILE, "72096a62d36e6034ea9fecc13b2dbdab"},
+ { "simon2.gme", GAME_GMEFILE, "5fa9d080b04c610f526bd685be1bf747"},
+ { "stripped.txt", GAME_STRFILE, "fd30df01cc248ecbaef302af855e0212"},
+ { "tbllist", GAME_TBLFILE, "2082f8d02075e590300478853a91ffd9"},
+};
+
+static GameFileDescription SIMON2DOS_IT_GameFiles[] = {
+ { "game32", GAME_BASEFILE, "3e11d400bea0638f360a724687005cd1"},
+ { "icon.dat", GAME_ICONFILE, "72096a62d36e6034ea9fecc13b2dbdab"},
+ { "simon2.gme", GAME_GMEFILE, "f306a397565d7f13bec7ecf14c723de7"},
+ { "stripped.txt", GAME_STRFILE, "bea6843fb9f3b2144fcb146d62db0b9a"},
+ { "tbllist", GAME_TBLFILE, "2082f8d02075e590300478853a91ffd9"},
+};
+
+static GameFileDescription SIMON2DEMO_GameFiles[] = {
+ { "gsptr30", GAME_BASEFILE, "3794c15887539b8578bacab694ccf08a"},
+ { "icon.dat", GAME_ICONFILE, "72096a62d36e6034ea9fecc13b2dbdab"},
+ { "simon2.gme", GAME_GMEFILE, "f8c9e6df1e55923a749e115ba74210c4"},
+ { "stripped.txt", GAME_STRFILE, "e229f84d46fa83f99b4a7115679f3fb6"},
+ { "tbllist", GAME_TBLFILE, "a0d5a494b5d3d209d1a1d76cc8d76601"},
+};
+
+static GameFileDescription SIMON2TALKIE_GameFiles[] = {
+ { "gsptr30", GAME_BASEFILE, "8c301fb9c4fcf119d2730ccd2a565eb3"},
+ { "icon.dat", GAME_ICONFILE, "72096a62d36e6034ea9fecc13b2dbdab"},
+ { "simon2.gme", GAME_GMEFILE, "9c535d403966750ae98bdaf698375a38"},
+ { "stripped.txt", GAME_STRFILE, "e229f84d46fa83f99b4a7115679f3fb6"},
+ { "tbllist", GAME_TBLFILE, "2082f8d02075e590300478853a91ffd9"},
+};
+
+static GameFileDescription SIMON2TALKIE2_GameFiles[] = {
+ { "gsptr30", GAME_BASEFILE, "608e277904d87dd28725fa08eacc2c0d"},
+ { "icon.dat", GAME_ICONFILE, "72096a62d36e6034ea9fecc13b2dbdab"},
+ { "simon2.gme", GAME_GMEFILE, "8d6dcc65577e285dbca03ff6d7d9323c"},
+ { "stripped.txt", GAME_STRFILE, "e229f84d46fa83f99b4a7115679f3fb6"},
+ { "tbllist", GAME_TBLFILE, "a0d5a494b5d3d209d1a1d76cc8d76601"},
+};
+
+static GameFileDescription SIMON2TALKIE_FR_GameFiles[] = {
+ { "gsptr30", GAME_BASEFILE, "43b3a04d2f0a0cbd1b024c814856561a"},
+ { "icon.dat", GAME_ICONFILE, "72096a62d36e6034ea9fecc13b2dbdab"},
+ { "simon2.gme", GAME_GMEFILE, "8af0e02c0c3344db64dffc12196eb59d"},
+ { "stripped.txt", GAME_STRFILE, "5ea27977b4d7dcfd50eb5074e162ebbf"},
+ { "tbllist", GAME_TBLFILE, "2082f8d02075e590300478853a91ffd9"},
+};
+
+static GameFileDescription SIMON2TALKIE_DE_GameFiles[] = {
+ { "gsptr30", GAME_BASEFILE, "0d05c3f4c06c9a4ceb3d2f5bc0b18e11"},
+ { "icon.dat", GAME_ICONFILE, "72096a62d36e6034ea9fecc13b2dbdab"},
+ { "simon2.gme", GAME_GMEFILE, "6c5fdfdd0eab9038767c2d22858406b2"},
+ { "stripped.txt", GAME_STRFILE, "6de6292c9ac11bfb2e70fdb0f773ba85"},
+ { "tbllist", GAME_TBLFILE, "2082f8d02075e590300478853a91ffd9"},
+};
+
+static GameFileDescription SIMON2TALKIE_DE2_GameFiles[] = {
+ { "gsptr30", GAME_BASEFILE, "a76ea940076b5d9316796dea225a9b69"},
+ { "icon.dat", GAME_ICONFILE, "72096a62d36e6034ea9fecc13b2dbdab"},
+ { "simon2.gme", GAME_GMEFILE, "ec9f0f24fd895e7ea72e3c8e448c0240"},
+ { "stripped.txt", GAME_STRFILE, "6de6292c9ac11bfb2e70fdb0f773ba85"},
+ { "tbllist", GAME_TBLFILE, "2082f8d02075e590300478853a91ffd9"},
+};
+
+static GameFileDescription SIMON2TALKIE_HB_GameFiles[] = {
+ { "gsptr30", GAME_BASEFILE, "952a2b1be23c3c609ba8d988a9a1627d"},
+ { "icon.dat", GAME_ICONFILE, "72096a62d36e6034ea9fecc13b2dbdab"},
+ { "simon2.gme", GAME_GMEFILE, "a2b249a82ea182af09789eb95fb6c5be"},
+ { "stripped.txt", GAME_STRFILE, "de9dbc24158660e153483fa0cf6c3172"},
+ { "tbllist", GAME_TBLFILE, "2082f8d02075e590300478853a91ffd9"},
+};
+
+static GameFileDescription SIMON2TALKIE_IT_GameFiles[] = {
+ { "gsptr30", GAME_BASEFILE, "3e11d400bea0638f360a724687005cd1"},
+ { "icon.dat", GAME_ICONFILE, "72096a62d36e6034ea9fecc13b2dbdab"},
+ { "simon2.gme", GAME_GMEFILE, "344aca58e5ad5e25c517d5eb1d85c435"},
+ { "stripped.txt", GAME_STRFILE, "bea6843fb9f3b2144fcb146d62db0b9a"},
+ { "tbllist", GAME_TBLFILE, "2082f8d02075e590300478853a91ffd9"},
+};
+
+static GameFileDescription SIMON2TALKIE_ES_GameFiles[] = {
+ { "gsptr30", GAME_BASEFILE, "268dc322aa73bcf27bb016b8e8ceb889"},
+ { "icon.dat", GAME_ICONFILE, "72096a62d36e6034ea9fecc13b2dbdab"},
+ { "simon2.gme", GAME_GMEFILE, "4f43bd06b6cc78dbd25a7475ca964eb1"},
+ { "stripped.txt", GAME_STRFILE, "d13753796bd81bf313a2449f34d8b112"},
+ { "tbllist", GAME_TBLFILE, "2082f8d02075e590300478853a91ffd9"},
+};
+
+static GameFileDescription SIMON2WIN_GameFiles[] = {
+ { "gsptr30", GAME_BASEFILE, "608e277904d87dd28725fa08eacc2c0d"},
+ { "icon.dat", GAME_ICONFILE, "72096a62d36e6034ea9fecc13b2dbdab"},
+ { "simon2.gme", GAME_GMEFILE, "e749c4c103d7e7d51b34620ed76c5a04"},
+ { "stripped.txt", GAME_STRFILE, "e229f84d46fa83f99b4a7115679f3fb6"},
+ { "tbllist", GAME_TBLFILE, "2082f8d02075e590300478853a91ffd9"},
+};
+
+static GameFileDescription SIMON2WIN_DE_GameFiles[] = {
+ { "gsptr30", GAME_BASEFILE, "a76ea940076b5d9316796dea225a9b69"},
+ { "icon.dat", GAME_ICONFILE, "72096a62d36e6034ea9fecc13b2dbdab"},
+ { "simon2.gme", GAME_GMEFILE, "9609a933c541fed2e00c6c3479d7c181"},
+ { "stripped.txt", GAME_STRFILE, "6de6292c9ac11bfb2e70fdb0f773ba85"},
+ { "tbllist", GAME_TBLFILE, "2082f8d02075e590300478853a91ffd9"},
+};
+
+static GameFileDescription SIMON2WIN_DE2_GameFiles[] = {
+ { "gsptr30", GAME_BASEFILE, "9e858b3bb189c134c3a5f34c3385a8d3"},
+ { "icon.dat", GAME_ICONFILE, "ee92d1f84893195a60449f2430d07285"},
+ { "simon2.gme", GAME_GMEFILE, "16d574da07e93bcae43cee353dab8c7e"},
+ { "stripped.txt", GAME_STRFILE, "6de6292c9ac11bfb2e70fdb0f773ba85"},
+ { "tbllist", GAME_TBLFILE, "2082f8d02075e590300478853a91ffd9"},
+};
+
+static GameFileDescription SIMON2WIN_PL_GameFiles[] = {
+ { "gsptr30", GAME_BASEFILE, "657fd873f5d0637097ee02315b447e6f"},
+ { "icon.dat", GAME_ICONFILE, "72096a62d36e6034ea9fecc13b2dbdab"},
+ { "simon2.gme", GAME_GMEFILE, "7b9afcf82a94722707e0d025c0192be8"},
+ { "stripped.txt", GAME_STRFILE, "e229f84d46fa83f99b4a7115679f3fb6"},
+ { "tbllist", GAME_TBLFILE, "2082f8d02075e590300478853a91ffd9"},
+};
+
+static GameFileDescription FEEBLEFILES_AMI_DE_GameFiles[] = {
+ { "game22", GAME_BASEFILE, "bcd76ac080003eee3649df18db25b60e"},
+ { "gfxindex.dat", GAME_GFXIDXFILE,"f550f7915c5ce3a68c9f870f507449c2"},
+ { "tbllist", GAME_TBLFILE, "0bbfee8e69739111eb36b0d138da8ddf"},
+};
+
+static GameFileDescription FEEBLEFILES_AMI_UK_GameFiles[] = {
+ { "game22", GAME_BASEFILE, "629762ea9ca9ee9ff85f4774d219f5c7"},
+ { "gfxindex.dat", GAME_GFXIDXFILE,"f550f7915c5ce3a68c9f870f507449c2"},
+ { "tbllist", GAME_TBLFILE, "0bbfee8e69739111eb36b0d138da8ddf"},
+};
+
+static GameFileDescription FEEBLEFILES_MAC_DE_GameFiles[] = {
+ { "game22", GAME_BASEFILE, "bcd76ac080003eee3649df18db25b60e"},
+ { "graphics.vga", GAME_GFXIDXFILE,"11a4853cb35956846976e9473ee0e41e"},
+ { "tbllist", GAME_TBLFILE, "0bbfee8e69739111eb36b0d138da8ddf"},
+};
+
+static GameFileDescription FEEBLEFILES_MAC_FR_GameFiles[] = {
+ { "game22", GAME_BASEFILE, "ba90b40a47726039671d9e91630dd7ed"},
+ { "graphics.vga", GAME_GFXIDXFILE,"11a4853cb35956846976e9473ee0e41e"},
+ { "tbllist", GAME_TBLFILE, "0bbfee8e69739111eb36b0d138da8ddf"},
+};
+
+static GameFileDescription FEEBLEFILES_MAC_ES_GameFiles[] = {
+ { "game22", GAME_BASEFILE, "71d7d2d5e479b053c5a9757f1702c9c3"},
+ { "graphics.vga", GAME_GFXIDXFILE,"11a4853cb35956846976e9473ee0e41e"},
+ { "tbllist", GAME_TBLFILE, "0bbfee8e69739111eb36b0d138da8ddf"},
+};
+
+static GameFileDescription FEEBLEFILES_MAC_UK_GameFiles[] = {
+ { "game22", GAME_BASEFILE, "629762ea9ca9ee9ff85f4774d219f5c7"},
+ { "graphics.vga", GAME_GFXIDXFILE,"11a4853cb35956846976e9473ee0e41e"},
+ { "tbllist", GAME_TBLFILE, "0bbfee8e69739111eb36b0d138da8ddf"},
+};
+
+static GameFileDescription FEEBLEFILES_2CD_GameFiles[] = {
+ { "game22", GAME_BASEFILE, "629762ea9ca9ee9ff85f4774d219f5c7"},
+ { "tbllist", GAME_TBLFILE, "0bbfee8e69739111eb36b0d138da8ddf"},
+};
+
+static GameFileDescription FEEBLEFILES_4CD_GameFiles[] = {
+ { "game22", GAME_BASEFILE, "a8746407a5b20a7da0da0a14c380af1c"},
+ { "tbllist", GAME_TBLFILE, "0bbfee8e69739111eb36b0d138da8ddf"},
+};
+
+static GameFileDescription FEEBLEFILES_DE_GameFiles[] = {
+ { "game22", GAME_BASEFILE, "bcd76ac080003eee3649df18db25b60e"},
+ { "tbllist", GAME_TBLFILE, "0bbfee8e69739111eb36b0d138da8ddf"},
+};
+
+static GameFileDescription FEEBLEFILES_FR_GameFiles[] = {
+ { "game22", GAME_BASEFILE, "ba90b40a47726039671d9e91630dd7ed"},
+ { "tbllist", GAME_TBLFILE, "0bbfee8e69739111eb36b0d138da8ddf"},
+};
+
+static GameFileDescription FEEBLEFILES_IT_GameFiles[] = {
+ { "game22", GAME_BASEFILE, "80576f2e1ed4c912b63921fe77af313e"},
+ { "tbllist", GAME_TBLFILE, "0bbfee8e69739111eb36b0d138da8ddf"},
+};
+
+static GameFileDescription FEEBLEFILES_ES_GameFiles[] = {
+ { "game22", GAME_BASEFILE, "71d7d2d5e479b053c5a9757f1702c9c3"},
+ { "tbllist", GAME_TBLFILE, "0bbfee8e69739111eb36b0d138da8ddf"},
+};
+
+static GameFileDescription WAXWORKS_GameFiles[] = {
+ { "gamepc", GAME_BASEFILE, "7751e9358e894e32ef40ef3b3bae0f2a"},
+ { "icon.dat", GAME_ICONFILE, "ef1b8ad3494cf103dc10a99fe152ef9a"},
+ { "roomslst", GAME_RMSLFILE, "e3758c46ab8f3c23a1ac012bd607108d"},
+ { "stripped.txt", GAME_STRFILE, "f259e3e07a1cde8d0404a767d815e12c"},
+ { "tbllist", GAME_TBLFILE, "95c44bfc380770a6b6dd0dfcc69e80a0"},
+ { "xtbllist", GAME_XTBLFILE, "6c7b3db345d46349a5226f695c03e20f"},
+};
+
+static GameFileDescription ELVIRA2_GameFiles[] = {
+ { "gamepc", GAME_BASEFILE, "3313254722031b22d833a2cf45a91fd7"},
+ { "icon.dat", GAME_ICONFILE, "83a7278bff55c82fbb3aef92981866c9"},
+ { "stripped.txt", GAME_STRFILE, "c2533277b7ff11f5495967d55355ea17"},
+ { "tbllist", GAME_TBLFILE, "8252660df0edbdbc3e6377e155bbd0c5"},
+};
+
+static GameFileDescription ELVIRA_GameFiles[] = {
+ { "gamepc", GAME_BASEFILE, "9076d507d60cc454df662316438ec843"},
+ { "icon.dat", GAME_ICONFILE, "fda48c9da7f3e72d0313e2f5f760fc45"},
+ { "tbllist", GAME_TBLFILE, "319f6b227c7822a551f57d24e70f8149"},
+};
+
+static GameFileDescription DIMP_GameFiles[] = {
+ { "Gdimp", GAME_BASEFILE, "0b1e89ae1dc2e012b7fa7a987b4ac42a"},
+};
+
+static GameFileDescription JUMBLE_GameFiles[] = {
+ { "Gjumble", GAME_BASEFILE, "d54cce46d339038d1a6b74ea213655bc"},
+};
+
+static GameFileDescription PUZZLE_GameFiles[] = {
+ { "Gpuzzle", GAME_BASEFILE, "3f80dac8e0d85401a1058a560fe49ab6"},
+};
+
+static GameFileDescription SWAMPY_GameFiles[] = {
+ { "Gswampy", GAME_BASEFILE, "3a6d4d7b2433e660f2483f9396cc87a2"},
+};
+
+static GameDescription gameDescriptions[] = {
+ // Elvira - English Floppy
+ {
+ "elvira",
+ GType_ELVIRA,
+ GID_ELVIRA,
+ "Floppy",
+ ARRAYSIZE(ELVIRA_GameFiles),
+ ELVIRA_GameFiles,
+ GF_OLD_BUNDLE,
+ Common::EN_ANY,
+ Common::kPlatformPC,
+ },
+
+ // Elvira 2 - English Floppy
+ {
+ "elvira2",
+ GType_ELVIRA2,
+ GID_ELVIRA2,
+ "Floppy",
+ ARRAYSIZE(ELVIRA2_GameFiles),
+ ELVIRA2_GameFiles,
+ GF_OLD_BUNDLE,
+ Common::EN_ANY,
+ Common::kPlatformPC,
+ },
+
+ // Waxworks - English Floppy
+ {
+ "waxworks",
+ GType_WW,
+ GID_WAXWORKS,
+ "Floppy",
+ ARRAYSIZE(WAXWORKS_GameFiles),
+ WAXWORKS_GameFiles,
+ GF_OLD_BUNDLE,
+ Common::EN_ANY,
+ Common::kPlatformPC,
+ },
+
+ // Simon the Sorcerer 1 - English Acorn CD Demo
+ {
+ "simon1",
+ GType_SIMON1,
+ GID_SIMON1ACORNDEMO,
+ "CD Demo",
+ ARRAYSIZE(SIMON1ACORNDEMO_GameFiles),
+ SIMON1ACORNDEMO_GameFiles,
+ GF_TALKIE,
+ Common::EN_ANY,
+ Common::kPlatformAcorn,
+ },
+
+ // Simon the Sorcerer 1 - English Acorn CD
+ {
+ "simon1",
+ GType_SIMON1,
+ GID_SIMON1ACORN,
+ "CD",
+ ARRAYSIZE(SIMON1ACORN_GameFiles),
+ SIMON1ACORN_GameFiles,
+ GF_TALKIE,
+ Common::EN_ANY,
+ Common::kPlatformAcorn,
+ },
+
+ // Simon the Sorcerer 1 - English AGA Floppy
+ {
+ "simon1",
+ GType_SIMON1,
+ GID_SIMON1AMIGA,
+ "AGA Floppy",
+ ARRAYSIZE(SIMON1AMIGA_GameFiles),
+ SIMON1AMIGA_GameFiles,
+ GF_CRUNCHED | GF_OLD_BUNDLE,
+ Common::EN_ANY,
+ Common::kPlatformAmiga,
+ },
+
+ // Simon the Sorcerer 1 - French AGA Floppy
+ {
+ "simon1",
+ GType_SIMON1,
+ GID_SIMON1AMIGA_FR,
+ "AGA Floppy",
+ ARRAYSIZE(SIMON1AMIGA_FR_GameFiles),
+ SIMON1AMIGA_FR_GameFiles,
+ GF_CRUNCHED | GF_OLD_BUNDLE,
+ Common::FR_FRA,
+ Common::kPlatformAmiga,
+ },
+
+ // Simon the Sorcerer 1 - German AGA Floppy
+ {
+ "simon1",
+ GType_SIMON1,
+ GID_SIMON1AMIGA_DE,
+ "AGA Floppy",
+ ARRAYSIZE(SIMON1AMIGA_DE_GameFiles),
+ SIMON1AMIGA_DE_GameFiles,
+ GF_CRUNCHED | GF_OLD_BUNDLE,
+ Common::DE_DEU,
+ Common::kPlatformAmiga,
+ },
+
+ // Simon the Sorcerer 1 - English Amiga ECS Demo
+ {
+ "simon1",
+ GType_SIMON1,
+ GID_SIMON1AMIGADEMO,
+ "ECS Demo",
+ ARRAYSIZE(SIMON1AMIGADEMO_GameFiles),
+ SIMON1AMIGADEMO_GameFiles,
+ GF_CRUNCHED | GF_OLD_BUNDLE,
+ Common::EN_ANY,
+ Common::kPlatformAmiga,
+ },
+
+ // Simon the Sorcerer 1 - English Amiga CD32
+ {
+ "simon1",
+ GType_SIMON1,
+ GID_SIMON1CD32,
+ "CD32",
+ ARRAYSIZE(SIMON1CD32_GameFiles),
+ SIMON1CD32_GameFiles,
+ GF_TALKIE | GF_OLD_BUNDLE,
+ Common::EN_ANY,
+ Common::kPlatformAmiga,
+ },
+
+ // Simon the Sorcerer 1 - English Amiga CD32 alternative?
+ {
+ "simon1",
+ GType_SIMON1,
+ GID_SIMON1CD32_2,
+ "CD32",
+ ARRAYSIZE(SIMON1CD32_2_GameFiles),
+ SIMON1CD32_2_GameFiles,
+ GF_TALKIE | GF_OLD_BUNDLE,
+ Common::EN_ANY,
+ Common::kPlatformAmiga,
+ },
+
+ // Simon the Sorcerer 1 - English DOS Floppy Demo
+ {
+ "simon1",
+ GType_SIMON1,
+ GID_SIMON1DEMO,
+ "Floppy Demo",
+ ARRAYSIZE(SIMON1DEMO_GameFiles),
+ SIMON1DEMO_GameFiles,
+ GF_OLD_BUNDLE,
+ Common::EN_ANY,
+ Common::kPlatformPC,
+ },
+
+ // Simon the Sorcerer 1 - English DOS Floppy
+ {
+ "simon1",
+ GType_SIMON1,
+ GID_SIMON1DOS,
+ "Floppy",
+ ARRAYSIZE(SIMON1DOS_GameFiles),
+ SIMON1DOS_GameFiles,
+ GF_OLD_BUNDLE,
+ Common::EN_ANY,
+ Common::kPlatformPC,
+ },
+
+ // Simon the Sorcerer 1 - English DOS Floppy with Russian patch
+ {
+ "simon1",
+ GType_SIMON1,
+ GID_SIMON1DOS_RU,
+ "Floppy",
+ ARRAYSIZE(SIMON1DOS_RU_GameFiles),
+ SIMON1DOS_RU_GameFiles,
+ GF_OLD_BUNDLE,
+ Common::RU_RUS,
+ Common::kPlatformPC,
+ },
+
+ // Simon the Sorcerer 1 - English DOS Floppy (Infocom)
+ {
+ "simon1",
+ GType_SIMON1,
+ GID_SIMON1DOS_INF,
+ "Floppy",
+ ARRAYSIZE(SIMON1DOS_INF_GameFiles),
+ SIMON1DOS_INF_GameFiles,
+ GF_OLD_BUNDLE,
+ Common::EN_ANY,
+ Common::kPlatformPC,
+ },
+
+ // Simon the Sorcerer 1 - English DOS Floppy (Infocom) with Russian patch
+ {
+ "simon1",
+ GType_SIMON1,
+ GID_SIMON1DOS_INF_RU,
+ "Floppy",
+ ARRAYSIZE(SIMON1DOS_INF_RU_GameFiles),
+ SIMON1DOS_INF_RU_GameFiles,
+ GF_OLD_BUNDLE,
+ Common::RU_RUS,
+ Common::kPlatformPC,
+ },
+
+ // Simon the Sorcerer 1 - French DOS Floppy
+ {
+ "simon1",
+ GType_SIMON1,
+ GID_SIMON1DOS_FR,
+ "Floppy",
+ ARRAYSIZE(SIMON1DOS_FR_GameFiles),
+ SIMON1DOS_FR_GameFiles,
+ GF_OLD_BUNDLE,
+ Common::FR_FRA,
+ Common::kPlatformPC,
+ },
+
+ // Simon the Sorcerer 1 - German DOS Floppy
+ {
+ "simon1",
+ GType_SIMON1,
+ GID_SIMON1DOS_DE,
+ "Floppy",
+ ARRAYSIZE(SIMON1DOS_DE_GameFiles),
+ SIMON1DOS_DE_GameFiles,
+ GF_OLD_BUNDLE,
+ Common::DE_DEU,
+ Common::kPlatformPC,
+ },
+
+ // Simon the Sorcerer 1 - Italian DOS Floppy
+ {
+ "simon1",
+ GType_SIMON1,
+ GID_SIMON1DOS_IT,
+ "Floppy",
+ ARRAYSIZE(SIMON1DOS_IT_GameFiles),
+ SIMON1DOS_IT_GameFiles,
+ GF_OLD_BUNDLE,
+ Common::IT_ITA,
+ Common::kPlatformPC,
+ },
+
+ // Simon the Sorcerer 1 - Spanish DOS Floppy
+ {
+ "simon1",
+ GType_SIMON1,
+ GID_SIMON1DOS_ES,
+ "Floppy",
+ ARRAYSIZE(SIMON1DOS_ES_GameFiles),
+ SIMON1DOS_ES_GameFiles,
+ GF_OLD_BUNDLE,
+ Common::ES_ESP,
+ Common::kPlatformPC,
+ },
+
+ // Simon the Sorcerer 1 - English DOS CD
+ {
+ "simon1",
+ GType_SIMON1,
+ GID_SIMON1TALKIE,
+ "CD",
+ ARRAYSIZE(SIMON1TALKIE_GameFiles),
+ SIMON1TALKIE_GameFiles,
+ GF_TALKIE,
+ Common::EN_ANY,
+ Common::kPlatformPC,
+ },
+
+ // Simon the Sorcerer 1 - English DOS CD alternate?
+ {
+ "simon1",
+ GType_SIMON1,
+ GID_SIMON1TALKIE2,
+ "CD",
+ ARRAYSIZE(SIMON1TALKIE2_GameFiles),
+ SIMON1TALKIE2_GameFiles,
+ GF_TALKIE,
+ Common::EN_ANY,
+ Common::kPlatformPC,
+ },
+
+ // Simon the Sorcerer 1 - French DOS CD
+ {
+ "simon1",
+ GType_SIMON1,
+ GID_SIMON1TALKIE_FR,
+ "CD",
+ ARRAYSIZE(SIMON1TALKIE_FR_GameFiles),
+ SIMON1TALKIE_FR_GameFiles,
+ GF_TALKIE,
+ Common::FR_FRA,
+ Common::kPlatformPC,
+ },
+
+ // Simon the Sorcerer 1 - German DOS CD
+ {
+ "simon1",
+ GType_SIMON1,
+ GID_SIMON1TALKIE_DE,
+ "CD",
+ ARRAYSIZE(SIMON1TALKIE_DE_GameFiles),
+ SIMON1TALKIE_DE_GameFiles,
+ GF_TALKIE,
+ Common::DE_DEU,
+ Common::kPlatformPC,
+ },
+
+ // Simon the Sorcerer 1 - Hebrew DOS CD
+ {
+ "simon1",
+ GType_SIMON1,
+ GID_SIMON1TALKIE_HB,
+ "CD",
+ ARRAYSIZE(SIMON1TALKIE_HB_GameFiles),
+ SIMON1TALKIE_HB_GameFiles,
+ GF_TALKIE,
+ Common::HB_ISR,
+ Common::kPlatformPC,
+ },
+
+ // Simon the Sorcerer 1 - Italian DOS CD
+ {
+ "simon1",
+ GType_SIMON1,
+ GID_SIMON1TALKIE_IT,
+ "CD",
+ ARRAYSIZE(SIMON1TALKIE_IT_GameFiles),
+ SIMON1TALKIE_IT_GameFiles,
+ GF_TALKIE,
+ Common::IT_ITA,
+ Common::kPlatformPC,
+ },
+
+ // Simon the Sorcerer 1 - Italian DOS CD alternate
+ {
+ "simon1",
+ GType_SIMON1,
+ GID_SIMON1TALKIE_IT2,
+ "CD",
+ ARRAYSIZE(SIMON1TALKIE_IT2_GameFiles),
+ SIMON1TALKIE_IT2_GameFiles,
+ GF_TALKIE,
+ Common::IT_ITA,
+ // FIXME: DOS version which uses WAV format
+ Common::kPlatformWindows,
+ },
+
+ // Simon the Sorcerer 1 - Spanish DOS CD
+ {
+ "simon1",
+ GType_SIMON1,
+ GID_SIMON1TALKIE_ES,
+ "CD",
+ ARRAYSIZE(SIMON1TALKIE_ES_GameFiles),
+ SIMON1TALKIE_ES_GameFiles,
+ GF_TALKIE,
+ Common::ES_ESP,
+ Common::kPlatformPC,
+ },
+
+ // Simon the Sorcerer 1 - English Windows CD
+ {
+ "simon1",
+ GType_SIMON1,
+ GID_SIMON1WIN,
+ "CD",
+ ARRAYSIZE(SIMON1WIN_GameFiles),
+ SIMON1WIN_GameFiles,
+ GF_TALKIE,
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ },
+
+ // Simon the Sorcerer 1 - English Windows CD with Russian patch
+ {
+ "simon1",
+ GType_SIMON1,
+ GID_SIMON1WIN_RU,
+ "CD",
+ ARRAYSIZE(SIMON1WIN_RU_GameFiles),
+ SIMON1WIN_RU_GameFiles,
+ GF_TALKIE,
+ Common::RU_RUS,
+ Common::kPlatformWindows,
+ },
+
+ // Simon the Sorcerer 1 - German Windows CD
+ {
+ "simon1",
+ GType_SIMON1,
+ GID_SIMON1WIN_DE,
+ "CD",
+ ARRAYSIZE(SIMON1WIN_DE_GameFiles),
+ SIMON1WIN_DE_GameFiles,
+ GF_TALKIE,
+ Common::DE_DEU,
+ Common::kPlatformWindows,
+ },
+
+ // Simon the Sorcerer 2 - English DOS Floppy
+ {
+ "simon2",
+ GType_SIMON2,
+ GID_SIMON2DOS,
+ "Floppy",
+ ARRAYSIZE(SIMON2DOS_GameFiles),
+ SIMON2DOS_GameFiles,
+ 0,
+ Common::EN_ANY,
+ Common::kPlatformPC,
+ },
+
+ // Simon the Sorcerer 2 - English DOS Floppy with Russian patch
+ {
+ "simon2",
+ GType_SIMON2,
+ GID_SIMON2DOS_RU,
+ "Floppy",
+ ARRAYSIZE(SIMON2DOS_RU_GameFiles),
+ SIMON2DOS_RU_GameFiles,
+ 0,
+ Common::RU_RUS,
+ Common::kPlatformPC,
+ },
+
+ // Simon the Sorcerer 2 - English DOS Floppy alternate?
+ {
+ "simon2",
+ GType_SIMON2,
+ GID_SIMON2DOS2,
+ "Floppy",
+ ARRAYSIZE(SIMON2DOS2_GameFiles),
+ SIMON2DOS2_GameFiles,
+ 0,
+ Common::EN_ANY,
+ Common::kPlatformPC,
+ },
+
+ // Simon the Sorcerer 2 - English DOS Floppy alternate? with Russian patch
+ {
+ "simon2",
+ GType_SIMON2,
+ GID_SIMON2DOS2_RU,
+ "Floppy",
+ ARRAYSIZE(SIMON2DOS2_RU_GameFiles),
+ SIMON2DOS2_RU_GameFiles,
+ 0,
+ Common::RU_RUS,
+ Common::kPlatformPC,
+ },
+
+ // Simon the Sorcerer 2 - German DOS Floppy
+ {
+ "simon2",
+ GType_SIMON2,
+ GID_SIMON2DOS_DE,
+ "Floppy",
+ ARRAYSIZE(SIMON2DOS_DE_GameFiles),
+ SIMON2DOS_DE_GameFiles,
+ 0,
+ Common::DE_DEU,
+ Common::kPlatformPC,
+ },
+
+ // Simon the Sorcerer 2 - Italian DOS Floppy
+ {
+ "simon2",
+ GType_SIMON2,
+ GID_SIMON2DOS_IT,
+ "Floppy",
+ ARRAYSIZE(SIMON2DOS_IT_GameFiles),
+ SIMON2DOS_IT_GameFiles,
+ 0,
+ Common::IT_ITA,
+ Common::kPlatformPC,
+ },
+
+ // Simon the Sorcerer 2 - English DOS CD Demo
+ {
+ "simon2",
+ GType_SIMON2,
+ GID_SIMON2DEMO,
+ "CD Demo",
+ ARRAYSIZE(SIMON2DEMO_GameFiles),
+ SIMON2DEMO_GameFiles,
+ GF_TALKIE,
+ Common::EN_ANY,
+ Common::kPlatformPC,
+ },
+
+ // Simon the Sorcerer 2 - English DOS CD
+ {
+ "simon2",
+ GType_SIMON2,
+ GID_SIMON2TALKIE,
+ "CD",
+ ARRAYSIZE(SIMON2TALKIE_GameFiles),
+ SIMON2TALKIE_GameFiles,
+ GF_TALKIE,
+ Common::EN_ANY,
+ Common::kPlatformPC,
+ },
+
+
+ // Simon the Sorcerer 2 - English DOS CD alternate?
+ {
+ "simon2",
+ GType_SIMON2,
+ GID_SIMON2TALKIE2,
+ "CD",
+ ARRAYSIZE(SIMON2TALKIE2_GameFiles),
+ SIMON2TALKIE2_GameFiles,
+ GF_TALKIE,
+ Common::EN_ANY,
+ Common::kPlatformPC,
+ },
+
+ // Simon the Sorcerer 2 - French DOS CD
+ {
+ "simon2",
+ GType_SIMON2,
+ GID_SIMON2TALKIE_FR,
+ "CD",
+ ARRAYSIZE(SIMON2TALKIE_FR_GameFiles),
+ SIMON2TALKIE_FR_GameFiles,
+ GF_TALKIE,
+ Common::FR_FRA,
+ Common::kPlatformPC,
+ },
+
+ // Simon the Sorcerer 2 - German DOS CD
+ {
+ "simon2",
+ GType_SIMON2,
+ GID_SIMON2TALKIE_DE,
+ "CD",
+ ARRAYSIZE(SIMON2TALKIE_DE_GameFiles),
+ SIMON2TALKIE_DE_GameFiles,
+ GF_TALKIE,
+ Common::DE_DEU,
+ Common::kPlatformPC,
+ },
+
+ // Simon the Sorcerer 2 - German DOS CD alternate?
+ {
+ "simon2",
+ GType_SIMON2,
+ GID_SIMON2TALKIE_DE2,
+ "CD",
+ ARRAYSIZE(SIMON2TALKIE_DE2_GameFiles),
+ SIMON2TALKIE_DE2_GameFiles,
+ GF_TALKIE,
+ Common::DE_DEU,
+ Common::kPlatformPC,
+ },
+
+ // Simon the Sorcerer 2 - Hebrew DOS CD
+ {
+ "simon2",
+ GType_SIMON2,
+ GID_SIMON2TALKIE_HB,
+ "CD",
+ ARRAYSIZE(SIMON2TALKIE_HB_GameFiles),
+ SIMON2TALKIE_HB_GameFiles,
+ GF_TALKIE,
+ Common::HB_ISR,
+ Common::kPlatformPC,
+ },
+
+ // Simon the Sorcerer 2 - Italian DOS CD
+ {
+ "simon2",
+ GType_SIMON2,
+ GID_SIMON2TALKIE_IT,
+ "CD",
+ ARRAYSIZE(SIMON2TALKIE_IT_GameFiles),
+ SIMON2TALKIE_IT_GameFiles,
+ GF_TALKIE,
+ Common::IT_ITA,
+ // FIXME: DOS version which uses WAV format
+ Common::kPlatformWindows,
+ },
+
+ // Simon the Sorcerer 2 - Spanish DOS CD
+ {
+ "simon2",
+ GType_SIMON2,
+ GID_SIMON2TALKIE_ES,
+ "CD",
+ ARRAYSIZE(SIMON2TALKIE_ES_GameFiles),
+ SIMON2TALKIE_ES_GameFiles,
+ GF_TALKIE,
+ Common::ES_ESP,
+ Common::kPlatformPC,
+ },
+
+ // Simon the Sorcerer 2 - English Windows CD
+ {
+ "simon2",
+ GType_SIMON2,
+ GID_SIMON2WIN,
+ "CD",
+ ARRAYSIZE(SIMON2WIN_GameFiles),
+ SIMON2WIN_GameFiles,
+ GF_TALKIE,
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ },
+
+ // Simon the Sorcerer 2 - German Windows CD
+ {
+ "simon2",
+ GType_SIMON2,
+ GID_SIMON2WIN_DE,
+ "CD",
+ ARRAYSIZE(SIMON2WIN_DE_GameFiles),
+ SIMON2WIN_DE_GameFiles,
+ GF_TALKIE,
+ Common::DE_DEU,
+ Common::kPlatformWindows,
+ },
+
+ // Simon the Sorcerer 2 - German Windows CD 1.1
+ {
+ "simon2",
+ GType_SIMON2,
+ GID_SIMON2WIN_DE2,
+ "CD",
+ ARRAYSIZE(SIMON2WIN_DE2_GameFiles),
+ SIMON2WIN_DE2_GameFiles,
+ GF_TALKIE,
+ Common::DE_DEU,
+ Common::kPlatformWindows,
+ },
+
+ // Simon the Sorcerer 2 - Polish Windows CD
+ {
+ "simon2",
+ GType_SIMON2,
+ GID_SIMON2WIN_PL,
+ "CD",
+ ARRAYSIZE(SIMON2WIN_PL_GameFiles),
+ SIMON2WIN_PL_GameFiles,
+ GF_TALKIE,
+ Common::PL_POL,
+ Common::kPlatformWindows,
+ },
+
+ // The Feeble Files - English Amiga CD
+ {
+ "feeble",
+ GType_FF,
+ GID_FEEBLEFILES_AMI_UK,
+ "CD",
+ ARRAYSIZE(FEEBLEFILES_AMI_UK_GameFiles),
+ FEEBLEFILES_AMI_UK_GameFiles,
+ GF_OLD_BUNDLE | GF_ZLIBCOMP | GF_TALKIE,
+ Common::EN_ANY,
+ Common::kPlatformAmiga,
+ },
+
+ // The Feeble Files - German Amiga CD
+ {
+ "feeble",
+ GType_FF,
+ GID_FEEBLEFILES_AMI_DE,
+ "CD",
+ ARRAYSIZE(FEEBLEFILES_AMI_DE_GameFiles),
+ FEEBLEFILES_AMI_DE_GameFiles,
+ GF_OLD_BUNDLE | GF_ZLIBCOMP | GF_TALKIE,
+ Common::DE_DEU,
+ Common::kPlatformAmiga,
+ },
+
+ // The Feeble Files - English Macintosh CD
+ {
+ "feeble",
+ GType_FF,
+ GID_FEEBLEFILES_MAC_UK,
+ "CD",
+ ARRAYSIZE(FEEBLEFILES_MAC_UK_GameFiles),
+ FEEBLEFILES_MAC_UK_GameFiles,
+ GF_OLD_BUNDLE | GF_ZLIBCOMP | GF_TALKIE,
+ Common::EN_ANY,
+ Common::kPlatformMacintosh,
+ },
+
+ // The Feeble Files - French Macintosh CD
+ {
+ "feeble",
+ GType_FF,
+ GID_FEEBLEFILES_MAC_FR,
+ "CD",
+ ARRAYSIZE(FEEBLEFILES_MAC_FR_GameFiles),
+ FEEBLEFILES_MAC_FR_GameFiles,
+ GF_OLD_BUNDLE | GF_ZLIBCOMP | GF_TALKIE,
+ Common::FR_FRA,
+ Common::kPlatformMacintosh,
+ },
+
+ // The Feeble Files - German Macintosh CD
+ {
+ "feeble",
+ GType_FF,
+ GID_FEEBLEFILES_MAC_DE,
+ "CD",
+ ARRAYSIZE(FEEBLEFILES_MAC_DE_GameFiles),
+ FEEBLEFILES_MAC_DE_GameFiles,
+ GF_OLD_BUNDLE | GF_ZLIBCOMP | GF_TALKIE,
+ Common::DE_DEU,
+ Common::kPlatformMacintosh,
+ },
+
+ // The Feeble Files - Spanish Macintosh CD
+ {
+ "feeble",
+ GType_FF,
+ GID_FEEBLEFILES_MAC_ES,
+ "CD",
+ ARRAYSIZE(FEEBLEFILES_MAC_ES_GameFiles),
+ FEEBLEFILES_MAC_ES_GameFiles,
+ GF_OLD_BUNDLE | GF_ZLIBCOMP | GF_TALKIE,
+ Common::ES_ESP,
+ Common::kPlatformMacintosh,
+ },
+
+ // The Feeble Files - English Windows 2CD
+ {
+ "feeble",
+ GType_FF,
+ GID_FEEBLEFILES_2CD,
+ "2CD",
+ ARRAYSIZE(FEEBLEFILES_2CD_GameFiles),
+ FEEBLEFILES_2CD_GameFiles,
+ GF_OLD_BUNDLE | GF_TALKIE,
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ },
+
+ // The Feeble Files - English Windows 4CD
+ {
+ "feeble",
+ GType_FF,
+ GID_FEEBLEFILES_4CD,
+ "4CD",
+ ARRAYSIZE(FEEBLEFILES_4CD_GameFiles),
+ FEEBLEFILES_4CD_GameFiles,
+ GF_OLD_BUNDLE | GF_TALKIE,
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ },
+
+ // The Feeble Files - French Windows 4CD
+ {
+ "feeble",
+ GType_FF,
+ GID_FEEBLEFILES_FR,
+ "4CD",
+ ARRAYSIZE(FEEBLEFILES_FR_GameFiles),
+ FEEBLEFILES_FR_GameFiles,
+ GF_OLD_BUNDLE | GF_TALKIE,
+ Common::FR_FRA,
+ Common::kPlatformWindows,
+ },
+
+ // The Feeble Files - German Windows 4CD
+ {
+ "feeble",
+ GType_FF,
+ GID_FEEBLEFILES_DE,
+ "4CD",
+ ARRAYSIZE(FEEBLEFILES_DE_GameFiles),
+ FEEBLEFILES_DE_GameFiles,
+ GF_OLD_BUNDLE | GF_TALKIE,
+ Common::DE_DEU,
+ Common::kPlatformWindows,
+ },
+
+ // The Feeble Files - Italian Windows 4CD
+ {
+ "feeble",
+ GType_FF,
+ GID_FEEBLEFILES_IT,
+ "4CD",
+ ARRAYSIZE(FEEBLEFILES_IT_GameFiles),
+ FEEBLEFILES_IT_GameFiles,
+ GF_OLD_BUNDLE | GF_TALKIE,
+ Common::IT_ITA,
+ Common::kPlatformWindows,
+ },
+
+ // The Feeble Files - Spanish Windows 4CD
+ {
+ "feeble",
+ GType_FF,
+ GID_FEEBLEFILES_ES,
+ "4CD",
+ ARRAYSIZE(FEEBLEFILES_ES_GameFiles),
+ FEEBLEFILES_ES_GameFiles,
+ GF_OLD_BUNDLE | GF_TALKIE,
+ Common::ES_ESP,
+ Common::kPlatformWindows,
+ },
+
+ // Simon the Sorcerer's Puzzle Pack - Demon in my Pocket
+ {
+ "dimp",
+ GType_PP,
+ GID_DIMP,
+ "CD",
+ ARRAYSIZE(DIMP_GameFiles),
+ DIMP_GameFiles,
+ GF_OLD_BUNDLE | GF_TALKIE,
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ },
+
+ // Simon the Sorcerer's Puzzle Pack - Jumble
+ {
+ "jumble",
+ GType_PP,
+ GID_JUMBLE,
+ "CD",
+ ARRAYSIZE(JUMBLE_GameFiles),
+ JUMBLE_GameFiles,
+ GF_OLD_BUNDLE | GF_TALKIE,
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ },
+
+ // Simon the Sorcerer's Puzzle Pack - NoPatience
+ {
+ "puzzle",
+ GType_PP,
+ GID_PUZZLE,
+ "CD",
+ ARRAYSIZE(PUZZLE_GameFiles),
+ PUZZLE_GameFiles,
+ GF_OLD_BUNDLE | GF_TALKIE,
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ },
+
+ // Simon the Sorcerer's Puzzle Pack - Swampy Adventures
+ {
+ "swampy",
+ GType_PP,
+ GID_SWAMPY,
+ "CD",
+ ARRAYSIZE(SWAMPY_GameFiles),
+ SWAMPY_GameFiles,
+ GF_OLD_BUNDLE | GF_TALKIE,
+ Common::EN_ANY,
+ Common::kPlatformWindows,
+ },
+
+};
+
+DetectedGame toDetectedGame(const GameDescription &g) {
+ const char *title;
+
+ const PlainGameDescriptor *sg = simonGames;
+ while (sg->gameid) {
+ if (!scumm_stricmp(g.name, sg->gameid))
+ title = sg->description;
+ sg++;
+ }
+
+ DetectedGame dg(g.name, title, g.language, g.platform);
+ dg.updateDesc(g.extra);
+ return dg;
+}
+
+static int detectGame(const FSList *fslist, Common::Language language, Common::Platform platform, int*& returnMatches) {
+ int gamesCount = ARRAYSIZE(gameDescriptions);
+ int filesCount;
+
+ typedef Common::HashMap<Common::String, bool, Common::CaseSensitiveString_Hash, Common::CaseSensitiveString_EqualTo> StringSet;
+ StringSet filesList;
+
+ typedef Common::StringMap StringMap;
+ StringMap filesMD5;
+
+ Common::String tstr, tstr2;
+
+ int i, j;
+ char md5str[32+1];
+ uint8 md5sum[16];
+
+ int matched[ARRAYSIZE(gameDescriptions)];
+ int matchedCount = 0;
+ bool fileMissing;
+ GameFileDescription *fileDesc;
+
+ // First we compose list of files which we need MD5s for
+ for (i = 0; i < gamesCount; i++) {
+ for (j = 0; j < gameDescriptions[i].filesCount; j++) {
+ tstr = Common::String(gameDescriptions[i].filesDescriptions[j].fileName);
+ tstr.toLowercase();
+ tstr2 = tstr + ".";
+ filesList[tstr] = true;
+ filesList[tstr2] = true;
+ }
+ }
+
+ if (fslist != NULL) {
+ for (FSList::const_iterator file = fslist->begin(); file != fslist->end(); ++file) {
+ if (file->isDirectory()) continue;
+ tstr = file->name();
+ tstr.toLowercase();
+ tstr2 = tstr + ".";
+
+ if (!filesList.contains(tstr) && !filesList.contains(tstr2)) continue;
+
+ if (!Common::md5_file(*file, md5sum, FILE_MD5_BYTES)) continue;
+ for (j = 0; j < 16; j++) {
+ sprintf(md5str + j*2, "%02x", (int)md5sum[j]);
+ }
+ filesMD5[tstr] = Common::String(md5str);
+ filesMD5[tstr2] = Common::String(md5str);
+ }
+ } else {
+ Common::File testFile;
+
+ for (StringSet::const_iterator file = filesList.begin(); file != filesList.end(); ++file) {
+ tstr = file->_key;
+ tstr.toLowercase();
+
+ if (!filesMD5.contains(tstr)) {
+ if (testFile.open(file->_key)) {
+ testFile.close();
+
+ if (Common::md5_file(file->_key.c_str(), md5sum, FILE_MD5_BYTES)) {
+ for (j = 0; j < 16; j++) {
+ sprintf(md5str + j*2, "%02x", (int)md5sum[j]);
+ }
+ filesMD5[tstr] = Common::String(md5str);
+ }
+ }
+ }
+ }
+ }
+
+ for (i = 0; i < gamesCount; i++) {
+ filesCount = gameDescriptions[i].filesCount;
+ fileMissing = false;
+
+ // Try to open all files for this game
+ for (j = 0; j < filesCount; j++) {
+ fileDesc = &gameDescriptions[i].filesDescriptions[j];
+ tstr = fileDesc->fileName;
+ tstr.toLowercase();
+ tstr2 = tstr + ".";
+
+ if (!filesMD5.contains(tstr) && !filesMD5.contains(tstr2)) {
+ fileMissing = true;
+ break;
+ }
+ if (strcmp(fileDesc->md5, filesMD5[tstr].c_str()) && strcmp(fileDesc->md5, filesMD5[tstr2].c_str())) {
+ fileMissing = true;
+ break;
+ }
+ }
+ if (!fileMissing) {
+ debug(2, "Found game: %s", toDetectedGame(gameDescriptions[i]).description.c_str());
+ matched[matchedCount++] = i;
+ }
+ }
+
+ if (!filesMD5.empty() && (matchedCount == 0)) {
+ printf("MD5s of your game version are unknown. Please, report following data to\n");
+ printf("ScummVM team along with your game name and version:\n");
+
+ for (StringMap::const_iterator file = filesMD5.begin(); file != filesMD5.end(); ++file)
+ printf("%s: %s\n", file->_key.c_str(), file->_value.c_str());
+ }
+
+ // We have some resource sets which are superpositions of other
+ // Now remove lesser set if bigger matches too
+
+ if (matchedCount > 1) {
+ // Search max number
+ int maxcount = 0;
+ for (i = 0; i < matchedCount; i++) {
+ maxcount = MAX(gameDescriptions[matched[i]].filesCount, maxcount);
+ }
+
+ // Now purge targets with number of files lesser than max
+ for (i = 0; i < matchedCount; i++) {
+ if ((gameDescriptions[matched[i]].language != language && language != Common::UNK_LANG) ||
+ (gameDescriptions[matched[i]].platform != platform && platform != Common::kPlatformUnknown)) {
+ debug(2, "Purged %s", toDetectedGame(gameDescriptions[matched[i]]).description.c_str());
+ matched[i] = -1;
+ continue;
+ }
+
+ if (gameDescriptions[matched[i]].filesCount < maxcount) {
+ debug(2, "Purged: %s", toDetectedGame(gameDescriptions[matched[i]]).description.c_str());
+ matched[i] = -1;
+ }
+ }
+ }
+
+
+ returnMatches = (int *)malloc(matchedCount * sizeof(int));
+ j = 0;
+ for (i = 0; i < matchedCount; i++)
+ if (matched[i] != -1)
+ returnMatches[j++] = matched[i];
+ return j;
+}
+
+bool SimonEngine::initGame() {
+ uint16 gameCount = ARRAYSIZE(gameDescriptions);
+ int gameNumber = -1;
+
+ DetectedGameList detectedGames;
+ int count;
+ int* matches;
+ Common::Language language = Common::UNK_LANG;
+ Common::Platform platform = Common::kPlatformUnknown;
+
+ if (ConfMan.hasKey("language"))
+ language = Common::parseLanguage(ConfMan.get("language"));
+ if (ConfMan.hasKey("platform"))
+ platform = Common::parsePlatform(ConfMan.get("platform"));
+
+ count = detectGame(NULL, language, platform, matches);
+
+ if (count == 0) {
+ warning("No valid games were found in the specified directory.");
+ return false;
+ }
+
+ if (count != 1)
+ warning("Conflicting targets detected (%d)", count);
+
+ gameNumber = matches[0];
+
+ free(matches);
+
+ if (gameNumber >= gameCount || gameNumber == -1) {
+ error("SimonEngine::loadGame wrong gameNumber");
+ }
+
+ debug(2, "Running %s", toDetectedGame(gameDescriptions[gameNumber]).description.c_str());
+
+ _gameDescription = &gameDescriptions[gameNumber];
+
+ return true;
+}
+
+DetectedGameList GAME_detectGames(const FSList &fslist) {
+ DetectedGameList detectedGames;
+ int count;
+ int* matches;
+ count = detectGame(&fslist, Common::UNK_LANG, Common::kPlatformUnknown, matches);
+
+ for (int i = 0; i < count; i++)
+ detectedGames.push_back(toDetectedGame(gameDescriptions[matches[i]]));
+ free(matches);
+ return detectedGames;
+}
+
+} // End of namespace Simon
diff --git a/engines/agos/icons.cpp b/engines/agos/icons.cpp
new file mode 100644
index 0000000000..2904d9024d
--- /dev/null
+++ b/engines/agos/icons.cpp
@@ -0,0 +1,571 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-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 "agos/agos.h"
+
+namespace Simon {
+
+void SimonEngine::loadIconFile() {
+ Common::File in;
+ uint size;
+
+ in.open(getFileName(GAME_ICONFILE));
+ if (in.isOpen() == false)
+ error("Can't open icons file '%s'", getFileName(GAME_ICONFILE));
+
+ size = in.size();
+
+ _iconFilePtr = (byte *)malloc(size);
+ if (_iconFilePtr == NULL)
+ error("Out of icon memory");
+
+ in.read(_iconFilePtr, size);
+ in.close();
+}
+
+void SimonEngine::loadIconData() {
+ loadZone(8);
+ VgaPointersEntry *vpe = &_vgaBufferPointers[8];
+
+ byte *src = vpe->vgaFile2 + READ_LE_UINT32(vpe->vgaFile2 + 8);
+
+ _iconFilePtr = (byte *)malloc(43 * 336);
+ if (_iconFilePtr == NULL)
+ error("Out of icon memory");
+
+ memcpy(_iconFilePtr, src, 43 * 336);
+ o_unfreezeZones();
+}
+
+// Thanks to Stuart Caie for providing the original
+// C conversion upon which this function is based.
+void decompressIconAmiga (byte *dst, byte *src, byte base, uint pitch) {
+ byte icon_pln[288];
+ byte *i, *o, x, y;
+
+ // Decode RLE planar icon data
+ i = src;
+ o = icon_pln;
+ while (o < &icon_pln[288]) {
+ x = *i++;
+ if (x < 128) {
+ do {
+ *o++ = *i++;
+ *o++ = *i++;
+ *o++ = *i++;
+ } while (x-- > 0);
+ } else {
+ x = 256 - x;
+ do {
+ *o++ = i[0];
+ *o++ = i[1];
+ *o++ = i[2];
+ } while (x-- > 0);
+ i += 3;
+ }
+ }
+
+ // Translate planar data to chunky (very slow method)
+ for (y = 0; y < 24; y++) {
+ for (x = 0; x < 24; x++) {
+ byte pixel =
+ (icon_pln[(( y) * 3) + (x >> 3)] & (1 << (7 - (x & 7))) ? 1 : 0)
+ | (icon_pln[((24 + y) * 3) + (x >> 3)] & (1 << (7 - (x & 7))) ? 2 : 0)
+ | (icon_pln[((48 + y) * 3) + (x >> 3)] & (1 << (7 - (x & 7))) ? 4 : 0)
+ | (icon_pln[((72 + y) * 3) + (x >> 3)] & (1 << (7 - (x & 7))) ? 8 : 0);
+ if (pixel)
+ dst[x] = pixel | base;
+ }
+ dst += pitch;
+ }
+}
+
+static void decompressIcon(byte *dst, byte *src, uint w, uint h_org, byte base, uint pitch) {
+ int8 reps;
+ byte color_1, color_2;
+ byte *dst_org = dst;
+ uint h = h_org;
+
+ for (;;) {
+ reps = *src++;
+ if (reps < 0) {
+ reps--;
+ color_1 = *src >> 4;
+ if (color_1 != 0)
+ color_1 |= base;
+ color_2 = *src++ & 0xF;
+ if (color_2 != 0)
+ color_2 |= base;
+
+ do {
+ if (color_1 != 0)
+ *dst = color_1;
+ dst += pitch;
+ if (color_2 != 0)
+ *dst = color_2;
+ dst += pitch;
+
+ // reached bottom?
+ if (--h == 0) {
+ // reached right edge?
+ if (--w == 0)
+ return;
+ dst = ++dst_org;
+ h = h_org;
+ }
+ } while (++reps != 0);
+ } else {
+ do {
+ color_1 = *src >> 4;
+ if (color_1 != 0)
+ *dst = color_1 | base;
+ dst += pitch;
+
+ color_2 = *src++ & 0xF;
+ if (color_2 != 0)
+ *dst = color_2 | base;
+ dst += pitch;
+
+ // reached bottom?
+ if (--h == 0) {
+ // reached right edge?
+ if (--w == 0)
+ return;
+ dst = ++dst_org;
+ h = h_org;
+ }
+ } while (--reps >= 0);
+ }
+ }
+}
+
+void SimonEngine::draw_icon_c(WindowBlock *window, uint icon, uint x, uint y) {
+ byte *dst;
+ byte *src;
+
+ _lockWord |= 0x8000;
+ dst = getFrontBuf();
+
+ if (getGameType() == GType_SIMON1) {
+ // Simon 1
+ dst += (x + window->x) * 8;
+ dst += (y * 25 + window->y) * _dxSurfacePitch;
+
+ if (getPlatform() == Common::kPlatformAmiga) {
+ src = _iconFilePtr;
+ src += READ_BE_UINT32(&((uint32 *)src)[icon]);
+ decompressIconAmiga (dst, src, 224, _dxSurfacePitch);
+ } else {
+ src = _iconFilePtr;
+ src += READ_LE_UINT16(&((uint16 *)src)[icon]);
+ decompressIcon(dst, src, 24, 12, 224, _dxSurfacePitch);
+ }
+ } else {
+ // Simon 2
+ dst += 110;
+ dst += x;
+ dst += (y + window->y) * _dxSurfacePitch;
+
+ src = _iconFilePtr;
+ src += READ_LE_UINT16(&((uint16 *)src)[icon * 2 + 0]);
+ decompressIcon(dst, src, 20, 10, 224, _dxSurfacePitch);
+
+ src = _iconFilePtr;
+ src += READ_LE_UINT16(&((uint16 *)src)[icon * 2 + 1]);
+ decompressIcon(dst, src, 20, 10, 208, _dxSurfacePitch);
+ }
+
+ _lockWord &= ~0x8000;
+}
+
+void SimonEngine::drawIconArray(uint num, Item *itemRef, int line, int classMask) {
+ if (getGameType() == GType_FF) {
+ drawIconArray_FF(num, itemRef, line, classMask);
+ } else {
+ drawIconArray_Simon(num, itemRef, line, classMask);
+ }
+}
+
+void SimonEngine::drawIconArray_Simon(uint num, Item *itemRef, int line, int classMask) {
+ Item *item_ptr_org = itemRef;
+ WindowBlock *window;
+ uint width, height;
+ uint k, i, curWidth;
+ bool item_again, showArrows;
+ uint x_pos, y_pos;
+ const int iconSize = (getGameType() == GType_SIMON1) ? 1 : 20;
+
+ window = _windowArray[num & 7];
+
+ if (getGameType() == GType_SIMON1) {
+ width = window->width / 3;
+ height = window->height / 3;
+ } else {
+ width = 100;
+ height = 40;
+ }
+
+ i = 0;
+
+ if (window == NULL)
+ return;
+
+ if (window->iconPtr)
+ removeIconArray(num);
+
+ window->iconPtr = (IconBlock *) malloc(sizeof(IconBlock));
+ window->iconPtr->itemRef = itemRef;
+ window->iconPtr->upArrow = -1;
+ window->iconPtr->downArrow = -1;
+ window->iconPtr->line = line;
+ window->iconPtr->classMask = classMask;
+
+ itemRef = derefItem(itemRef->child);
+
+ while (itemRef && line-- != 0) {
+ curWidth = 0;
+ while (itemRef && width > curWidth) {
+ if ((classMask == 0 || itemRef->classFlags & classMask) && has_item_childflag_0x10(itemRef))
+ curWidth += iconSize;
+ itemRef = derefItem(itemRef->sibling);
+ }
+ }
+
+ if (itemRef == NULL) {
+ window->iconPtr->line = 0;
+ itemRef = derefItem(item_ptr_org->child);
+ }
+
+ x_pos = 0;
+ y_pos = 0;
+ k = 0;
+ item_again = false;
+ showArrows = false;
+
+ while (itemRef) {
+ if ((classMask == 0 || itemRef->classFlags & classMask) && has_item_childflag_0x10(itemRef)) {
+ if (item_again == false) {
+ window->iconPtr->iconArray[k].item = itemRef;
+ if (getGameType() == GType_SIMON1) {
+ draw_icon_c(window, itemGetIconNumber(itemRef), x_pos * 3, y_pos);
+ window->iconPtr->iconArray[k].boxCode =
+ setupIconHitArea(window, 0, x_pos * 3, y_pos, itemRef);
+ } else {
+ draw_icon_c(window, itemGetIconNumber(itemRef), x_pos, y_pos);
+ window->iconPtr->iconArray[k].boxCode =
+ setupIconHitArea(window, 0, x_pos, y_pos, itemRef);
+ }
+ k++;
+ } else {
+ window->iconPtr->iconArray[k].item = NULL;
+ showArrows = 1;
+ }
+
+ x_pos += iconSize;
+ if (x_pos >= width) {
+ x_pos = 0;
+ y_pos += iconSize;
+ if (y_pos >= height)
+ item_again = true;
+ }
+ }
+ itemRef = derefItem(itemRef->sibling);
+ }
+
+ window->iconPtr->iconArray[k].item = NULL;
+
+ if (showArrows != 0 || window->iconPtr->line != 0) {
+ /* Plot arrows and add their boxes */
+ defineArrowBoxes(window);
+ window->iconPtr->upArrow = _scrollUpHitArea;
+ window->iconPtr->downArrow = _scrollDownHitArea;
+ }
+}
+
+void SimonEngine::drawIconArray_FF(uint num, Item *itemRef, int line, int classMask) {
+ Item *item_ptr_org = itemRef;
+ WindowBlock *window;
+ uint16 flagnumber = 201;
+ uint16 iconperline = 458;
+ uint16 iconsdown = 384;
+ uint16 idone = 0;
+ uint16 icount = 0;
+ uint16 xp = 188, yp = 306;
+ int k;
+ _iOverflow = 0;
+
+ line = _variableArray[30];
+ if (line == 0)
+ _variableArray[31] = 0;
+
+ window = _windowArray[num & 7];
+ if (window == NULL)
+ return;
+
+ for (k = flagnumber; k <= flagnumber + 18; k++)
+ _variableArray[k] = 0;
+
+ if (window->iconPtr)
+ removeIconArray(num);
+
+ window->iconPtr=(IconBlock *)malloc(sizeof(IconBlock));
+ window->iconPtr->itemRef = itemRef;
+ window->iconPtr->upArrow = -1;
+ window->iconPtr->downArrow = -1;
+ window->iconPtr->line = line;
+ window->iconPtr->classMask = classMask;
+
+ itemRef = derefItem(itemRef->child);
+ k = flagnumber;
+
+ while (itemRef && (line > 65)) {
+ uint16 ct = xp;
+ while (itemRef && ct < iconperline) {
+ if ((classMask == 0) || ((itemRef->classFlags & classMask) != 0)) {
+ if (has_item_childflag_0x10(itemRef)) {
+ ct += 45;
+ k++;
+ }
+ }
+ itemRef = derefItem(itemRef->sibling);
+ }
+ line -= 52;
+ if (k == (flagnumber + 18))
+ k = flagnumber;
+ }
+ yp -= line; // Adjust starting y
+
+ if (itemRef == NULL) {
+ window->iconPtr->line = 0;
+ itemRef = derefItem(item_ptr_org->child);
+ }
+
+ while (itemRef) {
+ if ((classMask != 0) && ((itemRef->classFlags & classMask) == 0))
+ goto l1;
+ if (has_item_childflag_0x10(itemRef) == 0)
+ goto l1;
+ if (!idone) {
+/*
+ * Create thee icon and graphics rendering
+ */
+ window->iconPtr->iconArray[icount].item = itemRef;
+ _variableArray[k] = itemGetIconNumber(itemRef);
+ window->iconPtr->iconArray[icount++].boxCode =
+ setupIconHitArea(window, k++, xp, yp, itemRef);
+ } else {
+/*
+ * Just remember the overflow has occured
+ */
+ window->iconPtr->iconArray[icount].item = NULL; /* END MARKINGS */
+ _iOverflow = 1;
+ }
+ xp += 45;
+ if (xp >= iconperline) { /* End of line ? */
+ if (k == (flagnumber + 18))
+ k = flagnumber;
+ xp = 188;
+ yp += 52; /* Move down */
+ if (yp >= iconsdown) { /* Full ? */
+ idone = 1; /* Note completed screen */
+ }
+ }
+l1:; itemRef = derefItem(itemRef->sibling);
+ }
+ window->iconPtr->iconArray[icount].item = NULL; /* END MARKINGS */
+ if (_variableArray[30] == 0) {
+ if (yp != 306)
+ _variableArray[31] = 52;
+ if ((xp == 188) && (yp == 358))
+ _variableArray[31] = 0;
+ }
+
+ /* Plot arrows and add their boxes */
+ defineArrowBoxes(window);
+ window->iconPtr->upArrow = _scrollUpHitArea;
+ window->iconPtr->downArrow = _scrollDownHitArea;
+}
+
+void SimonEngine::defineArrowBoxes(WindowBlock *window) {
+ HitArea *ha;
+
+ ha = findEmptyHitArea();
+ _scrollUpHitArea = ha - _hitAreas;
+ if (getGameType() == GType_FF) {
+ ha->x = 496;
+ ha->y = 279;
+ ha->width = 30;
+ ha->height = 45;
+ ha->flags = kBFBoxInUse | kBFNoTouchName;
+ ha->id = 0x7FFB;
+ ha->priority = 100;
+ ha->window = window;
+ ha->verb = 1;
+ } else if (getGameType() == GType_SIMON2) {
+ ha->x = 81;
+ ha->y = 158;
+ ha->width = 12;
+ ha->height = 26;
+ ha->flags = kBFBoxInUse | kBFNoTouchName;
+ ha->id = 0x7FFB;
+ ha->priority = 100;
+ ha->window = window;
+ ha->verb = 1;
+ } else {
+ ha->x = 308;
+ ha->y = 149;
+ ha->width = 12;
+ ha->height = 17;
+ ha->flags = kBFBoxInUse | kBFNoTouchName;
+ ha->id = 0x7FFB;
+ ha->priority = 100;
+ ha->window = window;
+ ha->verb = 1;
+ }
+
+ ha = findEmptyHitArea();
+ _scrollDownHitArea = ha - _hitAreas;
+
+ if (getGameType() == GType_FF) {
+ ha->x = 496;
+ ha->y = 324;
+ ha->width = 30;
+ ha->height = 44;
+ ha->flags = kBFBoxInUse | kBFNoTouchName;
+ ha->id = 0x7FFC;
+ ha->priority = 100;
+ ha->window = window;
+ ha->verb = 1;
+ } else if (getGameType() == GType_SIMON2) {
+ ha->x = 227;
+ ha->y = 162;
+ ha->width = 12;
+ ha->height = 26;
+ ha->flags = kBFBoxInUse | kBFNoTouchName;
+ ha->id = 0x7FFC;
+ ha->priority = 100;
+ ha->window = window;
+ ha->verb = 1;
+ } else {
+ ha->x = 308;
+ ha->y = 176;
+ ha->width = 12;
+ ha->height = 17;
+ ha->flags = kBFBoxInUse | kBFNoTouchName;
+ ha->id = 0x7FFC;
+ ha->priority = 100;
+ ha->window = window;
+ ha->verb = 1;
+
+ stopAnimateSimon1(128);
+ loadSprite(0, 1, 128, 0, 0, 14);
+ }
+}
+
+uint SimonEngine::setupIconHitArea(WindowBlock *window, uint num, uint x, uint y, Item *item_ptr) {
+ HitArea *ha;
+
+ ha = findEmptyHitArea();
+
+ if (getGameType() == GType_FF) {
+ ha->x = x;
+ ha->y = y;
+ ha->item_ptr = item_ptr;
+ ha->width = 45;
+ ha->height = 44;
+ ha->flags = kBFBoxInUse | kBFBoxItem;
+ ha->id = num;
+ ha->priority = 100;
+ ha->verb = 208;
+ } else if (getGameType() == GType_SIMON2) {
+ ha->x = x + 110;
+ ha->y = window->y + y;
+ ha->item_ptr = item_ptr;
+ ha->width = 20;
+ ha->height = 20;
+ ha->flags = kBFDragBox | kBFBoxInUse | kBFBoxItem;
+ ha->id = 0x7FFD;
+ ha->priority = 100;
+ ha->verb = 208;
+ } else {
+ ha->x = (x + window->x) * 8;
+ ha->y = y * 25 + window->y;
+ ha->item_ptr = item_ptr;
+ ha->width = 24;
+ ha->height = 24;
+ ha->flags = kBFDragBox | kBFBoxInUse | kBFBoxItem;
+ ha->id = 0x7FFD;
+ ha->priority = 100;
+ ha->verb = 208;
+ }
+
+ return ha - _hitAreas;
+}
+
+void SimonEngine::removeIconArray(uint num) {
+ WindowBlock *window;
+ uint16 curWindow;
+ uint16 i;
+
+ window = _windowArray[num & 7];
+ curWindow = _curWindow;
+
+ if (window == NULL || window->iconPtr == NULL)
+ return;
+
+ if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) {
+ changeWindow(num);
+ windowPutChar(12);
+ changeWindow(curWindow);
+ }
+
+ for (i = 0; window->iconPtr->iconArray[i].item != NULL; i++) {
+ delete_hitarea_by_index(window->iconPtr->iconArray[i].boxCode);
+ }
+
+ if (window->iconPtr->upArrow != -1) {
+ delete_hitarea_by_index(window->iconPtr->upArrow);
+ }
+
+ if (window->iconPtr->downArrow != -1) {
+ delete_hitarea_by_index(window->iconPtr->downArrow);
+ if (getGameType() == GType_SIMON1)
+ removeArrows(window, num);
+ }
+
+ free(window->iconPtr);
+ window->iconPtr = NULL;
+
+ _fcsData1[num] = 0;
+ _fcsData2[num] = 0;
+}
+
+void SimonEngine::removeArrows(WindowBlock *window, uint num) {
+ stopAnimateSimon1(128);
+}
+
+} // End of namespace Simon
diff --git a/engines/agos/intern.h b/engines/agos/intern.h
new file mode 100644
index 0000000000..587eca621c
--- /dev/null
+++ b/engines/agos/intern.h
@@ -0,0 +1,262 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-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 AGOS_INTERN_H
+#define AGOS_INTERN_H
+
+namespace Simon {
+
+struct Child {
+ Child *next;
+ uint16 type;
+};
+
+struct SubRoom : Child {
+ uint16 subroutine_id;
+ uint16 roomExitStates;
+ uint16 roomExit[1];
+};
+
+struct SubObject : Child {
+ uint16 objectName;
+ uint32 objectFlags;
+ int16 objectFlagValue[1];
+};
+
+struct SubUserChain : Child {
+ uint16 subroutine_id;
+ uint16 chChained;
+};
+
+struct SubUserInherit : Child {
+ uint16 subroutine_id;
+ uint16 inMaster;
+};
+
+struct SubUserFlag : Child {
+ uint16 subroutine_id;
+ uint16 userFlags[4];
+};
+
+enum {
+ SubRoom_SIZE = sizeof(SubRoom) - sizeof(uint16),
+ SubObject_SIZE = sizeof(SubObject) - sizeof(int16)
+};
+
+struct Item {
+ uint16 parent;
+ uint16 child;
+ uint16 sibling;
+ int16 noun;
+ int16 adjective;
+ int16 state; /* signed int */
+ uint16 classFlags;
+ uint16 itemName;
+ Child *children;
+
+ Item() { memset(this, 0, sizeof(*this)); }
+};
+
+struct IconEntry {
+ Item *item;
+ uint16 boxCode;
+};
+
+struct IconBlock {
+ int16 line;
+ Item *itemRef;
+ IconEntry iconArray[64];
+ int16 upArrow, downArrow;
+ uint16 classMask;
+};
+
+struct WindowBlock {
+ byte mode;
+ byte flags;
+ uint16 x, y;
+ uint16 width, height;
+ uint16 textColumn, textRow;
+ uint16 textColumnOffset, textLength, textMaxLength;
+ uint16 scrollY;
+ uint8 fill_color, text_color;
+ IconBlock *iconPtr;
+ WindowBlock() { memset(this, 0, sizeof(*this)); }
+};
+// note on text offset:
+// the actual x-coordinate is: textColumn * 8 + textColumnOffset
+// the actual y-coordinate is: textRow * 8
+
+enum {
+ SUBROUTINE_LINE_SMALL_SIZE = 2,
+ SUBROUTINE_LINE_BIG_SIZE = 8
+};
+
+struct Subroutine {
+ uint16 id; /* subroutine ID */
+ uint16 first; /* offset from subroutine start to first subroutine line */
+ Subroutine *next; /* next subroutine in linked list */
+};
+
+struct SubroutineLine {
+ uint16 next;
+ int16 verb;
+ int16 noun1;
+ int16 noun2;
+};
+
+struct TimeEvent {
+ uint32 time;
+ uint16 subroutine_id;
+ TimeEvent *next;
+};
+
+struct GameSpecificSettings {
+#ifndef PALMOS_68K
+ const char *effects_filename;
+ const char *speech_filename;
+ #else
+ const char effects_filename[12];
+ const char speech_filename[12];
+ #endif
+};
+
+enum BoxFlags {
+ kBFTextBox = 0x1,
+ kBFBoxSelected = 0x2,
+ kBFNoTouchName = 0x4,
+ kBFInvertTouch = 0x8,
+ kBFDragBox = 0x10, // Simon 1/2
+ kBFHyperBox = 0x10, // Feeble Files
+ kBFBoxInUse = 0x20,
+ kBFBoxDead = 0x40,
+ kBFBoxItem = 0x80
+};
+
+enum SubObjectFlags {
+ kOFText = 0x1,
+ kOFSize = 0x2,
+ kOFWeight = 0x4,
+ kOFVolume = 0x8,
+ kOFIcon = 0x10,
+ kOFKeyColor1 = 0x20,
+ kOFKeyColor2 = 0x40,
+ kOFMenu = 0x80,
+ kOFNumber = 0x100,
+ kOFVoice = 0x200
+};
+
+enum GameFeatures {
+ GF_TALKIE = 1 << 0,
+ GF_OLD_BUNDLE = 1 << 1,
+ GF_CRUNCHED = 1 << 2,
+ GF_ZLIBCOMP = 1 << 3
+};
+
+enum GameFileTypes {
+ GAME_BASEFILE = 1 << 0,
+ GAME_ICONFILE = 1 << 1,
+ GAME_GMEFILE = 1 << 2,
+ GAME_STRFILE = 1 << 3,
+ GAME_RMSLFILE = 1 << 4,
+ GAME_TBLFILE = 1 << 5,
+ GAME_XTBLFILE = 1 << 6,
+
+ GAME_GFXIDXFILE = 1 << 7
+};
+
+enum GameIds {
+ GID_ELVIRA,
+ GID_ELVIRA2,
+ GID_WAXWORKS,
+
+ GID_SIMON1DOS,
+ GID_SIMON1DOS_RU,
+ GID_SIMON1DOS_INF,
+ GID_SIMON1DOS_INF_RU,
+ GID_SIMON1DOS_FR,
+ GID_SIMON1DOS_DE,
+ GID_SIMON1DOS_IT,
+ GID_SIMON1DOS_ES,
+ GID_SIMON1DEMO,
+ GID_SIMON1AMIGA,
+ GID_SIMON1AMIGA_FR,
+ GID_SIMON1AMIGA_DE,
+ GID_SIMON1AMIGADEMO,
+ GID_SIMON1CD32,
+ GID_SIMON1CD32_2,
+ GID_SIMON1ACORN,
+ GID_SIMON1ACORNDEMO,
+ GID_SIMON1TALKIE,
+ GID_SIMON1TALKIE2,
+ GID_SIMON1TALKIE_FR,
+ GID_SIMON1TALKIE_DE,
+ GID_SIMON1TALKIE_HB,
+ GID_SIMON1TALKIE_IT,
+ GID_SIMON1TALKIE_IT2,
+ GID_SIMON1TALKIE_ES,
+ GID_SIMON1WIN,
+ GID_SIMON1WIN_RU,
+ GID_SIMON1WIN_DE,
+
+ GID_SIMON2DOS,
+ GID_SIMON2DOS_RU,
+ GID_SIMON2DOS2,
+ GID_SIMON2DOS2_RU,
+ GID_SIMON2DOS_DE,
+ GID_SIMON2DOS_IT,
+ GID_SIMON2DEMO,
+ GID_SIMON2TALKIE,
+ GID_SIMON2TALKIE2,
+ GID_SIMON2TALKIE_FR,
+ GID_SIMON2TALKIE_DE,
+ GID_SIMON2TALKIE_DE2,
+ GID_SIMON2TALKIE_HB,
+ GID_SIMON2TALKIE_IT,
+ GID_SIMON2TALKIE_ES,
+ GID_SIMON2WIN,
+ GID_SIMON2WIN_DE,
+ GID_SIMON2WIN_DE2,
+ GID_SIMON2WIN_PL,
+
+ GID_FEEBLEFILES_AMI_DE,
+ GID_FEEBLEFILES_AMI_UK,
+ GID_FEEBLEFILES_MAC_FR,
+ GID_FEEBLEFILES_MAC_DE,
+ GID_FEEBLEFILES_MAC_ES,
+ GID_FEEBLEFILES_MAC_UK,
+ GID_FEEBLEFILES_2CD,
+ GID_FEEBLEFILES_4CD,
+ GID_FEEBLEFILES_FR,
+ GID_FEEBLEFILES_DE,
+ GID_FEEBLEFILES_IT,
+ GID_FEEBLEFILES_ES,
+
+ GID_DIMP,
+ GID_JUMBLE,
+ GID_PUZZLE,
+ GID_SWAMPY
+};
+
+} // End of namespace Simon
+
+#endif
diff --git a/engines/agos/items.cpp b/engines/agos/items.cpp
new file mode 100644
index 0000000000..b908d0f5ab
--- /dev/null
+++ b/engines/agos/items.cpp
@@ -0,0 +1,2552 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-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$
+ *
+ */
+
+// Item script opcodes for Simon1/Simon2
+
+#include "common/stdafx.h"
+
+#include "common/system.h"
+
+#include "agos/animation.h"
+#include "agos/agos.h"
+
+#ifdef _WIN32_WCE
+extern bool isSmartphone(void);
+#endif
+
+namespace Simon {
+
+// Opcode table
+void SimonEngine::setupOpcodes() {
+ // This opcode table is for Simon 1. Changes for Simon 2 and FF are
+ // made below.
+
+ static OpcodeProc opcode_table[200] = {
+ // 0 - 4
+ NULL,
+ &SimonEngine::o_at,
+ &SimonEngine::o_notAt,
+ NULL,
+ NULL,
+ // 5 - 9
+ &SimonEngine::o_carried,
+ &SimonEngine::o_notCarried,
+ &SimonEngine::o_isAt,
+ NULL,
+ NULL,
+ // 10 - 14
+ NULL,
+ &SimonEngine::o_zero,
+ &SimonEngine::o_notZero,
+ &SimonEngine::o_eq,
+ &SimonEngine::o_notEq,
+ // 15 - 19
+ &SimonEngine::o_gt,
+ &SimonEngine::o_lt,
+ &SimonEngine::o_eqf,
+ &SimonEngine::o_notEqf,
+ &SimonEngine::o_ltf,
+ // 20 - 24
+ &SimonEngine::o_gtf,
+ NULL,
+ NULL,
+ &SimonEngine::o_chance,
+ NULL,
+ // 25 - 29
+ &SimonEngine::o_isRoom,
+ &SimonEngine::o_isObject,
+ &SimonEngine::o_state,
+ &SimonEngine::o_oflag,
+ NULL,
+ // 30 - 34
+ NULL,
+ &SimonEngine::o_destroy,
+ NULL,
+ &SimonEngine::o_place,
+ NULL,
+ // 35 - 39
+ NULL,
+ &SimonEngine::o_copyff,
+ NULL,
+ NULL,
+ NULL,
+ // 40 - 44
+ NULL,
+ &SimonEngine::o_clear,
+ &SimonEngine::o_let,
+ &SimonEngine::o_add,
+ &SimonEngine::o_sub,
+ // 45 - 49
+ &SimonEngine::o_addf,
+ &SimonEngine::o_subf,
+ &SimonEngine::o_mul,
+ &SimonEngine::o_div,
+ &SimonEngine::o_mulf,
+ // 50 - 54
+ &SimonEngine::o_divf,
+ &SimonEngine::o_mod,
+ &SimonEngine::o_modf,
+ &SimonEngine::o_random,
+ NULL,
+ // 55 - 59
+ &SimonEngine::o_goto,
+ &SimonEngine::o_oset,
+ &SimonEngine::o_oclear,
+ &SimonEngine::o_putBy,
+ &SimonEngine::o_inc,
+ // 60 - 64
+ &SimonEngine::o_dec,
+ &SimonEngine::o_setState,
+ &SimonEngine::o_print,
+ &SimonEngine::o_message,
+ &SimonEngine::o_msg,
+ // 65 - 69
+ &SimonEngine::o_addTextBox,
+ &SimonEngine::o_setShortText,
+ &SimonEngine::o_setLongText,
+ &SimonEngine::o_end,
+ &SimonEngine::o_done,
+ // 70 - 74
+ NULL,
+ &SimonEngine::o_process,
+ NULL,
+ NULL,
+ NULL,
+ // 75 - 79
+ NULL,
+ &SimonEngine::o_when,
+ &SimonEngine::o_if1,
+ &SimonEngine::o_if2,
+ &SimonEngine::o_isCalled,
+ // 80 - 84
+ &SimonEngine::o_is,
+ NULL,
+ &SimonEngine::o_debug,
+ NULL,
+ NULL,
+ // 85 - 89
+ NULL,
+ NULL,
+ &SimonEngine::o_comment,
+ &SimonEngine::o_haltAnimation,
+ &SimonEngine::o_restartAnimation,
+ // 90 - 94
+ &SimonEngine::o_getParent,
+ &SimonEngine::o_getNext,
+ &SimonEngine::o_getChildren,
+ NULL,
+ NULL,
+ // 95 - 99
+ NULL,
+ &SimonEngine::o_picture,
+ &SimonEngine::o_loadZone,
+ NULL,
+ NULL,
+ // 100 - 104
+ &SimonEngine::o_killAnimate,
+ &SimonEngine::o_defWindow,
+ &SimonEngine::o_window,
+ &SimonEngine::o_cls,
+ &SimonEngine::o_closeWindow,
+ // 105 - 109
+ NULL,
+ NULL,
+ &SimonEngine::o_addBox,
+ &SimonEngine::o_delBox,
+ &SimonEngine::o_enableBox,
+ // 110 - 114
+ &SimonEngine::o_disableBox,
+ &SimonEngine::o_moveBox,
+ NULL,
+ NULL,
+ &SimonEngine::o_doIcons,
+ // 115 - 119
+ &SimonEngine::o_isClass,
+ &SimonEngine::o_setClass,
+ &SimonEngine::o_unsetClass,
+ NULL,
+ &SimonEngine::o_waitSync,
+ // 120 - 124
+ &SimonEngine::o_sync,
+ &SimonEngine::o_defObj,
+ NULL,
+ NULL,
+ NULL,
+ // 125 - 129
+ &SimonEngine::o_here,
+ &SimonEngine::o_doClassIcons,
+ NULL,
+ &SimonEngine::o_waitEndTune,
+ &SimonEngine::o_ifEndTune,
+ // 130 - 134
+ &SimonEngine::o_setAdjNoun,
+ NULL,
+ &SimonEngine::o_saveUserGame,
+ &SimonEngine::o_loadUserGame,
+ &SimonEngine::o_stopTune,
+ // 135 - 139
+ &SimonEngine::o_pauseGame,
+ &SimonEngine::o_copysf,
+ &SimonEngine::o_restoreIcons,
+ &SimonEngine::o_freezeZones,
+ &SimonEngine::o_placeNoIcons,
+ // 140 - 144
+ &SimonEngine::o_clearTimers,
+ &SimonEngine::o_setDollar,
+ &SimonEngine::o_isBox,
+ &SimonEngine::o_doTable,
+ NULL,
+ // 145 - 149
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ // 150 - 154
+ NULL,
+ &SimonEngine::o_storeItem,
+ &SimonEngine::o_getItem,
+ &SimonEngine::o_bSet,
+ &SimonEngine::o_bClear,
+ // 155 - 159
+ &SimonEngine::o_bZero,
+ &SimonEngine::o_bNotZero,
+ &SimonEngine::o_getOValue,
+ &SimonEngine::o_setOValue,
+ NULL,
+ // 160 - 164
+ &SimonEngine::o_ink,
+ &SimonEngine::o_screenTextBox,
+ &SimonEngine::o_screenTextMsg,
+ &SimonEngine::o_playEffect,
+ &SimonEngine::o_getDollar2,
+ // 165 - 169
+ &SimonEngine::o_isAdjNoun,
+ &SimonEngine::o_b2Set,
+ &SimonEngine::o_b2Clear,
+ &SimonEngine::o_b2Zero,
+ &SimonEngine::o_b2NotZero,
+ // 170 - 174
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ // 175 - 179
+ &SimonEngine::o_lockZones,
+ &SimonEngine::o_unlockZones,
+ NULL,
+ &SimonEngine::o_getPathPosn,
+ &SimonEngine::o_scnTxtLongText,
+ // 180 - 184
+ &SimonEngine::o_mouseOn,
+ NULL,
+ NULL,
+ NULL,
+ &SimonEngine::o_unloadZone,
+ // 185 - 189
+ NULL,
+ &SimonEngine::o_unfreezeZones,
+ NULL,
+ NULL,
+ NULL,
+ // 190 - 194
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ // 195 - 199
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ };
+
+ _opcode_table = opcode_table;
+ _numOpcodes = ARRAYSIZE(opcode_table);
+
+ switch (getGameType()) {
+ case GType_ELVIRA:
+ case GType_ELVIRA2:
+ // Confirmed
+ opcode_table[48] = &SimonEngine::o_destroy;
+ opcode_table[51] = &SimonEngine::o_place;
+ opcode_table[91] = &SimonEngine::o_message;
+
+ opcode_table[70] = &SimonEngine::o1_printLongText;
+ opcode_table[83] = &SimonEngine::o1_rescan;
+ opcode_table[98] = &SimonEngine::o1_animate;
+ opcode_table[99] = &SimonEngine::o1_stopAnimate;
+ opcode_table[85] = &SimonEngine::oww_whereTo;
+ opcode_table[105] = &SimonEngine::oww_menu;
+ opcode_table[106] = &SimonEngine::oww_textMenu;
+ opcode_table[127] = &SimonEngine::o1_playTune;
+ opcode_table[148] = &SimonEngine::oww_ifDoorOpen;
+ opcode_table[179] = &SimonEngine::o_isAdjNoun;
+ opcode_table[180] = &SimonEngine::o_b2Set;
+ opcode_table[181] = &SimonEngine::o_b2Clear;
+ opcode_table[182] = &SimonEngine::o_b2Zero;
+ opcode_table[183] = &SimonEngine::o_b2NotZero;
+
+ // Code difference, check if triggered
+ opcode_table[161] = NULL;
+ opcode_table[162] = NULL;
+ opcode_table[163] = NULL;
+ opcode_table[164] = NULL;
+ opcode_table[165] = NULL;
+ opcode_table[166] = NULL;
+ opcode_table[167] = NULL;
+ opcode_table[168] = NULL;
+ opcode_table[169] = NULL;
+ opcode_table[170] = NULL;
+ opcode_table[171] = NULL;
+ opcode_table[172] = NULL;
+ opcode_table[173] = NULL;
+ opcode_table[174] = NULL;
+ opcode_table[175] = NULL;
+ opcode_table[176] = NULL;
+ opcode_table[177] = NULL;
+ opcode_table[178] = NULL;
+ opcode_table[184] = NULL;
+ opcode_table[185] = NULL;
+ opcode_table[186] = NULL;
+ opcode_table[187] = NULL;
+ opcode_table[188] = NULL;
+ opcode_table[189] = NULL;
+ opcode_table[190] = NULL;
+ break;
+ case GType_WW:
+ // Confirmed
+ opcode_table[70] = &SimonEngine::o1_printLongText;
+ opcode_table[83] = &SimonEngine::o1_rescan;
+ opcode_table[98] = &SimonEngine::o1_animate;
+ opcode_table[99] = &SimonEngine::o1_stopAnimate;
+ opcode_table[85] = &SimonEngine::oww_whereTo;
+ opcode_table[105] = &SimonEngine::oww_menu;
+ opcode_table[106] = &SimonEngine::oww_textMenu;
+ opcode_table[127] = &SimonEngine::o1_playTune;
+ opcode_table[148] = &SimonEngine::oww_ifDoorOpen;
+ opcode_table[179] = &SimonEngine::o_isAdjNoun;
+ opcode_table[180] = &SimonEngine::o_b2Set;
+ opcode_table[181] = &SimonEngine::o_b2Clear;
+ opcode_table[182] = &SimonEngine::o_b2Zero;
+ opcode_table[183] = &SimonEngine::o_b2NotZero;
+
+ // Code difference, check if triggered
+ opcode_table[161] = NULL;
+ opcode_table[162] = NULL;
+ opcode_table[163] = NULL;
+ opcode_table[164] = NULL;
+ opcode_table[165] = NULL;
+ opcode_table[166] = NULL;
+ opcode_table[167] = NULL;
+ opcode_table[168] = NULL;
+ opcode_table[169] = NULL;
+ opcode_table[170] = NULL;
+ opcode_table[171] = NULL;
+ opcode_table[172] = NULL;
+ opcode_table[173] = NULL;
+ opcode_table[174] = NULL;
+ opcode_table[175] = NULL;
+ opcode_table[176] = NULL;
+ opcode_table[177] = NULL;
+ opcode_table[178] = NULL;
+ opcode_table[184] = NULL;
+ opcode_table[185] = NULL;
+ opcode_table[186] = NULL;
+ opcode_table[187] = NULL;
+ opcode_table[188] = NULL;
+ opcode_table[189] = NULL;
+ opcode_table[190] = NULL;
+ break;
+ case GType_SIMON1:
+ opcode_table[70] = &SimonEngine::o1_printLongText;
+ opcode_table[83] = &SimonEngine::o1_rescan;
+ opcode_table[98] = &SimonEngine::o1_animate;
+ opcode_table[99] = &SimonEngine::o1_stopAnimate;
+ opcode_table[127] = &SimonEngine::o1_playTune;
+ opcode_table[177] = &SimonEngine::o1_screenTextPObj;
+ opcode_table[181] = &SimonEngine::o1_mouseOff;
+ opcode_table[182] = &SimonEngine::o1_loadBeard;
+ opcode_table[183] = &SimonEngine::o1_unloadBeard;
+ opcode_table[185] = &SimonEngine::o1_loadStrings;
+ opcode_table[187] = &SimonEngine::o1_specialFade;
+ break;
+ case GType_SIMON2:
+ opcode_table[70] = &SimonEngine::o2_printLongText;
+ opcode_table[83] = &SimonEngine::o2_rescan;
+ opcode_table[98] = &SimonEngine::o2_animate;
+ opcode_table[99] = &SimonEngine::o2_stopAnimate;
+ opcode_table[127] = &SimonEngine::o2_playTune;
+ opcode_table[177] = &SimonEngine::o2_screenTextPObj;
+ opcode_table[181] = &SimonEngine::o2_mouseOff;
+ opcode_table[188] = &SimonEngine::o2_isShortText;
+ opcode_table[189] = &SimonEngine::o2_clearMarks;
+ opcode_table[190] = &SimonEngine::o2_waitMark;
+ break;
+ case GType_FF:
+ opcode_table[23] = &SimonEngine::o3_chance;
+ opcode_table[37] = &SimonEngine::o3_jumpOut;
+ opcode_table[65] = &SimonEngine::o3_addTextBox;
+ opcode_table[70] = &SimonEngine::o3_printLongText;
+ opcode_table[83] = &SimonEngine::o2_rescan;
+ opcode_table[98] = &SimonEngine::o2_animate;
+ opcode_table[99] = &SimonEngine::o2_stopAnimate;
+ opcode_table[107] = &SimonEngine::o3_addBox;
+ opcode_table[122] = &SimonEngine::o3_oracleTextDown;
+ opcode_table[123] = &SimonEngine::o3_oracleTextUp;
+ opcode_table[124] = &SimonEngine::o3_ifTime;
+ opcode_table[127] = &SimonEngine::o3_playTune;
+ opcode_table[131] = &SimonEngine::o3_setTime;
+ opcode_table[132] = &SimonEngine::o3_saveUserGame,
+ opcode_table[133] = &SimonEngine::o3_loadUserGame;
+ opcode_table[134] = &SimonEngine::o3_listSaveGames;
+ opcode_table[135] = &SimonEngine::o3_checkCD;
+ opcode_table[161] = &SimonEngine::o3_screenTextBox;
+ opcode_table[165] = &SimonEngine::o3_isAdjNoun;
+ opcode_table[171] = &SimonEngine::o3_hyperLinkOn;
+ opcode_table[172] = &SimonEngine::o3_hyperLinkOff;
+ opcode_table[173] = &SimonEngine::o3_checkPaths;
+ opcode_table[177] = &SimonEngine::o3_screenTextPObj;
+ opcode_table[181] = &SimonEngine::o3_mouseOff;
+ opcode_table[182] = &SimonEngine::o3_loadVideo;
+ opcode_table[183] = &SimonEngine::o3_playVideo;
+ opcode_table[187] = &SimonEngine::o3_centreScroll;
+ opcode_table[188] = &SimonEngine::o2_isShortText;
+ opcode_table[189] = &SimonEngine::o2_clearMarks;
+ opcode_table[190] = &SimonEngine::o2_waitMark;
+ opcode_table[191] = &SimonEngine::o3_resetPVCount;
+ opcode_table[192] = &SimonEngine::o3_setPathValues;
+ opcode_table[193] = &SimonEngine::o3_stopClock;
+ opcode_table[194] = &SimonEngine::o3_restartClock;
+ opcode_table[195] = &SimonEngine::o3_setColour;
+ opcode_table[196] = &SimonEngine::o3_b3Set;
+ opcode_table[197] = &SimonEngine::o3_b3Clear;
+ opcode_table[198] = &SimonEngine::o3_b3Zero;
+ opcode_table[199] = &SimonEngine::o3_b3NotZero;
+ break;
+ case GType_PP:
+ // Confirmed
+ opcode_table[30] = &SimonEngine::o4_opcode30;
+ opcode_table[37] = &SimonEngine::o4_checkTiles;
+ opcode_table[38] = &SimonEngine::o4_opcode38;
+ opcode_table[105] = &SimonEngine::o4_loadHiScores;
+ opcode_table[106] = &SimonEngine::o4_checkHiScores;
+ opcode_table[133] = &SimonEngine::o4_loadUserGame;
+ opcode_table[166] = NULL;
+ opcode_table[167] = NULL;
+ opcode_table[168] = NULL;
+ opcode_table[169] = NULL;
+ opcode_table[173] = &SimonEngine::o4_saveOopsPosition;
+ opcode_table[191] = &SimonEngine::o4_resetPVCount;
+ opcode_table[192] = &SimonEngine::o4_setPathValues;
+
+ // Code difference, check if triggered
+ opcode_table[132] = &SimonEngine::o3_saveUserGame,
+ opcode_table[187] = &SimonEngine::o4_resetGameTime;
+
+ // Code difference. Some kind of logging?
+ opcode_table[190] = &SimonEngine::o2_waitMark;
+
+ // To check
+ opcode_table[23] = &SimonEngine::o3_chance;
+ opcode_table[65] = &SimonEngine::o3_addTextBox;
+ opcode_table[70] = &SimonEngine::o3_printLongText;
+ opcode_table[83] = &SimonEngine::o2_rescan;
+ opcode_table[98] = &SimonEngine::o2_animate;
+ opcode_table[99] = &SimonEngine::o2_stopAnimate;
+ opcode_table[107] = &SimonEngine::o3_addBox;
+ opcode_table[122] = &SimonEngine::o3_oracleTextDown;
+ opcode_table[123] = &SimonEngine::o3_oracleTextUp;
+ opcode_table[124] = &SimonEngine::o3_ifTime;
+ opcode_table[127] = &SimonEngine::o3_playTune;
+ opcode_table[131] = &SimonEngine::o3_setTime;
+ opcode_table[134] = &SimonEngine::o3_listSaveGames;
+ opcode_table[161] = &SimonEngine::o3_screenTextBox;
+ opcode_table[165] = &SimonEngine::o3_isAdjNoun;
+ opcode_table[171] = &SimonEngine::o3_hyperLinkOn;
+ opcode_table[172] = &SimonEngine::o3_hyperLinkOff;
+ opcode_table[177] = &SimonEngine::o3_screenTextPObj;
+ opcode_table[181] = &SimonEngine::o3_mouseOff;
+ opcode_table[188] = &SimonEngine::o2_isShortText;
+ opcode_table[189] = &SimonEngine::o2_clearMarks;
+ opcode_table[193] = &SimonEngine::o3_stopClock;
+ opcode_table[194] = &SimonEngine::o3_restartClock;
+ opcode_table[195] = &SimonEngine::o3_setColour;
+ break;
+ default:
+ error("setupOpcodes: Unknown game");
+ }
+}
+
+void SimonEngine::setScriptCondition(bool cond) {
+ _runScriptCondition[_recursionDepth] = cond;
+}
+
+bool SimonEngine::getScriptCondition() {
+ return _runScriptCondition[_recursionDepth];
+}
+
+void SimonEngine::setScriptReturn(int ret) {
+ _runScriptReturn[_recursionDepth] = ret;
+}
+
+int SimonEngine::getScriptReturn() {
+ return _runScriptReturn[_recursionDepth];
+}
+
+// -----------------------------------------------------------------------
+// Common Opcodes
+// -----------------------------------------------------------------------
+
+void SimonEngine::o_at() {
+ // 1: ptrA parent is
+ setScriptCondition(me()->parent == getNextItemID());
+}
+
+void SimonEngine::o_notAt() {
+ // 2: ptrA parent is not
+ setScriptCondition(me()->parent != getNextItemID());
+}
+
+void SimonEngine::o_carried() {
+ // 5: parent is 1
+ setScriptCondition(getNextItemPtr()->parent == getItem1ID());
+}
+
+void SimonEngine::o_notCarried() {
+ // 6: parent isnot 1
+ setScriptCondition(getNextItemPtr()->parent != getItem1ID());
+}
+
+void SimonEngine::o_isAt() {
+ // 7: parent is
+ Item *item = getNextItemPtr();
+ setScriptCondition(item->parent == getNextItemID());
+}
+
+void SimonEngine::o_zero() {
+ // 11: is zero
+ setScriptCondition(getNextVarContents() == 0);
+}
+
+void SimonEngine::o_notZero() {
+ // 12: isnot zero
+ setScriptCondition(getNextVarContents() != 0);
+}
+
+void SimonEngine::o_eq() {
+ // 13: equal
+ uint tmp = getNextVarContents();
+ setScriptCondition(tmp == getVarOrWord());
+}
+
+void SimonEngine::o_notEq() {
+ // 14: not equal
+ uint tmp = getNextVarContents();
+ setScriptCondition(tmp != getVarOrWord());
+}
+
+void SimonEngine::o_gt() {
+ // 15: is greater
+ uint tmp = getNextVarContents();
+ setScriptCondition(tmp > getVarOrWord());
+}
+
+void SimonEngine::o_lt() {
+ // 16: is less
+ uint tmp = getNextVarContents();
+ setScriptCondition(tmp < getVarOrWord());
+}
+
+void SimonEngine::o_eqf() {
+ // 17: is eq f
+ uint tmp = getNextVarContents();
+ setScriptCondition(tmp == getNextVarContents());
+}
+
+void SimonEngine::o_notEqf() {
+ // 18: is not equal f
+ uint tmp = getNextVarContents();
+ setScriptCondition(tmp != getNextVarContents());
+}
+
+void SimonEngine::o_ltf() {
+ // 19: is greater f
+ uint tmp = getNextVarContents();
+ setScriptCondition(tmp < getNextVarContents());
+}
+
+void SimonEngine::o_gtf() {
+ // 20: is less f
+ uint tmp = getNextVarContents();
+ setScriptCondition(tmp > getNextVarContents());
+}
+
+void SimonEngine::o_chance() {
+ // 23
+ uint a = getVarOrWord();
+
+ if (a == 0) {
+ setScriptCondition(false);
+ return;
+ }
+
+ if (a == 100) {
+ setScriptCondition(true);
+ return;
+ }
+
+ a += _chanceModifier;
+
+ if (a <= 0) {
+ _chanceModifier = 0;
+ setScriptCondition(false);
+ } else if ((uint)_rnd.getRandomNumber(99) < a) {
+ if (_chanceModifier <= 0)
+ _chanceModifier -= 5;
+ else
+ _chanceModifier = 0;
+ setScriptCondition(true);
+ } else {
+ if (_chanceModifier >= 0)
+ _chanceModifier += 5;
+ else
+ _chanceModifier = 0;
+ setScriptCondition(false);
+ }
+}
+
+void SimonEngine::o_isRoom() {
+ // 25: is room
+ setScriptCondition(isRoom(getNextItemPtr()));
+}
+
+void SimonEngine::o_isObject() {
+ // 26: is object
+ setScriptCondition(isObject(getNextItemPtr()));
+}
+
+void SimonEngine::o_state() {
+ // 27: item state is
+ Item *item = getNextItemPtr();
+ setScriptCondition((uint) item->state == getVarOrWord());
+}
+
+void SimonEngine::o_oflag() {
+ // 28: item has prop
+ SubObject *subObject = (SubObject *)findChildOfType(getNextItemPtr(), 2);
+ byte num = getVarOrByte();
+ setScriptCondition(subObject != NULL && (subObject->objectFlags & (1 << num)) != 0);
+}
+
+void SimonEngine::o_destroy() {
+ // 31: set no parent
+ setItemParent(getNextItemPtr(), NULL);
+}
+
+void SimonEngine::o_place() {
+ // 33: set item parent
+ Item *item = getNextItemPtr();
+ setItemParent(item, getNextItemPtr());
+}
+
+void SimonEngine::o_copyff() {
+ // 36: copy var
+ uint value = getNextVarContents();
+ writeNextVarContents(value);
+}
+
+void SimonEngine::o_clear() {
+ // 41: zero var
+ writeNextVarContents(0);
+}
+
+void SimonEngine::o_let() {
+ // 42: set var
+ uint var = getVarWrapper();
+ writeVariable(var, getVarOrWord());
+}
+
+void SimonEngine::o_add() {
+ // 43: add
+ uint var = getVarWrapper();
+ writeVariable(var, readVariable(var) + getVarOrWord());
+}
+
+void SimonEngine::o_sub() {
+ // 44: sub
+ uint var = getVarWrapper();
+ writeVariable(var, readVariable(var) - getVarOrWord());
+}
+
+void SimonEngine::o_addf() {
+ // 45: add f
+ uint var = getVarWrapper();
+ writeVariable(var, readVariable(var) + getNextVarContents());
+}
+
+void SimonEngine::o_subf() {
+ // 46: sub f
+ uint var = getVarWrapper();
+ writeVariable(var, readVariable(var) - getNextVarContents());
+}
+
+void SimonEngine::o_mul() {
+ // 47: mul
+ uint var = getVarWrapper();
+ writeVariable(var, readVariable(var) * getVarOrWord());
+}
+
+void SimonEngine::o_div() {
+ // 48: div
+ uint var = getVarWrapper();
+ int value = getVarOrWord();
+ if (value == 0)
+ error("o_div: Division by zero");
+ writeVariable(var, readVariable(var) / value);
+}
+
+void SimonEngine::o_mulf() {
+ // 49: mul f
+ uint var = getVarWrapper();
+ writeVariable(var, readVariable(var) * getNextVarContents());
+}
+
+void SimonEngine::o_divf() {
+ // 50: div f
+ uint var = getVarWrapper();
+ int value = getNextVarContents();
+ if (value == 0)
+ error("o_divf: Division by zero");
+ writeVariable(var, readVariable(var) / value);
+}
+
+void SimonEngine::o_mod() {
+ // 51: mod
+ uint var = getVarWrapper();
+ int value = getVarOrWord();
+ if (value == 0)
+ error("o_mod: Division by zero");
+ writeVariable(var, readVariable(var) % value);
+}
+
+void SimonEngine::o_modf() {
+ // 52: mod f
+ uint var = getVarWrapper();
+ int value = getNextVarContents();
+ if (value == 0)
+ error("o_modf: Division by zero");
+ writeVariable(var, readVariable(var) % value);
+}
+
+void SimonEngine::o_random() {
+ // 53: random
+ uint var = getVarWrapper();
+ uint value = (uint16)getVarOrWord();
+ writeVariable(var, _rnd.getRandomNumber(value - 1));
+}
+
+void SimonEngine::o_goto() {
+ // 55: set itemA parent
+ uint item = getNextItemID();
+ if (_itemArrayPtr[item] == NULL) {
+ setItemParent(me(), NULL);
+ loadRoomItems(item);
+ }
+ setItemParent(me(), _itemArrayPtr[item]);
+}
+
+void SimonEngine::o_oset() {
+ // 56: set child2 fr bit
+ SubObject *subObject = (SubObject *)findChildOfType(getNextItemPtr(), 2);
+ int value = getVarOrByte();
+ if (subObject != NULL && value >= 0x10)
+ subObject->objectFlags |= (1 << value);
+}
+
+void SimonEngine::o_oclear() {
+ // 57: clear child2 fr bit
+ SubObject *subObject = (SubObject *)findChildOfType(getNextItemPtr(), 2);
+ int value = getVarOrByte();
+ if (subObject != NULL && value >= 0x10)
+ subObject->objectFlags &= ~(1 << value);
+}
+
+void SimonEngine::o_putBy() {
+ // 58: make siblings
+ Item *item = getNextItemPtr();
+ setItemParent(item, derefItem(getNextItemPtr()->parent));
+}
+
+void SimonEngine::o_inc() {
+ // 59: item inc state
+ Item *item = getNextItemPtr();
+ if (item->state <= 30000)
+ setItemState(item, item->state + 1);
+}
+
+void SimonEngine::o_dec() {
+ // 60: item dec state
+ Item *item = getNextItemPtr();
+ if (item->state >= 0)
+ setItemState(item, item->state - 1);
+}
+
+void SimonEngine::o_setState() {
+ // 61: item set state
+ Item *item = getNextItemPtr();
+ int value = getVarOrWord();
+ if (value < 0)
+ value = 0;
+ if (value > 30000)
+ value = 30000;
+ setItemState(item, value);
+}
+
+void SimonEngine::o_print() {
+ // 62: show int
+ showMessageFormat("%d", getNextVarContents());
+}
+
+void SimonEngine::o_message() {
+ // 63: show string nl
+ showMessageFormat("%s\n", getStringPtrByID(getNextStringID()));
+}
+
+void SimonEngine::o_msg() {
+ // 64: show string
+ showMessageFormat("%s", getStringPtrByID(getNextStringID()));
+}
+
+void SimonEngine::o_addTextBox() {
+ // 65: add hit area
+ uint id = getVarOrWord();
+ uint x = getVarOrWord();
+ uint y = getVarOrWord();
+ uint w = getVarOrWord();
+ uint h = getVarOrWord();
+ uint number = getVarOrByte();
+ if (number < _numTextBoxes)
+ defineBox(id, x, y, w, h, (number << 8) + 129, 208, _dummyItem2);
+}
+
+void SimonEngine::o_setShortText() {
+ // 66: set item name
+ uint var = getVarOrByte();
+ uint stringId = getNextStringID();
+ if (var < _numTextBoxes) {
+ _shortText[var] = stringId;
+ if (getGameType() == GType_PP) {
+ _shortTextX[var] = getVarOrWord();
+ _shortTextY[var] = getVarOrWord();
+ }
+ }
+}
+
+void SimonEngine::o_setLongText() {
+ // 67: set item description
+ uint var = getVarOrByte();
+ uint stringId = getNextStringID();
+ if (getFeatures() & GF_TALKIE) {
+ uint speechId = getNextWord();
+ if (var < _numTextBoxes) {
+ _longText[var] = stringId;
+ _longSound[var] = speechId;
+ }
+ } else {
+ if (var < _numTextBoxes) {
+ _longText[var] = stringId;
+ }
+ }
+}
+
+void SimonEngine::o_end() {
+ // 68: exit interpreter
+ shutdown();
+}
+
+void SimonEngine::o_done() {
+ // 69: return 1
+ setScriptReturn(1);
+}
+
+void SimonEngine::o_process() {
+ // 71: start subroutine
+ Subroutine *sub = getSubroutineByID(getVarOrWord());
+ if (sub != NULL)
+ startSubroutine(sub);
+}
+
+void SimonEngine::o_when() {
+ // 76: add timeout
+ uint timeout = getVarOrWord();
+ addTimeEvent(timeout, getVarOrWord());
+}
+
+void SimonEngine::o_if1() {
+ // 77: has item minus 1
+ setScriptCondition(_subjectItem != NULL);
+}
+
+void SimonEngine::o_if2() {
+ // 78: has item minus 3
+ setScriptCondition(_objectItem != NULL);
+}
+
+void SimonEngine::o_isCalled() {
+ // 79: childstruct fr2 is
+ SubObject *subObject = (SubObject *)findChildOfType(getNextItemPtr(), 2);
+ uint stringId = getNextStringID();
+ setScriptCondition((subObject != NULL) && subObject->objectName == stringId);
+}
+
+void SimonEngine::o_is() {
+ // 80: item equal
+ setScriptCondition(getNextItemPtr() == getNextItemPtr());
+}
+
+void SimonEngine::o_debug() {
+ // 82: debug opcode
+ getVarOrByte();
+}
+
+void SimonEngine::o_comment() {
+ // 87: comment
+ getNextStringID();
+}
+
+void SimonEngine::o_haltAnimation() {
+ // 88: stop animation
+ _lockWord |= 0x10;
+}
+
+void SimonEngine::o_restartAnimation() {
+ // 89: restart animation
+ _lockWord &= ~0x10;
+}
+
+void SimonEngine::o_getParent() {
+ // 90: set minusitem to parent
+ Item *item = derefItem(getNextItemPtr()->parent);
+ switch (getVarOrByte()) {
+ case 0:
+ _objectItem = item;
+ break;
+ case 1:
+ _subjectItem = item;
+ break;
+ default:
+ error("o_getParent: invalid subcode");
+ }
+}
+
+void SimonEngine::o_getNext() {
+ // 91: set minusitem to sibling
+ Item *item = derefItem(getNextItemPtr()->sibling);
+ switch (getVarOrByte()) {
+ case 0:
+ _objectItem = item;
+ break;
+ case 1:
+ _subjectItem = item;
+ break;
+ default:
+ error("o_getNext: invalid subcode");
+ }
+}
+
+void SimonEngine::o_getChildren() {
+ // 92: set minusitem to child
+ Item *item = derefItem(getNextItemPtr()->child);
+ switch (getVarOrByte()) {
+ case 0:
+ _objectItem = item;
+ break;
+ case 1:
+ _subjectItem = item;
+ break;
+ default:
+ error("o_getChildren: invalid subcode");
+ }
+}
+
+void SimonEngine::o_picture() {
+ // 96
+ uint vga_res = getVarOrWord();
+ uint mode = getVarOrByte();
+
+ if (mode == 4)
+ vc29_stopAllSounds();
+
+ if (_lockWord & 0x10)
+ error("o_picture: _lockWord & 0x10");
+
+ set_video_mode_internal(mode, vga_res);
+}
+
+void SimonEngine::o_loadZone() {
+ // 97: load vga
+ uint vga_res = getVarOrWord();
+
+ _lockWord |= 0x80;
+ loadZone(vga_res);
+ _lockWord &= ~0x80;
+}
+
+void SimonEngine::o_killAnimate() {
+ // 100: vga reset
+ _lockWord |= 0x8000;
+ vc27_resetSprite();
+ _lockWord &= ~0x8000;
+}
+
+void SimonEngine::o_defWindow() {
+ // 101
+ uint num = getVarOrByte();
+ uint x = getVarOrWord();
+ uint y = getVarOrWord();
+ uint w = getVarOrWord();
+ uint h = getVarOrWord();
+ uint flags = getVarOrWord();
+ uint fill_color = getVarOrWord();
+ uint text_color = 0;
+
+ num &= 7;
+
+ if (_windowArray[num])
+ closeWindow(num);
+
+ _windowArray[num] = openWindow(x, y, w, h, flags, fill_color, text_color);
+
+ if (num == _curWindow) {
+ _textWindow = _windowArray[num];
+ if (getGameType() == GType_FF)
+ showmessage_helper_3(_textWindow->textColumn, _textWindow->width);
+ else
+ showmessage_helper_3(_textWindow->textLength, _textWindow->textMaxLength);
+ }
+}
+
+void SimonEngine::o_window() {
+ // 102
+ changeWindow(getVarOrByte() & 7);
+}
+
+void SimonEngine::o_cls() {
+ // 103
+ mouseOff();
+ removeIconArray(_curWindow);
+ showMessageFormat("\x0C");
+ _oracleMaxScrollY = 0;
+ _noOracleScroll = 0;
+ mouseOn();
+}
+
+void SimonEngine::o_closeWindow() {
+ // 104
+ closeWindow(getVarOrByte() & 7);
+}
+
+void SimonEngine::o_addBox() {
+ // 107: add item hitarea
+ uint flags = 0;
+ uint id = getVarOrWord();
+ uint params = id / 1000;
+ uint x, y, w, h, verb;
+ Item *item;
+
+ id = id % 1000;
+
+ if (params & 1)
+ flags |= kBFInvertTouch;
+ if (params & 2)
+ flags |= kBFNoTouchName;
+ if (params & 4)
+ flags |= kBFBoxItem;
+ if (params & 8)
+ flags |= kBFTextBox;
+ if (params & 16)
+ flags |= 0x10;
+
+ x = getVarOrWord();
+ y = getVarOrWord();
+ w = getVarOrWord();
+ h = getVarOrWord();
+ item = getNextItemPtrStrange();
+ verb = getVarOrWord();
+ if (x >= 1000) {
+ verb += 0x4000;
+ x -= 1000;
+ }
+ defineBox(id, x, y, w, h, flags, verb, item);
+}
+
+void SimonEngine::o_delBox() {
+ // 108: delete hitarea
+ undefineBox(getVarOrWord());
+}
+
+void SimonEngine::o_enableBox() {
+ // 109: clear hitarea bit 0x40
+ enableBox(getVarOrWord());
+}
+
+void SimonEngine::o_disableBox() {
+ // 110: set hitarea bit 0x40
+ disableBox(getVarOrWord());
+}
+
+void SimonEngine::o_moveBox() {
+ // 111: set hitarea xy
+ uint hitarea_id = getVarOrWord();
+ uint x = getVarOrWord();
+ uint y = getVarOrWord();
+ moveBox(hitarea_id, x, y);
+}
+
+void SimonEngine::o_doIcons() {
+ // 114
+ Item *item = getNextItemPtr();
+ uint num = getVarOrByte();
+ mouseOff();
+ drawIconArray(num, item, 0, 0);
+ mouseOn();
+}
+
+void SimonEngine::o_isClass() {
+ // 115: item has flag
+ Item *item = getNextItemPtr();
+ setScriptCondition((item->classFlags & (1 << getVarOrByte())) != 0);
+}
+
+void SimonEngine::o_setClass() {
+ // 116: item set flag
+ Item *item = getNextItemPtr();
+ item->classFlags |= (1 << getVarOrByte());
+}
+
+void SimonEngine::o_unsetClass() {
+ // 117: item clear flag
+ Item *item = getNextItemPtr();
+ item->classFlags &= ~(1 << getVarOrByte());
+}
+
+void SimonEngine::o_waitSync() {
+ // 119: wait vga
+ uint var = getVarOrWord();
+ _scriptVar2 = (var == 200);
+
+ if (var != 200 || !_skipVgaWait)
+ waitForSync(var);
+ _skipVgaWait = false;
+}
+
+void SimonEngine::o_sync() {
+ // 120: sync
+ sendSync(getVarOrWord());
+}
+
+void SimonEngine::o_defObj() {
+ // 121: set vga item
+ uint slot = getVarOrByte();
+ _objectArray[slot] = getNextItemPtr();
+}
+
+void SimonEngine::o_here() {
+ // 125: item is sibling with item 1
+ Item *item = getNextItemPtr();
+ setScriptCondition(me()->parent == item->parent);
+}
+
+void SimonEngine::o_doClassIcons() {
+ // 126
+ Item *item = getNextItemPtr();
+ uint num = getVarOrByte();
+ uint a = 1 << getVarOrByte();
+ mouseOff();
+ drawIconArray(num, item, 1, a);
+ mouseOn();
+}
+
+void SimonEngine::o_waitEndTune() {
+ // 128: dummy instruction
+ getVarOrWord();
+}
+
+void SimonEngine::o_ifEndTune() {
+ // 129: dummy instruction
+ getVarOrWord();
+ setScriptCondition(true);
+}
+
+void SimonEngine::o_setAdjNoun() {
+ // 130: set adj noun
+ uint var = getVarOrByte();
+ if (var == 1) {
+ _scriptAdj1 = getNextWord();
+ _scriptNoun1 = getNextWord();
+ } else {
+ _scriptAdj2 = getNextWord();
+ _scriptNoun2 = getNextWord();
+ }
+}
+
+void SimonEngine::o_saveUserGame() {
+ // 132: save game
+ _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true);
+ userGame(false);
+ _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
+}
+
+void SimonEngine::o_loadUserGame() {
+ // 133: load game
+ _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true);
+ userGame(true);
+ _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
+}
+
+void SimonEngine::o_stopTune() {
+ // 134: dummy opcode?
+ midi.stop();
+ _lastMusicPlayed = -1;
+}
+
+void SimonEngine::o_pauseGame() {
+ // 135: quit if user presses y
+ _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true);
+
+ // If all else fails, use English as fallback.
+ byte keyYes = 'y';
+ byte keyNo = 'n';
+
+ switch (_language) {
+ case Common::RU_RUS:
+ break;
+ case Common::PL_POL:
+ keyYes = 't';
+ break;
+ case Common::HB_ISR:
+ keyYes = 'f';
+ break;
+ case Common::ES_ESP:
+ keyYes = 's';
+ break;
+ case Common::IT_ITA:
+ keyYes = 's';
+ break;
+ case Common::FR_FRA:
+ keyYes = 'o';
+ break;
+ case Common::DE_DEU:
+ keyYes = 'j';
+ break;
+ default:
+ break;
+ }
+
+ for (;;) {
+ delay(1);
+#ifdef _WIN32_WCE
+ if (isSmartphone()) {
+ if (_keyPressed) {
+ if (_keyPressed == 13)
+ shutdown();
+ else
+ break;
+ }
+ }
+#endif
+ if (_keyPressed == keyYes || _keyPressed == (keyYes - 32))
+ shutdown();
+ else if (_keyPressed == keyNo || _keyPressed == (keyNo - 32))
+ break;
+ }
+
+ _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
+}
+
+void SimonEngine::o_copysf() {
+ // 136: set var to item unk3
+ Item *item = getNextItemPtr();
+ writeNextVarContents(item->state);
+}
+
+void SimonEngine::o_restoreIcons() {
+ // 137
+ uint num = getVarOrByte();
+ WindowBlock *window = _windowArray[num & 7];
+ if (window->iconPtr)
+ drawIconArray(num, window->iconPtr->itemRef, window->iconPtr->line, window->iconPtr->classMask);
+}
+
+void SimonEngine::o_freezeZones() {
+ // 138: vga pointer op 4
+ freezeBottom();
+}
+
+void SimonEngine::o_placeNoIcons() {
+ // 139: set parent special
+ Item *item = getNextItemPtr();
+ _noParentNotify = true;
+ setItemParent(item, getNextItemPtr());
+ _noParentNotify = false;
+}
+
+void SimonEngine::o_clearTimers() {
+ // 140: del te and add one
+ killAllTimers();
+ addTimeEvent(3, 0xA0);
+}
+
+void SimonEngine::o_setDollar() {
+ // 141: set m1 to m3
+ uint which = getVarOrByte();
+ Item *item = getNextItemPtr();
+ if (which == 1) {
+ _subjectItem = item;
+ } else {
+ _objectItem = item;
+ }
+}
+
+void SimonEngine::o_isBox() {
+ // 142: is hitarea 0x40 clear
+ setScriptCondition(isBoxDead(getVarOrWord()));
+}
+
+void SimonEngine::o_doTable() {
+ // 143: start item sub
+ SubRoom *subRoom = (SubRoom *)findChildOfType(getNextItemPtr(), 1);
+ if (subRoom != NULL) {
+ Subroutine *sub = getSubroutineByID(subRoom->subroutine_id);
+ if (sub)
+ startSubroutine(sub);
+ }
+}
+
+void SimonEngine::o_storeItem() {
+ // 151: set array6 to item
+ uint var = getVarOrByte();
+ Item *item = getNextItemPtr();
+ _itemStore[var] = item;
+}
+
+void SimonEngine::o_getItem() {
+ // 152: set m1 to m3 to array 6
+ Item *item = _itemStore[getVarOrByte()];
+ uint var = getVarOrByte();
+ if (var == 1) {
+ _subjectItem = item;
+ } else {
+ _objectItem = item;
+ }
+}
+
+void SimonEngine::o_bSet() {
+ // 153: set bit
+ setBitFlag(getVarWrapper(), true);
+}
+
+void SimonEngine::o_bClear() {
+ // 154: clear bit
+ setBitFlag(getVarWrapper(), false);
+}
+
+void SimonEngine::o_bZero() {
+ // 155: is bit clear
+ setScriptCondition(!getBitFlag(getVarWrapper()));
+}
+
+void SimonEngine::o_bNotZero() {
+ // 156: is bit set
+ uint bit = getVarWrapper();
+
+ // WORKAROUND: Fix for glitch in some versions
+ if (getGameType() == GType_SIMON1 && _subroutine == 2962 && bit == 63) {
+ bit = 50;
+ }
+
+ setScriptCondition(getBitFlag(bit));
+}
+
+void SimonEngine::o_getOValue() {
+ // 157: get item int prop
+ Item *item = getNextItemPtr();
+ SubObject *subObject = (SubObject *)findChildOfType(item, 2);
+ uint prop = getVarOrByte();
+
+ if (subObject != NULL && subObject->objectFlags & (1 << prop) && prop < 16) {
+ uint offs = getOffsetOfChild2Param(subObject, 1 << prop);
+ writeNextVarContents(subObject->objectFlagValue[offs]);
+ } else {
+ writeNextVarContents(0);
+ }
+}
+
+void SimonEngine::o_setOValue() {
+ // 158: set item prop
+ Item *item = getNextItemPtr();
+ SubObject *subObject = (SubObject *)findChildOfType(item, 2);
+ uint prop = getVarOrByte();
+ int value = getVarOrWord();
+
+ if (subObject != NULL && subObject->objectFlags & (1 << prop) && prop < 16) {
+ uint offs = getOffsetOfChild2Param(subObject, 1 << prop);
+ subObject->objectFlagValue[offs] = value;
+ }
+}
+
+void SimonEngine::o_ink() {
+ // 160
+ setTextColor(getVarOrByte());
+}
+
+void SimonEngine::o_screenTextBox() {
+ // 161: setup text
+ TextLocation *tl = getTextLocation(getVarOrByte());
+
+ tl->x = getVarOrWord();
+ tl->y = getVarOrByte();
+ tl->width = getVarOrWord();
+}
+
+void SimonEngine::o_screenTextMsg() {
+ // 162: print string
+ uint vgaSpriteId = getVarOrByte();
+ uint color = getVarOrByte();
+ uint stringId = getNextStringID();
+ const byte *string_ptr = NULL;
+ uint speechId = 0;
+ TextLocation *tl;
+
+ if (stringId != 0xFFFF)
+ string_ptr = getStringPtrByID(stringId);
+
+ if (getFeatures() & GF_TALKIE) {
+ if (getGameType() == GType_FF || getGameType() == GType_PP)
+ speechId = (uint16)getVarOrWord();
+ else
+ speechId = (uint16)getNextWord();
+ }
+
+ if (getGameType() == GType_FF || getGameType() == GType_PP)
+ vgaSpriteId = 1;
+
+ tl = getTextLocation(vgaSpriteId);
+ if (_speech && speechId != 0)
+ playSpeech(speechId, vgaSpriteId);
+ if (((getGameType() == GType_SIMON2 && (getFeatures() & GF_TALKIE)) || getGameType() == GType_FF) &&
+ speechId == 0) {
+ stopAnimateSimon2(2, vgaSpriteId + 2);
+ }
+
+ if (string_ptr != NULL && (speechId == 0 || _subtitles))
+ printScreenText(vgaSpriteId, color, (const char *)string_ptr, tl->x, tl->y, tl->width);
+
+}
+
+void SimonEngine::o_playEffect() {
+ // 163: play sound
+ uint soundId = getVarOrWord();
+
+ if (getGameType() == GType_FF)
+ error("o_playEffect: triggered");
+
+ if (getGameId() == GID_SIMON1DOS)
+ playSting(soundId);
+ else
+ _sound->playEffects(soundId);
+}
+
+void SimonEngine::o_getDollar2() {
+ // 164
+ _showPreposition = true;
+
+ setup_cond_c_helper();
+
+ _objectItem = _hitAreaObjectItem;
+
+ if (_objectItem == _dummyItem2)
+ _objectItem = me();
+
+ if (_objectItem == _dummyItem3)
+ _objectItem = derefItem(me()->parent);
+
+ if (_objectItem != NULL) {
+ _scriptNoun2 = _objectItem->noun;
+ _scriptAdj2 = _objectItem->adjective;
+ } else {
+ _scriptNoun2 = -1;
+ _scriptAdj2 = -1;
+ }
+
+ _showPreposition = false;
+}
+
+void SimonEngine::o_isAdjNoun() {
+ // 165: item unk1 unk2 is
+ Item *item = getNextItemPtr();
+ int16 a = getNextWord(), b = getNextWord();
+ setScriptCondition(item->adjective == a && item->noun == b);
+}
+
+void SimonEngine::o_b2Set() {
+ // 166: set bit2
+ uint bit = getVarOrByte();
+ _bitArrayTwo[bit / 16] |= (1 << (bit & 15));
+}
+
+void SimonEngine::o_b2Clear() {
+ // 167: clear bit2
+ uint bit = getVarOrByte();
+ _bitArrayTwo[bit / 16] &= ~(1 << (bit & 15));
+}
+
+void SimonEngine::o_b2Zero() {
+ // 168: is bit2 clear
+ uint bit = getVarOrByte();
+ setScriptCondition((_bitArrayTwo[bit / 16] & (1 << (bit & 15))) == 0);
+}
+
+void SimonEngine::o_b2NotZero() {
+ // 169: is bit2 set
+ uint bit = getVarOrByte();
+ setScriptCondition((_bitArrayTwo[bit / 16] & (1 << (bit & 15))) != 0);
+}
+
+void SimonEngine::o_lockZones() {
+ // 175: vga pointer op 1
+ _vgaMemBase = _vgaMemPtr;
+}
+
+void SimonEngine::o_unlockZones() {
+ // 176: vga pointer op 2
+ _vgaMemPtr = _vgaFrozenBase;
+ _vgaMemBase = _vgaFrozenBase;
+}
+
+void SimonEngine::o_getPathPosn() {
+ // 178: path find
+ uint x = getVarOrWord();
+ uint y = getVarOrWord();
+ uint var_1 = getVarOrByte();
+ uint var_2 = getVarOrByte();
+
+ const uint16 *p;
+ uint i, j;
+ uint prev_i;
+ uint x_diff, y_diff;
+ uint best_i = 0, best_j = 0, best_dist = 0xFFFFFFFF;
+ uint maxPath = (getGameType() == GType_FF) ? 100 : 20;
+
+ if (getGameType() == GType_FF) {
+ x += _scrollX;
+ y += _scrollY;
+ }
+ if (getGameType() == GType_SIMON2) {
+ x += _scrollX * 8;
+ }
+
+ int end = (getGameType() == GType_FF) ? 9999 : 999;
+ prev_i = maxPath + 1 - readVariable(12);
+ for (i = maxPath; i != 0; --i) {
+ p = (const uint16 *)_pathFindArray[maxPath - i];
+ if (!p)
+ continue;
+ for (j = 0; readUint16Wrapper(&p[0]) != end; j++, p += 2) {
+ x_diff = ABS((int16)(readUint16Wrapper(&p[0]) - x));
+ y_diff = ABS((int16)(readUint16Wrapper(&p[1]) - 12 - y));
+
+ if (x_diff < y_diff) {
+ x_diff /= 4;
+ y_diff *= 4;
+ }
+ x_diff += y_diff /= 4;
+
+ if (x_diff < best_dist || x_diff == best_dist && prev_i == i) {
+ best_dist = x_diff;
+ best_i = maxPath + 1 - i;
+ best_j = j;
+ }
+ }
+ }
+
+ writeVariable(var_1, best_i);
+ writeVariable(var_2, best_j);
+}
+
+void SimonEngine::o_scnTxtLongText() {
+ // 179: conversation responses and room descriptions
+ uint vgaSpriteId = getVarOrByte();
+ uint color = getVarOrByte();
+ uint stringId = getVarOrByte();
+ uint speechId = 0;
+ TextLocation *tl;
+
+ const char *string_ptr = (const char *)getStringPtrByID(_longText[stringId]);
+ if (getFeatures() & GF_TALKIE)
+ speechId = _longSound[stringId];
+
+ if (getGameType() == GType_FF)
+ vgaSpriteId = 1;
+ tl = getTextLocation(vgaSpriteId);
+
+ if (_speech && speechId != 0)
+ playSpeech(speechId, vgaSpriteId);
+ if (string_ptr != NULL && _subtitles)
+ printScreenText(vgaSpriteId, color, string_ptr, tl->x, tl->y, tl->width);
+}
+
+void SimonEngine::o_mouseOn() {
+ // 180: force mouseOn
+ scriptMouseOn();
+}
+
+void SimonEngine::o_unloadZone() {
+ // 184: clear vgapointer entry
+ uint a = getVarOrWord();
+ VgaPointersEntry *vpe = &_vgaBufferPointers[a];
+
+ vpe->sfxFile = NULL;
+ vpe->vgaFile1 = NULL;
+ vpe->vgaFile2 = NULL;
+}
+
+void SimonEngine::o_unfreezeZones() {
+ // 186: vga pointer op 3
+ unfreezeBottom();
+}
+
+// -----------------------------------------------------------------------
+// Waxworks 1 Opcodes
+// -----------------------------------------------------------------------
+
+void SimonEngine::oww_whereTo() {
+ // 85: where to
+ Item *i = getNextItemPtr();
+ int16 d = getVarOrByte();
+ int16 f = getVarOrByte();
+
+ if (f == 1)
+ _subjectItem = _itemArrayPtr[getExitOf(i, d)];
+ else
+ _objectItem = _itemArrayPtr[getExitOf(i, d)];
+}
+
+void SimonEngine::oww_menu() {
+ // 105: menu
+ getVarOrByte();
+}
+
+void SimonEngine::oww_textMenu() {
+ // 106: text menu
+
+ /* byte tmp = getVarOrByte();
+ TextMenu[tmp] = getVarOrByte(); */
+
+ getVarOrByte();
+ getVarOrByte();
+}
+
+void SimonEngine::oww_ifDoorOpen() {
+ // 148: if door open
+ Item *item = getNextItemPtr();
+ uint16 d = getVarOrByte();
+ setScriptCondition(getDoorState(item, d) != 0);
+}
+
+// -----------------------------------------------------------------------
+// Simon 1 Opcodes
+// -----------------------------------------------------------------------
+
+void SimonEngine::o1_printLongText() {
+ // 70: show string from array
+ const char *str = (const char *)getStringPtrByID(_longText[getVarOrByte()]);
+ showMessageFormat("%s\n", str);
+}
+
+void SimonEngine::o1_rescan() {
+ // 83: restart subroutine
+ setScriptReturn(-10);
+}
+
+void SimonEngine::o1_animate() {
+ // 98: start vga
+ uint vga_res, vgaSpriteId, windowNum, x, y, palette;
+ vgaSpriteId = getVarOrWord();
+ vga_res = vgaSpriteId / 100;
+ windowNum = getVarOrByte();
+ x = getVarOrWord();
+ y = getVarOrWord();
+ palette = getVarOrWord();
+ loadSprite(windowNum, vga_res, vgaSpriteId, x, y, palette);
+}
+
+void SimonEngine::o1_stopAnimate() {
+ // 99: kill sprite
+ stopAnimateSimon1(getVarOrWord());
+}
+
+void SimonEngine::o1_playTune() {
+ // 127: deals with music
+ int music = getVarOrWord();
+ int track = getVarOrWord();
+
+ // Jamieson630:
+ // This appears to be a "load or play music" command.
+ // The music resource is specified, and optionally
+ // a track as well. Normally we see two calls being
+ // made, one to load the resource and another to
+ // actually start a track (so the resource is
+ // effectively preloaded so there's no latency when
+ // starting playback).
+
+ if (music != _lastMusicPlayed) {
+ _lastMusicPlayed = music;
+ loadMusic(music);
+ midi.startTrack(track);
+ }
+}
+
+void SimonEngine::o1_screenTextPObj() {
+ // 177: inventory descriptions
+ uint vgaSpriteId = getVarOrByte();
+ uint color = getVarOrByte();
+
+ SubObject *subObject = (SubObject *)findChildOfType(getNextItemPtr(), 2);
+ if (getFeatures() & GF_TALKIE) {
+ if (subObject != NULL && subObject->objectFlags & kOFVoice) {
+ uint offs = getOffsetOfChild2Param(subObject, kOFVoice);
+ playSpeech(subObject->objectFlagValue[offs], vgaSpriteId);
+ } else if (subObject != NULL && subObject->objectFlags & kOFNumber) {
+ uint offs = getOffsetOfChild2Param(subObject, kOFNumber);
+ playSpeech(subObject->objectFlagValue[offs] + 3550, vgaSpriteId);
+ }
+ }
+
+ if (subObject != NULL && subObject->objectFlags & kOFText && _subtitles) {
+ const char *stringPtr = (const char *)getStringPtrByID(subObject->objectFlagValue[0]);
+ TextLocation *tl = getTextLocation(vgaSpriteId);
+ char buf[256];
+ int j, k;
+
+ if (subObject->objectFlags & kOFNumber) {
+ if (_language == Common::HB_ISR) {
+ j = subObject->objectFlagValue[getOffsetOfChild2Param(subObject, kOFNumber)];
+ k = (j % 10) * 10;
+ k += j / 10;
+ if (!(j % 10))
+ sprintf(buf,"0%d%s", k, stringPtr);
+ else
+ sprintf(buf,"%d%s", k, stringPtr);
+ } else {
+ sprintf(buf,"%d%s", subObject->objectFlagValue[getOffsetOfChild2Param(subObject, kOFNumber)], stringPtr);
+ }
+ stringPtr = buf;
+ }
+ if (stringPtr != NULL)
+ printScreenText(vgaSpriteId, color, stringPtr, tl->x, tl->y, tl->width);
+ }
+}
+
+void SimonEngine::o1_mouseOff() {
+ // 181: force mouseOff
+ scriptMouseOff();
+}
+
+void SimonEngine::o1_loadBeard() {
+ // 182: load beard
+ if (_beardLoaded == false) {
+ _beardLoaded = true;
+ _lockWord |= 0x8000;
+ loadSimonVGAFile(328);
+ _lockWord &= ~0x8000;
+ }
+}
+
+void SimonEngine::o1_unloadBeard() {
+ // 183: unload beard
+ if (_beardLoaded == true) {
+ _beardLoaded = false;
+ _lockWord |= 0x8000;
+ loadSimonVGAFile(23);
+ _lockWord &= ~0x8000;
+ }
+}
+
+void SimonEngine::o1_loadStrings() {
+ // 185: load sound files
+ _soundFileId = getVarOrWord();
+ if (getPlatform() == Common::kPlatformAmiga && getFeatures() & GF_TALKIE) {
+ char buf[10];
+ sprintf(buf, "%d%s", _soundFileId, "Effects");
+ _sound->readSfxFile(buf);
+ sprintf(buf, "%d%s", _soundFileId, "simon");
+ _sound->readVoiceFile(buf);
+ }
+}
+
+void SimonEngine::o1_specialFade() {
+ // 187: fade to black
+ uint i;
+
+ memcpy(_videoBuf1, _currentPalette, 4 * 256);
+
+ for (i = 32; i != 0; --i) {
+ paletteFadeOut(_videoBuf1, 32, 8);
+ paletteFadeOut(_videoBuf1 + 4 * 48, 144, 8);
+ paletteFadeOut(_videoBuf1 + 4 * 208, 48, 8);
+ _system->setPalette(_videoBuf1, 0, 256);
+ delay(5);
+ }
+
+ memcpy(_currentPalette, _videoBuf1, 1024);
+ memcpy(_displayPalette, _videoBuf1, 1024);
+}
+
+// -----------------------------------------------------------------------
+// Simon 2 Opcodes
+// -----------------------------------------------------------------------
+
+void SimonEngine::o2_printLongText() {
+ // 70: show string from array
+ const char *str = (const char *)getStringPtrByID(_longText[getVarOrByte()]);
+ writeVariable(51, strlen(str) / 53 * 8 + 8);
+ showMessageFormat("%s\n", str);
+}
+
+void SimonEngine::o2_rescan() {
+ // 83: restart subroutine
+ if (_exitCutscene) {
+ if (getBitFlag(9)) {
+ endCutscene();
+ }
+ } else {
+ processSpecialKeys();
+ }
+
+ setScriptReturn(-10);
+}
+
+void SimonEngine::o2_animate() {
+ // 98: start vga
+ uint vga_res = getVarOrWord();
+ uint vgaSpriteId = getVarOrWord();
+ uint windowNum = getVarOrByte();
+ uint x = getVarOrWord();
+ uint y = getVarOrWord();
+ uint palette = getVarOrWord();
+ loadSprite(windowNum, vga_res, vgaSpriteId, x, y, palette);
+}
+
+void SimonEngine::o2_stopAnimate() {
+ // 99: kill sprite
+ uint a = getVarOrWord();
+ uint b = getVarOrWord();
+ stopAnimateSimon2(a, b);
+}
+
+void SimonEngine::o2_playTune() {
+ // 127: deals with music
+ int music = getVarOrWord();
+ int track = getVarOrWord();
+ int loop = getVarOrByte();
+
+ // Jamieson630:
+ // This appears to be a "load or play music" command.
+ // The music resource is specified, and optionally
+ // a track as well. Normally we see two calls being
+ // made, one to load the resource and another to
+ // actually start a track (so the resource is
+ // effectively preloaded so there's no latency when
+ // starting playback).
+
+ midi.setLoop(loop != 0);
+ if (_lastMusicPlayed != music)
+ _nextMusicToPlay = music;
+ else
+ midi.startTrack(track);
+}
+
+void SimonEngine::o2_screenTextPObj() {
+ // 177: inventory descriptions
+ uint vgaSpriteId = getVarOrByte();
+ uint color = getVarOrByte();
+
+ SubObject *subObject = (SubObject *)findChildOfType(getNextItemPtr(), 2);
+ if (getFeatures() & GF_TALKIE) {
+ if (subObject != NULL && subObject->objectFlags & kOFVoice) {
+ uint speechId = subObject->objectFlagValue[getOffsetOfChild2Param(subObject, kOFVoice)];
+
+ if (subObject->objectFlags & kOFNumber) {
+ uint speechIdOffs = subObject->objectFlagValue[getOffsetOfChild2Param(subObject, kOFNumber)];
+
+ if (speechId == 116)
+ speechId = speechIdOffs + 115;
+ if (speechId == 92)
+ speechId = speechIdOffs + 98;
+ if (speechId == 99)
+ speechId = 9;
+ if (speechId == 97) {
+ switch (speechIdOffs) {
+ case 12:
+ speechId = 109;
+ break;
+ case 14:
+ speechId = 108;
+ break;
+ case 18:
+ speechId = 107;
+ break;
+ case 20:
+ speechId = 106;
+ break;
+ case 22:
+ speechId = 105;
+ break;
+ case 28:
+ speechId = 104;
+ break;
+ case 90:
+ speechId = 103;
+ break;
+ case 92:
+ speechId = 102;
+ break;
+ case 100:
+ speechId = 51;
+ break;
+ default:
+ error("o2_screenTextPObj: invalid case %d", speechIdOffs);
+ }
+ }
+ }
+
+ if (_speech)
+ playSpeech(speechId, vgaSpriteId);
+ }
+
+ }
+
+ if (subObject != NULL && subObject->objectFlags & kOFText && _subtitles) {
+ const char *stringPtr = (const char *)getStringPtrByID(subObject->objectFlagValue[0]);
+ TextLocation *tl = getTextLocation(vgaSpriteId);
+ char buf[256];
+ int j, k;
+
+ if (subObject->objectFlags & kOFNumber) {
+ if (_language == Common::HB_ISR) {
+ j = subObject->objectFlagValue[getOffsetOfChild2Param(subObject, kOFNumber)];
+ k = (j % 10) * 10;
+ k += j / 10;
+ if (!(j % 10))
+ sprintf(buf,"0%d%s", k, stringPtr);
+ else
+ sprintf(buf,"%d%s", k, stringPtr);
+ } else {
+ sprintf(buf,"%d%s", subObject->objectFlagValue[getOffsetOfChild2Param(subObject, kOFNumber)], stringPtr);
+ }
+ stringPtr = buf;
+ }
+ if (stringPtr != NULL)
+ printScreenText(vgaSpriteId, color, stringPtr, tl->x, tl->y, tl->width);
+ }
+}
+
+void SimonEngine::o2_mouseOff() {
+ // 181: force mouseOff
+ scriptMouseOff();
+ changeWindow(1);
+ showMessageFormat("\xC");
+}
+
+void SimonEngine::o2_isShortText() {
+ // 188: string2 is
+ uint i = getVarOrByte();
+ uint str = getNextStringID();
+ setScriptCondition(str < _numTextBoxes && _shortText[i] == str);
+}
+
+void SimonEngine::o2_clearMarks() {
+ // 189: clear_op189_flag
+ _marks = 0;
+}
+
+void SimonEngine::o2_waitMark() {
+ // 190
+ uint i = getVarOrByte();
+ if (!(_marks & (1 << i)))
+ waitForMark(i);
+}
+
+// -----------------------------------------------------------------------
+// Feeble Files Opcodes
+// -----------------------------------------------------------------------
+
+void SimonEngine::o3_chance() {
+ // 23
+ uint a = getVarOrWord();
+
+ if (a == 0) {
+ setScriptCondition(false);
+ return;
+ }
+
+ if (a == 100) {
+ setScriptCondition(true);
+ return;
+ }
+
+ if ((uint)_rnd.getRandomNumber(99) < a)
+ setScriptCondition(true);
+ else
+ setScriptCondition(false);
+}
+
+void SimonEngine::o3_jumpOut() {
+ // 37
+ getVarOrByte();
+ setScriptReturn(1);
+}
+
+void SimonEngine::o3_addTextBox() {
+ // 65: add hit area
+ uint flags = kBFTextBox | kBFBoxItem;
+ uint id = getVarOrWord();
+ uint params = id / 1000;
+ uint x, y, w, h, num;
+
+ id %= 1000;
+
+ if (params & 1)
+ flags |= kBFInvertTouch;
+
+ x = getVarOrWord();
+ y = getVarOrWord();
+ w = getVarOrWord();
+ h = getVarOrWord();
+ num = getVarOrByte();
+ if (num < _numTextBoxes)
+ defineBox(id, x, y, w, h, flags + (num << 8), 208, _dummyItem2);
+}
+
+void SimonEngine::o3_printLongText() {
+ // 70: show string from array
+ int num = getVarOrByte();
+ const char *str = (const char *)getStringPtrByID(_longText[num]);
+ sendInteractText(num, "%d. %s\n", num, str);
+}
+
+void SimonEngine::o3_addBox() {
+ // 107: add item hitarea
+ uint flags = 0;
+ uint id = getVarOrWord();
+ uint params = id / 1000;
+ uint x, y, w, h, verb;
+ Item *item;
+
+ id = id % 1000;
+
+ if (params & 1)
+ flags |= kBFInvertTouch;
+ if (params & 2)
+ flags |= kBFNoTouchName;
+ if (params & 4)
+ flags |= kBFBoxItem;
+ if (params & 8)
+ flags |= kBFTextBox;
+ if (params & 16)
+ flags |= 0x10;
+
+ x = getVarOrWord();
+ y = getVarOrWord();
+ w = getVarOrWord();
+ h = getVarOrWord();
+ item = getNextItemPtrStrange();
+ verb = getVarOrWord();
+ defineBox(id, x, y, w, h, flags, verb, item);
+}
+
+void SimonEngine::o3_oracleTextDown() {
+ // 122: oracle text down
+ oracleTextDown();
+}
+
+void SimonEngine::o3_oracleTextUp() {
+ // 123: oracle text up
+ oracleTextUp();
+}
+
+void SimonEngine::o3_ifTime() {
+ // 124: if time
+ time_t t;
+
+ uint a = getVarOrWord();
+ time(&t);
+ t -= _gameStoppedClock;
+ t -= a;
+ if (t >= _timeStore)
+ setScriptCondition(true);
+ else
+ setScriptCondition(false);
+}
+
+void SimonEngine::o3_playTune() {
+ // 127: usually deals with music, but is a no-op in FF.
+ getVarOrWord();
+ getVarOrWord();
+ getVarOrByte();
+}
+
+void SimonEngine::o3_setTime() {
+ // 131
+ time(&_timeStore);
+ _timeStore -= _gameStoppedClock;
+}
+
+void SimonEngine::o3_saveUserGame() {
+ // 132: save game
+ _noOracleScroll = 0;
+ _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true);
+ saveUserGame(countSaveGames() + 1 - readVariable(55));
+ _system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
+}
+
+void SimonEngine::o3_loadUserGame() {
+ // 133: load game
+ loadGame(readVariable(55));
+}
+
+void SimonEngine::o3_listSaveGames() {
+ // 134: dummy opcode?
+ listSaveGames(1);
+}
+
+void SimonEngine::o3_checkCD() {
+ // 135: switch CD
+ uint disc = readVariable(97);
+
+ if (!strcmp(_gameDescription->extra, "4CD")) {
+ _sound->switchVoiceFile(gss, disc);
+ } else if (!strcmp(_gameDescription->extra, "2CD")) {
+ if (disc == 1 || disc == 2)
+ _sound->switchVoiceFile(gss, 1);
+ else if (disc == 3 || disc == 4)
+ _sound->switchVoiceFile(gss, 2);
+ }
+
+ debug(0, "Switch to CD number %d", disc);
+}
+
+void SimonEngine::o3_screenTextBox() {
+ // 161: setup text
+ TextLocation *tl = getTextLocation(getVarOrByte());
+
+ tl->x = getVarOrWord();
+ tl->y = getVarOrWord();
+ tl->width = getVarOrWord();
+}
+
+void SimonEngine::o3_isAdjNoun() {
+ // 165: item unk1 unk2 is
+ Item *item = getNextItemPtr();
+ int16 a = getNextWord(), b = getNextWord();
+ if (item->adjective == a && item->noun == b)
+ setScriptCondition(true);
+ else if (a == -1 && item->noun == b)
+ setScriptCondition(true);
+ else
+ setScriptCondition(false);
+}
+
+void SimonEngine::o3_hyperLinkOn() {
+ // 171: oracle hyperlink on
+ hyperLinkOn(getVarOrWord());
+}
+
+void SimonEngine::o3_hyperLinkOff() {
+ // 172: oracle hyperlink off
+ hyperLinkOff();
+}
+
+void SimonEngine::o3_checkPaths() {
+ // 173 check paths
+ int i, count;
+ const uint8 *pathVal1 = _pathValues1;
+ bool result = false;
+
+ count = _variableArray2[38];
+ for (i = 0; i < count; i++) {
+ uint8 val = pathVal1[2];
+ if (val == _variableArray2[50] ||
+ val == _variableArray2[51] ||
+ val == _variableArray2[201] ||
+ val == _variableArray2[203] ||
+ val == _variableArray2[205] ||
+ val == _variableArray2[207] ||
+ val == _variableArray2[209] ||
+ val == _variableArray2[211] ||
+ val == _variableArray2[213] ||
+ val == _variableArray2[215] ||
+ val == _variableArray2[219] ||
+ val == _variableArray2[220] ||
+ val == _variableArray2[221] ||
+ val == _variableArray2[222] ||
+ val == _variableArray2[223] ||
+ val == _variableArray2[224] ||
+ val == _variableArray2[225] ||
+ val == _variableArray2[226]) {
+ result = true;
+ break;
+ }
+ pathVal1 += 4;
+ }
+
+ _variableArray2[52] = result;
+}
+
+void SimonEngine::o3_screenTextPObj() {
+ // 177: inventory descriptions
+ uint vgaSpriteId = getVarOrByte();
+ uint color = getVarOrByte();
+ const char *string_ptr = NULL;
+ TextLocation *tl = NULL;
+ char buf[256];
+
+ SubObject *subObject = (SubObject *)findChildOfType(getNextItemPtr(), 2);
+ if (subObject != NULL && subObject->objectFlags & kOFText) {
+ string_ptr = (const char *)getStringPtrByID(subObject->objectFlagValue[0]);
+ tl = getTextLocation(vgaSpriteId);
+ }
+
+ if (subObject != NULL && subObject->objectFlags & kOFVoice) {
+ uint offs = getOffsetOfChild2Param(subObject, kOFVoice);
+ playSpeech(subObject->objectFlagValue[offs], vgaSpriteId);
+ }
+
+ if (subObject != NULL && (subObject->objectFlags & kOFText) && _subtitles) {
+ if (subObject->objectFlags & kOFNumber) {
+ sprintf(buf, "%d%s", subObject->objectFlagValue[getOffsetOfChild2Param(subObject, kOFNumber)], string_ptr);
+ string_ptr = buf;
+ }
+ if (string_ptr != NULL)
+ printScreenText(vgaSpriteId, color, string_ptr, tl->x, tl->y, tl->width);
+ }
+}
+
+void SimonEngine::o3_mouseOff() {
+ // 181: force mouseOff
+ scriptMouseOff();
+ clearName();
+}
+
+void SimonEngine::o3_loadVideo() {
+ // 182: load video file
+ const byte *filename = getStringPtrByID(getNextStringID());
+ _moviePlay->load((const char *)filename);
+}
+
+void SimonEngine::o3_playVideo() {
+ // 183: play video
+ _moviePlay->play();
+}
+
+void SimonEngine::o3_centreScroll() {
+ // 187
+ centreScroll();
+}
+
+void SimonEngine::o3_resetPVCount() {
+ // 191
+ if (getBitFlag(83)) {
+ _PVCount1 = 0;
+ _GPVCount1 = 0;
+ } else {
+ _PVCount = 0;
+ _GPVCount = 0;
+ }
+}
+
+void SimonEngine::o3_setPathValues() {
+ // 192
+ uint8 a = getVarOrByte();
+ uint8 b = getVarOrByte();
+ uint8 c = getVarOrByte();
+ uint8 d = getVarOrByte();
+ if (getBitFlag(83)) {
+ _pathValues1[_PVCount1++] = a;
+ _pathValues1[_PVCount1++] = b;
+ _pathValues1[_PVCount1++] = c;
+ _pathValues1[_PVCount1++] = d;
+ } else {
+ _pathValues[_PVCount++] = a;
+ _pathValues[_PVCount++] = b;
+ _pathValues[_PVCount++] = c;
+ _pathValues[_PVCount++] = d;
+ }
+}
+
+void SimonEngine::o3_stopClock() {
+ // 193: pause clock
+ _clockStopped = time(NULL);
+}
+
+void SimonEngine::o3_restartClock() {
+ // 194: resume clock
+ if (_clockStopped != 0)
+ _gameStoppedClock += time(NULL) - _clockStopped;
+ _clockStopped = 0;
+}
+
+void SimonEngine::o3_setColour() {
+ // 195: set palette colour
+ uint c = getVarOrByte() * 4;
+ uint r = getVarOrByte();
+ uint g = getVarOrByte();
+ uint b = getVarOrByte();
+
+ _displayPalette[c + 0] = r;
+ _displayPalette[c + 1] = g;
+ _displayPalette[c + 2] = b;
+
+ _paletteFlag = 2;
+}
+
+void SimonEngine::o3_b3Set() {
+ // 196: set bit3
+ uint bit = getVarOrByte();
+ _bitArrayThree[bit / 16] |= (1 << (bit & 15));
+}
+
+void SimonEngine::o3_b3Clear() {
+ // 197: clear bit3
+ uint bit = getVarOrByte();
+ _bitArrayThree[bit / 16] &= ~(1 << (bit & 15));
+}
+
+void SimonEngine::o3_b3Zero() {
+ // 198: is bit3 clear
+ uint bit = getVarOrByte();
+ setScriptCondition((_bitArrayThree[bit / 16] & (1 << (bit & 15))) == 0);
+}
+
+void SimonEngine::o3_b3NotZero() {
+ // 199: is bit3 set
+ uint bit = getVarOrByte();
+ setScriptCondition((_bitArrayThree[bit / 16] & (1 << (bit & 15))) != 0);
+}
+
+// -----------------------------------------------------------------------
+// Puzzle Pack Opcodes
+// -----------------------------------------------------------------------
+
+void SimonEngine::o4_opcode30() {
+ // 30
+ getNextItemPtr();
+}
+
+void SimonEngine::o4_checkTiles() {
+ // 37: for MahJongg game
+ getVarOrByte();
+}
+
+void SimonEngine::o4_opcode38() {
+ // 38
+ getVarOrByte();
+ getNextItemPtr();
+}
+
+void SimonEngine::o4_loadHiScores() {
+ // 105
+ getVarOrByte();
+}
+
+void SimonEngine::o4_checkHiScores() {
+ // 106
+ getVarOrByte();
+ getVarOrByte();
+}
+
+void SimonEngine::o4_loadUserGame() {
+ // 133
+}
+
+void SimonEngine::o4_saveOopsPosition() {
+ // 173
+}
+
+void SimonEngine::o4_resetGameTime() {
+ // 187
+}
+
+void SimonEngine::o4_resetPVCount() {
+ // 191
+ _PVCount = 0;
+ _GPVCount = 0;
+}
+
+void SimonEngine::o4_setPathValues() {
+ // 192
+ _pathValues[_PVCount++] = getVarOrByte();
+ _pathValues[_PVCount++] = getVarOrByte();
+ _pathValues[_PVCount++] = getVarOrByte();
+ _pathValues[_PVCount++] = getVarOrByte();
+}
+
+// -----------------------------------------------------------------------
+
+int SimonEngine::runScript() {
+ int opcode;
+ bool flag;
+
+ do {
+ if (_continousMainScript)
+ dumpOpcode(_codePtr);
+
+ if (getGameType() == GType_ELVIRA || getGameType() == GType_ELVIRA2) {
+ opcode = getVarOrWord();
+ if (opcode == 10000)
+ return 0;
+ } else {
+ opcode = getByte();
+ if (opcode == 0xFF)
+ return 0;
+ }
+ debug(1, "runScript: opcode %d", opcode);
+
+ if (_runScriptReturn1)
+ return 1;
+
+ /* Invert condition? */
+ flag = false;
+ if (getGameType() == GType_ELVIRA || getGameType() == GType_ELVIRA2) {
+ if (opcode == 203) {
+ flag = true;
+ opcode = getVarOrWord();
+ if (opcode == 10000)
+ return 0;
+ }
+ } else {
+ if (opcode == 0) {
+ flag = true;
+ opcode = getByte();
+ if (opcode == 0xFF)
+ return 0;
+ }
+ }
+
+ setScriptCondition(true);
+ setScriptReturn(0);
+
+ if (opcode > _numOpcodes || !_opcode_table[opcode])
+ error("Invalid opcode '%d' encountered", opcode);
+
+ (this->*_opcode_table[opcode]) ();
+ } while (getScriptCondition() != flag && !getScriptReturn());
+
+ return getScriptReturn();
+}
+
+void SimonEngine::scriptMouseOn() {
+ if (getGameType() == GType_FF && _mouseCursor != 5) {
+ resetVerbs();
+ _noRightClick = 0;
+ }
+ if (getGameType() == GType_SIMON2 && getBitFlag(79)) {
+ _mouseCursor = 0;
+ }
+ _mouseHideCount = 0;
+}
+
+void SimonEngine::scriptMouseOff() {
+ _lockWord |= 0x8000;
+ vc34_setMouseOff();
+ _lockWord &= ~0x8000;
+}
+
+void SimonEngine::waitForMark(uint i) {
+ _exitCutscene = false;
+ while (!(_marks & (1 << i))) {
+ if (_exitCutscene) {
+ if (getBitFlag(9)) {
+ endCutscene();
+ break;
+ }
+ } else {
+ processSpecialKeys();
+ }
+
+ delay(10);
+ }
+}
+
+void SimonEngine::freezeBottom() {
+ _vgaMemBase = _vgaMemPtr;
+ _vgaFrozenBase = _vgaMemPtr;
+}
+
+void SimonEngine::unfreezeBottom() {
+ _vgaMemPtr = _vgaRealBase;
+ _vgaMemBase = _vgaRealBase;
+ _vgaFrozenBase = _vgaRealBase;
+}
+
+void SimonEngine::sendSync(uint a) {
+ uint16 id = to16Wrapper(a);
+ _lockWord |= 0x8000;
+ _vcPtr = (byte *)&id;
+ vc15_sync();
+ _lockWord &= ~0x8000;
+}
+
+void SimonEngine::setTextColor(uint color) {
+ WindowBlock *window;
+
+ window = _windowArray[_curWindow];
+ window->text_color = color;
+}
+
+void SimonEngine::stopAnimateSimon1(uint a) {
+ uint16 b = to16Wrapper(a);
+ _lockWord |= 0x8000;
+ _vcPtr = (byte *)&b;
+ vc60_killSprite();
+ _lockWord &= ~0x8000;
+}
+
+void SimonEngine::stopAnimateSimon2(uint a, uint b) {
+ uint16 items[2];
+
+ items[0] = to16Wrapper(a);
+ items[1] = to16Wrapper(b);
+
+ _lockWord |= 0x8000;
+ _vcPtr = (byte *)&items;
+ vc60_killSprite();
+ _lockWord &= ~0x8000;
+}
+
+} // End of namespace Simon
diff --git a/engines/agos/midi.cpp b/engines/agos/midi.cpp
new file mode 100644
index 0000000000..2ff9bbd8ad
--- /dev/null
+++ b/engines/agos/midi.cpp
@@ -0,0 +1,574 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-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/system.h"
+
+#include "agos/agos.h"
+
+#include "agos/agos.h"
+
+namespace Simon {
+
+
+// MidiParser_S1D is not considered part of the standard
+// MidiParser suite, but we still try to mask its details
+// and just provide a factory function.
+extern MidiParser *MidiParser_createS1D();
+
+MidiPlayer::MidiPlayer(OSystem *system) {
+ // Since initialize() is called every time the music changes,
+ // this is where we'll initialize stuff that must persist
+ // between songs.
+ _driver = 0;
+ _map_mt32_to_gm = false;
+ _passThrough = false;
+
+ _enable_sfx = true;
+ _current = 0;
+
+ _masterVolume = 255;
+ resetVolumeTable();
+ _paused = false;
+
+ _currentTrack = 255;
+ _loopTrack = 0;
+ _queuedTrack = 255;
+ _loopQueuedTrack = 0;
+}
+
+MidiPlayer::~MidiPlayer() {
+ _mutex.lock();
+ close();
+ _mutex.unlock();
+}
+
+int MidiPlayer::open() {
+ // Don't ever call open without first setting the output driver!
+ if (!_driver)
+ return 255;
+
+ int ret = _driver->open();
+ if (ret)
+ return ret;
+ _driver->setTimerCallback(this, &onTimer);
+ return 0;
+}
+
+void MidiPlayer::close() {
+ stop();
+// _system->lockMutex(_mutex);
+ if (_driver)
+ _driver->close();
+ _driver = NULL;
+ clearConstructs();
+// _system->unlockMutex(_mutex);
+}
+
+void MidiPlayer::send(uint32 b) {
+ if (!_current)
+ return;
+
+ if (_passThrough) {
+ _driver->send(b);
+ return;
+ }
+
+ byte channel = (byte)(b & 0x0F);
+ if ((b & 0xFFF0) == 0x07B0) {
+ // Adjust volume changes by master volume.
+ byte volume = (byte)((b >> 16) & 0x7F);
+ _current->volume[channel] = volume;
+ volume = volume * _masterVolume / 255;
+ b = (b & 0xFF00FFFF) | (volume << 16);
+ } else if ((b & 0xF0) == 0xC0 && _map_mt32_to_gm) {
+ b = (b & 0xFFFF00FF) | (MidiDriver::_mt32ToGm[(b >> 8) & 0xFF] << 8);
+ } else if ((b & 0xFFF0) == 0x007BB0) {
+ // Only respond to an All Notes Off if this channel
+ // has already been allocated.
+ if (!_current->channel[b & 0x0F])
+ return;
+ } else if ((b & 0xFFF0) == 0x79B0) {
+ // "Reset All Controllers". There seems to be some confusion
+ // about what this message should do to the volume controller.
+ // See http://www.midi.org/about-midi/rp15.shtml for more
+ // information.
+ //
+ // If I understand it correctly, the current standard indicates
+ // that the volume should be reset, but the next revision will
+ // exclude it. On my system, both ALSA and FluidSynth seem to
+ // reset it, while Adlib does not. Let's follow the majority.
+
+ _current->volume[channel] = 127;
+ }
+
+ if (!_current->channel[channel])
+ _current->channel[channel] = (channel == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel();
+ if (_current->channel[channel]) {
+ if (channel == 9)
+ _current->channel[9]->volume(_current->volume[9] * _masterVolume / 255);
+ _current->channel[channel]->send(b);
+ if ((b & 0xFFF0) == 0x79B0) {
+ // We have received a "Reset All Controllers" message
+ // and passed it on to the MIDI driver. This may or may
+ // not have affected the volume controller. To ensure
+ // consistent behaviour, explicitly set the volume to
+ // what we think it should be.
+
+ _current->channel[channel]->volume(_current->volume[channel] * _masterVolume / 255);
+ }
+ }
+}
+
+void MidiPlayer::metaEvent(byte type, byte *data, uint16 length) {
+ // Only thing we care about is End of Track.
+ if (!_current || type != 0x2F) {
+ return;
+ } else if (_current == &_sfx) {
+ clearConstructs(_sfx);
+ } else if (_loopTrack) {
+ _current->parser->jumpToTick(0);
+ } else if (_queuedTrack != 255) {
+ _currentTrack = 255;
+ byte destination = _queuedTrack;
+ _queuedTrack = 255;
+ _loopTrack = _loopQueuedTrack;
+ _loopQueuedTrack = false;
+
+ // Remember, we're still inside the locked mutex.
+ // Have to unlock it before calling jump()
+ // (which locks it itself), and then relock it
+ // upon returning.
+ _mutex.unlock();
+ startTrack(destination);
+ _mutex.lock();
+ } else {
+ stop();
+ }
+}
+
+void MidiPlayer::onTimer(void *data) {
+ MidiPlayer *p = (MidiPlayer *)data;
+ Common::StackLock lock(p->_mutex);
+
+ if (!p->_paused) {
+ if (p->_music.parser && p->_currentTrack != 255) {
+ p->_current = &p->_music;
+ p->_music.parser->onTimer();
+ }
+ }
+ if (p->_sfx.parser) {
+ p->_current = &p->_sfx;
+ p->_sfx.parser->onTimer();
+ }
+ p->_current = 0;
+}
+
+void MidiPlayer::startTrack(int track) {
+ if (track == _currentTrack)
+ return;
+
+ if (_music.num_songs > 0) {
+ if (track >= _music.num_songs)
+ return;
+
+ _mutex.lock();
+
+ if (_music.parser) {
+ _current = &_music;
+ delete _music.parser;
+ _current = 0;
+ _music.parser = 0;
+ }
+
+ MidiParser *parser = MidiParser::createParser_SMF();
+ parser->property (MidiParser::mpMalformedPitchBends, 1);
+ parser->setMidiDriver(this);
+ parser->setTimerRate(_driver->getBaseTempo());
+ if (!parser->loadMusic(_music.songs[track], _music.song_sizes[track])) {
+ printf ("Error reading track!\n");
+ delete parser;
+ parser = 0;
+ }
+
+ _currentTrack = (byte)track;
+ _music.parser = parser; // That plugs the power cord into the wall
+ } else if (_music.parser) {
+ _mutex.lock();
+ if (!_music.parser->setTrack(track)) {
+ _mutex.unlock();
+ return;
+ }
+ _currentTrack = (byte)track;
+ _current = &_music;
+ _music.parser->jumpToTick(0);
+ _current = 0;
+ }
+
+ _mutex.unlock();
+}
+
+void MidiPlayer::stop() {
+ Common::StackLock lock(_mutex);
+
+ if (_music.parser) {
+ _current = &_music;
+ _music.parser->jumpToTick(0);
+ }
+ _current = 0;
+ _currentTrack = 255;
+}
+
+void MidiPlayer::pause(bool b) {
+ if (_paused == b || !_driver)
+ return;
+ _paused = b;
+
+ Common::StackLock lock(_mutex);
+ for (int i = 0; i < 16; ++i) {
+ if (_music.channel[i])
+ _music.channel[i]->volume(_paused ? 0 : (_music.volume[i] * _masterVolume / 255));
+ if (_sfx.channel[i])
+ _sfx.channel[i]->volume(_paused ? 0 : (_sfx.volume[i] * _masterVolume / 255));
+ }
+}
+
+void MidiPlayer::set_volume(int volume) {
+ if (volume < 0)
+ volume = 0;
+ else if (volume > 255)
+ volume = 255;
+
+ if (_masterVolume == volume)
+ return;
+ _masterVolume = volume;
+
+ // Now tell all the channels this.
+ Common::StackLock lock(_mutex);
+ if (_driver && !_paused) {
+ for (int i = 0; i < 16; ++i) {
+ if (_music.channel[i])
+ _music.channel[i]->volume(_music.volume[i] * _masterVolume / 255);
+ if (_sfx.channel[i])
+ _sfx.channel[i]->volume(_sfx.volume[i] * _masterVolume / 255);
+ }
+ }
+}
+
+void MidiPlayer::set_driver(MidiDriver *md) {
+ // Don't try to set this more than once.
+ if (_driver)
+ return;
+ _driver = md;
+}
+
+void MidiPlayer::mapMT32toGM(bool map) {
+ Common::StackLock lock(_mutex);
+
+ _map_mt32_to_gm = map;
+}
+
+void MidiPlayer::setLoop(bool loop) {
+ Common::StackLock lock(_mutex);
+
+ _loopTrack = loop;
+}
+
+void MidiPlayer::queueTrack(int track, bool loop) {
+ _mutex.lock();
+ if (_currentTrack == 255) {
+ _mutex.unlock();
+ setLoop(loop);
+ startTrack(track);
+ } else {
+ _queuedTrack = track;
+ _loopQueuedTrack = loop;
+ _mutex.unlock();
+ }
+}
+
+void MidiPlayer::clearConstructs() {
+ clearConstructs(_music);
+ clearConstructs(_sfx);
+}
+
+void MidiPlayer::clearConstructs(MusicInfo &info) {
+ int i;
+ if (info.num_songs > 0) {
+ for (i = 0; i < info.num_songs; ++i)
+ free(info.songs[i]);
+ info.num_songs = 0;
+ }
+
+ if (info.data) {
+ free(info.data);
+ info.data = 0;
+ } // end if
+
+ if (info.parser) {
+ delete info.parser;
+ info.parser = 0;
+ }
+
+ if (_driver) {
+ for (i = 0; i < 16; ++i) {
+ if (info.channel[i]) {
+ info.channel[i]->allNotesOff();
+ info.channel[i]->release();
+ }
+ }
+ }
+ info.clear();
+}
+
+void MidiPlayer::resetVolumeTable() {
+ int i;
+ for (i = 0; i < 16; ++i) {
+ _music.volume[i] = _sfx.volume[i] = 127;
+ if (_driver)
+ _driver->send(((_masterVolume >> 1) << 16) | 0x7B0 | i);
+ }
+}
+
+static int simon1_gmf_size[] = {
+ 8900, 12166, 2848, 3442, 4034, 4508, 7064, 9730, 6014, 4742, 3138,
+ 6570, 5384, 8909, 6457, 16321, 2742, 8968, 4804, 8442, 7717,
+ 9444, 5800, 1381, 5660, 6684, 2456, 4744, 2455, 1177, 1232,
+ 17256, 5103, 8794, 4884, 16
+};
+
+void MidiPlayer::loadSMF(Common::File *in, int song, bool sfx) {
+ Common::StackLock lock(_mutex);
+
+ MusicInfo *p = sfx ? &_sfx : &_music;
+ clearConstructs(*p);
+
+ uint32 startpos = in->pos();
+ byte header[4];
+ in->read(header, 4);
+ bool isGMF = !memcmp(header, "GMF\x1", 4);
+ in->seek(startpos, SEEK_SET);
+
+ uint32 size = in->size() - in->pos();
+ if (isGMF) {
+ if (sfx) {
+ // Multiple GMF resources are stored in the SFX files,
+ // but each one is referenced by a pointer at the
+ // beginning of the file. Those pointers can be used
+ // to determine file size.
+ in->seek(0, SEEK_SET);
+ uint16 value = in->readUint16LE() >> 2; // Number of resources
+ if (song != value - 1) {
+ in->seek(song * 2 + 2, SEEK_SET);
+ value = in->readUint16LE();
+ size = value - startpos;
+ }
+ in->seek(startpos, SEEK_SET);
+ } else if (size >= 64000) {
+ // For GMF resources not in separate
+ // files, we're going to have to use
+ // hardcoded size tables.
+ size = simon1_gmf_size[song];
+ }
+ }
+
+ // When allocating space, add 4 bytes in case
+ // this is a GMF and we have to tack on our own
+ // End of Track event.
+ p->data = (byte *)calloc(size + 4, 1);
+ in->read(p->data, size);
+
+ uint32 timerRate = _driver->getBaseTempo();
+
+ if (!memcmp(p->data, "GMF\x1", 4)) {
+ // The GMF header
+ // 3 BYTES: 'GMF'
+ // 1 BYTE : Major version
+ // 1 BYTE : Minor version
+ // 1 BYTE : Ticks (Ranges from 2 - 8, always 2 for SFX)
+ // 1 BYTE : Loop control. 0 = no loop, 1 = loop
+
+ // In the original, the ticks value indicated how many
+ // times the music timer was called before it actually
+ // did something. The larger the value the slower the
+ // music.
+ //
+ // We, on the other hand, have a timer rate which is
+ // used to control by how much the music advances on
+ // each onTimer() call. The larger the value, the
+ // faster the music.
+ //
+ // It seems that 4 corresponds to our base tempo, so
+ // this should be the right way to calculate it.
+ timerRate = (4 * _driver->getBaseTempo()) / p->data[5];
+
+ // According to bug #1004919 calling setLoop() from
+ // within a lock causes a lockup, though I have no
+ // idea when this actually happens.
+ _loopTrack = (p->data[6] != 0);
+ }
+
+ MidiParser *parser = MidiParser::createParser_SMF();
+ parser->property(MidiParser::mpMalformedPitchBends, 1);
+ parser->setMidiDriver(this);
+ parser->setTimerRate(timerRate);
+ if (!parser->loadMusic(p->data, size)) {
+ printf("Error reading track!\n");
+ delete parser;
+ parser = 0;
+ }
+
+ if (!sfx) {
+ _currentTrack = 255;
+ resetVolumeTable();
+ }
+ p->parser = parser; // That plugs the power cord into the wall
+}
+
+void MidiPlayer::loadMultipleSMF(Common::File *in, bool sfx) {
+ // This is a special case for Simon 2 Windows.
+ // Instead of having multiple sequences as
+ // separate tracks in a Type 2 file, simon2win
+ // has multiple songs, each of which is a Type 1
+ // file. Thus, preceding the songs is a single
+ // byte specifying how many songs are coming.
+ // We need to load ALL the songs and then
+ // treat them as separate tracks -- for the
+ // purpose of jumps, anyway.
+ Common::StackLock lock(_mutex);
+
+ MusicInfo *p = sfx ? &_sfx : &_music;
+ clearConstructs(*p);
+
+ p->num_songs = in->readByte();
+ if (p->num_songs > 16) {
+ printf ("playMultipleSMF: %d is too many songs to keep track of!\n", (int)p->num_songs);
+ return;
+ }
+
+ byte i;
+ for (i = 0; i < p->num_songs; ++i) {
+ byte buf[5];
+ uint32 pos = in->pos();
+
+ // Make sure there's a MThd
+ in->read(buf, 4);
+ if (memcmp(buf, "MThd", 4)) {
+ printf("Expected MThd but found '%c%c%c%c' instead!\n", buf[0], buf[1], buf[2], buf[3]);
+ return;
+ }
+ in->seek(in->readUint32BE(), SEEK_CUR);
+
+ // Now skip all the MTrk blocks
+ while (true) {
+ in->read(buf, 4);
+ if (memcmp(buf, "MTrk", 4))
+ break;
+ in->seek(in->readUint32BE(), SEEK_CUR);
+ }
+
+ uint32 pos2 = in->pos() - 4;
+ uint32 size = pos2 - pos;
+ p->songs[i] = (byte *)calloc(size, 1);
+ in->seek(pos, SEEK_SET);
+ in->read(p->songs[i], size);
+ p->song_sizes[i] = size;
+ }
+
+ if (!sfx) {
+ _currentTrack = 255;
+ resetVolumeTable();
+ }
+}
+
+void MidiPlayer::loadXMIDI(Common::File *in, bool sfx) {
+ Common::StackLock lock(_mutex);
+ MusicInfo *p = sfx ? &_sfx : &_music;
+ clearConstructs(*p);
+
+ char buf[4];
+ uint32 pos = in->pos();
+ uint32 size = 4;
+ in->read(buf, 4);
+ if (!memcmp(buf, "FORM", 4)) {
+ int i;
+ for (i = 0; i < 16; ++i) {
+ if (!memcmp(buf, "CAT ", 4))
+ break;
+ size += 2;
+ memcpy(buf, &buf[2], 2);
+ in->read(&buf[2], 2);
+ }
+ if (memcmp(buf, "CAT ", 4)) {
+ error("Could not find 'CAT ' tag to determine resource size");
+ }
+ size += 4 + in->readUint32BE();
+ in->seek(pos, 0);
+ p->data = (byte *)calloc(size, 1);
+ in->read(p->data, size);
+ } else {
+ error("Expected 'FORM' tag but found '%c%c%c%c' instead", buf[0], buf[1], buf[2], buf[3]);
+ }
+
+ MidiParser *parser = MidiParser::createParser_XMIDI();
+ parser->setMidiDriver(this);
+ parser->setTimerRate(_driver->getBaseTempo());
+ if (!parser->loadMusic(p->data, size))
+ error("Error reading track");
+
+ if (!sfx) {
+ _currentTrack = 255;
+ resetVolumeTable();
+ }
+ p->parser = parser; // That plugs the power cord into the wall
+}
+
+void MidiPlayer::loadS1D(Common::File *in, bool sfx) {
+ Common::StackLock lock(_mutex);
+ MusicInfo *p = sfx ? &_sfx : &_music;
+ clearConstructs(*p);
+
+ uint16 size = in->readUint16LE();
+ if (size != in->size() - 2) {
+ error("Size mismatch in simon1demo MUS file (%ld versus reported %d)", (long)in->size() - 2, (int)size);
+ }
+
+ p->data = (byte *)calloc(size, 1);
+ in->read(p->data, size);
+
+ MidiParser *parser = MidiParser_createS1D();
+ parser->setMidiDriver(this);
+ parser->setTimerRate(_driver->getBaseTempo());
+ if (!parser->loadMusic(p->data, size))
+ error("Error reading track");
+
+ if (!sfx) {
+ _currentTrack = 255;
+ resetVolumeTable();
+ }
+ p->parser = parser; // That plugs the power cord into the wall
+}
+
+} // End of namespace Simon
diff --git a/engines/agos/midi.h b/engines/agos/midi.h
new file mode 100644
index 0000000000..cf055bffac
--- /dev/null
+++ b/engines/agos/midi.h
@@ -0,0 +1,128 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-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 AGOS_MIDI_H
+#define AGOS_MIDI_H
+
+#include "sound/mididrv.h"
+#include "sound/midiparser.h"
+#include "common/mutex.h"
+
+namespace Common {
+ class File;
+}
+
+namespace Simon {
+
+struct MusicInfo {
+ MidiParser *parser;
+ byte *data;
+ byte num_songs; // For Type 1 SMF resources
+ byte *songs[16]; // For Type 1 SMF resources
+ uint32 song_sizes[16]; // For Type 1 SMF resources
+
+ MidiChannel *channel[16]; // Dynamic remapping of channels to resolve conflicts
+ byte volume[16]; // Current channel volume
+
+ MusicInfo() { clear(); }
+ void clear() {
+ parser = 0; data = 0; num_songs = 0;
+ memset(songs, 0, sizeof(songs));
+ memset(song_sizes, 0, sizeof(song_sizes));
+ memset(channel, 0, sizeof(channel));
+ }
+};
+
+class MidiPlayer : public MidiDriver {
+protected:
+ Common::Mutex _mutex;
+ MidiDriver *_driver;
+ bool _map_mt32_to_gm;
+ bool _passThrough;
+
+ MusicInfo _music;
+ MusicInfo _sfx;
+ MusicInfo *_current; // Allows us to establish current context for operations.
+
+ // These are maintained for both music and SFX
+ byte _masterVolume; // 0-255
+ bool _paused;
+
+ // These are only used for music.
+ byte _currentTrack;
+ bool _loopTrack;
+ byte _queuedTrack;
+ bool _loopQueuedTrack;
+
+protected:
+ static void onTimer(void *data);
+ void clearConstructs();
+ void clearConstructs(MusicInfo &info);
+ void resetVolumeTable();
+
+public:
+ bool _enable_sfx;
+
+public:
+ MidiPlayer(OSystem *system);
+ virtual ~MidiPlayer();
+
+ void loadSMF(Common::File *in, int song, bool sfx = false);
+ void loadMultipleSMF(Common::File *in, bool sfx = false);
+ void loadXMIDI(Common::File *in, bool sfx = false);
+ void loadS1D(Common::File *in, bool sfx = false);
+
+ void mapMT32toGM(bool map);
+ void setLoop(bool loop);
+ void startTrack(int track);
+ void queueTrack(int track, bool loop);
+ bool isPlaying(bool check_queued = false) { return (_currentTrack != 255 && (_queuedTrack != 255 || !check_queued)); }
+
+ void stop();
+ void pause(bool b);
+
+ int get_volume() { return _masterVolume; }
+ void set_volume(int volume);
+ void set_driver(MidiDriver *md);
+
+public:
+ // MidiDriver interface implementation
+ int open();
+ void close();
+ void send(uint32 b);
+
+ void metaEvent(byte type, byte *data, uint16 length);
+ void setPassThrough(bool b) { _passThrough = b; }
+
+ // Timing functions - MidiDriver now operates timers
+ void setTimerCallback(void *timer_param, void (*timer_proc) (void *)) { }
+ uint32 getBaseTempo(void) { return _driver ? _driver->getBaseTempo() : 0; }
+
+ // Channel allocation functions
+ MidiChannel *allocateChannel() { return 0; }
+ MidiChannel *getPercussionChannel() { return 0; }
+};
+
+} // End of namespace Simon
+
+#endif
diff --git a/engines/agos/midiparser_s1d.cpp b/engines/agos/midiparser_s1d.cpp
new file mode 100644
index 0000000000..2b58c9ffa1
--- /dev/null
+++ b/engines/agos/midiparser_s1d.cpp
@@ -0,0 +1,155 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-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 "sound/mididrv.h"
+#include "sound/midiparser.h"
+
+#include <stdio.h>
+
+namespace Simon {
+
+/**
+ * Simon 1 Demo version of MidiParser.
+ *
+ * This parser is the result of eyeballing the one MUS file that's included
+ * with simon1demo. So there might be some things missing. I've tried to notate
+ * question-mark areas where they occur.
+ */
+class MidiParser_S1D : public MidiParser {
+protected:
+ byte *_data;
+ bool _no_delta;
+
+protected:
+ void parseNextEvent (EventInfo &info);
+ void resetTracking();
+ uint32 readVLQ2(byte * &data);
+
+public:
+ MidiParser_S1D() : _data(0), _no_delta(false) {}
+
+ bool loadMusic(byte *data, uint32 size);
+};
+
+
+// The VLQs for simon1demo seem to be
+// in Little Endian format.
+uint32 MidiParser_S1D::readVLQ2(byte * &data) {
+ byte str;
+ uint32 value = 0;
+ int i;
+
+ for (i = 0; i < 4; ++i) {
+ str = data[0];
+ ++data;
+ value |= (str & 0x7F) << (i * 7);
+ if (!(str & 0x80))
+ break;
+ }
+ return value;
+}
+
+void MidiParser_S1D::parseNextEvent(EventInfo &info) {
+ info.start = _position._play_pos;
+ info.delta = _no_delta ? 0 : readVLQ2(_position._play_pos);
+
+ _no_delta = false;
+ info.event = *(_position._play_pos++);
+ if (info.command() < 0x8) {
+ _no_delta = true;
+ info.event += 0x80;
+ }
+
+ switch (info.command()) {
+ case 0x8:
+ info.basic.param1 = *(_position._play_pos++);
+ info.basic.param2 = 0;
+ info.length = 0;
+ break;
+
+ case 0x9:
+ info.basic.param1 = *(_position._play_pos++);
+ info.basic.param2 = *(_position._play_pos++); // I'm ASSUMING this byte is velocity!
+ info.length = 0;
+ break;
+
+ case 0xC:
+ info.basic.param1 = *(_position._play_pos++);
+ info.basic.param2 = 0;
+ ++_position._play_pos; // I have NO IDEA what the second byte is for.
+ break;
+
+ case 0xF:
+ if (info.event == 0xFC) {
+ // This means End of Track.
+ // Rewrite in SMF (MIDI transmission) form.
+ info.event = 0xFF;
+ info.ext.type = 0x2F;
+ info.length = 0;
+ break;
+ }
+ // OTherwise fall through to default.
+
+ default:
+ debug(3, "MidiParser_S1D: Unexpected byte 0x%02X found", (int) info.command());
+ break;
+ }
+}
+
+bool MidiParser_S1D::loadMusic(byte *data, uint32 size) {
+ unloadMusic();
+
+ byte *pos = data;
+ if (*(pos++) != 0xFC)
+ error("Expected 0xFC header but found 0x%02X instead", (int) *pos);
+
+ // The next 3 bytes MIGHT be tempo, but we skip them and use the default.
+// setTempo (*(pos++) | (*(pos++) << 8) | (*(pos++) << 16));
+ pos += 3;
+
+ // And now we're at the actual data. Only one track.
+ _num_tracks = 1;
+ _data = pos;
+ _tracks[0] = pos;
+
+ // Note that we assume the original data passed in
+ // will persist beyond this call, i.e. we do NOT
+ // copy the data to our own buffer. Take warning....
+ resetTracking();
+ setTempo(666667);
+ setTrack(0);
+ return true;
+}
+
+void MidiParser_S1D::resetTracking() {
+ MidiParser::resetTracking();
+ _no_delta = false;
+}
+
+MidiParser *MidiParser_createS1D() { return new MidiParser_S1D; }
+
+} // End of namespace Simon
diff --git a/engines/agos/module.mk b/engines/agos/module.mk
new file mode 100644
index 0000000000..d58c545866
--- /dev/null
+++ b/engines/agos/module.mk
@@ -0,0 +1,34 @@
+MODULE := engines/agos
+
+MODULE_OBJS := \
+ agos.o \
+ animation.o \
+ charset.o \
+ cursor.o \
+ debug.o \
+ debugger.o \
+ draw.o \
+ event.o \
+ game.o \
+ icons.o \
+ items.o \
+ midi.o \
+ midiparser_s1d.o \
+ oracle.o \
+ res.o \
+ rooms.o \
+ saveload.o \
+ sound.o \
+ string.o \
+ subroutine.o \
+ verb.o \
+ vga.o \
+ window.o
+
+# This module can be built as a plugin
+ifdef BUILD_PLUGINS
+PLUGIN := 1
+endif
+
+# Include common rules
+include $(srcdir)/rules.mk
diff --git a/engines/agos/oracle.cpp b/engines/agos/oracle.cpp
new file mode 100644
index 0000000000..3e6448fbae
--- /dev/null
+++ b/engines/agos/oracle.cpp
@@ -0,0 +1,432 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-2006 The ScummVM project
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/stdafx.h"
+
+#include "common/savefile.h"
+
+#include "agos/agos.h"
+#include "agos/intern.h"
+#include "agos/vga.h"
+
+namespace Simon {
+
+void SimonEngine::checkLinkBox() { // Check for boxes spilling over to next row of text
+ if (_hyperLink != 0) {
+ _variableArray[52] = _textWindow->x + _textWindow->textColumn - _variableArray[50];
+ if (_variableArray[52] != 0) {
+ defineBox(_variableArray[53], _variableArray[50], _variableArray[51], _variableArray[52], 15, 145, 208, _dummyItem2);
+ _variableArray[53]++;
+ }
+ _variableArray[50] = _textWindow->x;
+ _variableArray[51] = _textWindow->textRow + _textWindow->y + (_oracleMaxScrollY-_textWindow->scrollY) * 15;
+ }
+}
+
+void SimonEngine::hyperLinkOn(uint16 x) {
+ if (!getBitFlag(51))
+ return;
+
+ _hyperLink = x;
+ _variableArray[50] = _textWindow->textColumn + _textWindow->x;
+ _variableArray[51] = _textWindow->textRow + _textWindow->y + (_oracleMaxScrollY - _textWindow->scrollY) * 15;
+}
+
+
+void SimonEngine::hyperLinkOff() {
+ if (!getBitFlag(51))
+ return;
+
+ _variableArray[52] = _textWindow->x + _textWindow->textColumn - _variableArray[50];
+ defineBox(_variableArray[53], _variableArray[50], _variableArray[51], _variableArray[52], 15, 145, 208, _dummyItem2);
+ _variableArray[53]++;
+ _hyperLink = 0;
+}
+
+void SimonEngine::linksUp() { // Scroll Oracle Links
+ uint16 j;
+ for (j = 700; j < _variableArray[53]; j++) {
+ moveBox(j, 0, -15);
+ }
+}
+
+void SimonEngine::linksDown() {
+ uint16 i;
+ for (i = 700; i < _variableArray[53]; i++) {
+ moveBox(i,0, 15);
+ }
+}
+
+void SimonEngine::scrollOracle() {
+ int i;
+
+ for (i = 0; i < 5; i++)
+ scrollOracleUp();
+}
+
+void SimonEngine::oracleTextUp() {
+ Subroutine *sub;
+ int i = 0;
+ changeWindow(3);
+ _noOracleScroll = 0;
+
+ if (_textWindow->scrollY > _oracleMaxScrollY) // For scroll up
+ _oracleMaxScrollY = _textWindow->scrollY;
+ while (1) {
+ if (_textWindow->scrollY == _oracleMaxScrollY)
+ break;
+ _textWindow->textRow = 105;
+ for (i = 0; i < 5; i++) {
+ _newLines = 0;
+ _textWindow->textColumn = 0;
+ _textWindow->textRow -= 3;
+ if (i == 2) {
+ _textWindow->scrollY += 1;
+ _textWindow->textRow += 15;
+ linksUp();
+ }
+ scrollOracleUp();
+ setBitFlag(94, true);
+ sub = getSubroutineByID(_variableArray[104]);
+ if (sub)
+ startSubroutineEx(sub);
+ setBitFlag(94, false);
+ }
+ if (_currentBoxNumber != 601 || !getBitFlag(89))
+ break;
+ delay(100);
+ }
+}
+
+void SimonEngine::oracleTextDown() {
+ Subroutine *sub;
+ int i = 0;
+ changeWindow(3);
+ _noOracleScroll = 0;
+
+ if (_textWindow->scrollY > _oracleMaxScrollY) // For scroll up
+ _oracleMaxScrollY = _textWindow->scrollY;
+ while (1) {
+ if (_textWindow->scrollY == 0)
+ break;
+
+ for (i = 0; i < 5; i++) {
+ _newLines = 0;
+ _textWindow->textColumn = 0;
+ _textWindow->textRow = (i + 1) * 3;
+ if (i == 4) {
+ _textWindow->scrollY -= 1;
+ _textWindow->textRow = 0;
+ linksDown();
+ }
+ scrollOracleDown();
+ setBitFlag(93, true);
+ sub = getSubroutineByID(_variableArray[104]);
+ if (sub)
+ startSubroutineEx(sub);
+ setBitFlag(93, false);
+ }
+ if (_currentBoxNumber != 600 || !getBitFlag(89))
+ break;
+ delay(100);
+ }
+}
+
+void SimonEngine::scrollOracleUp() {
+ byte *src, *dst;
+ uint16 w, h;
+
+ dst = getFrontBuf() + 103 * _screenWidth + 136;
+ src = getFrontBuf() + 106 * _screenWidth + 136;
+
+ for (h = 0; h < 21; h++) {
+ for (w = 0; w < 360; w++) {
+ if (dst[w] == 0 || dst[w] == 113 || dst[w] == 116 || dst[w] == 252)
+ dst[w] = src[w];
+ }
+ dst += _screenWidth;
+ src += _screenWidth;
+ }
+
+ for (h = 0; h < 80; h++) {
+ memcpy(dst, src, 360);
+ dst += _screenWidth;
+ src += _screenWidth;
+ }
+
+ for (h = 0; h < 3; h++) {
+ memset(dst, 0, 360);
+ dst += _screenWidth;
+ src += _screenWidth;
+ }
+}
+
+void SimonEngine::scrollOracleDown() {
+ byte *src, *dst;
+ uint16 w, h;
+
+ src = getFrontBuf() + 203 * _screenWidth + 136;
+ dst = getFrontBuf() + 206 * _screenWidth + 136;
+
+ for (h = 0; h < 77; h++) {
+ memcpy(dst, src, 360);
+ dst -= _screenWidth;
+ src -= _screenWidth;
+ }
+
+ for (h = 0; h < 24; h++) {
+ for (w = 0; w < 360; w++) {
+ if (src[w] == 0)
+ dst[w] = src[w];
+
+ if (src[w] == 113 || src[w] == 116 || src[w] == 252) {
+ dst[w] = src[w];
+ src[w] = 0;
+ }
+ }
+ dst -= _screenWidth;
+ src -= _screenWidth;
+ }
+}
+
+void SimonEngine::oracleLogo() {
+ Common::Rect srcRect, dstRect;
+ byte *src, *dst;
+ uint16 w, h;
+
+ dstRect.left = 16;
+ dstRect.top = 16;
+ dstRect.right = 58;
+ dstRect.bottom = 59;
+
+ srcRect.left = 0;
+ srcRect.top = 0;
+ srcRect.right = 42;
+ srcRect.bottom = 43;
+
+ src = _iconFilePtr;
+ dst = getBackBuf() + _screenWidth * dstRect.top + dstRect.left;
+
+ for (h = 0; h < dstRect.height(); h++) {
+ for (w = 0; w < dstRect.width(); w++) {
+ if (src[w])
+ dst[w] = src[w];
+ }
+ src += 336;
+ dst += _screenWidth;
+ }
+}
+
+void SimonEngine::swapCharacterLogo() {
+ Common::Rect srcRect, dstRect;
+ byte *src, *dst;
+ uint16 w, h;
+ int x;
+
+ dstRect.left = 64;
+ dstRect.top = 16;
+ dstRect.right = 106;
+ dstRect.bottom = 59;
+
+ srcRect.top = 0;
+ srcRect.bottom = 43;
+
+ x = _variableArray[91];
+ if (x > _variableArray[90])
+ x--;
+ if (x < _variableArray[90])
+ x++;
+ _variableArray[91] = x;
+
+ x++;
+ x *= 42;
+
+ srcRect.left = x;
+ srcRect.right = srcRect.left + 42;
+
+ src = _iconFilePtr + srcRect.top * 336 + srcRect.left;
+ dst = getBackBuf() + _screenWidth * dstRect.top + dstRect.left;
+
+ for (h = 0; h < dstRect.height(); h++) {
+ for (w = 0; w < dstRect.width(); w++) {
+ if (src[w])
+ dst[w] = src[w];
+ }
+ src += 336;
+ dst += _screenWidth;
+ }
+}
+
+void SimonEngine::listSaveGames(int n) {
+ char b[108];
+ Common::InSaveFile *in;
+ uint16 j, k, z, maxFiles;
+ int OK;
+ memset(b, 0, 108);
+
+ maxFiles = countSaveGames() - 1;
+ j = maxFiles - n + 1;
+ k = maxFiles - j + 1;
+ z = maxFiles;
+ if (getBitFlag(95)) {
+ j++;
+ z++;
+ }
+
+ while (1) {
+ OK = 1;
+ if (getBitFlag(93) || getBitFlag(94)) {
+ OK = 0;
+ if (j > z)
+ break;
+ }
+
+ if (getBitFlag(93)) {
+ if (((_newLines + 1) >= _textWindow->scrollY) && ((_newLines + 1) < (_textWindow->scrollY + 3)))
+ OK = 1;
+ }
+
+ if (getBitFlag(94)) {
+ if ((_newLines + 1) == (_textWindow->scrollY + 7))
+ OK = 1;
+ }
+
+
+ if (OK == 1) {
+ if (j == maxFiles + 1) {
+ showMessageFormat("\n");
+ hyperLinkOn(j + 400);
+ setTextColor(116);
+ showMessageFormat(" %d. ",1);
+ hyperLinkOff();
+ setTextColor(113);
+ k++;
+ j--;
+ }
+
+ if (!(in = _saveFileMan->openForLoading(genSaveName(j))))
+ break;
+ in->read(b, 100);
+ delete in;
+ }
+
+ showMessageFormat("\n");
+ hyperLinkOn(j + 400);
+ setTextColor(116);
+ if (k < 10)
+ showMessageFormat(" ");
+ showMessageFormat("%d. ",k);
+ setTextColor(113);
+ showMessageFormat("%s ",b);
+ hyperLinkOff();
+ j--;
+ k++;
+ }
+}
+
+void SimonEngine::saveUserGame(int slot) {
+ WindowBlock *window;
+ Common::InSaveFile *in;
+ char name[108];
+ int len;
+ memset(name, 0, 108);
+
+ window = _windowArray[3];
+
+ window->textRow = (slot + 1 - window->scrollY) * 15;
+ window->textColumn = 26;
+
+ if ((in = _saveFileMan->openForLoading(genSaveName(readVariable(55))))) {
+ in->read(name, 100);
+ delete in;
+ }
+
+ len = 0;
+ while (name[len]) {
+ byte chr = name[len];
+ window->textColumn += getFeebleFontSize(chr);
+ len++;
+ }
+
+ windowPutChar(window, 0x7f);
+ for (;;) {
+ _keyPressed = 0;
+ delay(1);
+
+ if (_keyPressed == 0 || _keyPressed >= 127)
+ continue;
+
+ window->textColumn -= getFeebleFontSize(127);
+ name[len] = 0;
+ windowBackSpace(_windowArray[3]);
+
+ if (_keyPressed == 27) {
+ _variableArray[55] = _keyPressed;
+ break;
+ }
+ if (_keyPressed == 10 || _keyPressed == 13) {
+ if (!saveGame(readVariable(55), name))
+ _variableArray[55] = (int16)0xFFFF;
+ else
+ _variableArray[55] = 0;
+ break;
+ }
+ if (_keyPressed == 8 && len != 0) {
+ len--;
+ byte chr = name[len];
+ window->textColumn -= getFeebleFontSize(chr);
+ name[len] = 0;
+ windowBackSpace(_windowArray[3]);
+ }
+ if (_keyPressed >= 32 && window->textColumn + 26 <= window->width) {
+ name[len++] = _keyPressed;
+ windowPutChar(_windowArray[3], _keyPressed);
+ }
+
+ windowPutChar(window, 0x7f);
+ }
+}
+
+void SimonEngine::windowBackSpace(WindowBlock *window) {
+ byte *dst;
+ uint x, y, h, w;
+
+ _lockWord |= 0x8000;
+
+ x = window->x + window->textColumn;
+ y = window->y + window->textRow;
+
+ dst = getFrontBuf() + _dxSurfacePitch * y + x;
+
+ for (h = 0; h < 13; h++) {
+ for (w = 0; w < 8; w++) {
+ if (dst[w] == 113 || dst[w] == 116 || dst[w] == 252)
+ dst[w] = 0;
+ }
+ dst += _screenWidth;
+ }
+
+ _lockWord &= ~0x8000;
+}
+
+} // End of namespace Simon
diff --git a/engines/agos/res.cpp b/engines/agos/res.cpp
new file mode 100644
index 0000000000..e8d4f2fd04
--- /dev/null
+++ b/engines/agos/res.cpp
@@ -0,0 +1,1055 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-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$
+ *
+ */
+
+// Resource file routines for Simon1/Simon2
+#include "common/stdafx.h"
+
+#include "common/file.h"
+
+#include "agos/agos.h"
+#include "agos/intern.h"
+#include "agos/sound.h"
+
+
+#ifdef USE_ZLIB
+#include <zlib.h>
+#endif
+
+using Common::File;
+
+namespace Simon {
+
+// Script opcodes to load into memory
+static const char *const opcode_arg_table_elvira[300] = {
+ "I ", "I ", "I ", "I ", "I ", "I ", "I ", "I ", "II ", "II ", "II ", "II ", "F ", "F ", "FN ", /* EQ", */
+ "FN ", "FN ", "FN ", "FF ", "FF ", "FF ", "FF ", "II ", "II ", "a ", "a ", "n ", "n ", "p ", /* PREP", */
+ "N ", "I ", "I ", "I ", "I ", "IN ", "IB ", "IB ", "II ", "IB ", "N ", " ", " ", " ", "I ", /* GET", */
+ "I ","I ","I ", "I ","I ","I ", "II ","II ","II ","II ","IBF ", "FIB ", "FF ", "N ", "NI ",
+ "IF ", "F ", "F ", "IB ", "IB ", "FN ", "FN ", "FN ", "FF ", "FF ", "FN ", "FN ", "FF ", "FF ", /* DIVF", */
+ "FN ", "FF ", "FN ", "F ", "I ", "IN ", "IN ", "IB ", "IB ", "IB ", "IB ", "II ", "I ", "I ", /* DEC", */
+ "IN ", "T ", "F ", " ", "T ", "T ", "I ", "I ", " ", " ", "T ", " ", " ", " ", " ", " ", "T ", /* PARSE", */
+ " ", "N ", "INN ", "II ", "II ", "ITN ", "ITIN ", "ITIN ", "I3 ", "IN ", "I ", "I ", "Ivnn ",
+ "vnn ", "Ivnn ", "NN ", "IT ", "INN ", " ", "N ", "N ", "N ", "T ", "v ", " ", " ", " ", " ",
+ "FN ", "I ", "TN ", "IT ", "II ", "I ", " ", "N ", "I ", " ", "I ", "NI ", "I ", "I ", "T ", /* BECOME", */
+ "I ", "I ", "N ", "N ", " ", "N ", "IF ", "IF ", "IF ", "IF ", "IF ", "IF ", "T ", "IB ",
+ "IB ", "IB ", "I ", " ", "vnnN ", "Ivnn ", "T ", "T ", "T ", "IF ", " ", " ", " ", "Ivnn ",
+ "IF ", "INI ", "INN ", "IN ", "II ", "IFF ", "IIF ", "I ", "II ", "I ", "I ", "IN ", "IN ", /* ROPENEXT", */
+ "II ", "II ", "II ", "II ", "IIN ", "IIN ", "IN ", "II ", "IN ", "IN ", "T ", "vanpan ",
+ "vIpI ", "T ", "T ", " ", " ", "IN ", "IN ", "IN ", "IN ", "N ", "INTTT ", "ITTT ",
+ "ITTT ", "I ", "I ", "IN ", "I ", " ", "F ", "NN ", "INN ", "INN ", "INNN ", "TF ", "NN ", /* PICTURE", */
+ "N ", "NNNNN ", "N ", " ", "NNNNNNN ", "N ", " ", "N ", "NN ", "N ", "NNNNNIN ", "N ", "N ", /* ENABLEBOX", */
+ "N ", "NNN ", "NNNN ", "INNN ", "IN ", "IN ", "TT ", "I ", "I ", "I ", "TTT ", "IN ", "IN ", /* UNSETCLASS",*/
+ "FN ", "FN ", "FN ", "N ", "N ", "N ", "NI ", " ", " ", "N ", "I ", "INN ", "NN ", "N ", /* WAITENDTUNE */
+ "N ", "Nan ", "NN ", " ", " ", " ", " ", " ", " ", " ", "IF ", "N ", " ", " ", " ", "II ", /* PLACENOICONS*/
+ " ", "NI ","N ",
+};
+
+static const char *const opcode_arg_table_waxworks[256] = {
+ " ", "I ", "I ", "I ", "I ", "I ", "I ", "II ", "II ", "II ", "II ", "B ", "B ", "BN ", "BN ",
+ "BN ", "BN ", "BB ", "BB ", "BB ", "BB ", "II ", "II ", "N ", "I ", "I ", "I ", "IN ", "IB ",
+ "II ", "I ", "I ", "II ", "II ", "IBB ", "BIB ", "BB ", "B ", "BI ", "IB ", "B ", "B ", "BN ",
+ "BN ", "BN ", "BB ", "BB ", "BN ", "BN ", "BB ", "BB ", "BN ", "BB ", "BN ", "B ", "I ", "IB ",
+ "IB ", "II ", "I ", "I ", "IN ", "B ", "T ", "T ", "NNNNNB ", "BT ", "BT ", "T ", " ", "B ",
+ "N ", "IBN ", "I ", "I ", "I ", "NN ", " ", " ", "IT ", "II ", "I ", "B ", " ", "IB ", "IBB ",
+ "IIB ", "T ", "T ", "T ", "IB ", "IB ", "IB ", "B ", "BB ", "IBB ", "NB ", "N ", "NBNNN ", "N ",
+ " ", "BNNNNNN ", "B ", " ", "B ", "B ", "BB ", "NNNNNIN ", "N ", "N ", "N ", "NNN ", "NBNN ",
+ "IBNN ", "IB ", "IB ", "IB ", "IB ", "N ", "N ", "N ", "BI ", " ", " ", "N ", "I ", "IBB ",
+ "NN ", "N ", "N ", "Ban ", "BB ", " ", " ", " ", " ", "IB ", "B ", " ", "II ", " ", "BI ", "N ",
+ "I ", "IB ", "IB ", "IB ", "IB ", "IB ", "IB ", "IB ", "BI ", "BB ", "B ", "B ", "B ", "B ",
+ "IBB ", "IBN ", "IB ", "B ", " ", "TB ", "TB ", "I ", "N ", "B ", "INB ", "INB ", "INB ", "INB ",
+ "INB ", "INB ", "INB ", "N ", " ", "INBB ", "B ", "B ", "Ian ", "B ", "B ", "B ", "B ", "T ",
+ "T ", "B ", " ", "I ", " ", " "
+};
+
+static const char *const opcode_arg_table_simon1win[256] = {
+ " ", "I ", "I ", "I ", "I ", "I ", "I ", "II ", "II ", "II ", "II ", "B ", "B ", "BN ", "BN ",
+ "BN ", "BN ", "BB ", "BB ", "BB ", "BB ", "II ", "II ", "N ", "I ", "I ", "I ", "IN ", "IB ",
+ "II ", "I ", "I ", "II ", "II ", "IBB ", "BIB ", "BB ", "B ", "BI ", "IB ", "B ", "B ", "BN ",
+ "BN ", "BN ", "BB ", "BB ", "BN ", "BN ", "BB ", "BB ", "BN ", "BB ", "BN ", "B ", "I ", "IB ",
+ "IB ", "II ", "I ", "I ", "IN ", "B ", "T ", "T ", "NNNNNB ", "BT ", "BTS ", "T ", " ", "B ",
+ "N ", "IBN ", "I ", "I ", "I ", "NN ", " ", " ", "IT ", "II ", "I ", "B ", " ", "IB ", "IBB ",
+ "IIB ", "T ", " ", " ", "IB ", "IB ", "IB ", "B ", "BB ", "IBB ", "NB ", "N ", "NBNNN ", "N ",
+ " ", "BNNNNNN ", "B ", " ", "B ", "B ", "BB ", "NNNNNIN ", "N ", "N ", "N ", "NNN ", "NBNN ",
+ "IBNN ", "IB ", "IB ", "IB ", "IB ", "N ", "N ", "N ", "BI ", " ", " ", "N ", "I ", "IBB ",
+ "NN ", "N ", "N ", "Ban ", "BB ", " ", " ", " ", " ", "IB ", "B ", " ", "II ", " ", "BI ", "N ",
+ "I ", "IB ", "IB ", "IB ", "IB ", "IB ", "IB ", "IB ", "BI ", "BB ", "B ", "B ", "B ", "B ",
+ "IBB ", "IBN ", "IB ", "B ", "BNBN ", "BBTS ", "N ", " ", "Ian ", "B ", "B ", "B ", "B ", "T ",
+ "T ", "B ", " ", "I ", " ", " ", "BBI ", "NNBB ", "BBB ", " ", " ", " ", " ", "N ", "N ", " ",
+ " ",
+};
+
+static const char *const opcode_arg_table_simon1dos[256] = {
+ " ", "I ", "I ", "I ", "I ", "I ", "I ", "II ", "II ", "II ", "II ", "B ", "B ", "BN ", "BN ",
+ "BN ", "BN ", "BB ", "BB ", "BB ", "BB ", "II ", "II ", "N ", "I ", "I ", "I ", "IN ", "IB ",
+ "II ", "I ", "I ", "II ", "II ", "IBB ", "BIB ", "BB ", "B ", "BI ", "IB ", "B ", "B ", "BN ",
+ "BN ", "BN ", "BB ", "BB ", "BN ", "BN ", "BB ", "BB ", "BN ", "BB ", "BN ", "B ", "I ", "IB ",
+ "IB ", "II ", "I ", "I ", "IN ", "B ", "T ", "T ", "NNNNNB ", "BT ", "BT ", "T ", " ", "B ",
+ "N ", "IBN ", "I ", "I ", "I ", "NN ", " ", " ", "IT ", "II ", "I ", "B ", " ", "IB ", "IBB ",
+ "IIB ", "T ", " ", " ", "IB ", "IB ", "IB ", "B ", "BB ", "IBB ", "NB ", "N ", "NBNNN ", "N ",
+ " ", "BNNNNNN ", "B ", " ", "B ", "B ", "BB ", "NNNNNIN ", "N ", "N ", "N ", "NNN ", "NBNN ",
+ "IBNN ", "IB ", "IB ", "IB ", "IB ", "N ", "N ", "N ", "BI ", " ", " ", "N ", "I ", "IBB ",
+ "NN ", "N ", "N ", "Ban ", "BB ", " ", " ", " ", " ", "IB ", "B ", " ", "II ", " ", "BI ", "N ",
+ "I ", "IB ", "IB ", "IB ", "IB ", "IB ", "IB ", "IB ", "BI ", "BB ", "B ", "B ", "B ", "B ",
+ "IBB ", "IBN ", "IB ", "B ", "BNBN ", "BBT ", "N ", " ", "Ian ", "B ", "B ", "B ", "B ", "T ",
+ "T ", "B ", " ", "I ", " ", " ", "BBI ", "NNBB ", "BBB ", " ", " ", " ", " ", "N ", "N ", " ",
+ " ",
+};
+
+static const char *const opcode_arg_table_simon2win[256] = {
+ " ", "I ", "I ", "I ", "I ", "I ", "I ", "II ", "II ", "II ", "II ", "B ", "B ", "BN ", "BN ",
+ "BN ", "BN ", "BB ", "BB ", "BB ", "BB ", "II ", "II ", "N ", "I ", "I ", "I ", "IN ", "IB ",
+ "II ", "I ", "I ", "II ", "II ", "IBB ", "BIB ", "BB ", "B ", "BI ", "IB ", "B ", "B ", "BN ",
+ "BN ", "BN ", "BB ", "BB ", "BN ", "BN ", "BB ", "BB ", "BN ", "BB ", "BN ", "B ", "I ", "IB ",
+ "IB ", "II ", "I ", "I ", "IN ", "B ", "T ", "T ", "NNNNNB ", "BT ", "BTS ", "T ", " ", "B ",
+ "N ", "IBN ", "I ", "I ", "I ", "NN ", " ", " ", "IT ", "II ", "I ", "B ", " ", "IB ", "IBB ",
+ "IIB ", "T ", " ", " ", "IB ", "IB ", "IB ", "B ", "BB ", "IBB ", "NB ", "N ", "NNBNNN ", "NN ",
+ " ", "BNNNNNN ", "B ", " ", "B ", "B ", "BB ", "NNNNNIN ", "N ", "N ", "N ", "NNN ", "NBNN ",
+ "IBNN ", "IB ", "IB ", "IB ", "IB ", "N ", "N ", "N ", "BI ", " ", " ", "N ", "I ", "IBB ",
+ "NNB ", "N ", "N ", "Ban ", "BB ", " ", " ", " ", " ", "IB ", "B ", " ", "II ", " ", "BI ",
+ "N ", "I ", "IB ", "IB ", "IB ", "IB ", "IB ", "IB ", "IB ", "BI ", "BB ", "B ", "B ", "B ",
+ "B ", "IBB ", "IBN ", "IB ", "B ", "BNBN ", "BBTS ", "N ", " ", "Ian ", "B ", "B ", "B ", "B ",
+ "T ", "T ", "B ", " ", "I ", " ", " ", "BBI ", "NNBB ", "BBB ", " ", " ", " ", " ", "N ", "N ",
+ " ", " ", "BT ", " ", "B "
+};
+
+static const char *const opcode_arg_table_simon2dos[256] = {
+ " ", "I ", "I ", "I ", "I ", "I ", "I ", "II ", "II ", "II ", "II ", "B ", "B ", "BN ", "BN ",
+ "BN ", "BN ", "BB ", "BB ", "BB ", "BB ", "II ", "II ", "N ", "I ", "I ", "I ", "IN ", "IB ",
+ "II ", "I ", "I ", "II ", "II ", "IBB ", "BIB ", "BB ", "B ", "BI ", "IB ", "B ", "B ", "BN ",
+ "BN ", "BN ", "BB ", "BB ", "BN ", "BN ", "BB ", "BB ", "BN ", "BB ", "BN ", "B ", "I ", "IB ",
+ "IB ", "II ", "I ", "I ", "IN ", "B ", "T ", "T ", "NNNNNB ", "BT ", "BT ", "T ", " ", "B ",
+ "N ", "IBN ", "I ", "I ", "I ", "NN ", " ", " ", "IT ", "II ", "I ", "B ", " ", "IB ", "IBB ",
+ "IIB ", "T ", " ", " ", "IB ", "IB ", "IB ", "B ", "BB ", "IBB ", "NB ", "N ", "NNBNNN ", "NN ",
+ " ", "BNNNNNN ", "B ", " ", "B ", "B ", "BB ", "NNNNNIN ", "N ", "N ", "N ", "NNN ", "NBNN ",
+ "IBNN ", "IB ", "IB ", "IB ", "IB ", "N ", "N ", "N ", "BI ", " ", " ", "N ", "I ", "IBB ",
+ "NNB ", "N ", "N ", "Ban ", "BB ", " ", " ", " ", " ", "IB ", "B ", " ", "II ", " ", "BI ",
+ "N ", "I ", "IB ", "IB ", "IB ", "IB ", "IB ", "IB ", "IB ", "BI ", "BB ", "B ", "B ", "B ",
+ "B ", "IBB ", "IBN ", "IB ", "B ", "BNBN ", "BBT ", "N ", " ", "Ian ", "B ", "B ", "B ", "B ",
+ "T ", "T ", "B ", " ", "I ", " ", " ", "BBI ", "NNBB ", "BBB ", " ", " ", " ", " ", "N ", "N ",
+ " ", " ", "BT ", " ", "B "
+};
+
+static const char *const opcode_arg_table_feeblefiles[256] = {
+ " ", "I ", "I ", "I ", "I ", "I ", "I ", "II ", "II ", "II ", "II ", "B ", "B ", "BN ", "BN ",
+ "BN ", "BN ", "BB ", "BB ", "BB ", "BB ", "II ", "II ", "N ", "I ", "I ", "I ", "IN ", "IB ",
+ "II ", "I ", "I ", "II ", "II ", "IBB ", "BIB ", "BB ", "B ", "BI ", "IB ", "B ", "B ", "BN ",
+ "BN ", "BN ", "BB ", "BB ", "BN ", "BN ", "BB ", "BB ", "BN ", "BB ", "BN ", "B ", "I ", "IB ",
+ "IB ", "II ", "I ", "I ", "IN ", "B ", "T ", "T ", "NNNNNB ", "BT ", "BTS ", "T ", " ", "B ",
+ "N ", "IBN ", "I ", "I ", "I ", "NN ", " ", " ", "IT ", "II ", "I ", "B ", " ", "IB ", "IBB ",
+ "IIB ", "T ", " ", " ", "IB ", "IB ", "IB ", "B ", "BB ", "IBB ", "NB ", "N ", "NNBNNN ", "NN ",
+ " ", "BNNNNNN ", "B ", " ", "B ", "B ", "BB ", "NNNNNIN ", "N ", "N ", "N ", "NNN ", "NBNN ",
+ "IBNN ", "IB ", "IB ", "IB ", "IB ", "N ", "N ", "N ", "BI ", " ", " ", "N ", "I ", "IBB ",
+ "NNB ", "N ", "N ", "Ban ", " ", " ", " ", " ", " ", "IB ", "B ", " ", "II ", " ", "BI ",
+ "N ", "I ", "IB ", "IB ", "IB ", "IB ", "IB ", "IB ", "IB ", "BI ", "BB ", "B ", "B ", "B ",
+ "B ", "IBB ", "IBN ", "IB ", "B ", "BNNN ", "BBTS ", "N ", " ", "Ian ", "B ", "B ", "B ", "B ",
+ "T ", "N ", " ", " ", "I ", " ", " ", "BBI ", "NNBB ", "BBB ", " ", " ", "T ", " ", "N ", "N ",
+ " ", " ", "BT ", " ", "B ", " ", "BBBB ", " ", " ", "BBBB ", "B ", "B ", "B ", "B "
+};
+
+static const char *const opcode_arg_table_puzzlepack[256] = {
+ " ", "I ", "I ", "I ", "I ", "I ", "I ", "II ", "II ", "II ", "II ", "N ", "N ", "NN ", "NN ",
+ "NN ", "NN ", "NN ", "NN ", "NN ", "NN ", "II ", "II ", "N ", "I ", "I ", "I ", "IN ", "IB ",
+ "II ", "I ", "I ", "II ", "II ", "IBN ", "NIB ", "NN ", "B ", "BI ", "IN ", "N ", "N ", "NN ",
+ "NN ", "NN ", "NN ", "NN ", "NN ", "NN ", "NN ", "NN ", "NN ", "NN ", "NN ", "B ", "I ", "IB ",
+ "IB ", "II ", "I ", "I ", "IN ", "N ", "T ", "T ", "NNNNNB ", "BTNN ", "BTS ", "T ", " ", "B ",
+ "N ", "IBN ", "I ", "I ", "I ", "NN ", " ", " ", "IT ", "II ", "I ", "B ", " ", "IB ", "IBB ",
+ "IIB ", "T ", " ", " ", "IB ", "IB ", "IB ", "B ", "BB ", "IBB ", "NB ", "N ", "NNBNNN ", "NN ",
+ " ", "BNNNNNN ", "B ", " ", "B ", "B ", "BB ", "NNNNNIN ", "N ", "N ", "N ", "NNN ", "NBNN ",
+ "IBNN ", "IB ", "IB ", "IB ", "IB ", "N ", "N ", "N ", "BI ", " ", " ", "N ", "I ", "IBB ",
+ "NNB ", "N ", "N ", "Ban ", " ", " ", " ", " ", " ", "IN ", "B ", " ", "II ", " ", "BI ",
+ "N ", "I ", "IB ", "IB ", "IB ", "IB ", "IB ", "IB ", "IB ", "BI ", "BB ", "N ", "N ", "N ",
+ "N ", "IBN ", "IBN ", "IN ", "B ", "BNNN ", "BBTS ", "N ", " ", "Ian ", "B ", "B ", "B ", "B ",
+ "T ", "N ", " ", " ", "I ", " ", " ", "BBI ", "NNBB ", "BBB ", " ", " ", "T ", " ", "N ", "N ",
+ " ", " ", "BT ", " ", "B ", " ", "BBBB ", " ", " ", "BBBB ", "B ", "B ", "B ", "B "
+};
+
+uint16 SimonEngine::to16Wrapper(uint value) {
+ if (getGameType() == GType_FF || getGameType() == GType_PP)
+ return TO_LE_16(value);
+ else
+ return TO_BE_16(value);
+}
+
+uint16 SimonEngine::readUint16Wrapper(const void *src) {
+ if (getGameType() == GType_FF || getGameType() == GType_PP)
+ return READ_LE_UINT16(src);
+ else
+ return READ_BE_UINT16(src);
+}
+
+uint32 SimonEngine::readUint32Wrapper(const void *src) {
+ if (getGameType() == GType_FF || getGameType() == GType_PP)
+ return READ_LE_UINT32(src);
+ else
+ return READ_BE_UINT32(src);
+}
+
+void SimonEngine::decompressData(const char *srcName, byte *dst, uint32 offset, uint32 srcSize, uint32 dstSize) {
+#ifdef USE_ZLIB
+ File in;
+ in.open(srcName);
+ if (in.isOpen() == false)
+ error("decompressData: Can't load %s", srcName);
+
+ in.seek(offset, SEEK_SET);
+ if (srcSize != dstSize) {
+ byte *srcBuffer = (byte *)malloc(srcSize);
+
+ if (in.read(srcBuffer, srcSize) != srcSize)
+ error("decompressData: Read failed");
+
+ unsigned long decompressedSize = dstSize;
+ int result = uncompress(dst, &decompressedSize, srcBuffer, srcSize);
+ if (result != Z_OK)
+ error("decompressData: Zlib uncompress error");
+ free(srcBuffer);
+ } else {
+ if (in.read(dst, dstSize) != dstSize)
+ error("decompressData: Read failed");
+ }
+ in.close();
+#else
+ error("Zlib support is required for Amiga and Macintosh versions");
+#endif
+}
+
+void SimonEngine::loadOffsets(const char *filename, int number, uint32 &file, uint32 &offset, uint32 &srcSize, uint32 &dstSize) {
+ Common::File in;
+
+ int offsSize = (getPlatform() == Common::kPlatformAmiga) ? 16 : 12;
+
+ /* read offsets from index */
+ in.open(filename);
+ if (in.isOpen() == false) {
+ error("loadOffsets: Can't load index file '%s'", filename);
+ }
+
+ in.seek(number * offsSize, SEEK_SET);
+ offset = in.readUint32LE();
+ dstSize = in.readUint32LE();
+ srcSize = in.readUint32LE();
+ file = in.readUint32LE();
+ in.close();
+}
+
+int SimonEngine::allocGamePcVars(File *in) {
+ uint item_array_size, item_array_inited, stringtable_num;
+ uint32 version;
+ uint i, start;
+
+ item_array_size = in->readUint32BE();
+ version = in->readUint32BE();
+ item_array_inited = in->readUint32BE();
+ stringtable_num = in->readUint32BE();
+
+ if (getGameType() == GType_ELVIRA || getGameType() == GType_ELVIRA2) {
+ item_array_inited = item_array_size;
+ start = 0;
+ } else {
+ item_array_inited += 2; // first two items are predefined
+ item_array_size += 2;
+ start = 1;
+ }
+
+ if (version != 0x80)
+ error("allocGamePcVars: Not a runtime database");
+
+ _itemArrayPtr = (Item **)calloc(item_array_size, sizeof(Item *));
+ if (_itemArrayPtr == NULL)
+ error("allocGamePcVars: Out of memory for Item array");
+
+ _itemArraySize = item_array_size;
+ _itemArrayInited = item_array_inited;
+
+ for (i = start; i < item_array_inited; i++) {
+ _itemArrayPtr[i] = (Item *)allocateItem(sizeof(Item));
+ }
+
+ // The rest is cleared automatically by calloc
+ allocateStringTable(stringtable_num + 10);
+ _stringTabNum = stringtable_num;
+
+ return item_array_inited;
+}
+
+void SimonEngine::loadGamePcFile() {
+ Common::File in;
+ int num_inited_objects;
+ int i, file_size;
+
+ /* read main gamepc file */
+ in.open(getFileName(GAME_BASEFILE));
+ if (in.isOpen() == false) {
+ error("loadGamePcFile: Can't load gamepc file '%s'", getFileName(GAME_BASEFILE));
+ }
+
+ num_inited_objects = allocGamePcVars(&in);
+
+ createPlayer();
+ readGamePcText(&in);
+
+ int start;
+ if (getGameType() == GType_ELVIRA || getGameType() == GType_ELVIRA2) {
+ start = 0;
+ } else {
+ start = 2;
+ }
+
+ for (i = start; i < num_inited_objects; i++) {
+ readItemFromGamePc(&in, _itemArrayPtr[i]);
+ }
+
+ readSubroutineBlock(&in);
+
+ in.close();
+
+ if (getGameType() == GType_PP)
+ return;
+
+ /* Read list of TABLE resources */
+ in.open(getFileName(GAME_TBLFILE));
+ if (in.isOpen() == false) {
+ error("loadGamePcFile: Can't load table resources file '%s'", getFileName(GAME_TBLFILE));
+ }
+
+ file_size = in.size();
+
+ _tblList = (byte *)malloc(file_size);
+ if (_tblList == NULL)
+ error("loadGamePcFile: Out of memory for strip table list");
+ in.read(_tblList, file_size);
+ in.close();
+
+ /* Remember the current state */
+ _subroutineListOrg = _subroutineList;
+ _tablesHeapPtrOrg = _tablesHeapPtr;
+ _tablesHeapCurPosOrg = _tablesHeapCurPos;
+
+ if (getGameType() == GType_ELVIRA || getGameType() == GType_FF)
+ return;
+
+ /* Read list of TEXT resources */
+ in.open(getFileName(GAME_STRFILE));
+ if (in.isOpen() == false)
+ error("loadGamePcFile: Can't load text resources file '%s'", getFileName(GAME_STRFILE));
+
+ file_size = in.size();
+ _strippedTxtMem = (byte *)malloc(file_size);
+ if (_strippedTxtMem == NULL)
+ error("loadGamePcFile: Out of memory for strip text list");
+ in.read(_strippedTxtMem, file_size);
+ in.close();
+
+ if (getGameType() != GType_WW)
+ return;
+
+ /* Read list of ROOM ITEMS resources */
+ in.open(getFileName(GAME_RMSLFILE));
+ if (in.isOpen() == false) {
+ error("loadGamePcFile: Can't load room resources file '%s'", getFileName(GAME_XTBLFILE));
+ }
+
+ file_size = in.size();
+
+ _roomsList = (byte *)malloc(file_size);
+ if (_roomsList == NULL)
+ error("loadGamePcFile: Out of memory for room items list");
+ in.read(_roomsList, file_size);
+ in.close();
+
+ /* Read list of XTABLE resources */
+ in.open(getFileName(GAME_XTBLFILE));
+ if (in.isOpen() == false) {
+ error("loadGamePcFile: Can't load xtable resources file '%s'", getFileName(GAME_XTBLFILE));
+ }
+
+ file_size = in.size();
+
+ _xtblList = (byte *)malloc(file_size);
+ if (_xtblList == NULL)
+ error("loadGamePcFile: Out of memory for strip xtable list");
+ in.read(_xtblList, file_size);
+ in.close();
+
+ /* Remember the current state */
+ _xsubroutineListOrg = _subroutineList;
+ _xtablesHeapPtrOrg = _tablesHeapPtr;
+ _xtablesHeapCurPosOrg = _tablesHeapCurPos;
+
+}
+
+void SimonEngine::readGamePcText(Common::File *in) {
+ _textSize = in->readUint32BE();
+ _textMem = (byte *)malloc(_textSize);
+ if (_textMem == NULL)
+ error("readGamePcText: Out of text memory");
+
+ in->read(_textMem, _textSize);
+
+ setupStringTable(_textMem, _stringTabNum);
+}
+
+void SimonEngine::readItemFromGamePc(Common::File *in, Item *item) {
+ uint32 type;
+
+ if (getGameType() == GType_ELVIRA || getGameType() == GType_ELVIRA2) {
+ item->itemName = (uint16)in->readUint32BE();
+ item->adjective = in->readUint16BE();
+ item->noun = in->readUint16BE();
+ item->state = in->readUint16BE();
+ in->readUint16BE();
+ item->sibling = (uint16)fileReadItemID(in);
+ item->child = (uint16)fileReadItemID(in);
+ item->parent = (uint16)fileReadItemID(in);
+ in->readUint16BE();
+ in->readUint16BE();
+ in->readUint16BE();
+ item->classFlags = in->readUint16BE();
+ item->children = NULL;
+ } else {
+ item->adjective = in->readUint16BE();
+ item->noun = in->readUint16BE();
+ item->state = in->readUint16BE();
+ item->sibling = (uint16)fileReadItemID(in);
+ item->child = (uint16)fileReadItemID(in);
+ item->parent = (uint16)fileReadItemID(in);
+ in->readUint16BE();
+ item->classFlags = in->readUint16BE();
+ item->children = NULL;
+ }
+
+
+ type = in->readUint32BE();
+ while (type) {
+ type = in->readUint16BE();
+ if (type != 0)
+ readItemChildren(in, item, type);
+ }
+}
+
+void SimonEngine::readItemChildren(Common::File *in, Item *item, uint type) {
+ if (type == 1) {
+ if (getGameType() == GType_ELVIRA || getGameType() == GType_ELVIRA2) {
+ // FIXME
+ in->readUint32BE();
+ in->readUint32BE();
+ in->readUint16BE();
+ } else {
+ uint fr1 = in->readUint16BE();
+ uint fr2 = in->readUint16BE();
+ uint i, size;
+ uint j, k;
+ SubRoom *subRoom;
+
+ size = SubRoom_SIZE;
+ for (i = 0, j = fr2; i != 6; i++, j >>= 2)
+ if (j & 3)
+ size += sizeof(subRoom->roomExit[0]);
+
+ subRoom = (SubRoom *)allocateChildBlock(item, 1, size);
+ subRoom->subroutine_id = fr1;
+ subRoom->roomExitStates = fr2;
+
+ for (i = k = 0, j = fr2; i != 6; i++, j >>= 2)
+ if (j & 3)
+ subRoom->roomExit[k++] = (uint16)fileReadItemID(in);
+ }
+ } else if (type == 2) {
+ uint32 fr = in->readUint32BE();
+ uint i, k, size;
+ SubObject *subObject;
+
+ size = SubObject_SIZE;
+ for (i = 0; i != 16; i++)
+ if (fr & (1 << i))
+ size += sizeof(subObject->objectFlagValue[0]);
+
+ subObject = (SubObject *)allocateChildBlock(item, 2, size);
+ subObject->objectFlags = fr;
+
+ k = 0;
+ if (fr & 1) {
+ subObject->objectFlagValue[k++] = (uint16)in->readUint32BE();
+ }
+ for (i = 1; i != 16; i++)
+ if (fr & (1 << i))
+ subObject->objectFlagValue[k++] = in->readUint16BE();
+
+ subObject->objectName = (uint16)in->readUint32BE();
+ } else if (type == 4) {
+ // FIXME
+ fileReadItemID(in);
+ fileReadItemID(in);
+ fileReadItemID(in);
+ fileReadItemID(in);
+ fileReadItemID(in);
+ fileReadItemID(in);
+ fileReadItemID(in);
+ fileReadItemID(in);
+ fileReadItemID(in);
+ fileReadItemID(in);
+ fileReadItemID(in);
+ fileReadItemID(in);
+ } else if (type == 7) {
+ // FIXME
+ in->readUint16BE();
+ in->readUint16BE();
+ } else if (type == 8) {
+ SubUserChain *chain = (SubUserChain *)allocateChildBlock(item, 8, sizeof(SubUserChain));
+ chain->chChained = (uint16)fileReadItemID(in);
+ } else if (type == 9) {
+ setUserFlag(item, 0, in->readUint16BE());
+ setUserFlag(item, 1, in->readUint16BE());
+ setUserFlag(item, 2, in->readUint16BE());
+ setUserFlag(item, 3, in->readUint16BE());
+ if (getGameType() == GType_ELVIRA || getGameType() == GType_ELVIRA2) {
+ setUserFlag(item, 4, in->readUint16BE());
+ setUserFlag(item, 5, in->readUint16BE());
+ setUserFlag(item, 6, in->readUint16BE());
+ setUserFlag(item, 7, in->readUint16BE());
+ // FIXME
+ fileReadItemID(in);
+ fileReadItemID(in);
+ fileReadItemID(in);
+ fileReadItemID(in);
+ }
+ } else if (type == 255) {
+ SubUserInherit *inherit = (SubUserInherit *)allocateChildBlock(item, 255, sizeof(SubUserInherit));
+ inherit->inMaster = (uint16)fileReadItemID(in);
+ } else {
+ error("readItemChildren: invalid type %d", type);
+ }
+}
+
+uint fileReadItemID(Common::File *in) {
+ uint32 val = in->readUint32BE();
+ if (val == 0xFFFFFFFF)
+ return 0;
+ return val + 2;
+}
+
+byte *SimonEngine::readSingleOpcode(Common::File *in, byte *ptr) {
+ int i, l;
+ const char *string_ptr;
+ uint opcode, val;
+
+ const char *const *table;
+
+ if (getGameType() == GType_PP)
+ table = opcode_arg_table_puzzlepack;
+ else if (getGameType() == GType_FF)
+ table = opcode_arg_table_feeblefiles;
+ else if (getGameType() == GType_SIMON2 && (getFeatures() & GF_TALKIE))
+ table = opcode_arg_table_simon2win;
+ else if (getGameType() == GType_SIMON2)
+ table = opcode_arg_table_simon2dos;
+ else if (getGameType() == GType_SIMON1 && (getFeatures() & GF_TALKIE))
+ table = opcode_arg_table_simon1win;
+ else if (getGameType() == GType_SIMON1)
+ table = opcode_arg_table_simon1dos;
+ else if (getGameType() == GType_WW)
+ table = opcode_arg_table_waxworks;
+ else
+ table = opcode_arg_table_elvira;
+
+ i = 0;
+ if (getGameType() == GType_ELVIRA || getGameType() == GType_ELVIRA2) {
+ opcode = READ_BE_UINT16(ptr);
+ ptr += 2;
+ } else {
+ opcode = *ptr++;
+ }
+
+ string_ptr = table[opcode];
+ if (!string_ptr)
+ error("Unable to locate opcode table. Perhaps you are using the wrong game target?");
+
+ for (;;) {
+ if (string_ptr[i] == ' ')
+ return ptr;
+
+ l = string_ptr[i++];
+
+ switch (l) {
+ case 'F':
+ case 'N':
+ case 'S':
+ case 'a':
+ case 'n':
+ case 'p':
+ case 'v':
+ case '3':
+ val = in->readUint16BE();
+ *ptr++ = val >> 8;
+ *ptr++ = val & 255;
+ break;
+
+ case 'B':
+ if (getGameType() == GType_ELVIRA || getGameType() == GType_ELVIRA2) {
+ val = in->readUint16BE();
+ *ptr++ = val >> 8;
+ *ptr++ = val & 255;
+ } else {
+ *ptr++ = in->readByte();
+ if (ptr[-1] == 0xFF) {
+ *ptr++ = in->readByte();
+ }
+ }
+ break;
+
+ case 'I':
+ val = in->readUint16BE();
+ switch (val) {
+ case 1:
+ val = 0xFFFF;
+ break;
+ case 3:
+ val = 0xFFFD;
+ break;
+ case 5:
+ val = 0xFFFB;
+ break;
+ case 7:
+ val = 0xFFF9;
+ break;
+ case 9:
+ val = 0xFFF7;
+ break;
+ default:
+ val = fileReadItemID(in);;
+ }
+ *ptr++ = val >> 8;
+ *ptr++ = val & 255;
+ break;
+
+ case 'T':
+ val = in->readUint16BE();
+ switch (val) {
+ case 0:
+ val = 0xFFFF;
+ break;
+ case 3:
+ val = 0xFFFD;
+ break;
+ default:
+ val = (uint16)in->readUint32BE();
+ break;
+ }
+ *ptr++ = val >> 8;
+ *ptr++ = val & 255;
+ break;
+ default:
+ error("readSingleOpcode: Bad cmd table entry %c", l);
+ }
+ }
+}
+
+void SimonEngine::openGameFile() {
+ if (!(getFeatures() & GF_OLD_BUNDLE)) {
+ _gameFile = new File();
+ _gameFile->open(getFileName(GAME_GMEFILE));
+
+ if (_gameFile->isOpen() == false)
+ error("openGameFile: Can't load game file '%s'", getFileName(GAME_GMEFILE));
+
+ uint32 size = _gameFile->readUint32LE();
+
+ _gameOffsetsPtr = (uint32 *)malloc(size);
+ if (_gameOffsetsPtr == NULL)
+ error("openGameFile: Out of memory, game offsets");
+
+ readGameFile(_gameOffsetsPtr, 0, size);
+#if defined(SCUMM_BIG_ENDIAN)
+ for (uint r = 0; r < size / 4; r++)
+ _gameOffsetsPtr[r] = FROM_LE_32(_gameOffsetsPtr[r]);
+#endif
+ }
+}
+
+void SimonEngine::readGameFile(void *dst, uint32 offs, uint32 size) {
+ _gameFile->seek(offs, SEEK_SET);
+ if (_gameFile->read(dst, size) != size)
+ error("readGameFile: Read failed (%d,%d)", offs, size);
+}
+
+// Thanks to Stuart Caie for providing the original
+// C conversion upon which this decruncher is based.
+
+#define SD_GETBIT(var) do { \
+ if (!bits--) { \
+ s -= 4; \
+ if (s < src) \
+ return false; \
+ bb = READ_BE_UINT32(s); \
+ bits = 31; \
+ } \
+ (var) = bb & 1; \
+ bb >>= 1; \
+}while (0)
+
+#define SD_GETBITS(var, nbits) do { \
+ bc = (nbits); \
+ (var) = 0; \
+ while (bc--) { \
+ (var) <<= 1; \
+ SD_GETBIT(bit); \
+ (var) |= bit; \
+ } \
+}while (0)
+
+#define SD_TYPE_LITERAL (0)
+#define SD_TYPE_MATCH (1)
+
+static bool decrunchFile(byte *src, byte *dst, uint32 size) {
+ byte *s = src + size - 4;
+ uint32 destlen = READ_BE_UINT32 (s);
+ uint32 bb, x, y;
+ byte *d = dst + destlen;
+ byte bc, bit, bits, type;
+
+ // Initialize bit buffer.
+ s -= 4;
+ bb = x = READ_BE_UINT32 (s);
+ bits = 0;
+ do {
+ x >>= 1;
+ bits++;
+ } while (x);
+ bits--;
+
+ while (d > dst) {
+ SD_GETBIT(x);
+ if (x) {
+ SD_GETBITS(x, 2);
+ switch (x) {
+ case 0:
+ type = SD_TYPE_MATCH;
+ x = 9;
+ y = 2;
+ break;
+
+ case 1:
+ type = SD_TYPE_MATCH;
+ x = 10;
+ y = 3;
+ break;
+
+ case 2:
+ type = SD_TYPE_MATCH;
+ x = 12;
+ SD_GETBITS(y, 8);
+ break;
+
+ default:
+ type = SD_TYPE_LITERAL;
+ x = 8;
+ y = 8;
+ }
+ } else {
+ SD_GETBIT(x);
+ if (x) {
+ type = SD_TYPE_MATCH;
+ x = 8;
+ y = 1;
+ } else {
+ type = SD_TYPE_LITERAL;
+ x = 3;
+ y = 0;
+ }
+ }
+
+ if (type == SD_TYPE_LITERAL) {
+ SD_GETBITS(x, x);
+ y += x;
+ if ((int)(y + 1) > (d - dst))
+ return false; // Overflow?
+ do {
+ SD_GETBITS(x, 8);
+ *--d = x;
+ } while (y-- > 0);
+ } else {
+ if ((int)(y + 1) > (d - dst))
+ return false; // Overflow?
+ SD_GETBITS(x, x);
+ if ((d + x) > (dst + destlen))
+ return false; // Offset overflow?
+ do {
+ d--;
+ *d = d[x];
+ } while (y-- > 0);
+ }
+ }
+
+ // Successful decrunch.
+ return true;
+}
+
+#undef SD_GETBIT
+#undef SD_GETBITS
+#undef SD_TYPE_LITERAL
+#undef SD_TYPE_MATCH
+
+void SimonEngine::loadSimonVGAFile(uint vga_id) {
+ uint32 offs, size;
+
+ if (getFeatures() & GF_OLD_BUNDLE) {
+ File in;
+ char filename[15];
+ if (vga_id == 23)
+ vga_id = 112;
+ if (vga_id == 328)
+ vga_id = 119;
+
+ if (getPlatform() == Common::kPlatformAmiga) {
+ if (getFeatures() & GF_TALKIE)
+ sprintf(filename, "0%d.out", vga_id);
+ else
+ sprintf(filename, "0%d.pkd", vga_id);
+ } else {
+ sprintf(filename, "0%d.VGA", vga_id);
+ }
+
+ in.open(filename);
+ if (in.isOpen() == false)
+ error("loadSimonVGAFile: Can't load %s", filename);
+
+ size = in.size();
+ if (getFeatures() & GF_CRUNCHED) {
+ byte *srcBuffer = (byte *)malloc(size);
+ if (in.read(srcBuffer, size) != size)
+ error("loadSimonVGAFile: Read failed");
+ decrunchFile(srcBuffer, _vgaBufferPointers[11].vgaFile2, size);
+ free(srcBuffer);
+ } else {
+ if (in.read(_vgaBufferPointers[11].vgaFile2, size) != size)
+ error("loadSimonVGAFile: Read failed");
+ }
+ in.close();
+ } else {
+ offs = _gameOffsetsPtr[vga_id];
+
+ size = _gameOffsetsPtr[vga_id + 1] - offs;
+ readGameFile(_vgaBufferPointers[11].vgaFile2, offs, size);
+ }
+}
+
+byte *SimonEngine::loadVGAFile(uint id, uint type, uint32 &dstSize) {
+ File in;
+ char filename[15];
+ byte *dst = NULL;
+ uint32 file, offs, srcSize;
+ uint extraBuffer = 0;
+
+ if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) {
+ // !!! HACK !!!
+ // Allocate more space for text to cope with foreign languages that use
+ // up more space than english. I hope 6400 bytes are enough. This number
+ // is base on: 2 (lines) * 320 (screen width) * 10 (textheight) -- olki
+ extraBuffer = (id == 5 ? 6400 : 0);
+ }
+
+ if (getFeatures() & GF_ZLIBCOMP) {
+ if (getPlatform() == Common::kPlatformAmiga) {
+ loadOffsets((const char*)"gfxindex.dat", id / 2 * 3 + type, file, offs, srcSize, dstSize);
+ } else {
+ loadOffsets((const char*)"graphics.vga", id / 2 * 3 + type, file, offs, srcSize, dstSize);
+ }
+
+ if (getPlatform() == Common::kPlatformAmiga)
+ sprintf(filename, "GFX%d.VGA", file);
+ else
+ sprintf(filename, "graphics.vga");
+
+ dst = allocBlock(dstSize + extraBuffer);
+ decompressData(filename, dst, offs, srcSize, dstSize);
+ } else if (getFeatures() & GF_OLD_BUNDLE) {
+ if (getPlatform() == Common::kPlatformAmiga) {
+ if (getFeatures() & GF_TALKIE)
+ sprintf(filename, "%.3d%d.out", id / 2, type);
+ else
+ sprintf(filename, "%.3d%d.pkd", id / 2, type);
+ } else {
+ if (getGameType() == GType_WW) {
+ sprintf(filename, "%.2d%d.VGA", id / 2, type);
+ } else {
+ sprintf(filename, "%.3d%d.VGA", id / 2, type);
+ }
+ }
+
+ in.open(filename);
+ if (in.isOpen() == false) {
+ if (type == 3)
+ return NULL;
+ else
+ error("loadVGAFile: Can't load %s", filename);
+ }
+
+ dstSize = srcSize = in.size();
+ if (getFeatures() & GF_CRUNCHED) {
+ byte *srcBuffer = (byte *)malloc(srcSize);
+ if (in.read(srcBuffer, srcSize) != srcSize)
+ error("loadVGAFile: Read failed");
+
+ dstSize = READ_BE_UINT32(srcBuffer + srcSize - 4);
+ dst = allocBlock (dstSize + extraBuffer);
+ decrunchFile(srcBuffer, dst, srcSize);
+ free(srcBuffer);
+ } else {
+ dst = allocBlock(dstSize + extraBuffer);
+ if (in.read(dst, dstSize) != dstSize)
+ error("loadVGAFile: Read failed");
+ }
+ in.close();
+ } else {
+ offs = _gameOffsetsPtr[id];
+
+ dstSize = _gameOffsetsPtr[id + 1] - offs;
+ dst = allocBlock(dstSize + extraBuffer);
+ readGameFile(dst, offs, dstSize);
+ }
+
+ dstSize += extraBuffer;
+ return dst;
+}
+
+static const char *dimpSoundList[32] = {
+ "Beep",
+ "Birth",
+ "Boiling",
+ "Burp",
+ "Cough",
+ "Die1",
+ "Die2",
+ "Fart",
+ "Inject",
+ "Killchik",
+ "Puke",
+ "Lights",
+ "Shock",
+ "Snore",
+ "Snotty",
+ "Whip",
+ "Whistle",
+ "Work1",
+ "Work2",
+ "Yawn",
+ "And0w",
+ "And0x",
+ "And0y",
+ "And0z",
+ "And10",
+ "And11",
+ "And12",
+ "And13",
+ "And14",
+ "And15",
+ "And16",
+ "And17",
+};
+
+
+void SimonEngine::loadSound(uint sound, int pan, int vol, uint type) {
+ byte *dst;
+
+ if (getGameId() == GID_DIMP) {
+ File in;
+ char filename[15];
+
+ assert(sound >= 1 && sound <= 32);
+ sprintf(filename, "%s.wav", dimpSoundList[sound - 1]);
+
+ in.open(filename);
+ if (in.isOpen() == false)
+ error("loadSound: Can't load %s", filename);
+
+ uint32 dstSize = in.size();
+ dst = (byte *)malloc(dstSize);
+ if (in.read(dst, dstSize) != dstSize)
+ error("loadSound: Read failed");
+ in.close();
+ } else if (getFeatures() & GF_ZLIBCOMP) {
+ char filename[15];
+
+ uint32 file, offset, srcSize, dstSize;
+ if (getPlatform() == Common::kPlatformAmiga) {
+ loadOffsets((const char*)"sfxindex.dat", _zoneNumber * 22 + sound, file, offset, srcSize, dstSize);
+ } else {
+ loadOffsets((const char*)"effects.wav", _zoneNumber * 22 + sound, file, offset, srcSize, dstSize);
+ }
+
+ if (getPlatform() == Common::kPlatformAmiga)
+ sprintf(filename, "sfx%d.wav", file);
+ else
+ sprintf(filename, "effects.wav");
+
+ dst = (byte *)malloc(dstSize);
+ decompressData(filename, dst, offset, srcSize, dstSize);
+ } else {
+ if (!_curSfxFile)
+ error("loadSound: Can't load sound data file '%d3.VGA'", _zoneNumber);
+
+ dst = _curSfxFile + READ_LE_UINT32(_curSfxFile + sound * 4);
+ }
+
+ if (type == 3)
+ _sound->playSfx5Data(dst, sound, pan, vol);
+ else if (type == 2)
+ _sound->playAmbientData(dst, sound, pan, vol);
+ else
+ _sound->playSfxData(dst, sound, pan, vol);
+}
+
+void SimonEngine::loadVoice(uint speechId) {
+ if (getGameType() == GType_PP && speechId == 99)
+ return;
+
+ if (getFeatures() & GF_ZLIBCOMP) {
+ char filename[15];
+
+ uint32 file, offset, srcSize, dstSize;
+ if (getPlatform() == Common::kPlatformAmiga) {
+ loadOffsets((const char*)"spindex.dat", speechId, file, offset, srcSize, dstSize);
+ } else {
+ loadOffsets((const char*)"speech.wav", speechId, file, offset, srcSize, dstSize);
+ }
+
+ // Voice segment doesn't exist
+ if (offset == 0xFFFFFFFF && srcSize == 0xFFFFFFFF && dstSize == 0xFFFFFFFF) {
+ debug(0, "loadVoice: speechId %d removed", speechId);
+ return;
+ }
+
+ if (getPlatform() == Common::kPlatformAmiga)
+ sprintf(filename, "sp%d.wav", file);
+ else
+ sprintf(filename, "speech.wav");
+
+ byte *dst = (byte *)malloc(dstSize);
+ decompressData(filename, dst, offset, srcSize, dstSize);
+ _sound->playVoiceData(dst, speechId);
+ } else {
+ _sound->playVoice(speechId);
+ }
+}
+
+} // End of namespace Simon
diff --git a/engines/agos/rooms.cpp b/engines/agos/rooms.cpp
new file mode 100644
index 0000000000..ca2b84e9f9
--- /dev/null
+++ b/engines/agos/rooms.cpp
@@ -0,0 +1,114 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-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 "agos/agos.h"
+#include "agos/intern.h"
+
+using Common::File;
+
+namespace Simon {
+
+uint16 SimonEngine::getDoorState(Item *item, uint16 d) {
+ uint16 mask = 3;
+ uint16 n;
+
+ SubRoom *subRoom = (SubRoom *)findChildOfType(item, 1);
+ if (subRoom == NULL)
+ return 0;
+
+ d <<= 1;
+ mask <<= d;
+ n = subRoom->roomExitStates & mask;
+ n >>= d;
+
+ return n;
+}
+
+uint16 SimonEngine::getExitOf(Item *item, uint16 d) {
+ uint16 x;
+ uint16 y = 0;
+
+ SubRoom *subRoom = (SubRoom *)findChildOfType(item, 1);
+ if (subRoom == NULL)
+ return 0;
+ x = d;
+ while (x > y) {
+ if (getDoorState(item, y) == 0)
+ d--;
+ y++;
+ }
+ return subRoom->roomExit[d];
+}
+
+bool SimonEngine::loadRoomItems(uint item) {
+ byte *p;
+ uint i, min_num, max_num;
+ char filename[30];
+ File in;
+
+ p = _roomsList;
+ if (p == NULL)
+ return 0;
+
+ while (*p) {
+ for (i = 0; *p; p++, i++)
+ filename[i] = *p;
+ filename[i] = 0;
+ p++;
+
+ for (;;) {
+ min_num = (p[0] * 256) | p[1];
+ p += 2;
+
+ if (min_num == 0)
+ break;
+
+ max_num = (p[0] * 256) | p[1];
+ p += 2;
+
+ if (item >= min_num && item <= max_num) {
+
+ in.open(filename);
+ if (in.isOpen() == false) {
+ error("loadRoomItems: Can't load rooms file '%s'", filename);
+ }
+
+ for (i = min_num; i <= max_num; i++) {
+ _itemArrayPtr[i] = (Item *)allocateItem(sizeof(Item));
+ in.readUint16BE();
+ readItemFromGamePc(&in, _itemArrayPtr[i]);
+ }
+ in.close();
+
+ return 1;
+ }
+ }
+ }
+
+ debug(1,"loadRoomItems: didn't find %d", item);
+ return 0;
+}
+
+} // End of namespace Simon
diff --git a/engines/agos/saveload.cpp b/engines/agos/saveload.cpp
new file mode 100644
index 0000000000..37907024b6
--- /dev/null
+++ b/engines/agos/saveload.cpp
@@ -0,0 +1,821 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-2006 The ScummVM project
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/stdafx.h"
+
+#include "common/savefile.h"
+#include "common/system.h"
+
+#include "gui/about.h"
+#include "gui/message.h"
+
+#include "agos/agos.h"
+#include "agos/intern.h"
+
+namespace Simon {
+
+int SimonEngine::countSaveGames() {
+ Common::InSaveFile *f;
+ uint i = 1;
+ bool marks[256];
+
+ char *prefix = genSaveName(999);
+ prefix[strlen(prefix)-3] = '\0';
+ _saveFileMan->listSavefiles(prefix, marks, 256);
+
+ while (i < 256) {
+ if (marks[i] &&
+ (f = _saveFileMan->openForLoading(genSaveName(i)))) {
+ i++;
+ delete f;
+ } else
+ break;
+ }
+ return i;
+}
+
+int SimonEngine::displaySaveGameList(int curpos, bool load, char *dst) {
+ int slot, last_slot;
+ Common::InSaveFile *in;
+
+ showMessageFormat("\xC");
+
+ memset(dst, 0, 108);
+
+ slot = curpos;
+
+ while (curpos + 6 > slot) {
+ if (!(in = _saveFileMan->openForLoading(genSaveName(slot))))
+ break;
+
+ in->read(dst, 18);
+ delete in;
+
+ last_slot = slot;
+ if (slot < 10) {
+ showMessageFormat(" ");
+ } else if (_language == Common::HB_ISR) {
+ last_slot = (slot % 10) * 10;
+ last_slot += slot / 10;
+ }
+
+ if (_language == Common::HB_ISR && !(slot % 10))
+ showMessageFormat("0");
+ showMessageFormat("%d", last_slot);
+ showMessageFormat(".%s\n", dst);
+ dst += 18;
+ slot++;
+ }
+ // while_break
+ if (!load) {
+ if (curpos + 6 == slot)
+ slot++;
+ else {
+ if (slot < 10)
+ showMessageFormat(" ");
+ showMessageFormat("%d.\n", slot);
+ }
+ } else {
+ if (curpos + 6 == slot) {
+ if ((in = _saveFileMan->openForLoading(genSaveName(slot)))) {
+ slot++;
+ delete in;
+ }
+ }
+ }
+
+ return slot - curpos;
+}
+
+char *SimonEngine::genSaveName(int slot) {
+ static char buf[15];
+
+ if (getGameType() == GType_FF) {
+ if (slot == 999) {
+ // Restart state
+ if (getPlatform() == Common::kPlatformWindows)
+ sprintf(buf, "save.%.3d", slot);
+ else
+ sprintf(buf, "setup");
+ } else {
+ sprintf(buf, "feeble.%.3d", slot);
+ }
+ } else if (getGameType() == GType_SIMON2) {
+ sprintf(buf, "simon2.%.3d", slot);
+ } else {
+ sprintf(buf, "simon1.%.3d", slot);
+ }
+ return buf;
+}
+
+void SimonEngine::quickLoadOrSave() {
+ // The demo of Simon 1 (DOS Floppy) is missing too many segments
+ // and the Feeble Files doesn't always allow a load or save
+ if (getGameId() == GID_SIMON1DEMO || getGameType() == GType_FF)
+ return;
+
+ bool success;
+ char buf[50];
+
+ char *filename = genSaveName(_saveLoadSlot);
+ if (_saveLoadType == 2) {
+ Subroutine *sub;
+ success = loadGame(_saveLoadSlot);
+ if (!success) {
+ sprintf(buf, "Failed to load game state to file:\n\n%s", filename);
+ } else {
+ // Redraw Inventory
+ mouseOff();
+ drawIconArray(2, me(), 0, 0);
+ mouseOn();
+ // Reset engine?
+ setBitFlag(97, true);
+ sub = getSubroutineByID(100);
+ startSubroutine(sub);
+ }
+ } else {
+ success = saveGame(_saveLoadSlot, _saveLoadName);
+ if (!success)
+ sprintf(buf, "Failed to save game state to file:\n\n%s", filename);
+ }
+
+ if (!success) {
+ GUI::MessageDialog dialog(buf, "OK");
+ dialog.runModal();
+
+ } else if (_saveLoadType == 1) {
+ sprintf(buf, "Successfully saved game state in file:\n\n%s", filename);
+ GUI::TimedMessageDialog dialog(buf, 1500);
+ dialog.runModal();
+
+ }
+
+ _saveLoadType = 0;
+}
+
+void SimonEngine::listSaveGames(char *buf) {
+ int i;
+
+ disableFileBoxes();
+
+ i = displaySaveGameList(_saveLoadRowCurPos, _saveOrLoad, buf);
+
+ _saveDialogFlag = true;
+
+ if (i != 7) {
+ i++;
+ if (!_saveOrLoad)
+ i++;
+ _saveDialogFlag = false;
+ }
+
+ if (!--i)
+ return;
+
+ do {
+ enableBox(208 + i - 1);
+ } while (--i);
+}
+
+
+const byte hebrewKeyTable[96] = {
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 90, 45, 85, 47, 48, 49, 50,
+ 51, 52, 53, 54, 55, 56, 57, 83, 83, 90, 61, 85, 63, 35, 89, 80, 65, 66, 87,
+ 75, 82, 73, 79, 71, 76, 74, 86, 78, 77, 84, 47, 88, 67, 64, 69, 68, 44, 81,
+ 72, 70, 91, 92, 93, 94, 95, 96, 89, 80, 65, 66, 87, 75, 82, 73, 79, 71, 76,
+ 74, 86, 78, 77, 84, 47, 88, 67, 64, 69, 68, 44, 81, 72, 70,
+ 123, 124, 125, 126, 127,
+};
+
+void SimonEngine::userGame(bool load) {
+ time_t save_time;
+ int number_of_savegames;
+ int i, name_len, result;
+ WindowBlock *window;
+ char *name;
+ bool b;
+ char buf[108];
+ int maxChar = (_language == Common::HB_ISR) ? 155: 128;
+
+ _saveOrLoad = load;
+
+ save_time = time(NULL);
+
+ _copyPartialMode = 1;
+
+ number_of_savegames = countSaveGames();
+ if (!load)
+ number_of_savegames++;
+ number_of_savegames -= 6;
+ if (number_of_savegames < 0)
+ number_of_savegames = 0;
+ number_of_savegames++;
+ _numSaveGameRows = number_of_savegames;
+
+ _saveLoadRowCurPos = 1;
+ if (!load)
+ _saveLoadRowCurPos = number_of_savegames;
+
+ _saveLoadEdit = false;
+
+restart:;
+ do {
+ i = userGameGetKey(&b, buf);
+ } while (!b);
+
+ if (i == 205)
+ goto get_out;
+ if (!load) {
+ // if_1
+ if_1:;
+ result = i;
+
+ disableBox(208 + i);
+ leaveHitAreaById(208 + i);
+
+ window = _windowArray[5];
+
+ window->textRow = result;
+
+ // init x offset with a 2 character savegame number + a period (18 pix)
+ if (_language == Common::HB_ISR) {
+ window->textColumn = 3;
+ window->textColumnOffset = 6;
+ window->textLength = 3;
+ } else {
+ window->textColumn = 2;
+ window->textColumnOffset = 2;
+ window->textLength = 3;
+ }
+
+ name = buf + i * 18;
+
+ // now process entire savegame name to get correct x offset for cursor
+ name_len = 0;
+ while (name[name_len]) {
+ if (_language == Common::HB_ISR) {
+ byte width = 6;
+ if (name[name_len] >= 64 && name[name_len] < 91)
+ width = _hebrewCharWidths [name[name_len] - 64];
+ window->textLength++;
+ window->textColumnOffset -= width;
+ if (window->textColumnOffset < width) {
+ window->textColumnOffset += 8;
+ window->textColumn++;
+ }
+ } else {
+ window->textLength++;
+ window->textColumnOffset += 6;
+ if (name[name_len] == 'i' || name[name_len] == 'l')
+ window->textColumnOffset -= 2;
+ if (window->textColumnOffset >= 8) {
+ window->textColumnOffset -= 8;
+ window->textColumn++;
+ }
+ }
+ name_len++;
+ }
+ // while_1_end
+
+ // do_3_start
+ for (;;) {
+ windowPutChar(window, 0x7f);
+
+ _saveLoadEdit = true;
+
+ // do_2
+ do {
+ i = userGameGetKey(&b, buf);
+
+ if (b) {
+ if (i == 205)
+ goto get_out;
+ enableBox(208 + result);
+ if (_saveLoadEdit) {
+ userGameBackSpace(_windowArray[5], 8);
+ }
+ goto if_1;
+ }
+
+ // is_not_b
+ if (!_saveLoadEdit) {
+ enableBox(208 + result);
+ goto restart;
+ }
+ } while (i >= maxChar || i == 0);
+
+ if (_language == Common::HB_ISR) {
+ if (i >= 128)
+ i -= 64;
+ else if (i >= 32)
+ i = hebrewKeyTable[i - 32];
+ }
+
+ // after_do_2
+ userGameBackSpace(_windowArray[5], 8);
+ if (i == 10 || i == 13)
+ break;
+ if (i == 8) {
+ // do_backspace
+ if (name_len != 0) {
+ int x;
+ byte m;
+
+ name_len--;
+ m = name[name_len];
+
+ if (_language == Common::HB_ISR)
+ x = 8;
+ else
+ x = (name[name_len] == 'i' || name[name_len] == 'l') ? 1 : 8;
+
+ name[name_len] = 0;
+
+ userGameBackSpace(_windowArray[5], x, m);
+ }
+ } else if (i >= 32 && name_len != 17) {
+ name[name_len++] = i;
+
+ windowPutChar(_windowArray[5], i);
+ }
+ }
+
+ // do_save
+ if (!saveGame(_saveLoadRowCurPos + result, buf + result * 18))
+ fileError(_windowArray[5], true);
+ } else {
+ if (!loadGame(_saveLoadRowCurPos + i))
+ fileError(_windowArray[5], false);
+ }
+
+get_out:;
+ disableFileBoxes();
+
+ _gameStoppedClock = time(NULL) - save_time + _gameStoppedClock;
+ _copyPartialMode = 0;
+
+ restoreBlock(94, 208, 46, 80);
+
+ i = _timer4;
+ do {
+ delay(10);
+ } while (i == _timer4);
+}
+
+int SimonEngine::userGameGetKey(bool *b, char *buf) {
+ HitArea *ha;
+ *b = true;
+
+ if (!_saveLoadEdit) {
+ listSaveGames(buf);
+ }
+
+ _keyPressed = 0;
+
+ for (;;) {
+ _lastHitArea = NULL;
+ _lastHitArea3 = NULL;
+
+ do {
+ if (_saveLoadEdit && _keyPressed != 0) {
+ *b = false;
+ return _keyPressed;
+ }
+ delay(10);
+ } while (_lastHitArea3 == 0);
+
+ ha = _lastHitArea;
+
+ if (ha == NULL || ha->id < 205) {
+ } else if (ha->id == 205) {
+ return ha->id;
+ } else if (ha->id == 206) {
+ if (_saveLoadRowCurPos != 1) {
+ if (_saveLoadRowCurPos < 7)
+ _saveLoadRowCurPos = 1;
+ else
+ _saveLoadRowCurPos -= 6;
+
+ _saveLoadEdit = false;
+ listSaveGames(buf);
+ }
+ } else if (ha->id == 207) {
+ if (_saveDialogFlag) {
+ _saveLoadRowCurPos += 6;
+ if (_saveLoadRowCurPos >= _numSaveGameRows)
+ _saveLoadRowCurPos = _numSaveGameRows;
+
+ _saveLoadEdit = false;
+ listSaveGames(buf);
+ }
+ } else if (ha->id < 214) {
+ return ha->id - 208;
+ }
+ }
+}
+
+void SimonEngine::disableFileBoxes() {
+ for (int i = 208; i != 214; i++)
+ disableBox(i);
+}
+
+void SimonEngine::userGameBackSpace(WindowBlock *window, int x, byte b) {
+ byte old_text;
+
+ windowPutChar(window, x, b);
+ old_text = window->text_color;
+ window->text_color = window->fill_color;
+
+ if (_language == Common::HB_ISR) {
+ x = 128;
+ } else {
+ x += 120;
+ if (x != 128)
+ x = 129;
+ }
+
+ windowPutChar(window, x);
+
+ window->text_color = old_text;
+ windowPutChar(window, 8);
+}
+
+void SimonEngine::fileError(WindowBlock *window, bool save_error) {
+ HitArea *ha;
+ const char *string1, *string2;
+
+ if (save_error) {
+ switch (_language) {
+ case Common::RU_RUS:
+ if (getGameType() == GType_SIMON2) {
+ string1 = "\r Mf sowrap+fts+.";
+ string2 = "\r Nzjb#a ejs#a.";
+ } else {
+ string1 = "\r Mf sowrap]fts].";
+ string2 = "\r Nzjb_a ejs_a.";
+ }
+ break;
+ case Common::PL_POL:
+ string1 = "\r Blad zapisu. ";
+ string2 = "\rBlad dysku. ";
+ break;
+ case Common::ES_ESP:
+ string1 = "\r Error al salvar";
+ string2 = "\r Intenta con otro disco";
+ break;
+ case Common::IT_ITA:
+ string1 = "\r Salvataggio non riuscito";
+ string2 = "\r Prova un""\x27""altro disco";
+ break;
+ case Common::FR_FRA:
+ string1 = "\r Echec sauvegarde";
+ string2 = "\rEssayez une autre disquette";
+ break;
+ case Common::DE_DEU:
+ string1 = "\r Sicherung erfolglos.";
+ string2 = "\rVersuche eine andere Diskette.";
+ break;
+ default:
+ string1 = "\r Save failed.";
+ string2 = "\r Disk error.";
+ break;
+ }
+ } else {
+ switch (_language) {
+ case Common::RU_RUS:
+ if (getGameType() == GType_SIMON2) {
+ string1 = "\r Mf ^adruhafts+.";
+ string2 = "\r Takm pf pakefp.";
+ } else {
+ string1 = "\r Mf ^adruhafts].";
+ string2 = "\r Takm pf pakefp.";
+ }
+ break;
+ case Common::PL_POL:
+ string1 = "\r Blad odczytu. ";
+ string2 = "\r Nie znaleziono pliku.";
+ break;
+ case Common::ES_ESP:
+ string1 = "\r Error al cargar";
+ string2 = "\r Archivo no encontrado";
+ break;
+ case Common::IT_ITA:
+ string1 = "\r Caricamento non riuscito";
+ string2 = "\r File non trovato";
+ break;
+ case Common::FR_FRA:
+ string1 = "\r Echec chargement";
+ string2 = "\r Fichier introuvable";
+ break;
+ case Common::DE_DEU:
+ string1 = "\r Laden erfolglos.";
+ string2 = "\r Datei nicht gefunden.";
+ break;
+ default:
+ string1 = "\r Load failed.";
+ string2 = "\r File not found.";
+ break;
+ }
+ }
+
+ windowPutChar(window, 0xC);
+ for (; *string1; string1++)
+ windowPutChar(window, *string1);
+ for (; *string2; string2++)
+ windowPutChar(window, *string2);
+
+ window->textColumn = (window->width / 2) - 3;
+ window->textRow = window->height - 1;
+ window->textLength = 0;
+
+ string1 = "[ OK ]";
+ for (; *string1; string1++)
+ windowPutChar(window, *string1);
+
+ ha = findEmptyHitArea();
+ ha->x = ((window->width / 2) + (window->x - 3)) * 8;
+ ha->y = (window->height * 8) + window->y - 8;
+ ha->width = 48;
+ ha->height = 8;
+ ha->flags = kBFBoxInUse;
+ ha->id = 0x7FFF;
+ ha->priority = 0x3EF;
+
+loop:;
+ _lastHitArea = _lastHitArea3 = 0;
+
+ do {
+ delay(1);
+ } while (_lastHitArea3 == 0);
+
+ ha = _lastHitArea;
+ if (ha == NULL || ha->id != 0x7FFF)
+ goto loop;
+
+ // Return
+ undefineBox(0x7FFF);
+}
+
+bool SimonEngine::saveGame(uint slot, char *caption) {
+ Common::WriteStream *f;
+ uint item_index, num_item, i, j;
+ TimeEvent *te;
+ uint32 curTime = 0;
+ uint32 gsc = _gameStoppedClock;
+
+ _lockWord |= 0x100;
+
+ f = _saveFileMan->openForSaving(genSaveName(slot));
+ if (f == NULL) {
+ warning("saveGame: Failed to save slot %d", slot);
+ _lockWord &= ~0x100;
+ return false;
+ }
+
+ if (getGameType() == GType_FF) {
+ f->write(caption, 100);
+ curTime = time(NULL);
+ } else {
+ f->write(caption, 18);
+ }
+
+ f->writeUint32BE(_itemArrayInited - 1);
+ f->writeUint32BE(0xFFFFFFFF);
+ f->writeUint32BE(0);
+ f->writeUint32BE(0);
+
+ i = 0;
+ for (te = _firstTimeStruct; te; te = te->next)
+ i++;
+ f->writeUint32BE(i);
+
+ if (_clockStopped)
+ gsc += ((uint32)time(NULL) - _clockStopped);
+ for (te = _firstTimeStruct; te; te = te->next) {
+ f->writeUint32BE(te->time - curTime + gsc);
+ f->writeUint16BE(te->subroutine_id);
+ }
+
+ item_index = 1;
+ for (num_item = _itemArrayInited - 1; num_item; num_item--) {
+ Item *item = _itemArrayPtr[item_index++];
+
+ f->writeUint16BE(item->parent);
+ f->writeUint16BE(item->sibling);
+ f->writeUint16BE(item->state);
+ f->writeUint16BE(item->classFlags);
+
+ SubRoom *subRoom = (SubRoom *)findChildOfType(item, 1);
+ if (subRoom) {
+ f->writeUint16BE(subRoom->roomExitStates);
+ }
+
+ SubObject *subObject = (SubObject *)findChildOfType(item, 2);
+ if (subObject) {
+ f->writeUint32BE(subObject->objectFlags);
+ i = subObject->objectFlags & 1;
+
+ for (j = 1; j < 16; j++) {
+ if (subObject->objectFlags & (1 << j)) {
+ f->writeUint16BE(subObject->objectFlagValue[i++]);
+ }
+ }
+ }
+
+ SubUserFlag *subUserFlag = (SubUserFlag *)findChildOfType(item, 9);
+ if (subUserFlag) {
+ for (i = 0; i != 4; i++) {
+ f->writeUint16BE(subUserFlag->userFlags[i]);
+ }
+ }
+ }
+
+ // write the 255 variables
+ for (i = 0; i != 255; i++) {
+ f->writeUint16BE(readVariable(i));
+ }
+
+ // write the items in array 6
+ for (i = 0; i != 10; i++) {
+ f->writeUint16BE(itemPtrToID(_itemStore[i]));
+ }
+
+ // Write the bits in array 1
+ for (i = 0; i != 16; i++)
+ f->writeUint16BE(_bitArray[i]);
+
+ // Write the bits in array 2
+ for (i = 0; i != 16; i++)
+ f->writeUint16BE(_bitArrayTwo[i]);
+
+ // Write the bits in array 3
+ if (getGameType() == GType_FF) {
+ for (i = 0; i != 16; i++)
+ f->writeUint16BE(_bitArrayThree[i]);
+ }
+
+ f->flush();
+ bool result = !f->ioFailed();
+
+ delete f;
+ _lockWord &= ~0x100;
+
+ return result;
+}
+
+bool SimonEngine::loadGame(uint slot) {
+ char ident[100];
+ Common::SeekableReadStream *f = NULL;
+ uint num, item_index, i, j;
+
+ _lockWord |= 0x100;
+
+ if (getGameType() == GType_FF && slot == 999) {
+ // Load restart state
+ Common::File *file = new Common::File();
+ file->open(genSaveName(slot), Common::File::kFileReadMode);
+ if (!file->isOpen()) {
+ delete file;
+ } else {
+ f = file;
+ }
+ } else {
+ f = _saveFileMan->openForLoading(genSaveName(slot));
+ }
+
+ if (f == NULL) {
+ warning("loadGame: Failed to load slot %d", slot);
+ _lockWord &= ~0x100;
+ return false;
+ }
+
+ if (getGameType() == GType_FF) {
+ f->read(ident, 100);
+ } else {
+ f->read(ident, 18);
+ }
+
+ num = f->readUint32BE();
+
+ if (f->readUint32BE() != 0xFFFFFFFF || num != _itemArrayInited - 1) {
+ delete f;
+ _lockWord &= ~0x100;
+ return false;
+ }
+
+ f->readUint32BE();
+ f->readUint32BE();
+ _noParentNotify = true;
+
+
+ // add all timers
+ killAllTimers();
+ for (num = f->readUint32BE(); num; num--) {
+ uint32 timeout = f->readUint32BE();
+ uint16 func_to_call = f->readUint16BE();
+ addTimeEvent(timeout, func_to_call);
+ }
+
+ item_index = 1;
+ for (num = _itemArrayInited - 1; num; num--) {
+ Item *item = _itemArrayPtr[item_index++], *parent_item;
+
+ uint parent = f->readUint16BE();
+ uint sibling = f->readUint16BE();
+
+ parent_item = derefItem(parent);
+
+ setItemParent(item, parent_item);
+
+ if (parent_item == NULL) {
+ item->parent = parent;
+ item->sibling = sibling;
+ }
+
+ item->state = f->readUint16BE();
+ item->classFlags = f->readUint16BE();
+
+ SubRoom *subRoom = (SubRoom *)findChildOfType(item, 1);
+ if (subRoom != NULL) {
+ subRoom->roomExitStates = f->readUint16BE();
+ }
+
+ SubObject *subObject = (SubObject *)findChildOfType(item, 2);
+ if (subObject != NULL) {
+ subObject->objectFlags = f->readUint32BE();
+ i = subObject->objectFlags & 1;
+
+ for (j = 1; j < 16; j++) {
+ if (subObject->objectFlags & (1 << j)) {
+ subObject->objectFlagValue[i++] = f->readUint16BE();
+ }
+ }
+ }
+
+ SubUserFlag *subUserFlag = (SubUserFlag *) findChildOfType(item, 9);
+ if (subUserFlag) {
+ for (i = 0; i != 4; i++) {
+ subUserFlag->userFlags[i] = f->readUint16BE();
+ }
+ }
+ }
+
+
+ // read the 255 variables
+ for (i = 0; i != 255; i++) {
+ writeVariable(i, f->readUint16BE());
+ }
+
+ // read the items in array 6
+ for (i = 0; i != 10; i++) {
+ _itemStore[i] = derefItem(f->readUint16BE());
+ }
+
+ // Read the bits in array 1
+ for (i = 0; i != 16; i++)
+ _bitArray[i] = f->readUint16BE();
+
+ // Read the bits in array 2
+ for (i = 0; i != 16; i++)
+ _bitArrayTwo[i] = f->readUint16BE();
+
+ // Read the bits in array 3
+ if (getGameType() == GType_FF) {
+ for (i = 0; i != 16; i++)
+ _bitArrayThree[i] = f->readUint16BE();
+ }
+
+ if (f->ioFailed()) {
+ error("load failed");
+ }
+
+ delete f;
+
+ _noParentNotify = false;
+
+ _lockWord &= ~0x100;
+
+ return true;
+}
+
+} // End of namespace Simon
diff --git a/engines/agos/simon.cpp b/engines/agos/simon.cpp
new file mode 100644
index 0000000000..4248e311ce
--- /dev/null
+++ b/engines/agos/simon.cpp
@@ -0,0 +1,2292 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-2006 The ScummVM project
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/stdafx.h"
+
+#include "common/config-manager.h"
+#include "common/file.h"
+#include "common/fs.h"
+#include "common/system.h"
+
+#include "gui/about.h"
+
+#include "agos/debugger.h"
+#include "agos/intern.h"
+#include "agos/agos.h"
+#include "agos/vga.h"
+
+#include "sound/mididrv.h"
+
+#ifdef PALMOS_68K
+#include "globals.h"
+#endif
+
+using Common::File;
+
+namespace Simon {
+
+#ifdef PALMOS_68K
+#define PTR(a) a
+static const GameSpecificSettings *simon1_settings;
+static const GameSpecificSettings *simon2_settings;
+static const GameSpecificSettings *feeblefiles_settings;
+#else
+#define PTR(a) &a
+static const GameSpecificSettings simon1_settings = {
+ "EFFECTS", // effects_filename
+ "SIMON", // speech_filename
+};
+
+static const GameSpecificSettings simon2_settings = {
+ "", // effects_filename
+ "SIMON2", // speech_filename
+};
+
+static const GameSpecificSettings feeblefiles_settings = {
+ "", // effects_filename
+ "VOICES", // speech_filename
+};
+
+static const GameSpecificSettings puzzlepack_settings = {
+ "", // effects_filename
+ "MUSIC", // speech_filename
+};
+#endif
+
+SimonEngine::SimonEngine(OSystem *syst)
+ : Engine(syst), midi(syst) {
+ _vcPtr = 0;
+ _vc_get_out_of_code = 0;
+ _gameOffsetsPtr = 0;
+
+ _debugger = 0;
+ setupVgaOpcodes();
+
+ _keyPressed = 0;
+
+ _gameFile = 0;
+
+ _strippedTxtMem = 0;
+ _textMem = 0;
+ _textSize = 0;
+ _stringTabNum = 0;
+ _stringTabPos = 0;
+ _stringtab_numalloc = 0;
+ _stringTabPtr = 0;
+
+ _itemArrayPtr = 0;
+ _itemArraySize = 0;
+ _itemArrayInited = 0;
+
+ _itemHeapPtr = 0;
+ _itemHeapCurPos = 0;
+ _itemHeapSize = 0;
+
+ _iconFilePtr = 0;
+
+ _codePtr = 0;
+
+ _localStringtable = 0;
+ _stringIdLocalMin = 0;
+ _stringIdLocalMax = 0;
+
+ _roomsList = 0;
+
+ _xtblList = 0;
+ _xtablesHeapPtrOrg = 0;
+ _xtablesHeapCurPosOrg = 0;
+ _xsubroutineListOrg = 0;
+
+ _tblList = 0;
+ _tablesHeapPtr = 0;
+ _tablesHeapPtrOrg = 0;
+ _tablesheapPtrNew = 0;
+ _tablesHeapSize = 0;
+ _tablesHeapCurPos = 0;
+ _tablesHeapCurPosOrg = 0;
+ _tablesHeapCurPosNew = 0;
+ _subroutineListOrg = 0;
+
+ _subroutineList = 0;
+ _subroutine = 0;
+
+ _dxSurfacePitch = 0;
+
+ _recursionDepth = 0;
+
+ _lastVgaTick = 0;
+
+ _marks = 0;
+
+ _scriptVar2 = 0;
+ _runScriptReturn1 = 0;
+ _skipVgaWait = 0;
+ _noParentNotify = 0;
+ _beardLoaded = 0;
+ _hitarea_unk_3 = 0;
+ _mortalFlag = 0;
+ _updateScreen = false;
+ _usePaletteDelay = 0;
+ _syncFlag2 = 0;
+ _inCallBack = 0;
+ _cepeFlag = 0;
+ _copyPartialMode = 0;
+ _fastMode = 0;
+ _useBackGround = 0;
+
+ _debugMode = 0;
+ _startMainScript = false;
+ _continousMainScript = false;
+ _startVgaScript = false;
+ _continousVgaScript = false;
+ _drawImagesDebug = false;
+ _dumpImages = false;
+
+ _pause = false;
+ _speech = false;
+ _subtitles = false;
+
+ _animatePointer = 0;
+ _mouseCursor = 0;
+ _mouseAnim = 0;
+ _mouseAnimMax = 0;
+ _oldMouseCursor = 0;
+ _currentMouseCursor = 0;
+ _currentMouseAnim = 0;
+ _oldMouseAnimMax = 0;
+
+ _vgaVar9 = 0;
+ _chanceModifier = 0;
+ _restoreWindow6 = 0;
+ _scrollX = 0;
+ _scrollY = 0;
+ _scrollXMax = 0;
+ _scrollYMax = 0;
+ _scrollCount = 0;
+ _scrollFlag = 0;
+ _scrollHeight = 0;
+ _scrollWidth = 0;
+ _scrollImage = 0;
+ _boxStarHeight = 0;
+
+ _scriptVerb = 0;
+ _scriptNoun1 = 0;
+ _scriptNoun2 = 0;
+ _scriptAdj1 = 0;
+ _scriptAdj2 = 0;
+
+ _curWindow = 0;
+ _textWindow = 0;
+
+ _subjectItem = 0;
+ _objectItem = 0;
+ _currentPlayer = 0;
+
+ _currentBoxNumber = 0;
+ _iOverflow = 0;
+ _hitAreaObjectItem = 0;
+ _lastHitArea = 0;
+ _lastNameOn = 0;
+ _lastHitArea3 = 0;
+ _hitAreaSubjectItem = 0;
+ _currentVerbBox = 0;
+ _lastVerbOn = 0;
+ _needHitAreaRecalc = 0;
+ _verbHitArea = 0;
+ _defaultVerb = 0;
+ _mouseHideCount = 0;
+
+ _windowNum = 0;
+
+ _printCharCurPos = 0;
+ _printCharMaxPos = 0;
+ _printCharPixelCount = 0;
+ _numLettersToPrint = 0;
+
+ _numTextBoxes = 0;
+
+ _clockStopped = 0;
+ _gameStoppedClock = 0;
+ _lastTime = 0;
+
+ _firstTimeStruct = 0;
+ _pendingDeleteTimeEvent = 0;
+
+ _mouseX = 0;
+ _mouseY = 0;
+ _mouseXOld = 0;
+ _mouseYOld = 0;
+
+ _leftButtonDown = 0;
+ _rightButtonDown = 0;
+ _noRightClick = false;
+
+ _dummyItem1 = new Item();
+ _dummyItem2 = new Item();
+ _dummyItem3 = new Item();
+
+ _lockWord = 0;
+ _scrollUpHitArea = 0;
+ _scrollDownHitArea = 0;
+
+ _fastFadeInFlag = 0;
+
+ _noOverWrite = 0;
+ _rejectBlock = false;
+
+ _fastFadeOutFlag = 0;
+ _unkPalFlag = 0;
+ _exitCutscene = 0;
+ _paletteFlag = 0;
+
+ _soundFileId = 0;
+ _lastMusicPlayed = 0;
+ _nextMusicToPlay = 0;
+
+ _showPreposition = 0;
+ _showMessageFlag = 0;
+
+ _fastFadeCount = 0;
+
+ _vgaSpriteChanged = 0;
+
+ _vgaMemPtr = 0;
+ _vgaMemEnd = 0;
+ _vgaMemBase = 0;
+ _vgaFrozenBase = 0;
+ _vgaRealBase = 0;
+ _zoneBuffers = 0;
+
+ _curVgaFile1 = 0;
+ _curVgaFile2 = 0;
+ _curSfxFile = 0;
+
+ _syncCount = 0;
+ _timer5 = 0;
+ _timer4 = 0;
+
+ _frameRate = 0;
+
+ _zoneNumber = 0;
+
+ _vgaWaitFor = 0;
+ _lastVgaWaitFor = 0;
+
+ _vgaCurZoneNum = 0;
+ _vgaCurSpriteId = 0;
+ _vgaCurSpritePriority = 0;
+
+ _baseY = 0;
+ _scale = 0;
+
+ _feebleRect.left = 0;
+ _feebleRect.right = 0;
+ _feebleRect.top = 0;
+ _feebleRect.bottom = 0;
+
+ _scaleX = 0;
+ _scaleY = 0;
+ _scaleWidth = 0;
+ _scaleHeight = 0;
+
+ _nextVgaTimerToProcess = 0;
+
+ memset(_objectArray, 0, sizeof(_objectArray));
+ memset(_itemStore, 0, sizeof(_itemStore));
+
+ memset(_shortText, 0, sizeof(_shortText));
+ memset(_shortTextX, 0, sizeof(_shortText));
+ memset(_shortTextY, 0, sizeof(_shortText));
+ memset(_longText, 0, sizeof(_longText));
+ memset(_longSound, 0, sizeof(_longSound));
+
+ memset(_bitArray, 0, sizeof(_bitArray));
+ memset(_bitArrayTwo, 0, sizeof(_bitArrayTwo));
+ memset(_bitArrayThree, 0, sizeof(_bitArrayThree));
+
+ _variableArray = 0;
+ _variableArray2 = 0;
+ _variableArrayPtr = 0;
+
+ memset(_windowArray, 0, sizeof(_windowArray));
+
+ memset(_fcsData1, 0, sizeof(_fcsData1));
+ memset(_fcsData2, 0, sizeof(_fcsData2));
+
+ _freeStringSlot = 0;
+
+ memset(_stringReturnBuffer, 0, sizeof(_stringReturnBuffer));
+
+ memset(_pathFindArray, 0, sizeof(_pathFindArray));
+
+ memset(_pathValues, 0, sizeof(_pathValues));
+ _PVCount = 0;
+ _GPVCount = 0;
+
+ memset(_pathValues1, 0, sizeof(_pathValues1));
+ _PVCount1 = 0;
+ _GPVCount1 = 0;
+
+ memset(_currentPalette, 0, sizeof(_currentPalette));
+ memset(_displayPalette, 0, sizeof(_displayPalette));
+
+ memset(_videoBuf1, 0, sizeof(_videoBuf1));
+
+ _windowList = new WindowBlock[16];
+
+ memset(_lettersToPrintBuf, 0, sizeof(_lettersToPrintBuf));
+
+ _vgaTickCounter = 0;
+
+ _moviePlay = 0;
+ _sound = 0;
+
+ _effectsPaused = false;
+ _ambientPaused = false;
+ _musicPaused = false;
+
+ _saveLoadType = 0;
+ _saveLoadSlot = 0;
+ memset(_saveLoadName, 0, sizeof(_saveLoadName));
+
+ _saveLoadRowCurPos = 0;
+ _numSaveGameRows = 0;
+ _saveDialogFlag = false;
+ _saveOrLoad = false;
+ _saveLoadEdit = false;
+
+ _hyperLink = 0;
+ _interactY = 0;
+ _oracleMaxScrollY = 0;
+ _noOracleScroll = 0;
+
+ _sdlMouseX = 0;
+ _sdlMouseY = 0;
+
+ _backGroundBuf = 0;
+ _frontBuf = 0;
+ _backBuf = 0;
+ _scaleBuf = 0;
+
+ _vc10BasePtrOld = 0;
+ memcpy (_hebrewCharWidths,
+ "\x5\x5\x4\x6\x5\x3\x4\x5\x6\x3\x5\x5\x4\x6\x5\x3\x4\x6\x5\x6\x6\x6\x5\x5\x5\x6\x5\x6\x6\x6\x6\x6", 32);
+
+
+ // Add default file directories for Acorn version of
+ // Simon the Sorcerer 1
+ File::addDefaultDirectory(_gameDataPath + "execute");
+ File::addDefaultDirectory(_gameDataPath + "EXECUTE");
+
+ // Add default file directories for Amiga/Macintosh
+ // verisons of Simon the Sorcerer 2
+ File::addDefaultDirectory(_gameDataPath + "voices");
+ File::addDefaultDirectory(_gameDataPath + "VOICES");
+
+ // Add default file directories for Amiga & Macintosh
+ // versions of The Feeble Files
+ File::addDefaultDirectory(_gameDataPath + "gfx");
+ File::addDefaultDirectory(_gameDataPath + "GFX");
+ File::addDefaultDirectory(_gameDataPath + "movies");
+ File::addDefaultDirectory(_gameDataPath + "MOVIES");
+ File::addDefaultDirectory(_gameDataPath + "sfx");
+ File::addDefaultDirectory(_gameDataPath + "SFX");
+ File::addDefaultDirectory(_gameDataPath + "speech");
+ File::addDefaultDirectory(_gameDataPath + "SPEECH");
+}
+
+int SimonEngine::init() {
+ // Detect game
+ if (!initGame()) {
+ GUIErrorMessage("No valid games were found in the specified directory.");
+ return -1;
+ }
+
+ if (getGameId() == GID_DIMP) {
+ _screenWidth = 496;
+ _screenHeight = 400;
+ } else if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ _screenWidth = 640;
+ _screenHeight = 480;
+ } else {
+ _screenWidth = 320;
+ _screenHeight = 200;
+ }
+
+ _system->beginGFXTransaction();
+ initCommonGFX(getGameType() == GType_FF || getGameType() == GType_PP);
+ _system->initSize(_screenWidth, _screenHeight);
+ _system->endGFXTransaction();
+
+ // Setup mixer
+ if (!_mixer->isReady())
+ warning("Sound initialization failed. "
+ "Features of the game that depend on sound synchronization will most likely break");
+ set_volume(ConfMan.getInt("sfx_volume"));
+ _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume"));
+
+ // Setup midi driver
+ MidiDriver *driver = 0;
+ if (getGameType() == GType_FF || getGameType() == GType_PP || getGameId() == GID_SIMON1CD32) {
+ driver = MidiDriver::createMidi(MD_NULL);
+ _native_mt32 = false;
+ } else {
+ int midiDriver = MidiDriver::detectMusicDriver(MDT_ADLIB | MDT_MIDI);
+ _native_mt32 = ((midiDriver == MD_MT32) || ConfMan.getBool("native_mt32"));
+ driver = MidiDriver::createMidi(midiDriver);
+ if (_native_mt32) {
+ driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
+ }
+ }
+
+ midi.mapMT32toGM (getGameType() == GType_SIMON1 && !_native_mt32);
+
+ midi.set_driver(driver);
+ int ret = midi.open();
+ if (ret)
+ warning ("MIDI Player init failed: \"%s\"", midi.getErrorName (ret));
+ midi.set_volume(ConfMan.getInt("music_volume"));
+
+ if (ConfMan.hasKey("music_mute") && ConfMan.getBool("music_mute") == 1)
+ midi.pause(_musicPaused ^= 1);
+
+ // allocate buffers
+ _backGroundBuf = (byte *)calloc(_screenWidth * _screenHeight, 1);
+ _frontBuf = (byte *)calloc(_screenWidth * _screenHeight, 1);
+ _backBuf = (byte *)calloc(_screenWidth * _screenHeight, 1);
+ if (getGameType() == GType_FF || getGameType() == GType_PP)
+ _scaleBuf = (byte *)calloc(_screenWidth * _screenHeight, 1);
+
+ setupGame();
+
+ _debugger = new Debugger(this);
+ _moviePlay = new MoviePlayer(this, _mixer);
+ _sound = new Sound(this, gss, _mixer);
+
+ if (ConfMan.hasKey("sfx_mute") && ConfMan.getBool("sfx_mute") == 1) {
+ if (getGameId() == GID_SIMON1DOS)
+ midi._enable_sfx ^= 1;
+ else
+ _sound->effectsPause(_effectsPaused ^= 1);
+ }
+
+ _language = Common::parseLanguage(ConfMan.get("language"));
+
+ if (getGameType() == GType_PP) {
+ _speech = true;
+ _subtitles = false;
+ } else if (getFeatures() & GF_TALKIE) {
+ _speech = !ConfMan.getBool("speech_mute");
+ _subtitles = ConfMan.getBool("subtitles");
+
+ if (getGameType() == GType_SIMON1) {
+ // English and German versions don't have full subtitles
+ if (_language == Common::EN_ANY || _language == Common::DE_DEU)
+ _subtitles = false;
+ // Other versions require speech to be enabled
+ else
+ _speech = true;
+ }
+
+ // Default to speech only, if both speech and subtitles disabled
+ if (!_speech && !_subtitles)
+ _speech = true;
+ } else {
+ _speech = false;
+ _subtitles = true;
+ }
+
+ _debugMode = (gDebugLevel >= 0);
+ if (gDebugLevel == 2)
+ _continousMainScript = true;
+ if (gDebugLevel == 3)
+ _continousVgaScript = true;
+ if (gDebugLevel == 4)
+ _startMainScript = true;
+ if (gDebugLevel == 5)
+ _startVgaScript = true;
+
+ return 0;
+}
+
+void SimonEngine::setupGame() {
+ if (getGameType() == GType_PP) {
+ gss = PTR(puzzlepack_settings);
+ _numTextBoxes = 40;
+ _numVideoOpcodes = 85;
+#ifndef PALMOS_68K
+ _vgaMemSize = 7000000;
+#else
+ _vgaMemSize = gVars->memory[kMemSimon2Games];
+#endif
+ _tableMemSize = 200000;
+ _vgaBaseDelay = 5;
+ _numVars = 2048;
+ } else if (getGameType() == GType_FF) {
+ gss = PTR(feeblefiles_settings);
+ _numTextBoxes = 40;
+ _numVideoOpcodes = 85;
+#ifndef PALMOS_68K
+ _vgaMemSize = 7000000;
+#else
+ _vgaMemSize = gVars->memory[kMemSimon2Games];
+#endif
+ _tableMemSize = 200000;
+ _vgaBaseDelay = 5;
+ _numVars = 256;
+ } else if (getGameType() == GType_SIMON2) {
+ gss = PTR(simon2_settings);
+ _tableIndexBase = 1580 / 4;
+ _textIndexBase = 1500 / 4;
+ _numTextBoxes = 20;
+ _numVideoOpcodes = 75;
+#ifndef PALMOS_68K
+ _vgaMemSize = 2000000;
+#else
+ _vgaMemSize = gVars->memory[kMemSimon2Games];
+#endif
+ _tableMemSize = 100000;
+ // Check whether to use MT-32 MIDI tracks in Simon the Sorcerer 2
+ if ((getGameType() == GType_SIMON2) && _native_mt32)
+ _musicIndexBase = (1128 + 612) / 4;
+ else
+ _musicIndexBase = 1128 / 4;
+ _soundIndexBase = 1660 / 4;
+ _vgaBaseDelay = 1;
+ _numVars = 256;
+ } else {
+ gss = PTR(simon1_settings);
+ _tableIndexBase = 1576 / 4;
+ _textIndexBase = 1460 / 4;
+ _numTextBoxes = 20;
+ _numVideoOpcodes = 64;
+#ifndef PALMOS_68K
+ _vgaMemSize = 1000000;
+#else
+ _vgaMemSize = gVars->memory[kMemSimon1Games];
+#endif
+ _tableMemSize = 150000;
+ _musicIndexBase = 1316 / 4;
+ _soundIndexBase = 0;
+ _vgaBaseDelay = 1;
+ _numVars = 256;
+ }
+
+ allocItemHeap();
+ allocTablesHeap();
+
+ _variableArray = (int16 *)calloc(_numVars, sizeof(int16));
+ _variableArray2 = (int16 *)calloc(_numVars, sizeof(int16));
+
+ setupOpcodes();
+
+ setZoneBuffers();
+
+ _currentMouseCursor = 255;
+ _currentMouseAnim = 255;
+
+ _frameRate = 1;
+
+ _lastMusicPlayed = -1;
+ _nextMusicToPlay = -1;
+
+ _noOverWrite = 0xFFFF;
+
+ _stringIdLocalMin = 1;
+
+ _variableArrayPtr = _variableArray;
+}
+
+SimonEngine::~SimonEngine() {
+ delete _gameFile;
+
+ midi.close();
+
+ free(_itemHeapPtr - _itemHeapCurPos);
+ free(_tablesHeapPtr - _tablesHeapCurPos);
+
+ free(_gameOffsetsPtr);
+ free(_iconFilePtr);
+ free(_itemArrayPtr);
+ free(_stringTabPtr);
+ free(_strippedTxtMem);
+ free(_tblList);
+ free(_textMem);
+
+ free(_backGroundBuf);
+ free(_frontBuf);
+ free(_backBuf);
+ free(_scaleBuf);
+
+ delete _dummyItem1;
+ delete _dummyItem2;
+ delete _dummyItem3;
+
+ delete [] _windowList;
+
+ delete _debugger;
+ delete _moviePlay;
+ delete _sound;
+}
+
+GUI::Debugger *SimonEngine::getDebugger() {
+ return _debugger;
+}
+
+void SimonEngine::paletteFadeOut(byte *palPtr, uint num, uint size) {
+ byte *p = palPtr;
+
+ do {
+ if (p[0] >= size)
+ p[0] -= size;
+ else
+ p[0] = 0;
+ if (p[1] >= size)
+ p[1] -= size;
+ else
+ p[1] = 0;
+ if (p[2] >= size)
+ p[2] -= size;
+ else
+ p[2] = 0;
+ p += 4;
+ } while (--num);
+}
+
+byte *SimonEngine::allocateItem(uint size) {
+ byte *org = _itemHeapPtr;
+ size = (size + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
+
+ _itemHeapPtr += size;
+ _itemHeapCurPos += size;
+
+ if (_itemHeapCurPos > _itemHeapSize)
+ error("allocateItem: Itemheap overflow");
+
+ return org;
+}
+
+void SimonEngine::setUserFlag(Item *item, int a, int b) {
+ SubUserFlag *subUserFlag;
+
+ subUserFlag = (SubUserFlag *) findChildOfType(item, 9);
+ if (subUserFlag == NULL) {
+ subUserFlag = (SubUserFlag *) allocateChildBlock(item, 9, sizeof(SubUserFlag));
+ }
+
+ if (a >= 0 && a <= 3)
+ subUserFlag->userFlags[a] = b;
+}
+
+void SimonEngine::createPlayer() {
+ Child *child;
+
+ _currentPlayer = _itemArrayPtr[1];
+ _currentPlayer->adjective = -1;
+ _currentPlayer->noun = 10000;
+
+ child = (Child *)allocateChildBlock(_currentPlayer, 3, sizeof(Child));
+ if (child == NULL)
+ error("createPlayer: player create failure");
+
+ setUserFlag(_currentPlayer, 0, 0);
+}
+
+Child *SimonEngine::findChildOfType(Item *i, uint type) {
+ Child *child = i->children;
+ for (; child; child = child->next)
+ if (child->type == type)
+ return child;
+ return NULL;
+}
+
+bool SimonEngine::isRoom(Item *item) {
+ return findChildOfType(item, 1) != NULL;
+}
+
+bool SimonEngine::isObject(Item *item) {
+ return findChildOfType(item, 2) != NULL;
+}
+
+uint SimonEngine::getOffsetOfChild2Param(SubObject *child, uint prop) {
+ uint m = 1;
+ uint offset = 0;
+ while (m != prop) {
+ if (child->objectFlags & m)
+ offset++;
+ m *= 2;
+ }
+ return offset;
+}
+
+Child *SimonEngine::allocateChildBlock(Item *i, uint type, uint size) {
+ Child *child = (Child *)allocateItem(size);
+ child->next = i->children;
+ i->children = child;
+ child->type = type;
+ return child;
+}
+
+void SimonEngine::allocItemHeap() {
+ _itemHeapSize = 64000;
+ _itemHeapCurPos = 0;
+ _itemHeapPtr = (byte *)calloc(64000, 1);
+}
+
+void SimonEngine::allocTablesHeap() {
+ _tablesHeapSize = _tableMemSize;
+ _tablesHeapCurPos = 0;
+ _tablesHeapPtr = (byte *)calloc(_tableMemSize, 1);
+}
+
+void SimonEngine::setItemState(Item *item, int value) {
+ item->state = value;
+}
+
+byte SimonEngine::getByte() {
+ return *_codePtr++;
+}
+
+int SimonEngine::getNextWord() {
+ int16 a = (int16)READ_BE_UINT16(_codePtr);
+ _codePtr += 2;
+ return a;
+}
+
+uint SimonEngine::getNextStringID() {
+ return (uint16)getNextWord();
+}
+
+uint SimonEngine::getVarOrByte() {
+ uint a = *_codePtr++;
+ if (a != 255)
+ return a;
+ return readVariable(*_codePtr++);
+}
+
+uint SimonEngine::getVarOrWord() {
+ uint a = READ_BE_UINT16(_codePtr);
+ _codePtr += 2;
+ if (getGameType() == GType_PP) {
+ if (a >= 60000 && a < 62048) {
+ return readVariable(a - 60000);
+ }
+ } else {
+ if (a >= 30000 && a < 30512) {
+ return readVariable(a - 30000);
+ }
+ }
+ return a;
+}
+
+uint SimonEngine::getVarWrapper() {
+ if (getGameType() == GType_PP)
+ return getVarOrWord();
+ else
+ return getVarOrByte();
+}
+
+Item *SimonEngine::getNextItemPtr() {
+ int a = getNextWord();
+
+ switch (a) {
+ case -1:
+ return _subjectItem;
+ case -3:
+ return _objectItem;
+ case -5:
+ return me();
+ case -7:
+ return actor();
+ case -9:
+ return derefItem(me()->parent);
+ default:
+ return derefItem(a);
+ }
+}
+
+Item *SimonEngine::getNextItemPtrStrange() {
+ int a = getNextWord();
+ switch (a) {
+ case -1:
+ return _subjectItem;
+ case -3:
+ return _objectItem;
+ case -5:
+ return _dummyItem2;
+ case -7:
+ return NULL;
+ case -9:
+ return _dummyItem3;
+ default:
+ return derefItem(a);
+ }
+}
+
+uint SimonEngine::getNextItemID() {
+ int a = getNextWord();
+ switch (a) {
+ case -1:
+ return itemPtrToID(_subjectItem);
+ case -3:
+ return itemPtrToID(_objectItem);
+ case -5:
+ return getItem1ID();
+ case -7:
+ return 0;
+ case -9:
+ return me()->parent;
+ default:
+ return a;
+ }
+}
+
+Item *SimonEngine::me() {
+ if (_currentPlayer)
+ return _currentPlayer;
+ return _dummyItem1;
+}
+
+Item *SimonEngine::actor() {
+ error("actor: is this code ever used?");
+ //if (_actorPlayer)
+ // return _actorPlayer;
+ return _dummyItem1;
+}
+
+uint SimonEngine::getNextVarContents() {
+ return (uint16)readVariable(getVarWrapper());
+}
+
+uint SimonEngine::readVariable(uint variable) {
+ if (variable >= _numVars)
+ error("readVariable: Variable %d out of range", variable);
+
+ if (getGameType() == GType_PP) {
+ return (uint16)_variableArray[variable];
+ } else if (getGameType() == GType_FF) {
+ if (getBitFlag(83))
+ return (uint16)_variableArray2[variable];
+ else
+ return (uint16)_variableArray[variable];
+ } else {
+ return _variableArray[variable];
+ }
+}
+
+void SimonEngine::writeNextVarContents(uint16 contents) {
+ writeVariable(getVarWrapper(), contents);
+}
+
+void SimonEngine::writeVariable(uint variable, uint16 contents) {
+ if (variable >= _numVars)
+ error("writeVariable: Variable %d out of range", variable);
+
+ if (getGameType() == GType_FF && getBitFlag(83))
+ _variableArray2[variable] = contents;
+ else
+ _variableArray[variable] = contents;
+}
+
+void SimonEngine::setItemParent(Item *item, Item *parent) {
+ Item *old_parent = derefItem(item->parent);
+
+ if (item == parent)
+ error("setItemParent: Trying to set item as its own parent");
+
+ // unlink it if it has a parent
+ if (old_parent)
+ unlinkItem(item);
+ itemChildrenChanged(old_parent);
+ linkItem(item, parent);
+ itemChildrenChanged(parent);
+}
+
+void SimonEngine::itemChildrenChanged(Item *item) {
+ int i;
+ WindowBlock *window;
+
+ if (_noParentNotify)
+ return;
+
+ mouseOff();
+
+ for (i = 0; i != 8; i++) {
+ window = _windowArray[i];
+ if (window && window->iconPtr && window->iconPtr->itemRef == item) {
+ if (_fcsData1[i]) {
+ _fcsData2[i] = true;
+ } else {
+ _fcsData2[i] = false;
+ drawIconArray(i, item, window->iconPtr->line, window->iconPtr->classMask);
+ }
+ }
+ }
+
+ mouseOn();
+}
+
+void SimonEngine::unlinkItem(Item *item) {
+ Item *first, *parent, *next;
+
+ // can't unlink item without parent
+ if (item->parent == 0)
+ return;
+
+ // get parent and first child of parent
+ parent = derefItem(item->parent);
+ first = derefItem(parent->child);
+
+ // the node to remove is first in the parent's children?
+ if (first == item) {
+ parent->child = item->sibling;
+ item->parent = 0;
+ item->sibling = 0;
+ return;
+ }
+
+ for (;;) {
+ if (!first)
+ error("unlinkItem: parent empty");
+ if (first->sibling == 0) {
+ warning("unlinkItem: parent does not contain child");
+ return;
+ }
+
+ next = derefItem(first->sibling);
+ if (next == item) {
+ first->sibling = next->sibling;
+ item->parent = 0;
+ item->sibling = 0;
+ return;
+ }
+ first = next;
+ }
+}
+
+void SimonEngine::linkItem(Item *item, Item *parent) {
+ uint id;
+ // Don't allow that an item that is already linked is relinked
+ if (item->parent)
+ return;
+
+ id = itemPtrToID(parent);
+ item->parent = id;
+
+ if (parent != 0) {
+ item->sibling = parent->child;
+ parent->child = itemPtrToID(item);
+ } else {
+ item->sibling = 0;
+ }
+}
+
+void SimonEngine::setup_cond_c_helper() {
+ HitArea *last;
+ uint id;
+
+ _noRightClick = 1;
+
+ if (getGameType() == GType_FF) {
+ int cursor = 5;
+ int animMax = 16;
+
+ if (getBitFlag(200)) {
+ cursor = 11;
+ animMax = 5;
+ } else if (getBitFlag(201)) {
+ cursor = 12;
+ animMax = 5;
+ } else if (getBitFlag(202)) {
+ cursor = 13;
+ animMax = 5;
+ } else if (getBitFlag(203)) {
+ cursor = 14;
+ animMax = 9;
+ } else if (getBitFlag(205)) {
+ cursor = 17;
+ animMax = 11;
+ } else if (getBitFlag(206)) {
+ cursor = 16;
+ animMax = 2;
+ } else if (getBitFlag(208)) {
+ cursor = 26;
+ animMax = 2;
+ } else if (getBitFlag(209)) {
+ cursor = 27;
+ animMax = 9;
+ } else if (getBitFlag(210)) {
+ cursor = 28;
+ animMax = 9;
+ }
+
+ _animatePointer = 0;
+ _mouseCursor = cursor;
+ _mouseAnimMax = animMax;
+ _mouseAnim = 1;
+ _needHitAreaRecalc++;
+ }
+
+ if (getGameType() == GType_SIMON2) {
+ _mouseCursor = 0;
+ if (_defaultVerb != 999) {
+ _mouseCursor = 9;
+ _needHitAreaRecalc++;
+ _defaultVerb = 0;
+ }
+ }
+
+ _lastHitArea = 0;
+ _hitAreaObjectItem = NULL;
+
+ last = _lastNameOn;
+ clearName();
+ _lastNameOn = last;
+
+ for (;;) {
+ _lastHitArea = NULL;
+ _lastHitArea3 = 0;
+ _leftButtonDown = 0;
+
+ do {
+ if (_exitCutscene && getBitFlag(9)) {
+ endCutscene();
+ goto out_of_here;
+ }
+
+ if (getGameType() == GType_FF) {
+ if (_variableArray[254] == 63) {
+ hitarea_stuff_helper_2();
+ } else if (_variableArray[254] == 75) {
+ hitarea_stuff_helper_2();
+ _variableArray[60] = 9999;
+ goto out_of_here;
+ }
+ }
+
+ delay(100);
+ } while (_lastHitArea3 == (HitArea *) -1 || _lastHitArea3 == 0);
+
+ if (_lastHitArea == NULL) {
+ } else if (_lastHitArea->id == 0x7FFB) {
+ inventoryUp(_lastHitArea->window);
+ } else if (_lastHitArea->id == 0x7FFC) {
+ inventoryDown(_lastHitArea->window);
+ } else if (_lastHitArea->item_ptr != NULL) {
+ _hitAreaObjectItem = _lastHitArea->item_ptr;
+ id = 0xFFFF;
+ if (_lastHitArea->flags & kBFTextBox) {
+ if (getGameType() == GType_PP)
+ id = _lastHitArea->id;
+ else if (getGameType() == GType_FF && (_lastHitArea->flags & kBFHyperBox))
+ id = _lastHitArea->data;
+ else
+ id = _lastHitArea->flags / 256;
+ }
+ if (getGameType() == GType_PP)
+ _variableArray[199] = id;
+ else
+ _variableArray[60] = id;
+ break;
+ }
+ }
+
+out_of_here:
+ _lastHitArea3 = 0;
+ _lastHitArea = 0;
+ _lastNameOn = NULL;
+ _mouseCursor = 0;
+ _noRightClick = 0;
+}
+
+void SimonEngine::endCutscene() {
+ Subroutine *sub;
+
+ _sound->stopVoice();
+
+ sub = getSubroutineByID(170);
+ if (sub != NULL)
+ startSubroutineEx(sub);
+
+ _runScriptReturn1 = true;
+}
+
+bool SimonEngine::has_item_childflag_0x10(Item *item) {
+ SubObject *child = (SubObject *)findChildOfType(item, 2);
+ return child && (child->objectFlags & kOFIcon) != 0;
+}
+
+uint SimonEngine::itemGetIconNumber(Item *item) {
+ SubObject *child = (SubObject *)findChildOfType(item, 2);
+ uint offs;
+
+ if (child == NULL || !(child->objectFlags & kOFIcon))
+ return 0;
+
+ offs = getOffsetOfChild2Param(child, 0x10);
+ return child->objectFlagValue[offs];
+}
+
+void SimonEngine::hitarea_stuff() {
+ HitArea *ha;
+ uint id;
+
+ _leftButtonDown = 0;
+ _lastHitArea = 0;
+ _verbHitArea = 0;
+ _hitAreaSubjectItem = NULL;
+ _hitAreaObjectItem = NULL;
+
+ resetVerbs();
+
+startOver:
+ for (;;) {
+ _lastHitArea = NULL;
+ _lastHitArea3 = NULL;
+
+ for (;;) {
+ if ((getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) && _keyPressed == 35)
+ displayBoxStars();
+ processSpecialKeys();
+ if (_lastHitArea3 == (HitArea *) -1)
+ goto startOver;
+ if (_lastHitArea3 != 0)
+ break;
+ hitarea_stuff_helper();
+ delay(100);
+ }
+
+ ha = _lastHitArea;
+
+ if (ha == NULL) {
+ } else if (ha->id == 0x7FFB) {
+ inventoryUp(ha->window);
+ } else if (ha->id == 0x7FFC) {
+ inventoryDown(ha->window);
+ } else if (ha->id >= 101 && ha->id < 113) {
+ _verbHitArea = ha->verb;
+ setVerb(ha);
+ _defaultVerb = 0;
+ } else {
+ if ((_verbHitArea != 0 || _hitAreaSubjectItem != ha->item_ptr && ha->flags & kBFBoxItem) &&
+ ha->item_ptr) {
+ if_1:;
+ _hitAreaSubjectItem = ha->item_ptr;
+ id = 0xFFFF;
+ if (ha->flags & kBFTextBox) {
+ if (getGameType() == GType_PP)
+ id = _lastHitArea->id;
+ else if (getGameType() == GType_FF && (ha->flags & kBFHyperBox))
+ id = ha->data;
+ else
+ id = ha->flags / 256;
+ }
+ if (getGameType() == GType_PP)
+ _variableArray[199] = id;
+ else
+ _variableArray[60] = id;
+ displayName(ha);
+ if (_verbHitArea != 0)
+ break;
+ } else {
+ // else 1
+ if (ha->verb == 0) {
+ if (ha->item_ptr)
+ goto if_1;
+ } else {
+ _verbHitArea = ha->verb & 0xBFFF;
+ if (ha->verb & 0x4000) {
+ _hitAreaSubjectItem = ha->item_ptr;
+ break;
+ }
+ if (_hitAreaSubjectItem != NULL)
+ break;
+ }
+ }
+ }
+ }
+
+ _needHitAreaRecalc++;
+}
+
+void SimonEngine::hitarea_stuff_helper() {
+ time_t cur_time;
+
+ if (getGameType() == GType_SIMON2 || getGameType() == GType_FF || getGameType() == GType_PP) {
+ if (_variableArray[254] || _variableArray[249]) {
+ hitarea_stuff_helper_2();
+ }
+ } else {
+ uint subr_id = (uint16)_variableArray[254];
+ if (subr_id != 0) {
+ Subroutine *sub = getSubroutineByID(subr_id);
+ if (sub != NULL) {
+ startSubroutineEx(sub);
+ permitInput();
+ }
+ _variableArray[254] = 0;
+ _runScriptReturn1 = false;
+ }
+ }
+
+ time(&cur_time);
+ if ((uint) cur_time != _lastTime) {
+ _lastTime = cur_time;
+ if (kickoffTimeEvents())
+ permitInput();
+ }
+}
+
+void SimonEngine::hitarea_stuff_helper_2() {
+ uint subr_id;
+ Subroutine *sub;
+
+ subr_id = (uint16)_variableArray[249];
+ if (subr_id != 0) {
+ sub = getSubroutineByID(subr_id);
+ if (sub != NULL) {
+ _variableArray[249] = 0;
+ startSubroutineEx(sub);
+ permitInput();
+ }
+ _variableArray[249] = 0;
+ }
+
+ subr_id = (uint16)_variableArray[254];
+ if (subr_id != 0) {
+ sub = getSubroutineByID(subr_id);
+ if (sub != NULL) {
+ _variableArray[254] = 0;
+ startSubroutineEx(sub);
+ permitInput();
+ }
+ _variableArray[254] = 0;
+ }
+
+ _runScriptReturn1 = false;
+}
+
+void SimonEngine::permitInput() {
+ if (!_mortalFlag) {
+ _mortalFlag = true;
+ showmessage_print_char(0);
+ _curWindow = 0;
+ if (_windowArray[0] != 0) {
+ _textWindow = _windowArray[0];
+ if (getGameType() == GType_FF || getGameType() == GType_PP)
+ showmessage_helper_3(_textWindow->textColumn, _textWindow->width);
+ else
+ showmessage_helper_3(_textWindow->textLength, _textWindow->textMaxLength);
+ }
+ _mortalFlag = false;
+ }
+}
+
+TextLocation *SimonEngine::getTextLocation(uint a) {
+ switch (a) {
+ case 1:
+ return &_textLocation1;
+ case 2:
+ return &_textLocation2;
+ case 101:
+ return &_textLocation3;
+ case 102:
+ return &_textLocation4;
+ default:
+ error("getTextLocation: Invalid text location %d", a);
+ }
+ return NULL;
+}
+
+void SimonEngine::loadZone(uint vga_res) {
+ VgaPointersEntry *vpe;
+ uint32 size;
+
+ CHECK_BOUNDS(vga_res, _vgaBufferPointers);
+
+ vpe = _vgaBufferPointers + vga_res;
+ if (vpe->vgaFile1 != NULL)
+ return;
+
+ vpe->vgaFile1 = loadVGAFile(vga_res * 2, 1, size);
+ vpe->vgaFile1End = vpe->vgaFile1 + size;
+
+ vpe->vgaFile2 = loadVGAFile(vga_res * 2 + 1, 2, size);
+ vpe->vgaFile2End = vpe->vgaFile2 + size;
+
+ vpe->sfxFile = NULL;
+ if (!(getFeatures() & GF_ZLIBCOMP)) {
+ vpe->sfxFile = loadVGAFile(vga_res * 2, 3, size);
+ vpe->sfxFileEnd = vpe->sfxFile + size;
+ }
+}
+
+void SimonEngine::setZoneBuffers() {
+ _zoneBuffers = (byte *)malloc(_vgaMemSize);
+
+ _vgaMemPtr = _zoneBuffers;
+ _vgaMemBase = _zoneBuffers;
+ _vgaFrozenBase = _zoneBuffers;
+ _vgaRealBase = _zoneBuffers;
+ _vgaMemEnd = _zoneBuffers + _vgaMemSize;
+}
+
+byte *SimonEngine::allocBlock(uint32 size) {
+ byte *block, *blockEnd;
+ uint i;
+
+ for (i = 0; i < _vgaMemSize / size; i++) {
+ block = _vgaMemPtr;
+ blockEnd = block + size;
+
+ if (blockEnd >= _vgaMemEnd) {
+ _vgaMemPtr = _vgaMemBase;
+ } else {
+ _rejectBlock = false;
+ checkNoOverWrite(blockEnd);
+ if (_rejectBlock)
+ continue;
+ checkRunningAnims(blockEnd);
+ if (_rejectBlock)
+ continue;
+ checkZonePtrs(blockEnd);
+ _vgaMemPtr = blockEnd;
+ return block;
+ }
+ }
+
+ error("allocBlock: Couldn't find free block");
+}
+
+void SimonEngine::checkNoOverWrite(byte *end) {
+ VgaPointersEntry *vpe;
+
+ if (_noOverWrite == 0xFFFF)
+ return;
+
+ vpe = &_vgaBufferPointers[_noOverWrite];
+
+ if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ if (vpe->vgaFile1 < end && vpe->vgaFile1End > _vgaMemPtr) {
+ _rejectBlock = true;
+ _vgaMemPtr = vpe->vgaFile1End;
+ } else if (vpe->vgaFile2 < end && vpe->vgaFile2End > _vgaMemPtr) {
+ _rejectBlock = true;
+ _vgaMemPtr = vpe->vgaFile2End;
+ } else if (vpe->sfxFile && vpe->sfxFile < end && vpe->sfxFileEnd > _vgaMemPtr) {
+ _rejectBlock = true;
+ _vgaMemPtr = vpe->sfxFileEnd;
+ } else {
+ _rejectBlock = false;
+ }
+ } else {
+ if (_vgaMemPtr <= vpe->vgaFile1 && end >= vpe->vgaFile1 ||
+ _vgaMemPtr <= vpe->vgaFile2 && end >= vpe->vgaFile2) {
+ _rejectBlock = true;
+ _vgaMemPtr = vpe->vgaFile1 + 0x5000;
+ } else {
+ _rejectBlock = false;
+ }
+ }
+}
+
+void SimonEngine::checkRunningAnims(byte *end) {
+ VgaSprite *vsp;
+ if (getGameType() != GType_FF && getGameType() != GType_PP && (_lockWord & 0x20)) {
+ return;
+ }
+
+ for (vsp = _vgaSprites; vsp->id; vsp++) {
+ checkAnims(vsp->zoneNum, end);
+ if (_rejectBlock == true)
+ return;
+ }
+}
+
+void SimonEngine::checkAnims(uint a, byte *end) {
+ VgaPointersEntry *vpe;
+
+ vpe = &_vgaBufferPointers[a];
+
+ if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ if (vpe->vgaFile1 < end && vpe->vgaFile1End > _vgaMemPtr) {
+ _rejectBlock = true;
+ _vgaMemPtr = vpe->vgaFile1End;
+ } else if (vpe->vgaFile2 < end && vpe->vgaFile2End > _vgaMemPtr) {
+ _rejectBlock = true;
+ _vgaMemPtr = vpe->vgaFile2End;
+ } else if (vpe->sfxFile && vpe->sfxFile < end && vpe->sfxFileEnd > _vgaMemPtr) {
+ _rejectBlock = true;
+ _vgaMemPtr = vpe->sfxFileEnd;
+ } else {
+ _rejectBlock = false;
+ }
+ } else {
+ if (_vgaMemPtr <= vpe->vgaFile1 && end >= vpe->vgaFile1 ||
+ _vgaMemPtr <= vpe->vgaFile2 && end >= vpe->vgaFile2) {
+ _rejectBlock = true;
+ _vgaMemPtr = vpe->vgaFile1 + 0x5000;
+ } else {
+ _rejectBlock = false;
+ }
+ }
+}
+
+void SimonEngine::checkZonePtrs(byte *end) {
+ uint count = ARRAYSIZE(_vgaBufferPointers);
+ VgaPointersEntry *vpe = _vgaBufferPointers;
+ do {
+ if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ if (vpe->vgaFile1 < end && vpe->vgaFile1End > _vgaMemPtr ||
+ vpe->vgaFile2 < end && vpe->vgaFile2End > _vgaMemPtr ||
+ vpe->sfxFile < end && vpe->sfxFileEnd > _vgaMemPtr) {
+ vpe->vgaFile1 = NULL;
+ vpe->vgaFile1End = NULL;
+ vpe->vgaFile2 = NULL;
+ vpe->vgaFile2End = NULL;
+ vpe->sfxFile = NULL;
+ vpe->sfxFileEnd = NULL;
+ }
+ } else {
+ if (_vgaMemPtr <= vpe->vgaFile1 && end >= vpe->vgaFile1 ||
+ _vgaMemPtr <= vpe->vgaFile2 && end >= vpe->vgaFile2) {
+ vpe->vgaFile1 = NULL;
+ vpe->vgaFile2 = NULL;
+ }
+ }
+ } while (++vpe, --count);
+}
+
+void SimonEngine::set_video_mode_internal(uint16 mode, uint16 vga_res_id) {
+ uint num, num_lines;
+ VgaPointersEntry *vpe;
+ byte *bb, *b;
+ uint16 count;
+ const byte *vc_ptr_org;
+
+ _windowNum = mode;
+ _lockWord |= 0x20;
+
+ if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ vc27_resetSprite();
+ }
+
+ if (vga_res_id == 0) {
+ if (getGameType() == GType_SIMON1) {
+ _unkPalFlag = true;
+ } else if (getGameType() == GType_SIMON2) {
+ _useBackGround = true;
+ _restoreWindow6 = true;
+ }
+ }
+
+ _zoneNumber = num = vga_res_id / 100;
+
+ for (;;) {
+ vpe = &_vgaBufferPointers[num];
+
+ _curVgaFile1 = vpe->vgaFile1;
+ _curVgaFile2 = vpe->vgaFile2;
+ _curSfxFile = vpe->sfxFile;
+
+ if (vpe->vgaFile1 != NULL)
+ break;
+
+ loadZone(num);
+ }
+
+ // ensure flipping complete
+
+ bb = _curVgaFile1;
+
+ if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ b = bb + READ_LE_UINT16(&((VgaFileHeader_Feeble *) bb)->hdr2_start);
+ count = READ_LE_UINT16(&((VgaFileHeader2_Feeble *) b)->imageCount);
+ b = bb + READ_LE_UINT16(&((VgaFileHeader2_Feeble *) b)->imageTable);
+
+ while (count--) {
+ if (READ_LE_UINT16(&((ImageHeader_Feeble *) b)->id) == vga_res_id)
+ break;
+ b += sizeof(ImageHeader_Feeble);
+ }
+ assert(READ_LE_UINT16(&((ImageHeader_Feeble *) b)->id) == vga_res_id);
+
+ } else if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) {
+ b = bb + READ_BE_UINT16(&((VgaFileHeader_Simon *) bb)->hdr2_start);
+ count = READ_BE_UINT16(&((VgaFileHeader2_Simon *) b)->imageCount);
+ b = bb + READ_BE_UINT16(&((VgaFileHeader2_Simon *) b)->imageTable);
+
+ while (count--) {
+ if (READ_BE_UINT16(&((ImageHeader_Simon *) b)->id) == vga_res_id)
+ break;
+ b += sizeof(ImageHeader_Simon);
+ }
+ assert(READ_BE_UINT16(&((ImageHeader_Simon *) b)->id) == vga_res_id);
+ } else {
+ b = bb + READ_BE_UINT16(bb + 10);
+ b += 20;
+
+ count = READ_BE_UINT16(&((VgaFileHeader2_WW *) b)->imageCount);
+ b = bb + READ_BE_UINT16(&((VgaFileHeader2_WW *) b)->imageTable);
+
+ while (count--) {
+ if (READ_BE_UINT16(&((ImageHeader_WW *) b)->id) == vga_res_id)
+ break;
+ b += sizeof(ImageHeader_WW);
+ }
+ assert(READ_BE_UINT16(&((ImageHeader_WW *) b)->id) == vga_res_id);
+ }
+
+ if (getGameType() == GType_SIMON1) {
+ if (vga_res_id == 16300) {
+ clearBackFromTop(134);
+ _usePaletteDelay = true;
+ }
+ } else {
+ _scrollX = 0;
+ _scrollY = 0;
+ _scrollXMax = 0;
+ _scrollYMax = 0;
+ _scrollCount = 0;
+ _scrollFlag = 0;
+ _scrollHeight = 134;
+ _variableArrayPtr = _variableArray;
+ if (_variableArray[34] >= 0) {
+ if (getGameType() == GType_FF)
+ _variableArray[250] = 0;
+ _variableArray[251] = 0;
+ }
+ }
+
+ vc_ptr_org = _vcPtr;
+
+ if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ _vcPtr = _curVgaFile1 + READ_LE_UINT16(&((ImageHeader_Feeble *) b)->scriptOffs);
+ } else if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) {
+ _vcPtr = _curVgaFile1 + READ_BE_UINT16(&((ImageHeader_Simon *) b)->scriptOffs);
+ } else {
+ _vcPtr = _curVgaFile1 + READ_BE_UINT16(&((ImageHeader_WW *) b)->scriptOffs);
+ }
+
+ //dump_vga_script(_vcPtr, num, vga_res_id);
+ runVgaScript();
+ _vcPtr = vc_ptr_org;
+
+
+ if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ fillFrontFromBack(0, 0, _screenWidth, _screenHeight);
+ fillBackGroundFromBack(_screenHeight);
+ _syncFlag2 = 1;
+ } else if (getGameType() == GType_SIMON2) {
+ if (!_useBackGround) {
+ num_lines = _windowNum == 4 ? 134 : 200;
+ _boxStarHeight = num_lines;
+ fillFrontFromBack(0, 0, _screenWidth, num_lines);
+ fillBackGroundFromBack(num_lines);
+ _syncFlag2 = 1;
+ }
+ _useBackGround = false;
+ } else {
+ // Allow one section of Simon the Sorcerer 1 introduction to be displayed
+ // in lower half of screen
+ if (_subroutine == 2923 || _subroutine == 2926)
+ num_lines = 200;
+ else
+ num_lines = _windowNum == 4 ? 134 : 200;
+
+ fillFrontFromBack(0, 0, _screenWidth, num_lines);
+ fillBackGroundFromBack(num_lines);
+
+ _syncFlag2 = 1;
+ _timer5 = 0;
+ }
+
+ _lockWord &= ~0x20;
+
+ if (getGameType() == GType_SIMON1) {
+ if (_unkPalFlag) {
+ _unkPalFlag = false;
+ while (_fastFadeInFlag != 0) {
+ delay(10);
+ }
+ }
+ }
+}
+
+void SimonEngine::waitForSync(uint a) {
+ const uint maxCount = (getGameType() == GType_SIMON1) ? 500 : 1000;
+
+ if (getGameType() == GType_SIMON1 && (getFeatures() & GF_TALKIE)) {
+ if (a != 200) {
+ uint16 tmp = _lastVgaWaitFor;
+ _lastVgaWaitFor = 0;
+ if (tmp == a)
+ return;
+ }
+ }
+
+ _vgaWaitFor = a;
+ _syncCount = 0;
+ _exitCutscene = false;
+ _rightButtonDown = false;
+
+ while (_vgaWaitFor != 0) {
+ if (_rightButtonDown) {
+ if (_vgaWaitFor == 200 && (getGameType() == GType_FF || !getBitFlag(14))) {
+ skipSpeech();
+ break;
+ }
+ }
+ if (_exitCutscene) {
+ if (getBitFlag(9)) {
+ endCutscene();
+ break;
+ }
+ }
+ processSpecialKeys();
+
+ if (_syncCount >= maxCount) {
+ warning("waitForSync: wait timed out");
+ break;
+ }
+
+ delay(1);
+ }
+}
+
+void SimonEngine::skipSpeech() {
+ _sound->stopVoice();
+ if (!getBitFlag(28)) {
+ setBitFlag(14, true);
+ if (getGameType() == GType_FF) {
+ _variableArray[103] = 5;
+ loadSprite(4, 2, 13, 0, 0, 0);
+ waitForSync(213);
+ stopAnimateSimon2(2, 1);
+ } else if (getGameType() == GType_SIMON2) {
+ _variableArray[100] = 5;
+ loadSprite(4, 1, 30, 0, 0, 0);
+ waitForSync(130);
+ stopAnimateSimon2(2, 1);
+ } else {
+ _variableArray[100] = 15;
+ loadSprite(4, 1, 130, 0, 0, 0);
+ waitForSync(130);
+ stopAnimateSimon1(1);
+ }
+ }
+}
+
+Item *SimonEngine::derefItem(uint item) {
+ if (item >= _itemArraySize)
+ error("derefItem: invalid item %d", item);
+ return _itemArrayPtr[item];
+}
+
+uint SimonEngine::itemPtrToID(Item *id) {
+ uint i;
+ for (i = 0; i != _itemArraySize; i++)
+ if (_itemArrayPtr[i] == id)
+ return i;
+ error("itemPtrToID: not found");
+ return 0;
+}
+
+bool SimonEngine::isSpriteLoaded(uint16 id, uint16 zoneNum) {
+ VgaSprite *vsp = _vgaSprites;
+ while (vsp->id) {
+ if (getGameType() == GType_SIMON1 || getGameType() == GType_WW) {
+ if (vsp->id == id)
+ return true;
+ } else {
+ if (vsp->id == id && vsp->zoneNum == zoneNum)
+ return true;
+ }
+ vsp++;
+ }
+ return false;
+}
+
+void SimonEngine::processSpecialKeys() {
+ switch (_keyPressed) {
+ case 27: // escape
+ _exitCutscene = true;
+ break;
+ case 59: // F1
+ if (getGameType() == GType_SIMON1) {
+ vcWriteVar(5, 40);
+ } else {
+ vcWriteVar(5, 50);
+ }
+ vcWriteVar(86, 0);
+ break;
+ case 60: // F2
+ if (getGameType() == GType_SIMON1) {
+ vcWriteVar(5, 60);
+ } else {
+ vcWriteVar(5, 75);
+ }
+ vcWriteVar(86, 1);
+ break;
+ case 61: // F3
+ if (getGameType() == GType_SIMON1) {
+ vcWriteVar(5, 100);
+ } else {
+ vcWriteVar(5, 125);
+ }
+ vcWriteVar(86, 2);
+ break;
+ case 63: // F5
+ if (getGameType() == GType_SIMON2 || getGameType() == GType_FF)
+ _exitCutscene = true;
+ break;
+ case 65: // F7
+ if (getGameType() == GType_FF && getBitFlag(76))
+ _variableArray[254] = 70;
+ break;
+ case 67: // F9
+ if (getGameType() == GType_FF)
+ setBitFlag(73, !getBitFlag(73));
+ break;
+ case 'p':
+ pause();
+ break;
+ case 't':
+ if (getGameType() == GType_FF || (getGameType() == GType_SIMON2 && (getFeatures() & GF_TALKIE)) ||
+ ((getFeatures() & GF_TALKIE) && _language != Common::EN_ANY && _language != Common::DE_DEU)) {
+ if (_speech)
+ _subtitles ^= 1;
+ }
+ break;
+ case 'v':
+ if (getGameType() == GType_FF || (getGameType() == GType_SIMON2 && (getFeatures() & GF_TALKIE))) {
+ if (_subtitles)
+ _speech ^= 1;
+ }
+ case '+':
+ midi.set_volume(midi.get_volume() + 16);
+ break;
+ case '-':
+ midi.set_volume(midi.get_volume() - 16);
+ break;
+ case 'm':
+ midi.pause(_musicPaused ^= 1);
+ break;
+ case 's':
+ if (getGameId() == GID_SIMON1DOS)
+ midi._enable_sfx ^= 1;
+ else
+ _sound->effectsPause(_effectsPaused ^= 1);
+ break;
+ case 'b':
+ _sound->ambientPause(_ambientPaused ^= 1);
+ break;
+ case 'r':
+ if (_debugMode)
+ _startMainScript ^= 1;
+ break;
+ case 'o':
+ if (_debugMode)
+ _continousMainScript ^= 1;
+ break;
+ case 'a':
+ if (_debugMode)
+ _startVgaScript ^= 1;
+ break;
+ case 'g':
+ if (_debugMode)
+ _continousVgaScript ^= 1;
+ break;
+ case 'i':
+ if (_debugMode)
+ _drawImagesDebug ^= 1;
+ break;
+ case 'd':
+ if (_debugMode)
+ _dumpImages ^=1;
+ break;
+ }
+
+ _keyPressed = 0;
+}
+
+void SimonEngine::pause() {
+ _keyPressed = 1;
+ _pause = 1;
+ bool ambient_status = _ambientPaused;
+ bool music_status = _musicPaused;
+
+ midi.pause(true);
+ _sound->ambientPause(true);
+ while (_pause) {
+ delay(1);
+ if (_keyPressed == 'p')
+ _pause = 0;
+ }
+ midi.pause(music_status);
+ _sound->ambientPause(ambient_status);
+
+}
+
+void SimonEngine::loadSprite(uint windowNum, uint zoneNum, uint vgaSpriteId, uint x, uint y, uint palette) {
+ VgaSprite *vsp;
+ VgaPointersEntry *vpe;
+ byte *p, *pp;
+ uint count;
+
+ if (vgaSpriteId >= 400)
+ _lastVgaWaitFor = 0;
+
+ _lockWord |= 0x40;
+
+ if (isSpriteLoaded(vgaSpriteId, zoneNum)) {
+ _lockWord &= ~0x40;
+ return;
+ }
+
+ vsp = _vgaSprites;
+ while (vsp->id != 0)
+ vsp++;
+
+ vsp->windowNum = windowNum;
+ vsp->priority = 0;
+ vsp->flags = 0;
+
+ vsp->y = y;
+ vsp->x = x;
+ vsp->image = 0;
+ if (getGameType() == GType_WW)
+ vsp->palette = 0;
+ else
+ vsp->palette = palette;
+ vsp->id = vgaSpriteId;
+ if (getGameType() == GType_SIMON1 || getGameType() == GType_WW)
+ vsp->zoneNum = zoneNum = vgaSpriteId / 100;
+ else
+ vsp->zoneNum = zoneNum;
+
+
+ for (;;) {
+ vpe = &_vgaBufferPointers[zoneNum];
+ _zoneNumber = zoneNum;
+ _curVgaFile1 = vpe->vgaFile1;
+ if (vpe->vgaFile1 != NULL)
+ break;
+ loadZone(zoneNum);
+ }
+
+ pp = _curVgaFile1;
+ if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ p = pp + READ_LE_UINT16(&((VgaFileHeader_Feeble *) pp)->hdr2_start);
+ count = READ_LE_UINT16(&((VgaFileHeader2_Feeble *) p)->animationCount);
+ p = pp + READ_LE_UINT16(&((VgaFileHeader2_Feeble *) p)->animationTable);
+ } else if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) {
+ p = pp + READ_BE_UINT16(&((VgaFileHeader_Simon *) pp)->hdr2_start);
+ count = READ_BE_UINT16(&((VgaFileHeader2_Simon *) p)->animationCount);
+ p = pp + READ_BE_UINT16(&((VgaFileHeader2_Simon *) p)->animationTable);
+ } else {
+ p = pp + READ_BE_UINT16(pp + 10);
+ p += 20;
+
+ count = READ_BE_UINT16(&((VgaFileHeader2_WW *) p)->animationCount);
+ p = pp + READ_BE_UINT16(&((VgaFileHeader2_WW *) p)->animationTable);
+ }
+
+ for (;;) {
+ if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ if (READ_LE_UINT16(&((AnimationHeader_Feeble *) p)->id) == vgaSpriteId) {
+ if (_startVgaScript)
+ dump_vga_script(pp + READ_LE_UINT16(&((AnimationHeader_Feeble*)p)->scriptOffs), zoneNum, vgaSpriteId);
+
+ addVgaEvent(_vgaBaseDelay, pp + READ_LE_UINT16(&((AnimationHeader_Feeble *) p)->scriptOffs), vgaSpriteId, zoneNum);
+ break;
+ }
+ p += sizeof(AnimationHeader_Feeble);
+ } else if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) {
+ if (READ_BE_UINT16(&((AnimationHeader_Simon *) p)->id) == vgaSpriteId) {
+ if (_startVgaScript)
+ dump_vga_script(pp + READ_BE_UINT16(&((AnimationHeader_Simon*)p)->scriptOffs), zoneNum, vgaSpriteId);
+
+ addVgaEvent(_vgaBaseDelay, pp + READ_BE_UINT16(&((AnimationHeader_Simon *) p)->scriptOffs), vgaSpriteId, zoneNum);
+ break;
+ }
+ p += sizeof(AnimationHeader_Simon);
+ } else {
+ if (READ_BE_UINT16(&((AnimationHeader_WW *) p)->id) == vgaSpriteId) {
+ if (_startVgaScript)
+ dump_vga_script(pp + READ_BE_UINT16(&((AnimationHeader_WW *)p)->scriptOffs), zoneNum, vgaSpriteId);
+
+ addVgaEvent(_vgaBaseDelay, pp + READ_BE_UINT16(&((AnimationHeader_WW *) p)->scriptOffs), vgaSpriteId, zoneNum);
+ break;
+ }
+ p += sizeof(AnimationHeader_WW);
+ }
+
+ if (!--count) {
+ vsp->id = 0;
+ break;
+ }
+ }
+
+ _lockWord &= ~0x40;
+}
+
+void SimonEngine::playSpeech(uint speech_id, uint vgaSpriteId) {
+ if (getGameType() == GType_SIMON1) {
+ if (speech_id == 9999) {
+ if (_subtitles)
+ return;
+ if (!getBitFlag(14) && !getBitFlag(28)) {
+ setBitFlag(14, true);
+ _variableArray[100] = 15;
+ loadSprite(4, 1, 130, 0, 0, 0);
+ waitForSync(130);
+ }
+ _skipVgaWait = true;
+ } else {
+ if (_subtitles && _scriptVar2) {
+ loadSprite(4, 2, 204, 0, 0, 0);
+ waitForSync(204);
+ stopAnimateSimon1(204);
+ }
+ stopAnimateSimon1(vgaSpriteId + 201);
+ loadVoice(speech_id);
+ loadSprite(4, 2, vgaSpriteId + 201, 0, 0, 0);
+ }
+ } else {
+ if (speech_id == 0xFFFF) {
+ if (_subtitles)
+ return;
+ if (!getBitFlag(14) && !getBitFlag(28)) {
+ setBitFlag(14, true);
+ _variableArray[100] = 5;
+ loadSprite(4, 1, 30, 0, 0, 0);
+ waitForSync(130);
+ }
+ _skipVgaWait = true;
+ } else {
+ if (getGameType() == GType_SIMON2 && _subtitles && _language != Common::HB_ISR) {
+ loadVoice(speech_id);
+ return;
+ }
+
+ if (_subtitles && _scriptVar2) {
+ loadSprite(4, 2, 5, 0, 0, 0);
+ waitForSync(205);
+ stopAnimateSimon2(2,5);
+ }
+
+ stopAnimateSimon2(2, vgaSpriteId + 2);
+ loadVoice(speech_id);
+ loadSprite(4, 2, vgaSpriteId + 2, 0, 0, 0);
+ }
+ }
+}
+
+int SimonEngine::go() {
+
+ loadGamePcFile();
+
+ addTimeEvent(0, 1);
+ openGameFile();
+
+ if (getGameType() == GType_FF)
+ loadIconData();
+ else if (getGameType() != GType_PP)
+ loadIconFile();
+
+ vc34_setMouseOff();
+
+ if ((getPlatform() == Common::kPlatformAmiga || getPlatform() == Common::kPlatformMacintosh) &&
+ getGameType() == GType_FF) {
+ _moviePlay->load((const char *)"epic.dxa");
+ _moviePlay->play();
+ }
+
+ runSubroutine101();
+ permitInput();
+
+ while (1) {
+ hitarea_stuff();
+ handleVerbClicked(_verbHitArea);
+ delay(100);
+ }
+
+ return 0;
+}
+
+void SimonEngine::shutdown() {
+ delete _gameFile;
+
+ midi.close();
+
+ free(_stringTabPtr);
+ free(_itemArrayPtr);
+ free(_itemHeapPtr - _itemHeapCurPos);
+ free(_tablesHeapPtr - _tablesHeapCurPos);
+ free(_tblList);
+ free(_zoneBuffers);
+ free(_iconFilePtr);
+ free(_gameOffsetsPtr);
+
+ _system->quit();
+}
+
+void SimonEngine::delay(uint amount) {
+ OSystem::Event event;
+
+ uint32 start = _system->getMillis();
+ uint32 cur = start;
+ uint this_delay, vga_period;
+
+ if (_debugger->isAttached())
+ _debugger->onFrame();
+
+ if (_fastMode)
+ vga_period = 10;
+ else if (getGameType() == GType_SIMON2)
+ vga_period = 45;
+ else
+ vga_period = 50;
+
+ _rnd.getRandomNumber(2);
+
+ do {
+ while (!_inCallBack && cur >= _lastVgaTick + vga_period && !_pause) {
+ _lastVgaTick += vga_period;
+
+ // don't get too many frames behind
+ if (cur >= _lastVgaTick + vga_period * 2)
+ _lastVgaTick = cur;
+
+ _inCallBack = true;
+ timer_callback();
+ _inCallBack = false;
+ }
+
+ while (_system->pollEvent(event)) {
+ switch (event.type) {
+ case OSystem::EVENT_KEYDOWN:
+ if (event.kbd.keycode >= '0' && event.kbd.keycode <='9'
+ && (event.kbd.flags == OSystem::KBD_ALT ||
+ event.kbd.flags == OSystem::KBD_CTRL)) {
+ _saveLoadSlot = event.kbd.keycode - '0';
+
+ // There is no save slot 0
+ if (_saveLoadSlot == 0)
+ _saveLoadSlot = 10;
+
+ sprintf(_saveLoadName, "Quicksave %d", _saveLoadSlot);
+ _saveLoadType = (event.kbd.flags == OSystem::KBD_ALT) ? 1 : 2;
+
+ // We should only allow a load or save when it was possible in original
+ // This stops load/save during copy protection, conversations and cut scenes
+ if (!_mouseHideCount && !_showPreposition)
+ quickLoadOrSave();
+ } else if (event.kbd.flags == OSystem::KBD_CTRL) {
+ if (event.kbd.keycode == 'a') {
+ GUI::Dialog *_aboutDialog;
+ _aboutDialog = new GUI::AboutDialog();
+ _aboutDialog->runModal();
+ } else if (event.kbd.keycode == 'f')
+ _fastMode ^= 1;
+ else if (event.kbd.keycode == 'd')
+ _debugger->attach();
+ }
+ // Make sure backspace works right (this fixes a small issue on OS X)
+ if (event.kbd.keycode == 8)
+ _keyPressed = 8;
+ else
+ _keyPressed = (byte)event.kbd.ascii;
+ break;
+ case OSystem::EVENT_MOUSEMOVE:
+ _sdlMouseX = event.mouse.x;
+ _sdlMouseY = event.mouse.y;
+ break;
+ case OSystem::EVENT_LBUTTONDOWN:
+ if (getGameType() == GType_FF)
+ setBitFlag(89, true);
+ _leftButtonDown++;
+#if defined (_WIN32_WCE) || defined(PALMOS_MODE)
+ _sdlMouseX = event.mouse.x;
+ _sdlMouseY = event.mouse.y;
+#endif
+ break;
+ case OSystem::EVENT_LBUTTONUP:
+ if (getGameType() == GType_FF)
+ setBitFlag(89, false);
+ break;
+ case OSystem::EVENT_RBUTTONDOWN:
+ if (getGameType() == GType_FF)
+ setBitFlag(92, false);
+ _rightButtonDown++;
+ break;
+ case OSystem::EVENT_QUIT:
+ shutdown();
+ return;
+ default:
+ break;
+ }
+ }
+
+ _system->updateScreen();
+
+ if (amount == 0)
+ break;
+
+ this_delay = _fastMode ? 1 : 20;
+ if (this_delay > amount)
+ this_delay = amount;
+ _system->delayMillis(this_delay);
+
+ cur = _system->getMillis();
+ } while (cur < start + amount);
+}
+
+void SimonEngine::loadMusic(uint music) {
+ char buf[4];
+
+ if (getGameType() == GType_SIMON2) { // Simon 2 music
+ midi.stop();
+ _gameFile->seek(_gameOffsetsPtr[_musicIndexBase + music - 1], SEEK_SET);
+ _gameFile->read(buf, 4);
+ if (!memcmp(buf, "FORM", 4)) {
+ _gameFile->seek(_gameOffsetsPtr[_musicIndexBase + music - 1], SEEK_SET);
+ midi.loadXMIDI (_gameFile);
+ } else {
+ _gameFile->seek(_gameOffsetsPtr[_musicIndexBase + music - 1], SEEK_SET);
+ midi.loadMultipleSMF (_gameFile);
+ }
+
+ _lastMusicPlayed = music;
+ _nextMusicToPlay = -1;
+ } else if (getGameType() == GType_SIMON1) { // Simon 1 music
+ if (getPlatform() == Common::kPlatformAmiga) {
+ if (getFeatures() & GF_CRUNCHED) {
+ // TODO Add support for decruncher
+ debug(5,"loadMusic - Decrunch %dtune attempt", music);
+ }
+ // TODO Add Protracker support for simon1amiga/cd32
+ debug(5,"playMusic - Load %dtune attempt", music);
+ return;
+ }
+
+ midi.stop();
+ midi.setLoop (true); // Must do this BEFORE loading music. (GMF may have its own override.)
+
+ if (getFeatures() & GF_TALKIE) {
+ // FIXME: The very last music resource, a cymbal crash for when the
+ // two demons crash into each other, should NOT be looped like the
+ // other music tracks. In simon1dos/talkie the GMF resource includes
+ // a loop override that acomplishes this, but there seems to be nothing
+ // for this in the SMF resources.
+ if (music == 35)
+ midi.setLoop (false);
+
+ _gameFile->seek(_gameOffsetsPtr[_musicIndexBase + music], SEEK_SET);
+ _gameFile->read(buf, 4);
+ if (!memcmp(buf, "GMF\x1", 4)) {
+ _gameFile->seek(_gameOffsetsPtr[_musicIndexBase + music], SEEK_SET);
+ midi.loadSMF (_gameFile, music);
+ } else {
+ _gameFile->seek(_gameOffsetsPtr[_musicIndexBase + music], SEEK_SET);
+ midi.loadMultipleSMF (_gameFile);
+ }
+
+ } else {
+ char filename[15];
+ File f;
+ sprintf(filename, "MOD%d.MUS", music);
+ f.open(filename);
+ if (f.isOpen() == false)
+ error("loadMusic: Can't load music from '%s'", filename);
+
+ if (getGameId() == GID_SIMON1DEMO)
+ midi.loadS1D (&f);
+ else
+ midi.loadSMF (&f, music);
+ }
+
+ midi.startTrack (0);
+ } else {
+ midi.stop();
+ midi.setLoop (true); // Must do this BEFORE loading music. (GMF may have its own override.)
+
+ char filename[15];
+ File f;
+ sprintf(filename, "MOD%d.MUS", music);
+ f.open(filename);
+ if (f.isOpen() == false)
+ error("loadMusic: Can't load music from '%s'", filename);
+
+ midi.loadS1D (&f);
+ midi.startTrack (0);
+ }
+}
+
+void SimonEngine::playSting(uint a) {
+ if (!midi._enable_sfx)
+ return;
+
+ char filename[15];
+
+ File mus_file;
+ uint16 mus_offset;
+
+ sprintf(filename, "STINGS%i.MUS", _soundFileId);
+ mus_file.open(filename);
+ if (!mus_file.isOpen())
+ error("playSting: Can't load sound effect from '%s'", filename);
+
+ mus_file.seek(a * 2, SEEK_SET);
+ mus_offset = mus_file.readUint16LE();
+ if (mus_file.ioFailed())
+ error("playSting: Can't read sting %d offset", a);
+
+ mus_file.seek(mus_offset, SEEK_SET);
+ midi.loadSMF(&mus_file, a, true);
+ midi.startTrack(0);
+}
+
+void SimonEngine::set_volume(int volume) {
+ _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, volume);
+}
+
+} // End of namespace Simon
+
+#ifdef PALMOS_68K
+#include "scumm_globals.h"
+
+_GINIT(AGOS_AGOS)
+_GSETPTR(Simon::simon1_settings, GBVARS_SIMON1SETTINGS_INDEX, Simon::GameSpecificSettings, GBVARS_SIMON)
+_GSETPTR(Simon::simon2_settings, GBVARS_SIMON2SETTINGS_INDEX, Simon::GameSpecificSettings, GBVARS_SIMON)
+_GSETPTR(Simon::feeblefiles_settings, GBVARS_FEEBLEFILESSETTINGS_INDEX, Simon::GameSpecificSettings, GBVARS_SIMON)
+_GEND
+
+_GRELEASE(AGOS_AGOS)
+_GRELEASEPTR(GBVARS_SIMON1SETTINGS_INDEX, GBVARS_SIMON)
+_GRELEASEPTR(GBVARS_SIMON2SETTINGS_INDEX, GBVARS_SIMON)
+_GRELEASEPTR(GBVARS_FEEBLEFILESSETTINGS_INDEX, GBVARS_SIMON)
+_GEND
+
+#endif
diff --git a/engines/agos/simon.h b/engines/agos/simon.h
new file mode 100644
index 0000000000..90f3a1506c
--- /dev/null
+++ b/engines/agos/simon.h
@@ -0,0 +1,1191 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-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 AGOS_AGOS_H
+#define AGOS_AGOS_H
+
+#include "engines/engine.h"
+
+#include "common/rect.h"
+#include "common/util.h"
+
+#include "agos/animation.h"
+#include "agos/midi.h"
+#include "agos/sound.h"
+#include "agos/vga.h"
+
+namespace Simon {
+
+/* Various other settings */
+//#define DUMP_FILE_NR 8
+//#define DUMP_BITMAPS_FILE_NR 8
+
+uint fileReadItemID(Common::File *in);
+
+#define CHECK_BOUNDS(x, y) assert((uint)(x) < ARRAYSIZE(y))
+
+struct Child;
+struct SubObject;
+
+struct Item;
+struct WindowBlock;
+struct Subroutine;
+struct SubroutineLine;
+struct TimeEvent;
+
+struct TextLocation {
+ int16 x, y, width;
+ TextLocation() { memset(this, 0, sizeof(*this)); }
+};
+
+struct HitArea {
+ uint16 x, y;
+ uint16 width, height;
+ uint16 flags;
+ uint16 id;
+ uint16 data;
+ WindowBlock *window;
+ Item *item_ptr;
+ uint16 verb;
+ uint16 priority;
+ HitArea() { memset(this, 0, sizeof(*this)); }
+};
+
+struct VgaPointersEntry {
+ byte *vgaFile1;
+ byte *vgaFile1End;
+ byte *vgaFile2;
+ byte *vgaFile2End;
+ byte *sfxFile;
+ byte *sfxFileEnd;
+ VgaPointersEntry() { memset(this, 0, sizeof(*this)); }
+};
+
+struct VgaSprite {
+ uint16 id;
+ uint16 image;
+ uint16 palette;
+ uint16 x, y; /* actually signed numbers */
+ uint16 flags;
+ uint16 priority;
+ uint16 windowNum, zoneNum;
+ VgaSprite() { memset(this, 0, sizeof(*this)); }
+};
+
+struct VgaSleepStruct {
+ uint16 ident;
+ const byte *code_ptr;
+ uint16 sprite_id;
+ uint16 cur_vga_file;
+ VgaSleepStruct() { memset(this, 0, sizeof(*this)); }
+};
+
+struct VgaTimerEntry {
+ int16 delay;
+ const byte *script_pointer;
+ uint16 sprite_id;
+ uint16 cur_vga_file;
+ int32 param;
+ VgaTimerEntry() { memset(this, 0, sizeof(*this)); }
+};
+
+enum SIMONGameType {
+ GType_ELVIRA = 0,
+ GType_ELVIRA2 = 1,
+ GType_WW = 2,
+ GType_SIMON1 = 3,
+ GType_SIMON2 = 4,
+ GType_FF = 6,
+ GType_PP = 7
+};
+
+struct GameFileDescription {
+ const char *fileName;
+ uint16 fileType;
+ const char *md5;
+};
+
+struct GameDescription {
+ const char *name;
+ SIMONGameType gameType;
+ GameIds gameId;
+ const char *extra;
+ int filesCount;
+ GameFileDescription *filesDescriptions;
+ uint32 features;
+ Common::Language language;
+ Common::Platform platform;
+};
+
+struct GameSpecificSettings;
+
+class Debugger;
+
+class SimonEngine : public Engine {
+ friend class Debugger;
+ friend class MoviePlayer;
+
+ GUI::Debugger *getDebugger();
+
+ typedef void (SimonEngine::*OpcodeProc) ();
+ void setupOpcodes();
+ const OpcodeProc *_opcode_table;
+ int _numOpcodes;
+
+ typedef void (SimonEngine::*VgaOpcodeProc) ();
+ void setupVgaOpcodes();
+ const VgaOpcodeProc *_vga_opcode_table;
+
+public:
+ GameDescription *_gameDescription;
+
+ bool initGame(void);
+ void setupGame();
+
+ int getGameId() const { return _gameDescription->gameId; }
+ int getGameType() const { return _gameDescription->gameType; }
+ uint32 getFeatures() const { return _gameDescription->features; }
+ Common::Language getLanguage() const { return _gameDescription->language; }
+ Common::Platform getPlatform() const { return _gameDescription->platform; }
+ const char *getFileName(int type) const {
+ for (int i = 0; i < _gameDescription->filesCount; i++) {
+ if (_gameDescription->filesDescriptions[i].fileType == type)
+ return _gameDescription->filesDescriptions[i].fileName;
+ }
+ error("getFileName: Invalid type %d", type);
+ }
+
+protected:
+ void playSting(uint a);
+
+ const byte *_vcPtr; /* video code ptr */
+ uint16 _vc_get_out_of_code;
+
+
+ uint32 *_gameOffsetsPtr;
+
+ uint _vgaBaseDelay;
+ uint _tableIndexBase;
+ uint _textIndexBase;
+ uint _numVideoOpcodes;
+ uint _vgaMemSize;
+ uint _tableMemSize;
+ uint _musicIndexBase;
+ uint _soundIndexBase;
+ uint _numVars;
+ const GameSpecificSettings *gss;
+
+ byte _keyPressed;
+
+ typedef enum {
+ FORMAT_NONE,
+ FORMAT_MP3,
+ FORMAT_WAV,
+ FORMAT_VOC
+ } SoundFormat;
+
+ Common::File *_gameFile;
+
+ byte *_strippedTxtMem;
+ byte *_textMem;
+ uint _textSize;
+ uint _stringTabNum, _stringTabPos, _stringtab_numalloc;
+ byte **_stringTabPtr;
+
+ Item **_itemArrayPtr;
+ uint _itemArraySize;
+ uint _itemArrayInited;
+
+ byte *_itemHeapPtr;
+ uint _itemHeapCurPos;
+ uint _itemHeapSize;
+
+ byte *_iconFilePtr;
+
+ const byte *_codePtr;
+
+ byte **_localStringtable;
+ uint _stringIdLocalMin, _stringIdLocalMax;
+
+ byte *_roomsList;
+
+ byte *_xtblList;
+ byte *_xtablesHeapPtrOrg;
+ uint _xtablesHeapCurPosOrg;
+ Subroutine *_xsubroutineListOrg;
+
+ byte *_tblList;
+ byte *_tablesHeapPtr, *_tablesHeapPtrOrg, *_tablesheapPtrNew;
+ uint _tablesHeapSize, _tablesHeapCurPos, _tablesHeapCurPosOrg;
+ uint _tablesHeapCurPosNew;
+ Subroutine *_subroutineListOrg;
+
+ Subroutine *_subroutineList;
+ uint _subroutine;
+
+ uint _dxSurfacePitch;
+
+ uint _recursionDepth;
+
+ uint32 _lastVgaTick;
+
+ uint16 _marks;
+
+ bool _scriptVar2;
+ bool _runScriptReturn1;
+ bool _runScriptCondition[40];
+ int _runScriptReturn[40];
+ bool _skipVgaWait;
+ bool _noParentNotify;
+ bool _beardLoaded;
+ bool _hitarea_unk_3;
+ bool _mortalFlag;
+ bool _updateScreen;
+ bool _usePaletteDelay;
+ bool _syncFlag2;
+ bool _inCallBack;
+ bool _cepeFlag;
+ byte _copyPartialMode;
+ bool _fastMode;
+ bool _useBackGround;
+
+ uint16 _debugMode;
+ uint16 _language;
+ bool _pause;
+ bool _startMainScript;
+ bool _continousMainScript;
+ bool _startVgaScript;
+ bool _continousVgaScript;
+ bool _drawImagesDebug;
+ bool _dumpImages;
+ bool _speech;
+ bool _subtitles;
+ bool _vgaVar9;
+ int16 _chanceModifier;
+ bool _restoreWindow6;
+ int _scrollX, _scrollXMax, _scrollWidth;
+ int _scrollY, _scrollYMax, _scrollHeight;
+ int _scrollCount, _scrollFlag;
+ const byte *_scrollImage;
+ byte _boxStarHeight;
+
+ uint16 _hyperLink, _newLines;
+ uint16 _oracleMaxScrollY, _noOracleScroll;
+ uint16 _interactY;
+
+ int16 _scriptVerb, _scriptNoun1, _scriptNoun2;
+ int16 _scriptAdj1, _scriptAdj2;
+
+ uint16 _curWindow;
+ WindowBlock *_textWindow;
+
+ Item *_subjectItem, *_objectItem;
+ Item *_currentPlayer;
+
+ Item *_hitAreaObjectItem;
+ HitArea *_lastHitArea;
+ HitArea *_lastNameOn;
+ HitArea *_lastHitArea3;
+ Item *_hitAreaSubjectItem;
+ HitArea *_currentVerbBox, *_lastVerbOn;
+ uint _needHitAreaRecalc;
+ uint _verbHitArea;
+ uint16 _defaultVerb;
+ uint _currentBoxNumber;
+ uint _iOverflow;
+
+ uint16 _windowNum;
+
+ uint _printCharCurPos, _printCharMaxPos, _printCharPixelCount;
+ uint _numLettersToPrint;
+
+ uint _numTextBoxes;
+
+ uint _lastTime;
+ uint32 _clockStopped, _gameStoppedClock;
+ time_t _timeStore;
+
+ TimeEvent *_firstTimeStruct, *_pendingDeleteTimeEvent;
+
+ int _mouseX, _mouseY;
+ int _mouseXOld, _mouseYOld;
+
+ enum {
+ kMaxCursorWidth = 40,
+ kMaxCursorHeight = 40
+ };
+
+ byte _mouseData[kMaxCursorWidth * kMaxCursorHeight];
+ byte _animatePointer;
+ byte _mouseCursor, _mouseAnim, _mouseAnimMax;
+ byte _currentMouseCursor, _currentMouseAnim;
+ byte _oldMouseCursor, _oldMouseAnimMax;
+ uint _mouseHideCount;
+ bool _mouseToggle;
+
+ byte _leftButtonDown;
+ byte _rightButtonDown;
+ bool _noRightClick;
+
+ Item *_dummyItem1;
+ Item *_dummyItem2;
+ Item *_dummyItem3;
+
+ volatile uint16 _lockWord;
+ uint16 _scrollUpHitArea;
+ uint16 _scrollDownHitArea;
+
+ bool _fastFadeOutFlag;
+ bool _unkPalFlag;
+ byte _paletteFlag;
+ uint _fastFadeCount;
+ volatile uint16 _fastFadeInFlag;
+
+ int _screenWidth, _screenHeight;
+
+ uint16 _noOverWrite;
+ bool _rejectBlock;
+
+ bool _exitCutscene;
+
+ uint _soundFileId;
+ int16 _lastMusicPlayed;
+ int16 _nextMusicToPlay;
+
+ bool _showPreposition;
+ bool _showMessageFlag;
+
+ uint _vgaSpriteChanged;
+
+ byte *_vgaMemPtr, *_vgaMemEnd, *_vgaMemBase;
+ byte *_vgaFrozenBase, *_vgaRealBase;
+ byte *_zoneBuffers;
+
+ byte *_curVgaFile1;
+ byte *_curVgaFile2;
+ byte *_curSfxFile;
+
+ uint16 _syncCount, _timer5, _timer4;
+
+ uint16 _frameRate;
+
+ uint16 _zoneNumber;
+ uint16 _vgaWaitFor, _lastVgaWaitFor;
+ uint16 _vgaCurSpriteId, _vgaCurZoneNum;
+ uint16 _vgaCurSpritePriority;
+
+ int16 _baseY;
+ float _scale;
+ Common::Rect _feebleRect;
+ int _scaleX, _scaleY, _scaleWidth, _scaleHeight;
+
+ VgaTimerEntry *_nextVgaTimerToProcess;
+
+ Item *_objectArray[20];
+ Item *_itemStore[20];
+
+ uint16 _shortText[40];
+ uint16 _shortTextX[40];
+ uint16 _shortTextY[40];
+ uint16 _longText[40];
+ uint16 _longSound[40];
+
+ uint16 _bitArray[128];
+ uint16 _bitArrayTwo[16];
+ uint16 _bitArrayThree[16];
+ int16 *_variableArray;
+ int16 *_variableArray2;
+ int16 *_variableArrayPtr;
+
+ WindowBlock *_windowArray[16];
+
+ byte _fcsData1[8];
+ bool _fcsData2[8];
+
+ TextLocation _textLocation1, _textLocation2, _textLocation3, _textLocation4;
+
+ int _freeStringSlot;
+
+ byte _stringReturnBuffer[2][180];
+
+ HitArea _hitAreas[250];
+
+ VgaPointersEntry _vgaBufferPointers[450];
+ VgaSprite _vgaSprites[180];
+ VgaSleepStruct _vgaSleepStructs[60];
+
+ const uint16 *_pathFindArray[100];
+
+ uint8 _pathValues[400];
+ uint16 _PVCount;
+ uint16 _GPVCount;
+
+ uint8 _pathValues1[400];
+ uint16 _PVCount1;
+ uint16 _GPVCount1;
+
+ uint8 _currentPalette[1024];
+ uint8 _displayPalette[1024];
+
+ byte _videoBuf1[3000];
+
+ VgaTimerEntry _vgaTimerList[900];
+
+ WindowBlock *_windowList;
+
+ byte _lettersToPrintBuf[80];
+
+ MidiPlayer midi;
+ bool _native_mt32;
+
+ int _vgaTickCounter;
+
+ MoviePlayer *_moviePlay;
+
+ Sound *_sound;
+
+ bool _effectsPaused;
+ bool _ambientPaused;
+ bool _musicPaused;
+
+ Debugger *_debugger;
+
+ int _saveLoadRowCurPos;
+ int _numSaveGameRows;
+ bool _saveDialogFlag;
+ bool _saveOrLoad;
+ bool _saveLoadEdit;
+
+ byte _saveLoadType, _saveLoadSlot;
+ char _saveLoadName[108];
+
+ int _sdlMouseX, _sdlMouseY;
+
+ byte *_backGroundBuf;
+ byte *_frontBuf;
+ byte *_backBuf;
+ byte *_scaleBuf;
+
+ Common::RandomSource _rnd;
+
+ const byte *_vc10BasePtrOld;
+ byte _hebrewCharWidths[32];
+
+public:
+ SimonEngine(OSystem *syst);
+ virtual ~SimonEngine();
+
+protected:
+ uint16 to16Wrapper(uint value);
+ uint16 readUint16Wrapper(const void *src);
+ uint32 readUint32Wrapper(const void *src);
+
+ int allocGamePcVars(Common::File *in);
+ void setUserFlag(Item *item, int a, int b);
+ void createPlayer();
+ void allocateStringTable(int num);
+ void setupStringTable(byte *mem, int num);
+ void setupLocalStringTable(byte *mem, int num);
+ void readGamePcText(Common::File *in);
+ void readItemChildren(Common::File *in, Item *item, uint tmp);
+ void readItemFromGamePc(Common::File *in, Item *item);
+ void loadGamePcFile();
+ void decompressData(const char *srcName, byte *dst, uint32 offset, uint32 srcSize, uint32 dstSize);
+ void loadOffsets(const char *filename, int number, uint32 &file, uint32 &offset, uint32 &compressedSize, uint32 &size);
+ void loadSound(uint sound, int pan, int vol, uint type);
+ void loadVoice(uint speechId);
+
+ void paletteFadeOut(byte *palPtr, uint num, uint size);
+
+ byte *allocateItem(uint size);
+ byte *allocateTable(uint size);
+ void alignTableMem();
+
+ Child *findChildOfType(Item *i, uint child);
+ Child *allocateChildBlock(Item *i, uint type, uint size);
+
+ void allocItemHeap();
+ void allocTablesHeap();
+
+ Subroutine *createSubroutine(uint a);
+ void readSubroutine(Common::File *in, Subroutine *sub);
+ SubroutineLine *createSubroutineLine(Subroutine *sub, int a);
+ void readSubroutineLine(Common::File *in, SubroutineLine *new_table, Subroutine *sub);
+ byte *readSingleOpcode(Common::File *in, byte *ptr);
+ void readSubroutineBlock(Common::File *in);
+
+ Subroutine *getSubroutineByID(uint subroutine_id);
+
+ /* used in debugger */
+ void dumpSubroutines();
+ void dumpSubroutine(Subroutine *sub);
+ void dumpSubroutineLine(SubroutineLine *sl, Subroutine *sub);
+ const byte *dumpOpcode(const byte *p);
+
+ int startSubroutine(Subroutine *sub);
+ int startSubroutineEx(Subroutine *sub);
+
+ bool checkIfToRunSubroutineLine(SubroutineLine *sl, Subroutine *sub);
+
+ int runScript();
+
+ Item *getNextItemPtr();
+ uint getNextItemID();
+ uint getItem1ID() {return 1;}
+ Item *me();
+ Item *actor();
+
+ byte getByte();
+ int getNextWord();
+
+ uint getNextVarContents();
+ uint getVarWrapper();
+ uint getVarOrWord();
+ uint getVarOrByte();
+ uint readVariable(uint variable);
+ void writeNextVarContents(uint16 contents);
+ void writeVariable(uint variable, uint16 contents);
+
+ void setItemParent(Item *item, Item *parent);
+
+ uint itemPtrToID(Item *id);
+
+ Item *derefItem(uint item);
+ void setItemState(Item *item, int value);
+
+ void showMessageFormat(const char *s, ...);
+ const byte *getStringPtrByID(uint stringId);
+ const byte *getLocalStringByID(uint stringId);
+ uint getNextStringID();
+
+ void addTimeEvent(uint timeout, uint subroutine_id);
+ void delTimeEvent(TimeEvent *te);
+
+ bool isRoom(Item *item);
+ bool isObject(Item *item);
+
+ void itemChildrenChanged(Item *item);
+ void unlinkItem(Item *item);
+ void linkItem(Item *item, Item *parent);
+
+ void stopAnimateSimon1(uint a);
+ void stopAnimateSimon2(uint a, uint b);
+
+ void enableBox(uint hitarea);
+ void disableBox(uint hitarea);
+ void moveBox(uint hitarea, int x, int y);
+ bool isBoxDead(uint hitarea);
+ void undefineBox(uint hitarea);
+ void defineBox(int id, int x, int y, int width, int height, int flags, int verb, Item *item_ptr);
+ HitArea *findEmptyHitArea();
+
+ void resetVerbs();
+ void setVerb(HitArea * ha);
+ void hitarea_leave(HitArea * ha, bool state = false);
+ void leaveHitAreaById(uint hitarea_id);
+
+ void sendSync(uint a);
+ void waitForSync(uint a);
+
+ uint getOffsetOfChild2Param(SubObject *child, uint prop);
+ void setTextColor(uint color);
+ void scriptMouseOn();
+ void scriptMouseOff();
+ void freezeBottom();
+ void unfreezeBottom();
+
+ TextLocation *getTextLocation(uint a);
+ void setup_cond_c_helper();
+
+ void checkLinkBox();
+ void hyperLinkOn(uint16 x);
+ void hyperLinkOff();
+ void linksUp();
+ void linksDown();
+ void oracleTextUp();
+ void oracleTextDown();
+ void listSaveGames(int n);
+ void saveUserGame(int slot);
+ void windowBackSpace(WindowBlock *window);
+
+ void oracleLogo();
+ void scrollOracle();
+ void scrollOracleUp();
+ void scrollOracleDown();
+ void swapCharacterLogo();
+
+ void mouseOff();
+ void mouseOn();
+
+ bool loadTablesIntoMem(uint subr_id);
+ bool loadTablesOldIntoMem(uint subr_id);
+ bool loadTablesNewIntoMem(uint subr_id);
+ bool loadXTablesIntoMem(uint subr_id);
+ void loadTextIntoMem(uint stringId);
+
+ bool loadRoomItems(uint item);
+
+ uint loadTextFile(const char *filename, byte *dst);
+ Common::File *openTablesFile(const char *filename);
+ void closeTablesFile(Common::File *in);
+
+ uint loadTextFile_simon1(const char *filename, byte *dst);
+ Common::File *openTablesFile_simon1(const char *filename);
+
+ uint loadTextFile_gme(const char *filename, byte *dst);
+ Common::File *openTablesFile_gme(const char *filename);
+
+ void invokeTimeEvent(TimeEvent *te);
+ bool kickoffTimeEvents();
+ void killAllTimers();
+
+ void endCutscene();
+ void runSubroutine101();
+
+ void checkUp(WindowBlock *window);
+ void checkDown(WindowBlock *window);
+ void inventoryUp(WindowBlock *window);
+ void inventoryDown(WindowBlock *window);
+
+ WindowBlock *openWindow(uint x, uint y, uint w, uint h, uint flags, uint fill_color, uint text_color);
+ uint getWindowNum(WindowBlock *window);
+ void clearWindow(WindowBlock *window);
+ void changeWindow(uint a);
+ void closeWindow(uint a);
+ void windowPutChar(WindowBlock *window, byte c, byte b = 0);
+
+ HitArea *findBox(uint hitarea_id);
+ void boxController(uint x, uint y, uint mode);
+ void handleVerbClicked(uint verb);
+ void clearName();
+ void displayName(HitArea * ha);
+ void resetNameWindow();
+ void displayBoxStars();
+ void hitarea_stuff();
+ void invertBox_FF(HitArea *ha, bool state);
+ void invertBox(HitArea * ha, byte a, byte b, byte c, byte d);
+
+ void handleMouseMoved();
+ void pollMouseXY();
+ void drawMousePointer();
+ void drawMousePointer_FF();
+ void drawMousePart(int image, byte x, byte y);
+
+ void defineArrowBoxes(WindowBlock *window);
+ void removeArrows(WindowBlock *window, uint num);
+
+ void draw_icon_c(WindowBlock *window, uint icon, uint x, uint y);
+ bool has_item_childflag_0x10(Item *item);
+ uint itemGetIconNumber(Item *item);
+ uint setupIconHitArea(WindowBlock *window, uint num, uint x, uint y, Item *item_ptr);
+ void drawIconArray(uint i, Item *item_ptr, int line, int classMask);
+ void drawIconArray_FF(uint i, Item *item_ptr, int line, int classMask);
+ void drawIconArray_Simon(uint i, Item *item_ptr, int line, int classMask);
+ void removeIconArray(uint num);
+
+ void loadIconData();
+ void loadIconFile();
+
+ void processSpecialKeys();
+ void hitarea_stuff_helper();
+
+ void permitInput();
+
+ uint getFeebleFontSize(byte chr);
+ void showmessage_helper_3(uint a, uint b);
+ void showmessage_print_char(byte chr);
+
+ void set_video_mode_internal(uint16 mode, uint16 vga_res_id);
+
+ void loadZone(uint vga_res);
+
+ void loadSprite(uint windowNum, uint vga_res, uint vga_sprite_id, uint x, uint y, uint palette);
+ void playSpeech(uint speech_id, uint vga_sprite_id);
+ void skipSpeech();
+
+ bool printNameOf(Item *item, uint x, uint y);
+ bool printTextOf(uint a, uint x, uint y);
+ void printVerbOf(uint hitarea_id);
+ void showActionString(const byte *string);
+
+ void printScreenText(uint vga_sprite_id, uint color, const char *string_ptr, int16 x, int16 y, int16 width);
+ void sendInteractText(uint16 num, const char *fmt, ...);
+ void printInteractText(uint16 num, const char *string);
+
+ void renderStringAmiga(uint vga_sprite_id, uint color, uint width, uint height, const char *txt);
+ void renderString(uint vga_sprite_id, uint color, uint width, uint height, const char *txt);
+
+ byte *allocBlock(uint32 size);
+ void checkNoOverWrite(byte *end);
+ void checkRunningAnims(byte *end);
+ void checkAnims(uint a, byte *end);
+ void checkZonePtrs(byte *end);
+ void setZoneBuffers();
+
+ void runVgaScript();
+
+public:
+ bool getBitFlag(uint bit);
+ void setBitFlag(uint bit, bool value);
+
+ // Simon1/Simon2 video script opcodes
+ void vc1_fadeOut();
+ void vc2_call();
+ void vc3_loadSprite();
+ void vc4_fadeIn();
+ void vc5_skip_if_neq();
+ void vc6_skip_ifn_sib_with_a();
+ void vc7_skip_if_sib_with_a();
+ void vc8_skip_if_parent_is();
+ void vc9_skip_if_unk3_is();
+ void vc10_draw();
+ void vc11_clearPathFinder();
+ void vc12_delay();
+ void vc13_addToSpriteX();
+ void vc14_addToSpriteY();
+ void vc15_sync();
+ void vc16_waitSync();
+ void vc17_setPathfinderItem();
+ void vc18_jump();
+ void vc19_chain_to_script();
+ void vc20_setRepeat();
+ void vc21_endRepeat();
+ void vc22_setSpritePalette();
+ void vc23_setSpritePriority();
+ void vc24_setSpriteXY();
+ void vc25_halt_sprite();
+ void vc26_setSubWindow();
+ void vc27_resetSprite();
+ void vc28_dummy_op();
+ void vc29_stopAllSounds();
+ void vc30_setFrameRate();
+ void vc31_setWindow();
+ void vc32_copyVar();
+ void vc33_setMouseOn();
+ void vc34_setMouseOff();
+ void vc35_clearWindow();
+ void vc36_setWindowImage();
+ void vc37_addToSpriteY();
+ void vc38_skipIfVarZero();
+ void vc39_setVar();
+ void vc40();
+ void vc41();
+ void vc42_delayIfNotEQ();
+ void vc43_skipIfBitClear();
+ void vc44_skipIfBitSet();
+ void vc45_setSpriteX();
+ void vc46_setSpriteY();
+ void vc47_addToVar();
+ void vc48_setPathFinder();
+ void vc49_setBit();
+ void vc50_clearBit();
+ void vc51_enableBox();
+ void vc52_playSound();
+ void vc53_panSFX();
+ void vc54_no_op();
+ void vc55_moveBox();
+ void vc56_delay();
+ void vc57_blackPalette();
+ void vc58();
+ void vc59();
+ void vc60_killSprite();
+ void vc61_setMaskImage();
+ void vc62_fastFadeOut();
+ void vc63_fastFadeIn();
+
+ // Simon2 specific Video Script Opcodes
+ void vc64_skipIfSpeechEnded();
+ void vc65_slowFadeIn();
+ void vc66_skipIfNotEqual();
+ void vc67_skipIfGE();
+ void vc68_skipIfLE();
+ void vc69_playTrack();
+ void vc70_queueMusic();
+ void vc71_checkMusicQueue();
+ void vc72_play_track_2();
+ void vc73_setMark();
+ void vc74_clearMark();
+
+ // Feeble specific Video Script Opcodes
+ void vc75_setScale();
+ void vc76_setScaleXOffs();
+ void vc77_setScaleYOffs();
+ void vc78_computeXY();
+ void vc79_computePosNum();
+ void vc80_setOverlayImage();
+ void vc81_setRandom();
+ void vc82_getPathValue();
+ void vc83_playSoundLoop();
+ void vc84_stopSoundLoop();
+
+ void setScriptCondition(bool cond);
+ bool getScriptCondition();
+ void setScriptReturn(int ret);
+ int getScriptReturn();
+
+ // Opcodes, Simon 1 and later
+ void o_at();
+ void o_notAt();
+ void o_carried();
+ void o_notCarried();
+ void o_isAt();
+ void o_zero();
+ void o_notZero();
+ void o_eq();
+ void o_notEq();
+ void o_gt();
+ void o_lt();
+ void o_eqf();
+ void o_notEqf();
+ void o_ltf();
+ void o_gtf();
+ void o_chance();
+ void o_isRoom();
+ void o_isObject();
+ void o_state();
+ void o_oflag();
+ void o_destroy();
+ void o_place();
+ void o_copyff();
+ void o_clear();
+ void o_let();
+ void o_add();
+ void o_sub();
+ void o_addf();
+ void o_subf();
+ void o_mul();
+ void o_div();
+ void o_mulf();
+ void o_divf();
+ void o_mod();
+ void o_modf();
+ void o_random();
+ void o_goto();
+ void o_oset();
+ void o_oclear();
+ void o_putBy();
+ void o_inc();
+ void o_dec();
+ void o_setState();
+ void o_print();
+ void o_message();
+ void o_msg();
+ void o_addTextBox();
+ void o_setShortText();
+ void o_setLongText();
+ void o_end();
+ void o_done();
+ void o_process();
+ void o_when();
+ void o_if1();
+ void o_if2();
+ void o_isCalled();
+ void o_is();
+ void o_debug();
+ void o_comment();
+ void o_haltAnimation();
+ void o_restartAnimation();
+ void o_getParent();
+ void o_getNext();
+ void o_getChildren();
+ void o_picture();
+ void o_loadZone();
+ void o_killAnimate();
+ void o_defWindow();
+ void o_window();
+ void o_cls();
+ void o_closeWindow();
+ void o_addBox();
+ void o_delBox();
+ void o_enableBox();
+ void o_disableBox();
+ void o_moveBox();
+ void o_doIcons();
+ void o_isClass();
+ void o_setClass();
+ void o_unsetClass();
+ void o_waitSync();
+ void o_sync();
+ void o_defObj();
+ void o_here();
+ void o_doClassIcons();
+ void o_waitEndTune();
+ void o_ifEndTune();
+ void o_setAdjNoun();
+ void o_saveUserGame();
+ void o_loadUserGame();
+ void o_stopTune();
+ void o_pauseGame();
+ void o_copysf();
+ void o_restoreIcons();
+ void o_freezeZones();
+ void o_placeNoIcons();
+ void o_clearTimers();
+ void o_setDollar();
+ void o_isBox();
+ void o_doTable();
+ void o_storeItem();
+ void o_getItem();
+ void o_bSet();
+ void o_bClear();
+ void o_bZero();
+ void o_bNotZero();
+ void o_getOValue();
+ void o_setOValue();
+ void o_ink();
+ void o_screenTextBox();
+ void o_screenTextMsg();
+ void o_playEffect();
+ void o_getDollar2();
+ void o_isAdjNoun();
+ void o_b2Set();
+ void o_b2Clear();
+ void o_b2Zero();
+ void o_b2NotZero();
+ void o_lockZones();
+ void o_unlockZones();
+ void o_getPathPosn();
+ void o_scnTxtLongText();
+ void o_mouseOn();
+ void o_unloadZone();
+ void o_unfreezeZones();
+
+ uint16 getDoorState(Item *item, uint16 d);
+ uint16 getExitOf(Item *item, uint16 d);
+
+ // Opcodes, Waxworks only
+ void oww_whereTo();
+ void oww_menu();
+ void oww_textMenu();
+ void oww_ifDoorOpen();
+
+ // Opcodes, Simon 1 only
+ void o1_printLongText();
+ void o1_rescan();
+ void o1_animate();
+ void o1_stopAnimate();
+ void o1_playTune();
+ void o1_screenTextPObj();
+ void o1_mouseOff();
+ void o1_loadBeard();
+ void o1_unloadBeard();
+ void o1_loadStrings();
+ void o1_specialFade();
+
+ // Opcodes, Simon 2 and later
+ void o2_printLongText();
+ void o2_rescan();
+ void o2_animate();
+ void o2_stopAnimate();
+ void o2_playTune();
+ void o2_screenTextPObj();
+ void o2_mouseOff();
+ void o2_isShortText();
+ void o2_clearMarks();
+ void o2_waitMark();
+
+ // Opcodes, Feeble Files only
+ void o3_chance();
+ void o3_jumpOut();
+ void o3_addTextBox();
+ void o3_printLongText();
+ void o3_addBox();
+ void o3_oracleTextDown();
+ void o3_oracleTextUp();
+ void o3_ifTime();
+ void o3_playTune();
+ void o3_setTime();
+ void o3_saveUserGame();
+ void o3_loadUserGame();
+ void o3_listSaveGames();
+ void o3_checkCD();
+ void o3_screenTextBox();
+ void o3_isAdjNoun();
+ void o3_hyperLinkOn();
+ void o3_hyperLinkOff();
+ void o3_checkPaths();
+ void o3_screenTextPObj();
+ void o3_mouseOff();
+ void o3_loadVideo();
+ void o3_playVideo();
+ void o3_centreScroll();
+ void o3_resetPVCount();
+ void o3_setPathValues();
+ void o3_stopClock();
+ void o3_restartClock();
+ void o3_setColour();
+ void o3_b3Set();
+ void o3_b3Clear();
+ void o3_b3Zero();
+ void o3_b3NotZero();
+
+ // Opcodes, Puzzle Pack only
+ void o4_opcode30();
+ void o4_checkTiles();
+ void o4_opcode38();
+ void o4_loadHiScores();
+ void o4_checkHiScores();
+ void o4_loadUserGame();
+ void o4_saveOopsPosition();
+ void o4_resetGameTime();
+ void o4_resetPVCount();
+ void o4_setPathValues();
+
+protected:
+ void drawImages(VC10_state *state);
+ void drawImages_Feeble(VC10_state *state);
+ bool drawImages_clip(VC10_state *state);
+ void scaleClip(int16 h, int16 w, int16 y, int16 x, int16 scrollY);
+ void horizontalScroll(VC10_state *state);
+ void verticalScroll(VC10_state *state);
+
+ int vcReadVarOrWord();
+ uint vcReadNextWord();
+ uint vcReadNextByte();
+ uint vcReadVar(uint var);
+ void vcWriteVar(uint var, int16 value);
+ void vcSkipNextInstruction();
+
+ int getScale(int16 y, int16 x);
+ void checkScrollX(int16 x, int16 xpos);
+ void checkScrollY(int16 y, int16 ypos);
+ void centreScroll();
+
+ bool itemIsSiblingOf(uint16 val);
+ bool itemIsParentOf(uint16 a, uint16 b);
+ bool vc_maybe_skip_proc_1(uint16 a, int16 b);
+
+ void addVgaEvent(uint16 num, const byte *code_ptr, uint16 cur_sprite, uint16 curZoneNum, int32 param = 0);
+ void deleteVgaEvent(VgaTimerEntry * vte);
+ void processVgaEvents();
+ void animateEvent(const byte *code_ptr, uint16 curZoneNum, uint16 cur_sprite);
+ void panEvent(uint16 curZoneNum, uint16 cur_sprite, int32 param);
+ void scrollEvent();
+
+ VgaSprite *findCurSprite();
+
+ bool isSpriteLoaded(uint16 id, uint16 zoneNum);
+
+ void resetWindow(WindowBlock *window);
+ void delete_hitarea_by_index(uint index);
+
+ void windowPutChar(uint a);
+
+ void restoreWindow(WindowBlock *window);
+ void colorWindow(WindowBlock *window);
+
+ void restoreBlock(uint h, uint w, uint y, uint x);
+
+ byte *getFrontBuf();
+ byte *getBackBuf();
+ byte *getBackGround();
+ byte *getScaleBuf();
+
+ byte *loadVGAFile(uint id, uint type, uint32 &dstSize);
+ void loadSimonVGAFile(uint vga_id);
+
+ int init();
+ int go();
+
+ void openGameFile();
+ void readGameFile(void *dst, uint32 offs, uint32 size);
+
+ void timer_callback();
+ void timer_proc1();
+
+ void animateSprites();
+ void animateSpritesDebug();
+ void animateSpritesByY();
+
+ void dx_clear_surfaces(uint num_lines);
+ void dx_update_screen_and_palette();
+
+ void dump_video_script(const byte *src, bool one_opcode_only);
+ void dump_vga_file(const byte *vga);
+ void dump_vga_script(const byte *ptr, uint res, uint sprite_id);
+ void dump_vga_script_always(const byte *ptr, uint res, uint sprite_id);
+ void dump_vga_bitmaps(const byte *vga, byte *vga1, int res);
+ void dump_single_bitmap(int file, int image, const byte *offs, int w, int h, byte base);
+ void dump_bitmap(const char *filename, const byte *offs, int w, int h, int flags, const byte *palette, byte base);
+
+ void clearBackFromTop(uint lines);
+ void fillFrontFromBack(uint x, uint y, uint w, uint h);
+ void fillBackGroundFromBack(uint lines);
+ void fillBackFromFront(uint x, uint y, uint w, uint h);
+
+ void print_char_helper_1(const byte *src, uint len);
+ void print_char_helper_5(WindowBlock *window);
+
+ void quickLoadOrSave();
+ void shutdown();
+
+ byte *vc10_uncompressFlip(const byte *src, uint w, uint h);
+ byte *vc10_flip(const byte *src, uint w, uint h);
+
+ Item *getNextItemPtrStrange();
+
+ bool saveGame(uint slot, char *caption);
+ bool loadGame(uint slot);
+
+ void openTextWindow();
+ void tidyIconArray(uint i);
+
+ void video_putchar_newline(WindowBlock *window);
+ void video_putchar_drawchar(WindowBlock *window, uint x, uint y, byte chr);
+
+ void loadMusic(uint music);
+ void checkTimerCallback();
+ void delay(uint delay);
+ void pause();
+
+ void waitForMark(uint i);
+ void scrollScreen();
+
+ void decodeColumn(byte *dst, const byte *src, int height);
+ void decodeRow(byte *dst, const byte *src, int width);
+ void hitarea_stuff_helper_2();
+ void fastFadeIn();
+ void slowFadeIn();
+
+ void vc_kill_sprite(uint file, uint sprite);
+
+ void set_dummy_cursor();
+
+ void set_volume(int volume);
+
+ void userGame(bool load);
+ void disableFileBoxes();
+ int userGameGetKey(bool *b, char *buf);
+ void userGameBackSpace(WindowBlock *window, int x, byte b = 0);
+ void listSaveGames(char *buf);
+ void fileError(WindowBlock *window, bool save_error);
+
+ int countSaveGames();
+ int displaySaveGameList(int curpos, bool load, char *dst);
+
+ char *genSaveName(int slot);
+};
+
+} // End of namespace Simon
+
+#endif
diff --git a/engines/agos/sound.cpp b/engines/agos/sound.cpp
new file mode 100644
index 0000000000..42c2df1723
--- /dev/null
+++ b/engines/agos/sound.cpp
@@ -0,0 +1,714 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-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 "agos/agos.h"
+#include "agos/sound.h"
+
+#include "sound/adpcm.h"
+#include "sound/audiostream.h"
+#include "sound/flac.h"
+#include "sound/mp3.h"
+#include "sound/voc.h"
+#include "sound/vorbis.h"
+#include "sound/wave.h"
+
+using Common::File;
+
+namespace Simon {
+
+#define SOUND_BIG_ENDIAN true
+
+class BaseSound {
+protected:
+ File *_file;
+ uint32 *_offsets;
+ Audio::Mixer *_mixer;
+ bool _freeOffsets;
+
+public:
+ BaseSound(Audio::Mixer *mixer, File *file, uint32 base = 0, bool bigendian = false);
+ BaseSound(Audio::Mixer *mixer, File *file, uint32 *offsets, bool bigendian = false);
+ virtual ~BaseSound();
+ virtual void playSound(uint sound, Audio::SoundHandle *handle, byte flags) = 0;
+};
+
+class WavSound : public BaseSound {
+public:
+ WavSound(Audio::Mixer *mixer, File *file, uint32 base = 0, bool bigendian = false) : BaseSound(mixer, file, base, bigendian) {};
+ WavSound(Audio::Mixer *mixer, File *file, uint32 *offsets) : BaseSound(mixer, file, offsets) {};
+ void playSound(uint sound, Audio::SoundHandle *handle, byte flags);
+};
+
+class VocSound : public BaseSound {
+public:
+ VocSound(Audio::Mixer *mixer, File *file, uint32 base = 0, bool bigendian = false) : BaseSound(mixer, file, base, bigendian) {};
+ void playSound(uint sound, Audio::SoundHandle *handle, byte flags);
+};
+class RawSound : public BaseSound {
+public:
+ RawSound(Audio::Mixer *mixer, File *file, uint32 base = 0, bool bigendian = false) : BaseSound(mixer, file, base, bigendian) {};
+ void playSound(uint sound, Audio::SoundHandle *handle, byte flags);
+};
+
+BaseSound::BaseSound(Audio::Mixer *mixer, File *file, uint32 base, bool bigendian) {
+ _mixer = mixer;
+ _file = file;
+
+ uint res = 0;
+ uint32 size;
+
+ _file->seek(base + sizeof(uint32), SEEK_SET);
+ if (bigendian)
+ size = _file->readUint32BE();
+ else
+ size = _file->readUint32LE();
+
+ // The Feeble Files uses set amount of voice offsets
+ if (size == 0)
+ size = 40000;
+
+ res = size / sizeof(uint32);
+
+ _offsets = (uint32 *)malloc(size + sizeof(uint32));
+ _freeOffsets = true;
+
+ _file->seek(base, SEEK_SET);
+
+ if (_file->read(_offsets, size) != size)
+ error("BaseSound: Can't read offsets");
+
+ for (uint i = 0; i < res; i++) {
+#if defined(SCUMM_BIG_ENDIAN)
+ if (!(bigendian))
+ _offsets[i] = FROM_LE_32(_offsets[i]);
+#endif
+ if (bigendian)
+ _offsets[i] = TO_BE_32(_offsets[i]);
+ _offsets[i] += base;
+ }
+
+ // only needed for mp3
+ _offsets[res] = _file->size();
+}
+
+BaseSound::BaseSound(Audio::Mixer *mixer, File *file, uint32 *offsets, bool bigendian) {
+ _mixer = mixer;
+ _file = file;
+ _offsets = offsets;
+ _freeOffsets = false;
+}
+
+BaseSound::~BaseSound() {
+ if (_freeOffsets)
+ free(_offsets);
+ delete _file;
+}
+
+void WavSound::playSound(uint sound, Audio::SoundHandle *handle, byte flags) {
+ if (_offsets == NULL)
+ return;
+
+ _file->seek(_offsets[sound], SEEK_SET);
+
+ byte wavFlags;
+ int size, rate;
+ if (!Audio::loadWAVFromStream(*_file, size, rate, wavFlags))
+ error("playSound: Not a valid WAV file");
+
+ flags |= wavFlags;
+
+ byte *buffer = (byte *)malloc(size);
+ // Check whether malloc was successful.
+ // TODO: Maybe we can handle this more graceful, by reverting to a smaller
+ // buffer and reading the audio data one piece at a time?
+ if (buffer) {
+ _file->read(buffer, size);
+ _mixer->playRaw(handle, buffer, size, rate, flags | Audio::Mixer::FLAG_AUTOFREE);
+ }
+}
+
+void VocSound::playSound(uint sound, Audio::SoundHandle *handle, byte flags) {
+ if (_offsets == NULL)
+ return;
+
+ _file->seek(_offsets[sound], SEEK_SET);
+
+ int size, rate;
+ byte *buffer = Audio::loadVOCFromStream(*_file, size, rate);
+ _mixer->playRaw(handle, buffer, size, rate, flags | Audio::Mixer::FLAG_AUTOFREE);
+}
+
+void RawSound::playSound(uint sound, Audio::SoundHandle *handle, byte flags) {
+ if (_offsets == NULL)
+ return;
+
+ _file->seek(_offsets[sound], SEEK_SET);
+
+ uint size = _file->readUint32BE();
+ byte *buffer = (byte *)malloc(size);
+ // Check whether malloc was successful.
+ // TODO: Maybe we can handle this more graceful, by reverting to a smaller
+ // buffer and reading the audio data one piece at a time?
+ if (buffer) {
+ _file->read(buffer, size);
+ _mixer->playRaw(handle, buffer, size, 22050, flags | Audio::Mixer::FLAG_AUTOFREE);
+ }
+}
+
+#ifdef USE_MAD
+class MP3Sound : public BaseSound {
+public:
+ MP3Sound(Audio::Mixer *mixer, File *file, uint32 base = 0) : BaseSound(mixer, file, base) {};
+ void playSound(uint sound, Audio::SoundHandle *handle, byte flags);
+};
+
+void MP3Sound::playSound(uint sound, Audio::SoundHandle *handle, byte flags)
+{
+ if (_offsets == NULL)
+ return;
+
+ _file->seek(_offsets[sound], SEEK_SET);
+
+ int i = 1;
+ while (_offsets[sound + i] == _offsets[sound])
+ i++;
+
+ uint32 size = _offsets[sound + i] - _offsets[sound];
+
+ _mixer->playInputStream(Audio::Mixer::kSFXSoundType, handle, Audio::makeMP3Stream(_file, size));
+}
+#endif
+
+#ifdef USE_VORBIS
+class VorbisSound : public BaseSound {
+public:
+ VorbisSound(Audio::Mixer *mixer, File *file, uint32 base = 0) : BaseSound(mixer, file, base) {};
+ void playSound(uint sound, Audio::SoundHandle *handle, byte flags);
+};
+
+void VorbisSound::playSound(uint sound, Audio::SoundHandle *handle, byte flags)
+{
+ if (_offsets == NULL)
+ return;
+
+ _file->seek(_offsets[sound], SEEK_SET);
+
+ int i = 1;
+ while (_offsets[sound + i] == _offsets[sound])
+ i++;
+
+ uint32 size = _offsets[sound + i] - _offsets[sound];
+
+ _mixer->playInputStream(Audio::Mixer::kSFXSoundType, handle, Audio::makeVorbisStream(_file, size));
+}
+#endif
+
+#ifdef USE_FLAC
+class FlacSound : public BaseSound {
+public:
+ FlacSound(Audio::Mixer *mixer, File *file, uint32 base = 0) : BaseSound(mixer, file, base) {};
+ void playSound(uint sound, Audio::SoundHandle *handle, byte flags);
+};
+
+void FlacSound::playSound(uint sound, Audio::SoundHandle *handle, byte flags)
+{
+ if (_offsets == NULL)
+ return;
+
+ _file->seek(_offsets[sound], SEEK_SET);
+
+ int i = 1;
+ while (_offsets[sound + i] == _offsets[sound])
+ i++;
+
+ uint32 size = _offsets[sound + i] - _offsets[sound];
+
+ _mixer->playInputStream(Audio::Mixer::kSFXSoundType, handle, Audio::makeFlacStream(_file, size));
+}
+#endif
+
+Sound::Sound(SimonEngine *vm, const GameSpecificSettings *gss, Audio::Mixer *mixer)
+ : _vm(vm), _mixer(mixer) {
+ _voice = 0;
+ _effects = 0;
+
+ _effectsPaused = false;
+ _ambientPaused = false;
+ _sfx5Paused = false;
+
+ _filenums = 0;
+ _lastVoiceFile = 0;
+ _offsets = 0;
+
+ _hasEffectsFile = false;
+ _hasVoiceFile = false;
+
+ _ambientPlaying = 0;
+
+ if (_vm->getFeatures() & GF_TALKIE) {
+ loadVoiceFile(gss);
+
+ if (_vm->getGameType() == GType_SIMON1)
+ loadSfxFile(gss);
+ }
+}
+
+Sound::~Sound() {
+ delete _voice;
+ delete _effects;
+
+ free(_filenums);
+ free(_offsets);
+}
+
+void Sound::loadVoiceFile(const GameSpecificSettings *gss) {
+ // Game versions which use separate voice files
+ if (_vm->getGameType() == GType_FF || _vm->getGameId() == GID_SIMON1CD32)
+ return;
+
+ char filename[16];
+ File *file = new File();
+
+#ifdef USE_FLAC
+ if (!_hasVoiceFile) {
+ sprintf(filename, "%s.fla", gss->speech_filename);
+ file->open(filename);
+ if (file->isOpen()) {
+ _hasVoiceFile = true;
+ _voice = new FlacSound(_mixer, file);
+ }
+ }
+#endif
+#ifdef USE_MAD
+ if (!_hasVoiceFile) {
+ sprintf(filename, "%s.mp3", gss->speech_filename);
+ file->open(filename);
+ if (file->isOpen()) {
+ _hasVoiceFile = true;
+ _voice = new MP3Sound(_mixer, file);
+ }
+ }
+#endif
+#ifdef USE_VORBIS
+ if (!_hasVoiceFile) {
+ sprintf(filename, "%s.ogg", gss->speech_filename);
+ file->open(filename);
+ if (file->isOpen()) {
+ _hasVoiceFile = true;
+ _voice = new VorbisSound(_mixer, file);
+ }
+ }
+#endif
+ if (!_hasVoiceFile && _vm->getGameType() == GType_SIMON2) {
+ // for simon2 mac/amiga, only read index file
+ file->open("voices.idx");
+ if (file->isOpen() == true) {
+ int end = file->size();
+ _filenums = (uint16 *)malloc((end / 6 + 1) * 2);
+ _offsets = (uint32 *)malloc((end / 6 + 1) * 4);
+
+ for (int i = 1; i <= end / 6; i++) {
+ _filenums[i] = file->readUint16BE();
+ _offsets[i] = file->readUint32BE();
+ }
+ _hasVoiceFile = true;
+ }
+ }
+ if (!_hasVoiceFile) {
+ sprintf(filename, "%s.wav", gss->speech_filename);
+ file->open(filename);
+ if (file->isOpen()) {
+ _hasVoiceFile = true;
+ _voice = new WavSound(_mixer, file);
+ }
+ }
+ if (!_hasVoiceFile) {
+ sprintf(filename, "%s.voc", gss->speech_filename);
+ file->open(filename);
+ if (file->isOpen()) {
+ _hasVoiceFile = true;
+ _voice = new VocSound(_mixer, file);
+ }
+ }
+ if (!_hasVoiceFile) {
+ sprintf(filename, "%s", gss->speech_filename);
+ file->open(filename);
+ if (file->isOpen()) {
+ _hasVoiceFile = true;
+ if (_vm->getGameType() == GType_PP)
+ _voice = new WavSound(_mixer, file);
+ else
+ _voice = new VocSound(_mixer, file);
+ }
+ }
+}
+
+void Sound::loadSfxFile(const GameSpecificSettings *gss) {
+ char filename[16];
+ File *file = new File();
+
+#ifdef USE_MAD
+ if (!_hasEffectsFile) {
+ sprintf(filename, "%s.mp3", gss->effects_filename);
+ file->open(filename);
+ if (file->isOpen()) {
+ _hasEffectsFile = true;
+ _effects = new MP3Sound(_mixer, file);
+ }
+ }
+#endif
+#ifdef USE_VORBIS
+ if (!_hasEffectsFile) {
+ sprintf(filename, "%s.ogg", gss->effects_filename);
+ file->open(filename);
+ if (file->isOpen()) {
+ _hasEffectsFile = true;
+ _effects = new VorbisSound(_mixer, file);
+ }
+ }
+#endif
+#ifdef USE_FLAC
+ if (!_hasEffectsFile) {
+ sprintf(filename, "%s.fla", gss->effects_filename);
+ file->open(filename);
+ if (file->isOpen()) {
+ _hasEffectsFile = true;
+ _effects = new FlacSound(_mixer, file);
+ }
+ }
+#endif
+ if (!_hasEffectsFile) {
+ sprintf(filename, "%s.voc", gss->effects_filename);
+ file->open(filename);
+ if (file->isOpen()) {
+ _hasEffectsFile = true;
+ _effects = new VocSound(_mixer, file);
+ }
+ }
+ if (!_hasEffectsFile) {
+ sprintf(filename, "%s", gss->effects_filename);
+ file->open(filename);
+ if (file->isOpen()) {
+ _hasEffectsFile = true;
+ _effects = new VocSound(_mixer, file);
+ }
+ }
+}
+
+void Sound::readSfxFile(const char *filename) {
+ if (_hasEffectsFile)
+ return;
+
+ stopAll();
+
+ File *file = new File();
+ file->open(filename);
+
+ if (file->isOpen() == false) {
+ error("readSfxFile: Can't load sfx file %s", filename);
+ }
+
+ delete _effects;
+ if (_vm->getGameId() == GID_SIMON1CD32) {
+ _effects = new VocSound(_mixer, file, 0, SOUND_BIG_ENDIAN);
+ } else
+ _effects = new WavSound(_mixer, file);
+}
+
+void Sound::loadSfxTable(File *gameFile, uint32 base) {
+ stopAll();
+
+ if (_vm->getPlatform() == Common::kPlatformWindows)
+ _effects = new WavSound(_mixer, gameFile, base);
+ else
+ _effects = new VocSound(_mixer, gameFile, base);
+}
+
+void Sound::readVoiceFile(const char *filename) {
+ stopAll();
+
+ File *file = new File();
+ file->open(filename);
+
+ if (file->isOpen() == false)
+ error("readVoiceFile: Can't load voice file %s", filename);
+
+ delete _voice;
+ _voice = new RawSound(_mixer, file, 0, SOUND_BIG_ENDIAN);
+}
+
+void Sound::playVoice(uint sound) {
+ if (_filenums) {
+ if (_lastVoiceFile != _filenums[sound]) {
+ stopAll();
+
+ char filename[16];
+ _lastVoiceFile = _filenums[sound];
+ sprintf(filename, "voices%d.dat", _filenums[sound]);
+ File *file = new File();
+ file->open(filename);
+ if (file->isOpen() == false)
+ error("playVoice: Can't load voice file %s", filename);
+
+ delete _voice;
+ _voice = new WavSound(_mixer, file, _offsets);
+ }
+ }
+
+ if (!_voice)
+ return;
+
+ _mixer->stopHandle(_voiceHandle);
+ if (_vm->getGameType() == GType_PP) {
+ _voice->playSound(sound, &_voiceHandle, Audio::Mixer::FLAG_LOOP);
+ } else if (_vm->getGameType() == GType_FF || _vm->getGameId() == GID_SIMON1CD32) {
+ _voice->playSound(sound, &_voiceHandle, 0);
+ } else {
+ _voice->playSound(sound, &_voiceHandle, Audio::Mixer::FLAG_UNSIGNED);
+ }
+}
+
+void Sound::playEffects(uint sound) {
+ if (!_effects)
+ return;
+
+ if (_effectsPaused)
+ return;
+
+ _effects->playSound(sound, &_effectsHandle, (_vm->getGameId() == GID_SIMON1CD32) ? 0 : Audio::Mixer::FLAG_UNSIGNED);
+}
+
+void Sound::playAmbient(uint sound) {
+ if (!_effects)
+ return;
+
+ if (sound == _ambientPlaying)
+ return;
+
+ _ambientPlaying = sound;
+
+ if (_ambientPaused)
+ return;
+
+ _mixer->stopHandle(_ambientHandle);
+ _effects->playSound(sound, &_ambientHandle, Audio::Mixer::FLAG_LOOP|Audio::Mixer::FLAG_UNSIGNED);
+}
+
+bool Sound::hasVoice() const {
+ return _hasVoiceFile;
+}
+
+bool Sound::isVoiceActive() const {
+ return _mixer->isSoundHandleActive(_voiceHandle);
+}
+
+void Sound::stopAllSfx() {
+ _mixer->stopHandle(_ambientHandle);
+ _mixer->stopHandle(_effectsHandle);
+ _mixer->stopHandle(_sfx5Handle);
+ _ambientPlaying = 0;
+}
+
+void Sound::stopVoice() {
+ _mixer->stopHandle(_voiceHandle);
+}
+
+void Sound::stopAll() {
+ _mixer->stopAll();
+ _ambientPlaying = 0;
+}
+
+void Sound::effectsPause(bool b) {
+ _effectsPaused = b;
+ _sfx5Paused = b;
+}
+
+void Sound::ambientPause(bool b) {
+ _ambientPaused = b;
+
+ if (_ambientPaused && _ambientPlaying) {
+ _mixer->stopHandle(_ambientHandle);
+ } else if (_ambientPlaying) {
+ uint tmp = _ambientPlaying;
+ _ambientPlaying = 0;
+ playAmbient(tmp);
+ }
+}
+
+// Feeble Files specific
+void Sound::playAmbientData(byte *soundData, uint sound, uint pan, uint vol) {
+ if (sound == _ambientPlaying)
+ return;
+
+ _ambientPlaying = sound;
+
+ if (_ambientPaused)
+ return;
+
+ _mixer->stopHandle(_ambientHandle);
+ playSoundData(&_ambientHandle, soundData, sound, pan, vol, true);
+}
+
+void Sound::playSfxData(byte *soundData, uint sound, uint pan, uint vol) {
+ if (_effectsPaused)
+ return;
+
+ playSoundData(&_effectsHandle, soundData, sound, pan, vol, false);
+}
+
+void Sound::playSfx5Data(byte *soundData, uint sound, uint pan, uint vol) {
+ if (_sfx5Paused)
+ return;
+
+ _mixer->stopHandle(_sfx5Handle);
+ playSoundData(&_sfx5Handle, soundData, sound, pan, vol, true);
+}
+
+void Sound::playVoiceData(byte *soundData, uint sound) {
+ _mixer->stopHandle(_voiceHandle);
+ playSoundData(&_voiceHandle, soundData, sound);
+}
+
+void Sound::playSoundData(Audio::SoundHandle *handle, byte *soundData, uint sound, int pan, int vol, bool loop) {
+ byte *buffer, flags;
+ uint16 compType;
+ int blockAlign, rate;
+
+ int size = READ_LE_UINT32(soundData + 4);
+ Common::MemoryReadStream stream(soundData, size);
+ if (!Audio::loadWAVFromStream(stream, size, rate, flags, &compType, &blockAlign))
+ error("playSoundData: Not a valid WAV data");
+
+ // The Feeble Files originally used DirectSound, which specifies volume
+ // and panning differently than ScummVM does, using a logarithmic scale
+ // rather than a linear one.
+ //
+ // Volume is a value between -10,000 and 0.
+ // Panning is a value between -10,000 and 10,000.
+ //
+ // In both cases, the -10,000 represents -100 dB. When panning, only
+ // one speaker's volume is affected - just like in ScummVM - with
+ // negative values affecting the left speaker, and positive values
+ // affecting the right speaker. Thus -10,000 means the left speaker is
+ // silent.
+
+ int v, p;
+
+ vol = CLIP(vol, -10000, 0);
+ pan = CLIP(pan, -10000, 10000);
+
+ if (vol) {
+ v = (int)((double)Audio::Mixer::kMaxChannelVolume * pow(10.0, (double)vol / 2000.0) + 0.5);
+ } else {
+ v = Audio::Mixer::kMaxChannelVolume;
+ }
+
+ if (pan < 0) {
+ p = (int)(255.0 * pow(10.0, (double)pan / 2000.0) + 127.5);
+ } else if (pan > 0) {
+ p = (int)(255.0 * pow(10.0, (double)pan / -2000.0) - 127.5);
+ } else {
+ p = 0;
+ }
+
+ if (loop == true)
+ flags |= Audio::Mixer::FLAG_LOOP;
+
+ if (compType == 2) {
+ Audio::AudioStream *sndStream = Audio::makeADPCMStream(&stream, size, Audio::kADPCMMS, rate, (flags & Audio::Mixer::FLAG_STEREO) ? 2 : 1, blockAlign);
+ buffer = (byte *)malloc(size * 4);
+ size = sndStream->readBuffer((int16*)buffer, size * 2);
+ size *= 2; // 16bits.
+ delete sndStream;
+ } else {
+ buffer = (byte *)malloc(size);
+ memcpy(buffer, soundData + stream.pos(), size);
+ }
+
+ _mixer->playRaw(handle, buffer, size, rate, flags | Audio::Mixer::FLAG_AUTOFREE, -1, v, p);
+}
+
+void Sound::stopSfx5() {
+ _mixer->stopHandle(_sfx5Handle);
+}
+
+void Sound::switchVoiceFile(const GameSpecificSettings *gss, uint disc) {
+ if (_lastVoiceFile == disc)
+ return;
+
+ stopAll();
+ delete _voice;
+
+ _hasVoiceFile = false;
+ _lastVoiceFile = disc;
+
+ char filename[16];
+ File *file = new File();
+
+#ifdef USE_FLAC
+ if (!_hasVoiceFile) {
+ sprintf(filename, "%s%d.fla", gss->speech_filename, disc);
+ file->open(filename);
+ if (file->isOpen()) {
+ _hasVoiceFile = true;
+ _voice = new FlacSound(_mixer, file);
+ }
+ }
+#endif
+#ifdef USE_MAD
+ if (!_hasVoiceFile) {
+ sprintf(filename, "%s%d.mp3", gss->speech_filename, disc);
+ file->open(filename);
+ if (file->isOpen()) {
+ _hasVoiceFile = true;
+ _voice = new MP3Sound(_mixer, file);
+ }
+ }
+#endif
+#ifdef USE_VORBIS
+ if (!_hasVoiceFile) {
+ sprintf(filename, "%s%d.ogg", gss->speech_filename, disc);
+ file->open(filename);
+ if (file->isOpen()) {
+ _hasVoiceFile = true;
+ _voice = new VorbisSound(_mixer, file);
+ }
+ }
+#endif
+ if (!_hasVoiceFile) {
+ sprintf(filename, "%s%d.wav", gss->speech_filename, disc);
+ file->open(filename);
+ if (file->isOpen() == false) {
+ error("switchVoiceFile: Can't load voice file %s", filename);
+ }
+ _hasVoiceFile = true;
+ _voice = new WavSound(_mixer, file);
+ }
+}
+
+} // End of namespace Simon
diff --git a/engines/agos/sound.h b/engines/agos/sound.h
new file mode 100644
index 0000000000..ce7b655b90
--- /dev/null
+++ b/engines/agos/sound.h
@@ -0,0 +1,98 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-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 AGOS_SOUND_H
+#define AGOS_SOUND_H
+
+#include "sound/mixer.h"
+#include "agos/intern.h"
+#include "common/str.h"
+
+namespace Simon {
+
+class BaseSound;
+
+class SimonEngine;
+
+class Sound {
+private:
+ SimonEngine *_vm;
+
+ Audio::Mixer *_mixer;
+
+ BaseSound *_voice;
+ BaseSound *_effects;
+
+ bool _effectsPaused;
+ bool _ambientPaused;
+ bool _sfx5Paused;
+
+ uint16 *_filenums;
+ uint32 *_offsets;
+ uint16 _lastVoiceFile;
+
+ Audio::SoundHandle _voiceHandle;
+ Audio::SoundHandle _effectsHandle;
+ Audio::SoundHandle _ambientHandle;
+ Audio::SoundHandle _sfx5Handle;
+
+ bool _hasEffectsFile;
+ bool _hasVoiceFile;
+ uint _ambientPlaying;
+
+public:
+ Sound(SimonEngine *vm, const GameSpecificSettings *gss, Audio::Mixer *mixer);
+ ~Sound();
+
+ void loadVoiceFile(const GameSpecificSettings *gss);
+ void loadSfxFile(const GameSpecificSettings *gss);
+
+ void readSfxFile(const char *filename);
+ void loadSfxTable(Common::File *gameFile, uint32 base);
+ void readVoiceFile(const char *filename);
+
+ void playVoice(uint sound);
+ void playEffects(uint sound);
+ void playAmbient(uint sound);
+
+ // Feeble Files specific
+ void playAmbientData(byte *soundData, uint sound, uint pan, uint vol);
+ void playSfxData(byte *soundData, uint sound, uint pan, uint vol);
+ void playSfx5Data(byte *soundData, uint sound, uint pan, uint vol);
+ void playSoundData(Audio::SoundHandle *handle, byte *soundData, uint sound, int pan = 0, int vol = 0, bool loop = false);
+ void playVoiceData(byte *soundData, uint sound);
+ void switchVoiceFile(const GameSpecificSettings *gss, uint disc);
+
+ bool hasVoice() const;
+ bool isVoiceActive() const;
+ void stopAllSfx();
+ void stopSfx5();
+ void stopVoice();
+ void stopAll();
+ void effectsPause(bool b);
+ void ambientPause(bool b);
+};
+
+} // End of namespace Simon
+
+#endif
diff --git a/engines/agos/string.cpp b/engines/agos/string.cpp
new file mode 100644
index 0000000000..b85eb9a9dd
--- /dev/null
+++ b/engines/agos/string.cpp
@@ -0,0 +1,470 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-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 "agos/agos.h"
+#include "agos/intern.h"
+
+using Common::File;
+
+namespace Simon {
+
+const byte *SimonEngine::getStringPtrByID(uint stringId) {
+ const byte *string_ptr;
+ byte *dst;
+
+ _freeStringSlot ^= 1;
+
+ if (stringId < 0x8000) {
+ string_ptr = _stringTabPtr[stringId];
+ } else {
+ string_ptr = getLocalStringByID(stringId);
+ }
+
+ dst = _stringReturnBuffer[_freeStringSlot];
+ strcpy((char *)dst, (const char *)string_ptr);
+ return dst;
+}
+
+const byte *SimonEngine::getLocalStringByID(uint stringId) {
+ if (stringId < _stringIdLocalMin || stringId >= _stringIdLocalMax) {
+ loadTextIntoMem(stringId);
+ }
+ return _localStringtable[stringId - _stringIdLocalMin];
+}
+
+void SimonEngine::allocateStringTable(int num) {
+ _stringTabPtr = (byte **)calloc(num, sizeof(byte *));
+ _stringTabPos = 0;
+ _stringtab_numalloc = num;
+}
+
+void SimonEngine::setupStringTable(byte *mem, int num) {
+ int i = 0;
+ for (;;) {
+ _stringTabPtr[i++] = mem;
+ if (--num == 0)
+ break;
+ for (; *mem; mem++);
+ mem++;
+ }
+
+ _stringTabPos = i;
+}
+
+void SimonEngine::setupLocalStringTable(byte *mem, int num) {
+ int i = 0;
+ for (;;) {
+ _localStringtable[i++] = mem;
+ if (--num == 0)
+ break;
+ for (; *mem; mem++);
+ mem++;
+ }
+}
+
+uint SimonEngine::loadTextFile(const char *filename, byte *dst) {
+ if (getFeatures() & GF_OLD_BUNDLE)
+ return loadTextFile_simon1(filename, dst);
+ else
+ return loadTextFile_gme(filename, dst);
+}
+
+uint SimonEngine::loadTextFile_simon1(const char *filename, byte *dst) {
+ File fo;
+ fo.open(filename);
+ uint32 size;
+
+ if (fo.isOpen() == false)
+ error("loadTextFile: Can't open '%s'", filename);
+
+ size = fo.size();
+
+ if (fo.read(dst, size) != size)
+ error("loadTextFile: fread failed");
+ fo.close();
+
+ return size;
+}
+
+uint SimonEngine::loadTextFile_gme(const char *filename, byte *dst) {
+ uint res;
+ uint32 offs;
+ uint32 size;
+
+ res = atoi(filename + 4) + _textIndexBase - 1;
+ offs = _gameOffsetsPtr[res];
+ size = _gameOffsetsPtr[res + 1] - offs;
+
+ readGameFile(dst, offs, size);
+
+ return size;
+}
+
+void SimonEngine::loadTextIntoMem(uint stringId) {
+ byte *p;
+ char filename[30];
+ int i;
+ uint base_min = 0x8000, base_max, size;
+
+ _tablesHeapPtr = _tablesheapPtrNew;
+ _tablesHeapCurPos = _tablesHeapCurPosNew;
+
+ p = _strippedTxtMem;
+
+ // get filename
+ while (*p) {
+ for (i = 0; *p; p++, i++)
+ filename[i] = *p;
+ filename[i] = 0;
+ p++;
+
+ base_max = (p[0] * 256) | p[1];
+ p += 2;
+
+ if (stringId < base_max) {
+ _stringIdLocalMin = base_min;
+ _stringIdLocalMax = base_max;
+
+ _localStringtable = (byte **)_tablesHeapPtr;
+
+ size = (base_max - base_min + 1) * sizeof(byte *);
+ _tablesHeapPtr += size;
+ _tablesHeapCurPos += size;
+
+ size = loadTextFile(filename, _tablesHeapPtr);
+
+ setupLocalStringTable(_tablesHeapPtr, base_max - base_min + 1);
+
+ _tablesHeapPtr += size;
+ _tablesHeapCurPos += size;
+
+ if (_tablesHeapCurPos > _tablesHeapSize) {
+ error("loadTextIntoMem: Out of table memory");
+ }
+ return;
+ }
+
+ base_min = base_max;
+ }
+
+ error("loadTextIntoMem: didn't find %d", stringId);
+}
+
+static const byte charWidth[226] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 6, 2, 4, 8, 6,10, 9, 2,
+ 4, 4, 6, 6, 3, 4, 2, 3, 6, 4,
+ 6, 6, 7, 6, 6, 6, 6, 6, 2, 3,
+ 7, 7, 7, 6,11, 8, 7, 8, 8, 7,
+ 6, 9, 8, 2, 6, 7, 6,10, 8, 9,
+ 7, 9, 7, 7, 8, 8, 8,12, 8, 8,
+ 7, 3, 3, 3, 6, 8, 3, 7, 7, 6,
+ 7, 7, 4, 7, 6, 2, 3, 6, 2,10,
+ 6, 7, 7, 7, 5, 6, 4, 7, 7,10,
+ 6, 6, 6, 0, 0, 0, 0, 0, 8, 6,
+ 7, 7, 7, 7, 7, 6, 7, 7, 7, 4,
+ 4, 3, 8, 8, 7, 0, 0, 7, 7, 7,
+ 6, 6, 6, 9, 8, 0, 0, 0, 0, 0,
+ 7, 3, 7, 6, 6, 8, 0, 6, 0, 0,
+ 0, 0, 0, 2, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 7
+};
+
+const char *getPixelLength(const char *string, uint16 maxWidth, uint16 &pixels) {
+ pixels = 0;
+
+ while (*string != 0) {
+ byte chr = *string;
+ if ((pixels + charWidth[chr]) > maxWidth)
+ break;
+ pixels += charWidth[chr];
+ string++;
+ }
+
+ return string;
+}
+
+bool SimonEngine::printTextOf(uint a, uint x, uint y) {
+ const byte *stringPtr;
+ uint16 pixels, w;
+
+ if (getGameType() == GType_SIMON2) {
+ if (getBitFlag(79)) {
+ Subroutine *sub;
+ _variableArray[84] = a;
+ sub = getSubroutineByID(5003);
+ if (sub != NULL)
+ startSubroutineEx(sub);
+ return true;
+ }
+ }
+
+ if (a >= _numTextBoxes)
+ return false;
+
+
+ stringPtr = getStringPtrByID(_shortText[a]);
+ if (getGameType() == GType_FF) {
+ getPixelLength((const char *)stringPtr, 400, pixels);
+ w = pixels + 1;
+ x -= w / 2;
+ printScreenText(6, 0, (const char *)stringPtr, x, y, w);
+ } else {
+ showActionString(stringPtr);
+ }
+
+ return true;
+}
+
+bool SimonEngine::printNameOf(Item *item, uint x, uint y) {
+ SubObject *subObject;
+ const byte *stringPtr;
+ uint16 pixels, w;
+
+ if (item == 0 || item == _dummyItem2 || item == _dummyItem3)
+ return false;
+
+ subObject = (SubObject *)findChildOfType(item, 2);
+ if (subObject == NULL)
+ return false;
+
+ stringPtr = getStringPtrByID(subObject->objectName);
+ if (getGameType() == GType_FF) {
+ getPixelLength((const char *)stringPtr, 400, pixels);
+ w = pixels + 1;
+ x -= w / 2;
+ printScreenText(6, 0, (const char *)stringPtr, x, y, w);
+ } else {
+ showActionString(stringPtr);
+ }
+
+ return true;
+}
+
+void SimonEngine::printInteractText(uint16 num, const char *string) {
+ char convertedString[320];
+ char *convertedString2 = convertedString;
+ const char *string2 = string;
+ uint16 height = 15;
+ uint16 w = 0xFFFF;
+ uint16 b, pixels, x;
+
+ // It doesn't really matter what 'w' is to begin with, as long as it's
+ // something that cannot be generated by getPixelLength(). The original
+ // used 620, which was a potential problem.
+
+ while (1) {
+ string2 = getPixelLength(string, 620, pixels);
+ if (*string2 == 0x00) {
+ if (w == 0xFFFF)
+ w = pixels;
+ strcpy(convertedString2, string);
+ break;
+ }
+ while (*string2 != ' ') {
+ byte chr = *string2;
+ pixels -= charWidth[chr];
+ string2--;
+ }
+ if (w == 0xFFFF)
+ w = pixels;
+ b = string2 - string;
+ strncpy(convertedString2, string, b);
+ convertedString2 += b;
+ *convertedString2++ = '\n';
+ height += 15;
+ string = string2;
+ }
+
+ // ScrollX
+ x = _variableArray[251];
+ x += 20;
+
+ if (num == 1)
+ _interactY = 385;
+
+ // Returned values for box definition
+ _variableArray[51] = x;
+ _variableArray[52] = _interactY;
+ _variableArray[53] = w;
+ _variableArray[54] = height;
+
+ stopAnimateSimon2(2, num + 6);
+ renderString(num, 0, w, height, convertedString);
+ loadSprite(4, 2, num + 6, x, _interactY, 12);
+
+ _interactY += height;
+}
+
+void SimonEngine::sendInteractText(uint16 num, const char *fmt, ...) {
+ va_list arglist;
+ char string[256];
+
+ va_start(arglist, fmt);
+ vsprintf(string, fmt, arglist);
+ va_end(arglist);
+
+ printInteractText(num, string);
+}
+
+void SimonEngine::printScreenText(uint vgaSpriteId, uint color, const char *string, int16 x, int16 y, int16 width) {
+ char convertedString[320];
+ char *convertedString2 = convertedString;
+ const char *string2 = string;
+ int16 height, talkDelay;
+ int stringLength = strlen(string);
+ int padding, lettersPerRow, lettersPerRowJustified;
+ const int textHeight = (getGameType() == GType_FF) ? 15: 10;
+
+ height = textHeight;
+ lettersPerRow = width / 6;
+ lettersPerRowJustified = stringLength / (stringLength / lettersPerRow + 1) + 1;
+
+ talkDelay = (stringLength + 3) / 3;
+ if ((getGameType() == GType_SIMON1) && (getFeatures() & GF_TALKIE)) {
+ if (_variableArray[141] == 0)
+ _variableArray[141] = 9;
+ _variableArray[85] = _variableArray[141] * talkDelay;
+ } else {
+ if (_variableArray[86] == 0)
+ talkDelay /= 2;
+ if (_variableArray[86] == 2)
+ talkDelay *= 2;
+ _variableArray[85] = talkDelay * 5;
+ }
+
+ assert(stringLength > 0);
+
+ if (getGameType() == GType_FF) {
+ uint16 b, pixels, spaces;
+
+ while (1) {
+ string2 = getPixelLength(string, width, pixels);
+ if (*string2 == 0) {
+ spaces = (width - pixels) / 12;
+ if (spaces != 0)
+ spaces--;
+ while (spaces) {
+ *convertedString2++ = ' ';
+ spaces--;
+ }
+ strcpy(convertedString2, string);
+ break;
+ }
+ while (*string2 != ' ') {
+ byte chr = *string2;
+ pixels -= charWidth[chr];
+ string2--;
+ }
+ spaces = (width - pixels) / 12;
+ if (spaces != 0)
+ spaces--;
+ while (spaces) {
+ *convertedString2++ = ' ';
+ spaces--;
+ }
+ b = string2 - string;
+ strncpy(convertedString2, string, b);
+ convertedString2 += b;
+ *convertedString2++ = '\n';
+ height += textHeight;
+ y -= textHeight;
+ if (y < 2)
+ y = 2;
+ string = string2;
+ }
+ } else {
+ while (stringLength > 0) {
+ int pos = 0;
+ if (stringLength > lettersPerRow) {
+ int removeLastWord = 0;
+ if (lettersPerRow > lettersPerRowJustified) {
+ pos = lettersPerRowJustified;
+ while (string[pos] != ' ')
+ pos++;
+ if (pos > lettersPerRow)
+ removeLastWord = 1;
+ }
+ if (lettersPerRow <= lettersPerRowJustified || removeLastWord) {
+ pos = lettersPerRow;
+ while (string[pos] != ' ' && pos > 0)
+ pos--;
+ }
+ height += textHeight;
+ y -= textHeight;
+ } else
+ pos = stringLength;
+ padding = (lettersPerRow - pos) % 2 ?
+ (lettersPerRow - pos) / 2 + 1 : (lettersPerRow - pos) / 2;
+ while (padding--)
+ *convertedString2++ = ' ';
+ stringLength -= pos;
+ while (pos--)
+ *convertedString2++ = *string++;
+ *convertedString2++ = '\n';
+ string++; // skip space
+ stringLength--; // skip space
+ }
+ *(convertedString2 - 1) = '\0';
+ }
+
+ if (getGameType() == GType_SIMON1)
+ stopAnimateSimon1(vgaSpriteId + 199);
+ else
+ stopAnimateSimon2(2, vgaSpriteId);
+
+ if (getGameType() == GType_FF) {
+ renderString(1, color, width, height, convertedString);
+ } else {
+ color = color * 3 + 192;
+ if (getPlatform() == Common::kPlatformAmiga)
+ renderStringAmiga(vgaSpriteId, color, width, height, convertedString);
+ else
+ renderString(vgaSpriteId, color, width, height, convertedString);
+ }
+
+ int b = 4;
+ if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) {
+ if (!getBitFlag(133))
+ b = 3;
+
+ x /= 8;
+ if (y < 2)
+ y = 2;
+ }
+
+ if (getGameType() == GType_SIMON1)
+ loadSprite(b, 2, vgaSpriteId + 199, x, y, 12);
+ else
+ loadSprite(b, 2, vgaSpriteId, x, y, 12);
+}
+
+} // End of namespace Simon
diff --git a/engines/agos/subroutine.cpp b/engines/agos/subroutine.cpp
new file mode 100644
index 0000000000..b5a7c1f9f7
--- /dev/null
+++ b/engines/agos/subroutine.cpp
@@ -0,0 +1,479 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-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 "agos/agos.h"
+#include "agos/intern.h"
+
+using Common::File;
+
+namespace Simon {
+
+Subroutine *SimonEngine::getSubroutineByID(uint subroutine_id) {
+ Subroutine *cur;
+
+ _subroutine = subroutine_id;
+
+ for (cur = _subroutineList; cur; cur = cur->next) {
+ if (cur->id == subroutine_id)
+ return cur;
+ }
+
+ if (loadXTablesIntoMem(subroutine_id)) {
+ for (cur = _subroutineList; cur; cur = cur->next) {
+ if (cur->id == subroutine_id)
+ return cur;
+ }
+ }
+
+ if (loadTablesIntoMem(subroutine_id)) {
+ for (cur = _subroutineList; cur; cur = cur->next) {
+ if (cur->id == subroutine_id)
+ return cur;
+ }
+ }
+
+ if (subroutine_id != 160)
+ debug(0,"getSubroutineByID: subroutine %d not found", subroutine_id);
+ return NULL;
+}
+
+void SimonEngine::alignTableMem() {
+ if ((unsigned long)_tablesHeapPtr & 3) {
+ _tablesHeapPtr += 2;
+ _tablesHeapCurPos += 2;
+ }
+}
+
+byte *SimonEngine::allocateTable(uint size) {
+ byte *org = _tablesHeapPtr;
+
+ size = (size + 1) & ~1;
+
+ _tablesHeapPtr += size;
+ _tablesHeapCurPos += size;
+
+ if (_tablesHeapCurPos > _tablesHeapSize)
+ error("Tablesheap overflow");
+
+ return org;
+}
+
+File *SimonEngine::openTablesFile(const char *filename) {
+ if (getFeatures() & GF_OLD_BUNDLE)
+ return openTablesFile_simon1(filename);
+ else
+ return openTablesFile_gme(filename);
+}
+
+File *SimonEngine::openTablesFile_simon1(const char *filename) {
+ File *fo = new File();
+ fo->open(filename);
+ if (fo->isOpen() == false)
+ error("openTablesFile: Can't open '%s'", filename);
+ return fo;
+}
+
+File *SimonEngine::openTablesFile_gme(const char *filename) {
+ uint res;
+ uint32 offs;
+
+ res = atoi(filename + 6) + _tableIndexBase - 1;
+ offs = _gameOffsetsPtr[res];
+
+ _gameFile->seek(offs, SEEK_SET);
+ return _gameFile;
+}
+
+bool SimonEngine::loadTablesIntoMem(uint subr_id) {
+ if (getGameType() == GType_ELVIRA || getGameType() == GType_ELVIRA2)
+ return loadTablesOldIntoMem(subr_id);
+ else
+ return loadTablesNewIntoMem(subr_id);
+}
+
+
+bool SimonEngine::loadTablesOldIntoMem(uint subr_id) {
+ byte *p;
+ uint16 min_num, max_num, file_num;
+ File *in;
+ char filename[30];
+
+ if (_tblList == NULL)
+ return 0;
+
+ p = _tblList + 32;
+
+ min_num = READ_BE_UINT16(p);
+ max_num = READ_BE_UINT16(p + 2);
+ file_num = *(p + 4);
+ p += 6;
+
+ while (min_num) {
+ if ((subr_id >= min_num) && (subr_id <= max_num)) {
+ _subroutineList = _subroutineListOrg;
+ _tablesHeapPtr = _tablesHeapPtrOrg;
+ _tablesHeapCurPos = _tablesHeapCurPosOrg;
+ _stringIdLocalMin = 1;
+ _stringIdLocalMax = 0;
+
+ sprintf(filename, "TABLES%.2d", file_num);
+ in = openTablesFile(filename);
+ readSubroutineBlock(in);
+ closeTablesFile(in);
+
+ alignTableMem();
+
+ _tablesheapPtrNew = _tablesHeapPtr;
+ _tablesHeapCurPosNew = _tablesHeapCurPos;
+
+ if (_tablesHeapCurPos > _tablesHeapSize)
+ error("loadTablesOldIntoMem: Out of table memory");
+ return 1;
+ }
+
+ min_num = READ_BE_UINT16(p);
+ max_num = READ_BE_UINT16(p + 2);
+ file_num = *(p + 4);
+ p += 6;
+ }
+
+ debug(1,"loadTablesOldIntoMem: didn't find %d", subr_id);
+ return 0;
+}
+
+bool SimonEngine::loadTablesNewIntoMem(uint subr_id) {
+ byte *p;
+ int i;
+ uint min_num, max_num;
+ char filename[30];
+ File *in;
+
+ p = _tblList;
+ if (p == NULL)
+ return 0;
+
+ while (*p) {
+ for (i = 0; *p; p++, i++)
+ filename[i] = *p;
+ filename[i] = 0;
+ p++;
+
+ for (;;) {
+ min_num = READ_BE_UINT16(p); p += 2;
+ if (min_num == 0)
+ break;
+
+ max_num = READ_BE_UINT16(p); p += 2;
+
+ if (subr_id >= min_num && subr_id <= max_num) {
+ _subroutineList = _subroutineListOrg;
+ _tablesHeapPtr = _tablesHeapPtrOrg;
+ _tablesHeapCurPos = _tablesHeapCurPosOrg;
+ _stringIdLocalMin = 1;
+ _stringIdLocalMax = 0;
+
+ in = openTablesFile(filename);
+ readSubroutineBlock(in);
+ closeTablesFile(in);
+ if (getGameType() == GType_SIMON2) {
+ _sound->loadSfxTable(_gameFile, _gameOffsetsPtr[atoi(filename + 6) - 1 + _soundIndexBase]);
+ } else if (getGameType() == GType_SIMON1 && getPlatform() == Common::kPlatformWindows) {
+ memcpy(filename, "SFXXXX", 6);
+ if (atoi(filename + 6) != 1 && atoi(filename + 6) != 30)
+ _sound->readSfxFile(filename);
+ }
+
+ alignTableMem();
+
+ _tablesheapPtrNew = _tablesHeapPtr;
+ _tablesHeapCurPosNew = _tablesHeapCurPos;
+
+ if (_tablesHeapCurPos > _tablesHeapSize)
+ error("loadTablesNewIntoMem: Out of table memory");
+ return 1;
+ }
+ }
+ }
+
+ debug(1,"loadTablesNewIntoMem: didn't find %d", subr_id);
+ return 0;
+}
+
+bool SimonEngine::loadXTablesIntoMem(uint subr_id) {
+ byte *p;
+ int i;
+ uint min_num, max_num;
+ char filename[30];
+ File *in;
+
+ p = _xtblList;
+ if (p == NULL)
+ return 0;
+
+ while (*p) {
+ for (i = 0; *p; p++, i++)
+ filename[i] = *p;
+ filename[i] = 0;
+ p++;
+
+ for (;;) {
+ min_num = READ_BE_UINT16(p);
+ p += 2;
+
+ if (min_num == 0)
+ break;
+
+ max_num = READ_BE_UINT16(p);
+ p += 2;
+
+ if (subr_id >= min_num && subr_id <= max_num) {
+ _subroutineList = _xsubroutineListOrg;
+ _tablesHeapPtr = _xtablesHeapPtrOrg;
+ _tablesHeapCurPos = _xtablesHeapCurPosOrg;
+ _stringIdLocalMin = 1;
+ _stringIdLocalMax = 0;
+
+ in = openTablesFile(filename);
+ readSubroutineBlock(in);
+ closeTablesFile(in);
+
+ alignTableMem();
+
+ _subroutineListOrg = _subroutineList;
+ _tablesHeapPtrOrg = _tablesHeapPtr;
+ _tablesHeapCurPosOrg = _tablesHeapCurPos;
+ _tablesheapPtrNew = _tablesHeapPtr;
+ _tablesHeapCurPosNew = _tablesHeapCurPos;
+
+ return 1;
+ }
+ }
+ }
+
+ debug(1,"loadXTablesIntoMem: didn't find %d", subr_id);
+ return 0;
+}
+
+void SimonEngine::closeTablesFile(File *in) {
+ if (getFeatures() & GF_OLD_BUNDLE) {
+ in->close();
+ delete in;
+ }
+}
+
+Subroutine *SimonEngine::createSubroutine(uint id) {
+ Subroutine *sub;
+
+ alignTableMem();
+
+ sub = (Subroutine *)allocateTable(sizeof(Subroutine));
+ sub->id = id;
+ sub->first = 0;
+ sub->next = _subroutineList;
+ _subroutineList = sub;
+ return sub;
+}
+
+SubroutineLine *SimonEngine::createSubroutineLine(Subroutine *sub, int where) {
+ SubroutineLine *sl, *cur_sl = NULL, *last_sl = NULL;
+
+ if (sub->id == 0)
+ sl = (SubroutineLine *)allocateTable(SUBROUTINE_LINE_BIG_SIZE);
+ else
+ sl = (SubroutineLine *)allocateTable(SUBROUTINE_LINE_SMALL_SIZE);
+
+ // where is what offset to insert the line at, locate the proper beginning line
+ if (sub->first != 0) {
+ cur_sl = (SubroutineLine *)((byte *)sub + sub->first);
+ while (where) {
+ last_sl = cur_sl;
+ cur_sl = (SubroutineLine *)((byte *)sub + cur_sl->next);
+ if ((byte *)cur_sl == (byte *)sub)
+ break;
+ where--;
+ }
+ }
+
+ if (last_sl != NULL) {
+ // Insert the subroutine line in the middle of the link
+ last_sl->next = (byte *)sl - (byte *)sub;
+ sl->next = (byte *)cur_sl - (byte *)sub;
+ } else {
+ // Insert the subroutine line at the head of the link
+ sl->next = sub->first;
+ sub->first = (byte *)sl - (byte *)sub;
+ }
+
+ return sl;
+}
+
+void SimonEngine::runSubroutine101() {
+ Subroutine *sub;
+
+ sub = getSubroutineByID(101);
+ if (sub != NULL)
+ startSubroutineEx(sub);
+
+ permitInput();
+}
+
+int SimonEngine::startSubroutine(Subroutine *sub) {
+ int result = -1;
+ SubroutineLine *sl;
+ const byte *old_code_ptr;
+
+ if (_startMainScript)
+ dumpSubroutine(sub);
+
+ old_code_ptr = _codePtr;
+
+ if (++_recursionDepth > 40)
+ error("Recursion error");
+
+ // WORKAROUND: Bit Flag 171 isn't set when Simon rides the lion to the
+ // goblin camp in non-English versions. Bit Flag 171 is required to display
+ // the red trail between locations on the map, during the ride.
+ if (getGameType() == GType_SIMON2) {
+ if (sub->id == 13020)
+ setBitFlag(171, true);
+ if (sub->id == 13021)
+ setBitFlag(171, false);
+ }
+
+ sl = (SubroutineLine *)((byte *)sub + sub->first);
+
+ while ((byte *)sl != (byte *)sub) {
+ if (checkIfToRunSubroutineLine(sl, sub)) {
+ result = 0;
+ _codePtr = (byte *)sl;
+ if (sub->id)
+ _codePtr += 2;
+ else
+ _codePtr += 8;
+
+ if (_continousMainScript)
+ printf("; %d\n", sub->id);
+ result = runScript();
+ if (result != 0) {
+ /* result -10 means restart subroutine */
+ if (result == -10) {
+ delay(0); /* maybe leave control to the VGA */
+ sl = (SubroutineLine *)((byte *)sub + sub->first);
+ continue;
+ }
+ break;
+ }
+ }
+ sl = (SubroutineLine *)((byte *)sub + sl->next);
+ }
+
+ _codePtr = old_code_ptr;
+
+ _recursionDepth--;
+ return result;
+}
+
+int SimonEngine::startSubroutineEx(Subroutine *sub) {
+ return startSubroutine(sub);
+}
+
+bool SimonEngine::checkIfToRunSubroutineLine(SubroutineLine *sl, Subroutine *sub) {
+ if (sub->id)
+ return true;
+
+ if (sl->verb != -1 && sl->verb != _scriptVerb &&
+ (sl->verb != -2 || _scriptVerb != -1))
+ return false;
+
+ if (sl->noun1 != -1 && sl->noun1 != _scriptNoun1 &&
+ (sl->noun1 != -2 || _scriptNoun1 != -1))
+ return false;
+
+ if (sl->noun2 != -1 && sl->noun2 != _scriptNoun2 &&
+ (sl->noun2 != -2 || _scriptNoun2 != -1))
+ return false;
+
+ return true;
+}
+
+void SimonEngine::readSubroutine(File *in, Subroutine *sub) {
+ while (in->readUint16BE() == 0) {
+ readSubroutineLine(in, createSubroutineLine(sub, 0xFFFF), sub);
+ }
+}
+
+void SimonEngine::readSubroutineLine(File *in, SubroutineLine *sl, Subroutine *sub) {
+ byte line_buffer[2048], *q = line_buffer;
+ int size;
+
+ if (sub->id == 0) {
+ sl->verb = in->readUint16BE();
+ sl->noun1 = in->readUint16BE();
+ sl->noun2 = in->readUint16BE();
+ } else if (getGameType() == GType_ELVIRA || getGameType() == GType_ELVIRA2) {
+ in->readUint16BE();
+ in->readUint16BE();
+ in->readUint16BE();
+ }
+
+ if (getGameType() == GType_ELVIRA || getGameType() == GType_ELVIRA2) {
+ int16 tmp;
+
+ tmp = in->readUint16BE();
+ WRITE_BE_UINT16(q, tmp);
+ while (tmp != 10000) {
+ if (READ_BE_UINT16(q) == 0xC6) {
+ in->readUint16BE();
+ } else {
+ q = readSingleOpcode(in, q);
+ }
+
+ tmp = in->readUint16BE();
+ WRITE_BE_UINT16(q, tmp);
+ }
+
+ size = (q - line_buffer + 1) * 2;
+ memcpy(allocateTable(size), line_buffer, size);
+ } else {
+ while ((*q = in->readByte()) != 0xFF) {
+ if (*q == 87) {
+ in->readUint16BE();
+ } else {
+ q = readSingleOpcode(in, q);
+ }
+ }
+
+ size = (q - line_buffer + 1);
+ memcpy(allocateTable(size), line_buffer, size);
+ }
+}
+
+void SimonEngine::readSubroutineBlock(File *in) {
+ while (in->readUint16BE() == 0) {
+ readSubroutine(in, createSubroutine(in->readUint16BE()));
+ }
+}
+
+} // End of namespace Simon
diff --git a/engines/agos/verb.cpp b/engines/agos/verb.cpp
new file mode 100644
index 0000000000..014ca36df7
--- /dev/null
+++ b/engines/agos/verb.cpp
@@ -0,0 +1,906 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-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$
+ *
+ */
+
+// Verb and hitarea handling
+#include "common/stdafx.h"
+
+#include "agos/agos.h"
+#include "agos/intern.h"
+
+namespace Simon {
+
+static const char *const russian_verb_names[] = {
+ "Ietj _",
+ "Qnotrft< pa",
+ "Nt_r[t<",
+ "Ecjdat<",
+ "Q=fst<",
+ "C^]t<",
+ "Ha_r[t<",
+ "Isqom<^ocat<",
+ "Docorjt<",
+ "Qp]t<",
+ "Neft<",
+ "Eat<"
+};
+
+static const char *const hebrew_verb_names[] = {
+ "LJ @L",
+ "DQZKL RL",
+ "TZG",
+ "DFF",
+ "@KEL",
+ "DXM",
+ "QBEX",
+ "DYZNY",
+ "CAX @L",
+ "DQX",
+ "LAY",
+ "ZO"
+};
+
+static const char *const spanish_verb_names[] = {
+ "Caminar",
+ "Mirar",
+ "Abrir",
+ "Mover",
+ "Consumir",
+ "Coger",
+ "Cerrar",
+ "Usar",
+ "Hablar",
+ "Quitar",
+ "Llevar",
+ "Dar"
+};
+
+static const char *const italian_verb_names[] = {
+ "Vai verso",
+ "Osserva",
+ "Apri",
+ "Sposta",
+ "Mangia",
+ "Raccogli",
+ "Chiudi",
+ "Usa",
+ "Parla a",
+ "Togli",
+ "Indossa",
+ "Dai"
+};
+
+static const char *const french_verb_names[] = {
+ "Aller vers",
+ "Regarder",
+ "Ouvrir",
+ "D/placer",
+ "Consommer",
+ "Prendre",
+ "Fermer",
+ "Utiliser",
+ "Parler ;",
+ "Enlever",
+ "Mettre",
+ "Donner"
+};
+
+static const char *const german_verb_names[] = {
+ "Gehe zu",
+ "Schau an",
+ ";ffne",
+ "Bewege",
+ "Verzehre",
+ "Nimm",
+ "Schlie+e",
+ "Benutze",
+ "Rede mit",
+ "Entferne",
+ "Trage",
+ "Gib"
+};
+
+static const char *const english_verb_names[] = {
+ "Walk to",
+ "Look at",
+ "Open",
+ "Move",
+ "Consume",
+ "Pick up",
+ "Close",
+ "Use",
+ "Talk to",
+ "Remove",
+ "Wear",
+ "Give"
+};
+
+static const char *const russian_verb_prep_names[] = {
+ "", "", "", "",
+ "", "", "", "s yfn?",
+ "", "", "", "_onu ?"
+};
+
+static const char *const hebrew_verb_prep_names[] = {
+ "", "", "", "",
+ "", "", "", "RM ND ?",
+ "", "", "", "LNI ?"
+};
+
+static const char *const spanish_verb_prep_names[] = {
+ "", "", "", "",
+ "", "", "", "^con qu/?",
+ "", "", "", "^a qui/n?"
+};
+
+static const char *const italian_verb_prep_names[] = {
+ "", "", "", "",
+ "", "", "", "con cosa ?",
+ "", "", "", "a chi ?"
+};
+
+static const char *const french_verb_prep_names[] = {
+ "", "", "", "",
+ "", "", "", "avec quoi ?",
+ "", "", "", "; qui ?"
+};
+
+static const char *const german_verb_prep_names[] = {
+ "", "", "", "",
+ "", "", "", "mit was ?",
+ "", "", "", "zu wem ?"
+};
+
+static const char *const english_verb_prep_names[] = {
+ "", "", "", "",
+ "", "", "", "with what ?",
+ "", "", "", "to whom ?"
+};
+
+void SimonEngine::clearName() {
+ HitArea *last;
+ HitArea *ha;
+
+ if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ stopAnimateSimon2(2, 6);
+ _lastNameOn = NULL;
+ _animatePointer = 0;
+ _mouseAnim = 1;
+ return;
+ }
+
+ if (getGameType() == GType_SIMON2) {
+ if (getBitFlag(79)) {
+ sendSync(202);
+ _lastNameOn = NULL;
+ return;
+ }
+ }
+
+ last = _currentVerbBox;
+
+ if (last == _lastVerbOn)
+ return;
+
+ resetNameWindow();
+ _lastVerbOn = last;
+
+ if (last != NULL && (ha = findBox(200)) && (ha->flags & kBFBoxDead) && !(last->flags & kBFBoxDead))
+ printVerbOf(last->id);
+}
+
+void SimonEngine::printVerbOf(uint hitarea_id) {
+ const char *txt;
+ const char * const *verb_names;
+ const char * const *verb_prep_names;
+
+ hitarea_id -= 101;
+
+ if (_showPreposition) {
+ switch (_language) {
+ case Common::RU_RUS:
+ verb_prep_names = russian_verb_prep_names;
+ break;
+ case Common::HB_ISR:
+ verb_prep_names = hebrew_verb_prep_names;
+ break;
+ case Common::ES_ESP:
+ verb_prep_names = spanish_verb_prep_names;
+ break;
+ case Common::IT_ITA:
+ verb_prep_names = italian_verb_prep_names;
+ break;
+ case Common::FR_FRA:
+ verb_prep_names = french_verb_prep_names;
+ break;
+ case Common::DE_DEU:
+ verb_prep_names = german_verb_prep_names;
+ break;
+ default:
+ verb_prep_names = english_verb_prep_names;
+ break;
+ }
+ CHECK_BOUNDS(hitarea_id, english_verb_prep_names);
+ txt = verb_prep_names[hitarea_id];
+ } else {
+ switch (_language) {
+ case Common::RU_RUS:
+ verb_names = russian_verb_names;
+ break;
+ case Common::HB_ISR:
+ verb_names = hebrew_verb_names;
+ break;
+ case Common::ES_ESP:
+ verb_names = spanish_verb_names;
+ break;
+ case Common::IT_ITA:
+ verb_names = italian_verb_names;
+ break;
+ case Common::FR_FRA:
+ verb_names = french_verb_names;
+ break;
+ case Common::DE_DEU:
+ verb_names = german_verb_names;
+ break;
+ default:
+ verb_names = english_verb_names;
+ break;
+ }
+ CHECK_BOUNDS(hitarea_id, english_verb_names);
+ txt = verb_names[hitarea_id];
+ }
+ showActionString((const byte *)txt);
+}
+
+void SimonEngine::showActionString(const byte *string) {
+ WindowBlock *window;
+ uint x;
+
+ window = _windowArray[1];
+ if (window == NULL || window->text_color == 0)
+ return;
+
+ // Arisme : hack for long strings in the French version
+ if ((strlen((const char*)string) - 1) <= 53)
+ x = (53 - (strlen((const char *)string) - 1)) * 3;
+ else
+ x = 0;
+
+ window->textColumn = x / 8;
+ window->textColumnOffset = x & 7;
+
+ for (; *string; string++)
+ windowPutChar(window, *string);
+}
+
+void SimonEngine::handleVerbClicked(uint verb) {
+ Subroutine *sub;
+ int result;
+
+ _objectItem = _hitAreaObjectItem;
+ if (_objectItem == _dummyItem2) {
+ _objectItem = me();
+ }
+ if (_objectItem == _dummyItem3) {
+ _objectItem = derefItem(me()->parent);
+ }
+
+ _subjectItem = _hitAreaSubjectItem;
+ if (_subjectItem == _dummyItem2) {
+ _subjectItem = me();
+ }
+ if (_subjectItem == _dummyItem3) {
+ _subjectItem = derefItem(me()->parent);
+ }
+
+ if (_subjectItem) {
+ _scriptNoun1 = _subjectItem->noun;
+ _scriptAdj1 = _subjectItem->adjective;
+ } else {
+ _scriptNoun1 = -1;
+ _scriptAdj1 = -1;
+ }
+
+ if (_objectItem) {
+ _scriptNoun2 = _objectItem->noun;
+ _scriptAdj2 = _objectItem->adjective;
+ } else {
+ _scriptNoun2 = -1;
+ _scriptAdj2 = -1;
+ }
+
+ _scriptVerb = _verbHitArea;
+
+ sub = getSubroutineByID(0);
+ if (sub == NULL)
+ return;
+
+ result = startSubroutine(sub);
+ if (result == -1)
+ showMessageFormat("I don't understand");
+
+ _runScriptReturn1 = false;
+
+ sub = getSubroutineByID(100);
+ if (sub)
+ startSubroutine(sub);
+
+ if (getGameType() == GType_SIMON2 || getGameType() == GType_FF || getGameType() == GType_PP)
+ _runScriptReturn1 = false;
+
+ permitInput();
+}
+
+void SimonEngine::resetNameWindow() {
+ WindowBlock *window;
+
+ if (getGameType() == GType_SIMON2 && getBitFlag(79))
+ return;
+
+ window = _windowArray[1];
+ if (window != NULL && window->text_color != 0)
+ clearWindow(window);
+
+ _lastNameOn = NULL;
+ _lastVerbOn = NULL;
+}
+
+HitArea *SimonEngine::findBox(uint hitarea_id) {
+ HitArea *ha = _hitAreas;
+ uint count = ARRAYSIZE(_hitAreas);
+
+ do {
+ if (ha->id == hitarea_id && ha->flags != 0)
+ return ha;
+ } while (ha++, --count);
+ return NULL;
+}
+
+HitArea *SimonEngine::findEmptyHitArea() {
+ HitArea *ha = _hitAreas;
+ uint count = ARRAYSIZE(_hitAreas);
+
+ do {
+ if (ha->flags == 0)
+ return ha;
+ } while (ha++, --count);
+ return NULL;
+}
+
+void SimonEngine::delete_hitarea_by_index(uint index) {
+ CHECK_BOUNDS(index, _hitAreas);
+ _hitAreas[index].flags = 0;
+}
+
+void SimonEngine::enableBox(uint hitarea) {
+ HitArea *ha = findBox(hitarea);
+ if (ha != NULL)
+ ha->flags &= ~kBFBoxDead;
+}
+
+void SimonEngine::disableBox(uint hitarea) {
+ HitArea *ha = findBox(hitarea);
+ if (ha != NULL) {
+ ha->flags |= kBFBoxDead;
+ ha->flags &= ~kBFBoxSelected;
+ if (hitarea == 102)
+ resetVerbs();
+ }
+}
+
+void SimonEngine::moveBox(uint hitarea, int x, int y) {
+ HitArea *ha = findBox(hitarea);
+ if (ha != NULL) {
+ if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ ha->x += x;
+ ha->y += y;
+ } else {
+ ha->x = x;
+ ha->y = y;
+ }
+ }
+}
+
+void SimonEngine::undefineBox(uint hitarea) {
+ HitArea *ha = findBox(hitarea);
+ if (ha != NULL) {
+ ha->flags = 0;
+ if (ha == _lastNameOn)
+ clearName();
+ _needHitAreaRecalc++;
+ }
+}
+
+bool SimonEngine::isBoxDead(uint hitarea) {
+ HitArea *ha = findBox(hitarea);
+ if (ha == NULL)
+ return false;
+ return (ha->flags & kBFBoxDead) == 0;
+}
+
+void SimonEngine::defineBox(int id, int x, int y, int width, int height, int flags, int verb, Item *item_ptr) {
+ HitArea *ha;
+ undefineBox(id);
+
+ ha = findEmptyHitArea();
+ ha->x = x;
+ ha->y = y;
+ ha->width = width;
+ ha->height = height;
+ ha->flags = flags | kBFBoxInUse;
+ ha->id = ha->priority = id;
+ ha->verb = verb;
+ ha->item_ptr = item_ptr;
+
+ if ((getGameType() == GType_FF || getGameType() == GType_PP) &&
+ (ha->flags & kBFHyperBox)) {
+ ha->data = _hyperLink;
+ ha->priority = 50;
+ }
+
+ _needHitAreaRecalc++;
+}
+
+void SimonEngine::resetVerbs() {
+ if (getGameType() == GType_PP) {
+ _verbHitArea = 300;
+ return;
+ } else if (getGameType() == GType_FF) {
+ _verbHitArea = 300;
+ int cursor = 0;
+ int animMax = 16;
+
+ if (getBitFlag(203)) {
+ cursor = 14;
+ animMax = 9;
+ } else if (getBitFlag(204)) {
+ cursor = 15;
+ animMax = 9;
+ } else if (getBitFlag(207)) {
+ cursor = 26;
+ animMax = 2;
+ }
+
+ _mouseCursor = cursor;
+ _mouseAnimMax = animMax;
+ _mouseAnim = 1;
+ _needHitAreaRecalc++;
+
+ if (getBitFlag(99)) {
+ setVerb(NULL);
+ }
+ } else {
+ uint id;
+ HitArea *ha;
+
+ if (getGameType() == GType_SIMON2) {
+ id = 2;
+ if (!getBitFlag(79))
+ id = (_mouseY >= 136) ? 102 : 101;
+ } else {
+ id = (_mouseY >= 136) ? 102 : 101;
+ }
+
+ _defaultVerb = id;
+
+ ha = findBox(id);
+ if (ha == NULL)
+ return;
+
+ if (ha->flags & kBFBoxDead) {
+ _defaultVerb = 999;
+ _currentVerbBox = NULL;
+ } else {
+ _verbHitArea = ha->verb;
+ setVerb(ha);
+ }
+ }
+}
+
+void SimonEngine::setVerb(HitArea *ha) {
+ if (getGameType() == GType_PP) {
+ return;
+ } else if (getGameType() == GType_FF) {
+ int cursor = _mouseCursor;
+ if (_noRightClick)
+ return;
+
+ if (cursor > 13)
+ cursor = 0;
+ cursor++;
+ if (cursor == 5)
+ cursor = 1;
+ if (cursor == 4) {
+ if (getBitFlag(72)) {
+ cursor = 1;
+ }
+ } else if (cursor == 2) {
+ if (getBitFlag(99)) {
+ cursor = 3;
+ }
+ }
+
+ _mouseCursor = cursor;
+ _mouseAnimMax = (cursor == 4) ? 14: 16;
+ _mouseAnim = 1;
+ _needHitAreaRecalc++;
+ _verbHitArea = cursor + 300;
+ } else {
+ HitArea *tmp = _currentVerbBox;
+
+ if (ha == tmp)
+ return;
+
+ if (getGameType() == GType_SIMON1) {
+ if (tmp != NULL) {
+ tmp->flags |= kBFInvertTouch;
+ invertBox(tmp, 213, 208, 213, 10);
+ }
+
+ if (ha->flags & kBFBoxSelected)
+ invertBox(ha, 218, 213, 213, 5);
+ else
+ invertBox(ha, 223, 218, 218, 10);
+
+ ha->flags &= ~(kBFBoxSelected + kBFInvertTouch);
+ } else {
+ if (ha->id < 101)
+ return;
+ _mouseCursor = ha->id - 101;
+ _needHitAreaRecalc++;
+ }
+ _currentVerbBox = ha;
+ }
+}
+
+void SimonEngine::hitarea_leave(HitArea *ha, bool state) {
+ if (getGameType() == GType_FF) {
+ invertBox_FF(ha, state);
+ } else if (getGameType() == GType_SIMON2) {
+ invertBox(ha, 231, 229, 230, 1);
+ } else {
+ invertBox(ha, 223, 213, 218, 5);
+ }
+}
+
+void SimonEngine::leaveHitAreaById(uint hitarea_id) {
+ HitArea *ha = findBox(hitarea_id);
+ if (ha)
+ hitarea_leave(ha);
+}
+
+void SimonEngine::checkUp(WindowBlock *window) {
+ uint16 j, k;
+
+ if (((_variableArray[31] - _variableArray[30]) == 40) && (_variableArray[31] > 52)) {
+ k = (((_variableArray[31] / 52) - 2) % 3);
+ j = k * 6;
+ if (!isBoxDead(j + 201)) {
+ uint index = getWindowNum(window);
+ drawIconArray(index, window->iconPtr->itemRef, 0, window->iconPtr->classMask);
+ loadSprite(4, 9, k + 34, 0, 0, 0);
+ }
+ }
+ if ((_variableArray[31] - _variableArray[30]) == 76) {
+ k = ((_variableArray[31] / 52) % 3);
+ j = k * 6;
+ if (isBoxDead(j + 201)) {
+ loadSprite(4, 9, k + 31, 0, 0, 0);
+ undefineBox(j + 201);
+ undefineBox(j + 202);
+ undefineBox(j + 203);
+ undefineBox(j + 204);
+ undefineBox(j + 205);
+ undefineBox(j + 206);
+ }
+ _variableArray[31] -= 52;
+ _iOverflow = 1;
+ }
+}
+
+void SimonEngine::checkDown(WindowBlock *window) {
+ uint16 j, k;
+
+ if (((_variableArray[31] - _variableArray[30]) == 24) && (_iOverflow == 1)) {
+ uint index = getWindowNum(window);
+ drawIconArray(index, window->iconPtr->itemRef, 0, window->iconPtr->classMask);
+ k = ((_variableArray[31] / 52) % 3);
+ loadSprite(4, 9, k + 25, 0, 0, 0);
+ _variableArray[31] += 52;
+ }
+ if (((_variableArray[31] - _variableArray[30]) == 40) && (_variableArray[30] > 52)) {
+ k = (((_variableArray[31] / 52) + 1) % 3);
+ j = k * 6;
+ if (isBoxDead(j + 201)) {
+ loadSprite(4, 9, k + 28, 0, 0, 0);
+ undefineBox(j + 201);
+ undefineBox(j + 202);
+ undefineBox(j + 203);
+ undefineBox(j + 204);
+ undefineBox(j + 205);
+ undefineBox(j + 206);
+ }
+ }
+}
+
+void SimonEngine::inventoryUp(WindowBlock *window) {
+ if (getGameType() == GType_FF) {
+ _marks = 0;
+ checkUp(window);
+ loadSprite(4, 9, 21, 0 ,0, 0);
+ while (1) {
+ if (_currentBoxNumber != 0x7FFB || !getBitFlag(89))
+ break;
+ checkUp(window);
+ delay(1);
+ }
+ waitForMark(2);
+ checkUp(window);
+ sendSync(922);
+ waitForMark(1);
+ checkUp(window);
+ } else {
+ if (window->iconPtr->line == 0)
+ return;
+
+ mouseOff();
+ uint index = getWindowNum(window);
+ drawIconArray(index, window->iconPtr->itemRef, window->iconPtr->line - 1, window->iconPtr->classMask);
+ mouseOn();
+ }
+}
+
+void SimonEngine::inventoryDown(WindowBlock *window) {
+ if (getGameType() == GType_FF) {
+ _marks = 0;
+ checkDown(window);
+ loadSprite(4, 9, 23, 0, 0, 0);
+ while (1) {
+ if (_currentBoxNumber != 0x7FFC || !getBitFlag(89))
+ break;
+ checkDown(window);
+ delay(1);
+ }
+ waitForMark(2);
+ checkDown(window);
+ sendSync(924);
+ waitForMark(1);
+ checkDown(window);
+ } else {
+ mouseOff();
+ uint index = getWindowNum(window);
+ drawIconArray(index, window->iconPtr->itemRef, window->iconPtr->line + 1, window->iconPtr->classMask);
+ mouseOn();
+ }
+}
+
+void SimonEngine::boxController(uint x, uint y, uint mode) {
+ HitArea *best_ha;
+ HitArea *ha = _hitAreas;
+ uint count = ARRAYSIZE(_hitAreas);
+ uint16 priority = 0;
+ uint16 x_ = x;
+ uint16 y_ = y;
+
+ if (getGameType() == GType_FF) {
+ x_ += _scrollX;
+ y_ += _scrollY;
+ }
+ if (getGameType() == GType_SIMON2) {
+ if (getBitFlag(79) || y < 134) {
+ x_ += _scrollX * 8;
+ }
+ }
+
+ best_ha = NULL;
+
+ do {
+ if (ha->flags & kBFBoxInUse) {
+ if (!(ha->flags & kBFBoxDead)) {
+ if (x_ >= ha->x && y_ >= ha->y &&
+ x_ - ha->x < ha->width && y_ - ha->y < ha->height && priority <= ha->priority) {
+ priority = ha->priority;
+ best_ha = ha;
+ } else {
+ if (ha->flags & kBFBoxSelected) {
+ hitarea_leave(ha , true);
+ ha->flags &= ~kBFBoxSelected;
+ }
+ }
+ } else {
+ ha->flags &= ~kBFBoxSelected;
+ }
+ }
+ } while (ha++, --count);
+
+ _currentBoxNumber = 0;
+
+ if (best_ha == NULL) {
+ clearName();
+ return;
+ }
+
+ _currentBoxNumber = best_ha->id;
+
+ if (mode != 0 && mode != 3) {
+ _lastHitArea = best_ha;
+ if (getGameType() == GType_PP) {
+ _variableArray[400] = x;
+ _variableArray[401] = y;
+ } else {
+ _variableArray[1] = x;
+ _variableArray[2] = y;
+ }
+ }
+
+ if (best_ha->flags & kBFNoTouchName) {
+ clearName();
+ } else if (best_ha != _lastNameOn) {
+ displayName(best_ha);
+ }
+
+ if (best_ha->flags & kBFInvertTouch && !(best_ha->flags & kBFBoxSelected)) {
+ hitarea_leave(best_ha, false);
+ best_ha->flags |= kBFBoxSelected;
+ }
+
+ return;
+}
+
+void SimonEngine::displayName(HitArea *ha) {
+ bool result;
+ int x = 0, y = 0;
+
+ if (getGameType() == GType_PP) {
+ if (ha->flags & kBFHyperBox) {
+ _lastNameOn = ha;
+ return;
+ }
+ if (findBox(50))
+ return;
+
+ y = ha->y;
+ y -= 17;
+ if (y < 0)
+ y = 0;
+ y += 2;
+ x = ha->width / 2 + ha->x;
+ } else if (getGameType() == GType_FF) {
+ if (ha->flags & kBFHyperBox) {
+ _lastNameOn = ha;
+ return;
+ }
+ if (findBox(50))
+ return;
+
+ if (getBitFlag(99))
+ _animatePointer = ((ha->flags & kBFTextBox) == 0);
+ else
+ _animatePointer = 1;
+
+ if (!getBitFlag(73))
+ return;
+
+ y = ha->y;
+ if (getBitFlag(99) && y > 288)
+ y = 288;
+ y -= 17;
+ if (y < 0)
+ y = 0;
+ y += 2;
+ x = ha->width / 2 + ha->x;
+ } else {
+ resetNameWindow();
+ }
+
+ if (ha->flags & kBFTextBox) {
+ result = printTextOf(ha->flags / 256, x, y);
+ } else {
+ result = printNameOf(ha->item_ptr, x, y);
+ }
+
+ if (result)
+ _lastNameOn = ha;
+}
+
+void SimonEngine::invertBox_FF(HitArea *ha, bool state) {
+ if (getBitFlag(205) || getBitFlag(206)) {
+ if (state != 0) {
+ _mouseAnimMax = _oldMouseAnimMax;
+ _mouseCursor = _oldMouseCursor;
+ } else if (_mouseCursor != 18) {
+ _oldMouseCursor = _mouseCursor;
+ _animatePointer = 0;
+ _oldMouseAnimMax = _mouseAnimMax;
+ _mouseAnimMax = 2;
+ _mouseCursor = 18;
+ }
+ } else {
+ if (getBitFlag(207)) {
+ if (state != 0) {
+ _noRightClick = 0;
+ resetVerbs();
+ } else {
+ int cursor = ha->id + 9;
+ if (cursor >= 23)
+ cursor = 21;
+ _mouseCursor = cursor;
+ _mouseAnimMax = 8;
+ _noRightClick = 1;
+ }
+ } else {
+ VgaSprite *vsp = _vgaSprites;
+
+ int id = ha->id - 43;
+ while (vsp->id) {
+ if (vsp->id == id && vsp->zoneNum == 2) {
+ if (state == 0)
+ vsp->flags |= kDFShaded;
+ else
+ vsp->flags &= ~kDFShaded;
+ break;
+ }
+ vsp++;
+ }
+ }
+ }
+}
+
+void SimonEngine::invertBox(HitArea * ha, byte a, byte b, byte c, byte d) {
+ byte *src, color;
+ int w, h, i;
+
+ _lockWord |= 0x8000;
+ src = getFrontBuf() + ha->y * _dxSurfacePitch + ha->x;
+
+ _hitarea_unk_3 = true;
+
+ w = ha->width;
+ h = ha->height;
+
+ // Works around bug in original Simon the Sorcerer 2
+ // Animations continue in background when load/save dialog is open
+ // often causing the savegame name highlighter to be cut short
+ if (!(h > 0 && w > 0 && ha->x + w <= _screenWidth && ha->y + h <= _screenHeight)) {
+ debug(1,"Invalid coordinates in invertBox (%d,%d,%d,%d)", ha->x, ha->y, ha->width, ha->height);
+ _lockWord &= ~0x8000;
+ return;
+ }
+
+ do {
+ for (i = 0; i != w; ++i) {
+ color = src[i];
+ if (a >= color && b < color) {
+ if (c >= color)
+ color += d;
+ else
+ color -= d;
+ src[i] = color;
+ }
+ }
+ src += _dxSurfacePitch;
+ } while (--h);
+
+ _lockWord &= ~0x8000;
+}
+
+} // End of namespace Simon
diff --git a/engines/agos/vga.cpp b/engines/agos/vga.cpp
new file mode 100644
index 0000000000..d7deb2fbc0
--- /dev/null
+++ b/engines/agos/vga.cpp
@@ -0,0 +1,2788 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-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$
+ *
+ */
+
+// Video script opcodes for Simon1/Simon2
+#include "common/stdafx.h"
+
+#include "agos/agos.h"
+#include "agos/intern.h"
+#include "agos/vga.h"
+
+#include "common/system.h"
+
+namespace Simon {
+
+// Opcode tables
+void SimonEngine::setupVgaOpcodes() {
+ static const VgaOpcodeProc vga_opcode_table[] = {
+ NULL,
+ &SimonEngine::vc1_fadeOut,
+ &SimonEngine::vc2_call,
+ &SimonEngine::vc3_loadSprite,
+ &SimonEngine::vc4_fadeIn,
+ &SimonEngine::vc5_skip_if_neq,
+ &SimonEngine::vc6_skip_ifn_sib_with_a,
+ &SimonEngine::vc7_skip_if_sib_with_a,
+ &SimonEngine::vc8_skip_if_parent_is,
+ &SimonEngine::vc9_skip_if_unk3_is,
+ &SimonEngine::vc10_draw,
+ &SimonEngine::vc11_clearPathFinder,
+ &SimonEngine::vc12_delay,
+ &SimonEngine::vc13_addToSpriteX,
+ &SimonEngine::vc14_addToSpriteY,
+ &SimonEngine::vc15_sync,
+ &SimonEngine::vc16_waitSync,
+ &SimonEngine::vc17_setPathfinderItem,
+ &SimonEngine::vc18_jump,
+ &SimonEngine::vc19_chain_to_script,
+ &SimonEngine::vc20_setRepeat,
+ &SimonEngine::vc21_endRepeat,
+ &SimonEngine::vc22_setSpritePalette,
+ &SimonEngine::vc23_setSpritePriority,
+ &SimonEngine::vc24_setSpriteXY,
+ &SimonEngine::vc25_halt_sprite,
+ &SimonEngine::vc26_setSubWindow,
+ &SimonEngine::vc27_resetSprite,
+ &SimonEngine::vc28_dummy_op,
+ &SimonEngine::vc29_stopAllSounds,
+ &SimonEngine::vc30_setFrameRate,
+ &SimonEngine::vc31_setWindow,
+ &SimonEngine::vc32_copyVar,
+ &SimonEngine::vc33_setMouseOn,
+ &SimonEngine::vc34_setMouseOff,
+ &SimonEngine::vc35_clearWindow,
+ &SimonEngine::vc36_setWindowImage,
+ &SimonEngine::vc37_addToSpriteY,
+ &SimonEngine::vc38_skipIfVarZero,
+ &SimonEngine::vc39_setVar,
+ &SimonEngine::vc40,
+ &SimonEngine::vc41,
+ &SimonEngine::vc42_delayIfNotEQ,
+ &SimonEngine::vc43_skipIfBitClear,
+ &SimonEngine::vc44_skipIfBitSet,
+ &SimonEngine::vc45_setSpriteX,
+ &SimonEngine::vc46_setSpriteY,
+ &SimonEngine::vc47_addToVar,
+ &SimonEngine::vc48_setPathFinder,
+ &SimonEngine::vc49_setBit,
+ &SimonEngine::vc50_clearBit,
+ &SimonEngine::vc51_enableBox,
+ &SimonEngine::vc52_playSound,
+ &SimonEngine::vc53_panSFX,
+ &SimonEngine::vc54_no_op,
+ &SimonEngine::vc55_moveBox,
+ &SimonEngine::vc56_delay,
+ &SimonEngine::vc57_blackPalette,
+ &SimonEngine::vc58,
+ &SimonEngine::vc59,
+ &SimonEngine::vc60_killSprite,
+ &SimonEngine::vc61_setMaskImage,
+ &SimonEngine::vc62_fastFadeOut,
+ &SimonEngine::vc63_fastFadeIn,
+ &SimonEngine::vc64_skipIfSpeechEnded,
+ &SimonEngine::vc65_slowFadeIn,
+ &SimonEngine::vc66_skipIfNotEqual,
+ &SimonEngine::vc67_skipIfGE,
+ &SimonEngine::vc68_skipIfLE,
+ &SimonEngine::vc69_playTrack,
+ &SimonEngine::vc70_queueMusic,
+ &SimonEngine::vc71_checkMusicQueue,
+ &SimonEngine::vc72_play_track_2,
+ &SimonEngine::vc73_setMark,
+ &SimonEngine::vc74_clearMark,
+ &SimonEngine::vc75_setScale,
+ &SimonEngine::vc76_setScaleXOffs,
+ &SimonEngine::vc77_setScaleYOffs,
+ &SimonEngine::vc78_computeXY,
+ &SimonEngine::vc79_computePosNum,
+ &SimonEngine::vc80_setOverlayImage,
+ &SimonEngine::vc81_setRandom,
+ &SimonEngine::vc82_getPathValue,
+ &SimonEngine::vc83_playSoundLoop,
+ &SimonEngine::vc84_stopSoundLoop,
+ };
+
+ _vga_opcode_table = vga_opcode_table;
+}
+
+// Script parser
+void SimonEngine::runVgaScript() {
+ for (;;) {
+ uint opcode;
+
+ if (_continousVgaScript) {
+ if (_vcPtr != (const byte *)&_vc_get_out_of_code) {
+ printf("%.5d %.5X: %5d %4d ", _vgaTickCounter, (unsigned int)(_vcPtr - _curVgaFile1), _vgaCurSpriteId, _vgaCurZoneNum);
+ dump_video_script(_vcPtr, true);
+ }
+ }
+
+ if (getGameType() == GType_SIMON1 || getGameType() == GType_WW) {
+ opcode = READ_BE_UINT16(_vcPtr);
+ _vcPtr += 2;
+ } else {
+ opcode = *_vcPtr++;
+ }
+
+ if (opcode >= _numVideoOpcodes)
+ error("Invalid VGA opcode '%d' encountered", opcode);
+
+ if (opcode == 0)
+ return;
+
+ (this->*_vga_opcode_table[opcode]) ();
+ }
+}
+
+bool SimonEngine::itemIsSiblingOf(uint16 a) {
+ Item *item;
+
+ CHECK_BOUNDS(a, _objectArray);
+
+ item = _objectArray[a];
+ if (item == NULL)
+ return true;
+
+ return me()->parent == item->parent;
+}
+
+bool SimonEngine::itemIsParentOf(uint16 a, uint16 b) {
+ Item *item_a, *item_b;
+
+ CHECK_BOUNDS(a, _objectArray);
+ CHECK_BOUNDS(b, _objectArray);
+
+ item_a = _objectArray[a];
+ item_b = _objectArray[b];
+
+ if (item_a == NULL || item_b == NULL)
+ return true;
+
+ return derefItem(item_a->parent) == item_b;
+}
+
+bool SimonEngine::vc_maybe_skip_proc_1(uint16 a, int16 b) {
+ Item *item;
+
+ CHECK_BOUNDS(a, _objectArray);
+
+ item = _objectArray[a];
+ if (item == NULL)
+ return true;
+ return item->state == b;
+}
+
+VgaSprite *SimonEngine::findCurSprite() {
+ VgaSprite *vsp = _vgaSprites;
+ while (vsp->id) {
+ if (getGameType() == GType_SIMON1 || getGameType() == GType_WW) {
+ if (vsp->id == _vgaCurSpriteId)
+ break;
+ } else {
+ if (vsp->id == _vgaCurSpriteId && vsp->zoneNum == _vgaCurZoneNum)
+ break;
+ }
+ vsp++;
+ }
+ return vsp;
+}
+
+int SimonEngine::vcReadVarOrWord() {
+ int16 var = vcReadNextWord();
+ if (var < 0)
+ var = vcReadVar(-var);
+ return var;
+}
+
+uint SimonEngine::vcReadNextWord() {
+ uint a;
+ a = readUint16Wrapper(_vcPtr);
+ _vcPtr += 2;
+ return a;
+}
+
+uint SimonEngine::vcReadNextByte() {
+ return *_vcPtr++;
+}
+
+uint SimonEngine::vcReadVar(uint var) {
+ assert(var < _numVars);
+ return (uint16)_variableArrayPtr[var];
+}
+
+void SimonEngine::vcWriteVar(uint var, int16 value) {
+ assert(var < _numVars);
+ _variableArrayPtr[var] = value;
+}
+
+void SimonEngine::vcSkipNextInstruction() {
+ static const byte opcodeParamLenWW[] = {
+ 0, 6, 2, 10, 6, 4, 2, 2,
+ 4, 4, 8, 2, 2, 2, 2, 2,
+ 2, 2, 2, 0, 4, 2, 2, 2,
+ 8, 0, 10, 0, 8, 0, 2, 2,
+ 0, 0, 0, 4, 4, 4, 2, 4,
+ 4, 4, 4, 2, 2, 4, 2, 2,
+ 2, 2, 2, 2, 2, 4, 6, 6,
+ 0, 0, 0, 0, 2, 2, 0, 0,
+ };
+
+ static const byte opcodeParamLenSimon1[] = {
+ 0, 6, 2, 10, 6, 4, 2, 2,
+ 4, 4, 10, 0, 2, 2, 2, 2,
+ 2, 0, 2, 0, 4, 2, 4, 2,
+ 8, 0, 10, 0, 8, 0, 2, 2,
+ 4, 0, 0, 4, 4, 2, 2, 4,
+ 4, 4, 4, 2, 2, 2, 2, 4,
+ 0, 2, 2, 2, 2, 4, 6, 6,
+ 0, 0, 0, 0, 2, 6, 0, 0,
+ };
+
+ static const byte opcodeParamLenSimon2[] = {
+ 0, 6, 2, 12, 6, 4, 2, 2,
+ 4, 4, 9, 0, 1, 2, 2, 2,
+ 2, 0, 2, 0, 4, 2, 4, 2,
+ 7, 0, 10, 0, 8, 0, 2, 2,
+ 4, 0, 0, 4, 4, 2, 2, 4,
+ 4, 4, 4, 2, 2, 2, 2, 4,
+ 0, 2, 2, 2, 2, 4, 6, 6,
+ 2, 0, 6, 6, 4, 6, 0, 0,
+ 0, 0, 4, 4, 4, 4, 4, 0,
+ 4, 2, 2
+ };
+
+ static const byte opcodeParamLenFeebleFiles[] = {
+ 0, 6, 2, 12, 6, 4, 2, 2,
+ 4, 4, 9, 0, 1, 2, 2, 2,
+ 2, 0, 2, 0, 4, 2, 4, 2,
+ 7, 0, 10, 0, 8, 0, 2, 2,
+ 4, 0, 0, 4, 4, 2, 2, 4,
+ 4, 4, 4, 2, 2, 2, 2, 4,
+ 0, 2, 2, 2, 6, 6, 6, 6,
+ 2, 0, 6, 6, 4, 6, 0, 0,
+ 0, 0, 4, 4, 4, 4, 4, 0,
+ 4, 2, 2, 4, 6, 6, 0, 0,
+ 6, 4, 2, 6, 0
+ };
+
+ uint16 opcode;
+ if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ opcode = vcReadNextByte();
+ _vcPtr += opcodeParamLenFeebleFiles[opcode];
+ } else if (getGameType() == GType_SIMON2) {
+ opcode = vcReadNextByte();
+ _vcPtr += opcodeParamLenSimon2[opcode];
+ } else if (getGameType() == GType_SIMON1) {
+ opcode = vcReadNextWord();
+ _vcPtr += opcodeParamLenSimon1[opcode];
+ } else {
+ opcode = vcReadNextWord();
+ _vcPtr += opcodeParamLenWW[opcode];
+ }
+
+ if (_continousVgaScript)
+ printf("; skipped\n");
+}
+
+// VGA Script commands
+void SimonEngine::vc1_fadeOut() {
+ /* dummy opcode */
+ _vcPtr += 6;
+}
+
+void SimonEngine::vc2_call() {
+ VgaPointersEntry *vpe;
+ uint16 count, num, res;
+ byte *old_file_1, *old_file_2;
+ byte *b, *bb;
+ const byte *vcPtrOrg;
+
+ num = vcReadVarOrWord();
+
+ old_file_1 = _curVgaFile1;
+ old_file_2 = _curVgaFile2;
+
+ for (;;) {
+ res = num / 100;
+ vpe = &_vgaBufferPointers[res];
+
+ _curVgaFile1 = vpe->vgaFile1;
+ _curVgaFile2 = vpe->vgaFile2;
+ if (vpe->vgaFile1 != NULL)
+ break;
+ if (_zoneNumber != res)
+ _noOverWrite = _zoneNumber;
+
+ loadZone(res);
+ _noOverWrite = 0xFFFF;
+ }
+
+
+ bb = _curVgaFile1;
+ if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ b = bb + READ_LE_UINT16(&((VgaFileHeader_Feeble *) bb)->hdr2_start);
+ count = READ_LE_UINT16(&((VgaFileHeader2_Feeble *) b)->imageCount);
+ b = bb + READ_LE_UINT16(&((VgaFileHeader2_Feeble *) b)->imageTable);
+
+ while (count--) {
+ if (READ_LE_UINT16(&((ImageHeader_Feeble *) b)->id) == num)
+ break;
+ b += sizeof(ImageHeader_Feeble);
+ }
+ assert(READ_LE_UINT16(&((ImageHeader_Feeble *) b)->id) == num);
+ } else if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) {
+ b = bb + READ_BE_UINT16(&((VgaFileHeader_Simon *) bb)->hdr2_start);
+ count = READ_BE_UINT16(&((VgaFileHeader2_Simon *) b)->imageCount);
+ b = bb + READ_BE_UINT16(&((VgaFileHeader2_Simon *) b)->imageTable);
+
+ while (count--) {
+ if (READ_BE_UINT16(&((ImageHeader_Simon *) b)->id) == num)
+ break;
+ b += sizeof(ImageHeader_Simon);
+ }
+ assert(READ_BE_UINT16(&((ImageHeader_Simon *) b)->id) == num);
+ } else {
+ b = bb + READ_BE_UINT16(bb + 10);
+ b += 20;
+
+ count = READ_BE_UINT16(&((VgaFileHeader2_WW *) b)->imageCount);
+ b = bb + READ_BE_UINT16(&((VgaFileHeader2_WW *) b)->imageTable);
+
+ while (count--) {
+ if (READ_BE_UINT16(&((ImageHeader_WW *) b)->id) == num)
+ break;
+ b += sizeof(ImageHeader_WW);
+ }
+ assert(READ_BE_UINT16(&((ImageHeader_WW *) b)->id) == num);
+ }
+
+ vcPtrOrg = _vcPtr;
+
+ if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ _vcPtr = _curVgaFile1 + READ_LE_UINT16(&((ImageHeader_Feeble *) b)->scriptOffs);
+ } else if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) {
+ _vcPtr = _curVgaFile1 + READ_BE_UINT16(&((ImageHeader_Simon *) b)->scriptOffs);
+ } else {
+ _vcPtr = _curVgaFile1 + READ_BE_UINT16(&((ImageHeader_WW *) b)->scriptOffs);
+ }
+
+ //dump_vga_script(_vcPtr, res, num);
+ runVgaScript();
+
+ _curVgaFile1 = old_file_1;
+ _curVgaFile2 = old_file_2;
+
+ _vcPtr = vcPtrOrg;
+}
+
+void SimonEngine::vc3_loadSprite() {
+ uint16 windowNum, zoneNum, palette, x, y, vgaSpriteId;
+ uint16 count, res;
+ VgaSprite *vsp;
+ VgaPointersEntry *vpe;
+ byte *p, *pp;
+ byte *old_file_1;
+
+ windowNum = vcReadNextWord(); /* 0 */
+
+ if (getGameType() == GType_SIMON1 || getGameType() == GType_WW) {
+ vgaSpriteId = vcReadNextWord(); /* 2 */
+ zoneNum = vgaSpriteId / 100;
+ } else {
+ zoneNum = vcReadNextWord(); /* 0 */
+ vgaSpriteId = vcReadNextWord(); /* 2 */
+ }
+
+ x = vcReadNextWord(); /* 4 */
+ y = vcReadNextWord(); /* 6 */
+ palette = vcReadNextWord(); /* 8 */
+
+ if (isSpriteLoaded(vgaSpriteId, zoneNum))
+ return;
+
+ vsp = _vgaSprites;
+ while (vsp->id)
+ vsp++;
+
+ if (getGameType() == GType_WW)
+ vsp->palette = 0;
+ else
+ vsp->palette = palette;
+ vsp->windowNum = windowNum;
+ vsp->priority = 0;
+ vsp->flags = 0;
+ vsp->image = 0;
+ vsp->x = x;
+ vsp->y = y;
+ vsp->id = vgaSpriteId;
+ vsp->zoneNum = res = zoneNum;
+
+ old_file_1 = _curVgaFile1;
+ for (;;) {
+ vpe = &_vgaBufferPointers[res];
+ _curVgaFile1 = vpe->vgaFile1;
+
+ if (vpe->vgaFile1 != NULL)
+ break;
+ if (_zoneNumber != res)
+ _noOverWrite = _zoneNumber;
+
+ loadZone(res);
+ _noOverWrite = 0xFFFF;
+ }
+
+ pp = _curVgaFile1;
+ if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ p = pp + READ_LE_UINT16(&((VgaFileHeader_Feeble *) pp)->hdr2_start);
+ count = READ_LE_UINT16(&((VgaFileHeader2_Feeble *) p)->animationCount);
+ p = pp + READ_LE_UINT16(&((VgaFileHeader2_Feeble *) p)->animationTable);
+
+ while (count--) {
+ if (READ_LE_UINT16(&((AnimationHeader_Feeble *) p)->id) == vgaSpriteId)
+ break;
+ p += sizeof(AnimationHeader_Feeble);
+ }
+ assert(READ_LE_UINT16(&((AnimationHeader_Feeble *) p)->id) == vgaSpriteId);
+ } else if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) {
+ p = pp + READ_BE_UINT16(&((VgaFileHeader_Simon *) pp)->hdr2_start);
+ count = READ_BE_UINT16(&((VgaFileHeader2_Simon *) p)->animationCount);
+ p = pp + READ_BE_UINT16(&((VgaFileHeader2_Simon *) p)->animationTable);
+
+ while (count--) {
+ if (READ_BE_UINT16(&((AnimationHeader_Simon *) p)->id) == vgaSpriteId)
+ break;
+ p += sizeof(AnimationHeader_Simon);
+ }
+ assert(READ_BE_UINT16(&((AnimationHeader_Simon *) p)->id) == vgaSpriteId);
+ } else {
+ p = pp + READ_BE_UINT16(pp + 10);
+ p += 20;
+
+ count = READ_BE_UINT16(&((VgaFileHeader2_WW *) p)->animationCount);
+ p = pp + READ_BE_UINT16(&((VgaFileHeader2_WW *) p)->animationTable);
+
+ while (count--) {
+ if (READ_BE_UINT16(&((AnimationHeader_WW *) p)->id) == vgaSpriteId)
+ break;
+ p += sizeof(AnimationHeader_WW);
+ }
+ assert(READ_BE_UINT16(&((AnimationHeader_WW *) p)->id) == vgaSpriteId);
+ }
+
+#ifdef DUMP_FILE_NR
+ {
+ static bool dumped = false;
+ if (res == DUMP_FILE_NR && !dumped) {
+ dumped = true;
+ dump_vga_file(_curVgaFile1);
+ }
+ }
+#endif
+
+#ifdef DUMP_BITMAPS_FILE_NR
+ {
+ static bool dumped = false;
+ if (res == DUMP_BITMAPS_FILE_NR && !dumped) {
+ dumped = true;
+ dump_vga_bitmaps(_curVgaFile2, _curVgaFile1, res);
+ }
+ }
+#endif
+
+ if (_startVgaScript) {
+ if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ dump_vga_script(_curVgaFile1 + READ_LE_UINT16(&((AnimationHeader_Feeble*)p)->scriptOffs), res, vgaSpriteId);
+ } else if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) {
+ dump_vga_script(_curVgaFile1 + READ_BE_UINT16(&((AnimationHeader_Simon*)p)->scriptOffs), res, vgaSpriteId);
+ } else {
+ dump_vga_script(_curVgaFile1 + READ_BE_UINT16(&((AnimationHeader_WW*)p)->scriptOffs), res, vgaSpriteId);
+ }
+ }
+
+ if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ addVgaEvent(_vgaBaseDelay, _curVgaFile1 + READ_LE_UINT16(&((AnimationHeader_Feeble *) p)->scriptOffs), vgaSpriteId, res);
+ } else if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) {
+ addVgaEvent(_vgaBaseDelay, _curVgaFile1 + READ_BE_UINT16(&((AnimationHeader_Simon *) p)->scriptOffs), vgaSpriteId, res);
+ } else {
+ addVgaEvent(_vgaBaseDelay, _curVgaFile1 + READ_BE_UINT16(&((AnimationHeader_WW *) p)->scriptOffs), vgaSpriteId, res);
+ }
+
+ _curVgaFile1 = old_file_1;
+}
+
+void SimonEngine::vc4_fadeIn() {
+ /* dummy opcode */
+ _vcPtr += 6;
+}
+
+void SimonEngine::vc5_skip_if_neq() {
+ uint16 var = vcReadNextWord();
+ uint16 value = vcReadNextWord();
+ if (vcReadVar(var) != value)
+ vcSkipNextInstruction();
+}
+
+void SimonEngine::vc6_skip_ifn_sib_with_a() {
+ if (!itemIsSiblingOf(vcReadNextWord()))
+ vcSkipNextInstruction();
+}
+
+void SimonEngine::vc7_skip_if_sib_with_a() {
+ if (itemIsSiblingOf(vcReadNextWord()))
+ vcSkipNextInstruction();
+}
+
+void SimonEngine::vc8_skip_if_parent_is() {
+ uint16 a = vcReadNextWord();
+ uint16 b = vcReadNextWord();
+ if (!itemIsParentOf(a, b))
+ vcSkipNextInstruction();
+}
+
+void SimonEngine::vc9_skip_if_unk3_is() {
+ uint16 a = vcReadNextWord();
+ uint16 b = vcReadNextWord();
+ if (!vc_maybe_skip_proc_1(a, b))
+ vcSkipNextInstruction();
+}
+
+byte *vc10_depackColumn(VC10_state * vs) {
+ int8 a = vs->depack_cont;
+ const byte *src = vs->depack_src;
+ byte *dst = vs->depack_dest;
+ uint16 dh = vs->dh;
+ byte color;
+
+ if (a == -0x80)
+ a = *src++;
+
+ for (;;) {
+ if (a >= 0) {
+ color = *src++;
+ do {
+ *dst++ = color;
+ if (!--dh) {
+ if (--a < 0)
+ a = -0x80;
+ else
+ src--;
+ goto get_out;
+ }
+ } while (--a >= 0);
+ } else {
+ do {
+ *dst++ = *src++;
+ if (!--dh) {
+ if (++a == 0)
+ a = -0x80;
+ goto get_out;
+ }
+ } while (++a != 0);
+ }
+ a = *src++;
+ }
+
+get_out:;
+ vs->depack_src = src;
+ vs->depack_cont = a;
+ return vs->depack_dest + vs->y_skip;
+}
+
+void vc10_skip_cols(VC10_state *vs) {
+ while (vs->x_skip) {
+ vc10_depackColumn(vs);
+ vs->x_skip--;
+ }
+}
+
+byte *SimonEngine::vc10_uncompressFlip(const byte *src, uint w, uint h) {
+ w *= 8;
+
+ byte *src_org, *dst_org;
+ byte color;
+ int8 cur = -0x80;
+ uint i, w_cur = w;
+
+ dst_org = _videoBuf1 + w;
+
+ do {
+ byte *dst = dst_org;
+ uint h_cur = h;
+
+ if (cur == -0x80)
+ cur = *src++;
+
+ for (;;) {
+ if (cur >= 0) {
+ /* rle_same */
+ color = *src++;
+ do {
+ *dst = color;
+ dst += w;
+ if (!--h_cur) {
+ if (--cur < 0)
+ cur = -0x80;
+ else
+ src--;
+ goto next_line;
+ }
+ } while (--cur >= 0);
+ } else {
+ /* rle_diff */
+ do {
+ *dst = *src++;
+ dst += w;
+ if (!--h_cur) {
+ if (++cur == 0)
+ cur = -0x80;
+ goto next_line;
+ }
+ } while (++cur != 0);
+ }
+ cur = *src++;
+ }
+ next_line:
+ dst_org++;
+ } while (--w_cur);
+
+
+ src_org = dst_org = _videoBuf1 + w;
+
+ do {
+ byte *dst = dst_org;
+ for (i = 0; i != w; ++i) {
+ byte b = src_org[i];
+ b = (b >> 4) | (b << 4);
+ *--dst = b;
+ }
+
+ src_org += w;
+ dst_org += w;
+ } while (--h);
+
+ return _videoBuf1;
+}
+
+byte *SimonEngine::vc10_flip(const byte *src, uint w, uint h) {
+ if (src == _vc10BasePtrOld)
+ return _videoBuf1;
+
+ _vc10BasePtrOld = src;
+
+ byte *dst_org, *src_org;
+ uint i;
+
+ w *= 8;
+ src_org = dst_org = _videoBuf1 + w;
+
+ do {
+ byte *dst = dst_org;
+ for (i = 0; i != w; ++i) {
+ byte b = src_org[i];
+ b = (b >> 4) | (b << 4);
+ *--dst = b;
+ }
+
+ src_org += w;
+ dst_org += w;
+ } while (--h);
+
+ return _videoBuf1;
+}
+
+/* must not be const */
+static uint16 _video_windows[128] = {
+ 0, 0, 20, 200,
+ 0, 0, 3, 136,
+ 17, 0, 3, 136,
+ 0, 0, 20, 200,
+ 0, 0, 20, 134
+};
+
+/* Elvira 1/2 & Waxworks
+static uint16 _video_windows[128] = {
+ 3, 0, 14, 136,
+ 0, 0, 3, 136,
+ 17, 0, 3, 136,
+ 0, 0, 20, 200,
+ 3, 3, 14, 127,
+};
+ */
+
+void SimonEngine::decodeColumn(byte *dst, const byte *src, int height) {
+ const uint pitch = _dxSurfacePitch;
+ int8 reps = (int8)0x80;
+ byte color;
+ byte *dst_org = dst;
+ uint h = height, w = 8;
+
+ for (;;) {
+ reps = *src++;
+ if (reps >= 0) {
+ color = *src++;
+
+ do {
+ *dst = color;
+ dst += pitch;
+
+ /* reached bottom? */
+ if (--h == 0) {
+ /* reached right edge? */
+ if (--w == 0)
+ return;
+ dst = ++dst_org;
+ h = height;
+ }
+ } while (--reps >= 0);
+ } else {
+
+ do {
+ *dst = *src++;
+ dst += pitch;
+
+ /* reached bottom? */
+ if (--h == 0) {
+ /* reached right edge? */
+ if (--w == 0)
+ return;
+ dst = ++dst_org;
+ h = height;
+ }
+ } while (++reps != 0);
+ }
+ }
+}
+
+void SimonEngine::decodeRow(byte *dst, const byte *src, int width) {
+ const uint pitch = _dxSurfacePitch;
+ int8 reps = (int8)0x80;
+ byte color;
+ byte *dst_org = dst;
+ uint w = width, h = 8;
+
+ for (;;) {
+ reps = *src++;
+ if (reps >= 0) {
+ color = *src++;
+
+ do {
+ *dst++ = color;
+
+ /* reached right edge? */
+ if (--w == 0) {
+ /* reached bottom? */
+ if (--h == 0)
+ return;
+ dst_org += pitch;
+ dst = dst_org;
+ w = width;
+ }
+ } while (--reps >= 0);
+ } else {
+
+ do {
+ *dst++ = *src++;
+
+ /* reached right edge? */
+ if (--w == 0) {
+ /* reached bottom? */
+ if (--h == 0)
+ return;
+ dst_org += pitch;
+ dst = dst_org;
+ w = width;
+ }
+ } while (++reps != 0);
+ }
+ }
+}
+
+void SimonEngine::vc10_draw() {
+ byte *p2;
+ uint width, height;
+ byte flags;
+ VC10_state state;
+
+ state.image = (int16)vcReadNextWord();
+ if (state.image == 0)
+ return;
+
+ if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ state.palette = (_vcPtr[0] * 16);
+ _vcPtr += 2;
+ } else if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) {
+ state.palette = (_vcPtr[1] * 16);
+ _vcPtr += 2;
+ } else {
+ state.palette = 0;
+ }
+
+ state.x = (int16)vcReadNextWord();
+ state.x -= _scrollX;
+
+ state.y = (int16)vcReadNextWord();
+ state.y -= _scrollY;
+
+ if (getGameType() == GType_SIMON1 || getGameType() == GType_WW) {
+ state.flags = vcReadNextWord();
+ } else {
+ state.flags = vcReadNextByte();
+ }
+
+ if (state.image < 0)
+ state.image = vcReadVar(-state.image);
+
+ p2 = _curVgaFile2 + state.image * 8;
+ state.depack_src = _curVgaFile2 + readUint32Wrapper(p2);
+ if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ width = READ_LE_UINT16(p2 + 6);
+ height = READ_LE_UINT16(p2 + 4) & 0x7FFF;
+ flags = p2[5];
+ } else {
+ width = READ_BE_UINT16(p2 + 6) / 16;
+ height = p2[5];
+ flags = p2[4];
+ }
+
+ if (height == 0 || width == 0)
+ return;
+
+ if (_dumpImages)
+ dump_single_bitmap(_vgaCurZoneNum, state.image, state.depack_src, width, height,
+ state.palette);
+ // Check if image is compressed
+ if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ if (flags & 0x80) {
+ state.flags |= kDFCompressed;
+ }
+ } else {
+ if (flags & 0x80 && !(state.flags & kDFCompressedFlip)) {
+ if (state.flags & kDFFlip) {
+ state.flags &= ~kDFFlip;
+ state.flags |= kDFCompressedFlip;
+ } else {
+ state.flags |= kDFCompressed;
+ }
+ }
+ }
+
+ state.width = state.draw_width = width; /* cl */
+ state.height = state.draw_height = height; /* ch */
+
+ state.depack_cont = -0x80;
+
+ state.x_skip = 0; /* colums to skip = bh */
+ state.y_skip = 0; /* rows to skip = bl */
+
+ uint maxWidth = (getGameType() == GType_FF || getGameType() == GType_PP) ? 640 : 20;
+ if ((getGameType() == GType_SIMON2 || getGameType() == GType_FF) && width > maxWidth) {
+ horizontalScroll(&state);
+ return;
+ }
+ if (getGameType() == GType_FF && height > 480) {
+ verticalScroll(&state);
+ return;
+ }
+
+ if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2 || getGameType() == GType_WW) {
+ if (state.flags & kDFCompressedFlip) {
+ state.depack_src = vc10_uncompressFlip(state.depack_src, width, height);
+ } else if (state.flags & kDFFlip) {
+ state.depack_src = vc10_flip(state.depack_src, width, height);
+ }
+ }
+
+ state.surf2_addr = getFrontBuf();
+ state.surf2_pitch = _dxSurfacePitch;
+
+ state.surf_addr = getBackBuf();
+ state.surf_pitch = _dxSurfacePitch;
+
+ if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ drawImages_Feeble(&state);
+ } else {
+ drawImages(&state);
+ }
+}
+
+bool SimonEngine::drawImages_clip(VC10_state *state) {
+ const uint16 *vlut;
+ uint maxWidth, maxHeight;
+ int cur;
+
+ vlut = &_video_windows[_windowNum * 4];
+
+ if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2 || getGameType() == GType_WW) {
+ state->draw_width = state->width * 2;
+ }
+
+ cur = state->x;
+ if (cur < 0) {
+ do {
+ if (!--state->draw_width)
+ return 0;
+ state->x_skip++;
+ } while (++cur);
+ }
+ state->x = cur;
+
+ maxWidth = (getGameType() == GType_FF || getGameType() == GType_PP) ? _screenWidth : (vlut[2] * 2);
+ cur += state->draw_width - maxWidth;
+ if (cur > 0) {
+ do {
+ if (!--state->draw_width)
+ return 0;
+ } while (--cur);
+ }
+
+ cur = state->y;
+ if (cur < 0) {
+ do {
+ if (!--state->draw_height)
+ return 0;
+ state->y_skip++;
+ } while (++cur);
+ }
+ state->y = cur;
+
+ maxHeight = (getGameType() == GType_FF || getGameType() == GType_PP) ? _screenHeight : vlut[3];
+ cur += state->draw_height - maxHeight;
+ if (cur > 0) {
+ do {
+ if (!--state->draw_height)
+ return 0;
+ } while (--cur);
+ }
+
+ assert(state->draw_width != 0 && state->draw_height != 0);
+
+ if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2 || getGameType() == GType_WW) {
+ state->draw_width *= 4;
+ }
+
+ return 1;
+}
+
+void SimonEngine::drawImages_Feeble(VC10_state *state) {
+ if (state->flags & kDFCompressed) {
+ if (state->flags & kDFScaled) {
+ state->surf_addr = getScaleBuf();
+ state->surf_pitch = _dxSurfacePitch;
+
+ uint w, h;
+ byte *src, *dst, *dst_org;
+
+ state->dl = state->width;
+ state->dh = state->height;
+
+ dst_org = state->surf_addr;
+ w = 0;
+ do {
+ src = vc10_depackColumn(state);
+ dst = dst_org;
+
+ h = 0;
+ do {
+ *dst = *src;
+ dst += _screenWidth;
+ src++;
+ } while (++h != state->draw_height);
+ dst_org++;
+ } while (++w != state->draw_width);
+
+ if (_vgaCurSpritePriority % 10 != 9) {
+ _scaleX = state->x;
+ _scaleY = state->y;
+ _scaleWidth = state->width;
+ _scaleHeight = state->height;
+ } else {
+ scaleClip(state->height, state->width, state->y, state->x, state->y + _scrollY);
+ }
+ } else if (state->flags & kDFOverlayed) {
+ state->surf_addr = getScaleBuf();
+ state->surf_pitch = _dxSurfacePitch;
+ state->surf_addr += (state->x + _scrollX) + (state->y + _scrollY) * state->surf_pitch;
+
+ uint w, h;
+ byte *src, *dst, *dst_org;
+
+ state->dl = state->width;
+ state->dh = state->height;
+
+ dst_org = state->surf_addr;
+ w = 0;
+ do {
+ byte color;
+
+ src = vc10_depackColumn(state);
+ dst = dst_org;
+
+ h = 0;
+ do {
+ color = *src;
+ if (color != 0)
+ *dst = color;
+ dst += _screenWidth;
+ src++;
+ } while (++h != state->draw_height);
+ dst_org++;
+ } while (++w != state->draw_width);
+
+ if (_vgaCurSpritePriority % 10 == 9) {
+ scaleClip(_scaleHeight, _scaleWidth, _scaleY, _scaleX, _scaleY + _scrollY);
+ }
+ } else {
+ if (drawImages_clip(state) == 0)
+ return;
+
+ state->surf_addr += state->x + state->y * state->surf_pitch;
+
+ uint w, h;
+ byte *src, *dst, *dst_org;
+
+ state->dl = state->width;
+ state->dh = state->height;
+
+ vc10_skip_cols(state);
+
+
+ if (state->flags & kDFMasked) {
+ if (getGameType() == GType_FF && !getBitFlag(81)) {
+ if (state->x > _feebleRect.right)
+ return;
+ if (state->y > _feebleRect.bottom)
+ return;
+ if (state->x + state->width < _feebleRect.left)
+ return;
+ if (state->y + state->height < _feebleRect.top)
+ return;
+ }
+
+ dst_org = state->surf_addr;
+ w = 0;
+ do {
+ byte color;
+
+ src = vc10_depackColumn(state);
+ dst = dst_org;
+
+ h = 0;
+ do {
+ color = *src;
+ if (color)
+ *dst = color;
+ dst += _screenWidth;
+ src++;
+ } while (++h != state->draw_height);
+ dst_org++;
+ } while (++w != state->draw_width);
+ } else {
+ dst_org = state->surf_addr;
+ w = 0;
+ do {
+ byte color;
+
+ src = vc10_depackColumn(state);
+ dst = dst_org;
+
+ h = 0;
+ do {
+ color = *src;
+ if ((state->flags & kDFNonTrans) || color != 0)
+ *dst = color;
+ dst += _screenWidth;
+ src++;
+ } while (++h != state->draw_height);
+ dst_org++;
+ } while (++w != state->draw_width);
+ }
+ }
+ } else {
+ if (drawImages_clip(state) == 0)
+ return;
+
+ state->surf_addr += state->x + state->y * state->surf_pitch;
+
+ const byte *src;
+ byte *dst;
+ uint count;
+
+ src = state->depack_src + state->width * state->y_skip;
+ dst = state->surf_addr;
+ do {
+ for (count = 0; count != state->draw_width; count++) {
+ byte color;
+ color = src[count + state->x_skip];
+ if (color) {
+ if ((state->flags & kDFShaded) && color == 220)
+ color = 244;
+
+ dst[count] = color;
+ }
+ }
+ dst += _screenWidth;
+ src += state->width;
+ } while (--state->draw_height);
+ }
+}
+
+void SimonEngine::drawImages(VC10_state *state) {
+ const uint16 *vlut = &_video_windows[_windowNum * 4];
+
+ if (drawImages_clip(state) == 0)
+ return;
+
+ uint offs, offs2;
+ // Allow one section of Simon the Sorcerer 1 introduction to be displayed
+ // in lower half of screen
+ if (getGameType() == GType_WW) {
+ //if (_windowNum == 4 || _windowNum >= 10) {
+ offs = state->x * 8;
+ offs2 = state->y;
+ //} else {
+ // offs = ((vlut[0] - _video_windows[16]) * 2 + state->x) * 8;
+ // offs2 = (vlut[1] - _video_windows[17] + state->y);
+ //}
+ } else if (getGameType() == GType_SIMON1) {
+ if (_windowNum != 2 || _windowNum != 3) {
+ offs = ((vlut[0]) * 2 + state->x) * 8;
+ offs2 = (vlut[1] + state->y);
+ } else {
+ offs = ((vlut[0] - _video_windows[16]) * 2 + state->x) * 8;
+ offs2 = (vlut[1] - _video_windows[17] + state->y);
+ }
+ } else {
+ offs = ((vlut[0] - _video_windows[16]) * 2 + state->x) * 8;
+ offs2 = (vlut[1] - _video_windows[17] + state->y);
+ }
+
+ state->surf2_addr += offs + offs2 * state->surf2_pitch;
+ state->surf_addr += offs + offs2 * state->surf_pitch;
+
+ if (state->flags & kDFMasked) {
+ byte *mask, *src, *dst;
+ byte h;
+ uint w;
+
+ state->x_skip *= 4;
+ state->dl = state->width;
+ state->dh = state->height;
+
+ vc10_skip_cols(state);
+
+ w = 0;
+ do {
+ mask = vc10_depackColumn(state); /* esi */
+ src = state->surf2_addr + w * 2; /* ebx */
+ dst = state->surf_addr + w * 2; /* edi */
+
+ h = state->draw_height;
+ if ((getGameType() == GType_SIMON1) && getBitFlag(88)) {
+ /* transparency */
+ do {
+ if (mask[0] & 0xF0) {
+ if ((dst[0] & 0x0F0) == 0x20)
+ dst[0] = src[0];
+ }
+ if (mask[0] & 0x0F) {
+ if ((dst[1] & 0x0F0) == 0x20)
+ dst[1] = src[1];
+ }
+ mask++;
+ dst += state->surf_pitch;
+ src += state->surf2_pitch;
+ } while (--h);
+ } else {
+ /* no transparency */
+ do {
+ if (mask[0] & 0xF0)
+ dst[0] = src[0];
+ if (mask[0] & 0x0F)
+ dst[1] = src[1];
+ mask++;
+ dst += state->surf_pitch;
+ src += state->surf2_pitch;
+ } while (--h);
+ }
+ } while (++w != state->draw_width);
+
+ /* vc10_helper_5 */
+ } else if ((((_lockWord & 0x20) && state->palette == 0) || state->palette == 0xC0) &&
+ getGameType() != GType_WW) {
+ const byte *src;
+ byte *dst;
+ uint h, i;
+
+ if (state->flags & kDFCompressed) {
+ byte *dst_org = state->surf_addr;
+ src = state->depack_src;
+ /* AAAAAAAA BBBBBBBB CCCCCCCC DDDDDDDD EEEEEEEE
+ * aaaaabbb bbcccccd ddddeeee efffffgg ggghhhhh
+ */
+
+ do {
+ uint count = state->draw_width / 4;
+
+ dst = dst_org;
+ do {
+ uint32 bits = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | (src[3]);
+ byte color;
+
+ color = (byte)((bits >> (32 - 5)) & 31);
+ if ((state->flags & kDFNonTrans) || color)
+ dst[0] = color;
+ color = (byte)((bits >> (32 - 10)) & 31);
+ if ((state->flags & kDFNonTrans) || color)
+ dst[1] = color;
+ color = (byte)((bits >> (32 - 15)) & 31);
+ if ((state->flags & kDFNonTrans) || color)
+ dst[2] = color;
+ color = (byte)((bits >> (32 - 20)) & 31);
+ if ((state->flags & kDFNonTrans) || color)
+ dst[3] = color;
+ color = (byte)((bits >> (32 - 25)) & 31);
+ if ((state->flags & kDFNonTrans) || color)
+ dst[4] = color;
+ color = (byte)((bits >> (32 - 30)) & 31);
+ if ((state->flags & kDFNonTrans) || color)
+ dst[5] = color;
+
+ bits = (bits << 8) | src[4];
+
+ color = (byte)((bits >> (40 - 35)) & 31);
+ if ((state->flags & kDFNonTrans) || color)
+ dst[6] = color;
+ color = (byte)((bits) & 31);
+ if ((state->flags & kDFNonTrans) || color)
+ dst[7] = color;
+
+ dst += 8;
+ src += 5;
+ } while (--count);
+ dst_org += _screenWidth;
+ } while (--state->draw_height);
+ } else {
+ src = state->depack_src + (state->width * state->y_skip * 16) + (state->x_skip * 8);
+ dst = state->surf_addr;
+
+ state->draw_width *= 2;
+
+ h = state->draw_height;
+ do {
+ for (i = 0; i != state->draw_width; i++)
+ if ((state->flags & kDFNonTrans) || src[i])
+ dst[i] = src[i];
+ dst += _screenWidth;
+ src += state->width * 16;
+ } while (--h);
+ }
+ /* vc10_helper_4 */
+ } else {
+ if (getGameType() == GType_SIMON2 && state->flags & kDFUseFrontBuf && getBitFlag(171)) {
+ state->surf_addr = state->surf2_addr;
+ state->surf_pitch = state->surf2_pitch;
+ }
+
+ if (state->flags & kDFCompressed) {
+ uint w, h;
+ byte *src, *dst, *dst_org;
+
+ state->x_skip *= 4; /* reached */
+
+ state->dl = state->width;
+ state->dh = state->height;
+
+ vc10_skip_cols(state);
+
+ dst_org = state->surf_addr;
+ if (!(state->flags & kDFNonTrans) && (state->flags & 0x40)) { /* reached */
+ dst_org += vcReadVar(252);
+ }
+ w = 0;
+ do {
+ byte color;
+
+ src = vc10_depackColumn(state);
+ dst = dst_org;
+
+ h = 0;
+ do {
+ color = (*src / 16);
+ if ((state->flags & kDFNonTrans) || color != 0)
+ dst[0] = color | state->palette;
+ color = (*src & 15);
+ if ((state->flags & kDFNonTrans) || color != 0)
+ dst[1] = color | state->palette;
+ dst += _screenWidth;
+ src++;
+ } while (++h != state->draw_height);
+ dst_org += 2;
+ } while (++w != state->draw_width);
+ /* vc10_helper_6 */
+ } else {
+ const byte *src;
+ byte *dst;
+ uint count;
+
+ src = state->depack_src + (state->width * state->y_skip) * 8;
+ dst = state->surf_addr;
+ state->x_skip *= 4;
+ do {
+ for (count = 0; count != state->draw_width; count++) {
+ byte color;
+ color = (src[count + state->x_skip] / 16);
+ if ((state->flags & kDFNonTrans) || color)
+ dst[count * 2] = color | state->palette;
+ color = (src[count + state->x_skip] & 15);
+ if ((state->flags & kDFNonTrans) || color)
+ dst[count * 2 + 1] = color | state->palette;
+ }
+ dst += _screenWidth;
+ src += state->width * 8;
+ } while (--state->draw_height);
+ /* vc10_helper_7 */
+ }
+ }
+}
+
+void SimonEngine::horizontalScroll(VC10_state *state) {
+ const byte *src;
+ byte *dst;
+ int w;
+
+ if (getGameType() == GType_FF)
+ _scrollXMax = state->width - 640;
+ else
+ _scrollXMax = state->width * 2 - 40;
+ _scrollYMax = 0;
+ _scrollImage = state->depack_src;
+ _scrollHeight = state->height;
+ if (_variableArrayPtr[34] < 0)
+ state->x = _variableArrayPtr[251];
+
+ _scrollX = state->x;
+
+ vcWriteVar(251, _scrollX);
+
+ dst = getBackBuf();
+
+ if (getGameType() == GType_FF)
+ src = state->depack_src + _scrollX / 2;
+ else
+ src = state->depack_src + _scrollX * 4;
+
+ for (w = 0; w < _screenWidth; w += 8) {
+ decodeColumn(dst, src + readUint32Wrapper(src), state->height);
+ dst += 8;
+ src += 4;
+ }
+}
+
+void SimonEngine::verticalScroll(VC10_state *state) {
+ const byte *src;
+ byte *dst;
+ int h;
+
+ _scrollXMax = 0;
+ _scrollYMax = state->height - 480;
+ _scrollImage = state->depack_src;
+ _scrollWidth = state->width;
+ if (_variableArrayPtr[34] < 0)
+ state->y = _variableArrayPtr[250];
+
+ _scrollY = state->y;
+
+ vcWriteVar(250, _scrollY);
+
+ dst = getBackBuf();
+ src = state->depack_src + _scrollY / 2;
+
+ for (h = 0; h < _screenHeight; h += 8) {
+ decodeRow(dst, src + READ_LE_UINT32(src), state->width);
+ dst += 8 * state->width;
+ src += 4;
+ }
+}
+
+void SimonEngine::scaleClip(int16 h, int16 w, int16 y, int16 x, int16 scrollY) {
+ Common::Rect srcRect, dstRect;
+ float factor, xscale;
+
+ srcRect.left = 0;
+ srcRect.top = 0;
+ srcRect.right = w;
+ srcRect.bottom = h;
+
+ if (scrollY > _baseY)
+ factor = 1 + ((scrollY - _baseY) * _scale);
+ else
+ factor = 1 - ((_baseY - scrollY) * _scale);
+
+ xscale = ((w * factor) / 2);
+
+ dstRect.left = (int16)(x - xscale);
+ if (dstRect.left > _screenWidth - 1)
+ return;
+ dstRect.top = (int16)(y - (h * factor));
+ if (dstRect.top > _screenHeight - 1)
+ return;
+
+ dstRect.right = (int16)(x + xscale);
+ dstRect.bottom = y;
+
+ _feebleRect = dstRect;
+
+ _variableArray[20] = _feebleRect.top;
+ _variableArray[21] = _feebleRect.left;
+ _variableArray[22] = _feebleRect.bottom;
+ _variableArray[23] = _feebleRect.right;
+
+ debug(5, "Left %d Right %d Top %d Bottom %d", dstRect.left, dstRect.right, dstRect.top, dstRect.bottom);
+
+ // Unlike normal rectangles in ScummVM, it seems that in the case of
+ // the destination rectangle the bottom and right coordinates are
+ // considered to be inside the rectangle. For the source rectangle,
+ // I believe that they are not.
+
+ int scaledW = dstRect.width() + 1;
+ int scaledH = dstRect.height() + 1;
+
+ byte *src = getScaleBuf();
+ byte *dst = getBackBuf();
+
+ dst += _dxSurfacePitch * dstRect.top + dstRect.left;
+
+ for (int dstY = 0; dstY < scaledH; dstY++) {
+ if (dstRect.top + dstY >= 0 && dstRect.top + dstY < _screenHeight) {
+ int srcY = (dstY * h) / scaledH;
+ byte *srcPtr = src + _dxSurfacePitch * srcY;
+ byte *dstPtr = dst + _dxSurfacePitch * dstY;
+ for (int dstX = 0; dstX < scaledW; dstX++) {
+ if (dstRect.left + dstX >= 0 && dstRect.left + dstX < _screenWidth) {
+ int srcX = (dstX * w) / scaledW;
+ if (srcPtr[srcX])
+ dstPtr[dstX] = srcPtr[srcX];
+ }
+ }
+ }
+ }
+}
+
+void SimonEngine::vc11_clearPathFinder() {
+ if (getGameType() == GType_WW) {
+ // FIXME
+ vcReadNextWord();
+ } else {
+ memset(&_pathFindArray, 0, sizeof(_pathFindArray));
+ }
+}
+
+void SimonEngine::vc12_delay() {
+ VgaSprite *vsp = findCurSprite();
+ uint16 num;
+
+ if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ num = vcReadNextByte();
+ } else if (getGameType() == GType_SIMON2) {
+ num = vcReadNextByte() * _frameRate;
+ } else {
+ num = vcReadVarOrWord();
+ }
+
+ // Work around to allow inventory arrows to be
+ // shown in some versions of Simon the Sorcerer 1
+ if ((getGameType() == GType_SIMON1) && vsp->id == 128)
+ num = 0;
+ else
+ num += _vgaBaseDelay;
+
+ addVgaEvent(num, _vcPtr, _vgaCurSpriteId, _vgaCurZoneNum);
+ _vcPtr = (byte *)&_vc_get_out_of_code;
+}
+
+void SimonEngine::vc13_addToSpriteX() {
+ VgaSprite *vsp = findCurSprite();
+ vsp->x += (int16)vcReadNextWord();
+ _vgaSpriteChanged++;
+}
+
+void SimonEngine::vc14_addToSpriteY() {
+ VgaSprite *vsp = findCurSprite();
+ vsp->y += (int16)vcReadNextWord();
+ _vgaSpriteChanged++;
+}
+
+void SimonEngine::vc15_sync() {
+ VgaSleepStruct *vfs = _vgaSleepStructs, *vfs_tmp;
+ uint16 id = vcReadNextWord();
+ while (vfs->ident != 0) {
+ if (vfs->ident == id) {
+ addVgaEvent(_vgaBaseDelay, vfs->code_ptr, vfs->sprite_id, vfs->cur_vga_file);
+ vfs_tmp = vfs;
+ do {
+ memcpy(vfs_tmp, vfs_tmp + 1, sizeof(VgaSleepStruct));
+ vfs_tmp++;
+ } while (vfs_tmp->ident != 0);
+ } else {
+ vfs++;
+ }
+ }
+
+ _lastVgaWaitFor = id;
+ /* clear a wait event */
+ if (id == _vgaWaitFor)
+ _vgaWaitFor = 0;
+}
+
+void SimonEngine::vc16_waitSync() {
+ VgaSleepStruct *vfs = _vgaSleepStructs;
+ while (vfs->ident)
+ vfs++;
+
+ vfs->ident = vcReadNextWord();
+ vfs->code_ptr = _vcPtr;
+ vfs->sprite_id = _vgaCurSpriteId;
+ vfs->cur_vga_file = _vgaCurZoneNum;
+
+ _vcPtr = (byte *)&_vc_get_out_of_code;
+}
+
+void SimonEngine::vc17_setPathfinderItem() {
+ if (getGameType() == GType_WW) {
+ // FIXME
+ vcReadNextWord();
+ } else {
+ uint16 a = vcReadNextWord();
+ _pathFindArray[a - 1] = (const uint16 *)_vcPtr;
+
+ int end = (getGameType() == GType_FF || getGameType() == GType_PP) ? 9999 : 999;
+ while (readUint16Wrapper(_vcPtr) != end)
+ _vcPtr += 4;
+ _vcPtr += 2;
+ }
+}
+
+void SimonEngine::vc18_jump() {
+ int16 offs = vcReadNextWord();
+ _vcPtr += offs;
+}
+
+/* chain to script? */
+void SimonEngine::vc19_chain_to_script() {
+ /* unused */
+ error("vc19_chain_to_script: not implemented");
+}
+
+/* helper routines */
+
+void SimonEngine::vc20_setRepeat() {
+ /* FIXME: This opcode is somewhat strange: it first reads a BE word from
+ * the script (advancing the script pointer in doing so); then it writes
+ * back the same word, this time as LE, into the script.
+ */
+ uint16 a = vcReadNextWord();
+ WRITE_LE_UINT16(const_cast<byte *>(_vcPtr), a);
+ _vcPtr += 2;
+}
+
+void SimonEngine::vc21_endRepeat() {
+ int16 a = vcReadNextWord();
+ const byte *tmp = _vcPtr + a;
+ if (getGameType() == GType_SIMON1 || getGameType() == GType_WW)
+ tmp += 4;
+ else
+ tmp += 3;
+
+ uint16 val = READ_LE_UINT16(tmp);
+ if (val != 0) {
+ // Decrement counter
+ WRITE_LE_UINT16(const_cast<byte *>(tmp), val - 1);
+ _vcPtr = tmp + 2;
+ }
+}
+
+void SimonEngine::vc22_setSpritePalette() {
+ byte *offs, *palptr, *src;
+ uint16 a, b, num, palSize;
+
+ if (getGameType() != GType_WW)
+ a = vcReadNextWord();
+ b = vcReadNextWord();
+
+ if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ num = 256;
+ palSize = 768;
+
+ palptr = _displayPalette;
+ offs = _curVgaFile1 + 6;
+ } else if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) {
+ num = a == 0 ? 32 : 16;
+ palSize = 96;
+
+ palptr = &_displayPalette[(a * 64)];
+ offs = _curVgaFile1 + 6;
+ } else {
+ num = 16;
+ palSize = 32;
+ palptr = _displayPalette;
+ offs = _curVgaFile1 + READ_BE_UINT16(_curVgaFile1 + 6);
+ }
+
+ src = offs + b * palSize;
+
+ do {
+ if (getGameType() == GType_WW) {
+ uint16 color = READ_BE_UINT16(src);
+ palptr[2] = ((color & 0x00f) >> 0) * 32;
+ palptr[1] = ((color & 0x0f0) >> 4) * 32;
+ palptr[0] = ((color & 0xf00) >> 8) * 32;
+ } else {
+ palptr[0] = src[0] * 4;
+ palptr[1] = src[1] * 4;
+ palptr[2] = src[2] * 4;
+ }
+ palptr[3] = 0;
+
+ palptr += 4;
+ src += (getGameType() == GType_WW) ? 2 : 3;
+ } while (--num);
+
+ _paletteFlag = 2;
+ _vgaSpriteChanged++;
+}
+
+void SimonEngine::vc23_setSpritePriority() {
+ VgaSprite *vsp = findCurSprite(), *vus2;
+ uint16 pri = vcReadNextWord();
+ VgaSprite bak;
+
+ if (vsp->id == 0)
+ return;
+
+ memcpy(&bak, vsp, sizeof(bak));
+ bak.priority = pri;
+ bak.windowNum |= 0x8000;
+
+ vus2 = vsp;
+
+ if (vsp != _vgaSprites && pri < vsp[-1].priority) {
+ do {
+ vsp--;
+ } while (vsp != _vgaSprites && pri < vsp[-1].priority);
+ do {
+ memcpy(vus2, vus2 - 1, sizeof(VgaSprite));
+ } while (--vus2 != vsp);
+ memcpy(vus2, &bak, sizeof(VgaSprite));
+ } else if (vsp[1].id != 0 && pri >= vsp[1].priority) {
+ do {
+ vsp++;
+ } while (vsp[1].id != 0 && pri >= vsp[1].priority);
+ do {
+ memcpy(vus2, vus2 + 1, sizeof(VgaSprite));
+ } while (++vus2 != vsp);
+ memcpy(vus2, &bak, sizeof(VgaSprite));
+ } else {
+ vsp->priority = pri;
+ }
+ _vgaSpriteChanged++;
+}
+
+void SimonEngine::vc24_setSpriteXY() {
+ VgaSprite *vsp = findCurSprite();
+ vsp->image = vcReadVarOrWord();
+
+ vsp->x += (int16)vcReadNextWord();
+ vsp->y += (int16)vcReadNextWord();
+ if (getGameType() == GType_SIMON1 || getGameType() == GType_WW) {
+ vsp->flags = vcReadNextWord();
+ } else {
+ vsp->flags = vcReadNextByte();
+ }
+
+ _vgaSpriteChanged++;
+}
+
+void SimonEngine::vc25_halt_sprite() {
+ VgaSprite *vsp = findCurSprite();
+ while (vsp->id != 0) {
+ memcpy(vsp, vsp + 1, sizeof(VgaSprite));
+ vsp++;
+ }
+ _vcPtr = (byte *)&_vc_get_out_of_code;
+ _vgaSpriteChanged++;
+}
+
+void SimonEngine::vc26_setSubWindow() {
+ uint16 *as = &_video_windows[vcReadNextWord() * 4]; // number
+ as[0] = vcReadNextWord(); // x
+ as[1] = vcReadNextWord(); // y
+ as[2] = vcReadNextWord(); // width
+ as[3] = vcReadNextWord(); // height
+}
+
+void SimonEngine::vc27_resetSprite() {
+ VgaSprite bak, *vsp;
+ VgaSleepStruct *vfs;
+ VgaTimerEntry *vte, *vte2;
+
+ _lockWord |= 8;
+
+ _lastVgaWaitFor = 0;
+
+ memset(&bak, 0, sizeof(bak));
+
+ vsp = _vgaSprites;
+ while (vsp->id) {
+ if ((getGameType() == GType_SIMON1) && vsp->id == 128) {
+ memcpy(&bak, vsp, sizeof(VgaSprite));
+ }
+ vsp->id = 0;
+ vsp++;
+ }
+
+ if (bak.id != 0)
+ memcpy(_vgaSprites, &bak, sizeof(VgaSprite));
+
+ vfs = _vgaSleepStructs;
+ while (vfs->ident) {
+ vfs->ident = 0;
+ vfs++;
+ }
+
+ vte = _vgaTimerList;
+ while (vte->delay) {
+ if ((getGameType() == GType_SIMON1) && vte->sprite_id == 128) {
+ vte++;
+ } else {
+ vte2 = vte;
+ while (vte2->delay) {
+ memcpy(vte2, vte2 + 1, sizeof(VgaTimerEntry));
+ vte2++;
+ }
+ }
+ }
+
+ vcWriteVar(254, 0);
+
+ if (getGameType() == GType_FF)
+ setBitFlag(42, true);
+
+ _lockWord &= ~8;
+}
+
+void SimonEngine::vc28_dummy_op() {
+ /* unused */
+ _vcPtr += 8;
+}
+
+void SimonEngine::vc29_stopAllSounds() {
+ if (getGameType() != GType_PP)
+ _sound->stopVoice();
+
+ _sound->stopAllSfx();
+}
+
+void SimonEngine::vc30_setFrameRate() {
+ _frameRate = vcReadNextWord();
+}
+
+void SimonEngine::vc31_setWindow() {
+ _windowNum = vcReadNextWord();
+}
+
+void SimonEngine::vc32_copyVar() {
+ if (getGameType() == GType_WW) {
+ // FIXME
+ } else {
+ uint16 a = vcReadVar(vcReadNextWord());
+ vcWriteVar(vcReadNextWord(), a);
+ }
+}
+
+void SimonEngine::vc33_setMouseOn() {
+ if (_mouseHideCount != 0) {
+ _mouseHideCount = 1;
+ mouseOn();
+ }
+}
+
+void SimonEngine::vc34_setMouseOff() {
+ mouseOff();
+ _mouseHideCount = 200;
+ _leftButtonDown = 0;
+}
+
+void SimonEngine::vc35_clearWindow() {
+ /* unused */
+ _vcPtr += 4;
+ _vgaSpriteChanged++;
+}
+
+void SimonEngine::vc36_setWindowImage() {
+ _updateScreen = false;
+ uint16 vga_res = vcReadNextWord();
+ uint16 windowNum = vcReadNextWord();
+
+ if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ _copyPartialMode = 2;
+ } else if (getGameType() == GType_SIMON2) {
+ set_video_mode_internal(windowNum, vga_res);
+ } else if (getGameType() == GType_SIMON1) {
+ if (windowNum == 16) {
+ _copyPartialMode = 2;
+ } else {
+ set_video_mode_internal(windowNum, vga_res);
+ }
+ }
+}
+
+void SimonEngine::vc37_addToSpriteY() {
+ if (getGameType() == GType_WW) {
+ // FIXME
+ vcReadNextWord();
+ vcReadNextWord();
+ } else {
+ VgaSprite *vsp = findCurSprite();
+ vsp->y += vcReadVar(vcReadNextWord());
+ _vgaSpriteChanged++;
+ }
+}
+
+void SimonEngine::vc38_skipIfVarZero() {
+ uint16 var = vcReadNextWord();
+ if (vcReadVar(var) == 0)
+ vcSkipNextInstruction();
+}
+
+void SimonEngine::vc39_setVar() {
+ uint16 var = vcReadNextWord();
+ int16 value = vcReadNextWord();
+ vcWriteVar(var, value);
+}
+
+void SimonEngine::vc40() {
+ uint16 var = vcReadNextWord();
+ int16 value = vcReadVar(var) + vcReadNextWord();
+
+ if ((getGameType() == GType_SIMON2) && var == 15 && !getBitFlag(80)) {
+ int16 tmp;
+
+ if (_scrollCount != 0) {
+ if (_scrollCount >= 0)
+ goto no_scroll;
+ _scrollCount = 0;
+ } else {
+ if (_scrollFlag != 0)
+ goto no_scroll;
+ }
+
+ if (value - _scrollX >= 30) {
+ _scrollCount = 20;
+ tmp = _scrollXMax - _scrollX;
+ if (tmp < 20)
+ _scrollCount = tmp;
+ addVgaEvent(6, NULL, 0, 0); /* scroll event */
+ }
+ }
+no_scroll:;
+
+ vcWriteVar(var, value);
+}
+
+void SimonEngine::vc41() {
+ uint16 var = vcReadNextWord();
+ int16 value = vcReadVar(var) - vcReadNextWord();
+
+ if ((getGameType() == GType_SIMON2) && var == 15 && !getBitFlag(80)) {
+ if (_scrollCount != 0) {
+ if (_scrollCount < 0)
+ goto no_scroll;
+ _scrollCount = 0;
+ } else {
+ if (_scrollFlag != 0)
+ goto no_scroll;
+ }
+
+ if ((uint16)(value - _scrollX) < 11) {
+ _scrollCount = -20;
+ if (_scrollX < 20)
+ _scrollCount = -_scrollX;
+ addVgaEvent(6, NULL, 0, 0); /* scroll event */
+ }
+ }
+no_scroll:;
+
+ vcWriteVar(var, value);
+}
+
+void SimonEngine::vc42_delayIfNotEQ() {
+ uint16 val = vcReadVar(vcReadNextWord());
+ if (val != vcReadNextWord()) {
+
+ addVgaEvent(_frameRate + 1, _vcPtr - 4, _vgaCurSpriteId, _vgaCurZoneNum);
+ _vcPtr = (byte *)&_vc_get_out_of_code;
+ }
+}
+
+void SimonEngine::vc43_skipIfBitClear() {
+ if (!getBitFlag(vcReadNextWord())) {
+ vcSkipNextInstruction();
+ }
+}
+
+void SimonEngine::vc44_skipIfBitSet() {
+ if (getBitFlag(vcReadNextWord())) {
+ vcSkipNextInstruction();
+ }
+}
+
+void SimonEngine::vc45_setSpriteX() {
+ if (getGameType() == GType_WW) {
+ //FIXME
+ vcReadNextWord();
+ vcReadNextWord();
+ } else {
+ VgaSprite *vsp = findCurSprite();
+ vsp->x = vcReadVar(vcReadNextWord());
+ _vgaSpriteChanged++;
+ }
+}
+
+void SimonEngine::vc46_setSpriteY() {
+ VgaSprite *vsp = findCurSprite();
+ vsp->y = vcReadVar(vcReadNextWord());
+ _vgaSpriteChanged++;
+}
+
+void SimonEngine::vc47_addToVar() {
+ if (getGameType() == GType_WW) {
+ //FIXME
+ vcReadNextWord();
+ } else {
+ uint16 var = vcReadNextWord();
+ vcWriteVar(var, vcReadVar(var) + vcReadVar(vcReadNextWord()));
+ }
+}
+
+void SimonEngine::vc48_setPathFinder() {
+ uint16 a = (uint16)_variableArrayPtr[12];
+ const uint16 *p = _pathFindArray[a - 1];
+
+ if (getGameType() == GType_WW) {
+ //FIXME
+ vcReadNextWord();
+ } else if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ VgaSprite *vsp = findCurSprite();
+ int16 x, y, ydiff;
+ int16 x1, y1, x2, y2;
+ uint pos = 0;
+
+ x = vsp->x;
+ while (x >= (int16)readUint16Wrapper(p + 2)) {
+ p += 2;
+ pos++;
+ }
+
+ x1 = readUint16Wrapper(p);
+ y1 = readUint16Wrapper(p + 1);
+ x2 = readUint16Wrapper(p + 2);
+ y2 = readUint16Wrapper(p + 3);
+
+ if (x2 != 9999) {
+ ydiff = y2 - y1;
+ if (ydiff < 0) {
+ ydiff = -ydiff;
+ x = vsp->x & 7;
+ ydiff *= x;
+ ydiff /= 8;
+ ydiff = -ydiff;
+ } else {
+ x = vsp->x & 7;
+ ydiff *= x;
+ ydiff /= 8;
+ }
+ y1 += ydiff;
+ }
+
+ y = vsp->y;
+ vsp->y = y1;
+ checkScrollY(y1 - y, y1);
+
+ _variableArrayPtr[11] = x1;
+ _variableArrayPtr[13] = pos;
+ } else {
+ uint b = (uint16)_variableArray[13];
+ p += b * 2 + 1;
+ int c = _variableArray[14];
+
+ int step;
+ int y1, y2;
+ int16 *vp;
+
+ step = 2;
+ if (c < 0) {
+ c = -c;
+ step = -2;
+ }
+
+ vp = &_variableArray[20];
+
+ do {
+ y2 = readUint16Wrapper(p);
+ p += step;
+ y1 = readUint16Wrapper(p) - y2;
+
+ vp[0] = y1 / 2;
+ vp[1] = y1 - (y1 / 2);
+
+ vp += 2;
+ } while (--c);
+ }
+}
+
+void SimonEngine::setBitFlag(uint bit, bool value) {
+ uint16 *bits = &_bitArray[bit / 16];
+ *bits = (*bits & ~(1 << (bit & 15))) | (value << (bit & 15));
+}
+
+bool SimonEngine::getBitFlag(uint bit) {
+ uint16 *bits = &_bitArray[bit / 16];
+ return (*bits & (1 << (bit & 15))) != 0;
+}
+
+void SimonEngine::vc49_setBit() {
+ uint16 bit = vcReadNextWord();
+ if (getGameType() == GType_FF && bit == 82) {
+ _variableArrayPtr = _variableArray2;
+ }
+ setBitFlag(bit, true);
+}
+
+void SimonEngine::vc50_clearBit() {
+ uint16 bit = vcReadNextWord();
+ if (getGameType() == GType_FF && bit == 82) {
+ _variableArrayPtr = _variableArray;
+ }
+ setBitFlag(bit, false);
+}
+
+void SimonEngine::vc51_enableBox() {
+ enableBox(vcReadNextWord());
+}
+
+void SimonEngine::vc52_playSound() {
+ bool ambient = false;
+
+ uint16 sound = vcReadNextWord();
+ if (sound >= 0x8000) {
+ ambient = true;
+ sound = -sound;
+ }
+
+ if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ int16 pan = vcReadNextWord();
+ int16 vol = vcReadNextWord();
+
+ if (ambient)
+ loadSound(sound, pan, vol, 2);
+ else
+ loadSound(sound, pan, vol, 1);
+ } else if (getGameType() == GType_SIMON2) {
+ if (ambient)
+ _sound->playAmbient(sound);
+ else
+ _sound->playEffects(sound);
+ } else if (getFeatures() & GF_TALKIE) {
+ _sound->playEffects(sound);
+ } else if (getGameId() == GID_SIMON1DOS) {
+ playSting(sound);
+ }
+}
+
+void SimonEngine::vc53_panSFX() {
+ VgaSprite *vsp = findCurSprite();
+ int pan;
+
+ uint16 sound = vcReadNextWord();
+ int16 xoffs = vcReadNextWord();
+ int16 vol = vcReadNextWord();
+
+ pan = (vsp->x - _scrollX + xoffs) * 8 - 2560;
+ if (pan < -10000)
+ pan = -10000;
+ if (pan > 10000)
+ pan = 10000;
+
+ loadSound(sound, 0, vol, 1);
+
+ if (xoffs != 2)
+ xoffs |= 0x10;
+
+ addVgaEvent(10, NULL, _vgaCurSpriteId, _vgaCurZoneNum, xoffs); /* pan event */
+ debug(0, "vc53_panSFX: snd %d xoffs %d vol %d", sound, xoffs, vol);
+}
+
+void SimonEngine::vc54_no_op() {
+ /* unused */
+ _vcPtr += 6;
+}
+
+void SimonEngine::vc55_moveBox() {
+ HitArea *ha = _hitAreas;
+ uint count = ARRAYSIZE(_hitAreas);
+ uint16 id = vcReadNextWord();
+ int16 x = vcReadNextWord();
+ int16 y = vcReadNextWord();
+
+ for (;;) {
+ if (ha->id == id) {
+ ha->x += x;
+ ha->y += y;
+ break;
+ }
+ ha++;
+ if (!--count)
+ break;
+ }
+
+ _needHitAreaRecalc++;
+}
+
+void SimonEngine::vc56_delay() {
+ if (getGameType() == GType_WW) {
+ byte *src = _curVgaFile2 + 32;
+ byte *dst = getBackBuf();
+
+ uint8 palette[1024];
+ for (int i = 0; i < 256; i++) {
+ palette[i * 4 + 0] = *src++ * 4;
+ palette[i * 4 + 1] = *src++ * 4;
+ palette[i * 4 + 2] = *src++ * 4;
+ palette[i * 4 + 3] = 0;
+ }
+
+ _system->setPalette(palette, 0, 256);
+ memcpy(dst, src, _screenHeight * _screenWidth);
+ } else {
+ uint16 num = vcReadVarOrWord() * _frameRate;
+
+ addVgaEvent(num + _vgaBaseDelay, _vcPtr, _vgaCurSpriteId, _vgaCurZoneNum);
+ _vcPtr = (byte *)&_vc_get_out_of_code;
+ }
+}
+
+void SimonEngine::vc57_blackPalette() {
+ if (getGameType() == GType_WW) {
+ uint8 palette[1024];
+ memset(palette, 0, sizeof(palette));
+ _system->setPalette(palette, 0, 256);
+ }
+}
+
+void SimonEngine::vc58() {
+ if (getGameType() == GType_WW)
+ return;
+
+ uint16 sprite = _vgaCurSpriteId;
+ uint16 file = _vgaCurZoneNum;
+ const byte *vcPtrOrg;
+ uint16 tmp;
+
+ _vgaCurZoneNum = vcReadNextWord();
+ _vgaCurSpriteId = vcReadNextWord();
+
+ tmp = to16Wrapper(vcReadNextWord());
+
+ vcPtrOrg = _vcPtr;
+ _vcPtr = (byte *)&tmp;
+ vc23_setSpritePriority();
+
+ _vcPtr = vcPtrOrg;
+ _vgaCurSpriteId = sprite;
+ _vgaCurZoneNum = file;
+}
+
+void SimonEngine::vc59() {
+ if (getGameType() == GType_SIMON2 || getGameType() == GType_FF || getGameType() == GType_PP) {
+ uint16 file = vcReadNextWord();
+ uint16 start = vcReadNextWord();
+ uint16 end = vcReadNextWord() + 1;
+
+ do {
+ vc_kill_sprite(file, start);
+ } while (++start != end);
+ } else if (getGameType() == GType_SIMON1) {
+ if (!_sound->isVoiceActive())
+ vcSkipNextInstruction();
+ } else {
+ // Skip if not EGA
+ vcSkipNextInstruction();
+ }
+}
+
+void SimonEngine::vc_kill_sprite(uint file, uint sprite) {
+ uint16 old_sprite_id, old_cur_file_id;
+ VgaSleepStruct *vfs;
+ VgaSprite *vsp;
+ VgaTimerEntry *vte;
+ const byte *vcPtrOrg;
+
+ old_sprite_id = _vgaCurSpriteId;
+ old_cur_file_id = _vgaCurZoneNum;
+ vcPtrOrg = _vcPtr;
+
+ _vgaCurZoneNum = file;
+ _vgaCurSpriteId = sprite;
+
+ vfs = _vgaSleepStructs;
+ while (vfs->ident != 0) {
+ if (vfs->sprite_id == _vgaCurSpriteId && ((getGameType() == GType_SIMON1) || vfs->cur_vga_file == _vgaCurZoneNum)) {
+ while (vfs->ident != 0) {
+ memcpy(vfs, vfs + 1, sizeof(VgaSleepStruct));
+ vfs++;
+ }
+ break;
+ }
+ vfs++;
+ }
+
+ vsp = findCurSprite();
+ if (vsp->id) {
+ vc25_halt_sprite();
+
+ vte = _vgaTimerList;
+ while (vte->delay != 0) {
+ if (vte->sprite_id == _vgaCurSpriteId && ((getGameType() == GType_SIMON1) || vte->cur_vga_file == _vgaCurZoneNum)) {
+ deleteVgaEvent(vte);
+ break;
+ }
+ vte++;
+ }
+ }
+
+ _vgaCurZoneNum = old_cur_file_id;
+ _vgaCurSpriteId = old_sprite_id;
+ _vcPtr = vcPtrOrg;
+}
+
+void SimonEngine::vc60_killSprite() {
+ uint16 zoneNum;
+
+ if (getGameType() == GType_SIMON1) {
+ zoneNum = _vgaCurZoneNum;
+ } else {
+ zoneNum = vcReadNextWord();
+ }
+ uint16 sprite = vcReadNextWord();
+ vc_kill_sprite(zoneNum, sprite);
+}
+
+void SimonEngine::vc61_setMaskImage() {
+ if (getGameType() == GType_WW) {
+ // FIXME
+ vcReadVarOrWord();
+ } else {
+ VgaSprite *vsp = findCurSprite();
+
+ vsp->image = vcReadVarOrWord();
+ vsp->x += vcReadNextWord();
+ vsp->y += vcReadNextWord();
+ vsp->flags = kDFMasked | kDFUseFrontBuf;
+
+ _vgaSpriteChanged++;
+ }
+}
+
+void SimonEngine::vc62_fastFadeOut() {
+ vc29_stopAllSounds();
+
+ if (!_fastFadeOutFlag) {
+ uint i, fadeSize, fadeCount;
+
+ if (getGameType() != GType_WW)
+ _fastFadeOutFlag = true;
+
+ _fastFadeCount = 256;
+ if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) {
+ if (_windowNum == 4)
+ _fastFadeCount = 208;
+ }
+
+ memcpy(_videoBuf1, _currentPalette, _fastFadeCount * 4);
+
+ if ((getGameType() == GType_FF || getGameType() == GType_PP) && !getBitFlag(75)) {
+ fadeCount = 32;
+ fadeSize = 8;
+ } else {
+ fadeCount = 4;
+ fadeSize = 64;
+ }
+
+ for (i = fadeCount; i != 0; --i) {
+ paletteFadeOut(_videoBuf1, _fastFadeCount, fadeSize);
+ _system->setPalette(_videoBuf1, 0, _fastFadeCount);
+ delay(5);
+ }
+
+ if (getGameType() == GType_SIMON1) {
+ uint16 params[5]; /* parameters to vc10_draw */
+ VgaSprite *vsp;
+ VgaPointersEntry *vpe;
+ const byte *vcPtrOrg = _vcPtr;
+
+ vsp = _vgaSprites;
+ while (vsp->id != 0) {
+ if (vsp->id == 128) {
+ byte *old_file_1 = _curVgaFile1;
+ byte *old_file_2 = _curVgaFile2;
+ uint palmode = _windowNum;
+
+ vpe = &_vgaBufferPointers[vsp->zoneNum];
+ _curVgaFile1 = vpe->vgaFile1;
+ _curVgaFile2 = vpe->vgaFile2;
+ _windowNum = vsp->windowNum;
+
+ params[0] = READ_BE_UINT16(&vsp->image);
+ params[1] = READ_BE_UINT16(&vsp->palette);
+ params[2] = READ_BE_UINT16(&vsp->x);
+ params[3] = READ_BE_UINT16(&vsp->y);
+ params[4] = READ_BE_UINT16(&vsp->flags);
+ _vcPtr = (byte *)params;
+ vc10_draw();
+
+ _windowNum = palmode;
+ _curVgaFile1 = old_file_1;
+ _curVgaFile2 = old_file_2;
+ break;
+ }
+ vsp++;
+ }
+ _vcPtr = vcPtrOrg;
+ }
+
+ // Allow one section of Simon the Sorcerer 1 introduction to be displayed
+ // in lower half of screen
+ if ((getGameType() == GType_SIMON1) && (_subroutine == 2923 || _subroutine == 2926)) {
+ dx_clear_surfaces(200);
+ } else if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ dx_clear_surfaces(480);
+ } else {
+ dx_clear_surfaces(_windowNum == 4 ? 134 : 200);
+ }
+ }
+ if (getGameType() == GType_SIMON2) {
+ if (_nextMusicToPlay != -1)
+ loadMusic(_nextMusicToPlay);
+ }
+}
+
+void SimonEngine::vc63_fastFadeIn() {
+ if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ _fastFadeInFlag = 256;
+ } else {
+ _fastFadeInFlag = 208;
+ if (_windowNum != 4) {
+ _fastFadeInFlag = 256;
+ }
+ }
+ _fastFadeOutFlag = false;
+}
+
+void SimonEngine::vc64_skipIfSpeechEnded() {
+ if ((getGameType() == GType_SIMON2 && _subtitles && _language != Common::HB_ISR) ||
+ !_sound->isVoiceActive()) {
+ vcSkipNextInstruction();
+ }
+}
+
+void SimonEngine::vc65_slowFadeIn() {
+ _fastFadeInFlag = 624;
+ _fastFadeCount = 208;
+ if (_windowNum != 4) {
+ _fastFadeInFlag = 768;
+ _fastFadeCount = 256;
+ }
+ _fastFadeInFlag |= 0x8000;
+ _fastFadeOutFlag = false;
+}
+
+void SimonEngine::vc66_skipIfNotEqual() {
+ uint16 a = vcReadNextWord();
+ uint16 b = vcReadNextWord();
+
+ if (vcReadVar(a) != vcReadVar(b))
+ vcSkipNextInstruction();
+}
+
+void SimonEngine::vc67_skipIfGE() {
+ uint16 a = vcReadNextWord();
+ uint16 b = vcReadNextWord();
+
+ if (vcReadVar(a) >= vcReadVar(b))
+ vcSkipNextInstruction();
+}
+
+void SimonEngine::vc68_skipIfLE() {
+ uint16 a = vcReadNextWord();
+ uint16 b = vcReadNextWord();
+
+ if (vcReadVar(a) <= vcReadVar(b))
+ vcSkipNextInstruction();
+}
+
+void SimonEngine::vc69_playTrack() {
+ int16 track = vcReadNextWord();
+ int16 loop = vcReadNextWord();
+
+ // Jamieson630:
+ // This is a "play track". The original
+ // design stored the track to play if one was
+ // already in progress, so that the next time a
+ // "fill MIDI stream" event occured, the MIDI
+ // player would find the change and switch
+ // tracks. We use a different architecture that
+ // allows for an immediate response here, but
+ // we'll simulate the variable changes so other
+ // scripts don't get thrown off.
+ // NOTE: This opcode looks very similar in function
+ // to vc72(), except that vc72() may allow for
+ // specifying a non-valid track number (999 or -1)
+ // as a means of stopping what music is currently
+ // playing.
+ midi.setLoop(loop != 0);
+ midi.startTrack(track);
+}
+
+void SimonEngine::vc70_queueMusic() {
+ // Simon2
+ uint16 track = vcReadNextWord();
+ uint16 loop = vcReadNextWord();
+
+ // Jamieson630:
+ // This sets the "on end of track" action.
+ // It specifies whether to loop the current
+ // track and, if not, whether to switch to
+ // a different track upon completion.
+ if (track != 0xFFFF && track != 999)
+ midi.queueTrack(track, loop != 0);
+ else
+ midi.setLoop(loop != 0);
+}
+
+void SimonEngine::vc71_checkMusicQueue() {
+ // Jamieson630:
+ // This command skips the next instruction
+ // unless (1) there is a track playing, AND
+ // (2) there is a track queued to play after it.
+ if (!midi.isPlaying (true))
+ vcSkipNextInstruction();
+}
+
+void SimonEngine::vc72_play_track_2() {
+ // Jamieson630:
+ // This is a "play or stop track". Note that
+ // this opcode looks very similar in function
+ // to vc69(), except that this opcode may allow
+ // for specifying a track of 999 or -1 in order to
+ // stop the music. We'll code it that way for now.
+
+ // NOTE: It's possible that when "stopping" a track,
+ // we're supposed to just go on to the next queued
+ // track, if any. Must find out if there is ANY
+ // case where this is used to stop a track in the
+ // first place.
+
+ int16 track = vcReadNextWord();
+ int16 loop = vcReadNextWord();
+
+ if (track == -1 || track == 999) {
+ midi.stop();
+ } else {
+ midi.setLoop (loop != 0);
+ midi.startTrack (track);
+ }
+}
+
+void SimonEngine::vc73_setMark() {
+ _marks |= (1 << vcReadNextWord());
+}
+
+void SimonEngine::vc74_clearMark() {
+ _marks &= ~(1 << vcReadNextWord());
+}
+
+int SimonEngine::getScale(int16 y, int16 x) {
+ int16 z;
+
+ if (y > _baseY) {
+ return((int16)(x * (1 + ((y - _baseY) * _scale))));
+ } else {
+ if (x == 0)
+ return(0);
+ if (x < 0) {
+ z = ((int16)((x * (1 - ((_baseY - y)* _scale))) - 0.5));
+ if (z >- 2)
+ return(-2);
+ return(z);
+ }
+
+ z = ((int16)((x * (1 - ((_baseY - y) * _scale))) + 0.5));
+ if (z < 2)
+ return(2);
+
+ return(z);
+ }
+}
+
+void SimonEngine::vc75_setScale() {
+ _baseY = vcReadNextWord();
+ _scale = (float)vcReadNextWord() / 1000000.;
+}
+
+void SimonEngine::vc76_setScaleXOffs() {
+ VgaSprite *vsp = findCurSprite();
+
+ vsp->image = vcReadNextWord();
+ int16 x = vcReadNextWord();
+ uint16 var = vcReadNextWord();
+
+ vsp->x += getScale(vsp->y, x);
+ _variableArrayPtr[var] = vsp->x;
+
+ checkScrollX(x, vsp->x);
+
+ vsp->flags = kDFScaled;
+}
+
+void SimonEngine::vc77_setScaleYOffs() {
+ VgaSprite *vsp = findCurSprite();
+
+ vsp->image = vcReadNextWord();
+ int16 y = vcReadNextWord();
+ uint16 var = vcReadNextWord();
+
+ vsp->y += getScale(vsp->y, y);
+ _variableArrayPtr[var] = vsp->y;
+
+ if (y != 0)
+ checkScrollY(y, vsp->y);
+
+ vsp->flags = kDFScaled;
+}
+
+void SimonEngine::vc78_computeXY() {
+ VgaSprite *vsp = findCurSprite();
+
+ uint16 a = (uint16)_variableArrayPtr[12];
+ uint16 b = (uint16)_variableArrayPtr[13];
+
+ const uint16 *p = _pathFindArray[a - 1];
+ p += b * 2;
+
+ uint16 posx = readUint16Wrapper(p);
+ _variableArrayPtr[15] = posx;
+ vsp->x = posx;
+
+ uint16 posy = readUint16Wrapper(p + 1);
+ _variableArrayPtr[16] = posy;
+ vsp->y = posy;
+
+ setBitFlag(85, false);
+ if (getBitFlag(74)) {
+ centreScroll();
+ }
+}
+
+void SimonEngine::vc79_computePosNum() {
+ uint a = (uint16)_variableArrayPtr[12];
+ const uint16 *p = _pathFindArray[a - 1];
+ uint pos = 0;
+
+ int16 y = _variableArrayPtr[16];
+ while (y >= (int16)readUint16Wrapper(p + 1)) {
+ p += 2;
+ pos++;
+ }
+
+ _variableArrayPtr[13] = pos;
+}
+
+void SimonEngine::vc80_setOverlayImage() {
+ VgaSprite *vsp = findCurSprite();
+
+ vsp->image = vcReadVarOrWord();
+
+ vsp->x += vcReadNextWord();
+ vsp->y += vcReadNextWord();
+ vsp->flags = kDFOverlayed;
+
+ _vgaSpriteChanged++;
+}
+
+void SimonEngine::vc81_setRandom() {
+ uint16 var = vcReadNextWord();
+ uint16 value = vcReadNextWord();
+
+ _variableArray[var] = _rnd.getRandomNumber(value - 1);
+}
+
+void SimonEngine::vc82_getPathValue() {
+ uint8 val;
+
+ uint16 var = vcReadNextWord();
+
+ if (getBitFlag(82)) {
+ val = _pathValues1[_GPVCount1++];
+ } else {
+ val = _pathValues[_GPVCount++];
+ }
+
+ vcWriteVar(var, val);
+}
+
+void SimonEngine::vc83_playSoundLoop() {
+ uint16 sound = vcReadNextWord();
+ int16 vol = vcReadNextWord();
+ int16 pan = vcReadNextWord();
+
+ loadSound(sound, pan, vol, 3);
+}
+
+void SimonEngine::vc84_stopSoundLoop() {
+ _sound->stopSfx5();
+}
+
+// Scrolling functions for Feeble Files
+void SimonEngine::checkScrollX(int16 x, int16 xpos) {
+ if (_scrollXMax == 0 || getBitFlag(80) || getBitFlag(82) || x == 0)
+ return;
+
+ int16 tmp;
+ if (x > 0) {
+ if (_scrollCount != 0) {
+ if (_scrollCount >= 0)
+ return;
+ _scrollCount = 0;
+ } else {
+ if (_scrollFlag != 0)
+ return;
+ }
+
+ if (xpos - _scrollX >= 480) {
+ _scrollCount = 320;
+ tmp = _scrollXMax - _scrollX;
+ if (tmp < 320)
+ _scrollCount = tmp;
+ }
+ } else {
+ if (_scrollCount != 0) {
+ if (_scrollCount < 0)
+ return;
+ _scrollCount = 0;
+ } else {
+ if (_scrollFlag != 0)
+ return;
+ }
+
+ if (xpos - _scrollX < 161) {
+ _scrollCount = -320;
+ if (_scrollX < 320)
+ _scrollCount = -_scrollX;
+ }
+ }
+}
+
+void SimonEngine::checkScrollY(int16 y, int16 ypos) {
+ if (_scrollYMax == 0 || getBitFlag(80))
+ return;
+
+ int16 tmp;
+ if (y >= 0) {
+ if (_scrollCount != 0) {
+ if (_scrollCount >= 0)
+ return;
+ } else {
+ if (_scrollFlag != 0)
+ return;
+ }
+
+ if (ypos - _scrollY >= 440) {
+ _scrollCount = 240;
+ tmp = _scrollYMax - _scrollY;
+ if (tmp < 240)
+ _scrollCount = tmp;
+ }
+ } else {
+ if (_scrollCount != 0) {
+ if (_scrollCount < 0)
+ return;
+ } else {
+ if (_scrollFlag != 0)
+ return;
+ }
+
+ if (ypos - _scrollY < 100) {
+ _scrollCount = -240;
+ if (_scrollY < 240)
+ _scrollCount = -_scrollY;
+ }
+ }
+}
+
+void SimonEngine::centreScroll() {
+ int16 x, y, tmp;
+
+ if (_scrollXMax != 0) {
+ _scrollCount = 0;
+ x = _variableArray[15] - _scrollX;
+ if (x < 17 || (getBitFlag(85) && x < 320)) {
+ x -= 320;
+ if (_scrollX < -x)
+ x = -_scrollX;
+ _scrollCount = x;
+ } else if ((getBitFlag(85) && x >= 320) || x >= 624) {
+ x -= 320;
+ tmp = _scrollXMax - _scrollX;
+ if (tmp < x)
+ x = tmp;
+ _scrollCount = x;
+ }
+ } else if (_scrollYMax != 0) {
+ _scrollCount = 0;
+ y = _variableArray[16] - _scrollY;
+ if (y < 30) {
+ y -= 240;
+ if (_scrollY < -y)
+ y = -_scrollY;
+ _scrollCount = y;
+ } else if (y >= 460) {
+ y -= 240;
+ tmp = _scrollYMax - _scrollY;
+ if (tmp < y)
+ y = tmp;
+ _scrollCount = y;
+ }
+ }
+}
+
+} // End of namespace Simon
diff --git a/engines/agos/vga.h b/engines/agos/vga.h
new file mode 100644
index 0000000000..e963d0350b
--- /dev/null
+++ b/engines/agos/vga.h
@@ -0,0 +1,167 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2002-2006 The ScummVM project
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef AGOS_VGA_H
+#define AGOS_VGA_H
+
+namespace Simon {
+
+#include "common/pack-start.h" // START STRUCT PACKING
+
+// Feeble Files
+struct VgaFileHeader_Feeble {
+ uint16 x_1;
+ uint16 hdr2_start;
+ uint16 x_2, x_3;
+};
+
+struct VgaFileHeader2_Feeble {
+ uint16 imageCount;
+ uint16 x_2;
+ uint16 animationCount;
+ uint16 x_3;
+ uint16 imageTable;
+ uint16 x_4;
+ uint16 animationTable;
+ uint16 x_5;
+};
+
+struct ImageHeader_Feeble {
+ uint16 id;
+ uint16 x_1;
+ uint16 scriptOffs;
+ uint16 x_2;
+};
+
+struct AnimationHeader_Feeble {
+ uint16 scriptOffs;
+ uint16 x_2;
+ uint16 id;
+};
+
+// Simon 1/2
+struct VgaFileHeader_Simon {
+ uint16 x_1, x_2;
+ uint16 hdr2_start;
+ uint16 x_3, x_4;
+};
+
+struct VgaFileHeader2_Simon {
+ uint16 x_1;
+ uint16 imageCount;
+ uint16 x_2;
+ uint16 animationCount;
+ uint16 x_3;
+ uint16 imageTable;
+ uint16 x_4;
+ uint16 animationTable;
+ uint16 x_5;
+};
+
+struct ImageHeader_Simon {
+ uint16 id;
+ uint16 x_1;
+ uint16 x_2;
+ uint16 scriptOffs;
+};
+
+struct AnimationHeader_Simon {
+ uint16 id;
+ uint16 x_2;
+ uint16 scriptOffs;
+};
+
+
+// Waxworks
+struct VgaFileHeader2_WW {
+ uint16 x_1;
+ uint16 imageCount;
+ uint16 x_2;
+ uint16 animationCount;
+ uint16 x_3;
+ uint16 imageTable;
+ uint16 x_4;
+ uint16 animationTable;
+ uint16 x_5;
+};
+
+struct ImageHeader_WW {
+ uint16 id;
+ uint16 x_1;
+ uint16 x_2;
+ uint16 scriptOffs;
+};
+
+struct AnimationHeader_WW {
+ uint16 id;
+ uint16 x_1;
+ uint16 x_2;
+ uint16 scriptOffs;
+};
+
+
+#include "common/pack-end.h" // END STRUCT PACKING
+
+enum DrawFlags {
+ kDFFlip = 0x1,
+ kDFNonTrans = 0x2,
+ kDFUseFrontBuf = 0x4,
+ kDFCompressed = 0x8,
+ kDFCompressedFlip = 0x10,
+ kDFMasked = 0x20,
+
+ // Feeble specific
+ kDFOverlayed = 0x10,
+ kDFScaled = 0x40,
+ kDFShaded = 0x80
+};
+
+struct VC10_state {
+ int image;
+ uint16 flags;
+ byte palette;
+
+ int x, y;
+ int width, height;
+ uint draw_width, draw_height;
+ uint x_skip, y_skip;
+
+ byte *surf2_addr;
+ uint surf2_pitch;
+
+ byte *surf_addr;
+ uint surf_pitch;
+
+ uint16 dl, dh;
+
+ const byte *depack_src;
+ int8 depack_cont;
+
+ byte depack_dest[480];
+};
+
+byte *vc10_depackColumn(VC10_state *vs);
+
+} // End of namespace Simon
+
+#endif
diff --git a/engines/agos/window.cpp b/engines/agos/window.cpp
new file mode 100644
index 0000000000..c21f8ad6d2
--- /dev/null
+++ b/engines/agos/window.cpp
@@ -0,0 +1,185 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-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 "agos/agos.h"
+#include "agos/intern.h"
+
+namespace Simon {
+
+uint SimonEngine::getWindowNum(WindowBlock *window) {
+ uint i;
+
+ for (i = 0; i != ARRAYSIZE(_windowArray); i++)
+ if (_windowArray[i] == window)
+ return i;
+
+ error("getWindowNum: not found");
+ return 0;
+}
+
+WindowBlock *SimonEngine::openWindow(uint x, uint y, uint w, uint h, uint flags, uint fill_color, uint text_color) {
+ WindowBlock *window;
+
+ window = _windowList;
+ while (window->mode != 0)
+ window++;
+
+ window->mode = 2;
+ window->x = x;
+ window->y = y;
+ window->width = w;
+ window->height = h;
+ window->flags = flags;
+ window->fill_color = fill_color;
+ window->text_color = text_color;
+ window->textColumn = 0;
+ window->textRow = 0;
+ window->textColumnOffset = 0;
+ window->textMaxLength = window->width * 8 / 6; // characters are 6 pixels
+ window->scrollY = 0;
+ return window;
+}
+
+void SimonEngine::changeWindow(uint a) {
+ a &= 7;
+
+ if (_windowArray[a] == NULL || _curWindow == a)
+ return;
+
+ _curWindow = a;
+ showmessage_print_char(0);
+ _textWindow = _windowArray[a];
+
+ if (getGameType() == GType_FF || getGameType() == GType_PP)
+ showmessage_helper_3(_textWindow->textColumn, _textWindow->width);
+ else
+ showmessage_helper_3(_textWindow->textLength, _textWindow->textMaxLength);
+}
+
+void SimonEngine::closeWindow(uint a) {
+ if (_windowArray[a] == NULL)
+ return;
+ removeIconArray(a);
+ resetWindow(_windowArray[a]);
+ _windowArray[a] = NULL;
+ if (_curWindow == a) {
+ _textWindow = NULL;
+ changeWindow(0);
+ }
+}
+
+void SimonEngine::clearWindow(WindowBlock *window) {
+ if (window->flags & 0x10)
+ restoreWindow(window);
+ else
+ colorWindow(window);
+
+ window->textColumn = 0;
+ window->textRow = 0;
+ window->textColumnOffset = 0;
+ window->textLength = 0;
+ window->scrollY = 0;
+}
+
+void SimonEngine::colorWindow(WindowBlock *window) {
+ byte *dst;
+ uint h, w;
+
+ _lockWord |= 0x8000;
+
+ if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ dst = getFrontBuf() + _dxSurfacePitch * window->y + window->x;
+
+ for (h = 0; h < window->height; h++) {
+ for (w = 0; w < window->width; w++) {
+ if (dst[w] == 113 || dst[w] == 116 || dst[w] == 252)
+ dst[w] = window->fill_color;
+ }
+ dst += _screenWidth;
+ }
+ } else {
+ dst = getFrontBuf() + _dxSurfacePitch * window->y + window->x * 8;
+ h = window->height * 8;
+ w = window->width * 8;
+
+ do {
+ memset(dst, window->fill_color, w);
+ dst += _dxSurfacePitch;
+ } while (--h);
+ }
+
+ _lockWord &= ~0x8000;
+}
+
+void SimonEngine::resetWindow(WindowBlock *window) {
+ if (window->flags & 8)
+ restoreWindow(window);
+ window->mode = 0;
+}
+
+void SimonEngine::restoreWindow(WindowBlock *window) {
+ _lockWord |= 0x8000;
+
+ if (getGameType() == GType_FF || getGameType() == GType_PP) {
+ restoreBlock(window->y + window->height, window->x + window->width, window->y, window->x);
+ } else if (getGameType() == GType_SIMON2) {
+ if (_restoreWindow6 && _windowArray[2] == window) {
+ window = _windowArray[6];
+ _restoreWindow6 = 0;
+ }
+
+ restoreBlock(window->y + window->height * 8, (window->x + window->width) * 8, window->y, window->x * 8);
+ } else {
+ restoreBlock(window->y + window->height * 8 + ((window == _windowArray[2]) ? 1 : 0), (window->x + window->width) * 8, window->y, window->x * 8);
+ }
+
+ _lockWord &= ~0x8000;
+}
+
+void SimonEngine::restoreBlock(uint h, uint w, uint y, uint x) {
+ byte *dst, *src;
+ uint i;
+
+ dst = getFrontBuf();
+ src = _backGroundBuf;
+
+ dst += y * _dxSurfacePitch;
+ src += y * _dxSurfacePitch;
+
+ while (y < h) {
+ for (i = x; i < w; i++)
+ dst[i] = src[i];
+ y++;
+ dst += _dxSurfacePitch;
+ src += _dxSurfacePitch;
+ }
+}
+
+void SimonEngine::windowPutChar(uint a) {
+ if (_textWindow != _windowArray[0])
+ windowPutChar(_textWindow, a);
+}
+
+} // End of namespace Simon