aboutsummaryrefslogtreecommitdiff
path: root/engines/supernova
diff options
context:
space:
mode:
authorThierry Crozat2018-01-23 21:53:11 +0000
committerThierry Crozat2018-01-23 21:53:11 +0000
commit2db8fbcb9de08a36fd1aa22d2c925ea47a4ddd36 (patch)
treebaa760a3f9998238f7fea2f57cf347e4e0678e67 /engines/supernova
parent5189dbb7ba7d3db8a7e78906e5bc5ab8d1677955 (diff)
parentccd4e20e3264f24eca5ff674e5a0d5fc0b262d36 (diff)
downloadscummvm-rg350-2db8fbcb9de08a36fd1aa22d2c925ea47a4ddd36.tar.gz
scummvm-rg350-2db8fbcb9de08a36fd1aa22d2c925ea47a4ddd36.tar.bz2
scummvm-rg350-2db8fbcb9de08a36fd1aa22d2c925ea47a4ddd36.zip
Merge branch 'supernova'
Diffstat (limited to 'engines/supernova')
-rw-r--r--engines/supernova/NOTES72
-rw-r--r--engines/supernova/POTFILES2
-rw-r--r--engines/supernova/configure.engine3
-rw-r--r--engines/supernova/console.cpp114
-rw-r--r--engines/supernova/console.h55
-rw-r--r--engines/supernova/detection.cpp220
-rw-r--r--engines/supernova/graphics.cpp256
-rw-r--r--engines/supernova/graphics.h87
-rw-r--r--engines/supernova/module.mk20
-rw-r--r--engines/supernova/msn_def.h643
-rw-r--r--engines/supernova/rooms.cpp3247
-rw-r--r--engines/supernova/rooms.h1388
-rw-r--r--engines/supernova/state.cpp2388
-rw-r--r--engines/supernova/state.h234
-rw-r--r--engines/supernova/supernova.cpp1156
-rw-r--r--engines/supernova/supernova.h218
16 files changed, 10103 insertions, 0 deletions
diff --git a/engines/supernova/NOTES b/engines/supernova/NOTES
new file mode 100644
index 0000000000..909f4eb9d0
--- /dev/null
+++ b/engines/supernova/NOTES
@@ -0,0 +1,72 @@
+Audio
+-----------
+
+There may be several sound effects in one file.
+This list shows them and their offsets.
+
+46:
+ 0 - Voice "Halt!"
+ 2510 -
+ 4020 -
+
+47:
+ 0 - Voice "Mission Supernova"
+ 24010 - Voice "Yeaahh.."
+
+48:
+ 0 -
+ 2510 -
+ 10520 - electric shock
+ 13530 - (playing turntable)
+
+50:
+ 0 -
+ 12786 -
+
+51:
+
+53: Death sound
+
+54:
+ 0 - Alarm
+ 8010 -
+ 24020 - Door sound
+ 30030 - Door open
+ 31040 - Door close
+
+Engine
+----------
+MouseFields
+ [0;256[ - Viewport
+ [256;512[ - Command Row
+ [512;768[ - Inventory
+ [768;769] - Inventory Arrows
+
+Dimensions
+ Viewport: (0,0) (320, 150)
+ Command Row: (0, 150) (320, 159)
+ Inventory: (0, 161) (270, 200)
+ Inventory Arrows: (271, 161) (279, 200)
+ Exit Maps: (283, 163) (317, 197)
+
+
+timer2 == animation timer
+
+
+Text
+-------
+AE - 216 ae - 204
+OE - 231 oe - 224
+UE - 232 ue - 201
+SZ - 341
+
+
+Ingame Bugs
+------------
+In Cabin_R3 (starting room) you can take the discman from your locker without
+opening it first.
+
+
+Improvements
+-------------
+Incidate in inventory (?) what parts of your space suit you are wearing
diff --git a/engines/supernova/POTFILES b/engines/supernova/POTFILES
new file mode 100644
index 0000000000..80d6dee582
--- /dev/null
+++ b/engines/supernova/POTFILES
@@ -0,0 +1,2 @@
+engines/supernova/supernova.cpp
+
diff --git a/engines/supernova/configure.engine b/engines/supernova/configure.engine
new file mode 100644
index 0000000000..8f75fa4a3e
--- /dev/null
+++ b/engines/supernova/configure.engine
@@ -0,0 +1,3 @@
+# This file is included from the main "configure" script
+# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps]
+add_engine supernova "Mission Supernova" no
diff --git a/engines/supernova/console.cpp b/engines/supernova/console.cpp
new file mode 100644
index 0000000000..ee1905a3ce
--- /dev/null
+++ b/engines/supernova/console.cpp
@@ -0,0 +1,114 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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.
+ *
+ */
+
+#include "gui/debugger.h"
+
+#include "supernova/supernova.h"
+#include "supernova/state.h"
+#include "supernova/console.h"
+
+namespace Supernova {
+
+Console::Console(SupernovaEngine *vm, GameManager *gm)
+{
+ registerCmd("render", WRAP_METHOD(Console, cmdRenderImage));
+ registerCmd("play", WRAP_METHOD(Console, cmdPlaySound));
+ registerCmd("music", WRAP_METHOD(Console, cmdMusic));
+ registerCmd("list", WRAP_METHOD(Console, cmdList));
+ registerCmd("inventory", WRAP_METHOD(Console, cmdInventory));
+ registerCmd("giveall", WRAP_METHOD(Console, cmdGiveAll));
+
+ _vm = vm;
+ _gm = gm;
+}
+
+bool Console::cmdRenderImage(int argc, const char **argv) {
+ if (argc != 3) {
+ debugPrintf("Usage: render [filenumber] [section]\n");
+ return true;
+ }
+
+ int image = atoi(argv[1]);
+ if (_vm->setCurrentImage(image))
+ _vm->renderImage(atoi(argv[2]));
+ else
+ debugPrintf("Image %d is invalid!", image);
+
+ return true;
+}
+
+bool Console::cmdPlaySound(int argc, const char **argv) {
+ if (argc != 2) {
+ debugPrintf("Usage: play [0-%d]\n", kAudioNumSamples - 1);
+ return true;
+ }
+
+ int sample = Common::String(argv[1]).asUint64();
+ _vm->playSound(static_cast<AudioIndex>(sample));
+
+ return true;
+}
+
+bool Console::cmdMusic(int argc, const char **argv) {
+ if (argc != 2) {
+ debugPrintf("Usage: music [49/52]\n");
+ return true;
+ }
+
+ _vm->playSoundMod(atoi(argv[1]));
+
+ return true;
+}
+
+bool Console::cmdList(int argc, const char **argv) {
+ // Objects in room and sections
+
+ return true;
+}
+
+bool Console::cmdInventory(int argc, const char **argv) {
+ if (argc != 2 || argc != 3) {
+ debugPrintf("Usage: inventory [list][add/remove [object]]");
+ return true;
+ }
+
+ // TODO
+
+ return true;
+}
+
+bool Console::cmdGiveAll(int argc, const char **argv) {
+ _gm->takeObject(*_gm->_rooms[INTRO]->getObject(0));
+ _gm->takeObject(*_gm->_rooms[INTRO]->getObject(1));
+ _gm->takeObject(*_gm->_rooms[INTRO]->getObject(2));
+ _gm->takeObject(*_gm->_rooms[GENERATOR]->getObject(2)); // Commander Keycard
+ _gm->takeObject(*_gm->_rooms[GENERATOR]->getObject(0)); // Power Cord with Plug
+ _gm->takeObject(*_gm->_rooms[CABIN_L1]->getObject(5)); // Pen
+ _gm->takeObject(*_gm->_rooms[CABIN_R3]->getObject(0)); // Chess Board
+ _gm->takeObject(*_gm->_rooms[CABIN_R3]->getObject(9)); // Rope
+ _gm->takeObject(*_gm->_rooms[AIRLOCK]->getObject(4)); // Helmet
+ _gm->takeObject(*_gm->_rooms[AIRLOCK]->getObject(5)); // Space Suit
+ _gm->takeObject(*_gm->_rooms[AIRLOCK]->getObject(6)); // Supply
+ return true;
+}
+
+}
diff --git a/engines/supernova/console.h b/engines/supernova/console.h
new file mode 100644
index 0000000000..74b40c25f8
--- /dev/null
+++ b/engines/supernova/console.h
@@ -0,0 +1,55 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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.
+ *
+ */
+
+#ifndef SUPERNOVA_CONSOLE_H
+#define SUPERNOVA_CONSOLE_H
+
+#include "gui/debugger.h"
+
+namespace Supernova {
+
+class SupernovaEngine;
+class GameManager;
+
+enum {
+ kDebugGeneral = 1 << 0
+};
+
+class Console : public GUI::Debugger {
+public:
+ Console(Supernova::SupernovaEngine *vm, Supernova::GameManager *gm);
+ virtual ~Console() {}
+
+ bool cmdRenderImage(int argc, const char **argv);
+ bool cmdPlaySound(int argc, const char **argv);
+ bool cmdMusic(int argc, const char **argv);
+ bool cmdList(int argc, const char **argv);
+ bool cmdInventory(int argc, const char **argv);
+ bool cmdGiveAll(int argc, const char **argv);
+private:
+ SupernovaEngine *_vm;
+ GameManager *_gm;
+};
+
+}
+
+#endif
diff --git a/engines/supernova/detection.cpp b/engines/supernova/detection.cpp
new file mode 100644
index 0000000000..61a99f083c
--- /dev/null
+++ b/engines/supernova/detection.cpp
@@ -0,0 +1,220 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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.
+ *
+ */
+
+#include "base/plugins.h"
+#include "common/file.h"
+#include "common/savefile.h"
+#include "common/system.h"
+#include "graphics/thumbnail.h"
+#include "engines/advancedDetector.h"
+
+#include "supernova/supernova.h"
+
+static const PlainGameDescriptor supernovaGames[] = {
+ {"msn1", "Mission Supernova 1"},
+ {"msn2", "Mission Supernova 2"},
+ {NULL, NULL}
+};
+
+namespace Supernova {
+static const ADGameDescription gameDescriptions[] = {
+ // Mission Supernova 1
+ {
+ "msn1",
+ NULL,
+ AD_ENTRY1s("msn_data.000", "f64f16782a86211efa919fbae41e7568", 24163),
+ Common::DE_DEU,
+ Common::kPlatformDOS,
+ ADGF_UNSTABLE,
+ GUIO1(GUIO_NONE)
+ },
+ {
+ "msn1",
+ NULL,
+ AD_ENTRY1s("msn_data.000", "f64f16782a86211efa919fbae41e7568", 24163),
+ Common::EN_ANY,
+ Common::kPlatformDOS,
+ ADGF_UNSTABLE,
+ GUIO1(GUIO_NONE)
+ },
+
+ // Mission Supernova 2
+ {
+ "msn2",
+ NULL,
+ AD_ENTRY1s("ms2_data.000", "e595610cba4a6d24a763e428d05cc83f", 24805),
+ Common::DE_DEU,
+ Common::kPlatformDOS,
+ ADGF_UNSTABLE,
+ GUIO1(GUIO_NONE)
+ },
+
+ AD_TABLE_END_MARKER
+};
+}
+
+class SupernovaMetaEngine: public AdvancedMetaEngine {
+public:
+ SupernovaMetaEngine() : AdvancedMetaEngine(Supernova::gameDescriptions, sizeof(ADGameDescription), supernovaGames) {
+// _singleId = "supernova";
+ }
+
+ virtual const char *getName() const {
+ return "Supernova Engine";
+ }
+
+ virtual const char *getOriginalCopyright() const {
+ return "Mission Supernova (c) 1994 Thomas and Steffen Dingel";
+ }
+
+ virtual bool hasFeature(MetaEngineFeature f) const;
+ virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
+ virtual SaveStateList listSaves(const char *target) const;
+ virtual void removeSaveState(const char *target, int slot) const;
+ virtual int getMaximumSaveSlot() const {
+ return 99;
+ }
+ virtual SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;
+};
+
+bool SupernovaMetaEngine::hasFeature(MetaEngineFeature f) const {
+ switch (f) {
+ case kSupportsLoadingDuringStartup:
+ // fallthrough
+ case kSupportsListSaves:
+ // fallthrough
+ case kSupportsDeleteSave:
+ // fallthrough
+ case kSavesSupportMetaInfo:
+ // fallthrough
+ case kSavesSupportThumbnail:
+ // fallthrough
+ case kSavesSupportCreationDate:
+ // fallthrough
+ case kSavesSupportPlayTime:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool SupernovaMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
+ if (desc) {
+ *engine = new Supernova::SupernovaEngine(syst);
+ }
+
+ return desc != NULL;
+}
+
+SaveStateList SupernovaMetaEngine::listSaves(const char *target) const {
+ Common::StringArray filenames;
+ Common::String pattern("msn_save.###");
+
+ filenames = g_system->getSavefileManager()->listSavefiles(pattern);
+
+ SaveStateList saveFileList;
+ for (Common::StringArray::const_iterator file = filenames.begin();
+ file != filenames.end(); ++file) {
+ int saveSlot = atoi(file->c_str() + file->size() - 3);
+ if (saveSlot >= 0 && saveSlot <= getMaximumSaveSlot()) {
+ Common::InSaveFile *savefile = g_system->getSavefileManager()->openForLoading(*file);
+ if (savefile) {
+ uint saveHeader = savefile->readUint32LE();
+ if (saveHeader == SAVEGAME_HEADER) {
+ byte saveVersion = savefile->readByte();
+ if (saveVersion <= SAVEGAME_VERSION) {
+ int saveFileDescSize = savefile->readSint16LE();
+ char* saveFileDesc = new char[saveFileDescSize];
+ savefile->read(saveFileDesc, saveFileDescSize);
+ saveFileList.push_back(SaveStateDescriptor(saveSlot, saveFileDesc));
+ delete [] saveFileDesc;
+ }
+ }
+ delete savefile;
+ }
+ }
+ }
+
+ Common::sort(saveFileList.begin(), saveFileList.end(), SaveStateDescriptorSlotComparator());
+ return saveFileList;
+}
+
+void SupernovaMetaEngine::removeSaveState(const char *target, int slot) const {
+ Common::String filename = Common::String::format("msn_save.%03d", slot);
+ g_system->getSavefileManager()->removeSavefile(filename);
+}
+
+SaveStateDescriptor SupernovaMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
+ Common::String fileName = Common::String::format("msn_save.%03d", slot);
+ Common::InSaveFile *savefile = g_system->getSavefileManager()->openForLoading(fileName);
+
+ if (savefile) {
+ uint saveHeader = savefile->readUint32LE();
+ if (saveHeader != SAVEGAME_HEADER) {
+ delete savefile;
+ return SaveStateDescriptor();
+ }
+ byte saveVersion = savefile->readByte();
+ if (saveVersion > SAVEGAME_VERSION){
+ delete savefile;
+ return SaveStateDescriptor();
+ }
+
+ int descriptionSize = savefile->readSint16LE();
+ char* description = new char[descriptionSize];
+ savefile->read(description, descriptionSize);
+ SaveStateDescriptor desc(slot, description);
+ delete [] description;
+
+ uint32 saveDate = savefile->readUint32LE();
+ int day = (saveDate >> 24) & 0xFF;
+ int month = (saveDate >> 16) & 0xFF;
+ int year = saveDate & 0xFFFF;
+ desc.setSaveDate(year, month, day);
+
+ uint16 saveTime = savefile->readUint16LE();
+ int hour = (saveTime >> 8) & 0xFF;
+ int minutes = saveTime & 0xFF;
+ desc.setSaveTime(hour, minutes);
+
+ uint32 playTime =savefile->readUint32LE();
+ desc.setPlayTime(playTime * 1000);
+
+ if (Graphics::checkThumbnailHeader(*savefile)) {
+ Graphics::Surface *const thumbnail = Graphics::loadThumbnail(*savefile);
+ desc.setThumbnail(thumbnail);
+ }
+
+ delete savefile;
+
+ return desc;
+ }
+
+ return SaveStateDescriptor();
+}
+
+
+#if PLUGIN_ENABLED_DYNAMIC(SUPERNOVA)
+REGISTER_PLUGIN_DYNAMIC(SUPERNOVA, PLUGIN_TYPE_ENGINE, SupernovaMetaEngine);
+#else
+REGISTER_PLUGIN_STATIC(SUPERNOVA, PLUGIN_TYPE_ENGINE, SupernovaMetaEngine);
+#endif
diff --git a/engines/supernova/graphics.cpp b/engines/supernova/graphics.cpp
new file mode 100644
index 0000000000..d7839c1dcb
--- /dev/null
+++ b/engines/supernova/graphics.cpp
@@ -0,0 +1,256 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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.
+ *
+ */
+
+#include "common/algorithm.h"
+#include "common/file.h"
+#include "common/stream.h"
+#include "common/system.h"
+#include "common/config-manager.h"
+#include "graphics/palette.h"
+#include "graphics/surface.h"
+
+#include "graphics.h"
+#include "msn_def.h"
+#include "supernova.h"
+
+namespace Supernova {
+
+MSNImageDecoder::MSNImageDecoder() {
+ _palette = nullptr;
+ _encodedImage = nullptr;
+ _filenumber = -1;
+ _pitch = 0;
+ _numSections = 0;
+ _numClickFields = 0;
+}
+
+MSNImageDecoder::~MSNImageDecoder() {
+ destroy();
+}
+
+bool MSNImageDecoder::init(int filenumber) {
+ Common::File file;
+ if (!file.open(Common::String::format("msn_data.%03d", filenumber))) {
+ warning("Image data file msn_data.%03d could not be read!", filenumber);
+ return false;
+ }
+
+ _filenumber = filenumber;
+ loadStream(file);
+
+ return true;
+}
+
+bool MSNImageDecoder::loadFromEngineDataFile() {
+ Common::String name;
+ if (_filenumber == 1)
+ name = "IMG1";
+ else if (_filenumber == 2)
+ name = "IMG2";
+ else
+ return false;
+
+ Common::String cur_lang = ConfMan.get("language");
+
+ // Note: we don't print any warning or errors here if we cannot find the file
+ // or the format is not as expected. We will get those warning when reading the
+ // strings anyway (actually the engine will even refuse to start).
+ Common::File f;
+ if (!f.open(SUPERNOVA_DAT))
+ return false;
+
+ char id[5], lang[5];
+ id[4] = lang[4] = '\0';
+ f.read(id, 3);
+ if (strncmp(id, "MSN", 3) != 0)
+ return false;
+ int version = f.readByte();
+ if (version != SUPERNOVA_DAT_VERSION)
+ return false;
+
+ while (!f.eos()) {
+ f.read(id, 4);
+ f.read(lang, 4);
+ uint32 size = f.readUint32LE();
+ if (f.eos())
+ break;
+ if (name == id && cur_lang == lang) {
+ return f.read(_encodedImage, size) == size;
+ } else
+ f.skip(size);
+ }
+
+ return false;
+}
+
+bool MSNImageDecoder::loadStream(Common::SeekableReadStream &stream) {
+ destroy();
+
+ uint size = 0;
+ size = (stream.readUint16LE() + 0xF) >> 4;
+ size |= (stream.readUint16LE() & 0xF) << 12;
+ size += 0x70; // zus_paragraph
+ size *= 16; // a paragraph is 16 bytes
+ _encodedImage = new byte[size];
+
+ _palette = new byte[717];
+ g_system->getPaletteManager()->grabPalette(_palette, 16, 239);
+
+ byte pal_diff;
+ byte flag = stream.readByte();
+ if (flag == 0) {
+ pal_diff = 0;
+ _palette[141] = 0xE0;
+ _palette[142] = 0xE0;
+ _palette[143] = 0xE0;
+ } else {
+ pal_diff = 1;
+ for (int i = flag * 3; i != 0; --i) {
+ _palette[717 - i] = stream.readByte() << 2;
+ }
+ }
+
+ _numSections = stream.readByte();
+ for (uint i = 0; i < kMaxSections; ++i) {
+ _section[i].addressHigh = 0xff;
+ _section[i].addressLow = 0xffff;
+ _section[i].x2 = 0;
+ _section[i].next = 0;
+ }
+ for (int i = 0; i < _numSections; ++i) {
+ _section[i].x1 = stream.readUint16LE();
+ _section[i].x2 = stream.readUint16LE();
+ _section[i].y1 = stream.readByte();
+ _section[i].y2 = stream.readByte();
+ _section[i].next = stream.readByte();
+ _section[i].addressLow = stream.readUint16LE();
+ _section[i].addressHigh = stream.readByte();
+ }
+
+ _numClickFields = stream.readByte();
+ for (int i = 0; i < _numClickFields; ++i) {
+ _clickField[i].x1 = stream.readUint16LE();
+ _clickField[i].x2 = stream.readUint16LE();
+ _clickField[i].y1 = stream.readByte();
+ _clickField[i].y2 = stream.readByte();
+ _clickField[i].next = stream.readByte();
+ }
+ for (int i = _numClickFields; i < kMaxClickFields; ++i) {
+ _clickField[i].x1 = 0;
+ _clickField[i].x2 = 0;
+ _clickField[i].y1 = 0;
+ _clickField[i].y2 = 0;
+ _clickField[i].next = 0;
+ }
+
+ // Newspaper images may be in the engine data file. So first try to read
+ // it from there.
+ if (!loadFromEngineDataFile()) {
+ // Load the image from the stream
+ byte zwCodes[256] = {0};
+ byte numRepeat = stream.readByte();
+ byte numZw = stream.readByte();
+ stream.read(zwCodes, numZw);
+ numZw += numRepeat;
+
+ byte input = 0;
+ uint i = 0;
+
+ while (stream.read(&input, 1)) {
+ if (input < numRepeat) {
+ ++input;
+ byte value = stream.readByte();
+ for (--value; input > 0; --input) {
+ _encodedImage[i++] = value;
+ }
+ } else if (input < numZw) {
+ input = zwCodes[input - numRepeat];
+ --input;
+ _encodedImage[i++] = input;
+ _encodedImage[i++] = input;
+ } else {
+ input -= pal_diff;
+ _encodedImage[i++] = input;
+ }
+ }
+ }
+
+ loadSections();
+
+ return true;
+}
+
+bool MSNImageDecoder::loadSections() {
+ bool isNewspaper = _filenumber == 1 || _filenumber == 2;
+ int imageWidth = isNewspaper ? 640 : 320;
+ int imageHeight = isNewspaper ? 480 : 200;
+ _pitch = imageWidth;
+
+ for (int section = 0; section < _numSections; ++section) {
+ Graphics::Surface *surface = new Graphics::Surface;
+ _sectionSurfaces.push_back(surface);
+
+ if (isNewspaper) {
+ surface->create(imageWidth, imageHeight, g_system->getScreenFormat());
+ byte *surfacePixels = static_cast<byte *>(surface->getPixels());
+ for (int i = 0; i < imageWidth * imageHeight / 8; ++i) {
+ *surfacePixels++ = (_encodedImage[i] & 0x80) ? kColorWhite63 : kColorBlack;
+ *surfacePixels++ = (_encodedImage[i] & 0x40) ? kColorWhite63 : kColorBlack;
+ *surfacePixels++ = (_encodedImage[i] & 0x20) ? kColorWhite63 : kColorBlack;
+ *surfacePixels++ = (_encodedImage[i] & 0x10) ? kColorWhite63 : kColorBlack;
+ *surfacePixels++ = (_encodedImage[i] & 0x08) ? kColorWhite63 : kColorBlack;
+ *surfacePixels++ = (_encodedImage[i] & 0x04) ? kColorWhite63 : kColorBlack;
+ *surfacePixels++ = (_encodedImage[i] & 0x02) ? kColorWhite63 : kColorBlack;
+ *surfacePixels++ = (_encodedImage[i] & 0x01) ? kColorWhite63 : kColorBlack;
+ }
+ } else {
+ uint32 offset = (_section[section].addressHigh << 16) + _section[section].addressLow;
+ if (offset == kInvalidAddress || _section[section].x2 == 0) {
+ return false;
+ }
+ int width = _section[section].x2 - _section[section].x1 + 1;
+ int height = _section[section].y2 - _section[section].y1 + 1;
+ surface->create(width, height, g_system->getScreenFormat());
+ byte *surfacePixels = static_cast<byte *>(surface->getPixels());
+ Common::copy(_encodedImage + offset, _encodedImage + offset + width * height, surfacePixels);
+ }
+ }
+
+ return true;
+}
+
+void MSNImageDecoder::destroy() {
+ if (_palette) {
+ delete[] _palette;
+ _palette = NULL;
+ }
+ if (_encodedImage) {
+ delete[] _encodedImage;
+ _encodedImage = NULL;
+ }
+ for (Common::Array<Graphics::Surface *>::iterator it = _sectionSurfaces.begin();
+ it != _sectionSurfaces.end(); ++it) {
+ (*it)->free();
+ }
+}
+
+}
diff --git a/engines/supernova/graphics.h b/engines/supernova/graphics.h
new file mode 100644
index 0000000000..2a820c9432
--- /dev/null
+++ b/engines/supernova/graphics.h
@@ -0,0 +1,87 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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.
+ *
+ */
+
+#ifndef SUPERNOVA_GRAPHICS_H
+#define SUPERNOVA_GRAPHICS_H
+
+#include "common/scummsys.h"
+#include "image/image_decoder.h"
+
+namespace Common {
+class SeekableReadStream;
+}
+
+namespace Graphics {
+struct Surface;
+}
+
+namespace Supernova {
+
+class MSNImageDecoder : public Image::ImageDecoder {
+public:
+ MSNImageDecoder();
+ virtual ~MSNImageDecoder();
+
+ virtual void destroy();
+ virtual bool loadStream(Common::SeekableReadStream &stream);
+ virtual const Graphics::Surface *getSurface() const { return _sectionSurfaces[0]; }
+ virtual const byte *getPalette() const { return _palette; }
+
+ bool init(int filenumber);
+
+ static const int kMaxSections = 50;
+ static const int kMaxClickFields = 80;
+ static const uint32 kInvalidAddress = 0x00FFFFFF;
+
+ int _filenumber;
+ int _pitch;
+ int _numSections;
+ int _numClickFields;
+ Common::Array<Graphics::Surface *> _sectionSurfaces;
+ byte *_palette;
+ byte *_encodedImage;
+
+ struct Section {
+ int16 x1;
+ int16 x2;
+ byte y1;
+ byte y2;
+ byte next;
+ uint16 addressLow;
+ byte addressHigh;
+ } _section[kMaxSections];
+
+ struct ClickField {
+ int16 x1;
+ int16 x2;
+ byte y1;
+ byte y2;
+ byte next;
+ } _clickField[kMaxClickFields];
+
+private:
+ bool loadFromEngineDataFile();
+ bool loadSections();
+};
+
+}
+#endif
diff --git a/engines/supernova/module.mk b/engines/supernova/module.mk
new file mode 100644
index 0000000000..9baf196c7c
--- /dev/null
+++ b/engines/supernova/module.mk
@@ -0,0 +1,20 @@
+MODULE := engines/supernova
+
+MODULE_OBJS := \
+ console.o \
+ detection.o \
+ graphics.o \
+ supernova.o \
+ rooms.o \
+ state.o
+
+MODULE_DIRS += \
+ engines/supernova
+
+# This module can be built as a plugin
+ifeq ($(ENABLE_SUPERNOVA), DYNAMIC_PLUGIN)
+PLUGIN := 1
+endif
+
+# Include common rules
+include $(srcdir)/rules.mk
diff --git a/engines/supernova/msn_def.h b/engines/supernova/msn_def.h
new file mode 100644
index 0000000000..ad28cd5bef
--- /dev/null
+++ b/engines/supernova/msn_def.h
@@ -0,0 +1,643 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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.
+ *
+ */
+
+#ifndef SUPERNOVA_MSN_DEF_H
+#define SUPERNOVA_MSN_DEF_H
+
+namespace Supernova {
+
+const int kScreenWidth = 320;
+const int kScreenHeight = 200;
+const int kFontWidth = 5;
+const int kFontHeight = 8;
+const int kTextSpeed[] = {19, 14, 10, 7, 4};
+const int kMsecPerTick = 55;
+
+const int kMaxSection = 40;
+const int kMaxDialog = 2;
+const int kMaxObject = 25;
+const int kMaxCarry = 30;
+
+const int kSleepAutosaveSlot = 999;
+
+const byte kShownFalse = 0;
+const byte kShownTrue = 1;
+
+enum MessagePosition {
+ kMessageNormal,
+ kMessageLeft,
+ kMessageRight,
+ kMessageCenter,
+ kMessageTop
+};
+
+enum AudioIndex {
+ kAudioFoundLocation, // 44|0
+ kAudioCrash, // 45|0
+ kAudioVoiceHalt, // 46|0
+ kAudioGunShot, // 46|2510
+ kAudioSmash, // 46|4020
+ kAudioVoiceSupernova, // 47|0
+ kAudioVoiceYeah, // 47|24010
+ kAudioRobotShock, // 48|0
+ kAudioRobotBreaks, // 48|2510
+ kAudioShock, // 48|10520
+ kAudioTurntable, // 48|13530
+ kAudioSiren, // 50|0
+ kAudioSnoring, // 50|12786
+ kAudioRocks, // 51|0
+ kAudioDeath, // 53|0
+ kAudioAlarm, // 54|0
+ kAudioSuccess, // 54|8010
+ kAudioSlideDoor, // 54|24020
+ kAudioDoorOpen, // 54|30030
+ kAudioDoorClose, // 54|31040
+ kAudioNumSamples
+};
+
+enum MusicIndex {
+ kMusicIntro = 52,
+ kMusicOutro = 49
+};
+
+struct AudioInfo {
+ int _filenumber;
+ int _offsetStart;
+ int _offsetEnd;
+};
+
+const int kColorBlack = 0;
+const int kColorWhite25 = 1;
+const int kColorWhite35 = 2;
+const int kColorWhite44 = 3;
+const int kColorWhite99 = 4;
+const int kColorDarkGreen = 5;
+const int kColorGreen = 6;
+const int kColorDarkRed = 7;
+const int kColorRed = 8;
+const int kColorDarkBlue = 9;
+const int kColorBlue = 10;
+const int kColorWhite63 = 11;
+const int kColorLightBlue = 12;
+const int kColorLightGreen = 13;
+const int kColorLightYellow = 14;
+const int kColorLightRed = 15;
+const int kColorCursorTransparent = kColorWhite25;
+
+const byte mouseNormal[64] = {
+ 0xff,0x3f,0xff,0x1f,0xff,0x0f,0xff,0x07,
+ 0xff,0x03,0xff,0x01,0xff,0x00,0x7f,0x00,
+ 0x3f,0x00,0x1f,0x00,0x0f,0x00,0x0f,0x00,
+ 0xff,0x00,0x7f,0x18,0x7f,0x38,0x7f,0xfc,
+
+ 0x00,0x00,0x00,0x40,0x00,0x60,0x00,0x70,
+ 0x00,0x78,0x00,0x7c,0x00,0x7e,0x00,0x7f,
+ 0x80,0x7f,0xc0,0x7f,0xe0,0x7f,0x00,0x7e,
+ 0x00,0x66,0x00,0x43,0x00,0x03,0x00,0x00
+};
+
+const byte mouseWait[64] = {
+ 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,
+ 0x01,0x80,0x01,0x80,0x11,0x88,0x31,0x8c,
+ 0x31,0x8c,0x11,0x88,0x01,0x80,0x01,0x80,
+ 0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,
+
+ 0x00,0x00,0xfe,0x7f,0xf4,0x2f,0xf4,0x2f,
+ 0x14,0x28,0x24,0x24,0x44,0x22,0x84,0x21,
+ 0x84,0x21,0xc4,0x23,0xe4,0x27,0x74,0x2e,
+ 0x34,0x2c,0x14,0x28,0xfe,0x7f,0x00,0x00
+};
+
+const byte font[][5] = {
+ {0x00,0x00,0x00,0xff,0x00},
+ {0x5f,0xff,0x00,0x00,0x00},
+ {0x03,0x00,0x03,0xff,0x00},
+ {0x14,0x7f,0x14,0x7f,0x14},
+ {0x24,0x2a,0x7f,0x2a,0x12},
+ {0x61,0x10,0x08,0x04,0x43},
+ {0x38,0x4e,0x59,0x26,0x50},
+ {0x03,0xff,0x00,0x00,0x00},
+ {0x3e,0x41,0xff,0x00,0x00},
+ {0x41,0x3e,0xff,0x00,0x00},
+ {0x10,0x54,0x38,0x54,0x10},
+ {0x10,0x10,0x7c,0x10,0x10},
+ {0x80,0x40,0xff,0x00,0x00},
+ {0x10,0x10,0x10,0x10,0x10},
+ {0x40,0xff,0x00,0x00,0x00},
+ {0x60,0x10,0x08,0x04,0x03},
+
+ {0x3e,0x41,0x41,0x41,0x3e}, /* digits */
+ {0x04,0x02,0x7f,0xff,0x00},
+ {0x42,0x61,0x51,0x49,0x46},
+ {0x22,0x41,0x49,0x49,0x36},
+ {0x18,0x14,0x12,0x7f,0x10},
+ {0x27,0x45,0x45,0x45,0x39},
+ {0x3e,0x49,0x49,0x49,0x32},
+ {0x01,0x61,0x19,0x07,0x01},
+ {0x36,0x49,0x49,0x49,0x36},
+ {0x26,0x49,0x49,0x49,0x3e},
+
+ {0x44,0xff,0x00,0x00,0x00},
+ {0x80,0x44,0xff,0x00,0x00},
+ {0x10,0x28,0x44,0xff,0x00},
+ {0x28,0x28,0x28,0x28,0x28},
+ {0x44,0x28,0x10,0xff,0x00},
+ {0x02,0x01,0x51,0x09,0x06},
+ {0x3e,0x41,0x5d,0x5d,0x1e},
+
+ {0x7c,0x12,0x11,0x12,0x7c}, /* uppercase letters*/
+ {0x7f,0x49,0x49,0x49,0x36},
+ {0x3e,0x41,0x41,0x41,0x22},
+ {0x7f,0x41,0x41,0x22,0x1c},
+ {0x7f,0x49,0x49,0x49,0xff},
+ {0x7f,0x09,0x09,0x09,0xff},
+ {0x3e,0x41,0x41,0x49,0x3a},
+ {0x7f,0x08,0x08,0x08,0x7f},
+ {0x41,0x7f,0x41,0xff,0x00},
+ {0x20,0x40,0x40,0x3f,0xff},
+ {0x7f,0x08,0x14,0x22,0x41},
+ {0x7f,0x40,0x40,0x40,0xff},
+ {0x7f,0x02,0x04,0x02,0x7f},
+ {0x7f,0x02,0x0c,0x10,0x7f},
+ {0x3e,0x41,0x41,0x41,0x3e},
+ {0x7f,0x09,0x09,0x09,0x06},
+ {0x3e,0x41,0x51,0x21,0x5e},
+ {0x7f,0x09,0x19,0x29,0x46},
+ {0x26,0x49,0x49,0x49,0x32},
+ {0x01,0x01,0x7f,0x01,0x01},
+ {0x3f,0x40,0x40,0x40,0x3f},
+ {0x07,0x18,0x60,0x18,0x07},
+ {0x1f,0x60,0x18,0x60,0x1f},
+ {0x63,0x14,0x08,0x14,0x63},
+ {0x03,0x04,0x78,0x04,0x03},
+ {0x61,0x51,0x49,0x45,0x43},
+
+ {0x7f,0x41,0x41,0xff,0x00},
+ {0x03,0x04,0x08,0x10,0x60},
+ {0x41,0x41,0x7f,0xff,0x00},
+ {0x02,0x01,0x02,0xff,0x00},
+ {0x80,0x80,0x80,0x80,0x80},
+ {0x01,0x02,0xff,0x00,0x00},
+
+ {0x38,0x44,0x44,0x44,0x7c}, /* lowercase letters */
+ {0x7f,0x44,0x44,0x44,0x38},
+ {0x38,0x44,0x44,0x44,0x44},
+ {0x38,0x44,0x44,0x44,0x7f},
+ {0x38,0x54,0x54,0x54,0x58},
+ {0x04,0x7e,0x05,0x01,0xff},
+ {0x98,0xa4,0xa4,0xa4,0x7c},
+ {0x7f,0x04,0x04,0x04,0x78},
+ {0x7d,0xff,0x00,0x00,0x00},
+ {0x80,0x80,0x7d,0xff,0x00},
+ {0x7f,0x10,0x28,0x44,0xff},
+ {0x7f,0xff,0x00,0x00,0x00},
+ {0x7c,0x04,0x7c,0x04,0x78},
+ {0x7c,0x04,0x04,0x04,0x78},
+ {0x38,0x44,0x44,0x44,0x38},
+ {0xfc,0x24,0x24,0x24,0x18},
+ {0x18,0x24,0x24,0x24,0xfc},
+ {0x7c,0x08,0x04,0x04,0xff},
+ {0x48,0x54,0x54,0x54,0x24},
+ {0x04,0x3e,0x44,0x40,0xff},
+ {0x7c,0x40,0x40,0x40,0x3c},
+ {0x0c,0x30,0x40,0x30,0x0c},
+ {0x3c,0x40,0x3c,0x40,0x3c},
+ {0x44,0x28,0x10,0x28,0x44},
+ {0x9c,0xa0,0xa0,0xa0,0x7c},
+ {0x44,0x64,0x54,0x4c,0x44},
+
+ {0x08,0x36,0x41,0xff,0x00},
+ {0x77,0xff,0x00,0x00,0x00},
+ {0x41,0x36,0x08,0xff,0x00},
+ {0x02,0x01,0x02,0x01,0xff},
+ {0xff,0x00,0x00,0x00,0x00},
+
+ {0xfe,0x49,0x49,0x4e,0x30}, /* sharp S */
+
+ {0x7c,0x41,0x40,0x41,0x3c}, /* umlauts */
+
+ {0x04,0x06,0x7f,0x06,0x04}, /* arrows */
+ {0x20,0x60,0xfe,0x60,0x20},
+
+ {0x38,0x45,0x44,0x45,0x7c}, /* umlauts */
+ {0xff,0x00,0x00,0x00,0x00},
+ {0xff,0x00,0x00,0x00,0x00},
+ {0xff,0x00,0x00,0x00,0x00},
+ {0xff,0x00,0x00,0x00,0x00},
+ {0xff,0x00,0x00,0x00,0x00},
+ {0xff,0x00,0x00,0x00,0x00},
+ {0xff,0x00,0x00,0x00,0x00},
+ {0xff,0x00,0x00,0x00,0x00},
+ {0xff,0x00,0x00,0x00,0x00},
+ {0x79,0x14,0x12,0x14,0x79},
+ {0xff,0x00,0x00,0x00,0x00},
+ {0xff,0x00,0x00,0x00,0x00},
+ {0xff,0x00,0x00,0x00,0x00},
+ {0xff,0x00,0x00,0x00,0x00},
+ {0xff,0x00,0x00,0x00,0x00},
+ {0x38,0x45,0x44,0x45,0x38},
+ {0xff,0x00,0x00,0x00,0x00},
+ {0xff,0x00,0x00,0x00,0x00},
+ {0xff,0x00,0x00,0x00,0x00},
+ {0xff,0x00,0x00,0x00,0x00},
+ {0x3d,0x42,0x42,0x42,0x3d},
+ {0x3d,0x40,0x40,0x40,0x3d},
+};
+
+// Default palette
+const byte initVGAPalette[768] = {
+ 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x58, 0x58, 0x58, 0x70, 0x70, 0x70, 0xfc, 0xfc, 0xfc, 0x00, 0xd0, 0x00,
+ 0x00, 0xfc, 0x00, 0xd8, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0xb0, 0xa0, 0xa0, 0xa0,
+ 0x50, 0xc8, 0xfc, 0x28, 0xfc, 0x28, 0xf0, 0xf0, 0x00, 0xfc, 0x28, 0x28, 0x00, 0x00, 0x00, 0x14, 0x14, 0x14,
+ 0x20, 0x20, 0x20, 0x2c, 0x2c, 0x2c, 0x38, 0x38, 0x38, 0x44, 0x44, 0x44, 0x50, 0x50, 0x50, 0x60, 0x60, 0x60,
+ 0x70, 0x70, 0x70, 0x80, 0x80, 0x80, 0x90, 0x90, 0x90, 0xa0, 0xa0, 0xa0, 0xb4, 0xb4, 0xb4, 0xc8, 0xc8, 0xc8,
+ 0xe0, 0xe0, 0xe0, 0xfc, 0xfc, 0xfc, 0x00, 0x00, 0xfc, 0x40, 0x00, 0xfc, 0x7c, 0x00, 0xfc, 0xbc, 0x00, 0xfc,
+ 0xfc, 0x00, 0xfc, 0xfc, 0x00, 0xbc, 0xfc, 0x00, 0x7c, 0xfc, 0x00, 0x40, 0xfc, 0x00, 0x00, 0xfc, 0x40, 0x00,
+ 0xfc, 0x7c, 0x00, 0xfc, 0xbc, 0x00, 0xfc, 0xfc, 0x00, 0xbc, 0xfc, 0x00, 0x7c, 0xfc, 0x00, 0x40, 0xfc, 0x00,
+ 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x40, 0x00, 0xfc, 0x7c, 0x00, 0xfc, 0xbc, 0x00, 0xfc, 0xfc, 0x00, 0xbc, 0xfc,
+ 0x00, 0x7c, 0xfc, 0x00, 0x40, 0xfc, 0x7c, 0x7c, 0xfc, 0x9c, 0x7c, 0xfc, 0xbc, 0x7c, 0xfc, 0xdc, 0x7c, 0xfc,
+ 0xfc, 0x7c, 0xfc, 0xfc, 0x7c, 0xdc, 0xfc, 0x7c, 0xbc, 0xfc, 0x7c, 0x9c, 0xfc, 0x7c, 0x7c, 0xfc, 0x9c, 0x7c,
+ 0xfc, 0xbc, 0x7c, 0xfc, 0xdc, 0x7c, 0xfc, 0xfc, 0x7c, 0xdc, 0xfc, 0x7c, 0xbc, 0xfc, 0x7c, 0x9c, 0xfc, 0x7c,
+ 0x7c, 0xfc, 0x7c, 0x7c, 0xfc, 0x9c, 0x7c, 0xfc, 0xbc, 0x7c, 0xfc, 0xdc, 0x7c, 0xfc, 0xfc, 0x7c, 0xdc, 0xfc,
+ 0x7c, 0xbc, 0xfc, 0x7c, 0x9c, 0xfc, 0xb4, 0xb4, 0xfc, 0xc4, 0xb4, 0xfc, 0xd8, 0xb4, 0xfc, 0xe8, 0xb4, 0xfc,
+ 0xfc, 0xb4, 0xfc, 0xfc, 0xb4, 0xe8, 0xfc, 0xb4, 0xd8, 0xfc, 0xb4, 0xc4, 0xfc, 0xb4, 0xb4, 0xfc, 0xc4, 0xb4,
+ 0xfc, 0xd8, 0xb4, 0xfc, 0xe8, 0xb4, 0xfc, 0xfc, 0xb4, 0xe8, 0xfc, 0xb4, 0xd8, 0xfc, 0xb4, 0xc4, 0xfc, 0xb4,
+ 0xb4, 0xfc, 0xb4, 0xb4, 0xfc, 0xc4, 0xb4, 0xfc, 0xd8, 0xb4, 0xfc, 0xe8, 0xb4, 0xfc, 0xfc, 0xb4, 0xe8, 0xfc,
+ 0xb4, 0xd8, 0xfc, 0xb4, 0xc4, 0xfc, 0x00, 0x00, 0x70, 0x1c, 0x00, 0x70, 0x38, 0x00, 0x70, 0x54, 0x00, 0x70,
+ 0x70, 0x00, 0x70, 0x70, 0x00, 0x54, 0x70, 0x00, 0x38, 0x70, 0x00, 0x1c, 0x70, 0x00, 0x00, 0x70, 0x1c, 0x00,
+ 0x70, 0x38, 0x00, 0x70, 0x54, 0x00, 0x70, 0x70, 0x00, 0x54, 0x70, 0x00, 0x38, 0x70, 0x00, 0x1c, 0x70, 0x00,
+ 0x00, 0x70, 0x00, 0x00, 0x70, 0x1c, 0x00, 0x70, 0x38, 0x00, 0x70, 0x54, 0x00, 0x70, 0x70, 0x00, 0x54, 0x70,
+ 0x00, 0x38, 0x70, 0x00, 0x1c, 0x70, 0x38, 0x38, 0x70, 0x44, 0x38, 0x70, 0x54, 0x38, 0x70, 0x60, 0x38, 0x70,
+ 0x70, 0x38, 0x70, 0x70, 0x38, 0x60, 0x70, 0x38, 0x54, 0x70, 0x38, 0x44, 0x70, 0x38, 0x38, 0x70, 0x44, 0x38,
+ 0x70, 0x54, 0x38, 0x70, 0x60, 0x38, 0x70, 0x70, 0x38, 0x60, 0x70, 0x38, 0x54, 0x70, 0x38, 0x44, 0x70, 0x38,
+ 0x38, 0x70, 0x38, 0x38, 0x70, 0x44, 0x38, 0x70, 0x54, 0x38, 0x70, 0x60, 0x38, 0x70, 0x70, 0x38, 0x60, 0x70,
+ 0x38, 0x54, 0x70, 0x38, 0x44, 0x70, 0x50, 0x50, 0x70, 0x58, 0x50, 0x70, 0x60, 0x50, 0x70, 0x68, 0x50, 0x70,
+ 0x70, 0x50, 0x70, 0x70, 0x50, 0x68, 0x70, 0x50, 0x60, 0x70, 0x50, 0x58, 0x70, 0x50, 0x50, 0x70, 0x58, 0x50,
+ 0x70, 0x60, 0x50, 0x70, 0x68, 0x50, 0x70, 0x70, 0x50, 0x68, 0x70, 0x50, 0x60, 0x70, 0x50, 0x58, 0x70, 0x50,
+ 0x50, 0x70, 0x50, 0x50, 0x70, 0x58, 0x50, 0x70, 0x60, 0x50, 0x70, 0x68, 0x50, 0x70, 0x70, 0x50, 0x68, 0x70,
+ 0x50, 0x60, 0x70, 0x50, 0x58, 0x70, 0x00, 0x00, 0x40, 0x10, 0x00, 0x40, 0x20, 0x00, 0x40, 0x30, 0x00, 0x40,
+ 0x40, 0x00, 0x40, 0x40, 0x00, 0x30, 0x40, 0x00, 0x20, 0x40, 0x00, 0x10, 0x40, 0x00, 0x00, 0x40, 0x10, 0x00,
+ 0x40, 0x20, 0x00, 0x40, 0x30, 0x00, 0x40, 0x40, 0x00, 0x30, 0x40, 0x00, 0x20, 0x40, 0x00, 0x10, 0x40, 0x00,
+ 0x00, 0x40, 0x00, 0x00, 0x40, 0x10, 0x00, 0x40, 0x20, 0x00, 0x40, 0x30, 0x00, 0x40, 0x40, 0x00, 0x30, 0x40,
+ 0x00, 0x20, 0x40, 0x00, 0x10, 0x40, 0x20, 0x20, 0x40, 0x28, 0x20, 0x40, 0x30, 0x20, 0x40, 0x38, 0x20, 0x40,
+ 0x40, 0x20, 0x40, 0x40, 0x20, 0x38, 0x40, 0x20, 0x30, 0x40, 0x20, 0x28, 0x40, 0x20, 0x20, 0x40, 0x28, 0x20,
+ 0x40, 0x30, 0x20, 0x40, 0x38, 0x20, 0x40, 0x40, 0x20, 0x38, 0x40, 0x20, 0x30, 0x40, 0x20, 0x28, 0x40, 0x20,
+ 0x20, 0x40, 0x20, 0x20, 0x40, 0x28, 0x20, 0x40, 0x30, 0x20, 0x40, 0x38, 0x20, 0x40, 0x40, 0x20, 0x38, 0x40,
+ 0x20, 0x30, 0x40, 0x20, 0x28, 0x40, 0x2c, 0x2c, 0x40, 0x30, 0x2c, 0x40, 0x34, 0x2c, 0x40, 0x3c, 0x2c, 0x40,
+ 0x40, 0x2c, 0x40, 0x40, 0x2c, 0x3c, 0x40, 0x2c, 0x34, 0x40, 0x2c, 0x30, 0x40, 0x2c, 0x2c, 0x40, 0x30, 0x2c,
+ 0x40, 0x34, 0x2c, 0x40, 0x3c, 0x2c, 0x40, 0x40, 0x2c, 0x3c, 0x40, 0x2c, 0x34, 0x40, 0x2c, 0x30, 0x40, 0x2c,
+ 0x2c, 0x40, 0x2c, 0x2c, 0x40, 0x30, 0x2c, 0x40, 0x34, 0x2c, 0x40, 0x3c, 0x2c, 0x40, 0x40, 0x2c, 0x3c, 0x40,
+ 0x2c, 0x34, 0x40, 0x2c, 0x30, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+enum ObjectType {
+ NULLTYPE = 0,
+ TAKE = 1,
+ OPENABLE = 2,
+ OPENED = 4,
+ CLOSED = 8,
+ EXIT = 16,
+ PRESS = 32,
+ COMBINABLE = 64,
+ CARRIED = 128,
+ UNNECESSARY = 256,
+ WORN = 512,
+ TALK = 1024,
+ OCCUPIED = 2048,
+ CAUGHT = 4096
+};
+typedef uint16 ObjectTypes;
+
+enum Action {
+ ACTION_WALK,
+ ACTION_LOOK,
+ ACTION_TAKE,
+ ACTION_OPEN,
+ ACTION_CLOSE,
+ ACTION_PRESS,
+ ACTION_PULL,
+ ACTION_USE,
+ ACTION_TALK,
+ ACTION_GIVE
+};
+
+enum RoomID {
+ INTRO,CORRIDOR,HALL,SLEEP,COCKPIT,AIRLOCK,
+ HOLD,LANDINGMODULE,GENERATOR,OUTSIDE,
+ CABIN_R1,CABIN_R2,CABIN_R3,CABIN_L1,CABIN_L2,CABIN_L3,BATHROOM,
+
+ ROCKS,CAVE,MEETUP,ENTRANCE,REST,ROGER,GLIDER,MEETUP2,MEETUP3,
+
+ CELL,CORRIDOR1,CORRIDOR2,CORRIDOR3,CORRIDOR4,CORRIDOR5,CORRIDOR6,CORRIDOR7,CORRIDOR8,CORRIDOR9,
+ BCORRIDOR,GUARD,GUARD3,OFFICE_L1,OFFICE_L2,OFFICE_R1,OFFICE_R2,OFFICE_L,
+ ELEVATOR,STATION,SIGN,OUTRO,NUMROOMS,NULLROOM
+};
+
+enum ObjectID {
+ INVALIDOBJECT = -1,
+ NULLOBJECT = 0,
+ KEYCARD,KNIFE,WATCH,
+ SOCKET,
+ BUTTON,HATCH1,
+ BUTTON1,BUTTON2,MANOMETER,SUIT,HELMET,LIFESUPPORT,
+ SCRAP_LK,OUTERHATCH_TOP,GENERATOR_TOP,TERMINALSTRIP,LANDINGMOD_OUTERHATCH,
+ HOLD_WIRE,
+ LANDINGMOD_BUTTON,LANDINGMOD_SOCKET,LANDINGMOD_WIRE,LANDINGMOD_HATCH,LANDINGMOD_MONITOR,
+ KEYBOARD,
+ KEYCARD2,OUTERHATCH,GENERATOR_WIRE,TRAP,SHORT_WIRE,CLIP,
+ VOLTMETER,LADDER,GENERATOR_ROPE,
+ KITCHEN_HATCH,SLEEP_SLOT,
+ MONITOR,INSTRUMENTS,
+ COMPUTER,CABINS,CABIN,
+ SLOT_K1,SLOT_K2,SLOT_K3,SLOT_K4,
+ SHELF1,SHELF2,SHELF3,SHELF4,
+ ROPE,BOOK,DISCMAN,CHESS,
+ SLOT_KL1,SLOT_KL2,SLOT_KL3,SLOT_KL4,
+ SHELF_L1,SHELF_L2,SHELF_L3,SHELF_L4,
+ PISTOL,BOOK2,SPOOL,
+ RECORD,TURNTABLE,TURNTABLE_BUTTON,WIRE,WIRE2,PLUG,
+ PEN,
+ BATHROOM_DOOR,BATHROOM_EXIT,SHOWER,TOILET,
+
+ STONE,
+ SPACESHIPS,SPACESHIP,STAR,DOOR,MEETUP_SIGN,
+ PORTER,BATHROOM_BUTTON,BATHROOM_SIGN,KITCHEN_SIGN,CAR_SLOT,
+ ARSANO_BATHROOM,COINS,SCHNUCK,EGG,PILL,PILL_HULL,STAIRCASE,
+ MEETUP_EXIT,
+ ROGER_W,WALLET,KEYCARD_R,CUP,
+ GLIDER_BUTTON1,GLIDER_BUTTON2,GLIDER_BUTTON3,GLIDER_BUTTON4,GLIDER_SLOT,GLIDER_BUTTONS,
+ GLIDER_DISPLAY,GLIDER_INSTRUMENTS,GLIDER_KEYCARD,
+ UFO,
+
+ CELL_BUTTON,CELL_TABLE,CELL_WIRE,TRAY,CELL_DOOR,MAGNET,
+ NEWSPAPER,TABLE,
+ PILLAR1,PILLAR2,DOOR1,DOOR2,DOOR3,DOOR4,
+ GUARDIAN,LAMP,
+ MASTERKEYCARD,PAINTING,MONEY,LOCKER,LETTER,
+ JUNGLE,STATION_SLOT,STATION_SIGN
+};
+
+enum StringID {
+ kNoString = -1,
+ // 0
+ kStringCommandGo = 0, kStringCommandLook, kStringCommandTake, kStringCommandOpen, kStringCommandClose,
+ kStringCommandPress, kStringCommandPull, kStringCommandUse, kStringCommandTalk, kStringCommandGive,
+ kStringStatusCommandGo, kStringStatusCommandLook, kStringStatusCommandTake, kStringStatusCommandOpen, kStringStatusCommandClose,
+ kStringStatusCommandPress, kStringStatusCommandPull, kStringStatusCommandUse, kStringStatusCommandTalk, kStringStatusCommandGive,
+ kStringTitleVersion, kStringTitle1, kStringTitle2, kStringTitle3, kStringIntro1,
+ kStringIntro2, kStringIntro3, kStringIntro4, kStringIntro5, kStringIntro6,
+ kStringIntro7, kStringIntro8, kStringIntro9, kStringIntro10, kStringIntro11,
+ kStringIntro12, kStringIntro13, kStringBroken, kStringDefaultDescription, kStringTakeMessage,
+ kStringKeycard, kStringKeycardDescription, kStringKnife, kStringKnifeDescription, kStringWatch,
+ kStringDiscman, kStringDiscmanDescription, kStringHatch, kStringButton, kStringHatchButtonDescription,
+ // 50
+ kStringLadder, kStringExit, kStringCockpitHatchDescription, kStringKitchenHatchDescription, kStringStasisHatchDescription,
+ kStringStasisHatchDescription2, kStringSlot, kStringSlotDescription, kStringCorridor, kStringComputer,
+ kStringComputerPassword, kStringInstruments, kStringInstrumentsDescription1, kStringMonitor, kStringMonitorDescription,
+ kStringImage, kStringGenericDescription1, kStringGenericDescription2, kStringGenericDescription3, kStringGenericDescription4,
+ kStringMagnete, kStringMagneteDescription, kStringPen, kStringPenDescription, kStringShelf,
+ kStringCompartment, kStringSocket, kStringToilet, kStringPistol, kStringPistolDescription,
+ kStringBooks, kStringBooksDescription, kStringSpool, kStringSpoolDescription, kStringBook,
+ kStringUnderwear, kStringUnderwearDescription, kStringClothes, kStringJunk, kStringJunkDescription,
+ kStringFolders, kStringFoldersDescription, kStringPoster, kStringPosterDescription1, kStringPosterDescription2,
+ kStringSpeaker, kStringRecord, kStringRecordDescription, kStringRecordStand, kStringRecordStandDescription,
+ // 100
+ kStringTurntable, kStringTurntableDescription, kStringWire, kStringPlug, kStringImageDescription1,
+ kStringDrawingInstruments, kStringDrawingInstrumentsDescription, kStringChessGame, kStringChessGameDescription1, kStringTennisRacket,
+ kStringTennisRacketDescription, kStringTennisBall, kStringChessGameDescription2, kStringBed, kStringBedDescription,
+ kStringCompartmentDescription, kStringAlbums, kStringAlbumsDescription, kStringRope, kStringRopeDescription,
+ kStringShelfDescription, kStringClothesDescription, kStringSocks, kStringBookHitchhiker, kStringBathroom,
+ kStringBathroomDescription, kStringShower, kStringHatchDescription1, kStringHatchDescription2, kStringHelmet,
+ kStringHelmetDescription, kStringSuit, kStringSuitDescription, kStringLifeSupport, kStringLifeSupportDescription,
+ kStringScrap, kStringScrapDescription1, kStringTerminalStrip, kStringScrapDescription2, kStringReactor,
+ kStringReactorDescription, kStringNozzle, kStringPumpkin, kStringPumpkinDescription, kStringLandingModule,
+ kStringLandingModuleDescription, kStringHatchDescription3, kStringGenerator, kStringGeneratorDescription, kStringScrapDescription3,
+ // 150
+ kSafetyButtonDescription, kStringKeyboard, kStringGeneratorWire, kStringEmptySpool, kStringKeycard2,
+ kStringKeycard2Description, kStringTrap, kStringVoltmeter, kStringClip, kStringWireDescription,
+ kStringStone, kStringCaveOpening, kStringCaveOpeningDescription, kStringExitDescription, kStringCave,
+ kStringSign, kStringSignDescription, kStringEntrance, kStringStar, kStringSpaceshift,
+ kStringPorter, kStringPorterDescription, kStringDoor, kStringChewingGum, kStringGummyBears,
+ kStringChocolateBall, kStringEgg, kStringLiquorice, kStringPill, kStringPillDescription,
+ kStringVendingMachine, kStringVendingMachineDescription, kStringToiletDescription, kStringStaircase, kStringCoins,
+ kStringCoinsDescription, kStringTabletPackage, kStringTabletPackageDescription, kStringChair, kStringShoes,
+ kStringShoesDescription, kStringFrogFace, kStringScrible, kStringScribleDescription, kStringWallet,
+ kStringMenu, kStringMenuDescription, kStringCup, kStringCupDescription, kStringBill,
+ // 200
+ kStringBillDescription, kStringKeycard3, kStringAnnouncement, kStringAnnouncementDescription, kStringRoger,
+ kStringUfo, kStringUfoDescription, kStringTray, kStringTrayDescription, kStringLamp,
+ kStringLampDescription, kStringEyes, kStringEyesDescription, kStringSocketDescription, kStringMetalBlock,
+ kStringMetalBlockDescription, kStringRobot, kStringRobotDescription, kStringTable, kStringTableDescription,
+ kStringCellDoor, kStringCellDoorDescription, kStringLaptop, kStringWristwatch, kStringPillar,
+ kStringDoorDescription1, kStringDoorDescription2, kStringDoorDescription3, kStringDoorDescription4, kStringDontEnter,
+ kStringAxacussan, kStringAxacussanDescription, kStringImageDescription2, kStringMastercard, kStringMastercardDescription,
+ kStringLamp2, kStringGenericDescription5, kStringMoney, kStringMoneyDescription1, kStringLocker,
+ kStringLockerDescription, kStringLetter, kStringCube, kStringGenericDescription6, kStringGenericDescription7,
+ kStringStrangeThing, kStringGenericDescription8, kStringImageDescription3, kStringPlant, kStringStatue,
+ // 250
+ kStringStatueDescription, kStringPlantDescription, kStringComputerDescription, kStringGraffiti, kStringGraffitiDescription,
+ kStringMoneyDescription2, kStringJungle, kStringJungleDescription, kStringOutro1, kStringOutro2,
+ kStringOutro3, kStringOutro4, kStringOutro5, kStringOutro6, kStringOutro7,
+ kStringOutro8, kStringOutro9, kStringOutro10, kStringOutro11, kStringOutro12,
+ kStringOutro13, kStringOutro14, kStringWireAndPlug, kStringWireAndClip, kStringWireAndPlug2,
+ // 275
+ kStringSignDescription2, kStringCoin, kStringDoorDescription5, kStringDoorDescription6, kStringKeycard2Description2,
+ kSringSpoolAndClip, kStringIntroCutscene1, kStringIntroCutscene2, kStringIntroCutscene3, kStringIntroCutscene4,
+ kStringIntroCutscene5, kStringIntroCutscene6, kStringIntroCutscene7, kStringIntroCutscene8, kStringIntroCutscene9,
+ kStringIntroCutscene10, kStringIntroCutscene11, kStringIntroCutscene12, kStringIntroCutscene13, kStringIntroCutscene14,
+ kStringIntroCutscene15, kStringIntroCutscene16, kStringIntroCutscene17, kStringIntroCutscene18, kStringIntroCutscene19,
+ // 300
+ kStringIntroCutscene20, kStringIntroCutscene21, kStringIntroCutscene22, kStringIntroCutscene23, kStringIntroCutscene24,
+ kStringIntroCutscene25, kStringIntroCutscene26, kStringIntroCutscene27, kStringIntroCutscene28, kStringIntroCutscene29,
+ kStringIntroCutscene30, kStringIntroCutscene31, kStringIntroCutscene32, kStringIntroCutscene33, kStringIntroCutscene34,
+ kStringIntroCutscene35, kStringIntroCutscene36, kStringIntroCutscene37, kStringIntroCutscene38, kStringIntroCutscene39,
+ kStringIntroCutscene40, kStringIntroCutscene41, kStringIntroCutscene42, kStringShipHall1, kStringShipSleepCabin1,
+ //325
+ kStringShipSleepCabin2, kStringShipSleepCabin3, kStringShipSleepCabin4, kStringShipSleepCabin5, kStringShipSleepCabin6,
+ kStringShipSleepCabin7, kStringShipSleepCabin8, kStringShipSleepCabin9, kStringShipSleepCabin10, kStringShipSleepCabin11,
+ kStringShipSleepCabin12, kStringShipSleepCabin13, kStringShipSleepCabin14, kStringShipSleepCabin15, kStringShipSleepCabin16,
+ kStringShipCockpit1, kStringShipCockpit2, kStringShipCockpit3, kStringShipCockpit4, kStringShipCockpit5,
+ kStringShipCockpit6, kStringShipCockpit7, kStringShipCockpit8, kStringShipCockpit9, kStringShipCockpit10,
+ // 350
+ kStringShipCockpit11, kStringShipCockpit12, kStringShipCockpit13, kStringShipCabinL3_1, kStringShipCabinL3_2,
+ kStringShipCabinL3_3, kStringShipCabinL3_4, kStringShipCabinL3_5, kStringShipAirlock1, kStringShipAirlock2,
+ kStringShipAirlock3, kStringShipAirlock4, kStringShipHold1, kStringCable1, kStringCable2,
+ kStringCable3, kStringCable4, kStringShipHold2, kStringShipHold3, kStringShipHold4,
+ kStringShipHold5, kStringShipHold6, kStringShipHold7, kStringShipHold8, kStringShipHold9,
+ // 375
+ kStringShipHold10, kStringShipHold11, kStringShipHold12, kStringShipHold13, kStringShipHold14,
+ kStringShipHold15, kStringShipHold16, kStringArsanoMeetup1, kStringArsanoMeetup2, kStringArsanoMeetup3,
+ kStringArsanoEntrance1, kStringArsanoEntrance2, kStringArsanoEntrance3, kStringArsanoEntrance4, kStringArsanoEntrance5,
+ kStringArsanoEntrance6, kStringArsanoEntrance7, kStringArsanoEntrance8, kStringArsanoEntrance9, kStringArsanoEntrance10,
+ kStringArsanoEntrance11, kStringArsanoEntrance12, kStringArsanoEntrance13, kStringArsanoEntrance14, kStringArsanoEntrance15,
+ // 400
+ kStringArsanoEntrance16, kStringArsanoEntrance17, kStringArsanoEntrance18, kStringArsanoEntrance19, kStringArsanoEntrance20,
+ kStringArsanoEntrance21, kStringArsanoEntrance22, kStringArsanoEntrance23, kStringArsanoEntrance24, kStringArsanoEntrance25,
+ kStringArsanoEntrance26, kStringArsanoEntrance27, kStringArsanoDialog1, kStringArsanoDialog2, kStringArsanoDialog3,
+ kStringArsanoDialog4, kStringArsanoDialog5, kStringArsanoDialog6, kStringArsanoDialog7, kStringArsanoDialog8,
+ kStringArsanoDialog9, kStringDialogSeparator, kStringDialogArsanoRoger1, kStringDialogArsanoRoger2, kStringDialogArsanoRoger3,
+ // 425
+ kStringDialogArsanoMeetup3_1, kStringDialogArsanoMeetup3_2, kStringDialogArsanoMeetup3_3, kStringDialogArsanoMeetup3_4, kStringDialogArsanoMeetup3_5,
+ kStringArsanoRoger1, kStringArsanoRoger2, kStringArsanoRoger3, kStringArsanoRoger4, kStringArsanoRoger5,
+ kStringArsanoRoger6, kStringArsanoRoger7, kStringArsanoRoger8, kStringArsanoRoger9, kStringArsanoRoger10,
+ kStringArsanoRoger11, kStringArsanoRoger12, kStringArsanoRoger13, kStringArsanoRoger14, kStringArsanoRoger15,
+ kStringArsanoRoger16, kStringArsanoRoger17, kStringArsanoRoger18, kStringArsanoRoger19, kStringArsanoRoger20,
+ // 450
+ kStringArsanoRoger21, kStringArsanoRoger22, kStringArsanoRoger23, kStringArsanoRoger24, kStringArsanoRoger25,
+ kStringArsanoRoger26, kStringArsanoRoger27, kStringArsanoRoger28, kStringArsanoRoger29, kStringArsanoRoger30,
+ kStringArsanoRoger31, kStringArsanoRoger32, kStringArsanoRoger33, kStringArsanoRoger34, kStringArsanoRoger35,
+ kStringArsanoRoger36, kStringArsanoRoger37, kStringArsanoRoger38, kStringArsanoRoger39, kStringArsanoRoger40,
+ kStringArsanoGlider1, kStringArsanoMeetup2_1, kStringArsanoMeetup2_2, kStringArsanoMeetup2_3, kStringArsanoMeetup2_4,
+ // 475
+ kStringArsanoMeetup2_5, kStringArsanoMeetup2_6, kStringArsanoMeetup2_7, kStringArsanoMeetup2_8, kStringArsanoMeetup2_9,
+ kStringArsanoMeetup2_10, kStringArsanoMeetup2_11, kStringArsanoMeetup2_12, kStringArsanoMeetup2_13, kStringArsanoMeetup3_1,
+ kStringArsanoMeetup3_2, kStringArsanoMeetup3_3, kStringArsanoMeetup3_4, kStringArsanoMeetup3_5, kStringArsanoMeetup3_6,
+ kStringArsanoMeetup3_7, kStringArsanoMeetup3_8, kStringArsanoMeetup3_9, kStringArsanoMeetup3_10, kStringArsanoMeetup3_11,
+ kStringArsanoMeetup3_12, kStringArsanoMeetup3_13, kStringArsanoMeetup3_14, kStringArsanoMeetup3_15, kStringArsanoMeetup3_16,
+ // 500
+ kStringArsanoMeetup3_17, kStringArsanoMeetup3_18, kStringArsanoMeetup3_19, kStringArsanoMeetup3_20, kStringArsanoMeetup3_21,
+ kStringArsanoMeetup3_22, kStringArsanoMeetup3_23, kStringArsanoMeetup3_24, kStringArsanoMeetup3_25, kStringArsanoMeetup3_26,
+ kStringArsanoMeetup3_27, kStringArsanoMeetup3_28, kStringAxacussCell_1, kStringAxacussCell_2, kStringAxacussCell_3,
+ kStringAxacussCell_4, kStringAxacussCell_5, kStringOk, kStringDialogArsanoMeetup2_1, kStringDialogArsanoMeetup2_2,
+ kStringDialogArsanoMeetup2_3, kStringDialogArsanoMeetup2_4, kStringDialogArsanoMeetup2_5, kStringDialogArsanoMeetup2_6, kStringDialogArsanoMeetup2_7,
+ // 525
+ kStringDialogArsanoMeetup2_8, kStringDialogArsanoMeetup2_9, kStringDialogArsanoMeetup2_10, kStringDialogArsanoMeetup2_11, kStringDialogAxacussCorridor5_1,
+ kStringDialogAxacussCorridor5_2, kStringDialogAxacussCorridor5_3, kStringDialogAxacussCorridor5_4, kStringDialogAxacussCorridor5_5, kStringDialogAxacussCorridor5_6,
+ kStringDialogAxacussCorridor5_7, kStringDialogX1, kStringDialogX2, kStringDialogX3, kStringAxacussCorridor5_1,
+ kStringAxacussCorridor5_2, kStringAxacussCorridor5_3, kStringAxacussCorridor5_4, kStringAxacussCorridor5_5, kStringAxacussCorridor5_6,
+ kStringAxacussCorridor5_7, kStringAxacussBcorridor_1, kStringAxacussOffice1_1, kStringAxacussOffice1_2, kStringAxacussOffice1_3,
+ // 550
+ kStringAxacussOffice1_4, kStringAxacussOffice1_5, kStringAxacussOffice1_6, kStringAxacussOffice1_7, kStringAxacussOffice1_8,
+ kStringAxacussOffice1_9, kStringAxacussOffice1_10, kStringAxacussOffice1_11, kStringAxacussOffice1_12, kStringAxacussOffice1_13,
+ kStringAxacussOffice1_14, kStringAxacussOffice1_15, kStringAxacussOffice1_16, kStringAxacussOffice3_1, kStringAxacussElevator_1,
+ kStringAxacussElevator_2, kStringAxacussElevator_3, kStringShock, kStringShot, kStringCloseLocker_1,
+ kStringIsHelmetOff_1, kStringGenericInteract_1, kStringGenericInteract_2, kStringGenericInteract_3, kStringGenericInteract_4,
+ // 575
+ kStringGenericInteract_5, kStringGenericInteract_6, kStringGenericInteract_7, kStringGenericInteract_8, kStringGenericInteract_9,
+ kStringGenericInteract_10, kStringGenericInteract_11, kStringGenericInteract_12, kPhrasalVerbParticleGiveTo, kPhrasalVerbParticleUseWith,
+ kStringGenericInteract_13, kStringGenericInteract_14, kStringGenericInteract_15, kStringGenericInteract_16, kStringGenericInteract_17,
+ kStringGenericInteract_18, kStringGenericInteract_19, kStringGenericInteract_20, kStringGenericInteract_21, kStringGenericInteract_22,
+ kStringGenericInteract_23, kStringGenericInteract_24, kStringGenericInteract_25, kStringGenericInteract_26, kStringGenericInteract_27,
+ // 600
+ kStringGenericInteract_28, kStringGenericInteract_29, kStringGenericInteract_30, kStringGenericInteract_31, kStringGenericInteract_32,
+ kStringGenericInteract_33, kStringGenericInteract_34, kStringGenericInteract_35, kStringGenericInteract_36, kStringGenericInteract_37,
+ kStringGenericInteract_38, kStringGenericInteract_39, kStringGenericInteract_40, kStringGenericInteract_41, kStringGenericInteract_42,
+ kStringGenericInteract_43, kStringConversationEnd, kStringSupernova1, kStringSupernova2, kStringSupernova3,
+ kStringSupernova4, kStringSupernova5, kStringSupernova6, kStringSupernova7, kStringSupernova8,
+ // 625
+ kStringTextSpeed, kStringGuardNoticed1, kStringGuardNoticed2, kStringTelomat1, kStringTelomat2,
+ kStringTelomat3, kStringTelomat4, kStringTelomat5, kStringTelomat6, kStringTelomat7,
+ kStringTelomat8, kStringTelomat9, kStringTelomat10, kStringTelomat11, kStringTelomat12,
+ kStringTelomat13, kStringTelomat14, kStringTelomat15, kStringTelomat16, kStringTelomat17,
+ kStringTelomat18, kStringTelomat19, kStringTelomat20, kStringTelomat21, kStringAlarm,
+
+ // Add two placeholder strings at the end for variable text
+ kStringPlaceholder1, kStringPlaceholder2,
+
+ // String for money in inventory
+ kStringInventoryMoney
+};
+
+ObjectType operator|(ObjectType a, ObjectType b);
+ObjectType operator&(ObjectType a, ObjectType b);
+ObjectType operator^(ObjectType a, ObjectType b);
+ObjectType &operator|=(ObjectType &a, ObjectType b);
+ObjectType &operator&=(ObjectType &a, ObjectType b);
+ObjectType &operator^=(ObjectType &a, ObjectType b);
+
+struct Object {
+ static const Object nullObject;
+
+ Object()
+ : _name(kNoString)
+ , _description(kStringDefaultDescription)
+ , _id(INVALIDOBJECT)
+ , _roomId(NULLROOM)
+ , _type(NULLTYPE)
+ , _click(0)
+ , _click2(0)
+ , _section(0)
+ , _exitRoom(NULLROOM)
+ , _direction(0)
+ {}
+ Object(byte roomId, StringID name, StringID description, ObjectID id, ObjectType type,
+ byte click, byte click2, byte section = 0, RoomID exitRoom = NULLROOM, byte direction = 0)
+ : _name(name)
+ , _description(description)
+ , _id(id)
+ , _roomId(roomId)
+ , _type(type)
+ , _click(click)
+ , _click2(click2)
+ , _section(section)
+ , _exitRoom(exitRoom)
+ , _direction(direction)
+ {}
+
+ static void setObjectNull(Object *&obj) {
+ obj = const_cast<Object *>(&nullObject);
+ }
+ static bool isNullObject(Object *obj) {
+ return obj == &nullObject;
+ }
+ void resetProperty(ObjectType type = NULLTYPE) {
+ _type = type;
+ }
+
+ void setProperty(ObjectType type) {
+ _type |= type;
+ }
+
+ void disableProperty(ObjectType type) {
+ _type &= ~type;
+ }
+
+ bool hasProperty(ObjectType type) const {
+ return _type & type;
+ }
+
+ static bool combine(Object &obj1, Object &obj2, ObjectID id1, ObjectID id2) {
+ if (obj1.hasProperty(COMBINABLE))
+ return (((obj1._id == id1) && (obj2._id == id2)) ||
+ ((obj1._id == id2) && (obj2._id == id1)));
+ else
+ return false;
+ }
+
+ byte _roomId;
+ StringID _name;
+ StringID _description;
+ ObjectID _id;
+ ObjectTypes _type;
+ byte _click;
+ byte _click2;
+ byte _section;
+ RoomID _exitRoom;
+ byte _direction;
+};
+
+#define ticksToMsec(x) (x * kMsecPerTick)
+
+}
+
+#endif // SUPERNOVA_MSN_DEF_H
diff --git a/engines/supernova/rooms.cpp b/engines/supernova/rooms.cpp
new file mode 100644
index 0000000000..d8b138f9a7
--- /dev/null
+++ b/engines/supernova/rooms.cpp
@@ -0,0 +1,3247 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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.
+ *
+ */
+
+#include "common/system.h"
+#include "graphics/palette.h"
+#include "graphics/cursorman.h"
+
+#include "supernova/supernova.h"
+#include "supernova/state.h"
+
+namespace Supernova {
+
+bool Room::serialize(Common::WriteStream *out) {
+ if (out->err())
+ return false;
+
+ out->writeSint32LE(_id);
+ for (int i = 0; i < kMaxSection; ++i)
+ out->writeByte(_shown[i]);
+ for (int i = 0; i < kMaxDialog ; ++i)
+ out->writeByte(_sentenceRemoved[i]);
+
+ int numObjects = 0;
+ while ((_objectState[numObjects]._id != INVALIDOBJECT) && (numObjects < kMaxObject))
+ ++numObjects;
+ out->writeSint32LE(numObjects);
+
+ for (int i = 0; i < numObjects; ++i) {
+ out->writeSint32LE(_objectState[i]._name);
+ out->writeSint32LE(_objectState[i]._description);
+ out->writeByte(_objectState[i]._roomId);
+ out->writeSint32LE(_objectState[i]._id);
+ out->writeSint32LE(_objectState[i]._type);
+ out->writeByte(_objectState[i]._click);
+ out->writeByte(_objectState[i]._click2);
+ out->writeByte(_objectState[i]._section);
+ out->writeSint32LE(_objectState[i]._exitRoom);
+ out->writeByte(_objectState[i]._direction);
+ }
+
+ out->writeByte(_seen);
+
+ return !out->err();
+}
+
+bool Room::deserialize(Common::ReadStream *in, int version) {
+ if (in->err())
+ return false;
+
+ in->readSint32LE();
+
+ for (int i = 0; i < kMaxSection; ++i)
+ _shown[i] = in->readByte();
+
+ // Prior to version 3, _sentenceRemoved was part of _shown (the last two values)
+ // But on the other hand dialog was not implemented anyway, so we don't even try to
+ // recover it.
+ for (int i = 0; i < kMaxDialog ; ++i)
+ _sentenceRemoved[i] = version < 3 ? 0 : in->readByte();
+
+ int numObjects = in->readSint32LE();
+ for (int i = 0; i < numObjects; ++i) {
+ _objectState[i]._name = static_cast<StringID>(in->readSint32LE());
+ _objectState[i]._description = static_cast<StringID>(in->readSint32LE());
+ _objectState[i]._roomId = in->readByte();
+ _objectState[i]._id = static_cast<ObjectID>(in->readSint32LE());
+ _objectState[i]._type = static_cast<ObjectType>(in->readSint32LE());
+ _objectState[i]._click = in->readByte();
+ _objectState[i]._click2 = in->readByte();
+ _objectState[i]._section = in->readByte();
+ _objectState[i]._exitRoom = static_cast<RoomID>(in->readSint32LE());
+ _objectState[i]._direction = in->readByte();
+ }
+
+ _seen = in->readByte();
+
+ return !in->err();
+}
+
+Intro::Intro(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = -1;
+ _id = INTRO;
+ _shown[0] = kShownFalse;
+
+ _objectState[0] =
+ Object(_id, kStringKeycard, kStringKeycardDescription, KEYCARD,
+ TAKE | CARRIED | COMBINABLE, 255, 255, 0, NULLROOM, 0);
+ _objectState[1] =
+ Object(_id, kStringKnife, kStringKnifeDescription, KNIFE,
+ TAKE | CARRIED | COMBINABLE, 255, 255, 0, NULLROOM, 0);
+ _objectState[2] =
+ Object(_id, kStringWatch, kStringDefaultDescription, WATCH,
+ TAKE | COMBINABLE | CARRIED, 255, 255, 8, NULLROOM, 0);
+ _objectState[3] =
+ Object(_id, kStringDiscman, kStringDiscmanDescription, DISCMAN,
+ TAKE | COMBINABLE, 255, 255, 0, NULLROOM, 0);
+ _objectState[4] =
+ Object(_id, kStringInventoryMoney, kStringDefaultDescription, MONEY,
+ TAKE | COMBINABLE, 255, 255, 0);
+
+ _shouldExit = false;
+
+ introText =
+ _vm->getGameString(kStringIntro1) +
+ _vm->getGameString(kStringIntro2) +
+ _vm->getGameString(kStringIntro3) +
+ _vm->getGameString(kStringIntro4) +
+ _vm->getGameString(kStringIntro5) +
+ _vm->getGameString(kStringIntro6) +
+ _vm->getGameString(kStringIntro7) +
+ _vm->getGameString(kStringIntro8) +
+ _vm->getGameString(kStringIntro9) +
+ _vm->getGameString(kStringIntro10) +
+ _vm->getGameString(kStringIntro11) +
+ _vm->getGameString(kStringIntro12) +
+ _vm->getGameString(kStringIntro13);
+}
+
+void Intro::onEntrance() {
+ _gm->_guiEnabled = false;
+ _vm->_allowSaveGame = false;
+ _vm->_allowLoadGame = false;
+ titleScreen();
+ cutscene();
+ leaveCutscene();
+}
+
+void Intro::titleScreen() {
+ // Newspaper
+ CursorMan.showMouse(false);
+ _vm->_brightness = 0;
+ _vm->_menuBrightness = 0;
+ _vm->paletteBrightness();
+ _vm->setCurrentImage(1);
+ _vm->renderImage(0);
+ _vm->paletteFadeIn();
+ _gm->getInput();
+ _vm->paletteFadeOut();
+
+ // Title Screen
+ _vm->setCurrentImage(31);
+ _vm->renderImage(0);
+ _vm->paletteFadeIn();
+ _gm->wait2(1);
+ _vm->playSound(kAudioVoiceSupernova);
+ while (_vm->_mixer->isSoundHandleActive(_vm->_soundHandle))
+ _gm->wait2(1);
+ titleFadeIn();
+ _vm->renderText(kStringTitleVersion, 295, 190, kColorWhite44);
+ const Common::String& title1 = _vm->getGameString(kStringTitle1);
+ const Common::String& title2 = _vm->getGameString(kStringTitle2);
+ const Common::String& title3 = _vm->getGameString(kStringTitle3);
+ _vm->renderText(title1, 78 - _vm->textWidth(title1) / 2, 120, kColorLightBlue);
+ _vm->renderText(title2, 78 - _vm->textWidth(title2) / 2, 132, kColorWhite99);
+ _vm->renderText(title3, 78 - _vm->textWidth(title3) / 2, 142, kColorWhite99);
+ _gm->wait2(1);
+ CursorMan.showMouse(true);
+ _vm->playSoundMod(kMusicIntro);
+ _gm->getInput();
+ // TODO: render animated text
+ _vm->playSound(kAudioVoiceYeah);
+ while (_vm->_mixer->isSoundHandleActive(_vm->_soundHandle))
+ _gm->wait2(1);
+ _vm->paletteFadeOut();
+}
+
+void Intro::titleFadeIn() {
+ byte titlePaletteColor[] = {0xfe, 0xeb};
+ byte titleNewColor[2][3] = {{255, 255, 255}, {199, 21, 21}};
+ byte newColors[2][3];
+
+ for (int brightness = 1; brightness <= 40; ++brightness) {
+ for (int colorIndex = 0; colorIndex < 2; ++colorIndex) {
+ for (int i = 0; i < 3; ++i) {
+ newColors[colorIndex][i] = (titleNewColor[colorIndex][i] * brightness) / 40;
+ }
+ }
+
+ _vm->_system->getPaletteManager()->setPalette(newColors[0], titlePaletteColor[0], 1);
+ _vm->_system->getPaletteManager()->setPalette(newColors[1], titlePaletteColor[1], 1);
+ _vm->_system->updateScreen();
+ _vm->_system->delayMillis(_vm->_delay);
+ }
+}
+
+bool Intro::animate(int section1, int section2, int duration) {
+ Common::KeyCode key = Common::KEYCODE_INVALID;
+ while (duration) {
+ _vm->renderImage(section1);
+ if (_gm->waitOnInput(2, key))
+ return key != Common::KEYCODE_ESCAPE;
+ _vm->renderImage(section2);
+ if (_gm->waitOnInput(2, key))
+ return key != Common::KEYCODE_ESCAPE;
+ --duration;
+ }
+ return true;
+}
+
+bool Intro::animate(int section1, int section2, int duration,
+ MessagePosition position, StringID textId) {
+ Common::KeyCode key = Common::KEYCODE_INVALID;
+ const Common::String& text = _vm->getGameString(textId);
+ _vm->renderMessage(text, position);
+ int delay = (MIN(text.size(), (uint)512) + 20) * (10 - duration) * _vm->_textSpeed / 400;
+ while (delay) {
+ if (section1)
+ _vm->renderImage(section1);
+ if (_gm->waitOnInput(2, key)) {
+ _vm->removeMessage();
+ return key != Common::KEYCODE_ESCAPE;
+ }
+ if (section2)
+ _vm->renderImage(section2);
+ if (_gm->waitOnInput(2, key)) {
+ _vm->removeMessage();
+ return key != Common::KEYCODE_ESCAPE;
+ }
+ --delay;
+ }
+ _vm->removeMessage();
+ return true;
+}
+
+bool Intro::animate(int section1, int section2, int section3, int section4,
+ int duration, MessagePosition position, StringID textId) {
+ Common::KeyCode key = Common::KEYCODE_INVALID;
+ const Common::String& text = _vm->getGameString(textId);
+ _vm->renderMessage(text, position);
+ if (duration == 0)
+ duration = (MIN(text.size(), (uint)512) + 20) * _vm->_textSpeed / 40;
+
+ while(duration) {
+ _vm->renderImage(section1);
+ _vm->renderImage(section3);
+ if (_gm->waitOnInput(2, key)) {
+ _vm->removeMessage();
+ return key != Common::KEYCODE_ESCAPE;
+ }
+ _vm->renderImage(section2);
+ _vm->renderImage(section4);
+ if (_gm->waitOnInput(2, key)) {
+ _vm->removeMessage();
+ return key != Common::KEYCODE_ESCAPE;
+ }
+ duration--;
+ }
+ _vm->removeMessage();
+ return true;
+}
+
+void Intro::cutscene() {
+#define exitOnEscape(X) do { \
+ Common::KeyCode key = Common::KEYCODE_INVALID; \
+ if ((_gm->waitOnInput(X, key) && key == Common::KEYCODE_ESCAPE) || _vm->shouldQuit()) { \
+ CursorMan.showMouse(true); \
+ return; \
+ } \
+} while (0);
+
+ _vm->_system->fillScreen(kColorBlack);
+ _vm->setCurrentImage(31);
+ _vm->_menuBrightness = 255;
+ _vm->paletteBrightness();
+ if (!animate(0, 0, 0, kMessageNormal, kStringIntroCutscene1))
+ return;
+ _vm->_menuBrightness = 0;
+ _vm->paletteBrightness();
+ exitOnEscape(1);
+
+ _vm->setCurrentImage(9);
+ _vm->renderImage(0);
+ _vm->renderImage(1);
+ _vm->renderImage(9);
+ _vm->paletteFadeIn();
+ if (!animate(11, 10, 6, kMessageRight, kStringIntroCutscene2))
+ return;
+ _vm->renderImage(3);
+ exitOnEscape(4);
+ _vm->renderImage(4);
+ if (!animate(11, 10, 3)) {// test duration
+ _vm->removeMessage();
+ return;
+ }
+ _vm->removeMessage();
+ if (!animate(5, 4, 0, kMessageLeft, kStringIntroCutscene3))
+ return;
+ _vm->renderImage(3);
+ exitOnEscape(3);
+ _vm->renderImage(2);
+ exitOnEscape(3);
+ _vm->renderImage(7);
+ exitOnEscape(6);
+ _vm->renderImage(6);
+ exitOnEscape(6);
+ if (!animate(0, 0, 0, kMessageLeft, kStringIntroCutscene4))
+ return;
+ _vm->renderMessage(kStringIntroCutscene5, kMessageLeft);
+ exitOnEscape(28);
+ _vm->removeMessage();
+ _vm->renderMessage(kStringIntroCutscene6, kMessageLeft);
+ exitOnEscape(28);
+ _vm->removeMessage();
+
+ StringID textCounting[4] =
+ {kStringIntroCutscene7, kStringIntroCutscene8, kStringIntroCutscene9, kStringIntroCutscene10};
+ _vm->setCurrentImage(31);
+ _vm->renderImage(0);
+ _vm->paletteBrightness();
+ for (int i = 0; i < 4; ++i){
+ _vm->renderMessage(textCounting[i], kMessageLeft);
+ for (int j = 0; j < 28; ++j) {
+ _vm->renderImage((j % 3) + 1);
+ Common::KeyCode key = Common::KEYCODE_INVALID;
+ if (_gm->waitOnInput(1, key)) {
+ if (key == Common::KEYCODE_ESCAPE)
+ return;
+ break;
+ }
+ }
+ _vm->removeMessage();
+ }
+ _vm->renderMessage(kStringIntroCutscene11, kMessageLeft);
+ _vm->renderImage(6);
+ exitOnEscape(3);
+ _vm->renderImage(3);
+ exitOnEscape(3);
+ _vm->renderImage(4);
+ exitOnEscape(3);
+ _vm->renderImage(5);
+ exitOnEscape(3);
+ _vm->renderImage(_gm->invertSection(5));
+ exitOnEscape(18);
+ _vm->removeMessage();
+
+ _vm->setCurrentImage(9);
+ _vm->renderImage(0);
+ _vm->renderImage(1);
+ _vm->renderImage(9);
+ _vm->paletteBrightness();
+ _vm->renderBox(0, 138, 320, 62, kColorBlack);
+ _vm->paletteBrightness();
+ if (!animate(11, 10, 0, kMessageRight, kStringIntroCutscene12))
+ return;
+ _vm->renderImage(3);
+ exitOnEscape(3);
+ _vm->renderImage(4);
+ if (!animate(5, 4, 0, kMessageLeft, kStringIntroCutscene13))
+ return;
+ if (!animate(0, 0, 0, kMessageCenter, kStringIntroCutscene14))
+ return;
+ _vm->renderImage(12);
+ exitOnEscape(2);
+ _vm->renderImage(13);
+ exitOnEscape(2);
+ _vm->renderImage(14);
+ if (!animate(19, 20, 0, kMessageRight, kStringIntroCutscene15))
+ return;
+ if (!animate(0, 0, 0, kMessageCenter, kStringIntroCutscene16))
+ return;
+ exitOnEscape(20);
+ if (!animate(0, 0, 0, kMessageCenter, kStringIntroCutscene17))
+ return;
+ if (!animate(19, 20, 0, kMessageRight, kStringIntroCutscene18))
+ return;
+ if (!animate(0, 0, 0, kMessageCenter, kStringIntroCutscene19))
+ return;
+ _vm->renderImage(16);
+ exitOnEscape(3);
+ _vm->renderImage(17);
+ if (!animate(19, 20, 18, 17, 0, kMessageRight, kStringIntroCutscene20))
+ return;
+ if (!animate(19, 20, 18, 17, 0, kMessageRight, kStringIntroCutscene21))
+ return;
+ if (!animate(5, 4, 0, kMessageLeft, kStringIntroCutscene3))
+ return;
+ _vm->renderImage(3);
+ exitOnEscape(3);
+ _vm->renderImage(2);
+ exitOnEscape(3);
+ _vm->renderImage(8);
+ exitOnEscape(6);
+ _vm->renderImage(6);
+ _vm->playSound(kAudioSiren);
+
+ exitOnEscape(6);
+ _vm->renderImage(3);
+ exitOnEscape(3);
+ _vm->renderImage(4);
+ _vm->renderImage(16);
+ exitOnEscape(3);
+ _vm->renderImage(15);
+ if (!animate(19, 20, 0, kMessageRight, kStringIntroCutscene22))
+ return;
+ if (!animate(19, 20, 0, kMessageRight, kStringIntroCutscene23))
+ return;
+ exitOnEscape(10);
+ _vm->renderImage(13);
+ exitOnEscape(2);
+ _vm->renderImage(12);
+ exitOnEscape(2);
+ _vm->renderImage(9);
+ if (!animate(11, 10, 0, kMessageRight, kStringIntroCutscene24))
+ return;
+ if (!animate(5, 4, 0, kMessageLeft, kStringIntroCutscene3))
+ return;
+ _vm->paletteFadeOut();
+
+ while (_vm->_mixer->isSoundHandleActive(_vm->_soundHandle))
+ exitOnEscape(1);
+
+ _vm->_system->fillScreen(kColorBlack);
+ _vm->_menuBrightness = 255;
+ _vm->paletteBrightness();
+ if (!animate(0, 0, 0, kMessageNormal, kStringIntroCutscene25))
+ return;
+ _vm->_menuBrightness = 5;
+ _vm->paletteBrightness();
+
+ _vm->setCurrentImage(31);
+ _vm->renderImage(0);
+ _vm->paletteFadeIn();
+ if (!animate(0, 0, 0, kMessageNormal, kStringIntroCutscene26))
+ return;
+ if (!animate(0, 0, 0, kMessageNormal, kStringIntroCutscene27))
+ return;
+ if (!animate(0, 0, 0, kMessageNormal, kStringIntroCutscene28))
+ return;
+ if (!animate(0, 0, 0, kMessageNormal, kStringIntroCutscene29))
+ return;
+ exitOnEscape(54);
+ if (!animate(0, 0, 0, kMessageNormal, kStringIntroCutscene30))
+ return;
+ if (!animate(0, 0, 0, kMessageNormal, kStringIntroCutscene31))
+ return;
+ if (!animate(0, 0, 0, kMessageNormal, kStringIntroCutscene32))
+ return;
+
+ CursorMan.showMouse(false);
+ _vm->_brightness = 0;
+ _vm->paletteBrightness();
+ exitOnEscape(10);
+ _vm->playSound(kAudioSnoring);
+ while (_vm->_mixer->isSoundHandleActive(_vm->_soundHandle))
+ _gm->wait2(1);
+ exitOnEscape(10);
+ _vm->playSound(kAudioSnoring);
+ while (_vm->_mixer->isSoundHandleActive(_vm->_soundHandle))
+ _gm->wait2(1);
+ exitOnEscape(10);
+ _vm->playSound(kAudioSnoring);
+ while (_vm->_mixer->isSoundHandleActive(_vm->_soundHandle))
+ _gm->wait2(1);
+ exitOnEscape(30);
+ CursorMan.showMouse(true);
+
+ _vm->setCurrentImage(22);
+ if (!animate(0, 0, 0, kMessageNormal, kStringIntroCutscene33))
+ return;
+ exitOnEscape(18);
+ if (!animate(0, 0, 0, kMessageNormal, kStringIntroCutscene34))
+ return;
+ if (!animate(0, 0, 0, kMessageNormal, kStringIntroCutscene35))
+ return;
+ if (!animate(0, 0, 0, kMessageNormal, kStringIntroCutscene36))
+ return;
+ if (!animate(0, 0, 0, kMessageNormal, kStringIntroCutscene37))
+ return;
+ exitOnEscape(18);
+ if (!animate(0, 0, 0, kMessageNormal, kStringIntroCutscene38))
+ return;
+ if (!animate(0, 0, 0, kMessageNormal, kStringIntroCutscene39))
+ return;
+ exitOnEscape(18);
+ if (!animate(0, 0, 0, kMessageNormal, kStringIntroCutscene40))
+ return;
+ if (!animate(0, 0, 0, kMessageNormal, kStringIntroCutscene41))
+ return;
+ exitOnEscape(36);
+ animate(0, 0, 0, kMessageNormal, kStringIntroCutscene42);
+ _vm->removeMessage();
+
+#undef exitOnEscape
+}
+
+void Intro::leaveCutscene() {
+ _vm->_brightness = 255;
+ _vm->removeMessage();
+ _gm->changeRoom(CABIN_R3);
+ _gm->_guiEnabled = true;
+ _vm->_allowSaveGame = true;
+ _vm->_allowLoadGame = true;
+}
+
+bool ShipCorridor::interact(Action verb, Object &obj1, Object &obj2) {
+ if ((verb == ACTION_PRESS) && (obj1._id == BUTTON)) {
+ if (_objectState[6].hasProperty(OPENED)) {
+ _vm->playSound(kAudioSlideDoor);
+ _objectState[6].disableProperty(OPENED);
+ _vm->renderImage(8);
+ setSectionVisible(9, false);
+ _gm->wait2(2);
+ _vm->renderImage(7);
+ setSectionVisible(8, false);
+ _gm->wait2(2);
+ _vm->renderImage(_gm->invertSection(7));
+ } else {
+ _vm->playSound(kAudioSlideDoor);
+ _objectState[6].setProperty(OPENED);
+ _vm->renderImage(7);
+ _gm->wait2(2);
+ _vm->renderImage(8);
+ setSectionVisible(7, false);
+ _gm->wait2(2);
+ _vm->renderImage(9);
+ setSectionVisible(8, false);
+ }
+ return true;
+ }
+ return false;
+}
+
+bool ShipHall::interact(Action verb, Object &obj1, Object &obj2) {
+ if ((verb == ACTION_OPEN) && (obj1._id == KITCHEN_HATCH)) {
+ _vm->renderMessage(kStringShipHall1);
+ } else if ((verb == ACTION_USE) && Object::combine(obj1,obj2,KEYCARD2,SLEEP_SLOT)) {
+ if (_objectState[2].hasProperty(OPENED)) {
+ _objectState[2].disableProperty(OPENED);
+ _vm->renderImage(3);
+ setSectionVisible(4, false);
+ _gm->wait2(2);
+ _vm->renderImage(2);
+ setSectionVisible(3, false);
+ _gm->wait2(2);
+ _vm->renderImage(_gm->invertSection(2));
+ } else {
+ _objectState[2].setProperty(OPENED);
+ _vm->renderImage(2);
+ _gm->wait2(2);
+ _vm->renderImage(3);
+ setSectionVisible(2, false);
+ _gm->wait2(2);
+ _vm->renderImage(4);
+ setSectionVisible(3, false);
+ _gm->great(1);
+ }
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+bool ShipSleepCabin::interact(Action verb, Object &obj1, Object &obj2) {
+ Room *room;
+ Common::String input;
+
+ if (((verb == ACTION_LOOK) || (verb == ACTION_USE)) && (obj1._id == COMPUTER)) {
+ _gm->_guiEnabled = false;
+ setSectionVisible(4, false);
+ g_system->fillScreen(kColorDarkBlue);
+ if (_gm->_state._arrivalDaysLeft == 0) {
+ // Destination reached
+ _vm->renderText(kStringShipSleepCabin1, 60, 95, kColorWhite99);
+ _gm->getInput();
+ } else if (_gm->_state._powerOff) {
+ // Energy depleted
+ _vm->renderText(kStringShipSleepCabin2, 60, 95, kColorWhite99);
+ // Artificial coma interrupted
+ _vm->renderText(kStringShipSleepCabin3, 60, 115, kColorWhite99);
+ _gm->getInput();
+ } else if (isSectionVisible(5)) {
+ // Sleep duration in days
+ _vm->renderText(kStringShipSleepCabin4, 30, 85, kColorWhite99);
+ _vm->renderText(Common::String::format("%d",_gm->_state._timeSleep).c_str(),
+ 150, 85, kColorWhite99);
+ _vm->renderText(kStringShipSleepCabin5, 30, 105, kColorWhite99);
+ _gm->getInput();
+ } else {
+ _vm->renderText(kStringShipSleepCabin6, 100, 85, kColorWhite99);
+ _gm->edit(input, 100, 105, 30);
+
+ input.toUppercase();
+ if (_gm->_key.keycode != Common::KEYCODE_ESCAPE) {
+ if (input == _vm->getGameString(kStringComputerPassword)) {
+ _gm->great(6);
+ g_system->fillScreen(kColorDarkBlue);
+ _vm->renderText(kStringShipSleepCabin7, 30, 85, kColorWhite99);
+ uint daysSleep = 0;
+ do {
+ input.clear();
+ _vm->renderBox(150, 85, 150, 8, kColorDarkBlue);
+ _gm->edit(input, 150, 85, 10);
+
+ if (_gm->_key.keycode == Common::KEYCODE_ESCAPE) {
+ break;
+ } else {
+ daysSleep = input.asUint64();
+ for (uint i = 0; i < input.size(); i++) {
+ if (!Common::isDigit(input[i])) {
+ daysSleep = 0;
+ break;
+ }
+ }
+ }
+ if (daysSleep != 0) {
+ _gm->_state._timeSleep = daysSleep;
+ _vm->renderText(kStringShipSleepCabin8, 30, 105, kColorWhite99);
+ _gm->wait2(18);
+ setSectionVisible(5, true);
+ }
+ } while (daysSleep == 0);
+ } else {
+ _vm->renderText(kStringShipSleepCabin9, 100, 125, kColorLightRed);
+ _gm->wait2(18);
+ }
+ }
+ }
+
+ _gm->_guiEnabled = true;
+ input.clear();
+ } else if (((verb == ACTION_WALK) || (verb == ACTION_USE)) &&
+ ((obj1._id == CABINS) || (obj1._id == CABIN))) {
+ room = _gm->_rooms[AIRLOCK];
+ if (!(obj1._id == CABIN) || !isSectionVisible(5)) {
+ _vm->renderMessage(kStringShipSleepCabin10);
+ } else if (room->getObject(5)->hasProperty(WORN)) {
+ _vm->renderMessage(kStringShipSleepCabin11);
+ } else {
+ _vm->paletteFadeOut();
+ _vm->renderImage(_gm->invertSection(5));
+ _vm->renderImage(_gm->invertSection(4));
+ room = _gm->_rooms[GENERATOR];
+ int32 *energyDaysLeft;
+ if (room->isSectionVisible(9)) {
+ energyDaysLeft = &_gm->_state._landingModuleEnergyDaysLeft;
+ } else {
+ energyDaysLeft = &_gm->_state._shipEnergyDaysLeft;
+ }
+ if (_gm->_state._timeSleep > _gm->_state._arrivalDaysLeft) {
+ _gm->_state._timeSleep = _gm->_state._arrivalDaysLeft;
+ }
+ if (_gm->_state._timeSleep >= *energyDaysLeft) {
+ _gm->_state._timeSleep = *energyDaysLeft;
+ if (room->isSectionVisible(9)) {
+ room = _gm->_rooms[LANDINGMODULE]; // Monitors off
+ room->setSectionVisible(2, false);
+ room->setSectionVisible(7, false);
+ room->setSectionVisible(8, false);
+ room->setSectionVisible(9, false);
+ room->setSectionVisible(10, false);
+ }
+ }
+ if (_gm->_state._timeSleep == _gm->_state._arrivalDaysLeft) {
+ _vm->renderImage(3);
+ room = _gm->_rooms[COCKPIT];
+ room->setSectionVisible(23, true);
+ room = _gm->_rooms[CABIN_R2];
+ room->setSectionVisible(5, false);
+ room->setSectionVisible(6, true);
+ room->getObject(2)->_click = 10;
+ room = _gm->_rooms[HOLD];
+ room->setSectionVisible(0, false);
+ room->setSectionVisible(1, true);
+ room->getObject(1)->_click = 255;
+ room->getObject(3)->_click = 255;
+ room = _gm->_rooms[GENERATOR];
+ room->setSectionVisible(6, false);
+ room->setSectionVisible(7, true);
+ room->getObject(1)->_click = 14;
+ if (room->isSectionVisible(1)) {
+ room->setSectionVisible(10, true);
+ }
+ if (room->isSectionVisible(12)) {
+ room->setSectionVisible(12, false);
+ room->setSectionVisible(11, true);
+ }
+ }
+ _gm->_state._arrivalDaysLeft -= _gm->_state._timeSleep;
+ *energyDaysLeft -= _gm->_state._timeSleep;
+ _gm->_state._time = ticksToMsec(786520); // 12pm
+ _gm->_state._alarmOn = (_gm->_state._timeAlarm > _gm->_state._time);
+ if (*energyDaysLeft == 0) {
+ _gm->turnOff();
+ room = _gm->_rooms[GENERATOR];
+ room->setSectionVisible(4, room->isSectionVisible(2));
+ }
+ if (_gm->_state._arrivalDaysLeft == 0) {
+ _gm->saveTime();
+ if (!_vm->saveGame(kSleepAutosaveSlot, "Sleep autosave"))
+ _vm->errorTempSave(true);
+ _gm->_state._dream = true;
+ _gm->loadTime();
+ }
+ _gm->wait2(18);
+ _vm->paletteFadeIn();
+ if (_gm->_state._arrivalDaysLeft == 0) {
+ _vm->playSound(kAudioCrash);
+ _gm->screenShake();
+ _gm->wait2(18);
+ _vm->renderMessage(kStringShipSleepCabin12);
+ }
+ }
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+void ShipSleepCabin::animation() {
+ if (_gm->_state._powerOff && _gm->_state._arrivalDaysLeft) {
+ if (_gm->_guiEnabled) {
+ if (isSectionVisible(1)) {
+ _vm->renderImage(2);
+ setSectionVisible(1, false);
+ } else {
+ _vm->renderImage(1);
+ setSectionVisible(2, false);
+ }
+ } else {
+ if (_color == kColorLightRed) {
+ _color = kColorDarkBlue;
+ } else {
+ _color = kColorLightRed;
+ }
+
+ _vm->renderText(kStringShipSleepCabin13, 60, 75, _color);
+ }
+ } else if (isSectionVisible(5) && _gm->_guiEnabled) {
+ if (isSectionVisible(4))
+ _vm->renderImage(_gm->invertSection(4));
+ else
+ _vm->renderImage(4);
+ }
+
+ _gm->setAnimationTimer(6);
+}
+void ShipSleepCabin::onEntrance() {
+ if (_gm->_state._dream && (_gm->_rooms[CAVE]->getObject(1)->_exitRoom == MEETUP3)) {
+ _vm->renderMessage(kStringShipSleepCabin14);
+ _gm->waitOnInput(_gm->_timer1);
+ _vm->removeMessage();
+ _vm->renderMessage(kStringShipSleepCabin15);
+ _gm->waitOnInput(_gm->_timer1);
+ _vm->removeMessage();
+ _vm->renderMessage(kStringShipSleepCabin16);
+ _gm->_state._dream = false;
+ }
+}
+
+bool ShipCockpit::interact(Action verb, Object &obj1, Object &obj2) {
+ // TODO: distance and remaining time not accurate
+
+ if ((verb == ACTION_LOOK) && (obj1._id == MONITOR)) {
+ char c[2] = {0, 0};
+ _gm->_guiEnabled = false;
+ _vm->renderBox(0, 0, 320, 200, kColorBlack);
+ _vm->renderText(kStringShipCockpit1, 50, 50, kColorLightYellow);
+ if (_gm->_state._arrivalDaysLeft)
+ _vm->renderText(kStringShipCockpit2);
+ else
+ _vm->renderText(kStringShipCockpit3);
+ _vm->renderText(kStringShipCockpit4, 50, 70, kColorLightYellow);
+ _vm->renderText(kStringShipCockpit5, 50, 90, kColorLightYellow);
+ _vm->renderText(Common::String::format("%d", _gm->_state._arrivalDaysLeft / 400).c_str());
+ _vm->renderText(",");
+ c[0] = (_gm->_state._arrivalDaysLeft / 40) % 10 + '0';
+ _vm->renderText(c);
+ c[0] = (_gm->_state._arrivalDaysLeft / 4) % 10 + '0';
+ _vm->renderText(c);
+ _vm->renderText(kStringShipCockpit6);
+ _vm->renderText(kStringShipCockpit7, 50, 110, kColorLightYellow);
+ _vm->renderText(Common::String::format("%d", _gm->_state._arrivalDaysLeft).c_str(),
+ 50, 120, kColorLightYellow);
+ _vm->renderText(kStringShipCockpit8);
+
+ _gm->getInput();
+ _gm->_guiEnabled = true;
+ } else if ((verb == ACTION_USE) && (obj1._id == INSTRUMENTS))
+ _vm->renderMessage(kStringShipCockpit9);
+ else
+ return false;
+
+ return true;
+}
+void ShipCockpit::animation() {
+ if (!_gm->_guiEnabled) {
+ if (_color) {
+ _color = kColorBlack;
+ _gm->setAnimationTimer(5);
+ } else {
+ _color = kColorLightYellow;
+ _gm->setAnimationTimer(10);
+ }
+ _vm->renderText(kStringShipCockpit10, 50, 145, _color);
+ } else if (isSectionVisible(21)) {
+ _vm->renderImage(_gm->invertSection(21));
+ _gm->setAnimationTimer(5);
+ } else {
+ _vm->renderImage(21);
+ _gm->setAnimationTimer(10);
+ }
+
+ if (_gm->_state._powerOff) {
+ if (!_gm->_guiEnabled) {
+ _vm->renderText(kStringShipCockpit11, 97, 165, _color);
+ _vm->renderText(kStringShipCockpit12, 97, 175, _color);
+ } else if (isSectionVisible(21))
+ _vm->renderImage(22);
+ else
+ _vm->renderImage(_gm->invertSection(22));
+ }
+}
+
+void ShipCockpit::onEntrance() {
+ if (!hasSeen())
+ _vm->renderMessage(kStringShipCockpit13);
+ setRoomSeen(true);
+}
+
+bool ShipCabinL2::interact(Action verb, Object &obj1, Object &obj2) {
+ if ((verb == ACTION_USE) && Object::combine(obj1, obj2, SLOT_KL1, KEYCARD2)) {
+ _gm->openLocker(this, getObject(4), getObject(0), 17);
+ if (getObject(5)->_click == 255)
+ _vm->renderImage(20); // Remove Pistol
+ _gm->great(2);
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, SLOT_KL2, KEYCARD2)) {
+ _gm->openLocker(this, getObject(6), getObject(1), 18);
+ _gm->great(2);
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, SLOT_KL3, KEYCARD2)) {
+ _gm->openLocker(this, getObject(8), getObject(2), 19);
+ if (getObject(9)->_click == 255)
+ _vm->renderImage(21); // Remove cable spool
+ _gm->great(2);
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, SLOT_KL4, KEYCARD2)) {
+ _gm->openLocker(this, getObject(10), getObject(3), 22);
+ if (getObject(11)->_click == 255)
+ _vm->renderImage(23); // Remove book
+ _gm->great(2);
+ } else if ((verb == ACTION_CLOSE) && (obj1._id == SHELF_L1)) {
+ _gm->closeLocker(this, getObject(4), getObject(0), 17);
+ setSectionVisible(20, false);
+ } else if ((verb == ACTION_CLOSE) && (obj1._id == SHELF_L2))
+ _gm->closeLocker(this, getObject(6), getObject(1), 18);
+ else if ((verb == ACTION_CLOSE) && (obj1._id == SHELF_L3)) {
+ _gm->closeLocker(this, getObject(8), getObject(2), 19);
+ setSectionVisible(21, false);
+ } else if ((verb == ACTION_CLOSE) && (obj1._id == SHELF_L4)) {
+ _gm->closeLocker(this, getObject(10), getObject(3), 22);
+ setSectionVisible(23, false);
+ } else if ((verb == ACTION_TAKE) && (obj1._id == SPOOL) && !obj1.hasProperty(CARRIED)) {
+ getObject(8)->_click = 42; // empty shelf
+ return false;
+ } else if ((verb == ACTION_TAKE) && (obj1._id == BOOK2) && !obj1.hasProperty(CARRIED)) {
+ getObject(10)->_click = 47; // empty shelf
+ return false;
+ } else
+ return false;
+
+ return true;
+}
+
+bool ShipCabinL3::interact(Action verb, Object &obj1, Object &obj2) {
+ Room *r;
+
+ if ((verb == ACTION_USE) && Object::combine(obj1, obj2, RECORD, TURNTABLE)) {
+ if (!_gm->_guiEnabled || isSectionVisible(15))
+ _vm->renderMessage(kStringShipCabinL3_1);
+ else {
+ if (!getObject(4)->hasProperty(CARRIED))
+ _vm->renderImage(_gm->invertSection(8));
+ else
+ _gm->_inventory.remove(*getObject(4));
+ _vm->renderImage(15);
+ getObject(4)->_click = 48;
+ }
+ } else if ((verb == ACTION_PRESS) && (obj1._id == TURNTABLE_BUTTON)) {
+ if (!isSectionVisible(15)) {
+ _vm->renderMessage(kStringShipCabinL3_2);
+ } else if (!isSectionVisible(10) && !isSectionVisible(11) && isSectionVisible(12)) {
+ _vm->renderImage(14);
+ setSectionVisible(15, false);
+ for (int i = 3; i; i--) {
+ _vm->playSound(kAudioTurntable);
+ while (_vm->_mixer->isSoundHandleActive(_vm->_soundHandle)) {
+ if (isSectionVisible(13)) {
+ _vm->renderImage(14);
+ setSectionVisible(13, false);
+ } else {
+ _vm->renderImage(13);
+ setSectionVisible(14, false);
+ }
+ _gm->wait2(3);
+ }
+ }
+
+ _vm->renderImage(15);
+ setSectionVisible(14, false);
+ setSectionVisible(13, false);
+ _vm->renderMessage(kStringShipCabinL3_3);
+ }
+ } else if ((verb == ACTION_TAKE) && (obj1._id == RECORD) && (obj1._click != 15)) {
+ _vm->renderImage(9);
+ setSectionVisible(13, false);
+ setSectionVisible(14, false);
+ setSectionVisible(15, false);
+ obj1._section = 0;
+ _gm->takeObject(obj1);
+ } else if ((verb == ACTION_PULL) && (obj1._id == PLUG)) {
+ _vm->renderImage(10);
+ setSectionVisible(7, false);
+ obj1._click = 21;
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, PLUG, SOCKET)) {
+ _vm->renderImage(7);
+ setSectionVisible(10, false);
+ getObject(10)->_click = 20;
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, KNIFE, WIRE2))
+ _vm->renderMessage(kStringShipCabinL3_4);
+ else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, KNIFE, WIRE)) {
+ r = _gm->_rooms[AIRLOCK];
+ if (!isSectionVisible(10) && !r->getObject(5)->hasProperty(WORN)) {
+ _vm->renderImage(25);
+ _gm->shock();
+ }
+ _vm->renderImage(11);
+ _vm->renderImage(26);
+ setSectionVisible(12, false);
+ } else if ((verb == ACTION_TAKE) && ((obj1._id == WIRE) || (obj1._id == WIRE2) || (obj1._id == PLUG))) {
+ if (isSectionVisible(10) && isSectionVisible(11)) {
+ _vm->renderImage(_gm->invertSection(10));
+ _vm->renderImage(_gm->invertSection(11));
+ getObject(8)->_name = kStringWireAndPlug;
+ _gm->takeObject(*getObject(8));
+ getObject(9)->_click = 255;
+ getObject(10)->_click = 255;
+ } else
+ _vm->renderMessage(kStringShipCabinL3_5);
+ } else
+ return false;
+
+ return true;
+}
+
+bool ShipCabinR3::interact(Action verb, Object &obj1, Object &obj2) {
+ if ((verb == ACTION_USE) && Object::combine(obj1, obj2, SLOT_K1, KEYCARD))
+ _gm->openLocker(this, getObject(6), getObject(2), 9);
+ else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, SLOT_K2, KEYCARD)) {
+ _gm->openLocker(this, getObject(8), getObject(3), 10);
+ if (getObject(9)->_click == 255)
+ _vm->renderImage(12); // Remove rope
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, SLOT_K3, KEYCARD)) {
+ _gm->openLocker(this, getObject(10), getObject(4), 11);
+ if (getObject(17)->_click == 255)
+ _vm->renderImage(16); // Remove Discman
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, SLOT_K4, KEYCARD)) {
+ _gm->openLocker(this, getObject(15), getObject(5), 13);
+ if (getObject(16)->_click == 255)
+ _vm->renderImage(14); // Remove Book
+ } else if ((verb == ACTION_CLOSE) && (obj1._id == SHELF1))
+ _gm->closeLocker(this, getObject(6), getObject(2), 9);
+ else if ((verb == ACTION_CLOSE) && (obj1._id == SHELF2)) {
+ setSectionVisible(12, false);
+ _gm->closeLocker(this, getObject(8), getObject(3), 10);
+ } else if ((verb == ACTION_CLOSE) && (obj1._id == SHELF3)) {
+ setSectionVisible(16, false);
+ _gm->closeLocker(this, getObject(10), getObject(4), 11);
+ } else if ((verb == ACTION_CLOSE) && (obj1._id == SHELF4)) {
+ setSectionVisible(14, false);
+ setSectionVisible(14, false);
+ _gm->closeLocker(this, getObject(15), getObject(5), 13);
+ } else if ((verb == ACTION_TAKE) && (obj1._id == DISCMAN) && !_gm->_rooms[0]->getObject(3)->hasProperty(CARRIED)) {
+ getObject(10)->_click = 34; // Locker empty
+ obj1._click = 255;
+ _gm->takeObject(*_gm->_rooms[0]->getObject(3));
+ _vm->renderImage(16);
+ } else if ((verb == ACTION_TAKE) && (obj1._id == ROPE) && obj1.hasProperty(CARRIED)) {
+ getObject(8)->_click = 31; // Shelf empty
+ return false;
+ } else if ((verb == ACTION_TAKE) && (obj1._id == BOOK) && !obj1.hasProperty(CARRIED)) {
+ getObject(15)->_click = 32; // Shelf empty
+ return false;
+ } else
+ return false;
+
+ return true;
+}
+
+void ShipCabinR3::onEntrance() {
+ for (int i = 0; i < 3; ++i)
+ _gm->_inventory.add(*_gm->_rooms[INTRO]->getObject(i));
+
+ setRoomSeen(true);
+}
+
+
+bool ShipAirlock::interact(Action verb, Object &obj1, Object &obj2) {
+ Room *r;
+
+ if ((verb == ACTION_PRESS) && (obj1._id == BUTTON1)) {
+ if (!getObject(1)->hasProperty(OPENED)) {
+ _vm->renderImage(10);
+ _vm->playSound(kAudioSlideDoor);
+ if (getObject(0)->hasProperty(OPENED)) {
+ getObject(0)->disableProperty(OPENED);
+ _vm->renderImage(1);
+ _gm->wait2(2);
+ _vm->renderImage(2);
+ setSectionVisible(1, false);
+ _gm->wait2(2);
+ _vm->renderImage(3);
+ setSectionVisible(2, false);
+ } else {
+ getObject(0)->setProperty(OPENED);
+ _vm->renderImage(2);
+ setSectionVisible(3, false);
+ _gm->wait2(2);
+ _vm->renderImage(1);
+ setSectionVisible(2, false);
+ _gm->wait2(2);
+ _vm->renderImage(_gm->invertSection(1));
+ }
+ _vm->renderImage(_gm->invertSection(10));
+ }
+ } else if ((verb == ACTION_PRESS) && (obj1._id == BUTTON2)) {
+ if (!getObject(0)->hasProperty(OPENED)) {
+ _vm->renderImage(11);
+ if (getObject(1)->hasProperty(OPENED)) {
+ _vm->playSound(kAudioSlideDoor);
+ getObject(1)->disableProperty(OPENED);
+ _vm->renderImage(4);
+ _gm->wait2(2);
+ _vm->renderImage(5);
+ setSectionVisible(4, false);
+ _gm->wait2(2);
+ _vm->renderImage(6);
+ setSectionVisible(5, false);
+ _vm->renderImage(16);
+ setSectionVisible(17, false);
+ _gm->wait2(3);
+ _vm->renderImage(15);
+ setSectionVisible(16, false);
+ _gm->wait2(3);
+ _vm->renderImage(14);
+ setSectionVisible(15, false);
+ _gm->wait2(3);
+ _vm->renderImage(13);
+ setSectionVisible(14, false);
+ _gm->wait2(3);
+ _vm->renderImage(12);
+ setSectionVisible(13, false);
+ _gm->wait2(3);
+ _vm->renderImage(_gm->invertSection(12));
+ } else {
+ getObject(1)->setProperty(OPENED);
+ _vm->renderImage(12);
+ _gm->wait2(3);
+ _vm->renderImage(13);
+ setSectionVisible(12, false);
+ _gm->wait2(3);
+ _vm->renderImage(14);
+ setSectionVisible(13, false);
+ _gm->wait2(3);
+ _vm->renderImage(15);
+ setSectionVisible(14, false);
+ _gm->wait2(3);
+ _vm->renderImage(16);
+ setSectionVisible(15, false);
+ _gm->wait2(3);
+ _vm->renderImage(17);
+ setSectionVisible(16, false);
+ _vm->playSound(kAudioSlideDoor);
+ _vm->renderImage(5);
+ setSectionVisible(6, false);
+ _gm->wait2(2);
+ _vm->renderImage(4);
+ setSectionVisible(5, false);
+ _gm->wait2(2);
+ _vm->renderImage(_gm->invertSection(4));
+ r = _gm->_rooms[AIRLOCK];
+ if (!r->getObject(4)->hasProperty(WORN) ||
+ !r->getObject(5)->hasProperty(WORN) ||
+ !r->getObject(6)->hasProperty(WORN)) {
+ _gm->dead(kStringShipAirlock1);
+ return true;
+ }
+ }
+ _vm->renderImage(_gm->invertSection(11));
+ }
+ } else if ((verb == ACTION_LOOK) && (obj1._id == MANOMETER))
+ _vm->renderMessage(getObject(1)->hasProperty(OPENED) ? kStringShipAirlock2 : kStringShipAirlock3);
+ else
+ return false;
+
+ return true;
+}
+
+void ShipAirlock::onEntrance() {
+ if (!hasSeen())
+ _vm->renderMessage(kStringShipAirlock4);
+
+ setRoomSeen(true);
+}
+
+bool ShipHold::interact(Action verb, Object &obj1, Object &obj2) {
+ Room *room;
+
+ if ((verb == ACTION_LOOK) && (obj1._id == SCRAP_LK) && (obj1._description != kStringScrapDescription3)) {
+ _vm->renderMessage(obj1._description);
+ obj1._description = kStringScrapDescription3;
+ _gm->takeObject(*getObject(2));
+ } else if (((verb == ACTION_OPEN) || (verb == ACTION_CLOSE)) && (obj1._id == OUTERHATCH_TOP))
+ _vm->renderMessage(kStringShipHold1);
+ else if ((verb == ACTION_CLOSE) && (obj1._id == LANDINGMOD_HATCH) && (isSectionVisible(4) || isSectionVisible(6)))
+ _vm->renderMessage(kStringCable1);
+ else if (((verb == ACTION_TAKE) && (obj1._id == HOLD_WIRE)) ||
+ ((verb == ACTION_USE) && Object::combine(obj1, obj2, HOLD_WIRE, LANDINGMOD_HATCH)))
+ _vm->renderMessage(kStringCable2);
+ else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, TERMINALSTRIP, HOLD_WIRE)) {
+ getObject(0)->_name = kStringWireAndClip;
+ _gm->_inventory.remove(*getObject(2));
+ _gm->_state._terminalStripConnected = true;
+ _gm->_state._terminalStripWire = true;
+ _vm->renderMessage(kStringOk);
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, HOLD_WIRE, SPOOL)) {
+ if (!_gm->_state._terminalStripConnected)
+ _vm->renderMessage(kStringCable3);
+ else {
+ _vm->renderImage(5);
+ getObject(0)->_name = kStringWireAndPlug2;
+ getObject(0)->_click = 10;
+ room = _gm->_rooms[CABIN_L2];
+ _gm->_inventory.remove(*getObject(9));
+ }
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, HOLD_WIRE, GENERATOR_TOP)) {
+ if (isSectionVisible(5)) {
+ room = _gm->_rooms[GENERATOR];
+ room->getObject(0)->_click = 15;
+ room->getObject(1)->_click = 13;
+ room->setSectionVisible(6, true);
+ room->setSectionVisible(8, true);
+ _vm->renderImage(_gm->invertSection(5));
+ _vm->renderImage(6);
+ setSectionVisible(4, false);
+ getObject(0)->_click = 11;
+ } else
+ _vm->renderMessage(kStringCable4);
+ } else
+ return false;
+
+ return true;
+}
+
+void ShipHold::onEntrance() {
+ if (!hasSeen())
+ _vm->renderMessage(kStringShipHold2);
+ setRoomSeen(true);
+ _gm->_rooms[COCKPIT]->setRoomSeen(true);
+}
+
+bool ShipLandingModule::interact(Action verb, Object &obj1, Object &obj2) {
+ if ((verb == ACTION_PRESS) && (obj1._id == LANDINGMOD_BUTTON))
+ _vm->renderMessage(obj1._description);
+ else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, PEN, LANDINGMOD_BUTTON)) {
+ if (_gm->_state._landingModuleEnergyDaysLeft) {
+ Room *r = _gm->_rooms[GENERATOR];
+ if (isSectionVisible(7)) {
+ _vm->renderImage(_gm->invertSection(9));
+ _vm->renderImage(_gm->invertSection(2));
+ _vm->renderImage(_gm->invertSection(8));
+ _vm->renderImage(_gm->invertSection(7));
+ _vm->renderImage(_gm->invertSection(10));
+ if (r->isSectionVisible(9))
+ _gm->_state._powerOff = true;
+ _gm->roomBrightness();
+ } else {
+ _vm->renderImage(7);
+ if (r->isSectionVisible(9))
+ _gm->_state._powerOff = false;
+ _gm->roomBrightness();
+ r = _gm->_rooms[SLEEP];
+ r->setSectionVisible(1, false);
+ r->setSectionVisible(2, false);
+ _gm->wait2(2);
+ _vm->renderImage(2);
+ _gm->wait2(3);
+ _vm->renderImage(8);
+ _gm->wait2(2);
+ _vm->renderImage(9);
+ _gm->wait2(1);
+ _vm->renderImage(10);
+ }
+ }
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, KNIFE, LANDINGMOD_BUTTON))
+ _vm->renderMessage(kStringShipHold3);
+ else if ((verb == ACTION_LOOK) && (obj1._id == LANDINGMOD_MONITOR) && isSectionVisible(7))
+ _vm->renderMessage(kStringShipHold4);
+ else if ((verb == ACTION_USE) && (obj1._id == KEYBOARD))
+ _vm->renderMessage(kStringShipHold5);
+ else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, WIRE, LANDINGMOD_SOCKET)) {
+ Room *r = _gm->_rooms[CABIN_L3];
+ _gm->_inventory.remove(*r->getObject(8));
+ getObject(4)->_name = r->getObject(8)->_name;
+ _vm->renderImage(4);
+ if (_gm->_state._cableConnected) {
+ _vm->renderImage(5);
+ getObject(4)->_click = 6;
+ } else {
+ getObject(4)->_click = 5;
+ if (_gm->_state._terminalStripWire)
+ _vm->renderImage(11);
+ }
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, SPOOL, LANDINGMOD_SOCKET))
+ _vm->renderMessage(kStringShipHold8);
+ else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, LANDINGMOD_WIRE, TERMINALSTRIP)) {
+ _vm->renderImage(11);
+ getObject(4)->_name = kStringWireAndClip;
+ Room *r = _gm->_rooms[HOLD];
+ _gm->_inventory.remove(*r->getObject(2));
+ _gm->_state._terminalStripConnected = true;
+ _gm->_state._terminalStripWire = true;
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, LANDINGMOD_WIRE, SPOOL)) {
+ if (!_gm->_state._terminalStripConnected)
+ _vm->renderMessage(kStringCable3);
+ else {
+ _vm->renderImage(5);
+ getObject(4)->_name = kStringWireAndPlug2;
+ getObject(4)->_click = 6;
+ _gm->_inventory.remove(*_gm->_rooms[CABIN_L2]->getObject(9));
+ }
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, LANDINGMOD_WIRE, LANDINGMOD_HATCH)) {
+ if (getObject(5)->hasProperty(OPENED)) {
+ Room *r = _gm->_rooms[HOLD];
+ if (isSectionVisible(5)) {
+ r->setSectionVisible(5, true);
+ r->getObject(0)->_click = 10;
+ } else
+ r->getObject(0)->_click = 9;
+
+ r->setSectionVisible(4, true);
+ r->getObject(0)->_name = getObject(4)->_name;
+ _vm->renderImage(_gm->invertSection(5));
+ _vm->renderImage(_gm->invertSection(4));
+ setSectionVisible(11, false);
+ _vm->renderImage(6);
+ getObject(4)->_click = 7;
+ } else
+ _vm->renderMessage(kStringShipHold6);
+ } else if ((verb == ACTION_CLOSE) && (obj1._id == LANDINGMOD_HATCH) && isSectionVisible(6))
+ _vm->renderMessage(kStringCable1);
+ else if (((verb == ACTION_TAKE) || (verb == ACTION_PULL)) && (obj1._id == LANDINGMOD_WIRE))
+ _vm->renderMessage(kStringCable2);
+ else
+ return false;
+
+ return true;
+}
+
+bool ShipGenerator::interact(Action verb, Object &obj1, Object &obj2) {
+ if ((verb == ACTION_OPEN) && (obj1._id == OUTERHATCH)) {
+ if (obj1.hasProperty(OPENED))
+ return false;
+ _vm->playSound(kAudioSlideDoor);
+ _vm->renderImage(1);
+ if (isSectionVisible(7))
+ _vm->renderImage(10);
+ if (isSectionVisible(13))
+ _vm->renderImage(13);
+ _gm->_rooms[HOLD]->setSectionVisible(3, true);
+ obj1.setProperty(OPENED);
+ obj1._click = 2;
+ _vm->playSound(kAudioDoorOpen);
+ } else if ((verb == ACTION_CLOSE) && (obj1._id == OUTERHATCH)) {
+ if (!obj1.hasProperty(OPENED))
+ return false;
+ if (isSectionVisible(11) || isSectionVisible(12))
+ _vm->renderMessage(kStringShipHold7);
+ else {
+ _vm->playSound(kAudioSlideDoor);
+ _vm->renderImage(_gm->invertSection(1));
+ setSectionVisible(10, false);
+ if (isSectionVisible(13))
+ _vm->renderImage(13);
+ _gm->_rooms[HOLD]->setSectionVisible(3, false);
+ obj1.disableProperty(OPENED);
+ obj1._click = 1;
+ _vm->playSound(kAudioDoorClose);
+ }
+ } else if ((verb == ACTION_WALK) && (obj1._id == OUTERHATCH) &&
+ isSectionVisible(7)) {
+ if (!obj1.hasProperty(OPENED))
+ _vm->renderMessage(kStringShipHold9);
+ else if (!isSectionVisible(11))
+ _vm->renderMessage(kStringShipHold10);
+ else {
+ obj1._exitRoom = ROCKS;
+ return false;
+ }
+ } else if ((verb == ACTION_TAKE) && (obj1._id == GENERATOR_WIRE))
+ _vm->renderMessage(kStringCable2);
+ else if ((verb == ACTION_PULL) && (obj1._id == SHORT_WIRE) &&
+ (obj1._click != 11)) {
+ _vm->renderImage(3);
+ _vm->renderImage(4);
+ obj1._click = 11;
+ _gm->turnOff();
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, SHORT_WIRE, CLIP) &&
+ (getObject(11)->_click == 11) && !isSectionVisible(9)) {
+ _vm->renderImage(2);
+ setSectionVisible(3, false);
+ setSectionVisible(4, false);
+ getObject(11)->_click = 10;
+ if (_gm->_state._shipEnergyDaysLeft)
+ _gm->turnOn();
+ else
+ _vm->renderImage(4);
+ } else if ((verb == ACTION_OPEN) && (obj1._id == TRAP)) {
+ _vm->playSound(kAudioSlideDoor);
+ _vm->renderImage(2);
+ if (getObject(11)->_click == 11)
+ _vm->renderImage(3);
+ if (_gm->_state._powerOff)
+ _vm->renderImage(4);
+ obj1.setProperty(OPENED);
+ obj1._click = 6;
+
+ obj1._click2 = 5;
+ _vm->playSound(kAudioDoorOpen);
+ } else if ((verb == ACTION_CLOSE) && (obj1._id == TRAP)) {
+ if (isSectionVisible(9))
+ _vm->renderMessage(kStringCable1);
+ else {
+ setSectionVisible(3, false);
+ return false;
+ }
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, GENERATOR_WIRE, CLIP) &&
+ isSectionVisible(3) && (getObject(0)->_click != 16)) {
+ _vm->renderImage(_gm->invertSection(8));
+ _vm->renderImage(2);
+ setSectionVisible(4, false);
+ _vm->renderImage(3);
+ _vm->renderImage(9);
+ getObject(0)->_click = 16;
+ Room *r = _gm->_rooms[LANDINGMODULE];
+ if (_gm->_state._landingModuleEnergyDaysLeft && r->isSectionVisible(7))
+ _gm->turnOn();
+ else
+ _vm->renderImage(4);
+ _gm->_rooms[HOLD]->setSectionVisible(7, true);
+ _gm->great(3);
+ } else if ((verb == ACTION_PULL) && (obj1._id == GENERATOR_WIRE) && (obj1._click == 16)) {
+ _vm->renderImage(_gm->invertSection(9));
+ _vm->renderImage(2);
+ _vm->renderImage(3);
+ _vm->renderImage(4);
+ _vm->renderImage(8);
+ obj1._click = 15;
+ _gm->turnOff();
+ _gm->_rooms[HOLD]->setSectionVisible(7, false);
+ } else if ((verb == ACTION_USE) &&
+ (Object::combine(obj1, obj2, WIRE, CLIP) ||
+ Object::combine(obj1, obj2, SPOOL, CLIP)) &&
+ isSectionVisible(3)) {
+ _vm->renderMessage(kStringShipHold11);
+ } else if ((verb == ACTION_LOOK) && (obj1._id == VOLTMETER)) {
+ if (_gm->_state._powerOff)
+ _vm->renderMessage(kStringShipHold12);
+ else
+ _vm->renderMessage(kStringShipHold13);
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, LADDER, ROPE)) {
+ _vm->renderImage(13);
+ Room *r = _gm->_rooms[CABIN_R3];
+ _gm->_inventory.remove(*r->getObject(9));
+ getObject(3)->_click = 18;
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, OUTERHATCH, GENERATOR_ROPE)) {
+ if (!isSectionVisible(1))
+ _vm->renderMessage(kStringShipHold14);
+ else {
+ _vm->renderImage(_gm->invertSection(13));
+ _vm->renderImage(1);
+ if (isSectionVisible(7)) {
+ _vm->renderImage(10);
+ _vm->renderImage(11);
+ } else
+ _vm->renderImage(12);
+
+ Room *r = _gm->_rooms[OUTSIDE];
+ r->setSectionVisible(1, true);
+ r->getObject(1)->_click = 1;
+ getObject(3)->_click = 17;
+ }
+ } else if ((verb == ACTION_TAKE) && (obj1._id == GENERATOR_ROPE))
+ _vm->renderMessage(kStringShipHold15);
+ else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, OUTERHATCH, GENERATOR_WIRE) && isSectionVisible(1))
+ _vm->renderMessage(kStringShipHold16);
+ else
+ return false;
+
+ return true;
+}
+
+// Arsano
+void ArsanoRocks::onEntrance() {
+ _gm->great(8);
+}
+
+bool ArsanoRocks::interact(Action verb, Object &obj1, Object &obj2) {
+ if (((verb == ACTION_PULL) || (verb == ACTION_PRESS)) &&
+ (obj1._id == STONE) && !isSectionVisible(3)) {
+ _vm->renderImage(1);
+ _gm->wait2(2);
+ _vm->renderImage(2);
+ _gm->wait2(2);
+ _vm->renderImage(3);
+ _vm->playSound(kAudioRocks);
+ obj1._click = 3;
+ getObject(3)->_click = 4;
+ getObject(3)->setProperty(EXIT);
+ return true;
+ }
+ return false;
+}
+
+void ArsanoMeetup::onEntrance() {
+ if (isSectionVisible(7)) {
+ _gm->wait2(3);
+ _vm->renderImage(6);
+ setSectionVisible(7, false);
+ _gm->wait2(3);
+ _vm->renderImage(_gm->invertSection(6));
+ }
+ if (!(_gm->_state._greatFlag & 0x8000)) {
+ _vm->playSound(kAudioFoundLocation);
+ _gm->_state._greatFlag |= 0x8000;
+ }
+}
+
+void ArsanoMeetup::animation() {
+ _vm->renderImage(_gm->invertSection(1) + _beacon);
+ _beacon = (_beacon + 1) % 5;
+ _vm->renderImage(_beacon + 1);
+ _vm->renderImage(_beacon + 8);
+ if (isSectionVisible(_sign + 13))
+ _vm->renderImage(_gm->invertSection(13) + _sign);
+ else
+ _vm->renderImage(13 + _sign);
+
+ _sign = (_sign + 1) % 14;
+ _gm->setAnimationTimer(3);
+}
+
+bool ArsanoMeetup::interact(Action verb, Object &obj1, Object &obj2) {
+ if ((verb == ACTION_WALK) &&
+ ((obj1._id == SPACESHIPS) ||
+ ((obj1._id == SPACESHIP) && !obj1.hasProperty(OPENED)))) {
+ _vm->renderMessage(kStringArsanoMeetup1);
+ } else if ((verb == ACTION_WALK) && (obj1._id == SPACESHIP))
+ _gm->changeRoom(GLIDER);
+ else if ((verb == ACTION_WALK) && (obj1._id == STAR))
+ _vm->renderMessage(kStringArsanoMeetup2);
+ else if ((verb == ACTION_LOOK) && (obj1._id == STAR)) {
+ _vm->setCurrentImage(26);
+ _vm->renderImage(0);
+ _vm->paletteBrightness();
+ _gm->animationOff();
+ _gm->getInput();
+ _gm->animationOn();
+ g_system->fillScreen(kColorBlack);
+ _vm->renderRoom(*this);
+ _vm->paletteBrightness();
+ } else if ((verb == ACTION_WALK) && (obj1._id == DOOR)) {
+ _vm->renderImage(6);
+ _gm->wait2(3);
+ _vm->renderImage(7);
+ setSectionVisible(6, false);
+ _gm->wait2(3);
+
+ return false;
+ } else if ((verb == ACTION_LOOK) && (obj1._id == MEETUP_SIGN) && _gm->_state._language) {
+ if (_gm->_state._language == 2)
+ _vm->renderMessage(kStringArsanoMeetup3);
+
+ obj1._description = kStringSignDescription2;
+ if (_gm->_state._language == 1)
+ return false;
+
+ _gm->_state._language = 1;
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, KEYCARD_R, SPACESHIP)) {
+ getObject(5)->setProperty(OPENED);
+ _gm->changeRoom(GLIDER);
+ } else
+ return false;
+
+ return true;
+}
+
+void ArsanoEntrance::animation() {
+ if (!_vm->_messageDisplayed && isSectionVisible(kMaxSection - 5)) {
+ _gm->animationOff(); // to avoid recursive call
+ _vm->playSound(kAudioSlideDoor);
+ _vm->renderImage(8);
+ setSectionVisible(9, false);
+ _gm->wait2(2);
+ _vm->renderImage(7);
+ setSectionVisible(8, false);
+ _gm->wait2(2);
+ _vm->renderImage(6);
+ setSectionVisible(7, false);
+ _gm->wait2(2);
+ _vm->renderImage(5);
+ setSectionVisible(6, false);
+ _gm->wait2(2);
+ _vm->renderImage(_gm->invertSection(5));
+ getObject(11)->_click = 255;
+ setSectionVisible(kMaxSection - 5, false);
+ _gm->animationOn();
+ }
+ if (isSectionVisible(2))
+ _vm->renderImage(_gm->invertSection(2));
+ else if (_eyewitness)
+ --_eyewitness;
+ else {
+ _eyewitness = 20;
+ _vm->renderImage(2);
+ }
+
+ _gm->setAnimationTimer(4);
+}
+
+bool ArsanoEntrance::interact(Action verb, Object &obj1, Object &obj2) {
+ static byte row1[6] = {1, 1, 1, 1, 1, 0};
+ static byte row2[6] = {1, 1, 1, 1, 1, 0};
+ static byte row3[6] = {1, 1, 0, 0, 0, 0};
+
+ if ((verb == ACTION_TALK) && (obj1._id == PORTER)) {
+ if (_gm->_rooms[AIRLOCK]->getObject(4)->hasProperty(WORN))
+ _vm->renderMessage(kStringArsanoEntrance1);
+ else {
+ if (_gm->_state._language) {
+ int e;
+ do {
+ if (_gm->_state._shoes == 1) {
+ _dialog2[2] = kStringArsanoEntrance2;
+ addSentence(2, 2);
+ } else if (_gm->_state._shoes > 1)
+ removeSentence(2, 2);
+
+ switch (e = _gm->dialog(5, row2, _dialog2, 2)) {
+ case 0:
+ _gm->reply(kStringArsanoEntrance3, 1, _gm->invertSection(1));
+ _gm->reply(kStringArsanoEntrance4, 1, _gm->invertSection(1));
+ _gm->reply(kStringArsanoEntrance5, 1, _gm->invertSection(1));
+ removeSentence(1, 1);
+ break;
+ case 1:
+ _gm->reply(kStringArsanoEntrance6, 1, _gm->invertSection(1));
+ addSentence(1, 2);
+ break;
+ case 2:
+ if (_gm->_state._shoes == 1) {
+ _gm->reply(kStringArsanoEntrance7, 1, _gm->invertSection(1));
+ _gm->_state._shoes = 2;
+ } else {
+ _gm->reply(kStringArsanoEntrance8, 1, _gm->invertSection(1));
+ _gm->_state._shoes = 1;
+ }
+ break;
+ case 3:
+ _gm->reply(kStringArsanoEntrance9, 1, _gm->invertSection(1));
+ }
+ } while (e != 4);
+ } else if (_gm->dialog(5, row2, _dialog2, 0) != 4)
+ _gm->reply(kStringArsanoEntrance10, 1, _gm->invertSection(1));
+ }
+ } else if ((verb == ACTION_WALK) && (obj1._id == STAIRCASE) && (_gm->_state._shoes != 3)) {
+ _vm->renderImage(3);
+ _gm->wait2(2);
+ _vm->renderImage(4);
+ setSectionVisible(3, false);
+ if (_gm->_rooms[AIRLOCK]->getObject(4)->hasProperty(WORN))
+ _gm->reply(kStringDialogSeparator, 1, _gm->invertSection(1));
+ else if (_gm->_state._language)
+ _gm->reply(kStringArsanoEntrance11, 1, _gm->invertSection(1));
+ else
+ _gm->reply(kStringArsanoEntrance12, 1, _gm->invertSection(1));
+ _vm->renderImage(3);
+ setSectionVisible(4, false);
+ _gm->wait2(2);
+ _vm->renderImage(_gm->invertSection(3));
+ if (!_gm->_rooms[AIRLOCK]->getObject(4)->hasProperty(WORN)) {
+ if (_gm->_state._language) {
+ if (_gm->_state._shoes)
+ _gm->reply(kStringArsanoEntrance13, 1, _gm->invertSection(1));
+ else
+ _gm->reply(kStringArsanoEntrance14, 1, _gm->invertSection(1));
+ int e = 0;
+ while ((e < 3) && (!allSentencesRemoved(4, 1))) {
+ switch (e = _gm->dialog(5, row1, _dialog1, 1)) {
+ case 0:
+ _gm->reply(kStringArsanoEntrance15, 1, 1 + 128);
+ break;
+ case 1:
+ _gm->reply(kStringArsanoEntrance3, 1, 1 + 128);
+ _gm->reply(kStringArsanoEntrance4, 1, 1 + 128);
+ _gm->reply(kStringArsanoEntrance5, 1, 1 + 128);
+ removeSentence(0, 2);
+ break;
+ case 2:
+ _gm->reply(kStringArsanoEntrance7, 1, 1 + 128);
+ _gm->_state._shoes = 2;
+ break;
+ case 3:
+ _vm->renderImage(3);
+ _gm->wait2(2);
+ _vm->renderImage(4);
+ setSectionVisible(3, false);
+ _gm->reply(kStringArsanoEntrance16, 1, 1 + 128);
+ _vm->renderImage(3);
+ setSectionVisible(4, false);
+ _gm->wait2(2);
+ _vm->renderImage(_gm->invertSection(3));
+ break;
+ }
+ removeSentence(0, 1);
+ }
+ } else {
+ _gm->dialog(2, row3, _dialog3, 0);
+ _gm->reply(kStringArsanoEntrance10, 1, 1 + 128);
+ }
+ }
+ } else if ((verb == ACTION_PRESS) && (obj1._id == BATHROOM_BUTTON)) {
+ _vm->playSound(kAudioSlideDoor);
+ _vm->renderImage(5);
+ _gm->wait2(2);
+ _vm->renderImage(6);
+ setSectionVisible(5, false);
+ _gm->wait2(2);
+ _vm->renderImage(7);
+ setSectionVisible(6, false);
+ _gm->wait2(2);
+ _vm->renderImage(8);
+ setSectionVisible(7, false);
+ _gm->wait2(2);
+ _vm->renderImage(9);
+ setSectionVisible(8, false);
+ getObject(11)->_click = 9;
+ } else if ((verb == ACTION_WALK) && (obj1._id == ARSANO_BATHROOM)) {
+ if (_gm->_state._coins) {
+ if (_gm->_state._shoes == 2) {
+ _vm->renderMessage(kStringArsanoEntrance17);
+ _gm->_state._shoes = 3;
+ removeSentence(2, 2);
+ removeSentence(3, 2);
+ } else if (_gm->_state._shoes == 3) {
+ _vm->renderMessage(kStringArsanoEntrance18);
+ _gm->_state._shoes = 2;
+ } else
+ _vm->renderMessage(kStringArsanoEntrance19);
+ } else {
+ if (_gm->_rooms[AIRLOCK]->getObject(5)->hasProperty(WORN))
+ _vm->renderMessage(kStringArsanoEntrance20);
+ else {
+ _vm->renderMessage(kStringArsanoEntrance21);
+ _gm->waitOnInput(_gm->_timer1);
+ _vm->removeMessage();
+ _vm->renderMessage(kStringArsanoEntrance22);
+ _gm->takeObject(*getObject(16));
+ _gm->_state._coins = 5;
+ }
+ }
+ // This shown object is an abuse in the original engine as it's not a real shown variable
+ // It's an internal (boolean) status
+ _shown[kMaxSection - 5] = kShownTrue;
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, COINS, CAR_SLOT)) {
+ if ((_gm->_state._coins < 5) && (getObject(7 - _gm->_state._coins)->_click == 7))
+ _vm->renderMessage(kStringArsanoEntrance23);
+ else {
+ _vm->renderImage(15 - _gm->_state._coins);
+ getObject(8 - _gm->_state._coins)->_click = 7;
+ --_gm->_state._coins;
+ if (_gm->_state._coins == 1)
+ getObject(16)->_name = kStringCoin;
+
+ if (_gm->_state._coins == 0) {
+ _gm->_inventory.remove(*getObject(16));
+ _gm->_state._coins = 255;
+ }
+ }
+ } else if ((verb == ACTION_LOOK) && (obj1._id == KITCHEN_SIGN) && _gm->_state._language) {
+ if (_gm->_state._language == 2)
+ _vm->renderMessage(kStringArsanoEntrance24);
+ obj1._description = kStringDoorDescription5;
+ if (_gm->_state._language == 1)
+ return false;
+ _gm->_state._language = 1;
+ } else if ((verb == ACTION_LOOK) && (obj1._id == BATHROOM_SIGN) && _gm->_state._language) {
+ if (_gm->_state._language == 2)
+ _vm->renderMessage(kStringArsanoEntrance25);
+ obj1._description = kStringDoorDescription6;
+ if (_gm->_state._language == 1)
+ return false;
+ _gm->_state._language = 1;
+ } else if ((verb == ACTION_WALK) && (obj1._id == MEETUP_EXIT)) {
+ if (!((_gm->_rooms[AIRLOCK]->getObject(4)->hasProperty(WORN)) &&
+ (_gm->_rooms[AIRLOCK]->getObject(5)->hasProperty(WORN)) &&
+ (_gm->_rooms[AIRLOCK]->getObject(6)->hasProperty(WORN)))) {
+ _vm->renderMessage(kStringArsanoEntrance26);
+ _gm->_rooms[AIRLOCK]->getObject(4)->setProperty(WORN);
+ _gm->_rooms[AIRLOCK]->getObject(5)->setProperty(WORN);
+ _gm->_rooms[AIRLOCK]->getObject(6)->setProperty(WORN);
+ _gm->waitOnInput(_gm->_timer1);
+ _vm->removeMessage();
+ }
+ return false;
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, KNIFE, PORTER))
+ _vm->renderMessage(kStringArsanoEntrance27);
+ else
+ return false;
+
+ return true;
+}
+
+void ArsanoRemaining::animation() {
+ switch (_i) {
+ case 0:
+ _vm->renderImage(1);
+ _vm->renderImage(_gm->invertSection(4));
+ break;
+ case 1:
+ _vm->renderImage(_gm->invertSection(1));
+ _vm->renderImage(4);
+ break;
+ case 2:
+ _vm->renderImage(2);
+ _vm->renderImage(_gm->invertSection(4));
+ break;
+
+ case 3:
+ _vm->renderImage(7); // Dragon
+ _vm->renderImage(_gm->invertSection(2));
+ _vm->renderImage(4);
+ break;
+ case 4:
+ _vm->renderImage(8);
+ setSectionVisible(7, false);
+ _vm->renderImage(2);
+ _vm->renderImage(_gm->invertSection(4));
+ break;
+ case 5:
+ _vm->renderImage(_gm->invertSection(8));
+ _vm->renderImage(_gm->invertSection(2));
+ break;
+ case 6:
+ _vm->renderImage(3);
+ _vm->renderImage(2);
+ break;
+ case 7:
+ _vm->renderImage(_gm->invertSection(3));
+ _vm->renderImage(_gm->invertSection(2));
+ break;
+ case 8:
+ _vm->renderImage(3);
+ break;
+ case 9:
+ _vm->renderImage(14); // Card Player 1
+ _vm->renderImage(4);
+ _vm->renderImage(_gm->invertSection(3));
+ break;
+ case 10:
+ _vm->renderImage(15);
+ _vm->renderImage(14);
+ _vm->renderImage(_gm->invertSection(4));
+ _vm->renderImage(3);
+ break;
+ case 11:
+ _vm->renderImage(16);
+ setSectionVisible(15, false);
+ _vm->renderImage(4);
+ _vm->renderImage(_gm->invertSection(3));
+ break;
+ case 12:
+ _vm->renderImage(17);
+ setSectionVisible(16, false);
+ _vm->renderImage(_gm->invertSection(4));
+ _vm->renderImage(3);
+ break;
+ case 13:
+ _vm->renderImage(_gm->invertSection(17));
+ _vm->renderImage(4);
+ _vm->renderImage(_gm->invertSection(3));
+ break;
+ case 14:
+ _vm->renderImage(_gm->invertSection(4));
+ break;
+ case 15:
+ _vm->renderImage(6);
+ break;
+ case 16:
+ _vm->renderImage(18); // Card Player 2
+ _vm->renderImage(5);
+ break;
+ case 17:
+ _vm->renderImage(19);
+ setSectionVisible(18, false);
+ _vm->renderImage(_gm->invertSection(5));
+ break;
+ case 18:
+ _vm->renderImage(20);
+ setSectionVisible(19, false);
+ _vm->renderImage(5);
+ break;
+ case 19:
+ _vm->renderImage(21);
+ setSectionVisible(20, false);
+ _vm->renderImage(_gm->invertSection(5));
+ break;
+ case 20:
+ _vm->renderImage(_gm->invertSection(21));
+ _vm->renderImage(5);
+ break;
+ case 21:
+ _vm->renderImage(_gm->invertSection(5));
+ break;
+ case 22:
+ _vm->renderImage(5);
+ break;
+ case 23:
+ _vm->renderImage(10);
+ _chewing = false;
+ _vm->renderImage(_gm->invertSection(5));
+ break;
+ case 24:
+ _vm->renderImage(11);
+ setSectionVisible(10, false);
+ break;
+ case 25:
+ _vm->renderImage(12);
+ setSectionVisible(11, false);
+ break;
+ case 26:
+ _vm->renderImage(13);
+ setSectionVisible(12, false);
+ break;
+ case 27:
+ _vm->renderImage(12);
+ setSectionVisible(13, false);
+ break;
+ case 28:
+ _vm->renderImage(11);
+ setSectionVisible(12, false);
+ break;
+ case 29:
+ _vm->renderImage(10);
+ setSectionVisible(11, false);
+ break;
+ case 30:
+ _vm->renderImage(_gm->invertSection(10));
+ _chewing = true;
+ break;
+ case 31:
+ _vm->renderImage(22); // Card Player 3
+ break;
+ case 32:
+ _vm->renderImage(_gm->invertSection(22));
+ break;
+ case 33:
+ _vm->renderImage(_gm->invertSection(6));
+ break;
+ case 34:
+ _vm->renderImage(4);
+ }
+
+ _i = (_i + 1) % 35;
+ if (_chewing) {
+ if (isSectionVisible(9))
+ _vm->renderImage(_gm->invertSection(9));
+ else
+ _vm->renderImage(9);
+ }
+ _gm->setAnimationTimer(3);
+}
+
+void ArsanoRoger::onEntrance() {
+ if (!sentenceRemoved(0, 2)) {
+ _gm->say(kStringArsanoRoger1);
+ _gm->reply(kStringArsanoRoger2, 2, 2 + 128);
+ removeSentence(0, 2);
+ }
+}
+
+void ArsanoRoger::animation() {
+ if (isSectionVisible(1))
+ _vm->renderImage(_gm->invertSection(1));
+ else if (isSectionVisible(10)) {
+ _vm->renderImage(12);
+ setSectionVisible(10, false);
+ setSectionVisible(12, false);
+ } else if (_eyewitness) {
+ --_eyewitness;
+ } else {
+ _eyewitness = 20;
+ if (isSectionVisible(3))
+ _vm->renderImage(10);
+ else
+ _vm->renderImage(1);
+ }
+
+ if (isSectionVisible(3)) {
+ setSectionVisible(5 + _hands, false);
+ _hands = (_hands + 1) % 5;
+ _vm->renderImage(5 + _hands);
+ }
+ _gm->setAnimationTimer(4);
+}
+
+bool ArsanoRoger::interact(Action verb, Object &obj1, Object &obj2) {
+ static byte row1[6] = {1, 1, 1, 1, 0, 0};
+
+ if ((verb == ACTION_TAKE) && (obj1._id == WALLET)) {
+ if (isSectionVisible(3)) {
+ _gm->great(0);
+ return false;
+ }
+ _gm->reply(kStringArsanoRoger3, 2, 2 + 128);
+ } else if ((verb == ACTION_USE) && (obj1._id == CUP))
+ _vm->renderMessage(kStringArsanoRoger4);
+ else if ((verb == ACTION_TALK) && (obj1._id == ROGER_W)) {
+ if (isSectionVisible(3))
+ _vm->renderMessage(kStringArsanoRoger5);
+ else {
+ switch (_gm->dialog(4, row1, _dialog1, 1)) {
+ case 0:
+ _gm->reply(kStringArsanoRoger6, 2, 2 + 128);
+ _gm->reply(kStringArsanoRoger7, 2, 2 + 128);
+ break;
+ case 1:
+ _gm->reply(kStringArsanoRoger8, 2, 2 + 128);
+ _gm->reply(kStringArsanoRoger9, 2, 2 + 128);
+ _gm->say(kStringArsanoRoger10);
+ break;
+ case 2:
+ _gm->reply(kStringArsanoRoger11, 2, 2 + 128);
+ _gm->say(kStringArsanoRoger12);
+ _gm->reply(kStringArsanoRoger13, 2, 2 + 128);
+ _gm->say(kStringArsanoRoger14);
+ _gm->reply(kStringArsanoRoger15, 2, 2 + 128);
+ _gm->reply(kStringArsanoRoger16, 2, 2 + 128);
+ _gm->say(kStringArsanoRoger17);
+ _gm->say(kStringArsanoRoger18);
+ _gm->reply(kStringArsanoRoger19, 2, 2 + 128);
+ _gm->say(kStringArsanoRoger20);
+ _gm->say(kStringArsanoRoger21);
+ _gm->reply(kStringArsanoRoger22, 2, 2 + 128);
+ _gm->say(kStringArsanoRoger23);
+ _gm->reply(kStringArsanoRoger24, 2, 2 + 128);
+ _gm->reply(kStringArsanoRoger25, 2, 2 + 128);
+ _gm->say(kStringArsanoRoger26);
+ _gm->reply(kStringArsanoRoger27, 2, 2 + 128);
+ _gm->reply(kStringArsanoRoger28, 2, 2 + 128);
+ _gm->say(kStringArsanoRoger29);
+ _gm->reply(kStringArsanoRoger30, 2, 2 + 128);
+ _gm->reply(kStringArsanoRoger31, 2, 2 + 128);
+ _gm->say(kStringArsanoRoger32);
+ _gm->reply(kStringArsanoRoger33, 2, 2 + 128);
+ _gm->say(kStringArsanoRoger34);
+ _gm->reply(kStringArsanoRoger35, 2, 2 + 128);
+ }
+ }
+ } else if (((verb == ACTION_USE) && Object::combine(obj1, obj2, CHESS, ROGER_W)) ||
+ ((verb == ACTION_GIVE) && (obj1._id == CHESS) && (obj2._id == ROGER_W))) {
+ _vm->renderImage(11);
+ _gm->great(0);
+ _gm->say(kStringArsanoRoger36);
+ _gm->reply(kStringArsanoRoger37, 2, 2 + 128);
+ _gm->say(kStringArsanoRoger38);
+ _vm->paletteFadeOut();
+ _gm->_inventory.remove(*_gm->_rooms[CABIN_R3]->getObject(0)); // Chess board
+ g_system->fillScreen(kColorBlack);
+ _vm->_menuBrightness = 255;
+ _vm->paletteBrightness();
+ _vm->renderMessage(kStringArsanoRoger39);
+ _gm->waitOnInput(_gm->_timer1);
+ _vm->removeMessage();
+ _vm->_menuBrightness = 0;
+ _vm->paletteBrightness();
+ _gm->_state._time += ticksToMsec(125000); // 2 hours
+ _gm->_state._alarmOn = (_gm->_state._timeAlarm > _gm->_state._time);
+ _gm->_state._eventTime = _gm->_state._time + ticksToMsec(4000);
+ _gm->_state._eventCallback = kSupernovaFn;
+ setSectionVisible(11, false);
+ setSectionVisible(1, false);
+ _vm->renderRoom(*this);
+ _vm->renderImage(3);
+ getObject(3)->_click = 5;
+ getObject(5)->_click = 6;
+ getObject(6)->_click = 7;
+ _vm->paletteFadeIn();
+ _vm->renderMessage(kStringArsanoRoger40);
+ _gm->waitOnInput(_gm->_timer1);
+ _vm->removeMessage();
+ } else
+ return false;
+
+ return true;
+}
+
+void ArsanoGlider::animation() {
+ if (isSectionVisible(8)) {
+ setSectionVisible(24 + _sinus, false);
+ _sinus = (_sinus + 1) % 14;
+ _vm->renderImage(24 + _sinus);
+ } else if (isSectionVisible(24 + _sinus))
+ _vm->renderImage(_gm->invertSection(24 + _sinus));
+
+ _gm->setAnimationTimer(2);
+}
+
+bool ArsanoGlider::interact(Action verb, Object &obj1, Object &obj2) {
+ static char l, r;
+ if ((verb == ACTION_USE) && Object::combine(obj1, obj2, KEYCARD_R, GLIDER_SLOT)) {
+ _vm->renderImage(5);
+ _gm->wait2(7);
+ _vm->renderImage(8);
+ getObject(5)->_click = 10;
+ _gm->_inventory.remove(*_gm->_rooms[ROGER]->getObject(8));
+ } else if (((verb == ACTION_TAKE) || (verb == ACTION_PULL)) &&
+ (obj1._id == GLIDER_KEYCARD)) {
+ _vm->renderImage(_gm->invertSection(5));
+ _vm->renderImage(_gm->invertSection(8));
+ getObject(5)->_click = 255;
+ _gm->takeObject(*_gm->_rooms[ROGER]->getObject(8));
+ for (int i = 9; i <= 22; i++)
+ _vm->renderImage(_gm->invertSection(i));
+ l = r = 0;
+ } else if ((verb == ACTION_PRESS) &&
+ (obj1._id >= GLIDER_BUTTON1) && (obj1._id <= GLIDER_BUTTON4)) {
+ int i = obj1._id - GLIDER_BUTTON1 + 1;
+ _vm->renderImage(i);
+ if (isSectionVisible(8)) {
+ l = 0;
+ r = 0;
+ for (int j = 1; j < 8; j++) {
+ if (isSectionVisible(j + 8))
+ l = j;
+ if (isSectionVisible(j + 15))
+ r = j;
+ }
+ switch (i) {
+ case 1:
+ if (l < 7) {
+ l++;
+ _vm->renderImage(l + 8);
+ }
+ break;
+ case 3:
+ if (r < 7) {
+ r++;
+ _vm->renderImage(r + 15);
+ }
+ break;
+ case 2:
+ if (l) {
+ _vm->renderImage(_gm->invertSection(l + 8));
+ l--;
+ }
+ break;
+ case 4:
+ if (r) {
+ _vm->renderImage(_gm->invertSection(r + 15));
+ r--;
+ }
+ }
+ }
+ _gm->wait2(4);
+ _vm->renderImage(_gm->invertSection(i));
+ } else if ((verb == ACTION_USE) && (obj1._id == GLIDER_BUTTONS))
+ _vm->renderMessage(kStringArsanoGlider1);
+ else
+ return false;
+
+ return true;
+}
+
+void ArsanoMeetup2::onEntrance() {
+ if (sentenceRemoved(0, 1)) {
+ if (sentenceRemoved(1, 1))
+ _vm->renderMessage(kStringArsanoMeetup2_2); // All spaceships have left the planet, except one ...
+ else
+ shipStart();
+ } else if (sentenceRemoved(1, 1))
+ _vm->renderMessage(kStringArsanoMeetup2_1); // All spaceships have left the planet
+
+ addAllSentences(1);
+}
+
+bool ArsanoMeetup2::interact(Action verb, Object &obj1, Object &obj2) {
+ static byte row1[6] = {1, 1, 0, 0, 0, 0};
+ static byte row2[6] = {1, 1, 0, 0, 0, 0};
+ static byte row3[6] = {1, 1, 1, 1, 0, 0};
+ static byte row4[6] = {2, 1, 0, 0, 0, 0};
+
+ if (((verb == ACTION_WALK) &&
+ ((obj1._id == SPACESHIP) || (obj1._id == ROGER_W))) ||
+ ((verb == ACTION_TALK) && (obj1._id == ROGER_W))) {
+ _gm->changeRoom(INTRO);
+ _vm->setCurrentImage(30);
+ _vm->renderImage(0);
+ _vm->paletteBrightness();
+ bool found;
+ if (sentenceRemoved(0, 2) || sentenceRemoved(1, 2)) {
+ _gm->reply(kStringArsanoMeetup2_3, 1, 1 + 128);
+ found = !_gm->dialog(2, row4, _dialog4, 0);
+ if (!(found))
+ _gm->reply(kStringArsanoMeetup2_4, 1, 1 + 128);
+ } else {
+ _gm->reply(kStringArsanoMeetup2_5, 1, 1 + 128);
+ _gm->reply(kStringArsanoMeetup2_6, 1, 1 + 128);
+ found = !_gm->dialog(2, row1, _dialog1, 0);
+ removeSentence(0, 2);
+ }
+ if (found) {
+ _gm->_inventory.remove(*_gm->_rooms[ROGER]->getObject(3));
+ _gm->_inventory.remove(*_gm->_rooms[ROGER]->getObject(7));
+ _gm->_inventory.remove(*_gm->_rooms[ROGER]->getObject(8));
+ _gm->reply(kStringArsanoMeetup2_7, 1, 1 + 128);
+ _gm->reply(kStringArsanoMeetup2_8, 1, 1 + 128);
+ bool flight = _gm->dialog(2, row2, _dialog2, 0);
+ if (flight) {
+ _gm->reply(kStringArsanoMeetup2_9, 1, 1 + 128);
+ _gm->dialog(4, row3, _dialog3, 0);
+ _gm->reply(kStringArsanoMeetup2_10, 1, 1 + 128);
+ } else
+ _gm->reply(kStringArsanoMeetup2_11, 1, 1 + 128);
+
+ _gm->changeRoom(MEETUP2);
+ _gm->_rooms[MEETUP2]->setSectionVisible(12, false);
+ _gm->_rooms[MEETUP2]->getObject(0)->_click = 255;
+ _gm->_rooms[MEETUP2]->getObject(1)->_click = 255;
+ _vm->renderRoom(*this);
+ _vm->paletteBrightness();
+ shipStart();
+ if (flight) {
+ _vm->setCurrentImage(13);
+ _vm->renderImage(0);
+ _vm->paletteBrightness();
+ _gm->wait2(36);
+ for (int i = 1; i <= 13; i++) {
+ if (i > 1)
+ _vm->renderImage(_gm->invertSection(i - 1));
+ _vm->renderImage(i);
+ _gm->wait2(2);
+ }
+ _vm->renderImage(_gm->invertSection(13));
+ _gm->wait2(20);
+ _vm->setCurrentImage(14);
+ _vm->renderImage(0);
+ _vm->paletteBrightness();
+ _gm->wait2(36);
+ for (int i = 1; i <= 13; i++) {
+ if (i > 1)
+ _vm->renderImage(_gm->invertSection(i - 1));
+ _vm->renderImage(i);
+ _gm->wait2(2);
+ }
+ _vm->renderImage(_gm->invertSection(13));
+ _gm->wait2(9);
+ _vm->playSound(kAudioCrash);
+ for (int i = 14; i <= 19; i++) {
+ _vm->renderImage(i);
+ _gm->wait2(3);
+ }
+ _vm->paletteFadeOut();
+ _vm->setCurrentImage(11);
+ _vm->renderImage(0);
+ _vm->paletteFadeIn();
+ _gm->wait2(18);
+ _vm->renderMessage(kStringArsanoMeetup2_12);
+ _gm->great(0);
+ _gm->waitOnInput(_gm->_timer1);
+ _vm->removeMessage();
+ _vm->paletteFadeOut();
+ g_system->fillScreen(kColorBlack);
+ _gm->_state._dream = false;
+ if (!_vm->loadGame(kSleepAutosaveSlot))
+ _vm->errorTempSave(false);
+ _gm->loadTime();
+ _gm->_rooms[CAVE]->getObject(1)->_exitRoom = MEETUP3;
+ _gm->_state._dream = true;
+ }
+ } else {
+ _gm->changeRoom(MEETUP2);
+ _vm->renderRoom(*this);
+ }
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, KEYCARD_R, SPACESHIP))
+ _vm->renderMessage(kStringArsanoMeetup2_13);
+ else
+ return false;
+
+ return true;
+}
+
+void ArsanoMeetup2::shipStart() {
+ _gm->wait2(12);
+ for (int i = 2; i <= 11; ++i) {
+ if (i >= 9)
+ _vm->renderImage(i - 1 + 128);
+ else
+ setSectionVisible(i - 1, false);
+ _vm->renderImage(i);
+ _gm->wait2(2);
+ }
+ _vm->renderImage(11 + 128);
+}
+
+bool ArsanoMeetup3::interact(Action verb, Object &obj1, Object &obj2) {
+ byte row2[6] = {1, 1, 1, 1, 0, 0};
+ byte row3[6] = {1, 1, 0, 0, 0, 0};
+ byte rowsX[6] = {1, 1, 1, 0, 0, 0};
+
+ if ((verb == ACTION_WALK) && (obj1._id == STAR))
+ _vm->renderMessage(kStringArsanoMeetup2);
+ else if ((verb == ACTION_LOOK) && (obj1._id == STAR)) {
+ _vm->setCurrentImage(26);
+ _vm->renderImage(0);
+ _vm->paletteBrightness();
+ _gm->getInput();
+ g_system->fillScreen(kColorBlack);
+ _vm->renderRoom(*this);
+ } else if ((verb == ACTION_WALK) && (obj1._id == UFO)) {
+ g_system->fillScreen(kColorBlack);
+ _vm->setCurrentImage(36);
+ _vm->renderImage(0);
+ _vm->paletteBrightness();
+ _gm->dialog(3, rowsX, _dialogsX, 0);
+ _vm->renderImage(1);
+ _gm->wait2(3);
+ _vm->renderImage(2);
+ _gm->wait2(3);
+ _vm->renderImage(3);
+ _gm->wait2(6);
+ _vm->renderImage(4);
+ _vm->playSound(kAudioGunShot);
+
+ while (_vm->_mixer->isSoundHandleActive(_vm->_soundHandle))
+ _gm->wait2(1);
+
+ _vm->renderImage(5);
+ _gm->wait2(3);
+ _vm->renderImage(4);
+ _vm->playSound(kAudioGunShot);
+
+ while (_vm->_mixer->isSoundHandleActive(_vm->_soundHandle))
+ _gm->wait2(1);
+
+ _vm->renderImage(5);
+ _vm->paletteFadeOut();
+ _gm->wait2(12);
+ _vm->setCurrentImage(0);
+ _vm->renderImage(0);
+ _vm->paletteFadeIn();
+ _gm->wait2(18);
+ _gm->reply(kStringArsanoMeetup3_1, 2, 2 + 128);
+ _gm->wait2(10);
+ _gm->reply(kStringArsanoMeetup3_2, 1, 1 + 128);
+
+ do {
+ int i = _gm->dialog(4, row2, _dialog2, 2);
+ switch (i) {
+ case 0:
+ _gm->reply(kStringArsanoMeetup3_3, 1, 1 + 128);
+ _gm->reply(kStringArsanoMeetup3_4, 1, 1 + 128);
+ break;
+ case 1:
+ _gm->reply(kStringArsanoMeetup3_5, 2, 2 + 128);
+ _gm->say(kStringArsanoMeetup3_6);
+ _gm->reply(kStringArsanoMeetup3_7, 2, 2 + 128);
+ _gm->reply(kStringArsanoMeetup3_8, 2, 2 + 128);
+ _gm->reply(kStringArsanoMeetup3_9, 2, 2 + 128);
+ _gm->reply(kStringArsanoMeetup3_10, 2, 2 + 128);
+ _gm->reply(kStringArsanoMeetup3_11, 2, 2 + 128);
+ if (_gm->dialog(2, row3, _dialog3, 0)) {
+ _gm->reply(kStringArsanoMeetup3_12, 2, 2 + 128);
+ _gm->say(kStringArsanoMeetup3_13);
+ }
+ _gm->reply(kStringArsanoMeetup3_14, 2, 2 + 128);
+ _gm->reply(kStringArsanoMeetup3_15, 2, 2 + 128);
+ _gm->reply(kStringArsanoMeetup3_16, 2, 2 + 128);
+ _gm->reply(kStringArsanoMeetup3_17, 2, 2 + 128);
+ if (_gm->dialog(2, row3, _dialog3, 0)) {
+ _gm->reply(kStringArsanoMeetup3_12, 2, 2 + 128);
+ _gm->say(kStringArsanoMeetup3_13);
+ }
+ _gm->reply(kStringArsanoMeetup3_18, 2, 2 + 128);
+ break;
+ case 2:
+ _gm->reply(kStringArsanoMeetup3_19, 2, 2 + 128);
+ _gm->reply(kStringArsanoMeetup3_20, 2, 2 + 128);
+ break;
+ case 3:
+ _gm->reply(kStringArsanoMeetup3_21, 1, 1 + 128);
+ _gm->reply(kStringArsanoMeetup3_22, 1, 1 + 128);
+ _gm->say(kStringArsanoMeetup3_23);
+ _gm->reply(kStringArsanoMeetup3_24, 1, 1 + 128);
+ _gm->reply(kStringArsanoMeetup3_25, 1, 1 + 128);
+ }
+ removeSentence(2, 2);
+ } while (!allSentencesRemoved(4, 2));
+ _gm->say(kStringArsanoMeetup3_26);
+ _gm->reply(kStringArsanoMeetup3_27, 1, 1 + 128);
+ _gm->reply(kStringArsanoMeetup3_28, 1, 1 + 128);
+ _vm->paletteFadeOut();
+ // Remove all objects from the inventory except the Knife, Watch and Discman
+ bool has_knife = _gm->_rooms[INTRO]->getObject(1)->hasProperty(CARRIED);
+ bool has_watch = _gm->_rooms[INTRO]->getObject(2)->hasProperty(CARRIED);
+ bool has_discman = _gm->_rooms[INTRO]->getObject(3)->hasProperty(CARRIED);
+ _gm->_inventory.clear();
+ _gm->_inventoryScroll = 0;
+ if (has_knife)
+ _gm->_inventory.add(*_gm->_rooms[INTRO]->getObject(1));
+ if (has_watch)
+ _gm->_inventory.add(*_gm->_rooms[INTRO]->getObject(2));
+ if (has_discman)
+ _gm->_inventory.add(*_gm->_rooms[INTRO]->getObject(3));
+ _gm->changeRoom(CELL);
+ _gm->_state._dream = true;
+ } else
+ return false;
+
+ return true;
+}
+
+void AxacussCell::onEntrance() {
+ if (_gm->_state._dream) {
+ _vm->renderMessage(kStringAxacussCell_1);
+ _gm->_state._time = ticksToMsec(500000);
+ _gm->_state._alarmOn = (_gm->_state._timeAlarm > _gm->_state._time);
+ _gm->_state._powerOff = false;
+ _gm->_state._dream = false;
+ }
+}
+
+void AxacussCell::animation() {
+ ++_gm->_state._timeRobot;
+
+ if (_gm->_state._timeRobot == 299) {
+ _vm->renderImage(_gm->invertSection(31));
+ _vm->renderImage(28);
+ getObject(0)->_click = 255;
+ getObject(1)->resetProperty(EXIT | OPENABLE | OPENED | CLOSED);
+ } else if ((_gm->_state._timeRobot >= 301) && (_gm->_state._timeRobot <= 320)) {
+ _vm->renderImage(_gm->invertSection(329 - _gm->_state._timeRobot));
+ _vm->renderImage(328 - _gm->_state._timeRobot);
+ } else if (_gm->_state._timeRobot == 321) {
+ _vm->renderImage(31);
+ setSectionVisible(8, false);
+ getObject(0)->_click = 1;
+ getObject(1)->resetProperty(EXIT | OPENABLE | CLOSED);
+ }
+
+ if (_gm->_state._timeRobot == 599) {
+ _vm->renderImage(_gm->invertSection(31));
+ _vm->renderImage(8);
+ getObject(0)->_click = 255;
+ getObject(1)->resetProperty(EXIT | OPENABLE | OPENED | CLOSED);
+ } else if ((_gm->_state._timeRobot >= 601) && (_gm->_state._timeRobot <= 620)) {
+ _vm->renderImage(_gm->_state._timeRobot - 593 + 128);
+ _vm->renderImage(_gm->_state._timeRobot - 592);
+ } else if (_gm->_state._timeRobot == 621) {
+ _vm->renderImage(31);
+ setSectionVisible(28, false);
+ getObject(0)->_click = 1;
+ getObject(1)->resetProperty(EXIT | OPENABLE | CLOSED);
+ } else if (_gm->_state._timeRobot == 700)
+ _gm->_state._timeRobot = 0;
+ else if (_gm->_state._timeRobot == 10002) {
+ _vm->renderImage(18 + 128);
+ _vm->renderImage(29);
+ _vm->renderImage(7);
+ getObject(2)->_click = 13;
+ } else if (_gm->_state._timeRobot == 10003) {
+ setSectionVisible(29, false);
+ _vm->renderImage(30);
+ getObject(8)->_click = 12;
+ getObject(7)->_click = 14;
+ _vm->playSound(kAudioRobotBreaks);
+ } else if (_gm->_state._timeRobot == 10010)
+ --_gm->_state._timeRobot;
+
+ if (_gm->_state._timeRobot == 312) {
+ _vm->renderImage(7);
+ getObject(2)->_click = 13;
+ } else if (_gm->_state._timeRobot == 610) {
+ setSectionVisible(7, false);
+ getObject(2)->_click = 255;
+ }
+
+ if ((isSectionVisible(6)) &&
+ ((_gm->_state._timeRobot == 310) || (_gm->_state._timeRobot == 610))) {
+ _vm->playSound(kAudioRobotShock);
+ _gm->_state._timeRobot = 10000;
+ }
+
+ _gm->setAnimationTimer(3);
+}
+
+bool AxacussCell::interact(Action verb, Object &obj1, Object &obj2) {
+ if ((verb == ACTION_PRESS) && (obj1._id == CELL_BUTTON))
+ _vm->renderMessage(kStringAxacussCell_2);
+ else if ((verb == ACTION_PULL) && (obj1._id == CELL_WIRE) &&
+ !isSectionVisible(2) &&
+ !isSectionVisible(3) &&
+ !isSectionVisible(5)) {
+ if (isSectionVisible(1)) {
+ _vm->renderImage(_gm->invertSection(1));
+ _vm->renderImage(2);
+ getObject(5)->_click = 7;
+ } else if (isSectionVisible(4)) {
+ _vm->renderImage(_gm->invertSection(4));
+ _vm->renderImage(3);
+ getObject(5)->_click = 8;
+ } else if (isSectionVisible(6)) {
+ _vm->renderImage(_gm->invertSection(6));
+ _vm->renderImage(5);
+ getObject(5)->_click = 10;
+ }
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, CELL_WIRE, SOCKET) &&
+ !isSectionVisible(1) && !isSectionVisible(4) && !isSectionVisible(6)) {
+ if (isSectionVisible(2)) {
+ _vm->renderImage(_gm->invertSection(2));
+ _vm->renderImage(1);
+ getObject(5)->_click = 6;
+ } else if (isSectionVisible(3)) {
+ _vm->renderImage(_gm->invertSection(3));
+ _vm->renderImage(4);
+ getObject(5)->_click = 9;
+ } else if (isSectionVisible(5)) {
+ _vm->renderImage(_gm->invertSection(5));
+ _vm->renderImage(6);
+ getObject(5)->_click = 11;
+ } else {
+ _gm->_inventory.remove(*getObject(5));
+ _vm->renderImage(4);
+ getObject(5)->_click = 9;
+ }
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, CELL_WIRE, KNIFE) &&
+ ((isSectionVisible(1)) || (isSectionVisible(2)))) {
+ if (isSectionVisible(1))
+ _gm->shock();
+ else {
+ _vm->renderImage(_gm->invertSection(2));
+ _vm->renderImage(3);
+ getObject(5)->_click = 8;
+ }
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, CELL_WIRE, CELL_TABLE) &&
+ !isSectionVisible(1) &&
+ !isSectionVisible(2) &&
+ !isSectionVisible(5) &&
+ !isSectionVisible(6)) {
+ if (isSectionVisible(3)) {
+ _vm->renderImage(_gm->invertSection(3));
+ _vm->renderImage(5);
+ getObject(5)->_click = 10;
+ } else if (isSectionVisible(4)) {
+ _vm->renderImage(_gm->invertSection(4));
+ _vm->renderImage(6);
+ _gm->shock();
+ } else {
+ _gm->_inventory.remove(*getObject(5));
+ _vm->renderImage(5);
+ getObject(5)->_click = 10;
+ }
+ } else if ((verb == ACTION_TAKE) && (obj1._id == CELL_WIRE) && !(obj1.hasProperty(CARRIED))) {
+ if (isSectionVisible(3)) {
+ _vm->renderImage(_gm->invertSection(3));
+ _gm->takeObject(obj1);
+ } else if (isSectionVisible(5)) {
+ _vm->renderImage(_gm->invertSection(5));
+ _gm->takeObject(obj1);
+ } else
+ _vm->renderMessage(kStringAxacussCell_3);
+ } else if ((verb == ACTION_WALK) && (obj1._id == CELL_DOOR) && (obj1.hasProperty(OPENED))) {
+ if (isSectionVisible(30) || isSectionVisible(29))
+ return false;
+ _vm->playSound(kAudioGunShot);
+
+ while (_vm->_mixer->isSoundHandleActive(_vm->_soundHandle))
+ _gm->wait2(1);
+
+ _vm->playSound(kAudioGunShot);
+ _vm->playSound(kAudioGunShot);
+ _gm->dead(kStringAxacussCell_4);
+ } else if ((verb == ACTION_USE) && (obj1._id == TRAY))
+ _vm->renderMessage(kStringAxacussCell_5);
+ else if ((verb == ACTION_TAKE) && (obj1._id == MAGNET)) {
+ if (isSectionVisible(6))
+ _gm->shock();
+ _gm->takeObject(obj1);
+ _vm->renderMessage(kStringOk);
+ } else
+ return false;
+
+ return true;
+}
+
+
+void AxacussCorridor1::onEntrance() {
+ _gm->corridorOnEntrance();
+}
+
+void AxacussCorridor2::onEntrance() {
+ _gm->corridorOnEntrance();
+}
+
+void AxacussCorridor3::onEntrance() {
+ _gm->corridorOnEntrance();
+}
+
+void AxacussCorridor4::onEntrance() {
+ _gm->great(4);
+ _gm->corridorOnEntrance();
+ if (_gm->_rooms[GUARD]->isSectionVisible(1))
+ _gm->busted(0);
+}
+
+void AxacussCorridor4::animation() {
+}
+
+bool AxacussCorridor4::interact(Action verb, Object &obj1, Object &obj2) {
+ if ((verb == ACTION_TAKE) && (obj1._id == NEWSPAPER)) {
+ setSectionVisible(9, false);
+ _gm->takeObject(obj1);
+ if (isSectionVisible(29))
+ _vm->renderImage(29);
+ } else if (((verb == ACTION_USE) && Object::combine(obj1, obj2, TABLE, WATCH)) ||
+ ((verb == ACTION_GIVE) && (obj1._id == WATCH) && (obj2._id == TABLE))) {
+ if (obj1._id == WATCH)
+ _gm->_inventory.remove(obj1);
+ else
+ _gm->_inventory.remove(obj2);
+
+ _vm->renderImage(29);
+ getObject(4)->_click = 8;
+ } else if ((verb == ACTION_TAKE) && (obj1._id == WATCH) && !obj1.hasProperty(CARRIED)) {
+ setSectionVisible(29, false);
+ getObject(4)->_click = 255;
+ _gm->takeObject(*_gm->_rooms[INTRO]->getObject(2));
+ if (isSectionVisible(9))
+ _vm->renderImage(9);
+ } else
+ return false;
+
+ return true;
+}
+
+void AxacussCorridor5::onEntrance() {
+ _gm->corridorOnEntrance();
+}
+
+bool AxacussCorridor5::handleMoneyDialog() {
+ if (_gm->dialog(2, _rows, _dialog2, 0) == 0) {
+ _gm->reply(kStringAxacussCorridor5_5, 1, 1 + 128);
+ addAllSentences(2);
+ if (_gm->_state._money == 0) {
+ removeSentence(2, 2);
+ removeSentence(3, 2);
+ } else {
+ Common::String string = _vm->getGameString(kStringDialogAxacussCorridor5_7);
+ _vm->setGameString(kStringPlaceholder1, Common::String::format(string.c_str(), _gm->_state._money - 200));
+ _vm->setGameString(kStringPlaceholder2, Common::String::format(string.c_str(), _gm->_state._money));
+ _dialog3[2] = kStringPlaceholder1;
+ _dialog3[3] = kStringPlaceholder2;
+ }
+ switch (_gm->dialog(4, _rows, _dialog3, 2)) {
+ case 1:
+ _gm->wait2(3);
+ _vm->renderImage(1);
+ _vm->playSound(kAudioVoiceHalt);
+ _vm->renderImage(_gm->invertSection(1));
+ _gm->wait2(5);
+ _vm->renderImage(2);
+ _gm->wait2(2);
+ _gm->shot(3, _gm->invertSection(3));
+ break;
+ case 3:
+ if (_gm->_state._money >= 900) {
+ stopInteract(_gm->_state._money);
+ return true;
+ }
+ case 2:
+ if (_gm->_state._money > 1100) {
+ stopInteract(_gm->_state._money - 200);
+ return true;
+ }
+ _gm->reply(kStringAxacussCorridor5_6, 1, 1 + 128);
+ }
+ }
+ return false;
+}
+
+void AxacussCorridor5::stopInteract(int sum) {
+ _gm->reply(kStringAxacussCorridor5_7, 1, 1 + 128);
+ _gm->great(0);
+ _gm->changeRoom(ELEVATOR);
+ _gm->takeMoney(-sum);
+}
+
+bool AxacussCorridor5::interact(Action verb, Object &obj1, Object &obj2) {
+ if ((verb == ACTION_WALK) && (obj1._id == DOOR)) {
+ g_system->fillScreen(kColorBlack);
+ _vm->setCurrentImage(41);
+ _vm->renderImage(0);
+ _vm->paletteBrightness();
+ if (_gm->_guiEnabled) {
+ _gm->reply(kStringAxacussCorridor5_1, 1, 1 + 128);
+ if (handleMoneyDialog())
+ return true;
+ } else {
+ _gm->_guiEnabled = true;
+ _gm->reply(kStringAxacussCorridor5_2, 1, 1 + 128);
+ if (_gm->dialog(2, _rows, _dialog1, 0))
+ _gm->reply(kStringAxacussCorridor5_3, 1, 1 + 128);
+ else {
+ _gm->reply(kStringAxacussCorridor5_4, 1, 1 + 128);
+ if (handleMoneyDialog())
+ return true;
+ }
+ }
+ g_system->fillScreen(kColorBlack);
+ return true;
+ }
+ return false;
+}
+
+void AxacussCorridor6::onEntrance() {
+ _gm->corridorOnEntrance();
+}
+
+bool AxacussCorridor6::interact(Action verb, Object &obj1, Object &obj2) {
+ if ((verb == ACTION_CLOSE) && (obj1._id == DOOR) &&
+ (obj1.hasProperty(OPENED))) {
+ _vm->renderImage(6);
+ setSectionVisible(7, false);
+ obj1.resetProperty(EXIT | OPENABLE | CLOSED);
+ _gm->_rooms[CORRIDOR8]->setSectionVisible(27, false);
+ _gm->_rooms[CORRIDOR8]->setSectionVisible(28, true);
+ _gm->_rooms[CORRIDOR8]->getObject(0)->disableProperty(OPENED);
+ _vm->playSound(kAudioDoorClose);
+ } else
+ return false;
+
+ return true;
+}
+
+void AxacussCorridor7::onEntrance() {
+ _gm->corridorOnEntrance();
+}
+
+void AxacussCorridor8::onEntrance() {
+ _gm->corridorOnEntrance();
+}
+
+bool AxacussCorridor8::interact(Action verb, Object &obj1, Object &obj2) {
+ if ((verb == ACTION_OPEN) && (obj1._id == DOOR) && !obj1.hasProperty(OPENED)) {
+ _vm->renderImage(27);
+ setSectionVisible(28, false);
+ obj1.setProperty(OPENED);
+ _gm->_rooms[CORRIDOR6]->setSectionVisible(6, false);
+ _gm->_rooms[CORRIDOR6]->setSectionVisible(7, true);
+ _gm->_rooms[CORRIDOR6]->getObject(2)->resetProperty(EXIT | OPENED | OPENABLE);
+ _gm->_rooms[CORRIDOR6]->getObject(2)->_click = 4;
+ _vm->playSound(kAudioDoorOpen);
+ } else if ((verb == ACTION_CLOSE) && (obj1._id == DOOR) && (obj1._type & OPENED)) {
+ _vm->renderImage(28);
+ setSectionVisible(27, false);
+ obj1.disableProperty(OPENED);
+ _gm->_rooms[CORRIDOR6]->setSectionVisible(6, true);
+ _gm->_rooms[CORRIDOR6]->setSectionVisible(7, false);
+ _gm->_rooms[CORRIDOR6]->getObject(2)->resetProperty(EXIT | CLOSED | OPENABLE);
+ _vm->playSound(kAudioDoorClose);
+ } else
+ return false;
+
+ return true;
+}
+
+void AxacussCorridor9::onEntrance() {
+ _gm->corridorOnEntrance();
+}
+
+bool AxacussCorridor9::interact(Action verb, Object &obj1, Object &obj2) {
+ if ((verb == ACTION_CLOSE) && (obj1._id == DOOR) && (obj1.hasProperty(OPENED))) {
+ _vm->renderImage(28);
+ setSectionVisible(27, false);
+ obj1.disableProperty(OPENED);
+ _gm->_rooms[GUARD]->setSectionVisible(6, false);
+ _gm->_rooms[GUARD]->getObject(2)->disableProperty(OPENED);
+ _vm->playSound(kAudioDoorClose);
+ } else if ((verb == ACTION_OPEN) && (obj1._id == DOOR) && !obj1.hasProperty(OPENED)) {
+ _vm->renderImage(27);
+ setSectionVisible(28, false);
+ obj1.setProperty(OPENED);
+ _gm->_rooms[GUARD]->setSectionVisible(6, true);
+ _gm->_rooms[GUARD]->getObject(2)->setProperty(OPENED);
+ _vm->playSound(kAudioDoorOpen);
+ if (!_gm->_rooms[GUARD]->isSectionVisible(1))
+ _gm->busted(0);
+ } else
+ return false;
+
+ return true;
+}
+
+void AxacussBcorridor::onEntrance() {
+ _gm->corridorOnEntrance();
+ if (isSectionVisible(7))
+ _gm->busted(-1);
+}
+
+bool AxacussBcorridor::interact(Action verb, Object &obj1, Object &obj2) {
+ if (obj1.hasProperty(EXIT) ||
+ ((verb == ACTION_USE) && obj1.hasProperty(COMBINABLE) && obj2.hasProperty(EXIT))) {
+ _gm->_state._playerHidden = false;
+ }
+
+ if ((verb == ACTION_CLOSE) && (obj1._id >= DOOR1) && (obj1._id <= DOOR4) && obj1.hasProperty(OPENED)) {
+ _vm->renderImage(_gm->invertSection(obj1._id - DOOR1 + 1));
+ _vm->playSound(kAudioDoorClose);
+ obj1.disableProperty(OPENED);
+ obj1.setProperty(CLOSED);
+ if (obj1.hasProperty(OCCUPIED)) {
+ _gm->_state._destination = 255;
+ obj1.disableProperty(OCCUPIED);
+ obj1.setProperty(CAUGHT);
+ if (!_gm->_rooms[OFFICE_L1 + obj1._id - DOOR1]->isSectionVisible(4))
+ _gm->search(180);
+ else
+ _gm->_state._eventTime = kMaxTimerValue;
+ }
+ } else if (((verb == ACTION_WALK) || ((verb == ACTION_OPEN) && !obj1.hasProperty(OPENED))) &&
+ (obj1._id >= DOOR1) && (obj1._id <= DOOR4) &&
+ obj1.hasProperty(OCCUPIED)) {
+ _vm->renderMessage(kStringDontEnter);
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, MASTERKEYCARD, DOOR1) &&
+ !getObject(4)->hasProperty(OPENED)) {
+ if (getObject(4)->hasProperty(OCCUPIED))
+ _vm->renderMessage(kStringDontEnter);
+ else {
+ _vm->renderImage(1);
+ _vm->playSound(kAudioDoorOpen);
+ if (getObject(4)->hasProperty(CAUGHT))
+ _gm->busted(11);
+ getObject(4)->resetProperty(EXIT | OPENABLE | OPENED);
+ }
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, MASTERKEYCARD, DOOR2) && !getObject(5)->hasProperty(OPENED)) {
+ if (getObject(5)->hasProperty(OCCUPIED))
+ _vm->renderMessage(kStringDontEnter);
+ else {
+ _vm->renderImage(2);
+ _vm->playSound(kAudioDoorOpen);
+ if (getObject(5)->hasProperty(CAUGHT))
+ _gm->busted(16);
+ getObject(5)->resetProperty(EXIT | OPENABLE | OPENED);
+ }
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, MASTERKEYCARD, DOOR3) && !getObject(6)->hasProperty(OPENED)) {
+ if (getObject(6)->hasProperty(OCCUPIED))
+ _vm->renderMessage(kStringDontEnter);
+ else {
+ _vm->renderImage(3);
+ _vm->playSound(kAudioDoorOpen);
+ if (getObject(6)->hasProperty(CAUGHT))
+ _gm->busted(15);
+ getObject(6)->resetProperty(EXIT | OPENABLE | OPENED);
+ }
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, MASTERKEYCARD, DOOR4) && !getObject(7)->hasProperty(OPENED)) {
+ if (getObject(7)->hasProperty(OCCUPIED)) {
+ _vm->renderMessage(kStringDontEnter);
+ } else {
+ _vm->renderImage(4);
+ _vm->playSound(kAudioDoorOpen);
+ if (getObject(7)->hasProperty(CAUGHT))
+ _gm->busted(20);
+ getObject(7)->resetProperty(EXIT | OPENABLE | OPENED);
+ }
+ } else if ((verb == ACTION_LOOK) && (obj1._id >= DOOR1) && (obj1._id <= DOOR4)) {
+ _gm->_state._nameSeen[obj1._id - DOOR1] = true;
+ return false;
+ } else if ((verb == ACTION_WALK) && ((obj1._id == PILLAR1) || (obj1._id == PILLAR2))) {
+ _vm->renderMessage(kStringAxacussBcorridor_1);
+ _gm->_state._playerHidden = true;
+ } else
+ return false;
+
+ return true;
+}
+
+bool AxacussIntersection::interact(Action verb, Object &obj1, Object &obj2) {
+ byte rowsX[6] = {1, 1, 1, 0, 0, 0};
+
+ if (((verb == ACTION_WALK) || (verb == ACTION_OPEN)) && (obj1._id == DOOR) && !isSectionVisible(1))
+ _gm->guardShot();
+ else if ((verb == ACTION_OPEN) && (obj1._id == DOOR) && !obj1.hasProperty(OPENED)) {
+ _gm->_rooms[CORRIDOR9]->setSectionVisible(27, true);
+ _gm->_rooms[CORRIDOR9]->setSectionVisible(28, false);
+ _gm->_rooms[CORRIDOR9]->getObject(1)->setProperty(OPENED);
+ return false;
+ } else if ((verb == ACTION_CLOSE) && (obj1._id == DOOR) && obj1.hasProperty(OPENED)) {
+ _gm->_rooms[CORRIDOR9]->setSectionVisible(27, false);
+ _gm->_rooms[CORRIDOR9]->setSectionVisible(28, true);
+ _gm->_rooms[CORRIDOR9]->getObject(1)->disableProperty(OPENED);
+ return false;
+ } else if ((verb == ACTION_TALK) && (obj1._id == GUARDIAN)) {
+ _gm->dialog(3, rowsX, _dialogsX, 0);
+ _gm->guardShot();
+ } else if ((verb == ACTION_TAKE) && (obj1._id == MASTERKEYCARD)) {
+ _gm->great(0);
+ setSectionVisible(7, false);
+ return false;
+ } else if ((verb == ACTION_USE) && (Object::combine(obj1, obj2, MAGNET, GUARDIAN) || Object::combine(obj1, obj2, KNIFE, GUARDIAN)))
+ _vm->renderMessage(kStringArsanoEntrance27);
+ else
+ return false;
+
+ return true;
+}
+
+bool AxacussExit::interact(Action verb, Object &obj1, Object &obj2) {
+ byte rowsX[6] = {1, 1, 1, 0, 0, 0};
+
+ if (((verb == ACTION_WALK) || (verb == ACTION_OPEN)) && (obj1._id == DOOR) && !_gm->_state._powerOff)
+ _gm->guard3Shot();
+ else if ((verb == ACTION_TALK) && (obj1._id == GUARDIAN)) {
+ _gm->dialog(3, rowsX, _dialogsX,0);
+ _gm->guard3Shot();
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, LAMP, MAGNET)) {
+ _gm->_inventory.remove(*_gm->_rooms[CELL]->getObject(7));
+ for (int i = 4; i <= 11; i++) {
+ _vm->renderImage(i);
+ if (i == 11)
+ _vm->playSound(kAudioSmash); // 046/4020
+ _gm->wait2(1);
+ _vm->renderImage(i + 128);
+ }
+ _gm->_state._powerOff = true;
+ _objectState[5]._click = 255;
+
+ _gm->search(450);
+ _gm->roomBrightness();
+ } else if ((verb == ACTION_USE) && (Object::combine(obj1,obj2,MAGNET,GUARDIAN) || Object::combine(obj1,obj2,KNIFE,GUARDIAN)))
+ _vm->renderMessage(kStringArsanoEntrance27);
+ else
+ return false;
+
+ return true;
+}
+
+bool AxacussOffice1::interact(Action verb, Object &obj1, Object &obj2) {
+ Common::String input;
+ if ((verb == ACTION_CLOSE) && (obj1._id == DOOR) &&
+ obj1.hasProperty(OPENED)) {
+ _vm->renderImage(_gm->invertSection(9));
+ obj1.disableProperty(OPENED);
+ obj1.setProperty(CLOSED);
+ _vm->playSound(kAudioDoorClose);
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, MASTERKEYCARD, DOOR) &&
+ !getObject(0)->hasProperty(OPENED)) {
+ _vm->renderImage(9);
+ getObject(0)->disableProperty(CLOSED);
+ getObject(0)->setProperty(OPENED);
+ _vm->playSound(kAudioDoorOpen);
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, COMPUTER, MAGNET)) {
+ _vm->renderImage(4);
+ setSectionVisible(16, false);
+ _vm->playSound(kAudioSmash);
+ } else if ((verb == ACTION_LOOK) && (obj1._id == COMPUTER)) {
+ if (isSectionVisible(4))
+ _vm->renderMessage(kStringBroken);
+ else
+ _gm->telomat(0);
+ } else if (((verb == ACTION_OPEN) || (verb == ACTION_USE)) &&
+ (obj1._id == LOCKER) &&
+ !obj1.hasProperty(OPENED)) {
+ _vm->renderMessage(kStringAxacussOffice1_1);
+ _vm->renderBox(160, 70, 70, 10, kColorDarkBlue);
+ _gm->edit(input, 161, 71, 10);
+
+ _vm->removeMessage();
+ if (_gm->_key.keycode != Common::KEYCODE_ESCAPE) {
+ if (!input.equals("89814")) {
+ if (input.equals("41898"))
+ _vm->renderMessage(kStringAxacussOffice1_2);
+ else
+ _vm->renderMessage(kStringAxacussOffice1_3);
+ } else {
+ _vm->renderImage(6);
+ setSectionVisible(7, false);
+ obj1.resetProperty(OPENABLE | OPENED);
+ if (getObject(2)->hasProperty(TAKE)) {
+ _vm->renderImage(8);
+ getObject(2)->_click = 9;
+ }
+ _vm->playSound(kAudioDoorOpen);
+ _gm->great(7);
+ }
+ }
+ } else if ((verb == ACTION_CLOSE) && (obj1._id == LOCKER) && obj1.hasProperty(OPENED)) {
+ _vm->renderImage(7);
+ setSectionVisible(6, false);
+ obj1.resetProperty(OPENABLE | CLOSED);
+ setSectionVisible(8, false);
+ getObject(2)->_click = 255;
+ _vm->playSound(kAudioDoorClose);
+ } else if ((verb == ACTION_TAKE) && (obj1._id == MONEY)) {
+ _vm->renderImage(6);
+ setSectionVisible(8, false);
+ getObject(2)->_click = 255;
+ getObject(2)->resetProperty();
+ _gm->takeMoney(500);
+ } else if ((verb == ACTION_LOOK) && (obj1._id == LETTER)) {
+ g_system->fillScreen(kColorBlack);
+ _vm->renderText(kStringAxacussOffice1_4, 10, 10, 4);
+ _vm->renderText(kStringAxacussOffice1_5, 270, 10, 4);
+ _vm->renderText(kStringAxacussOffice1_6, 10, 60, 4);
+ _vm->renderText(kStringAxacussOffice1_7, 10, 75, 4);
+ _vm->renderText(kStringAxacussOffice1_8, 10, 86, 4);
+ _vm->renderText(kStringAxacussOffice1_9, 10, 97, 4);
+ _vm->renderText(kStringAxacussOffice1_10, 10, 108, 4);
+ _vm->renderText(kStringAxacussOffice1_11, 10, 119, 4);
+ _vm->renderText(kStringAxacussOffice1_12, 10, 130, 4);
+ _vm->renderText(kStringAxacussOffice1_13, 10, 147, 4);
+ _vm->renderText(kStringAxacussOffice1_14, 200, 170, 4);
+ _vm->renderText(kStringAxacussOffice1_15, 200, 181, 4);
+ _gm->getInput();
+ g_system->fillScreen(kColorBlack);
+ _vm->renderMessage(kStringAxacussOffice1_16);
+ } else
+ return false;
+
+ return true;
+}
+
+bool AxacussOffice2::interact(Action verb, Object &obj1, Object &obj2) {
+ if ((verb == ACTION_CLOSE) && (obj1._id == DOOR) &&
+ obj1.hasProperty(OPENED)) {
+ _vm->renderImage(_gm->invertSection(9));
+ obj1.disableProperty(OPENED);
+ obj1.setProperty(CLOSED);
+ _vm->playSound(kAudioDoorClose);
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, MASTERKEYCARD, DOOR) && !getObject(0)->hasProperty(OPENED)) {
+ _vm->renderImage(9);
+ getObject(0)->disableProperty(CLOSED);
+ getObject(0)->setProperty(OPENED);
+ _vm->playSound(kAudioDoorOpen);
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, COMPUTER, MAGNET)) {
+ _vm->renderImage(4);
+ setSectionVisible(16, false);
+ _vm->playSound(kAudioSmash);
+ } else if ((verb == ACTION_LOOK) && (obj1._id == COMPUTER)) {
+ if (isSectionVisible(4))
+ _vm->renderMessage(kStringBroken);
+ else
+ _gm->telomat(1);
+ } else
+ return false;
+
+ return true;
+}
+
+bool AxacussOffice3::interact(Action verb, Object &obj1, Object &obj2) {
+ if ((verb == ACTION_CLOSE) && (obj1._id == DOOR) &&
+ obj1.hasProperty(OPENED)) {
+ _vm->renderImage(_gm->invertSection(3));
+ obj1.disableProperty(OPENED);
+ obj1.setProperty(CLOSED);
+ _vm->playSound(kAudioDoorClose);
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, MASTERKEYCARD, DOOR) &&
+ !getObject(0)->hasProperty(OPENED)) {
+ _vm->renderImage(3);
+ getObject(0)->disableProperty(CLOSED);
+ getObject(0)->setProperty(OPENED);
+ _vm->playSound(kAudioDoorOpen);
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, COMPUTER, MAGNET)) {
+ _vm->renderImage(4);
+ _vm->playSound(kAudioSmash);
+ } else if ((verb == ACTION_LOOK) && (obj1._id == COMPUTER)) {
+ if (isSectionVisible(4))
+ _vm->renderMessage(kStringBroken);
+ else
+ _gm->telomat(2);
+ } else if ((verb == ACTION_LOOK) && (obj1._id == PAINTING)) {
+ _vm->renderMessage(kStringAxacussOffice3_1);
+ _gm->takeMoney(300);
+ obj1._id = NULLOBJECT;
+ } else
+ return false;
+
+ return true;
+}
+
+bool AxacussOffice4::interact(Action verb, Object &obj1, Object &obj2) {
+ if ((verb == ACTION_CLOSE) && (obj1._id == DOOR) && obj1.hasProperty(OPENED)) {
+ _vm->renderImage(_gm->invertSection(3));
+ obj1.disableProperty(OPENED);
+ obj1.setProperty(CLOSED);
+ _vm->playSound(kAudioDoorClose);
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, MASTERKEYCARD, DOOR) &&
+ !getObject(0)->hasProperty(OPENED)) {
+ _vm->renderImage(3);
+ getObject(0)->disableProperty(CLOSED);
+ getObject(0)->setProperty(OPENED);
+ _vm->playSound(kAudioDoorOpen);
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, COMPUTER, MAGNET)) {
+ _vm->renderImage(4);
+ _vm->playSound(kAudioSmash);
+ } else if ((verb == ACTION_LOOK) && (obj1._id == COMPUTER)) {
+ if (isSectionVisible(4))
+ _vm->renderMessage(kStringBroken);
+ else
+ _gm->telomat(3);
+ } else
+ return false;
+
+ return true;
+}
+
+void AxacussOffice5::onEntrance() {
+ _gm->great(5);
+}
+
+bool AxacussOffice5::interact(Action verb, Object &obj1, Object &obj2) {
+ if ((verb == ACTION_USE) && Object::combine(obj1, obj2, COMPUTER, MAGNET)) {
+ _vm->renderImage(4);
+ _vm->playSound(kAudioSmash);
+ } else if ((verb == ACTION_TAKE) && (obj1._id == MONEY)) {
+ _vm->renderImage(_gm->invertSection(5));
+ obj1._click = 255;
+ _gm->takeMoney(350);
+ } else
+ return false;
+
+ return true;
+}
+
+bool AxacussElevator::interact(Action verb, Object &obj1, Object &obj2) {
+ if ((verb == ACTION_WALK) && (obj1._id == DOOR)) {
+ g_system->fillScreen(kColorBlack);
+ _vm->setCurrentImage(41);
+ _vm->renderImage(0);
+ _vm->paletteBrightness();
+ _gm->reply(kStringAxacussElevator_1, 1, 1 + 128);
+ _gm->say(kStringAxacussElevator_2);
+ g_system->fillScreen(kColorBlack);
+ } else if ((verb == ACTION_PRESS) && (obj1._id == BUTTON1)) {
+ if (!isSectionVisible(3)) {
+ _vm->renderImage(1);
+ getObject(2)->resetProperty();
+ _vm->playSound(kAudioSlideDoor);
+ _gm->wait2(25);
+ for (int i = 3; i <= 7; i++) {
+ _gm->wait2(2);
+ _vm->renderImage(i);
+ }
+ getObject(3)->resetProperty(EXIT);
+ getObject(3)->_click = 2;
+ _vm->renderImage(_gm->invertSection(1));
+ if (!(_gm->_state._greatFlag & 0x4000)) {
+ _vm->playSound(kAudioFoundLocation);
+ _gm->_state._greatFlag |= 0x4000;
+ }
+ }
+ } else if ((verb == ACTION_PRESS) && (obj1._id == BUTTON2)) {
+ if (isSectionVisible(3)) {
+ _vm->renderImage(2);
+ getObject(3)->resetProperty();
+ getObject(3)->_click = 255;
+ _vm->playSound(kAudioSlideDoor);
+ for (int i = 7; i >= 3; i--) {
+ _gm->wait2(2);
+ _vm->renderImage(_gm->invertSection(i));
+ }
+ _gm->wait2(25);
+ _vm->playSound(kAudioSlideDoor);
+ getObject(2)->resetProperty(EXIT);
+ _vm->renderImage(_gm->invertSection(2));
+ }
+ } else if ((verb == ACTION_WALK) && (obj1._id == JUNGLE)) {
+ _vm->paletteFadeOut();
+ g_system->fillScreen(kColorBlack);
+ _vm->_menuBrightness = 255;
+ _vm->paletteBrightness();
+ _vm->renderMessage(kStringAxacussElevator_3);
+ _gm->waitOnInput(_gm->_timer1);
+ _vm->removeMessage();
+ _vm->_menuBrightness = 0;
+ _vm->paletteBrightness();
+ _gm->_state._time += ticksToMsec(125000); // 2 hours
+ _gm->_state._alarmOn = (_gm->_state._timeAlarm > _gm->_state._time);
+ return false;
+ } else
+ return false;
+
+ return true;
+}
+
+bool AxacussStation::interact(Action verb, Object &obj1, Object &obj2) {
+ if ((verb == ACTION_LOOK) && (obj1._id == STATION_SIGN)) {
+ _gm->changeRoom(SIGN);
+ } else if ((verb == ACTION_WALK) && (obj1._id == DOOR) && obj1.hasProperty(OPENED)) {
+ _gm->great(0);
+ _vm->paletteFadeOut();
+ _vm->setCurrentImage(35);
+ _vm->renderImage(0);
+ _vm->renderImage(1);
+ _vm->paletteFadeIn();
+ _gm->wait2(10);
+ for (int i = 8; i <= 21; i++) {
+ _vm->renderImage(i);
+ _gm->wait2(2);
+ _vm->renderImage(_gm->invertSection(i));
+ }
+ _gm->wait2(18);
+ _vm->renderImage(_gm->invertSection(1));
+ for (int i = 2; i <= 7; i++) {
+ _vm->renderImage(i);
+ _gm->wait2(3);
+ _vm->renderImage(_gm->invertSection(i));
+ }
+ _gm->outro();
+ } else
+ return false;
+
+ return true;
+}
+
+bool AxacussSign::interact(Action verb, Object &obj1, Object &obj2) {
+ if ((verb == ACTION_USE) && Object::combine(obj1, obj2, STATION_SLOT, MONEY) &&
+ isSectionVisible(1)) {
+ _gm->takeMoney(-180);
+ _vm->renderImage(2);
+ setSectionVisible(1, false);
+ _gm->_state._eventTime = _gm->_state._time + ticksToMsec(600);
+ _gm->_state._eventCallback = kTaxiFn;
+ return true;
+ }
+ return false;
+}
+
+Outro::Outro(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = -1;
+ _id = OUTRO;
+ _shown[0] = kShownFalse;
+
+ outroText =
+ _vm->getGameString(kStringOutro1) +
+ _vm->getGameString(kStringOutro2) +
+ _vm->getGameString(kStringOutro3) +
+ _vm->getGameString(kStringOutro4) +
+ _vm->getGameString(kStringOutro5) +
+ _vm->getGameString(kStringOutro6) +
+ _vm->getGameString(kStringOutro7) +
+ _vm->getGameString(kStringOutro8) +
+ _vm->getGameString(kStringOutro9) +
+ _vm->getGameString(kStringOutro10) +
+ _vm->getGameString(kStringOutro11) +
+ _vm->getGameString(kStringOutro12) +
+ _vm->getGameString(kStringOutro13) +
+ _vm->getGameString(kStringOutro14);
+}
+
+void Outro::onEntrance() {
+}
+
+void Outro::animation() {
+}
+
+void Outro::animate(int filenumber, int section1, int section2, int duration) {
+ _vm->setCurrentImage(filenumber);
+ while (duration) {
+ _vm->renderImage(section1);
+ _gm->wait2(2);
+ _vm->renderImage(section2);
+ _gm->wait2(2);
+ --duration;
+ }
+}
+
+void Outro::animate(int filenumber, int section1, int section2, int duration,
+ MessagePosition position, const char *text) {
+ _vm->renderMessage(text, position);
+ int delay = (Common::strnlen(text, 512) + 20) * (10 - duration) * _vm->_textSpeed / 400;
+ _vm->setCurrentImage(filenumber);
+ while (delay) {
+ if (section1)
+ _vm->renderImage(section1);
+ _gm->wait2(2);
+ if (section2)
+ _vm->renderImage(section2);
+ _gm->wait2(2);
+ --delay;
+ }
+ _vm->removeMessage();
+}
+
+void Outro::animate(int filenumber, int section1, int section2, int section3, int section4,
+ int duration, MessagePosition position, const char *text) {
+ _vm->renderMessage(text, position);
+ if (duration == 0)
+ duration = (Common::strnlen(text, 512) + 20) * _vm->_textSpeed / 40;
+
+ _vm->setCurrentImage(filenumber);
+ while(duration) {
+ _vm->renderImage(section1);
+ _vm->renderImage(section3);
+ _gm->wait2(2);
+ _vm->renderImage(section2);
+ _vm->renderImage(section4);
+ _gm->wait2(2);
+ duration--;
+ }
+ _vm->removeMessage();
+}
+
+}
diff --git a/engines/supernova/rooms.h b/engines/supernova/rooms.h
new file mode 100644
index 0000000000..a16f57ee52
--- /dev/null
+++ b/engines/supernova/rooms.h
@@ -0,0 +1,1388 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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.
+ *
+ */
+
+#ifndef SUPERNOVA_ROOMS_H
+#define SUPERNOVA_ROOMS_H
+
+#include "common/scummsys.h"
+
+#include "msn_def.h"
+
+namespace Supernova {
+
+class GameManager;
+class SupernovaEngine;
+
+class Room {
+public:
+ Room() {
+ _seen = false;
+ for (int i = 0; i < kMaxSection; ++i)
+ _shown[i] = kShownFalse;
+ for (int i = 0; i < kMaxDialog; ++i)
+ _sentenceRemoved[i] = 0;
+ }
+
+ bool hasSeen() {
+ return _seen;
+ }
+ void setRoomSeen(bool seen) {
+ _seen = seen;
+ }
+
+ int getFileNumber() const {
+ return _fileNumber;
+ }
+ RoomID getId() const {
+ return _id;
+ }
+
+ void setSectionVisible(uint section, bool visible) {
+ _shown[section] = visible ? kShownTrue : kShownFalse;
+ }
+
+ bool isSectionVisible(uint index) const {
+ return _shown[index] == kShownTrue;
+ }
+
+ void removeSentence(int sentence, int number) {
+ if (number > 0)
+ _sentenceRemoved[number - 1] |= (1 << sentence);
+ }
+
+ void addSentence(int sentence, int number) {
+ if (number > 0)
+ _sentenceRemoved[number - 1] &= ~(1 << sentence);
+ }
+
+ void addAllSentences(int number) {
+ if (number > 0)
+ _sentenceRemoved[number - 1] = 0;
+ }
+
+ bool sentenceRemoved(int sentence, int number) {
+ if (number <= 0)
+ return false;
+ return (_sentenceRemoved[number - 1] & (1 << sentence));
+ }
+
+ bool allSentencesRemoved(int maxSentence, int number) {
+ if (number <= 0)
+ return false;
+ for (int i = 0, flag = 1 ; i < maxSentence ; ++i, flag <<= 1)
+ if (!(_sentenceRemoved[number - 1] & flag))
+ return false;
+ return true;
+ }
+
+ Object *getObject(uint index) {
+ return &_objectState[index];
+ }
+
+ virtual ~Room() {}
+ virtual void animation() {}
+ virtual void onEntrance() {}
+ virtual bool interact(Action verb, Object &obj1, Object &obj2) {
+ return false;
+ }
+ virtual bool serialize(Common::WriteStream *out);
+ virtual bool deserialize(Common::ReadStream *in, int version);
+
+protected:
+ int _fileNumber;
+ bool _shown[kMaxSection];
+ byte _sentenceRemoved[kMaxDialog];
+ Object _objectState[kMaxObject];
+ RoomID _id;
+ SupernovaEngine *_vm;
+ GameManager *_gm;
+
+private:
+ bool _seen;
+};
+
+// Room 0
+class Intro : public Room {
+public:
+ Intro(SupernovaEngine *vm, GameManager *gm);
+ virtual void onEntrance();
+
+private:
+ bool animate(int section1, int section2, int duration);
+ bool animate(int section1, int section2, int duration, MessagePosition position,
+ StringID text);
+ bool animate(int section1, int section2, int section3, int section4, int duration,
+ MessagePosition position, StringID text);
+
+ void titleScreen();
+ void titleFadeIn();
+ void cutscene();
+ void leaveCutscene();
+
+ bool _shouldExit;
+ Common::String introText;
+};
+
+// Spaceship
+class ShipCorridor : public Room {
+public:
+ ShipCorridor(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 17;
+ _id = CORRIDOR;
+ _shown[0] = kShownTrue;
+ _shown[4] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringHatch, kStringDefaultDescription, HATCH1, OPENABLE | EXIT, 0, 6, 1, CABIN_L1, 15);
+ _objectState[1] = Object(_id, kStringHatch, kStringDefaultDescription, NULLOBJECT, OPENABLE | EXIT, 1, 7, 2, CABIN_L2, 10);
+ _objectState[2] = Object(_id, kStringHatch, kStringDefaultDescription, NULLOBJECT, OPENABLE | EXIT, 2, 8, 3, CABIN_L3, 5);
+ _objectState[3] = Object(_id, kStringHatch, kStringDefaultDescription, NULLOBJECT, OPENABLE | EXIT, 5, 11, 6, CABIN_R1, 19);
+ _objectState[4] = Object(_id, kStringHatch, kStringDefaultDescription, NULLOBJECT, OPENABLE | EXIT, 4, 10, 5, CABIN_R2, 14);
+ _objectState[5] = Object(_id, kStringHatch, kStringDefaultDescription, NULLOBJECT, OPENABLE | EXIT | OPENED, 9, 3, 4, CABIN_R3, 9);
+ _objectState[6] = Object(_id, kStringHatch, kStringDefaultDescription, NULLOBJECT, OPENABLE | CLOSED | EXIT, 12, 12, 0, AIRLOCK, 2);
+ _objectState[7] = Object(_id, kStringButton, kStringHatchButtonDescription, BUTTON, PRESS, 13, 13, 0, NULLROOM, 0);
+ _objectState[8] = Object(_id, kStringLadder, kStringDefaultDescription, NULLOBJECT, NULLTYPE, 14, 14, 0, NULLROOM, 0);
+ _objectState[9] = Object(_id, kStringExit, kStringDefaultDescription, NULLOBJECT, EXIT, 15, 15, 0, HALL, 22);
+ }
+
+ virtual bool interact(Action verb, Object &obj1, Object &obj2);
+};
+
+class ShipHall: public Room {
+public:
+ ShipHall(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 15;
+ _id = HALL;
+ _shown[0] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringHatch, kStringCockpitHatchDescription, NULLOBJECT, OPENABLE | EXIT, 4, 5, 1, COCKPIT, 10);
+ _objectState[1] = Object(_id, kStringHatch, kStringKitchenHatchDescription, KITCHEN_HATCH, OPENABLE | EXIT, 0, 0, 0, NULLROOM, 1);
+ _objectState[2] = Object(_id, kStringHatch, kStringStasisHatchDescription, NULLOBJECT, OPENABLE | CLOSED | EXIT, 1, 1, 2, SLEEP, 8);
+ _objectState[3] = Object(_id, kStringSlot, kStringSlotDescription, SLEEP_SLOT, COMBINABLE, 2, 2, 0, NULLROOM, 0);
+ _objectState[4] = Object(_id, kStringLadder, kStringDefaultDescription, NULLOBJECT, NULLTYPE, 3, SLEEP, 0, NULLROOM, 0);
+ _objectState[5] = Object(_id, kStringCorridor, kStringDefaultDescription, NULLOBJECT, EXIT, 6, 6, 0, CORRIDOR, 19);
+ }
+
+ virtual bool interact(Action verb, Object &obj1, Object &obj2);
+};
+
+class ShipSleepCabin: public Room {
+public:
+ ShipSleepCabin(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 33;
+ _id = SLEEP;
+ _shown[0] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringHatch, kStringStasisHatchDescription2, CABINS, NULLTYPE, 0, 0, 0, NULLROOM, 0);
+ _objectState[1] = Object(_id, kStringHatch, kStringStasisHatchDescription2, CABIN, NULLTYPE, 1, 1, 0, NULLROOM, 0);
+ _objectState[2] = Object(_id, kStringComputer, kStringDefaultDescription, COMPUTER, NULLTYPE, 2, 2, 0, NULLROOM, 0);
+ _objectState[3] = Object(_id, kStringExit, kStringDefaultDescription, NULLOBJECT, EXIT, 255, 255, 0, HALL, 22);
+ }
+
+ virtual bool interact(Action verb, Object &obj1, Object &obj2);
+ virtual void animation();
+ virtual void onEntrance();
+
+private:
+ byte _color;
+};
+
+class ShipCockpit : public Room {
+public:
+ ShipCockpit(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 9;
+ _id = COCKPIT;
+ _shown[0] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringInstruments, kStringInstrumentsDescription1, INSTRUMENTS, NULLTYPE, 2, 2, 0, NULLROOM, 0);
+ _objectState[1] = Object(_id, kStringMonitor, kStringDefaultDescription, MONITOR, NULLTYPE, 0, 0, 0, NULLROOM, 0);
+ _objectState[2] = Object(_id, kStringMonitor, kStringMonitorDescription, NULLOBJECT, TAKE, 1, 0, 0, NULLROOM, 0);
+ _objectState[3] = Object(_id, kStringExit, kStringDefaultDescription, NULLOBJECT, EXIT, 255, 255, 0, HALL, 22);
+ }
+
+ virtual bool interact(Action verb, Object &obj1, Object &obj2);
+ virtual void animation();
+ virtual void onEntrance();
+
+private:
+ byte _color;
+};
+
+class ShipCabinL1: public Room {
+public:
+ ShipCabinL1(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 21;
+ _id = CABIN_L1;
+ _shown[0] = kShownTrue;
+ _shown[1] = kShownTrue;
+ _shown[2] = kShownTrue;
+ _shown[3] = kShownTrue;
+ _shown[4] = kShownTrue;
+ _shown[5] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringImage, kStringGenericDescription1, NULLOBJECT, UNNECESSARY, 5, 5, 0, NULLROOM, 0);
+ _objectState[1] = Object(_id, kStringImage, kStringGenericDescription2, NULLOBJECT, UNNECESSARY, 6, 6, 0, NULLROOM, 0);
+ _objectState[2] = Object(_id, kStringImage, kStringGenericDescription3, NULLOBJECT, UNNECESSARY, 7, 7, 0, NULLROOM, 0);
+ _objectState[3] = Object(_id, kStringMagnete, kStringMagneteDescription, NULLOBJECT, UNNECESSARY, 8, 8, 0, NULLROOM, 0);
+ _objectState[4] = Object(_id, kStringImage, kStringGenericDescription4, NULLOBJECT, UNNECESSARY, 9, 9, 0);
+ _objectState[5] = Object(_id, kStringPen, kStringPenDescription, PEN, TAKE | COMBINABLE, 10, 10, 5 | 128);
+ _objectState[6] = Object(_id, kStringHatch, kStringDefaultDescription, NULLOBJECT, OPENABLE | OPENED | EXIT, 3, 3, 24 | 128, CORRIDOR, 9);
+ _objectState[7] = Object(_id, kStringSlot, kStringSlotDescription, NULLOBJECT, COMBINABLE, 0, 0, 0);
+ _objectState[8] = Object(_id, kStringShelf, kStringDefaultDescription, NULLOBJECT, OPENABLE | CLOSED, 1, 1, 0);
+ _objectState[9] = Object(_id, kStringCompartment, kStringDefaultDescription, NULLOBJECT, OPENABLE | CLOSED, 2, 2, 0);
+ _objectState[10] = Object(_id, kStringSocket, kStringDefaultDescription, SOCKET, COMBINABLE, 4, 4, 0);
+ _objectState[11] = Object(_id, kStringToilet, kStringDefaultDescription, BATHROOM_DOOR, EXIT, 255, 255, 0, BATHROOM, 22);
+ }
+};
+
+class ShipCabinL2 : public Room {
+public:
+ ShipCabinL2(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 21;
+ _id = CABIN_L2;
+ _shown[0] = kShownTrue;
+ _shown[16] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringSlot,kStringSlotDescription,SLOT_KL1,COMBINABLE,31,31,0);
+ _objectState[1] = Object(_id, kStringSlot,kStringSlotDescription,SLOT_KL2,COMBINABLE,32,32,0);
+ _objectState[2] = Object(_id, kStringSlot,kStringSlotDescription,SLOT_KL3,COMBINABLE,33,33,0);
+ _objectState[3] = Object(_id, kStringSlot,kStringSlotDescription,SLOT_KL4,COMBINABLE,45,45,0);
+ _objectState[4] = Object(_id, kStringShelf,kStringDefaultDescription,SHELF_L1,OPENABLE | CLOSED,25,26,17);
+ _objectState[5] = Object(_id, kStringPistol,kStringPistolDescription,PISTOL,TAKE,39,39,20);
+ _objectState[6] = Object(_id, kStringCompartment,kStringDefaultDescription,SHELF_L2,OPENABLE | CLOSED,27,28,18);
+ _objectState[7] = Object(_id, kStringBooks,kStringBooksDescription,NULLOBJECT,UNNECESSARY,40,40,0);
+ _objectState[8] = Object(_id, kStringCompartment,kStringDefaultDescription,SHELF_L3,OPENABLE | CLOSED,29,30,19);
+ _objectState[9] = Object(_id, kStringSpool,kStringSpoolDescription, SPOOL,TAKE | COMBINABLE,41,41,21);
+ _objectState[10] = Object(_id, kStringCompartment,kStringDefaultDescription,SHELF_L4,OPENABLE | CLOSED,43,44,22);
+ _objectState[11] = Object(_id, kStringBook,kStringDefaultDescription,BOOK2,TAKE,46,46,23);
+ _objectState[12] = Object(_id, kStringUnderwear,kStringUnderwearDescription,NULLOBJECT,UNNECESSARY,34,34,0);
+ _objectState[13] = Object(_id, kStringUnderwear,kStringUnderwearDescription,NULLOBJECT,UNNECESSARY,35,35,0);
+ _objectState[14] = Object(_id, kStringClothes,kStringDefaultDescription,NULLOBJECT,UNNECESSARY,36,36,0);
+ _objectState[15] = Object(_id, kStringJunk,kStringJunkDescription,NULLOBJECT,UNNECESSARY,37,37,0);
+ _objectState[16] = Object(_id, kStringJunk,kStringJunkDescription,NULLOBJECT,UNNECESSARY,38,38,0);
+ _objectState[17] = Object(_id, kStringMagnete,kStringMagneteDescription,NULLOBJECT,UNNECESSARY,23,23,0);
+ _objectState[18] = Object(_id, kStringToilet,kStringDefaultDescription,BATHROOM_DOOR,EXIT,255,255,0,BATHROOM,22);
+ _objectState[19] = Object(_id, kStringHatch,kStringDefaultDescription,NULLOBJECT,OPENABLE | OPENED | EXIT,3,3,24 | 128,CORRIDOR,9);
+ _objectState[20] = Object(_id, kStringSlot,kStringSlotDescription,NULLOBJECT,COMBINABLE,0,0,0);
+ _objectState[21] = Object(_id, kStringShelf,kStringDefaultDescription,NULLOBJECT,OPENABLE | CLOSED,1,1,0);
+ _objectState[22] = Object(_id, kStringCompartment,kStringDefaultDescription,NULLOBJECT,OPENABLE | CLOSED,2,2,0);
+ _objectState[23] = Object(_id, kStringSocket,kStringDefaultDescription,SOCKET,COMBINABLE,4,4,0);
+ _objectState[24] = Object(_id, kStringFolders,kStringFoldersDescription,NULLOBJECT,UNNECESSARY,49,49,0);
+ }
+
+ virtual bool interact(Action verb, Object &obj1, Object &obj2);
+};
+
+class ShipCabinL3 : public Room {
+public:
+ ShipCabinL3(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 21;
+ _id = CABIN_L3;
+ _shown[0] = kShownTrue;
+ _shown[6] = kShownTrue;
+ _shown[7] = kShownTrue;
+ _shown[8] = kShownTrue;
+ _shown[9] = kShownTrue;
+ _shown[12] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringPoster,kStringPosterDescription1,NULLOBJECT,UNNECESSARY,11,11,0);
+ _objectState[1] = Object(_id, kStringPoster,kStringPosterDescription2,NULLOBJECT,UNNECESSARY,12,12,0);
+ _objectState[2] = Object(_id, kStringSpeaker,kStringDefaultDescription,NULLOBJECT,NULLTYPE,13,13,0);
+ _objectState[3] = Object(_id, kStringMagnete,kStringMagneteDescription,NULLOBJECT,UNNECESSARY,14,14,0);
+ _objectState[4] = Object(_id, kStringRecord,kStringRecordDescription,RECORD,TAKE | COMBINABLE,15,15,8 | 128);
+ _objectState[5] = Object(_id, kStringRecordStand,kStringRecordStandDescription,NULLOBJECT,UNNECESSARY,16,16,0);
+ _objectState[6] = Object(_id, kStringButton,kStringDefaultDescription,TURNTABLE_BUTTON,PRESS,22,22,0);
+ _objectState[7] = Object(_id, kStringTurntable,kStringTurntableDescription,TURNTABLE,UNNECESSARY | COMBINABLE,17,17,0);
+ _objectState[8] = Object(_id, kStringWire,kStringDefaultDescription,WIRE,COMBINABLE,18,18,0);
+ _objectState[9] = Object(_id, kStringWire,kStringDefaultDescription,WIRE2,COMBINABLE,19,19,0);
+ _objectState[10] = Object(_id, kStringPlug,kStringDefaultDescription,PLUG,COMBINABLE,20,20,0);
+ _objectState[11] = Object(_id, kStringHatch,kStringDefaultDescription,NULLOBJECT,OPENABLE | OPENED | EXIT,3,3,24 | 128,CORRIDOR,9);
+ _objectState[12] = Object(_id, kStringSlot,kStringSlotDescription,NULLOBJECT,COMBINABLE,0,0,0);
+ _objectState[13] = Object(_id, kStringShelf,kStringDefaultDescription,NULLOBJECT,OPENABLE | CLOSED,1,1,0);
+ _objectState[14] = Object(_id, kStringCompartment,kStringDefaultDescription,NULLOBJECT,OPENABLE | CLOSED,2,2,0);
+ _objectState[15] = Object(_id, kStringSocket,kStringDefaultDescription,SOCKET,COMBINABLE,4,4,0);
+ _objectState[16] = Object(_id, kStringToilet,kStringDefaultDescription,BATHROOM_DOOR,EXIT,255,255,0,BATHROOM,22);
+ }
+
+ virtual bool interact(Action verb, Object &obj1, Object &obj2);
+};
+
+class ShipCabinR1 : public Room {
+public:
+ ShipCabinR1(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 22;
+ _id = CABIN_R1;
+ _shown[0] = kShownTrue;
+ _shown[1] = kShownTrue;
+ _shown[2] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringImage,kStringImageDescription1,NULLOBJECT,UNNECESSARY,5,5,0);
+ _objectState[1] = Object(_id, kStringDrawingInstruments,kStringDrawingInstrumentsDescription,NULLOBJECT,UNNECESSARY,6,6,0);
+ _objectState[2] = Object(_id, kStringMagnete,kStringMagneteDescription,NULLOBJECT,UNNECESSARY,7,7,0);
+ _objectState[3] = Object(_id, kStringHatch,kStringDefaultDescription,NULLOBJECT,OPENABLE | OPENED | EXIT,3,3,15 | 128,CORRIDOR,5);
+ _objectState[4] = Object(_id, kStringSlot,kStringSlotDescription,NULLOBJECT,COMBINABLE,0,0,0);
+ _objectState[5] = Object(_id, kStringShelf,kStringDefaultDescription,NULLOBJECT,OPENABLE | CLOSED,1,1,0);
+ _objectState[6] = Object(_id, kStringCompartment,kStringDefaultDescription,NULLOBJECT,OPENABLE | CLOSED,2,2,0);
+ _objectState[7] = Object(_id, kStringSocket,kStringDefaultDescription,SOCKET,COMBINABLE,4,4,0);
+ _objectState[8] = Object(_id, kStringToilet,kStringDefaultDescription,BATHROOM_DOOR,EXIT,255,255,0,BATHROOM,22);
+ }
+};
+
+class ShipCabinR2 : public Room {
+public:
+ ShipCabinR2(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 22;
+ _id = CABIN_R2;
+ _shown[0] = kShownTrue;
+ _shown[3] = kShownTrue;
+ _shown[4] = kShownTrue;
+ _shown[5] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringChessGame,kStringChessGameDescription1,NULLOBJECT,UNNECESSARY,11,11,0);
+ _objectState[1] = Object(_id, kStringTennisRacket,kStringTennisRacketDescription,NULLOBJECT,UNNECESSARY,8,8,0);
+ _objectState[2] = Object(_id, kStringTennisBall,kStringGenericDescription2,NULLOBJECT,UNNECESSARY,9,9,0);
+ _objectState[3] = Object(_id, kStringHatch,kStringDefaultDescription,NULLOBJECT,OPENABLE | OPENED | EXIT,3,3,15 | 128,CORRIDOR,5);
+ _objectState[4] = Object(_id, kStringSlot,kStringSlotDescription,NULLOBJECT,COMBINABLE,0,0,0);
+ _objectState[5] = Object(_id, kStringShelf,kStringDefaultDescription,NULLOBJECT,OPENABLE | CLOSED,1,1,0);
+ _objectState[6] = Object(_id, kStringCompartment,kStringDefaultDescription,NULLOBJECT,OPENABLE | CLOSED,2,2,0);
+ _objectState[7] = Object(_id, kStringSocket,kStringDefaultDescription,SOCKET,COMBINABLE,4,4,0);
+ _objectState[8] = Object(_id, kStringToilet,kStringDefaultDescription,BATHROOM_DOOR,EXIT,255,255,0,BATHROOM,22);
+ }
+};
+
+class ShipCabinR3 : public Room {
+public:
+ ShipCabinR3(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 22;
+ _id = CABIN_R3;
+ _shown[0] = kShownTrue;
+ _shown[7] = kShownTrue;
+ _shown[8] = kShownTrue;
+ _shown[15] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringChessGame,kStringChessGameDescription2,CHESS,TAKE | COMBINABLE,12,12,7 | 128);
+ _objectState[1] = Object(_id, kStringBed,kStringBedDescription,NULLOBJECT,NULLTYPE,13,13,0);
+ _objectState[2] = Object(_id, kStringSlot,kStringSlotDescription,SLOT_K1,COMBINABLE,27,27,0);
+ _objectState[3] = Object(_id, kStringSlot,kStringSlotDescription,SLOT_K2,COMBINABLE,28,28,0);
+ _objectState[4] = Object(_id, kStringSlot,kStringSlotDescription,SLOT_K3,COMBINABLE,29,29,0);
+ _objectState[5] = Object(_id, kStringSlot,kStringSlotDescription,SLOT_K4,COMBINABLE,30,30,0);
+ _objectState[6] = Object(_id, kStringCompartment,kStringCompartmentDescription,SHELF1,OPENABLE | CLOSED,14,18,9);
+ _objectState[7] = Object(_id, kStringAlbums,kStringAlbumsDescription,NULLOBJECT,UNNECESSARY,14,14,0);
+ _objectState[8] = Object(_id, kStringCompartment,kStringCompartmentDescription,SHELF2,OPENABLE | CLOSED,15,19,10);
+ _objectState[9] = Object(_id, kStringRope,kStringRopeDescription,ROPE,TAKE | COMBINABLE,15,15,12);
+ _objectState[10] = Object(_id, kStringShelf,kStringShelfDescription,SHELF3,OPENABLE | CLOSED,16,17,11);
+ _objectState[11] = Object(_id, kStringJunk,kStringJunkDescription,NULLOBJECT,UNNECESSARY,20,20,0);
+ _objectState[12] = Object(_id, kStringClothes,kStringClothesDescription,NULLOBJECT,UNNECESSARY,21,21,0);
+ _objectState[13] = Object(_id, kStringUnderwear,kStringDefaultDescription,NULLOBJECT,UNNECESSARY,22,22,0);
+ _objectState[14] = Object(_id, kStringSocks,kStringDefaultDescription,NULLOBJECT,UNNECESSARY,23,23,0);
+ _objectState[15] = Object(_id, kStringCompartment,kStringCompartmentDescription,SHELF4,OPENABLE | CLOSED,24,25,13);
+ _objectState[16] = Object(_id, kStringBook,kStringBookHitchhiker,BOOK,TAKE,26,26,14);
+ _objectState[17] = Object(_id, kStringDiscman,kStringDiscmanDescription,DISCMAN,TAKE | COMBINABLE,33,33,16);
+ _objectState[18] = Object(_id, kStringHatch,kStringDefaultDescription,NULLOBJECT,OPENABLE | EXIT,3,3,15 | 128,CORRIDOR,5);
+ _objectState[19] = Object(_id, kStringSlot,kStringSlotDescription,NULLOBJECT,COMBINABLE,0,0,0);
+ _objectState[20] = Object(_id, kStringShelf,kStringDefaultDescription,NULLOBJECT,OPENABLE | CLOSED,1,1,0);
+ _objectState[21] = Object(_id, kStringCompartment,kStringDefaultDescription,NULLOBJECT,OPENABLE | CLOSED,2,2,0);
+ _objectState[22] = Object(_id, kStringSocket,kStringDefaultDescription,SOCKET,COMBINABLE,4,4,0);
+ _objectState[23] = Object(_id, kStringToilet,kStringDefaultDescription,BATHROOM_DOOR,EXIT,255,255,0,BATHROOM,22);
+ }
+
+ virtual bool interact(Action verb, Object &obj1, Object &obj2);
+ virtual void onEntrance();
+};
+
+class ShipCabinBathroom : public Room {
+public:
+ ShipCabinBathroom(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 23;
+ _id = BATHROOM;
+ _shown[0] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringBathroom,kStringBathroomDescription,TOILET,NULLTYPE,0,0,0);
+ _objectState[1] = Object(_id, kStringShower,kStringDefaultDescription,SHOWER,NULLTYPE,1,1,0);
+ _objectState[2] = Object(_id, kStringExit,kStringDefaultDescription,BATHROOM_EXIT,EXIT,255,255,0,CABIN_R3,2);
+ }
+};
+
+class ShipAirlock : public Room {
+public:
+ ShipAirlock(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 34;
+ _id = AIRLOCK;
+ _shown[0] = kShownTrue;
+ _shown[6] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringHatch,kStringHatchDescription1,NULLOBJECT,EXIT | OPENABLE | OPENED | CLOSED,0,0,0,CORRIDOR,10);
+ _objectState[1] = Object(_id, kStringHatch,kStringHatchDescription2,NULLOBJECT,EXIT | OPENABLE | CLOSED,1,1,0,HOLD,14);
+ _objectState[2] = Object(_id, kStringButton,kStringDefaultDescription,BUTTON1,PRESS,2,2,0);
+ _objectState[3] = Object(_id, kStringButton,kStringDefaultDescription,BUTTON2,PRESS,3,3,0);
+ _objectState[4] = Object(_id, kStringHelmet,kStringHelmetDescription,HELMET,TAKE,4,4,7);
+ _objectState[5] = Object(_id, kStringSuit,kStringSuitDescription,SUIT,TAKE,5,5,8);
+ _objectState[6] = Object(_id, kStringLifeSupport,kStringLifeSupportDescription,LIFESUPPORT,TAKE,6,6,9);
+ }
+
+ virtual bool interact(Action verb, Object &obj1, Object &obj2);
+ virtual void onEntrance();
+};
+
+class ShipHold : public Room {
+public:
+ ShipHold(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 24;
+ _id = HOLD;
+ _shown[0] = kShownTrue;
+
+ _objectState[0] = Object(_id, kNoString,kStringDefaultDescription,HOLD_WIRE,COMBINABLE,255,255,0);
+ _objectState[1] = Object(_id, kStringScrap,kStringScrapDescription1,SCRAP_LK,NULLTYPE,4,4,0);
+ _objectState[2] = Object(_id, kStringTerminalStrip,kStringDefaultDescription,TERMINALSTRIP,COMBINABLE,255,255,0);
+ _objectState[3] = Object(_id, kStringScrap,kStringScrapDescription2,NULLOBJECT,NULLTYPE,5,5,0);
+ _objectState[4] = Object(_id, kStringReactor,kStringReactorDescription,NULLOBJECT,NULLTYPE,6,6,0);
+ _objectState[5] = Object(_id, kStringNozzle,kStringDefaultDescription,NULLOBJECT,NULLTYPE,7,7,0);
+ _objectState[6] = Object(_id, kStringPumpkin,kStringPumpkinDescription,NULLOBJECT,NULLTYPE,8,8,0);
+ _objectState[7] = Object(_id, kStringHatch,kStringDefaultDescription,LANDINGMOD_OUTERHATCH,EXIT | OPENABLE,1,2,2,LANDINGMODULE,6);
+ _objectState[8] = Object(_id, kStringLandingModule,kStringLandingModuleDescription,NULLOBJECT,NULLTYPE,0,0,0);
+ _objectState[9] = Object(_id, kStringExit,kStringDefaultDescription,NULLOBJECT,EXIT,255,255,0,AIRLOCK,22);
+ _objectState[10] = Object(_id, kStringHatch,kStringHatchDescription3,OUTERHATCH_TOP,EXIT | OPENABLE | OPENED,3,3,0,GENERATOR,8);
+ _objectState[11] = Object(_id, kStringGenerator,kStringGeneratorDescription,GENERATOR_TOP,EXIT,12,12,0,GENERATOR,8);
+ }
+
+ virtual bool interact(Action verb, Object &obj1, Object &obj2);
+ virtual void onEntrance();
+};
+
+class ShipLandingModule : public Room {
+public:
+ ShipLandingModule(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 25;
+ _id = LANDINGMODULE;
+ _shown[0] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringSocket,kStringDefaultDescription,LANDINGMOD_SOCKET,COMBINABLE,1,1,0);
+ _objectState[1] = Object(_id, kStringButton,kSafetyButtonDescription,LANDINGMOD_BUTTON,PRESS | COMBINABLE,2,2,0);
+ _objectState[2] = Object(_id, kStringMonitor,kStringDefaultDescription,LANDINGMOD_MONITOR,NULLTYPE,3,3,0);
+ _objectState[3] = Object(_id, kStringKeyboard,kStringDefaultDescription,KEYBOARD,NULLTYPE,4,4,0);
+ _objectState[4] = Object(_id, kNoString,kStringDefaultDescription,LANDINGMOD_WIRE,COMBINABLE,255,255,0);
+ _objectState[5] = Object(_id, kStringHatch,kStringDefaultDescription,LANDINGMOD_HATCH,EXIT | OPENABLE | OPENED | COMBINABLE, 0,0,1 | 128,HOLD,10);
+ }
+
+ virtual bool interact(Action verb, Object &obj1, Object &obj2);
+};
+
+class ShipGenerator : public Room {
+public:
+ ShipGenerator(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 18;
+ _id = GENERATOR;
+ _shown[0] = kShownTrue;
+ _shown[5] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringGeneratorWire,kStringDefaultDescription,GENERATOR_WIRE,COMBINABLE,255,255,0);
+ _objectState[1] = Object(_id, kStringEmptySpool,kStringDefaultDescription,NULLOBJECT,UNNECESSARY,255,255,0);
+ _objectState[2] = Object(_id, kStringKeycard2,kStringKeycard2Description,KEYCARD2,COMBINABLE | TAKE,12,12,5 | 128);
+ _objectState[3] = Object(_id, kStringRope,kStringDefaultDescription,GENERATOR_ROPE,COMBINABLE,255,255,0);
+ _objectState[4] = Object(_id, kStringHatch,kStringHatchDescription3,OUTERHATCH,EXIT | OPENABLE,1,2,1,OUTSIDE,22);
+ _objectState[5] = Object(_id, kStringHatch,kStringDefaultDescription,NULLOBJECT,OPENABLE | CLOSED,3,3,0);
+ _objectState[6] = Object(_id, kStringSlot,kStringSlotDescription,NULLOBJECT,COMBINABLE,4,4,0);
+ _objectState[7] = Object(_id, kStringTrap,kStringDefaultDescription,TRAP,OPENABLE,5,6,2);
+ _objectState[8] = Object(_id, kStringWire,kStringDefaultDescription,NULLOBJECT,NULLTYPE,7,7,0);
+ _objectState[9] = Object(_id, kStringVoltmeter,kStringDefaultDescription,VOLTMETER,NULLTYPE,9,9,0,NULLROOM,0);
+ _objectState[10] = Object(_id, kStringClip,kStringDefaultDescription,CLIP,COMBINABLE,8,8,0);
+ _objectState[11] = Object(_id, kStringWire,kStringWireDescription,SHORT_WIRE,COMBINABLE,10,10,0);
+ _objectState[12] = Object(_id, kStringLadder,kStringDefaultDescription,LADDER,EXIT,0,0,0,HOLD,1);
+ }
+
+ virtual bool interact(Action verb, Object &obj1, Object &obj2);
+};
+
+class ShipOuterSpace : public Room {
+public:
+ ShipOuterSpace(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 4;
+ _id = OUTSIDE;
+ _shown[0] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringHatch,kStringDefaultDescription,NULLOBJECT,EXIT,0,0,0,GENERATOR,3);
+ _objectState[1] = Object(_id, kStringRope,kStringDefaultDescription,NULLOBJECT,UNNECESSARY,255,255,0);
+ }
+};
+
+// Arsano
+class ArsanoRocks : public Room {
+public:
+ ArsanoRocks(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 12;
+ _id = OUTSIDE;
+ _shown[0] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringRope,kStringDefaultDescription,NULLOBJECT,UNNECESSARY | EXIT,0,0,0,GENERATOR,12);
+ _objectState[1] = Object(_id, kStringStone,kStringDefaultDescription,STONE,NULLTYPE,1,1,0);
+ _objectState[2] = Object(_id, kStringStone,kStringDefaultDescription,NULLOBJECT,NULLTYPE,2,2,0);
+ _objectState[3] = Object(_id, kStringCaveOpening,kStringCaveOpeningDescription,NULLOBJECT,NULLTYPE,255,255,0,CAVE,1);
+ }
+
+ virtual void onEntrance();
+ virtual bool interact(Action verb, Object &obj1, Object &obj2);
+};
+class ArsanoCave : public Room {
+public:
+ ArsanoCave(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 12;
+ _id = CAVE;
+
+ _objectState[0] = Object(_id, kStringExit,kStringExitDescription,NULLOBJECT,EXIT,255,255,0,ROCKS,22);
+ _objectState[1] = Object(_id, kStringExit,kStringDefaultDescription,NULLOBJECT,EXIT,255,255,0,MEETUP,2);
+ }
+};
+class ArsanoMeetup : public Room {
+public:
+ ArsanoMeetup(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 37;
+ _id = MEETUP;
+ _shown[0] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringCave,kStringDefaultDescription,NULLOBJECT,EXIT,255,255,0,CAVE,22);
+ _objectState[1] = Object(_id, kStringSign,kStringSignDescription,MEETUP_SIGN,NULLTYPE,0,0,0);
+ _objectState[2] = Object(_id, kStringEntrance,kStringDefaultDescription,DOOR,EXIT,1,1,0,ENTRANCE,7);
+ _objectState[3] = Object(_id, kStringStar,kStringDefaultDescription,STAR,NULLTYPE,2,2,0);
+ _objectState[4] = Object(_id, kStringSpaceshift,kStringDefaultDescription,SPACESHIPS,COMBINABLE,3,3,0);
+ _objectState[5] = Object(_id, kStringSpaceshift,kStringDefaultDescription,SPACESHIP,COMBINABLE,4,4,0);
+ }
+
+ virtual void onEntrance();
+ virtual void animation();
+ virtual bool interact(Action verb, Object &obj1, Object &obj2);
+
+private:
+ byte _sign;
+ byte _beacon;
+};
+class ArsanoEntrance : public Room {
+public:
+ ArsanoEntrance(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 10;
+ _id = ENTRANCE;
+ _shown[0] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringPorter,kStringPorterDescription,PORTER,TALK,0,0,0);
+ _objectState[1] = Object(_id, kStringDoor,kStringDefaultDescription,NULLOBJECT,EXIT | OPENABLE | CLOSED,1,1,0,NULLROOM,5);
+ _objectState[2] = Object(_id, kStringSign,kStringSignDescription,KITCHEN_SIGN,NULLTYPE,2,2,0);
+ _objectState[3] = Object(_id, kStringChewingGum,kStringDefaultDescription,SCHNUCK,TAKE,255,255,10+128);
+ _objectState[4] = Object(_id, kStringGummyBears,kStringDefaultDescription,SCHNUCK,TAKE,255,255,11+128);
+ _objectState[5] = Object(_id, kStringChocolateBall,kStringDefaultDescription,SCHNUCK,TAKE,255,255,12+128);
+ _objectState[6] = Object(_id, kStringEgg,kStringDefaultDescription,EGG,TAKE,255,255,13+128);
+ _objectState[7] = Object(_id, kStringLiquorice,kStringDefaultDescription,SCHNUCK,TAKE,255,255,14+128);
+ _objectState[8] = Object(_id, kStringPill,kStringPillDescription,PILL,TAKE,255,255,0);
+ _objectState[9] = Object(_id, kStringSlot,kStringDefaultDescription,CAR_SLOT,COMBINABLE,6,6,0);
+ _objectState[10] = Object(_id, kStringVendingMachine,kStringVendingMachineDescription,NULLOBJECT,NULLTYPE,5,5,0);
+ _objectState[11] = Object(_id, kStringToilet,kStringToiletDescription,ARSANO_BATHROOM,NULLTYPE,255,255,0);
+ _objectState[12] = Object(_id, kStringButton,kStringDefaultDescription,BATHROOM_BUTTON,PRESS,3,3,0);
+ _objectState[13] = Object(_id, kStringSign,kStringSignDescription,BATHROOM_SIGN,NULLTYPE,4,4,0);
+ _objectState[14] = Object(_id, kStringStaircase,kStringDefaultDescription,STAIRCASE,EXIT,8,8,0,REST,3);
+ _objectState[15] = Object(_id, kStringExit,kStringDefaultDescription,MEETUP_EXIT,EXIT,255,255,0,MEETUP,22);
+ _objectState[16] = Object(_id, kStringCoins,kStringCoinsDescription,COINS,TAKE|COMBINABLE,255,255,0);
+ _objectState[17] = Object(_id, kStringTabletPackage,kStringTabletPackageDescription,PILL_HULL,TAKE,255,255,0);
+
+ _dialog1[0] = kStringArsanoDialog7;
+ _dialog1[1] = kStringArsanoDialog1;
+ _dialog1[2] = kStringArsanoDialog8;
+ _dialog1[3] = kStringArsanoDialog9;
+ _dialog1[4] = kStringDialogSeparator;
+
+ _dialog2[0] = kStringArsanoDialog1;
+ _dialog2[1] = kStringArsanoDialog2;
+ _dialog2[2] = kStringArsanoDialog3;
+ _dialog2[3] = kStringArsanoDialog4;
+ _dialog2[4] = kStringDialogSeparator;
+
+ _dialog3[0] = kStringArsanoDialog5;
+ _dialog3[1] = kStringArsanoDialog6;
+
+ _eyewitness = 5;
+ }
+
+ virtual bool interact(Action verb, Object &obj1, Object &obj2);
+ virtual void animation();
+
+private:
+ StringID _dialog1[5];
+ StringID _dialog2[5];
+ StringID _dialog3[5];
+ byte _eyewitness;
+};
+class ArsanoRemaining : public Room {
+public:
+ ArsanoRemaining(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 28;
+ _id = REST;
+ _shown[0] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringStaircase,kStringDefaultDescription,NULLOBJECT,EXIT,0,0,0,ENTRANCE,17);
+ _objectState[1] = Object(_id, kStringChair,kStringDefaultDescription,NULLOBJECT,EXIT,1,1,0,ROGER,2);
+ _objectState[2] = Object(_id, kStringShoes,kStringShoesDescription,NULLOBJECT,NULLTYPE,2,2,0);
+
+ _chewing = kShownTrue;
+ }
+
+ virtual void animation();
+
+private:
+ bool _chewing;
+ int _i;
+};
+class ArsanoRoger : public Room {
+public:
+ ArsanoRoger(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 29;
+ _id = ROGER;
+ _shown[0] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringExit,kStringDefaultDescription,NULLOBJECT,EXIT,255,255,0,REST,19);
+ _objectState[1] = Object(_id, kStringFrogFace,kStringDefaultDescription,ROGER_W,TALK,0,0,0);
+ _objectState[2] = Object(_id, kStringScrible,kStringScribleDescription,NULLOBJECT,NULLTYPE,3,3,0);
+ _objectState[3] = Object(_id, kStringWallet,kStringDefaultDescription,WALLET,TAKE,1,1,4);
+ _objectState[4] = Object(_id, kStringMenu,kStringMenuDescription,NULLOBJECT,UNNECESSARY,2,2,0);
+ _objectState[5] = Object(_id, kStringCup,kStringCupDescription,CUP,UNNECESSARY,4,4,0);
+ _objectState[6] = Object(_id, kStringChessGame,kStringDefaultDescription,NULLOBJECT,UNNECESSARY,255,255,0);
+ _objectState[7] = Object(_id, kStringBill,kStringBillDescription,NULLOBJECT,TAKE|COMBINABLE,255,255,0);
+ _objectState[8] = Object(_id, kStringKeycard3,kStringDefaultDescription,KEYCARD_R,TAKE|COMBINABLE,255,255,0);
+
+ _dialog1[0] = kStringDialogArsanoRoger1;
+ _dialog1[1] = kStringDialogArsanoRoger2;
+ _dialog1[2] = kStringDialogArsanoRoger3;
+ _dialog1[3] = kStringDialogSeparator;
+
+ _eyewitness = 5;
+ }
+
+ virtual void animation();
+ virtual void onEntrance();
+ virtual bool interact(Action verb, Object &obj1, Object &obj2);
+
+private:
+ StringID _dialog1[4];
+ byte _eyewitness;
+ byte _hands;
+};
+class ArsanoGlider : public Room {
+public:
+ ArsanoGlider(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 19;
+ _id = GLIDER;
+ _shown[0] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringExit,kStringDefaultDescription,NULLOBJECT,EXIT,255,255,0,MEETUP,15);
+ _objectState[1] = Object(_id, kStringButton,kStringDefaultDescription,GLIDER_BUTTON1,PRESS,0,0,0);
+ _objectState[2] = Object(_id, kStringButton,kStringDefaultDescription,GLIDER_BUTTON2,PRESS,1,1,0);
+ _objectState[3] = Object(_id, kStringButton,kStringDefaultDescription,GLIDER_BUTTON3,PRESS,2,2,0);
+ _objectState[4] = Object(_id, kStringButton,kStringDefaultDescription,GLIDER_BUTTON4,PRESS,3,3,0);
+ _objectState[5] = Object(_id, kStringKeycard,kStringDefaultDescription,GLIDER_KEYCARD,TAKE|COMBINABLE,255,255,0);
+ _objectState[6] = Object(_id, kStringSlot,kStringDefaultDescription,GLIDER_SLOT,COMBINABLE,4,4,0);
+ _objectState[7] = Object(_id, kStringCompartment,kStringDefaultDescription,NULLOBJECT,OPENABLE,5,6,6);
+ _objectState[8] = Object(_id, kStringKeyboard,kStringDefaultDescription,GLIDER_BUTTONS,NULLTYPE,7,7,0);
+ _objectState[9] = Object(_id, kStringAnnouncement,kStringAnnouncementDescription,GLIDER_DISPLAY,NULLTYPE,8,8,0);
+ _objectState[10] = Object(_id, kStringInstruments,kStringAnnouncementDescription,GLIDER_INSTRUMENTS,NULLTYPE,9,9,0);
+ }
+
+ virtual void animation();
+ virtual bool interact(Action verb, Object &obj1, Object &obj2);
+
+private:
+ byte _sinus;
+};
+class ArsanoMeetup2 : public Room {
+public:
+ ArsanoMeetup2(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 38;
+ _id = MEETUP2;
+ _shown[0] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringRoger, kStringDefaultDescription, ROGER_W, TALK, 255, 255, 0);
+ _objectState[1] = Object(_id, kStringSpaceshift, kStringDefaultDescription, SPACESHIP, COMBINABLE, 255, 255, 0);
+ _objectState[2] = Object(_id, kStringCave, kStringDefaultDescription, NULLOBJECT, EXIT, 255, 255, 0, CAVE, 22);
+
+ _dialog1[0] = kStringDialogArsanoMeetup2_1;
+ _dialog1[1] = kStringDialogArsanoMeetup2_2;
+ _dialog2[0] = kStringDialogArsanoMeetup2_3;
+ _dialog2[1] = kStringDialogArsanoMeetup2_4;
+ _dialog3[0] = kStringDialogArsanoMeetup2_5;
+ _dialog3[1] = kStringDialogArsanoMeetup2_6;
+ _dialog3[2] = kStringDialogArsanoMeetup2_7;
+ _dialog3[3] = kStringDialogArsanoMeetup2_8;
+ _dialog4[0] = kStringDialogArsanoMeetup2_9;
+ _dialog4[1] = kStringDialogArsanoMeetup2_10;
+ _dialog4[2] = kStringDialogArsanoMeetup2_11;
+ }
+
+ virtual void onEntrance();
+ virtual bool interact(Action verb, Object &obj1, Object &obj2);
+
+ void shipStart();
+
+private:
+ // TODO: change to 6, fix initialization
+ StringID _dialog1[2];
+ StringID _dialog2[2];
+ StringID _dialog3[4];
+ StringID _dialog4[3];
+
+ bool _found;
+ bool _flug;
+};
+class ArsanoMeetup3 : public Room {
+public:
+ ArsanoMeetup3(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 39;
+ _id = MEETUP3;
+ _shown[0] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringUfo,kStringUfoDescription,UFO,EXIT,0,0,0,NULLROOM,3);
+ _objectState[1] = Object(_id, kStringStar,kStringDefaultDescription,STAR,NULLTYPE,1,1,0);
+ _objectState[2] = Object(_id, kStringCave,kStringDefaultDescription,NULLOBJECT,EXIT,255,255,0,CAVE,22);
+
+ _dialog2[0] = kStringArsanoDialog1;
+ _dialog2[1] = kStringDialogArsanoMeetup3_1;
+ _dialog2[2] = kStringDialogArsanoMeetup3_2;
+ _dialog2[3] = kStringDialogArsanoMeetup3_3;
+ _dialog3[0] = kStringDialogArsanoMeetup3_4;
+ _dialog3[1] = kStringDialogArsanoMeetup3_5;
+
+ _dialogsX[0] = kStringDialogX1;
+ _dialogsX[1] = kStringDialogX2;
+ _dialogsX[2] = kStringDialogX3;
+ }
+
+ virtual bool interact(Action verb, Object &obj1, Object &obj2);
+
+private:
+ StringID _dialog2[4];
+ StringID _dialog3[2];
+
+ // TODO: Hack, to be move away and renamed when the other uses are found
+ StringID _dialogsX[6];
+ //
+};
+
+// Axacuss
+class AxacussCell : public Room {
+public:
+ AxacussCell(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 43;
+ _id = CELL;
+ _shown[0] = kShownTrue;
+ _shown[1] = kShownTrue;
+ _shown[31] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringButton,kStringDefaultDescription,CELL_BUTTON,PRESS,1,1,0);
+ _objectState[1] = Object(_id, kStringDoor,kStringDefaultDescription,CELL_DOOR,EXIT|OPENABLE|CLOSED,0,0,31+128,CORRIDOR4,1);
+ _objectState[2] = Object(_id, kStringTray,kStringTrayDescription,TRAY,UNNECESSARY,255,255,0);
+ _objectState[3] = Object(_id, kStringLamp,kStringLampDescription,NULLOBJECT,COMBINABLE,3,3,0);
+ _objectState[4] = Object(_id, kStringEyes,kStringEyesDescription,NULLOBJECT,NULLTYPE,4,4,0);
+ _objectState[5] = Object(_id, kStringWire,kStringDefaultDescription,CELL_WIRE,COMBINABLE|TAKE,6,6,0);
+ _objectState[6] = Object(_id, kStringSocket,kStringSocketDescription,SOCKET,COMBINABLE,5,5,0);
+ _objectState[7] = Object(_id, kStringMetalBlock,kStringMetalBlockDescription,MAGNET,TAKE|COMBINABLE,255,255,30);
+ _objectState[8] = Object(_id, kStringRobot,kStringRobotDescription,NULLOBJECT,NULLTYPE,255,255,0);
+ _objectState[9] = Object(_id, kStringTable,kStringTableDescription,CELL_TABLE,COMBINABLE,2,2,0);
+ }
+
+ virtual bool interact(Action verb, Object &obj1, Object &obj2);
+ virtual void animation();
+ virtual void onEntrance();
+};
+class AxacussCorridor1 : public Room {
+public:
+ AxacussCorridor1(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 16;
+ _id = CORRIDOR1;
+ _shown[0] = kShownTrue;
+ _shown[3] = kShownTrue;
+ _shown[4] = kShownTrue;
+ _shown[5] = kShownTrue;
+ _shown[13] = kShownTrue;
+ _shown[21] = kShownTrue;
+ _shown[23] = kShownTrue;
+ _shown[25] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringExit,kStringDefaultDescription,NULLOBJECT,EXIT,2,2,0,GUARD3,2);
+ _objectState[1] = Object(_id, kStringExit,kStringDefaultDescription,NULLOBJECT,EXIT,3,3,0,CORRIDOR2,22);
+ }
+
+ virtual void onEntrance();
+};
+class AxacussCorridor2 : public Room {
+public:
+ AxacussCorridor2(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 16;
+ _id = CORRIDOR2;
+ _shown[0] = kShownTrue;
+ _shown[2] = kShownTrue;
+ _shown[3] = kShownTrue;
+ _shown[4] = kShownTrue;
+ _shown[5] = kShownTrue;
+ _shown[17] = kShownTrue;
+ _shown[21] = kShownTrue;
+ _shown[24] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringExit,kStringDefaultDescription,NULLOBJECT,EXIT,2,2,0,CORRIDOR1,2);
+ _objectState[1] = Object(_id, kStringExit,kStringDefaultDescription,NULLOBJECT,EXIT,3,3,0,CORRIDOR3,22);
+ _objectState[2] = Object(_id, kStringExit,kStringDefaultDescription,NULLOBJECT,EXIT,1,1,0,CORRIDOR4,14);
+ }
+
+ virtual void onEntrance();
+};
+class AxacussCorridor3 : public Room {
+public:
+ AxacussCorridor3(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 16;
+ _id = CORRIDOR3;
+ _shown[0] = kShownTrue;
+ _shown[3] = kShownTrue;
+ _shown[5] = kShownTrue;
+ _shown[19] = kShownTrue;
+ _shown[23] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringExit,kStringDefaultDescription,NULLOBJECT,EXIT,2,2,0,CORRIDOR2,2);
+ }
+
+ virtual void onEntrance();
+};
+class AxacussCorridor4 : public Room {
+public:
+ AxacussCorridor4(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 16;
+ _id = CORRIDOR4;
+ _shown[0] = kShownTrue;
+ _shown[1] = kShownTrue;
+ _shown[2] = kShownTrue;
+ _shown[8] = kShownTrue;
+ _shown[9] = kShownTrue;
+ _shown[11] = kShownTrue;
+ _shown[15] = kShownTrue;
+ _shown[18] = kShownTrue;
+ _shown[20] = kShownTrue;
+ _shown[26] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringExit,kStringDefaultDescription,NULLOBJECT,EXIT,0,0,0,CORRIDOR2,10);
+ _objectState[1] = Object(_id, kStringExit,kStringDefaultDescription,NULLOBJECT,EXIT,1,1,0,GUARD,14);
+ _objectState[2] = Object(_id, kStringCellDoor,kStringCellDoorDescription,DOOR,EXIT|OPENABLE|OPENED|CLOSED,7,7,0,CELL,16);
+ _objectState[3] = Object(_id, kStringLaptop,kStringDefaultDescription,NEWSPAPER,TAKE,6,6,8);
+ _objectState[4] = Object(_id, kStringWristwatch,kStringDefaultDescription,WATCH,TAKE|COMBINABLE,255,255,8);
+ _objectState[5] = Object(_id, kStringTable,kStringDefaultDescription,TABLE,COMBINABLE,5,5,0);
+ }
+
+ virtual void onEntrance();
+ virtual void animation();
+ virtual bool interact(Action verb, Object &obj1, Object &obj2);
+};
+class AxacussCorridor5 : public Room {
+public:
+ AxacussCorridor5(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 16;
+ _id = CORRIDOR5;
+ _shown[0] = kShownTrue;
+ _shown[3] = kShownTrue;
+ _shown[4] = kShownTrue;
+ _shown[5] = kShownTrue;
+ _shown[12] = kShownTrue;
+ _shown[22] = kShownTrue;
+ _shown[23] = kShownTrue;
+ _shown[24] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringExit,kStringDefaultDescription,DOOR,EXIT,2,2,0,NULLROOM,2);
+ _objectState[1] = Object(_id, kStringExit,kStringDefaultDescription,NULLOBJECT,EXIT,3,3,0,CORRIDOR6,22);
+
+ _dialog1[0] = kStringDialogAxacussCorridor5_1;
+ _dialog1[1] = kStringDialogAxacussCorridor5_2;
+ _dialog2[0] = kStringDialogAxacussCorridor5_3;
+ _dialog2[1] = kStringDialogAxacussCorridor5_4;
+ _dialog3[0] = kStringDialogAxacussCorridor5_5;
+ _dialog3[1] = kStringDialogAxacussCorridor5_6;
+ _dialog3[2] = kStringDialogAxacussCorridor5_7;
+ _dialog3[3] = kStringDialogAxacussCorridor5_7;
+
+ _rows[0] = 1;
+ _rows[1] = 1;
+ _rows[2] = 1;
+ _rows[3] = 1;
+ _rows[4] = 0;
+ _rows[5] = 0;
+ }
+
+ virtual void onEntrance();
+ virtual bool interact(Action verb, Object &obj1, Object &obj2);
+
+private:
+ void stopInteract(int sum);
+ bool handleMoneyDialog();
+
+ // TODO: Change to 6, or change struct, and fix initialization
+ StringID _dialog1[2];
+ StringID _dialog2[2];
+ StringID _dialog3[4];
+
+ byte _rows[6];
+};
+
+class AxacussCorridor6 : public Room {
+public:
+ AxacussCorridor6(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 16;
+ _id = CORRIDOR6;
+ _shown[0] = kShownTrue;
+ _shown[3] = kShownTrue;
+ _shown[4] = kShownTrue;
+ _shown[5] = kShownTrue;
+ _shown[6] = kShownTrue;
+ _shown[22] = kShownTrue;
+ _shown[24] = kShownTrue;
+ _shown[25] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringExit,kStringDefaultDescription,NULLOBJECT,EXIT,2,2,0,CORRIDOR5,2);
+ _objectState[1] = Object(_id, kStringExit,kStringDefaultDescription,NULLOBJECT,EXIT,3,3,0,CORRIDOR7,22);
+ _objectState[2] = Object(_id, kStringDoor,kStringDefaultDescription,DOOR,OPENABLE|CLOSED,255,255,0,CORRIDOR8,13);
+ }
+
+ virtual void onEntrance();
+ virtual bool interact(Action verb, Object &obj1, Object &obj2);
+};
+class AxacussCorridor7 : public Room {
+public:
+ AxacussCorridor7(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 16;
+ _id = CORRIDOR7;
+ _shown[0] = kShownTrue;
+ _shown[3] = kShownTrue;
+ _shown[4] = kShownTrue;
+ _shown[5] = kShownTrue;
+ _shown[10] = kShownTrue;
+ _shown[21] = kShownTrue;
+ _shown[24] = kShownTrue;
+ _shown[25] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringExit,kStringDefaultDescription,NULLOBJECT,EXIT,2,2,0,CORRIDOR6,2);
+ _objectState[1] = Object(_id, kStringExit,kStringDefaultDescription,NULLOBJECT,EXIT,3,3,0,GUARD,22);
+ }
+
+ virtual void onEntrance();
+};
+class AxacussCorridor8 : public Room {
+public:
+ AxacussCorridor8(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 16;
+ _id = CORRIDOR8;
+ _shown[0] = kShownTrue;
+ _shown[1] = kShownTrue;
+ _shown[4] = kShownTrue;
+ _shown[15] = kShownTrue;
+ _shown[20] = kShownTrue;
+ _shown[22] = kShownTrue;
+ _shown[28] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringDoor,kStringDefaultDescription,DOOR,EXIT|OPENABLE,0,0,0,CORRIDOR6,10);
+ _objectState[1] = Object(_id, kStringExit,kStringDefaultDescription,NULLOBJECT,EXIT,3,3,0,BCORRIDOR,22);
+ }
+
+ virtual void onEntrance();
+ virtual bool interact(Action verb, Object &obj1, Object &obj2);
+};
+class AxacussCorridor9 : public Room {
+public:
+ AxacussCorridor9(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 16;
+ _id = CORRIDOR9;
+ _shown[0] = kShownTrue;
+ _shown[1] = kShownTrue;
+ _shown[3] = kShownTrue;
+ _shown[14] = kShownTrue;
+ _shown[19] = kShownTrue;
+ _shown[23] = kShownTrue;
+ _shown[28] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringExit,kStringDefaultDescription,NULLOBJECT,EXIT,2,2,0,BCORRIDOR,2);
+ _objectState[1] = Object(_id, kStringDoor,kStringDefaultDescription,DOOR,EXIT|OPENABLE,0,0,0,GUARD,10);
+ }
+
+ virtual void onEntrance();
+ virtual bool interact(Action verb, Object &obj1, Object &obj2);
+};
+class AxacussBcorridor : public Room {
+public:
+ AxacussBcorridor(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 6;
+ _id = BCORRIDOR;
+ _shown[0] = kShownTrue;
+ _shown[3] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringPillar,kStringDefaultDescription,PILLAR1,NULLTYPE,4,4,0);
+ _objectState[1] = Object(_id, kStringPillar,kStringDefaultDescription,PILLAR2,NULLTYPE,5,5,0);
+ _objectState[2] = Object(_id, kStringExit,kStringDefaultDescription,NULLOBJECT,EXIT,6,6,0,CORRIDOR8,2);
+ _objectState[3] = Object(_id, kStringExit,kStringDefaultDescription,NULLOBJECT,EXIT,7,7,0,CORRIDOR9,22);
+ _objectState[4] = Object(_id, kStringDoor,kStringDoorDescription1,DOOR1,EXIT|OPENABLE|CLOSED|OCCUPIED,0,0,1,OFFICE_L1,6);
+ _objectState[5] = Object(_id, kStringDoor,kStringDoorDescription2,DOOR2,EXIT|OPENABLE|CLOSED|OCCUPIED,1,1,2,OFFICE_L2,16);
+ _objectState[6] = Object(_id, kStringDoor,kStringDoorDescription3,DOOR3,EXIT|OPENABLE|OPENED,2,2,3,OFFICE_R1,8);
+ _objectState[7] = Object(_id, kStringDoor,kStringDoorDescription4,DOOR4,EXIT|OPENABLE|CLOSED|OCCUPIED,3,3,4,OFFICE_R2,18);
+ }
+
+ virtual void onEntrance();
+ virtual bool interact(Action verb, Object &obj1, Object &obj2);
+};
+
+class AxacussIntersection : public Room {
+public:
+ AxacussIntersection(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 40;
+ _id = GUARD;
+ _shown[0] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringExit, kStringDefaultDescription, NULLOBJECT, EXIT, 255, 255, 0, CORRIDOR4, 21);
+ _objectState[1] = Object(_id, kStringCorridor, kStringDefaultDescription, NULLOBJECT, EXIT, 3, 3, 0, CORRIDOR7, 5);
+ _objectState[2] = Object(_id, kStringDoor, kStringDefaultDescription, DOOR, EXIT | OPENABLE, 1, 1, 6, CORRIDOR9, 3);
+ _objectState[3] = Object(_id, kStringAxacussan, kStringAxacussanDescription, GUARDIAN, TALK, 0, 0, 0);
+ _objectState[4] = Object(_id, kStringImage, kStringImageDescription2, NULLOBJECT, NULLTYPE, 2, 2, 0);
+ _objectState[5] = Object(_id, kStringMastercard, kStringMastercardDescription, MASTERKEYCARD, TAKE | COMBINABLE, 255, 255, 1);
+
+ _dialogsX[0] = kStringDialogX1;
+ _dialogsX[1] = kStringDialogX2;
+ _dialogsX[2] = kStringDialogX3;
+ }
+
+ virtual bool interact(Action verb, Object &obj1, Object &obj2);
+
+private:
+ StringID _dialogsX[6];
+};
+
+class AxacussExit : public Room {
+public:
+ AxacussExit(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 42;
+ _id = GUARD3;
+ _shown[0] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringExit,kStringDefaultDescription,NULLOBJECT,EXIT,255,255,0,CORRIDOR1,22);
+ _objectState[1] = Object(_id, kStringDoor,kStringDefaultDescription,NULLOBJECT,EXIT|OPENABLE|CLOSED,0,0,0,NULLROOM,20);
+ _objectState[2] = Object(_id, kStringDoor,kStringDefaultDescription,NULLOBJECT,EXIT|OPENABLE|CLOSED,1,1,0,NULLROOM,15);
+ _objectState[3] = Object(_id, kStringDoor,kStringDefaultDescription,DOOR,EXIT|OPENABLE,2,2,11,OFFICE_L,0);
+ _objectState[4] = Object(_id, kStringLamp2,kStringDefaultDescription,LAMP,COMBINABLE,3,3,0);
+ _objectState[5] = Object(_id, kStringAxacussan,kStringDefaultDescription,GUARDIAN,TALK,5,5,0);
+ _objectState[6] = Object(_id, kStringImage,kStringGenericDescription5,NULLOBJECT,NULLTYPE,4,4,0);
+
+ _dialogsX[0] = kStringDialogX1;
+ _dialogsX[1] = kStringDialogX2;
+ _dialogsX[2] = kStringDialogX3;
+ }
+
+ virtual bool interact(Action verb, Object &obj1, Object &obj2);
+
+private:
+ StringID _dialogsX[6];
+};
+class AxacussOffice1 : public Room {
+public:
+ AxacussOffice1(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 7;
+ _id = OFFICE_L1;
+ _shown[0] = kShownTrue;
+ _shown[2] = kShownTrue;
+ _shown[7] = kShownTrue;
+ _shown[9] = kShownTrue;
+ _shown[16] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringDoor,kStringDefaultDescription,DOOR,EXIT|OPENABLE|OPENED,6,6,9,BCORRIDOR,9);
+ _objectState[1] = Object(_id, kStringComputer,kStringDefaultDescription,COMPUTER,COMBINABLE,4,4,0);
+ _objectState[2] = Object(_id, kStringMoney,kStringMoneyDescription1,MONEY,TAKE,255,255,0);
+ _objectState[3] = Object(_id, kStringLocker,kStringLockerDescription,LOCKER,OPENABLE|CLOSED,5,5,0);
+ _objectState[4] = Object(_id, kStringLetter,kStringDefaultDescription,LETTER,UNNECESSARY,3,3,0);
+ }
+
+ virtual bool interact(Action verb, Object &obj1, Object &obj2);
+};
+class AxacussOffice2 : public Room {
+public:
+ AxacussOffice2(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 7;
+ _id = OFFICE_L2;
+ _shown[0] = kShownTrue;
+ _shown[1] = kShownTrue;
+ _shown[9] = kShownTrue;
+ _shown[16] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringDoor,kStringDefaultDescription,DOOR,EXIT|OPENABLE|OPENED,6,6,9,BCORRIDOR,9);
+ _objectState[1] = Object(_id, kStringComputer,kStringDefaultDescription,COMPUTER,COMBINABLE,4,4,0);
+ _objectState[2] = Object(_id, kStringCube,kStringGenericDescription6,NULLOBJECT,NULLTYPE,0,0,0);
+ _objectState[3] = Object(_id, kStringImage,kStringGenericDescription7,NULLOBJECT,NULLTYPE,1,1,0);
+ _objectState[4] = Object(_id, kStringStrangeThing,kStringGenericDescription8,NULLOBJECT,UNNECESSARY,2,2,0);
+ }
+
+ virtual bool interact(Action verb, Object &obj1, Object &obj2);
+};
+class AxacussOffice3 : public Room {
+public:
+ AxacussOffice3(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 8;
+ _id = OFFICE_R1;
+ _shown[0] = kShownTrue;
+ _shown[1] = kShownTrue;
+ _shown[3] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringDoor,kStringDefaultDescription,DOOR,EXIT|OPENABLE|OPENED,0,0,3,BCORRIDOR,5);
+ _objectState[1] = Object(_id, kStringComputer,kStringDefaultDescription,COMPUTER,COMBINABLE,4,4,0);
+ _objectState[2] = Object(_id, kStringImage,kStringImageDescription2,NULLOBJECT,UNNECESSARY,1,1,0);
+ _objectState[3] = Object(_id, kStringImage,kStringImageDescription2,PAINTING,UNNECESSARY,2,2,0);
+ _objectState[4] = Object(_id, kStringPlant,kStringDefaultDescription,NULLOBJECT,UNNECESSARY,3,3,0);
+ _objectState[5] = Object(_id, kNoString,kStringDefaultDescription,MONEY,TAKE|COMBINABLE,255,255,0);
+ }
+
+ virtual bool interact(Action verb, Object &obj1, Object &obj2);
+};
+class AxacussOffice4 : public Room {
+public:
+ AxacussOffice4(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 8;
+ _id = OFFICE_R2;
+ _shown[0] = kShownTrue;
+ _shown[2] = kShownTrue;
+ _shown[3] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringDoor,kStringDefaultDescription,DOOR,EXIT|OPENABLE|OPENED,0,0,3,BCORRIDOR,5);
+ _objectState[1] = Object(_id, kStringComputer,kStringDefaultDescription,COMPUTER,COMBINABLE,4,4,0);
+ _objectState[2] = Object(_id, kStringStatue,kStringStatueDescription,NULLOBJECT,UNNECESSARY,6,6,0);
+ _objectState[3] = Object(_id, kStringPlant,kStringPlantDescription,NULLOBJECT,UNNECESSARY,5,5,0);
+ }
+
+ virtual bool interact(Action verb, Object &obj1, Object &obj2);
+};
+class AxacussOffice5 : public Room {
+public:
+ AxacussOffice5(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 7;
+ _id = OFFICE_L;
+ _shown[0] = kShownTrue;
+ _shown[3] = kShownTrue;
+ _shown[5] = kShownTrue;
+ _shown[17] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringDoor,kStringDefaultDescription,DOOR,EXIT|OPENABLE|OPENED,6,6,17,GUARD3,9);
+ _objectState[1] = Object(_id, kStringComputer,kStringComputerDescription,COMPUTER,COMBINABLE,4,4,0);
+ _objectState[2] = Object(_id, kStringGraffiti,kStringGraffitiDescription,NULLOBJECT,NULLTYPE,7,7,0);
+ _objectState[3] = Object(_id, kStringMoney,kStringMoneyDescription2,MONEY,TAKE,8,8,0);
+ }
+
+ virtual void onEntrance();
+ virtual bool interact(Action verb, Object &obj1, Object &obj2);
+};
+class AxacussElevator : public Room {
+public:
+ AxacussElevator(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 3;
+ _id = ELEVATOR;
+ _shown[0] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringButton,kStringDefaultDescription,BUTTON1,PRESS,0,0,0);
+ _objectState[1] = Object(_id, kStringButton,kStringDefaultDescription,BUTTON2,PRESS,1,1,0);
+ _objectState[2] = Object(_id, kStringExit,kStringDefaultDescription,DOOR,EXIT,255,255,0,NULLROOM,22);
+ _objectState[3] = Object(_id, kStringJungle,kStringJungleDescription,JUNGLE,NULLTYPE,255,255,0,STATION,2);
+ }
+
+ virtual bool interact(Action verb, Object &obj1, Object &obj2);
+};
+class AxacussStation : public Room {
+public:
+ AxacussStation(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 5;
+ _id = STATION;
+ _shown[0] = kShownTrue;
+ _objectState[0] = Object(_id, kStringSign,kStringDefaultDescription,STATION_SIGN,NULLTYPE,0,0,0);
+ _objectState[1] = Object(_id, kStringDoor,kStringDefaultDescription,DOOR,EXIT|OPENABLE|CLOSED,1,1,0,NULLROOM,7);
+ }
+
+ virtual bool interact(Action verb, Object &obj1, Object &obj2);
+};
+class AxacussSign : public Room {
+public:
+ AxacussSign(SupernovaEngine *vm, GameManager *gm) {
+ _vm = vm;
+ _gm = gm;
+
+ _fileNumber = 32;
+ _id = SIGN;
+ _shown[0] = kShownTrue;
+ _shown[1] = kShownTrue;
+
+ _objectState[0] = Object(_id, kStringExit,kStringDefaultDescription,NULLOBJECT,EXIT,255,255,0,STATION,22);
+ _objectState[1] = Object(_id, kStringSlot,kStringDefaultDescription,STATION_SLOT,COMBINABLE,0,0,0);
+ }
+
+ virtual bool interact(Action verb, Object &obj1, Object &obj2);
+};
+
+class Outro : public Room {
+public:
+ Outro(SupernovaEngine *vm, GameManager *gm);
+
+ virtual void onEntrance();
+ virtual void animation();
+
+private:
+ void animate(int filenumber, int section1, int section2, int duration);
+ void animate(int filenumber, int section1, int section2, int duration, MessagePosition position,
+ const char *text);
+ void animate(int filenumber, int section1, int section2, int section3, int section4, int duration,
+ MessagePosition position, const char *text);
+
+ Common::String outroText;
+};
+
+}
+#endif // SUPERNOVA_ROOMS_H
diff --git a/engines/supernova/state.cpp b/engines/supernova/state.cpp
new file mode 100644
index 0000000000..f7bf70f15d
--- /dev/null
+++ b/engines/supernova/state.cpp
@@ -0,0 +1,2388 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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.
+ *
+ */
+
+#include "common/system.h"
+#include "graphics/palette.h"
+#include "gui/message.h"
+#include "supernova/supernova.h"
+#include "supernova/state.h"
+#include "graphics/cursorman.h"
+
+namespace Supernova {
+
+bool GameManager::serialize(Common::WriteStream *out) {
+ if (out->err())
+ return false;
+
+ // GameState
+ out->writeSint32LE(_state._time);
+ out->writeSint32LE(_state._timeSleep);
+ out->writeSint32LE(_state._timeAlarm);
+ out->writeSint32LE(_state._eventTime);
+ out->writeSint32LE(_state._eventCallback);
+ out->writeSint32LE(_state._arrivalDaysLeft);
+ out->writeSint32LE(_state._shipEnergyDaysLeft);
+ out->writeSint32LE(_state._landingModuleEnergyDaysLeft);
+ out->writeUint16LE(_state._greatFlag);
+ out->writeSint16LE(_state._timeRobot);
+ out->writeSint16LE(_state._money);
+ out->writeByte(_state._coins);
+ out->writeByte(_state._shoes);
+ out->writeByte(_state._origin);
+ out->writeByte(_state._destination);
+ out->writeByte(_state._language);
+ out->writeByte(_state._corridorSearch);
+ out->writeByte(_state._alarmOn);
+ out->writeByte(_state._terminalStripConnected);
+ out->writeByte(_state._terminalStripWire);
+ out->writeByte(_state._cableConnected);
+ out->writeByte(_state._powerOff);
+ out->writeByte(_state._dream);
+ for (int i = 0; i < 4; i++)
+ out->writeByte(_state._nameSeen[i]);
+ out->writeByte(_state._playerHidden);
+
+ // Inventory
+ out->writeSint32LE(_inventory.getSize());
+ out->writeSint32LE(_inventoryScroll);
+ for (int i = 0; i < _inventory.getSize(); ++i) {
+ Object *objectStateBegin = _rooms[_inventory.get(i)->_roomId]->getObject(0);
+ byte objectIndex = _inventory.get(i) - objectStateBegin;
+ out->writeSint32LE(_inventory.get(i)->_roomId);
+ out->writeSint32LE(objectIndex);
+ }
+
+ // Rooms
+ out->writeByte(_currentRoom->getId());
+ for (int i = 0; i < NUMROOMS; ++i) {
+ _rooms[i]->serialize(out);
+ }
+
+ return !out->err();
+}
+
+
+bool GameManager::deserialize(Common::ReadStream *in, int version) {
+ if (in->err())
+ return false;
+
+ // GameState
+ _state._time = in->readSint32LE();
+ _state._timeSleep = in->readSint32LE();
+ _state._timeAlarm = in->readSint32LE();
+ _state._eventTime = in->readSint32LE();
+ if (version >= 4)
+ _state._eventCallback = (EventFunction)in->readSint32LE();
+ else
+ _state._eventCallback = kNoFn;
+ _state._arrivalDaysLeft = in->readSint32LE();
+ _state._shipEnergyDaysLeft = in->readSint32LE();
+ _state._landingModuleEnergyDaysLeft = in->readSint32LE();
+ _state._greatFlag = in->readUint16LE();
+ _state._timeRobot = in->readSint16LE();
+ _state._money = in->readSint16LE();
+ _vm->setGameString(kStringInventoryMoney, Common::String::format("%d Xa", _state._money));
+ _state._coins = in->readByte();
+ _state._shoes = in->readByte();
+ if (version >= 6)
+ _state._origin = in->readByte();
+ else
+ _state._origin = 0;
+ _state._destination = in->readByte();
+ _state._language = in->readByte();
+ _state._corridorSearch = in->readByte();
+ _state._alarmOn = in->readByte();
+ _state._terminalStripConnected = in->readByte();
+ _state._terminalStripWire = in->readByte();
+ _state._cableConnected = in->readByte();
+ _state._powerOff = in->readByte();
+ _state._dream = in->readByte();
+
+ for (int i = 0; i < 4; i++) {
+ if (version >= 7)
+ _state._nameSeen[i] = in->readByte();
+ else
+ _state._nameSeen[i] = false;
+ }
+
+ if (version >= 8)
+ _state._playerHidden = in->readByte();
+ else
+ _state._playerHidden = false;
+
+ _oldTime = g_system->getMillis();
+
+ // Inventory
+ int inventorySize = in->readSint32LE();
+ _inventoryScroll = in->readSint32LE();
+ _inventory.clear();
+ for (int i = 0; i < inventorySize; ++i) {
+ RoomID objectRoom = static_cast<RoomID>(in->readSint32LE());
+ int objectIndex = in->readSint32LE();
+ _inventory.add(*_rooms[objectRoom]->getObject(objectIndex));
+ }
+
+ // Rooms
+ RoomID curRoomId = static_cast<RoomID>(in->readByte());
+ for (int i = 0; i < NUMROOMS; ++i) {
+ _rooms[i]->deserialize(in, version);
+ }
+ changeRoom(curRoomId);
+
+ // Some additional variables
+ _guiEnabled = true;
+ _animationEnabled = true;
+
+ return !in->err();
+}
+
+void Inventory::add(Object &obj) {
+ if (_numObjects < kMaxCarry) {
+ _inventory[_numObjects++] = &obj;
+ obj.setProperty(CARRIED);
+ }
+
+ if (getSize() > _inventoryScroll + 8) {
+ _inventoryScroll = getSize() - 8;
+ _inventoryScroll += _inventoryScroll % 2;
+ }
+}
+
+void Inventory::remove(Object &obj) {
+ for (int i = 0; i < _numObjects; ++i) {
+ if (_inventory[i] == &obj) {
+ if (_inventoryScroll >= 2 && getSize() % 2)
+ _inventoryScroll -= 2;
+
+ --_numObjects;
+ while (i < _numObjects) {
+ _inventory[i] = _inventory[i + 1];
+ ++i;
+ }
+ obj.disableProperty(CARRIED);
+ }
+ }
+}
+
+void Inventory::clear() {
+ for (int i = 0; i < _numObjects; ++i)
+ _inventory[i]->disableProperty(CARRIED);
+ _numObjects = 0;
+ _inventoryScroll = 0;
+}
+
+Object *Inventory::get(int index) const {
+ if (index < _numObjects)
+ return _inventory[index];
+
+ return const_cast<Object *>(&Object::nullObject);
+}
+
+Object *Inventory::get(ObjectID id) const {
+ for (int i = 0; i < _numObjects; ++i) {
+ if (_inventory[i]->_id == id)
+ return _inventory[i];
+ }
+
+ return const_cast<Object *>(&Object::nullObject);
+}
+
+
+GuiElement::GuiElement()
+ : _isHighlighted(false)
+ , _bgColorNormal(kColorWhite25)
+ , _bgColorHighlighted(kColorWhite44)
+ , _bgColor(kColorWhite25)
+ , _textColorNormal(kColorGreen)
+ , _textColorHighlighted(kColorLightGreen)
+ , _textColor(kColorGreen)
+{
+ _text[0] = '\0';
+}
+
+void GuiElement::setText(const char *text) {
+ strncpy(_text, text, sizeof(_text));
+}
+
+void GuiElement::setTextPosition(int x, int y) {
+ _textPosition = Common::Point(x, y);
+}
+
+void GuiElement::setSize(int x1, int y1, int x2, int y2) {
+ this->left = x1;
+ this->top = y1;
+ this->right = x2;
+ this->bottom = y2;
+
+ _textPosition = Common::Point(x1 + 1, y1 + 1);
+}
+
+void GuiElement::setColor(int bgColor, int textColor, int bgColorHighlighted, int textColorHightlighted) {
+ _bgColor = bgColor;
+ _textColor = textColor;
+ _bgColorNormal = bgColor;
+ _textColorNormal = textColor;
+ _bgColorHighlighted = bgColorHighlighted;
+ _textColorHighlighted = textColorHightlighted;
+}
+
+void GuiElement::setHighlight(bool isHighlighted) {
+ if (isHighlighted) {
+ _bgColor = _bgColorHighlighted;
+ _textColor = _textColorHighlighted;
+ } else {
+ _bgColor = _bgColorNormal;
+ _textColor = _textColorNormal;
+ }
+}
+
+// Used by Look Watch (when it's fixed). Do not remove.
+static Common::String timeToString(int msec) {
+ char s[9] = " 0:00:00";
+ msec /= 1000;
+ s[7] = msec % 10 + '0';
+ msec /= 10;
+ s[6] = msec % 6 + '0';
+ msec /= 6;
+ s[4] = msec % 10 + '0';
+ msec /= 10;
+ s[3] = msec % 6 + '0';
+ msec /= 6;
+ s[1] = msec % 10 + '0';
+ msec /= 10;
+ if (msec)
+ s[0] = msec + '0';
+
+ return Common::String(s);
+}
+
+StringID GameManager::guiCommands[] = {
+ kStringCommandGo, kStringCommandLook, kStringCommandTake, kStringCommandOpen, kStringCommandClose,
+ kStringCommandPress, kStringCommandPull, kStringCommandUse, kStringCommandTalk, kStringCommandGive
+};
+
+StringID GameManager::guiStatusCommands[] = {
+ kStringStatusCommandGo, kStringStatusCommandLook, kStringStatusCommandTake, kStringStatusCommandOpen, kStringStatusCommandClose,
+ kStringStatusCommandPress, kStringStatusCommandPull, kStringStatusCommandUse, kStringStatusCommandTalk, kStringStatusCommandGive
+};
+
+GameManager::GameManager(SupernovaEngine *vm)
+ : _inventory(_inventoryScroll)
+ , _vm(vm) {
+ initRooms();
+ changeRoom(INTRO);
+ initState();
+ initGui();
+}
+
+GameManager::~GameManager() {
+ destroyRooms();
+}
+
+void GameManager::destroyRooms() {
+ delete _rooms[INTRO];
+ delete _rooms[CORRIDOR];
+ delete _rooms[HALL];
+ delete _rooms[SLEEP];
+ delete _rooms[COCKPIT];
+ delete _rooms[AIRLOCK];
+ delete _rooms[HOLD];
+ delete _rooms[LANDINGMODULE];
+ delete _rooms[GENERATOR];
+ delete _rooms[OUTSIDE];
+ delete _rooms[CABIN_R1];
+ delete _rooms[CABIN_R2];
+ delete _rooms[CABIN_R3];
+ delete _rooms[CABIN_L1];
+ delete _rooms[CABIN_L2];
+ delete _rooms[CABIN_L3];
+ delete _rooms[BATHROOM];
+
+ delete _rooms[ROCKS];
+ delete _rooms[CAVE];
+ delete _rooms[MEETUP];
+ delete _rooms[ENTRANCE];
+ delete _rooms[REST];
+ delete _rooms[ROGER];
+ delete _rooms[GLIDER];
+ delete _rooms[MEETUP2];
+ delete _rooms[MEETUP3];
+
+ delete _rooms[CELL];
+ delete _rooms[CORRIDOR1];
+ delete _rooms[CORRIDOR2];
+ delete _rooms[CORRIDOR3];
+ delete _rooms[CORRIDOR4];
+ delete _rooms[CORRIDOR5];
+ delete _rooms[CORRIDOR6];
+ delete _rooms[CORRIDOR7];
+ delete _rooms[CORRIDOR8];
+ delete _rooms[CORRIDOR9];
+ delete _rooms[BCORRIDOR];
+ delete _rooms[GUARD];
+ delete _rooms[GUARD3];
+ delete _rooms[OFFICE_L1];
+ delete _rooms[OFFICE_L2];
+ delete _rooms[OFFICE_R1];
+ delete _rooms[OFFICE_R2];
+ delete _rooms[OFFICE_L];
+ delete _rooms[ELEVATOR];
+ delete _rooms[STATION];
+ delete _rooms[SIGN];
+ delete _rooms[OUTRO];
+}
+
+
+void GameManager::initState() {
+ Object::setObjectNull(_currentInputObject);
+ Object::setObjectNull(_inputObject[0]);
+ Object::setObjectNull(_inputObject[1]);
+ _inputVerb = ACTION_WALK;
+ _processInput = false;
+ _guiEnabled = true;
+ _animationEnabled = true;
+ _roomBrightness = 255;
+ _mouseClicked = false;
+ _keyPressed = false;
+ _mouseX = -1;
+ _mouseY = -1;
+ _mouseField = -1;
+ _inventoryScroll = 0;
+ _oldTime = g_system->getMillis();
+ _timerPaused = 0;
+ _timePaused = false;
+ _timer1 = 0;
+ _animationTimer = 0;
+
+ _currentSentence = -1;
+ for (int i = 0 ; i < 6 ; ++i) {
+ _sentenceNumber[i] = -1;
+ _texts[i] = kNoString;
+ _rows[i] = 0;
+ _rowsStart[i] = 0;
+ }
+
+ _state._time = ticksToMsec(916364); // 2 pm
+ _state._timeSleep = 0;
+ _state._timeAlarm = ticksToMsec(458182); // 7 am
+ _state._eventTime = kMaxTimerValue;
+ _state._eventCallback = kNoFn;
+ _state._arrivalDaysLeft = 2840;
+ _state._shipEnergyDaysLeft = 2135;
+ _state._landingModuleEnergyDaysLeft = 923;
+ _state._greatFlag = 0;
+ _state._timeRobot = 0;
+ _state._money = 0;
+ _state._coins = 0;
+ _state._shoes = 0;
+ _state._origin = 0;
+ _state._destination = 255;
+ _state._language = 0;
+ _state._corridorSearch = false;
+ _state._alarmOn = false;
+ _state._terminalStripConnected = false;
+ _state._terminalStripWire = false;
+ _state._cableConnected = false;
+ _state._powerOff = false;
+ _state._dream = false;
+
+ _prevImgId = 0;
+}
+
+void GameManager::initRooms() {
+ _rooms[INTRO] = new Intro(_vm, this);
+ _rooms[CORRIDOR] = new ShipCorridor(_vm, this);
+ _rooms[HALL] = new ShipHall(_vm, this);
+ _rooms[SLEEP] = new ShipSleepCabin(_vm, this);
+ _rooms[COCKPIT] = new ShipCockpit(_vm, this);
+ _rooms[AIRLOCK] = new ShipAirlock(_vm, this);
+ _rooms[HOLD] = new ShipHold(_vm, this);
+ _rooms[LANDINGMODULE] = new ShipLandingModule(_vm, this);
+ _rooms[GENERATOR] = new ShipGenerator(_vm, this);
+ _rooms[OUTSIDE] = new ShipOuterSpace(_vm, this);
+ _rooms[CABIN_R1] = new ShipCabinR1(_vm, this);
+ _rooms[CABIN_R2] = new ShipCabinR2(_vm, this);
+ _rooms[CABIN_R3] = new ShipCabinR3(_vm, this);
+ _rooms[CABIN_L1] = new ShipCabinL1(_vm, this);
+ _rooms[CABIN_L2] = new ShipCabinL2(_vm, this);
+ _rooms[CABIN_L3] = new ShipCabinL3(_vm, this);
+ _rooms[BATHROOM] = new ShipCabinBathroom(_vm, this);
+
+ _rooms[ROCKS] = new ArsanoRocks(_vm, this);
+ _rooms[CAVE] = new ArsanoCave(_vm, this);
+ _rooms[MEETUP] = new ArsanoMeetup(_vm, this);
+ _rooms[ENTRANCE] = new ArsanoEntrance(_vm, this);
+ _rooms[REST] = new ArsanoRemaining(_vm, this);
+ _rooms[ROGER] = new ArsanoRoger(_vm, this);
+ _rooms[GLIDER] = new ArsanoGlider(_vm, this);
+ _rooms[MEETUP2] = new ArsanoMeetup2(_vm, this);
+ _rooms[MEETUP3] = new ArsanoMeetup3(_vm, this);
+
+ _rooms[CELL] = new AxacussCell(_vm, this);
+ _rooms[CORRIDOR1] = new AxacussCorridor1(_vm, this);
+ _rooms[CORRIDOR2] = new AxacussCorridor2(_vm, this);
+ _rooms[CORRIDOR3] = new AxacussCorridor3(_vm, this);
+ _rooms[CORRIDOR4] = new AxacussCorridor4(_vm, this);
+ _rooms[CORRIDOR5] = new AxacussCorridor5(_vm, this);
+ _rooms[CORRIDOR6] = new AxacussCorridor6(_vm, this);
+ _rooms[CORRIDOR7] = new AxacussCorridor7(_vm, this);
+ _rooms[CORRIDOR8] = new AxacussCorridor8(_vm, this);
+ _rooms[CORRIDOR9] = new AxacussCorridor9(_vm, this);
+ _rooms[BCORRIDOR] = new AxacussBcorridor(_vm, this);
+ _rooms[GUARD] = new AxacussIntersection(_vm, this);
+ _rooms[GUARD3] = new AxacussExit(_vm, this);
+ _rooms[OFFICE_L1] = new AxacussOffice1(_vm, this);
+ _rooms[OFFICE_L2] = new AxacussOffice2(_vm, this);
+ _rooms[OFFICE_R1] = new AxacussOffice3(_vm, this);
+ _rooms[OFFICE_R2] = new AxacussOffice4(_vm, this);
+ _rooms[OFFICE_L] = new AxacussOffice5(_vm, this);
+ _rooms[ELEVATOR] = new AxacussElevator(_vm, this);
+ _rooms[STATION] = new AxacussStation(_vm, this);
+ _rooms[SIGN] = new AxacussSign(_vm, this);
+ _rooms[OUTRO] = new Outro(_vm, this);
+}
+
+void GameManager::initGui() {
+ int commandButtonX = 0;
+ for (int i = 0; i < ARRAYSIZE(_guiCommandButton); ++i) {
+ const Common::String &text = _vm->getGameString(guiCommands[i]);
+ int width;
+ if (i < 9)
+ width = _vm->textWidth(text) + 2;
+ else
+ width = 320 - commandButtonX;
+
+ _guiCommandButton[i].setSize(commandButtonX, 150, commandButtonX + width, 159);
+ _guiCommandButton[i].setText(text.c_str());
+ _guiCommandButton[i].setColor(kColorWhite25, kColorDarkGreen, kColorWhite44, kColorGreen);
+ commandButtonX += width + 2;
+ }
+
+ for (int i = 0; i < ARRAYSIZE(_guiInventory); ++i) {
+ int inventoryX = 136 * (i % 2);
+ int inventoryY = 161 + 10 * (i / 2);
+
+ _guiInventory[i].setSize(inventoryX, inventoryY, inventoryX + 135, inventoryY + 9);
+ _guiInventory[i].setColor(kColorWhite25, kColorDarkRed, kColorWhite35, kColorRed);
+ }
+ _guiInventoryArrow[0].setSize(272, 161, 279, 180);
+ _guiInventoryArrow[0].setColor(kColorWhite25, kColorDarkRed, kColorWhite35, kColorRed);
+ _guiInventoryArrow[0].setText("\x82");
+ _guiInventoryArrow[0].setTextPosition(273, 166);
+ _guiInventoryArrow[1].setSize(272, 181, 279, 200);
+ _guiInventoryArrow[1].setColor(kColorWhite25, kColorDarkRed, kColorWhite35, kColorRed);
+ _guiInventoryArrow[1].setText("\x83");
+ _guiInventoryArrow[1].setTextPosition(273, 186);
+}
+
+
+void GameManager::processInput(Common::KeyState &state) {
+ _key = state;
+
+ switch (state.keycode) {
+ case Common::KEYCODE_F1:
+ // help
+ break;
+ case Common::KEYCODE_F2:
+ // show game doc
+ break;
+ case Common::KEYCODE_F3:
+ // show game info
+ break;
+ case Common::KEYCODE_F4:
+ _vm->setTextSpeed();
+ break;
+ case Common::KEYCODE_F5:
+ // load/save
+ break;
+ case Common::KEYCODE_x:
+ if (state.flags & Common::KBD_ALT) {
+ // quit game
+ GUI::MessageDialog *dialog = new GUI::MessageDialog("Quit Game?", "Quit", "Cancel");
+ if (dialog->runModal() == GUI::kMessageOK)
+ _vm->quitGame();
+ delete dialog;
+
+ // TODO: Add original quit game message prompt
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void GameManager::resetInputState() {
+ Object::setObjectNull(_inputObject[0]);
+ Object::setObjectNull(_inputObject[1]);
+ _inputVerb = ACTION_WALK;
+ _processInput = false;
+ _mouseClicked = false;
+ _keyPressed = false;
+ _key.reset();
+ _mouseClickType = Common::EVENT_MOUSEMOVE;
+
+ processInput();
+}
+
+void GameManager::processInput() {
+ enum {
+ onNone,
+ onObject,
+ onCmdButton,
+ onInventory,
+ onInventoryArrowUp,
+ onInventoryArrowDown
+ } mouseLocation;
+
+ if (_mouseField >= 0 && _mouseField < 256)
+ mouseLocation = onObject;
+ else if (_mouseField >= 256 && _mouseField < 512)
+ mouseLocation = onCmdButton;
+ else if (_mouseField >= 512 && _mouseField < 768)
+ mouseLocation = onInventory;
+ else if (_mouseField == 768)
+ mouseLocation = onInventoryArrowUp;
+ else if (_mouseField == 769)
+ mouseLocation = onInventoryArrowDown;
+ else
+ mouseLocation = onNone;
+
+ if (_mouseClickType == Common::EVENT_LBUTTONUP) {
+ if (_vm->_messageDisplayed) {
+ // Hide the message and consume the event
+ _vm->removeMessage();
+ if (mouseLocation != onCmdButton)
+ return;
+ }
+
+ switch(mouseLocation) {
+ case onObject:
+ case onInventory:
+ // Fallthrough
+ if (_inputVerb == ACTION_GIVE || _inputVerb == ACTION_USE) {
+ if (Object::isNullObject(_inputObject[0])) {
+ _inputObject[0] = _currentInputObject;
+ if (!_inputObject[0]->hasProperty(COMBINABLE))
+ _processInput = true;
+ } else {
+ _inputObject[1] = _currentInputObject;
+ _processInput = true;
+ }
+ } else {
+ _inputObject[0] = _currentInputObject;
+ if (!Object::isNullObject(_currentInputObject))
+ _processInput = true;
+ }
+ break;
+ case onCmdButton:
+ resetInputState();
+ _inputVerb = static_cast<Action>(_mouseField - 256);
+ break;
+ case onInventoryArrowUp:
+ if (_inventoryScroll >= 2)
+ _inventoryScroll -= 2;
+ break;
+ case onInventoryArrowDown:
+ if (_inventoryScroll < _inventory.getSize() - ARRAYSIZE(_guiInventory))
+ _inventoryScroll += 2;
+ break;
+ case onNone:
+ break;
+ }
+
+ } else if (_mouseClickType == Common::EVENT_RBUTTONUP) {
+ if (_vm->_messageDisplayed) {
+ // Hide the message and consume the event
+ _vm->removeMessage();
+ return;
+ }
+
+ if (Object::isNullObject(_currentInputObject))
+ return;
+
+ if (mouseLocation == onObject || mouseLocation == onInventory) {
+ _inputObject[0] = _currentInputObject;
+ ObjectTypes type = _inputObject[0]->_type;
+ if (type & OPENABLE)
+ _inputVerb = (type & OPENED) ? ACTION_CLOSE : ACTION_OPEN;
+ else if (type & PRESS)
+ _inputVerb = ACTION_PRESS;
+ else if (type & TALK)
+ _inputVerb = ACTION_TALK;
+ else
+ _inputVerb = ACTION_LOOK;
+
+ _processInput = true;
+ }
+
+ } else if (_mouseClickType == Common::EVENT_MOUSEMOVE) {
+ int field = -1;
+ int click = -1;
+
+ if ((_mouseY >= _guiCommandButton[0].top) && (_mouseY <= _guiCommandButton[0].bottom)) {
+ /* command row */
+ field = 9;
+ while (_mouseX < _guiCommandButton[field].left - 1)
+ field--;
+ field += 256;
+ } else if ((_mouseX >= 283) && (_mouseX <= 317) && (_mouseY >= 163) && (_mouseY <= 197)) {
+ /* exit box */
+ field = _exitList[(_mouseX - 283) / 7 + 5 * ((_mouseY - 163) / 7)];
+ } else if ((_mouseY >= 161) && (_mouseX <= 270)) {
+ /* inventory box */
+ field = (_mouseX + 1) / 136 + ((_mouseY - 161) / 10) * 2;
+ if (field + _inventoryScroll < _inventory.getSize())
+ field += 512;
+ else
+ field = -1;
+ } else if ((_mouseY >= 161) && (_mouseX >= 271) && (_mouseX < 279)) {
+ /* inventory arrows */
+ field = (_mouseY > 180) ? 769 : 768;
+ } else {
+ /* normal item */
+ for (int i = 0; (_currentRoom->getObject(i)->_id != INVALIDOBJECT) &&
+ (field == -1) && i < kMaxObject; i++) {
+ click = _currentRoom->getObject(i)->_click;
+ if (click != 255 && _vm->_currentImage) {
+ MSNImageDecoder::ClickField *clickField = _vm->_currentImage->_clickField;
+ do {
+ if ((_mouseX >= clickField[click].x1) && (_mouseX <= clickField[click].x2) &&
+ (_mouseY >= clickField[click].y1) && (_mouseY <= clickField[click].y2))
+ field = i;
+
+ click = clickField[click].next;
+ } while ((click != 0) && (field == -1));
+ }
+ }
+ }
+
+ if (_mouseField != field) {
+ switch (mouseLocation) {
+ case onInventoryArrowUp:
+ case onInventoryArrowDown:
+ // Fallthrough
+ _guiInventoryArrow[_mouseField - 768].setHighlight(false);
+ break;
+ case onInventory:
+ _guiInventory[_mouseField - 512].setHighlight(false);
+ break;
+ case onCmdButton:
+ _guiCommandButton[_mouseField - 256].setHighlight(false);
+ break;
+ case onObject:
+ case onNone:
+ // Fallthrough
+ break;
+ }
+
+ Object::setObjectNull(_currentInputObject);
+
+ _mouseField = field;
+ if (_mouseField >= 0 && _mouseField < 256)
+ mouseLocation = onObject;
+ else if (_mouseField >= 256 && _mouseField < 512)
+ mouseLocation = onCmdButton;
+ else if (_mouseField >= 512 && _mouseField < 768)
+ mouseLocation = onInventory;
+ else if (_mouseField == 768)
+ mouseLocation = onInventoryArrowUp;
+ else if (_mouseField == 769)
+ mouseLocation = onInventoryArrowDown;
+ else
+ mouseLocation = onNone;
+
+ switch (mouseLocation) {
+ case onInventoryArrowUp:
+ case onInventoryArrowDown:
+ // Fallthrough
+ _guiInventoryArrow[_mouseField - 768].setHighlight(true);
+ break;
+ case onInventory:
+ _guiInventory[_mouseField - 512].setHighlight(true);
+ _currentInputObject = _inventory.get(_mouseField - 512 + _inventoryScroll);
+ break;
+ case onCmdButton:
+ _guiCommandButton[_mouseField - 256].setHighlight(true);
+ break;
+ case onObject:
+ _currentInputObject = _currentRoom->getObject(_mouseField);
+ break;
+ case onNone:
+ break;
+ }
+ }
+ }
+}
+
+void GameManager::corridorOnEntrance() {
+ if (_state._corridorSearch)
+ busted(0);
+}
+
+void GameManager::telomat(int nr) {
+ static Common::String name[8] = {
+ "DR. ALAB HANSI",
+ "ALAB HANSI",
+ "SAVAL LUN",
+ "x",
+ "PROF. DR. UGNUL TSCHABB",
+ "UGNUL TSCHABB",
+ "ALGA HURZ LI",
+ "x"
+ };
+
+ static Common::String name2[4] = {
+ "Alab Hansi",
+ "Saval Lun",
+ "Ugnul Tschabb",
+ "Alga Hurz Li"
+ };
+
+ StringID dial1[4];
+ dial1[0] = kStringTelomat1;
+ dial1[1] = kNoString;
+ dial1[2] = kStringTelomat3;
+ dial1[3] = kStringDialogSeparator;
+
+ static byte rows1[3] = {1, 2, 1};
+
+ StringID dial2[4];
+ dial2[0] = kStringTelomat4;
+ dial2[1] = kStringTelomat5;
+ dial2[2] = kStringTelomat6;
+ dial2[3] = kStringDialogSeparator;
+
+ static byte rows2[4] = {1, 1, 1, 1};
+
+ _vm->renderBox(0, 0, 320, 200, kColorBlack);
+ _vm->renderText(kStringTelomat7, 100, 70, kColorGreen);
+ _vm->renderText(kStringTelomat8, 100, 81, kColorGreen);
+ _vm->renderText(kStringTelomat9, 100, 92, kColorGreen);
+ _vm->renderText(kStringTelomat10, 100, 103, kColorGreen);
+ _vm->renderText(kStringTelomat11, 100, 120, kColorDarkGreen);
+ Common::String input;
+ do {
+ getInput();
+
+ switch (_key.keycode) {
+ case Common::KEYCODE_2: {
+ _vm->renderBox(0, 0, 320, 200, kColorDarkBlue);
+ _vm->renderText(kStringTelomat12, 50, 80, kColorGreen);
+ _vm->renderText(kStringTelomat13, 50, 91, kColorGreen);
+ do
+ edit(input, 50, 105, 30);
+ while ((_key.keycode != Common::KEYCODE_RETURN) && (_key.keycode != Common::KEYCODE_ESCAPE));
+
+ if (_key.keycode == Common::KEYCODE_ESCAPE) {
+ _vm->renderBox(0, 0, 320, 200, kColorBlack);
+ _vm->renderRoom(*_currentRoom);
+ _vm->paletteBrightness();
+ _guiEnabled = true;
+ drawMapExits();
+ return;
+ }
+
+ input.toUppercase();
+
+ int i = 0;
+ while ((i < 8) && (input != name[i]))
+ i++;
+ i >>= 1;
+ if (i == 4) {
+ _vm->renderText(kStringTelomat14, 50, 120, kColorGreen);
+ wait2(10);
+ _vm->renderBox(0, 0, 320, 200, kColorBlack);
+ _vm->renderRoom(*_currentRoom);
+ _vm->paletteBrightness();
+ _guiEnabled = true;
+ drawMapExits();
+ return;
+ }
+
+ if ((i == nr) || _rooms[BCORRIDOR]->getObject(4 + i)->hasProperty(CAUGHT)) {
+ _vm->renderText(kStringTelomat15, 50, 120, kColorGreen);
+ wait2(10);
+ _vm->renderBox(0, 0, 320, 200, kColorBlack);
+ _vm->renderRoom(*_currentRoom);
+ _vm->paletteBrightness();
+ _guiEnabled = true;
+ drawMapExits();
+ return;
+ }
+
+ _vm->renderText(kStringTelomat16, 50, 120, kColorGreen);
+ wait2(10);
+ _vm->renderBox(0, 0, 320, 200, kColorBlack);
+ _vm->renderRoom(*_currentRoom);
+ _vm->paletteBrightness();
+ _vm->renderMessage(kStringTelomat17, kMessageTop, name2[i]);
+ waitOnInput(_timer1);
+ _vm->removeMessage();
+ if (_state._nameSeen[nr]) {
+ Common::String string = _vm->getGameString(kStringTelomat2);
+ _vm->setGameString(kStringPlaceholder1, Common::String::format(string.c_str(), name2[nr].c_str()));
+ dial1[1] = kStringPlaceholder1;
+ _currentRoom->addSentence(1, 1);
+ } else
+ _currentRoom->removeSentence(1, 1);
+
+ switch (dialog(3, rows1, dial1, 1)) {
+ case 1: _vm->renderMessage(kStringTelomat18, kMessageTop);
+ waitOnInput(_timer1);
+ _vm->removeMessage();
+ if ((_state._destination == 255) && !_rooms[BCORRIDOR]->isSectionVisible(7)) {
+ _state._eventTime = _state._time + ticksToMsec(150);
+ _state._eventCallback = kGuardWalkFn;
+ _state._origin = i;
+ _state._destination = nr;
+ }
+ break;
+ case 0: _vm->renderMessage(kStringTelomat19, kMessageTop);
+ waitOnInput(_timer1);
+ _vm->removeMessage();
+ if (dialog(4, rows2, dial2, 0) != 3) {
+ wait2(10);
+ say(kStringTelomat20);
+ }
+ _rooms[BCORRIDOR]->setSectionVisible(7, true);
+ _rooms[BCORRIDOR]->setSectionVisible(i + 1, true);
+ _state._eventTime = kMaxTimerValue;
+ _currentRoom->addSentence(0, 1);
+ }
+ _guiEnabled = true;
+ drawMapExits();
+ return;
+ }
+ case Common::KEYCODE_1:
+ case Common::KEYCODE_3:
+ case Common::KEYCODE_4:
+ _vm->renderBox(0, 0, 320, 200, kColorDarkBlue);
+ _vm->renderText(kStringTelomat21, 100, 90, kColorGreen);
+ input = "";
+ do
+ edit(input, 100, 105, 30);
+ while ((_key.keycode != Common::KEYCODE_RETURN) && (_key.keycode != Common::KEYCODE_ESCAPE));
+
+ if (_key.keycode == Common::KEYCODE_RETURN) {
+ _vm->renderText(kStringShipSleepCabin9, 100, 120, kColorGreen);
+ wait2(10);
+ }
+ case Common::KEYCODE_ESCAPE:
+ _vm->renderBox(0, 0, 320, 200, kColorBlack);
+ _vm->renderRoom(*_currentRoom);
+ _vm->paletteBrightness();
+ _guiEnabled = true;
+ drawMapExits();
+ return;
+ default:
+ break;
+ }
+ } while (true);
+}
+
+void GameManager::startSearch() {
+ if ((_currentRoom->getId() >= CORRIDOR1) && (_currentRoom->getId() <= BCORRIDOR))
+ busted(0);
+
+ _state._corridorSearch = true;
+}
+
+void GameManager::search(int time) {
+ _state._eventTime = _state._time + ticksToMsec(time);
+ _state._eventCallback = kSearchStartFn;
+}
+
+void GameManager::guardNoticed() {
+ _vm->paletteFadeOut();
+ Room *r = _currentRoom;
+ _currentRoom = _rooms[GUARD];
+ _vm->setCurrentImage(40);
+ _vm->renderBox(0, 0, 320, 200, 0);
+ _vm->renderImage(0);
+ _vm->paletteFadeIn();
+ _vm->renderImage(2);
+ reply(kStringGuardNoticed1, 2, 5);
+ wait2(2);
+ reply(kStringGuardNoticed2, 2, 5);
+ _vm->paletteFadeOut();
+ _currentRoom->setSectionVisible(2, false);
+ _currentRoom->setSectionVisible(5, false);
+ _currentRoom = r;
+ _guiEnabled = true;
+ drawMapExits();
+}
+
+void GameManager::busted(int i) {
+ if (i > 0)
+ _vm->renderImage(i);
+ if (i == 0) {
+ if ((_currentRoom->getId() >= OFFICE_L1) && (_currentRoom->getId() <= OFFICE_R2)) {
+ if (_currentRoom->getId() < OFFICE_R1)
+ i = 10;
+ else
+ i = 5;
+ if (!_currentRoom->getObject(0)->hasProperty(OPENED)) {
+ _vm->renderImage(i - 1);
+ _vm->playSound(kAudioDoorOpen);
+ wait2(2);
+ }
+ _vm->renderImage(i);
+ wait2(3);
+ _vm->renderImage(i + 3);
+ _vm->playSound(kAudioVoiceHalt);
+ _vm->renderImage(i);
+ wait2(5);
+ if (_currentRoom->getId() == OFFICE_L2)
+ i = 13;
+ _vm->renderImage(i + 1);
+ wait2(3);
+ _vm->renderImage(i + 2);
+ shot(0, 0);
+ } else if (_currentRoom->getId() == BCORRIDOR)
+ _vm->renderImage(21);
+ else if (_currentRoom->isSectionVisible(4))
+ _vm->renderImage(32); // below
+ else if (_currentRoom->isSectionVisible(2))
+ _vm->renderImage(30); // right
+ else if (_currentRoom->isSectionVisible(1))
+ _vm->renderImage(31); // left
+ else
+ _vm->renderImage(33); // above
+ }
+ _vm->playSound(kAudioVoiceHalt);
+ wait2(3);
+ shot(0, 0);
+}
+
+void GameManager::novaScroll() {
+ static byte planet_f[6] = {0xeb,0xec,0xf0,0xed,0xf1,0xf2};
+ static byte nova_f[13] = {0xea,0xe9,0xf5,0xf3,0xf7,0xf4,0xf6,
+ 0xf9,0xfb,0xfc,0xfd,0xfe,0xfa};
+ static byte rgb[65][3] = {
+ { 5, 0, 0},{10, 0, 0},{15, 0, 0},{20, 0, 0},{25, 0, 0},
+ {30, 0, 0},{35, 0, 0},{40, 0, 0},{45, 0, 0},{50, 0, 0},
+ {55, 0, 0},{60, 0, 0},{63,10, 5},{63,20,10},{63,30,15},
+ {63,40,20},{63,50,25},{63,60,30},{63,63,33},{63,63,30},
+ {63,63,25},{63,63,20},{63,63,15},{63,63,10},{60,60,15},
+ {57,57,20},{53,53,25},{50,50,30},{47,47,35},{43,43,40},
+ {40,40,45},{37,37,50},{33,33,53},{30,30,56},{27,27,59},
+ {23,23,61},{20,20,63},{21,25,63},{22,30,63},{25,35,63},
+ {30,40,63},{35,45,63},{40,50,63},{45,55,63},{50,60,63},
+ {55,63,63},{59,63,63},{63,63,63},{63,60,63},{60,50,60},
+ {55,40,55},{50,30,50},{45,20,45},{40,10,40},{42,15,42},
+ {45,20,45},{47,25,47},{50,30,50},{52,35,52},{55,40,55},
+ {57,45,57},{60,50,60},{62,55,62},{63,60,63},{63,63,63}};
+
+ byte palette[768];
+ _vm->_system->getPaletteManager()->grabPalette(palette, 0, 255);
+
+ for (int t = 0; t < 65; ++t) {
+ for (int i = 0; i < 6; ++i) {
+ int idx = 3 * (planet_f[i] - 1);
+ for (int c = 0 ; c < 3 ; ++c) {
+ if (palette[idx+c] < rgb[t][c])
+ palette[idx+c] = rgb[t][c];
+ }
+ }
+ for (int cycle = 0; cycle < t && cycle < 13; ++cycle) {
+ int idx = 3 * (nova_f[cycle] - 1);
+ for (int c = 0 ; c < 3 ; ++c)
+ palette[idx + c] = rgb[t - cycle - 1][c];
+ }
+
+ _vm->_system->getPaletteManager()->setPalette(palette, 0, 255);
+ _vm->_system->updateScreen();
+ _vm->_system->delayMillis(_vm->_delay);
+ }
+}
+
+void GameManager::supernovaEvent() {
+ _vm->removeMessage();
+ CursorMan.showMouse(false);
+ if (_currentRoom->getId() <= CAVE) {
+ _vm->renderMessage(kStringSupernova1);
+ waitOnInput(_timer1);
+ _vm->removeMessage();
+ _vm->paletteFadeOut();
+ changeRoom(MEETUP);
+ _rooms[AIRLOCK]->getObject(0)->disableProperty(OPENED);
+ _rooms[AIRLOCK]->setSectionVisible(3, true);
+ _rooms[AIRLOCK]->getObject(1)->setProperty(OPENED);
+ _rooms[AIRLOCK]->setSectionVisible(17, true);
+ _rooms[AIRLOCK]->setSectionVisible(6, false);
+ _vm->renderRoom(*_currentRoom);
+ _vm->paletteFadeIn();
+ }
+ _vm->renderMessage(kStringSupernova2);
+ waitOnInput(_timer1);
+ _vm->removeMessage();
+ _vm->setCurrentImage(26);
+ _vm->renderImage(0);
+ _vm->paletteBrightness();
+ novaScroll();
+ _vm->paletteFadeOut();
+ _vm->renderBox(0, 0, 320, 200, kColorBlack);
+ _vm->_menuBrightness = 255;
+ _vm->paletteBrightness();
+
+ if (_currentRoom->getId() == GLIDER) {
+ _vm->renderMessage(kStringSupernova3);
+ waitOnInput(_timer1);
+ _vm->removeMessage();
+ _vm->_menuBrightness = 0;
+ _vm->paletteBrightness();
+ _vm->renderRoom(*_currentRoom);
+ _vm->paletteFadeIn();
+ _vm->renderMessage(kStringSupernova4, kMessageTop);
+ waitOnInput(_timer1);
+ _vm->removeMessage();
+ _vm->renderMessage(kStringSupernova5, kMessageTop);
+ waitOnInput(_timer1);
+ _vm->removeMessage();
+ _vm->renderMessage(kStringSupernova6, kMessageTop);
+ waitOnInput(_timer1);
+ _vm->removeMessage();
+ _vm->renderMessage(kStringSupernova7, kMessageTop);
+ waitOnInput(_timer1);
+ _vm->removeMessage();
+ changeRoom(MEETUP2);
+ _rooms[MEETUP2]->setSectionVisible(1, true);
+ _rooms[MEETUP2]->removeSentence(0, 1);
+ _inventory.remove(*(_rooms[ROGER]->getObject(3)));
+ _inventory.remove(*(_rooms[ROGER]->getObject(7)));
+ _inventory.remove(*(_rooms[ROGER]->getObject(8)));
+ } else {
+ _vm->renderMessage(kStringSupernova8);
+ waitOnInput(_timer1);
+ _vm->removeMessage();
+ _vm->_menuBrightness = 0;
+ _vm->paletteBrightness();
+ changeRoom(MEETUP2);
+ if (_rooms[ROGER]->getObject(3)->hasProperty(CARRIED) && !_rooms[GLIDER]->isSectionVisible(5)) {
+ _rooms[MEETUP2]->setSectionVisible(1, true);
+ _rooms[MEETUP2]->setSectionVisible(12, true);
+ _rooms[MEETUP2]->getObject(1)->_click = 0;
+ _rooms[MEETUP2]->getObject(0)->_click = 1;
+ _rooms[MEETUP2]->removeSentence(0, 1);
+ }
+ _rooms[MEETUP2]->removeSentence(1, 1);
+ }
+ _rooms[AIRLOCK]->getObject(4)->setProperty(WORN);
+ _rooms[AIRLOCK]->getObject(5)->setProperty(WORN);
+ _rooms[AIRLOCK]->getObject(6)->setProperty(WORN);
+ _rooms[CAVE]->getObject(1)->_exitRoom = MEETUP2;
+ _guiEnabled = true;
+ CursorMan.showMouse(true);
+}
+
+void GameManager::guardReturnedEvent() {
+ if (_currentRoom->getId() == GUARD)
+ busted(-1);
+ else if ((_currentRoom->getId() == CORRIDOR9) && (_currentRoom->isSectionVisible(27)))
+ busted(0);
+
+ _rooms[GUARD]->setSectionVisible(1, false);
+ _rooms[GUARD]->getObject(3)->_click = 0;
+ _rooms[GUARD]->setSectionVisible(6, false);
+ _rooms[GUARD]->getObject(2)->disableProperty(OPENED);
+ _rooms[GUARD]->setSectionVisible(7, false);
+ _rooms[GUARD]->getObject(5)->_click = 255;
+ _rooms[CORRIDOR9]->setSectionVisible(27, false);
+ _rooms[CORRIDOR9]->setSectionVisible(28, true);
+ _rooms[CORRIDOR9]->getObject(1)->disableProperty(OPENED);
+}
+
+void GameManager::walk(int imgId) {
+ if (_prevImgId)
+ _vm->renderImage(_prevImgId + 128);
+ _vm->renderImage(imgId);
+ _prevImgId = imgId;
+ wait2(3);
+}
+
+void GameManager::guardWalkEvent() {
+ _prevImgId = 0;
+ bool behind = (!_rooms[BCORRIDOR]->getObject(_state._origin + 4)->hasProperty(OCCUPIED) ||
+ _rooms[BCORRIDOR]->getObject(_state._origin + 4)->hasProperty(OPENED));
+ _rooms[BCORRIDOR]->getObject(_state._origin + 4)->disableProperty(OCCUPIED);
+ if (_currentRoom == _rooms[BCORRIDOR]) {
+ if (_vm->_messageDisplayed)
+ _vm->removeMessage();
+
+ if (!behind) {
+ _vm->renderImage(_state._origin + 1);
+ _prevImgId = _state._origin + 1;
+ _vm->playSound(kAudioDoorOpen);
+ wait2(3);
+ }
+
+ int imgId;
+ switch (_state._origin) {
+ case 0:
+ imgId = 11;
+ break;
+ case 1:
+ imgId = 16;
+ break;
+ case 2:
+ imgId = 15;
+ break;
+ case 3:
+ default:
+ imgId = 20;
+ break;
+ }
+ _vm->renderImage(imgId);
+ if (!behind) {
+ wait2(3);
+ _vm->renderImage(_prevImgId + 128);
+ _vm->playSound(kAudioDoorClose);
+ }
+
+ _prevImgId = imgId;
+ wait2(3);
+ switch (_state._origin) {
+ case 0:
+ walk(12);
+ walk(13);
+ break;
+ case 1:
+ walk(17);
+ walk(18);
+ break;
+ case 2:
+ walk(14);
+ walk(13);
+ break;
+ case 3:
+ walk(19);
+ walk(18);
+ }
+
+ if (!_state._playerHidden) {
+ if (_state._origin & 1)
+ walk(10);
+ else
+ walk(5);
+ busted(-1);
+ }
+
+ if ((_state._origin & 1) && !(_state._destination & 1)) {
+ for (int i = 10; i >= 5; i--)
+ walk(i);
+ walk(13);
+ } else if (!(_state._origin & 1) && (_state._destination & 1)) {
+ for (int i = 5; i <= 10; i++)
+ walk(i);
+ walk(18);
+ }
+
+ switch (_state._destination) {
+ case 0:
+ for (int i = 13; i >= 11; i--)
+ walk(i);
+ break;
+ case 1:
+ for (int i = 18; i >= 16; i--)
+ walk(i);
+ break;
+ case 2:
+ for (int i = 13; i <= 15; i++)
+ walk(i);
+ break;
+ case 3:
+ for (int i = 18; i <= 20; i++)
+ walk(i);
+ }
+
+ if (behind) {
+ _vm->renderImage(_state._destination + 1);
+ _vm->playSound(kAudioDoorOpen);
+ wait2(3);
+ _vm->renderImage(_prevImgId + 128);
+ wait2(3);
+ _vm->renderImage(_state._destination + 1 + 128);
+ _vm->playSound(kAudioDoorClose);
+ _rooms[BCORRIDOR]->getObject(_state._destination + 4)->setProperty(OCCUPIED);
+ _state._destination = 255;
+ } else if (_rooms[BCORRIDOR]->isSectionVisible(_state._destination + 1)) {
+ _vm->renderImage(_prevImgId + 128);
+ _rooms[BCORRIDOR]->getObject(_state._destination + 4)->setProperty(OCCUPIED);
+ SWAP(_state._origin, _state._destination);
+ _state._eventTime = _state._time + ticksToMsec(60);
+ _state._eventCallback = kGuardWalkFn;
+ } else {
+ wait2(18);
+ SWAP(_state._origin, _state._destination);
+ _state._eventCallback = kGuardWalkFn;
+ }
+ } else if (behind) {
+ _rooms[BCORRIDOR]->getObject(_state._destination + 4)->setProperty(OCCUPIED);
+ if (_currentRoom == _rooms[OFFICE_L1 + _state._destination])
+ busted(0);
+ _state._destination = 255;
+ } else if (_rooms[BCORRIDOR]->isSectionVisible(_state._destination + 1) && _rooms[OFFICE_L1 + _state._destination]->getObject(0)->hasProperty(OPENED)) {
+ _rooms[BCORRIDOR]->getObject(_state._destination + 4)->setProperty(OCCUPIED);
+ if (_currentRoom == _rooms[OFFICE_L1 + _state._destination])
+ busted(0);
+ SWAP(_state._origin, _state._destination);
+ _state._eventTime = _state._time + ticksToMsec(60);
+ _state._eventCallback = kGuardWalkFn;
+ } else {
+ SWAP(_state._origin, _state._destination);
+ _state._eventCallback = kGuardWalkFn;
+ }
+}
+
+void GameManager::taxiEvent() {
+ if (_currentRoom->getId() == SIGN) {
+ changeRoom(STATION);
+ _vm->renderRoom(*_currentRoom);
+ }
+
+ _vm->renderImage(1);
+ _vm->renderImage(2);
+ _vm->playSound(kAudioRocks);
+ screenShake();
+ _vm->renderImage(9);
+ _currentRoom->getObject(1)->setProperty(OPENED);
+ _vm->renderImage(1);
+ _currentRoom->setSectionVisible(2, false);
+ _vm->renderImage(3);
+ for (int i = 4; i <= 8; i++) {
+ wait2(2);
+ _vm->renderImage(invertSection(i - 1));
+ _vm->renderImage(i);
+ }
+ _rooms[SIGN]->setSectionVisible(2, false);
+ _rooms[SIGN]->setSectionVisible(3, true);
+}
+
+void GameManager::searchStartEvent() {
+ if ((_currentRoom >= _rooms[CORRIDOR1]) && (_currentRoom <= _rooms[BCORRIDOR]))
+ busted(0);
+ _state._corridorSearch = true;
+}
+
+void GameManager::outro() {
+ _vm->playSoundMod(kMusicOutro);
+ _vm->paletteFadeOut();
+ _vm->setCurrentImage(55);
+ _vm->renderImage(0);
+ _vm->paletteFadeIn();
+ getInput();
+ _vm->paletteFadeOut();
+ _vm->_brightness = 1;
+
+ Common::Event event;
+ event.type = Common::EVENT_RTL;
+ _vm->getEventManager()->pushEvent(event);
+}
+
+void GameManager::great(uint number) {
+ if (number && (_state._greatFlag & (1 << number)))
+ return;
+
+ _vm->playSound(kAudioSuccess);
+ _state._greatFlag |= 1 << number;
+}
+
+bool GameManager::airless() {
+ return (_currentRoom->getId() == HOLD ||
+ _currentRoom->getId() == LANDINGMODULE ||
+ _currentRoom->getId() == GENERATOR ||
+ _currentRoom->getId() == OUTSIDE ||
+ _currentRoom->getId() == ROCKS ||
+ _currentRoom->getId() == CAVE ||
+ _currentRoom->getId() == MEETUP ||
+ _currentRoom->getId() == MEETUP2 ||
+ _currentRoom->getId() == MEETUP3 ||
+ (_currentRoom->getId() == AIRLOCK && _rooms[AIRLOCK]->getObject(1)->hasProperty(OPENED)));
+}
+
+void GameManager::sentence(int number, bool brightness) {
+ if (number < 0)
+ return;
+ _vm->renderBox(0, 141 + _rowsStart[number] * 10, 320, _rows[number] * 10 - 1, brightness ? kColorWhite44 : kColorWhite25);
+ if (_texts[_rowsStart[number]] == kStringDialogSeparator)
+ _vm->renderText(kStringConversationEnd, 1, 142 + _rowsStart[number] * 10, brightness ? kColorRed : kColorDarkRed);
+ else {
+ for (int r = _rowsStart[number]; r < _rowsStart[number] + _rows[number]; ++r)
+ _vm->renderText(_texts[r], 1, 142 + r * 10, brightness ? kColorGreen : kColorDarkGreen);
+ }
+}
+
+void GameManager::say(StringID textId) {
+ Common::String str = _vm->getGameString(textId);
+ if (!str.empty())
+ say(str.c_str());
+}
+
+void GameManager::say(const char *text) {
+ Common::String t(text);
+ char *row[6];
+ Common::String::iterator p = t.begin();
+ uint numRows = 0;
+ while (*p) {
+ row[numRows++] = p;
+ while ((*p != '\0') && (*p != '|')) {
+ ++p;
+ }
+ if (*p == '|') {
+ *p = 0;
+ ++p;
+ }
+ }
+
+ _vm->renderBox(0, 138, 320, 62, kColorBlack);
+ _vm->renderBox(0, 141, 320, numRows * 10 - 1, kColorWhite25);
+ for (uint r = 0; r < numRows; ++r)
+ _vm->renderText(row[r], 1, 142 + r * 10, kColorDarkGreen);
+ waitOnInput((t.size() + 20) * _vm->_textSpeed / 10);
+ _vm->renderBox(0, 138, 320, 62, kColorBlack);
+}
+
+void GameManager::reply(StringID textId, int aus1, int aus2) {
+ Common::String str = _vm->getGameString(textId);
+ if (!str.empty())
+ reply(str.c_str(), aus1, aus2);
+}
+
+void GameManager::reply(const char *text, int aus1, int aus2) {
+ if (*text != '|')
+ _vm->renderMessage(text, kMessageTop);
+
+ for (int z = (strlen(text) + 20) * _vm->_textSpeed / 40; z > 0; --z) {
+ _vm->renderImage(aus1);
+ waitOnInput(2);
+ if (_keyPressed || _mouseClicked)
+ z = 1;
+ _vm->renderImage(aus2);
+ waitOnInput(2);
+ if (_keyPressed || _mouseClicked)
+ z = 1;
+ }
+ if (*text != '|')
+ _vm->removeMessage();
+}
+
+int GameManager::dialog(int num, byte rowLength[6], StringID text[6], int number) {
+ _vm->_allowLoadGame = false;
+ _guiEnabled = false;
+
+ bool remove[6];
+ for (int i = 0; i < 5; ++i)
+ remove[i] = _currentRoom->sentenceRemoved(i, number);
+ // The original does not initialize remove[5]!!!
+ // Set it to false/0. But maybe the loop above should use 6 instead of 5?
+ remove[5] = false;
+
+ _vm->renderBox(0, 138, 320, 62, kColorBlack);
+
+ for (int i = 0; i < 6 ; ++i)
+ _sentenceNumber[i] = -1;
+
+ int r = 0, rq = 0;
+ for (int i = 0; i < num; ++i) {
+ if (!remove[i]) {
+ _rowsStart[i] = r;
+ _rows[i] = rowLength[i];
+ for (int j = 0; j < _rows[i]; ++j, ++r, ++rq) {
+ _texts[r] = text[rq];
+ _sentenceNumber[r] = i;
+ }
+ sentence(i, false);
+ } else
+ rq += rowLength[i];
+ }
+
+ _currentSentence = -1;
+ do {
+ mouseInput3();
+ } while (_currentSentence == -1 && !_vm->shouldQuit());
+
+ _vm->renderBox(0, 138, 320, 62, kColorBlack);
+
+ if (number && _texts[_rowsStart[_currentSentence]] != kStringDialogSeparator)
+ _currentRoom->removeSentence(_currentSentence, number);
+
+ _guiEnabled = true;
+ _vm->_allowLoadGame = true;
+
+ return _currentSentence;
+}
+
+void GameManager::mousePosDialog(int x, int y) {
+ int a = y < 141 ? -1 : _sentenceNumber[(y - 141) / 10];
+ if (a != _currentSentence) {
+ sentence(_currentSentence, false);
+ _currentSentence = a;
+ sentence(_currentSentence, true);
+ }
+}
+
+void GameManager::turnOff() {
+ if (_state._powerOff)
+ return;
+
+ _state._powerOff = true;
+ roomBrightness();
+}
+
+void GameManager::turnOn() {
+ if (!_state._powerOff)
+ return;
+
+ _state._powerOff = false;
+ _vm->_brightness = 255;
+ _rooms[SLEEP]->setSectionVisible(1, false);
+ _rooms[SLEEP]->setSectionVisible(2, false);
+ _rooms[COCKPIT]->setSectionVisible(22, false);
+}
+
+void GameManager::takeObject(Object &obj) {
+ if (obj.hasProperty(CARRIED))
+ return;
+
+ if (obj._section != 0)
+ _vm->renderImage(obj._section);
+ obj._click = obj._click2 = 255;
+ _inventory.add(obj);
+}
+
+void GameManager::drawCommandBox() {
+ for (int i = 0; i < ARRAYSIZE(_guiCommandButton); ++i) {
+ _vm->renderBox(_guiCommandButton[i].left,
+ _guiCommandButton[i].top,
+ _guiCommandButton[i].width(),
+ _guiCommandButton[i].height(),
+ _guiCommandButton[i]._bgColor);
+ _vm->renderText(_guiCommandButton[i]._text,
+ _guiCommandButton[i]._textPosition.x,
+ _guiCommandButton[i]._textPosition.y,
+ _guiCommandButton[i]._textColor);
+ }
+}
+
+void GameManager::drawInventory() {
+ for (int i = 0; i < ARRAYSIZE(_guiInventory); ++i) {
+ _vm->renderBox(_guiInventory[i].left,
+ _guiInventory[i].top,
+ _guiInventory[i].width(),
+ _guiInventory[i].height(),
+ _guiInventory[i]._bgColor);
+
+ _vm->renderText(_inventory.get(i + _inventoryScroll)->_name,
+ _guiInventory[i]._textPosition.x,
+ _guiInventory[i]._textPosition.y,
+ _guiInventory[i]._textColor);
+ }
+
+ _vm->renderBox(_guiInventoryArrow[0].left,
+ _guiInventoryArrow[0].top,
+ _guiInventoryArrow[0].width(),
+ _guiInventoryArrow[0].height(),
+ _guiInventoryArrow[0]._bgColor);
+ _vm->renderBox(_guiInventoryArrow[1].left,
+ _guiInventoryArrow[1].top,
+ _guiInventoryArrow[1].width(),
+ _guiInventoryArrow[1].height(),
+ _guiInventoryArrow[1]._bgColor);
+ if (_inventory.getSize() > ARRAYSIZE(_guiInventory)) {
+ if (_inventoryScroll != 0) {
+ _vm->renderText(_guiInventoryArrow[0]._text,
+ _guiInventoryArrow[0]._textPosition.x,
+ _guiInventoryArrow[0]._textPosition.y,
+ _guiInventoryArrow[0]._textColor);
+ }
+ if (_inventoryScroll + ARRAYSIZE(_guiInventory) < _inventory.getSize()) {
+ _vm->renderText(_guiInventoryArrow[1]._text,
+ _guiInventoryArrow[1]._textPosition.x,
+ _guiInventoryArrow[1]._textPosition.y,
+ _guiInventoryArrow[1]._textColor);
+ }
+ }
+}
+
+uint16 GameManager::getKeyInput(bool blockForPrintChar) {
+ while (!_vm->shouldQuit()) {
+ _vm->updateEvents();
+ if (_keyPressed) {
+ if (blockForPrintChar) {
+ if (Common::isPrint(_key.keycode) ||
+ _key.keycode == Common::KEYCODE_BACKSPACE ||
+ _key.keycode == Common::KEYCODE_DELETE ||
+ _key.keycode == Common::KEYCODE_RETURN ||
+ _key.keycode == Common::KEYCODE_SPACE ||
+ _key.keycode == Common::KEYCODE_ESCAPE ||
+ _key.keycode == Common::KEYCODE_UP ||
+ _key.keycode == Common::KEYCODE_DOWN ||
+ _key.keycode == Common::KEYCODE_LEFT ||
+ _key.keycode == Common::KEYCODE_RIGHT) {
+ if (_key.flags & Common::KBD_SHIFT)
+ return toupper(_key.ascii);
+ else
+ return tolower(_key.ascii);
+ }
+ } else {
+ return _key.ascii;
+ }
+ }
+ g_system->updateScreen();
+ g_system->delayMillis(_vm->_delay);
+ }
+ return 0;
+}
+
+Common::EventType GameManager::getMouseInput() {
+ while (!_vm->shouldQuit()) {
+ _vm->updateEvents();
+ if (_mouseClicked)
+ return _mouseClickType;
+ g_system->updateScreen();
+ g_system->delayMillis(_vm->_delay);
+ }
+ return Common::EVENT_INVALID;
+}
+
+void GameManager::getInput() {
+ while (!_vm->shouldQuit()) {
+ _vm->updateEvents();
+ if (_mouseClicked || _keyPressed)
+ break;
+ g_system->updateScreen();
+ g_system->delayMillis(_vm->_delay);
+ }
+}
+
+void GameManager::mouseInput3() {
+ do {
+ _vm->updateEvents();
+ mousePosDialog(_mouseX, _mouseY);
+ g_system->updateScreen();
+ g_system->delayMillis(_vm->_delay);
+ } while (!_mouseClicked && !_vm->shouldQuit());
+}
+
+void GameManager::roomBrightness() {
+ _roomBrightness = 255;
+ if ((_currentRoom->getId() != OUTSIDE) && (_currentRoom->getId() < ROCKS) && _state._powerOff)
+ _roomBrightness = 153;
+ else if (_currentRoom->getId() == CAVE)
+ _roomBrightness = 0;
+ else if ((_currentRoom->getId() == GUARD3) && _state._powerOff)
+ _roomBrightness = 0;
+
+ if (_vm->_brightness != 0)
+ _vm->_brightness = _roomBrightness;
+
+ _vm->paletteBrightness();
+}
+
+void GameManager::changeRoom(RoomID id) {
+ _currentRoom = _rooms[id];
+ _newRoom = true;
+}
+
+void GameManager::wait2(int ticks) {
+ int32 end = _state._time + ticksToMsec(ticks);
+ do {
+ g_system->delayMillis(_vm->_delay);
+ _vm->updateEvents();
+ g_system->updateScreen();
+ } while (_state._time < end && !_vm->shouldQuit());
+}
+
+void GameManager::waitOnInput(int ticks) {
+ int32 end = _state._time + ticksToMsec(ticks);
+ do {
+ g_system->delayMillis(_vm->_delay);
+ _vm->updateEvents();
+ g_system->updateScreen();
+ } while (_state._time < end && !_vm->shouldQuit() && !_keyPressed && !_mouseClicked);
+}
+
+bool GameManager::waitOnInput(int ticks, Common::KeyCode &keycode) {
+ keycode = Common::KEYCODE_INVALID;
+ int32 end = _state._time + ticksToMsec(ticks);
+ do {
+ g_system->delayMillis(_vm->_delay);
+ _vm->updateEvents();
+ g_system->updateScreen();
+ if (_keyPressed) {
+ keycode = _key.keycode;
+ _key.reset();
+ return true;
+ } else if (_mouseClicked)
+ return true;
+ } while (_state._time < end && !_vm->shouldQuit());
+ return false;
+}
+
+void GameManager::setAnimationTimer(int ticks) {
+ _animationTimer = ticksToMsec(ticks);
+}
+
+void GameManager::handleTime() {
+ if (_timerPaused)
+ return;
+ int32 newTime = g_system->getMillis();
+ int32 delta = newTime - _oldTime;
+ _state._time += delta;
+ if (_state._time > 86400000) {
+ _state._time -= 86400000; // 24h wrap around
+ _state._alarmOn = (_state._timeAlarm > _state._time);
+ }
+ if (_animationTimer > delta)
+ _animationTimer -= delta;
+ else
+ _animationTimer = 0;
+
+ _oldTime = newTime;
+}
+
+void GameManager::pauseTimer(bool pause) {
+ if (pause == _timerPaused)
+ return;
+
+ if (pause) {
+ _timerPaused = true;
+ int32 delta = g_system->getMillis() - _oldTime;
+ _timePaused = _state._time + delta;
+ } else {
+ _state._time = _timePaused;
+ _oldTime = g_system->getMillis();
+ _timerPaused = false;
+ }
+}
+
+void GameManager::loadTime() {
+ pauseTimer(false);
+}
+
+void GameManager::saveTime() {
+ pauseTimer(true);
+}
+
+void GameManager::screenShake() {
+ for (int i = 0; i < 12; ++i) {
+ _vm->_system->setShakePos(8);
+ wait2(1);
+ _vm->_system->setShakePos(0);
+ wait2(1);
+ }
+}
+
+void GameManager::shock() {
+ _vm->playSound(kAudioShock);
+ dead(kStringShock);
+}
+
+void GameManager::showMenu() {
+ _vm->renderBox(0, 138, 320, 62, 0);
+ _vm->renderBox(0, 140, 320, 9, kColorWhite25);
+ drawCommandBox();
+ _vm->renderBox(281, 161, 39, 39, kColorWhite25);
+ drawInventory();
+}
+
+void GameManager::drawMapExits() {
+// TODO: Preload _exitList on room entry instead on every call
+ _vm->renderBox(281, 161, 39, 39, kColorWhite25);
+
+ for (int i = 0; i < 25; i++)
+ _exitList[i] = -1;
+ for (int i = 0; i < kMaxObject; i++) {
+ if (_currentRoom->getObject(i)->hasProperty(EXIT)) {
+ byte r = _currentRoom->getObject(i)->_direction;
+ _exitList[r] = i;
+ int x = 284 + 7 * (r % 5);
+ int y = 164 + 7 * (r / 5);
+ _vm->renderBox(x, y, 5, 5, kColorDarkRed);
+ }
+ }
+}
+
+void GameManager::animationOff() {
+ _animationEnabled = false;
+}
+
+void GameManager::animationOn() {
+ _animationEnabled = true;
+}
+
+void GameManager::edit(Common::String &input, int x, int y, uint length) {
+ bool isEditing = true;
+ uint cursorIndex = input.size();
+ // NOTE: Pixels for char needed = kFontWidth + 2px left and right side bearing
+ int overdrawWidth = ((int)((length + 1) * (kFontWidth + 2)) > (kScreenWidth - x)) ?
+ kScreenWidth - x : (length + 1) * (kFontWidth + 2);
+
+ while (isEditing) {
+ _vm->_textCursorX = x;
+ _vm->_textCursorY = y;
+ _vm->_textColor = kColorWhite99;
+ _vm->renderBox(x, y - 1, overdrawWidth, 9, kColorDarkBlue);
+ for (uint i = 0; i < input.size(); ++i) {
+ // Draw char highlight depending on cursor position
+ if (i == cursorIndex) {
+ _vm->renderBox(_vm->_textCursorX, y - 1, _vm->textWidth(input[i]), 9, kColorWhite99);
+ _vm->_textColor = kColorDarkBlue;
+ _vm->renderText(input[i]);
+ _vm->_textColor = kColorWhite99;
+ } else
+ _vm->renderText(input[i]);
+ }
+
+ if (cursorIndex == input.size()) {
+ _vm->renderBox(_vm->_textCursorX + 1, y - 1, 6, 9, kColorDarkBlue);
+ _vm->renderBox(_vm->_textCursorX , y - 1, 1, 9, kColorWhite99);
+ }
+
+ getKeyInput(true);
+ if (_vm->shouldQuit())
+ break;
+ switch (_key.keycode) {
+ case Common::KEYCODE_RETURN:
+ case Common::KEYCODE_ESCAPE:
+ isEditing = false;
+ break;
+ case Common::KEYCODE_UP:
+ case Common::KEYCODE_DOWN:
+ cursorIndex = input.size();
+ break;
+ case Common::KEYCODE_LEFT:
+ if (cursorIndex != 0)
+ --cursorIndex;
+ break;
+ case Common::KEYCODE_RIGHT:
+ if (cursorIndex != input.size())
+ ++cursorIndex;
+ break;
+ case Common::KEYCODE_DELETE:
+ if (cursorIndex != input.size())
+ input.deleteChar(cursorIndex);
+ break;
+ case Common::KEYCODE_BACKSPACE:
+ if (cursorIndex != 0) {
+ --cursorIndex;
+ input.deleteChar(cursorIndex);
+ }
+ break;
+ default:
+ if (Common::isPrint(_key.ascii) && input.size() < length) {
+ input.insertChar(_key.ascii, cursorIndex);
+ ++cursorIndex;
+ }
+ break;
+ }
+ }
+}
+
+void GameManager::shot(int a, int b) {
+ if (a)
+ _vm->renderImage(a);
+ _vm->playSound(kAudioGunShot);
+ wait2(2);
+ if (b)
+ _vm->renderImage(b);
+ wait2(2);
+ if (a)
+ _vm->renderImage(a);
+ _vm->playSound(kAudioGunShot);
+ wait2(2);
+ if (b)
+ _vm->renderImage(b);
+
+ dead(kStringShot);
+}
+
+void GameManager::takeMoney(int amount) {
+ Object *moneyObject = _rooms[INTRO]->getObject(4);
+ _state._money += amount;
+ _vm->setGameString(kStringInventoryMoney, Common::String::format("%d Xa", _state._money));
+
+ if (_state._money > 0) {
+ takeObject(*moneyObject);
+ if (amount > 0)
+ great(0);
+ } else {
+ _inventory.remove(*moneyObject);
+ }
+}
+
+void GameManager::drawStatus() {
+ int index = static_cast<int>(_inputVerb);
+ _vm->renderBox(0, 140, 320, 9, kColorWhite25);
+ _vm->renderText(_vm->getGameString(guiStatusCommands[index]), 1, 141, kColorDarkGreen);
+
+ if (Object::isNullObject(_inputObject[0]))
+ _vm->renderText(_currentInputObject->_name);
+ else {
+ _vm->renderText(_inputObject[0]->_name);
+ if (_inputVerb == ACTION_GIVE)
+ _vm->renderText(kPhrasalVerbParticleGiveTo);
+ else if (_inputVerb == ACTION_USE)
+ _vm->renderText(kPhrasalVerbParticleUseWith);
+
+ _vm->renderText(_currentInputObject->_name);
+ }
+}
+
+void GameManager::openLocker(const Room *room, Object *obj, Object *lock, int section) {
+ _vm->renderImage(section);
+ obj->setProperty(OPENED);
+ lock->_click = 255;
+ SWAP(obj->_click, obj->_click2);
+}
+
+void GameManager::closeLocker(const Room *room, Object *obj, Object *lock, int section) {
+ if (!obj->hasProperty(OPENED))
+ _vm->renderMessage(kStringCloseLocker_1);
+ else {
+ _vm->renderImage(invertSection(section));
+ obj->disableProperty(OPENED);
+ lock->_click = lock->_click2;
+ SWAP(obj->_click, obj->_click2);
+ }
+}
+
+void GameManager::dead(StringID messageId) {
+ _vm->paletteFadeOut();
+ _guiEnabled = false;
+ _vm->setCurrentImage(11);
+ _vm->renderImage(0);
+ _vm->renderMessage(messageId);
+ _vm->playSound(kAudioDeath);
+ _vm->paletteFadeIn();
+ getInput();
+ _vm->paletteFadeOut();
+ _vm->removeMessage();
+
+ // TODO: Load screen
+ destroyRooms();
+ initRooms();
+ initState();
+ initGui();
+ _inventory.clear();
+ changeRoom(CABIN_R3);
+ g_system->fillScreen(kColorBlack);
+ _vm->paletteFadeIn();
+
+ _guiEnabled = true;
+}
+
+int GameManager::invertSection(int section) {
+ if (section < 128)
+ section += 128;
+ else
+ section -= 128;
+
+ return section;
+}
+
+bool GameManager::isHelmetOff() {
+ Object *helmet = _inventory.get(HELMET);
+ if (helmet && helmet->hasProperty(WORN)) {
+ _vm->renderMessage(kStringIsHelmetOff_1);
+ return false;
+ }
+
+ return true;
+}
+
+bool GameManager::genericInteract(Action verb, Object &obj1, Object &obj2) {
+ if ((verb == ACTION_USE) && (obj1._id == SCHNUCK)) {
+ if (isHelmetOff()) {
+ takeObject(obj1);
+ _vm->renderMessage(kStringGenericInteract_1);
+ _inventory.remove(obj1);
+ }
+ } else if ((verb == ACTION_USE) && (obj1._id == EGG)) {
+ if (isHelmetOff()) {
+ takeObject(obj1);
+ if (obj1.hasProperty(OPENED))
+ _vm->renderMessage(kStringGenericInteract_1);
+ else
+ _vm->renderMessage(kStringGenericInteract_2);
+
+ _inventory.remove(obj1);
+ }
+ } else if ((verb == ACTION_OPEN) && (obj1._id == EGG)) {
+ takeObject(obj1);
+ if (obj1.hasProperty(OPENED))
+ _vm->renderMessage(kStringGenericInteract_3);
+ else {
+ takeObject(*_rooms[ENTRANCE]->getObject(8));
+ _vm->renderMessage(kStringGenericInteract_4);
+ obj1.setProperty(OPENED);
+ }
+ } else if ((verb == ACTION_USE) && (obj1._id == PILL)) {
+ if (isHelmetOff()) {
+ _vm->renderMessage(kStringGenericInteract_5);
+ great(0);
+ _inventory.remove(obj1);
+ _state._language = 2;
+ takeObject(*_rooms[ENTRANCE]->getObject(17));
+ }
+ } else if ((verb == ACTION_LOOK) && (obj1._id == PILL_HULL) &&
+ (_state._language == 2)) {
+ _vm->renderMessage(kStringGenericInteract_6);
+ _state._language = 1;
+ } else if ((verb == ACTION_OPEN) && (obj1._id == WALLET)) {
+ if (!_rooms[ROGER]->getObject(3)->hasProperty(CARRIED))
+ _vm->renderMessage(kStringGenericInteract_7);
+ else if (_rooms[ROGER]->getObject(7)->hasProperty(CARRIED))
+ _vm->renderMessage(kStringGenericInteract_8);
+ else {
+ _vm->renderMessage(kStringGenericInteract_9);
+ takeObject(*_rooms[ROGER]->getObject(7));
+ takeObject(*_rooms[ROGER]->getObject(8));
+ }
+ } else if ((verb == ACTION_LOOK) && (obj1._id == NEWSPAPER)) {
+ _vm->renderMessage(kStringGenericInteract_10);
+ waitOnInput(_timer1);
+ _vm->removeMessage();
+ _vm->renderMessage(kStringGenericInteract_11);
+ waitOnInput(_timer1);
+ _vm->removeMessage();
+ _vm->setCurrentImage(2);
+ _vm->renderImage(0);
+ _vm->setColor63(40);
+ getInput();
+ _vm->renderRoom(*_currentRoom);
+ roomBrightness();
+ _vm->renderMessage(kStringGenericInteract_12);
+ } else if ((verb == ACTION_LOOK) && (obj1._id == KEYCARD2)) {
+ _vm->renderMessage(obj1._description);
+ obj1._description = kStringKeycard2Description2;
+ } else if ((verb == ACTION_LOOK) && (obj1._id == WATCH))
+ _vm->renderMessage(kStringGenericInteract_13, kMessageNormal, timeToString(_state._time), timeToString(_state._timeAlarm));
+ else if ((verb == ACTION_PRESS) && (obj1._id == WATCH)) {
+ bool validInput = true;
+ int hours = 0;
+ int minutes = 0;
+
+ animationOff();
+ _vm->saveScreen(88, 87, 144, 24);
+ _vm->renderBox(88, 87, 144, 24, kColorWhite35);
+ _vm->renderText(kStringGenericInteract_14, 91, 90, kColorWhite99);
+ Common::String input;
+ do {
+ validInput = true;
+ input.clear();
+ _vm->renderBox(91, 99, 138, 9, kColorDarkBlue);
+ edit(input, 91, 100, 5);
+
+ int seperator = -1;
+ for (uint i = 0; i < input.size(); ++i) {
+ if (input[i] == ':') {
+ seperator = i;
+ break;
+ }
+ }
+ if ((seperator == -1) || (seperator > 2)) {
+ validInput = false;
+ continue;
+ }
+
+ int decimalPlace = 1;
+ for (int i = 0; i < seperator; ++i) {
+ if (Common::isDigit(input[i])) {
+ hours = hours * decimalPlace + (input[i] - '0');
+ decimalPlace *= 10;
+ } else {
+ validInput = false;
+ break;
+ }
+ }
+ decimalPlace = 1;
+ for (uint i = seperator + 1; i < input.size(); ++i) {
+ if (Common::isDigit(input[i])) {
+ minutes = minutes * decimalPlace + (input[i] - '0');
+ decimalPlace *= 10;
+ } else {
+ validInput = false;
+ break;
+ }
+ }
+ if ((hours > 23) || (minutes > 59))
+ validInput = false;
+
+ animationOn();
+ } while (!validInput && (_key.keycode != Common::KEYCODE_ESCAPE));
+
+ _vm->restoreScreen();
+ if (_key.keycode != Common::KEYCODE_ESCAPE) {
+ _state._timeAlarm = (hours * 60 + minutes) * 60 * 1000;
+ _state._alarmOn = (_state._timeAlarm > _state._time);
+ }
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, TERMINALSTRIP, WIRE)) {
+ Room *r = _rooms[CABIN_L3];
+ if (!r->getObject(8)->hasProperty(CARRIED)) {
+ if (r->isSectionVisible(26))
+ _vm->renderMessage(kStringTakeMessage);
+ else
+ return false;
+ } else {
+ r->getObject(8)->_name = kStringWireAndClip;
+ r = _rooms[HOLD];
+ _inventory.remove(*r->getObject(2));
+ _state._terminalStripConnected = true;
+ _state._terminalStripWire = true;
+ _vm->renderMessage(kStringOk);
+ }
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, TERMINALSTRIP, SPOOL)) {
+ Room *r = _rooms[CABIN_L2];
+ takeObject(*r->getObject(9));
+ r->getObject(9)->_name = kSringSpoolAndClip;
+ r = _rooms[HOLD];
+ _inventory.remove(*r->getObject(2));
+ _state._terminalStripConnected = true;
+ _vm->renderMessage(kStringOk);
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, WIRE, SPOOL)) {
+ Room *r = _rooms[CABIN_L3];
+ if (!_state._terminalStripConnected) {
+ if (r->isSectionVisible(26))
+ _vm->renderMessage(kStringCable3);
+ else
+ return false;
+ } else {
+ if (!r->getObject(8)->hasProperty(CARRIED))
+ _vm->renderMessage(kStringTakeMessage);
+ else {
+ r = _rooms[CABIN_L2];
+ takeObject(*r->getObject(9));
+ r = _rooms[CABIN_L3];
+ r->getObject(8)->_name = kStringGeneratorWire;
+ r = _rooms[CABIN_L2];
+ _inventory.remove(*r->getObject(9));
+ _state._cableConnected = true;
+ _vm->renderMessage(kStringOk);
+ }
+ }
+ } else if ((verb == ACTION_USE) && (obj1._id == SUIT)) {
+ takeObject(obj1);
+ if ((_currentRoom->getId() >= ENTRANCE) && (_currentRoom->getId() <= ROGER)) {
+ if (obj1.hasProperty(WORN)) {
+ _vm->renderMessage(kStringGenericInteract_15);
+ _rooms[AIRLOCK]->getObject(4)->disableProperty(WORN);
+ _rooms[AIRLOCK]->getObject(5)->disableProperty(WORN);
+ _rooms[AIRLOCK]->getObject(6)->disableProperty(WORN);
+ } else
+ _vm->renderMessage(kStringGenericInteract_16);
+ } else {
+ if (obj1.hasProperty(WORN)) {
+ Room *r = _rooms[AIRLOCK];
+ if (r->getObject(4)->hasProperty(WORN))
+ _vm->renderMessage(kStringGenericInteract_17);
+ else if (r->getObject(6)->hasProperty(WORN))
+ _vm->renderMessage(kStringGenericInteract_18);
+ else {
+ obj1.disableProperty(WORN);
+ _vm->renderMessage(kStringGenericInteract_19);
+ }
+ } else {
+ obj1.setProperty(WORN);
+ _vm->renderMessage(kStringGenericInteract_20);
+ }
+ }
+ } else if ((verb == ACTION_USE) && (obj1._id == HELMET)) {
+ takeObject(obj1);
+ if ((_currentRoom->getId() >= ENTRANCE) && (_currentRoom->getId() <= ROGER)) {
+ if (obj1.hasProperty(WORN)) {
+ _vm->renderMessage(kStringGenericInteract_21);
+ _rooms[AIRLOCK]->getObject(4)->disableProperty(WORN);
+ _rooms[AIRLOCK]->getObject(5)->disableProperty(WORN);
+ _rooms[AIRLOCK]->getObject(6)->disableProperty(WORN);
+ } else
+ _vm->renderMessage(kStringGenericInteract_22);
+ } else if (obj1.hasProperty(WORN)) {
+ obj1.disableProperty(WORN);
+ _vm->renderMessage(kStringGenericInteract_24);
+ getInput();
+ if (airless())
+ dead(kStringGenericInteract_23);
+ } else {
+ Room *r = _rooms[AIRLOCK];
+ if (r->getObject(5)->hasProperty(WORN)) {
+ obj1.setProperty(WORN);
+ _vm->renderMessage(kStringGenericInteract_25);
+ } else
+ _vm->renderMessage(kStringGenericInteract_26);
+ }
+ } else if ((verb == ACTION_USE) && (obj1._id == LIFESUPPORT)) {
+ takeObject(obj1);
+ if ((_currentRoom->getId() >= ENTRANCE) && (_currentRoom->getId() <= ROGER)) {
+ if (obj1.hasProperty(WORN)) {
+ _vm->renderMessage(kStringGenericInteract_21);
+ _rooms[AIRLOCK]->getObject(4)->disableProperty(WORN);
+ _rooms[AIRLOCK]->getObject(5)->disableProperty(WORN);
+ _rooms[AIRLOCK]->getObject(6)->disableProperty(WORN);
+ } else
+ _vm->renderMessage(kStringGenericInteract_22);
+ } else if (obj1.hasProperty(WORN)) {
+ obj1.disableProperty(WORN);
+ _vm->renderMessage(kStringGenericInteract_28);
+ getInput();
+ if (airless())
+ dead(kStringGenericInteract_27);
+ } else {
+ Room *r = _rooms[AIRLOCK];
+ if (r->getObject(5)->hasProperty(WORN)) {
+ obj1.setProperty(WORN);
+ _vm->renderMessage(kStringGenericInteract_29);
+ } else
+ _vm->renderMessage(kStringGenericInteract_26);
+ }
+ } else if ((verb == ACTION_WALK) && (obj1._id == BATHROOM_DOOR)) {
+ _rooms[BATHROOM]->getObject(2)->_exitRoom = _currentRoom->getId();
+ return false;
+ } else if ((verb == ACTION_USE) && Object::combine(obj1, obj2, WIRE, SOCKET))
+ _vm->renderMessage(kStringGenericInteract_30);
+ else if ((verb == ACTION_LOOK) && (obj1._id == BOOK2)) {
+ _vm->renderMessage(kStringGenericInteract_31);
+ waitOnInput(_timer1);
+ _vm->removeMessage();
+ _vm->renderMessage(kStringGenericInteract_32);
+ } else
+ return false;
+
+ return true;
+}
+
+void GameManager::handleInput() {
+ bool validCommand = genericInteract(_inputVerb, *_inputObject[0], *_inputObject[1]);
+ if (!validCommand)
+ validCommand = _currentRoom->interact(_inputVerb, *_inputObject[0], *_inputObject[1]);
+ if (!validCommand) {
+ switch (_inputVerb) {
+ case ACTION_LOOK:
+ _vm->renderMessage(_inputObject[0]->_description);
+ break;
+
+ case ACTION_WALK:
+ if (_inputObject[0]->hasProperty(CARRIED)) {
+ // You already carry this.
+ _vm->renderMessage(kStringGenericInteract_33);
+ } else if (!_inputObject[0]->hasProperty(EXIT)) {
+ // You're already there.
+ _vm->renderMessage(kStringGenericInteract_34);
+ } else if (_inputObject[0]->hasProperty(OPENABLE) && !_inputObject[0]->hasProperty(OPENED)) {
+ // This is closed
+ _vm->renderMessage(kStringShipHold9);
+ } else
+ changeRoom(_inputObject[0]->_exitRoom);
+
+ break;
+
+ case ACTION_TAKE:
+ if (_inputObject[0]->hasProperty(OPENED)) {
+ // You already have that
+ _vm->renderMessage(kStringGenericInteract_35);
+ } else if (_inputObject[0]->hasProperty(UNNECESSARY)) {
+ // You do not need that.
+ _vm->renderMessage(kStringGenericInteract_36);
+ } else if (!_inputObject[0]->hasProperty(TAKE)) {
+ // You can't take that.
+ _vm->renderMessage(kStringGenericInteract_37);
+ } else
+ takeObject(*_inputObject[0]);
+
+ break;
+
+ case ACTION_OPEN:
+ if (!_inputObject[0]->hasProperty(OPENABLE)) {
+ // This can't be opened
+ _vm->renderMessage(kStringGenericInteract_38);
+ } else if (_inputObject[0]->hasProperty(OPENED)) {
+ // This is already opened.
+ _vm->renderMessage(kStringGenericInteract_39);
+ } else if (_inputObject[0]->hasProperty(CLOSED)) {
+ // This is locked.
+ _vm->renderMessage(kStringGenericInteract_40);
+ } else {
+ _vm->renderImage(_inputObject[0]->_section);
+ _inputObject[0]->setProperty(OPENED);
+ byte i = _inputObject[0]->_click;
+ _inputObject[0]->_click = _inputObject[0]->_click2;
+ _inputObject[0]->_click2 = i;
+ _vm->playSound(kAudioDoorOpen);
+ }
+ break;
+
+ case ACTION_CLOSE:
+ if (!_inputObject[0]->hasProperty(OPENABLE) ||
+ (_inputObject[0]->hasProperty(CLOSED) &&
+ _inputObject[0]->hasProperty(OPENED))) {
+ // This can't be closed.
+ _vm->renderMessage(kStringGenericInteract_41);
+ } else if (!_inputObject[0]->hasProperty(OPENED)) {
+ // This is already closed.
+ _vm->renderMessage(kStringCloseLocker_1);
+ } else {
+ _vm->renderImage(invertSection(_inputObject[0]->_section));
+ _inputObject[0]->disableProperty(OPENED);
+ byte i = _inputObject[0]->_click;
+ _inputObject[0]->_click = _inputObject[0]->_click2;
+ _inputObject[0]->_click2 = i;
+ _vm->playSound(kAudioDoorClose);
+ }
+ break;
+
+ case ACTION_GIVE:
+ if (_inputObject[0]->hasProperty(CARRIED)) {
+ // Better keep it!
+ _vm->renderMessage(kStringGenericInteract_42);
+ }
+ break;
+
+ default:
+ // This is not possible.
+ _vm->renderMessage(kStringGenericInteract_43);
+ }
+ }
+}
+
+void GameManager::executeRoom() {
+ if (_processInput && !_vm->_messageDisplayed && _guiEnabled) {
+ handleInput();
+ if (_mouseClicked) {
+ Common::Event event;
+ event.type = Common::EVENT_MOUSEMOVE;
+ event.mouse = Common::Point(0, 0);
+ _vm->getEventManager()->pushEvent(event);
+ event.type = Common::EVENT_MOUSEMOVE;
+ event.mouse = Common::Point(_mouseX, _mouseY);
+ _vm->getEventManager()->pushEvent(event);
+ }
+
+ resetInputState();
+ }
+
+ if (_guiEnabled) {
+ if (!_vm->_messageDisplayed) {
+ g_system->fillScreen(kColorBlack);
+ _vm->renderRoom(*_currentRoom);
+ }
+ drawMapExits();
+ drawInventory();
+ drawStatus();
+ drawCommandBox();
+ }
+
+ roomBrightness();
+ if (_vm->_brightness == 0)
+ _vm->paletteFadeIn();
+
+ if (!_currentRoom->hasSeen() && _newRoom) {
+ _newRoom = false;
+ _currentRoom->onEntrance();
+ }
+}
+
+void GameManager::guardShot() {
+ _vm->renderImage(2);
+ _vm->renderImage(5);
+ wait2(3);
+ _vm->renderImage(2);
+
+ _vm->playSound(kAudioVoiceHalt);
+ while (_vm->_mixer->isSoundHandleActive(_vm->_soundHandle))
+ wait2(1);
+
+ _vm->renderImage(5);
+ wait2(5);
+ _vm->renderImage(3);
+ wait2(3);
+
+ shot(4, 3);
+}
+
+void GameManager::guard3Shot() {
+ _vm->renderImage(1);
+ wait2(3);
+ _vm->playSound(kAudioVoiceHalt); // 46/0
+ while (_vm->_mixer->isSoundHandleActive(_vm->_soundHandle))
+ wait2(1);
+
+ wait2(5);
+ _vm->renderImage(2);
+ wait2(3);
+ shot(3,2);
+}
+
+void GameManager::alarm() {
+ if (_rooms[INTRO]->getObject(2)->hasProperty(CARRIED)) {
+ alarmSound();
+ if (_currentRoom->getId() == GUARD)
+ guardShot();
+ else if (_currentRoom->getId() == CORRIDOR4 || _currentRoom->getId() == CORRIDOR7) {
+ guardNoticed();
+ _state._corridorSearch = true;
+ } else if (_currentRoom->getId() == GUARD3)
+ guard3Shot();
+ else if (_currentRoom->getId() == CORRIDOR1)
+ busted(33);
+ } else {
+ if (_currentRoom->getId() == CORRIDOR2 || _currentRoom->getId() == CORRIDOR4 ||
+ _currentRoom->getId() == GUARD || _currentRoom->getId() == CORRIDOR7 ||
+ _currentRoom->getId() == CELL)
+ {
+ alarmSound();
+ if (_currentRoom->getId() == GUARD)
+ guardShot();
+ guardNoticed();
+ if (_currentRoom->getId() == CORRIDOR4)
+ _state._corridorSearch = true;
+ }
+ _rooms[GUARD]->setSectionVisible(1, true);
+ _rooms[GUARD]->getObject(3)->_click = 255;
+ if (!_rooms[GUARD]->getObject(5)->hasProperty(CARRIED)) {
+ _rooms[GUARD]->setSectionVisible(7, true);
+ _rooms[GUARD]->getObject(5)->_click = 4;
+ }
+ _state._eventTime = _state._time + ticksToMsec(180);
+ _state._eventCallback = kGuardReturnedFn;
+ }
+}
+
+void GameManager::alarmSound() {
+ animationOff();
+ _vm->removeMessage();
+ _vm->renderMessage(kStringAlarm);
+
+ int32 end = _state._time + ticksToMsec(_timer1);
+ do {
+ _vm->playSound(kAudioAlarm);
+ while (_vm->_mixer->isSoundHandleActive(_vm->_soundHandle)) {
+ g_system->delayMillis(_vm->_delay);
+ _vm->updateEvents();
+ g_system->updateScreen();
+ }
+ } while (_state._time < end && !_vm->shouldQuit());
+
+ _vm->removeMessage();
+ animationOn();
+}
+
+}
diff --git a/engines/supernova/state.h b/engines/supernova/state.h
new file mode 100644
index 0000000000..bb0b933b00
--- /dev/null
+++ b/engines/supernova/state.h
@@ -0,0 +1,234 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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.
+ *
+ */
+
+#ifndef SUPERNOVA_STATE_H
+#define SUPERNOVA_STATE_H
+
+#include "common/rect.h"
+#include "common/keyboard.h"
+#include "supernova/rooms.h"
+
+namespace Supernova {
+
+const int32 kMaxTimerValue = 0x7FFFFFFF;
+
+enum EventFunction { kNoFn, kSupernovaFn, kGuardReturnedFn, kGuardWalkFn, kTaxiFn, kSearchStartFn };
+
+struct GameState {
+ int32 _time;
+ int32 _timeSleep;
+ int32 _timeAlarm;
+ int32 _eventTime;
+ EventFunction _eventCallback;
+ int32 _arrivalDaysLeft;
+ int32 _shipEnergyDaysLeft;
+ int32 _landingModuleEnergyDaysLeft;
+ uint16 _greatFlag;
+ int16 _timeRobot;
+ int16 _money;
+ byte _coins;
+ byte _shoes;
+ byte _origin;
+ byte _destination;
+ byte _language;
+ bool _corridorSearch;
+ bool _alarmOn;
+ bool _terminalStripConnected;
+ bool _terminalStripWire;
+ bool _cableConnected;
+ bool _powerOff;
+ bool _dream;
+ bool _nameSeen[4];
+ bool _playerHidden;
+};
+
+class Inventory {
+public:
+ Inventory(int &inventoryScroll)
+ : _numObjects(0)
+ , _inventoryScroll(inventoryScroll)
+ {}
+
+ void add(Object &obj);
+ void remove(Object &obj);
+ void clear();
+ Object *get(int index) const;
+ Object *get(ObjectID id) const;
+ int getSize() const { return _numObjects; }
+
+private:
+ Object *_inventory[kMaxCarry];
+ int &_inventoryScroll;
+ int _numObjects;
+};
+
+class GuiElement : public Common::Rect {
+public:
+ GuiElement();
+
+ void setSize(int x1, int y1, int x2, int y2);
+ void setText(const char *text);
+ void setTextPosition(int x, int y);
+ void setColor(int bgColor, int textColor, int bgColorHighlighted, int textColorHightlighted);
+ void setHighlight(bool isHighlighted);
+
+ Common::Point _textPosition;
+ char _text[128];
+ int _bgColor;
+ int _textColor;
+ int _bgColorNormal;
+ int _bgColorHighlighted;
+ int _textColorNormal;
+ int _textColorHighlighted;
+ bool _isHighlighted;
+};
+
+class GameManager {
+public:
+ GameManager(SupernovaEngine *vm);
+ ~GameManager();
+
+ void processInput(Common::KeyState &state);
+ void processInput();
+ void executeRoom();
+ bool serialize(Common::WriteStream *out);
+ bool deserialize(Common::ReadStream *in, int version);
+
+ static StringID guiCommands[];
+ static StringID guiStatusCommands[];
+ SupernovaEngine *_vm;
+ Common::KeyState _key;
+ Common::EventType _mouseClickType;
+ bool _mouseClicked;
+ bool _keyPressed;
+ int _mouseX;
+ int _mouseY;
+ int _mouseField;
+ Room *_currentRoom;
+ bool _newRoom;
+ Room *_rooms[NUMROOMS];
+ Inventory _inventory;
+ GameState _state;
+ bool _processInput;
+ bool _guiEnabled;
+ bool _animationEnabled;
+ byte _roomBrightness;
+ Action _inputVerb;
+ Object *_currentInputObject;
+ Object *_inputObject[2];
+ bool _waitEvent;
+ int32 _oldTime;
+ uint _timePaused;
+ bool _timerPaused;
+ int32 _timer1;
+ int32 _animationTimer;
+ int _inventoryScroll;
+ int _exitList[25];
+ GuiElement _guiCommandButton[10];
+ GuiElement _guiInventory[8];
+ GuiElement _guiInventoryArrow[2];
+ // 0 PC Speaker | 1 SoundBlaster | 2 No Sound
+ int _soundDevice;
+ // Dialog
+ int _currentSentence;
+ int _sentenceNumber[6];
+ StringID _texts[6];
+ byte _rows[6];
+ byte _rowsStart[6];
+
+ void takeObject(Object &obj);
+
+ void initState();
+ void initRooms();
+ void destroyRooms();
+ void initGui();
+ bool genericInteract(Action verb, Object &obj1, Object &obj2);
+ bool isHelmetOff();
+ void great(uint number);
+ bool airless();
+ void shock();
+ Common::EventType getMouseInput();
+ uint16 getKeyInput(bool blockForPrintChar = false);
+ void getInput();
+ void mouseInput3();
+ void wait2(int ticks);
+ void waitOnInput(int ticks);
+ bool waitOnInput(int ticks, Common::KeyCode &keycode);
+ void turnOff();
+ void turnOn();
+ void screenShake();
+ void roomBrightness();
+ void showMenu();
+ void animationOff();
+ void animationOn();
+ void openLocker(const Room *room, Object *obj, Object *lock, int section);
+ void closeLocker(const Room *room, Object *obj, Object *lock, int section);
+ void edit(Common::String &input, int x, int y, uint length);
+ int invertSection(int section);
+ void drawMapExits();
+ void drawStatus();
+ void drawCommandBox();
+ void drawInventory();
+ void changeRoom(RoomID id);
+ void resetInputState();
+ void handleInput();
+ void handleTime();
+ void pauseTimer(bool pause);
+ void loadTime();
+ void saveTime();
+ void setAnimationTimer(int ticks);
+ void dead(StringID messageId);
+ int dialog(int num, byte rowLength[6], StringID text[6], int number);
+ void sentence(int number, bool brightness);
+ void say(StringID textId);
+ void say(const char *text);
+ void reply(StringID textId, int aus1, int aus2);
+ void reply(const char *text, int aus1, int aus2);
+ void mousePosDialog(int x, int y);
+ void shot(int a, int b);
+ void takeMoney(int amount);
+ void search(int time);
+ void startSearch();
+ void guardNoticed();
+ void busted(int i);
+ void corridorOnEntrance();
+ void telomat(int number);
+ void novaScroll();
+ void supernovaEvent();
+ void guardReturnedEvent();
+ void walk(int a);
+ void guardWalkEvent();
+ void taxiEvent();
+ void searchStartEvent();
+ void outro();
+ void guardShot();
+ void guard3Shot();
+ void alarm();
+ void alarmSound();
+
+private:
+ int _prevImgId;
+};
+
+}
+
+#endif // SUPERNOVA_STATE_H
diff --git a/engines/supernova/supernova.cpp b/engines/supernova/supernova.cpp
new file mode 100644
index 0000000000..a9f29748f9
--- /dev/null
+++ b/engines/supernova/supernova.cpp
@@ -0,0 +1,1156 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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.
+ *
+ */
+
+#include "audio/mods/protracker.h"
+#include "common/config-manager.h"
+#include "common/debug.h"
+#include "common/debug-channels.h"
+#include "common/endian.h"
+#include "common/error.h"
+#include "common/events.h"
+#include "common/file.h"
+#include "common/fs.h"
+#include "common/memstream.h"
+#include "common/savefile.h"
+#include "common/str.h"
+#include "common/system.h"
+#include "common/translation.h"
+#include "engines/util.h"
+#include "graphics/cursorman.h"
+#include "graphics/surface.h"
+#include "graphics/screen.h"
+#include "graphics/palette.h"
+#include "graphics/thumbnail.h"
+#include "gui/saveload.h"
+
+#include "supernova/supernova.h"
+#include "supernova/state.h"
+
+namespace Supernova {
+
+const AudioInfo audioInfo[kAudioNumSamples] = {
+ {44, 0, -1},
+ {45, 0, -1},
+ {46, 0, 2510},
+ {46, 2510, 4020},
+ {46, 4020, -1},
+ {47, 0, 24010},
+ {47, 24010, -1},
+ {48, 0, 2510},
+ {48, 2510, 10520},
+ {48, 10520, 13530},
+ {48, 13530, -1},
+ {50, 0, 12786},
+ {50, 12786, -1},
+ {51, 0, -1},
+ {53, 0, -1},
+ {54, 0, 8010},
+ {54, 8010, 24020},
+ {54, 24020, 30030},
+ {54, 30030, 31040},
+ {54, 31040, -1}
+};
+
+const Object Object::nullObject;
+
+ObjectType operator|(ObjectType a, ObjectType b) {
+ return static_cast<ObjectType>(+a | +b);
+}
+
+ObjectType operator&(ObjectType a, ObjectType b) {
+ return static_cast<ObjectType>(+a & +b);
+}
+
+ObjectType operator^(ObjectType a, ObjectType b) {
+ return static_cast<ObjectType>(+a ^ +b);
+}
+
+ObjectType &operator|=(ObjectType &a, ObjectType b) {
+ return a = a | b;
+}
+
+ObjectType &operator&=(ObjectType &a, ObjectType b) {
+ return a = a & b;
+}
+
+ObjectType &operator^=(ObjectType &a, ObjectType b) {
+ return a = a ^ b;
+}
+
+SupernovaEngine::SupernovaEngine(OSystem *syst)
+ : Engine(syst)
+ , _console(NULL)
+ , _gm(NULL)
+ , _currentImage(NULL)
+ , _soundMusicIntro(NULL)
+ , _soundMusicOutro(NULL)
+ , _rnd("supernova")
+ , _brightness(255)
+ , _menuBrightness(255)
+ , _delay(33)
+ , _textSpeed(kTextSpeed[2])
+ , _screenWidth(320)
+ , _screenHeight(200)
+ , _messageDisplayed(false)
+ , _allowLoadGame(true)
+ , _allowSaveGame(true)
+{
+// const Common::FSNode gameDataDir(ConfMan.get("path"));
+// SearchMan.addSubDirectoryMatching(gameDataDir, "sound");
+
+ if (ConfMan.hasKey("textspeed"))
+ _textSpeed = ConfMan.getInt("textspeed");
+
+ // setup engine specific debug channels
+ DebugMan.addDebugChannel(kDebugGeneral, "general", "Supernova general debug channel");
+}
+
+SupernovaEngine::~SupernovaEngine() {
+ DebugMan.clearAllDebugChannels();
+
+ delete _currentImage;
+ delete _console;
+ delete _gm;
+ delete _soundMusicIntro;
+ delete _soundMusicOutro;
+}
+
+Common::Error SupernovaEngine::run() {
+ Graphics::ModeList modes;
+ modes.push_back(Graphics::Mode(320, 200));
+ modes.push_back(Graphics::Mode(640, 480));
+ initGraphicsModes(modes);
+ initGraphics(_screenWidth, _screenHeight);
+
+ Common::Error status = loadGameStrings();
+ if (status.getCode() != Common::kNoError)
+ return status;
+
+ _gm = new GameManager(this);
+ _console = new Console(this, _gm);
+
+ initData();
+ initPalette();
+
+ CursorMan.replaceCursor(_mouseNormal, 16, 16, 0, 0, kColorCursorTransparent);
+ CursorMan.replaceCursorPalette(initVGAPalette, 0, 16);
+ CursorMan.showMouse(true);
+
+ setTotalPlayTime(0);
+
+ int saveSlot = ConfMan.getInt("save_slot");
+ if (saveSlot >= 0) {
+ if (loadGameState(saveSlot).getCode() != Common::kNoError)
+ error("Failed to load save game from slot %i", saveSlot);
+ }
+
+ while (!shouldQuit()) {
+ uint32 start = _system->getMillis();
+ updateEvents();
+ _gm->executeRoom();
+ _console->onFrame();
+ _system->updateScreen();
+ int end = _delay - (_system->getMillis() - start);
+ if (end > 0)
+ _system->delayMillis(end);
+ }
+
+ stopSound();
+
+ return Common::kNoError;
+}
+
+void SupernovaEngine::updateEvents() {
+ _gm->handleTime();
+ if (_gm->_animationEnabled && !_messageDisplayed && _gm->_animationTimer == 0)
+ _gm->_currentRoom->animation();
+
+ if (_gm->_state._eventCallback != kNoFn && _gm->_state._time >= _gm->_state._eventTime) {
+ _allowLoadGame = false;
+ _allowSaveGame = false;
+ _gm->_state._eventTime = kMaxTimerValue;
+ EventFunction fn = _gm->_state._eventCallback;
+ _gm->_state._eventCallback = kNoFn;
+ switch (fn) {
+ case kNoFn:
+ break;
+ case kSupernovaFn:
+ _gm->supernovaEvent();
+ break;
+ case kGuardReturnedFn:
+ _gm->guardReturnedEvent();
+ break;
+ case kGuardWalkFn:
+ _gm->guardWalkEvent();
+ break;
+ case kTaxiFn:
+ _gm->taxiEvent();
+ break;
+ case kSearchStartFn:
+ _gm->searchStartEvent();
+ break;
+ }
+ _allowLoadGame = true;
+ _allowSaveGame = true;
+ return;
+ }
+
+ if (_gm->_state._alarmOn && _gm->_state._timeAlarm <= _gm->_state._time) {
+ _gm->_state._alarmOn = false;
+ _gm->alarm();
+ return;
+ }
+
+ _gm->_mouseClicked = false;
+ _gm->_keyPressed = false;
+ Common::Event event;
+ while (g_system->getEventManager()->pollEvent(event)) {
+ switch (event.type) {
+ case Common::EVENT_KEYDOWN:
+ _gm->_keyPressed = true;
+ if (event.kbd.keycode == Common::KEYCODE_d &&
+ (event.kbd.flags & Common::KBD_CTRL)) {
+ _console->attach();
+ }
+ if (event.kbd.keycode == Common::KEYCODE_x &&
+ (event.kbd.flags & Common::KBD_CTRL)) {
+ // TODO: Draw exit box
+ }
+
+ _gm->processInput(event.kbd);
+ break;
+
+ case Common::EVENT_LBUTTONUP:
+ // fallthrough
+ case Common::EVENT_RBUTTONUP:
+ if (_gm->_currentRoom->getId() != INTRO && _mixer->isSoundHandleActive(_soundHandle))
+ return;
+ _gm->_mouseClicked = true;
+ // fallthrough
+ case Common::EVENT_MOUSEMOVE:
+ _gm->_mouseClickType = event.type;
+ _gm->_mouseX = event.mouse.x;
+ _gm->_mouseY = event.mouse.y;
+ if (_gm->_guiEnabled)
+ _gm->processInput();
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+bool SupernovaEngine::hasFeature(EngineFeature f) const {
+ switch (f) {
+ case kSupportsRTL:
+ return true;
+ case kSupportsLoadingDuringRuntime:
+ return true;
+ case kSupportsSavingDuringRuntime:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void SupernovaEngine::pauseEngineIntern(bool pause) {
+ _mixer->pauseAll(pause);
+ _gm->pauseTimer(pause);
+}
+
+Common::Error SupernovaEngine::loadGameStrings() {
+ Common::String cur_lang = ConfMan.get("language");
+ Common::String string_id("TEXT");
+
+ // Note: we don't print any warning or errors here if we cannot find the file
+ // or the format is not as expected. We will get those warning when reading the
+ // strings anyway (actually the engine will even refuse to start).
+ Common::File f;
+ if (!f.open(SUPERNOVA_DAT)) {
+ Common::String msg = Common::String::format(_("Unable to locate the '%s' engine data file."), SUPERNOVA_DAT);
+ GUIErrorMessage(msg);
+ return Common::kReadingFailed;
+ }
+
+ // Validate the data file header
+ char id[5], lang[5];
+ id[4] = lang[4] = '\0';
+ f.read(id, 3);
+ if (strncmp(id, "MSN", 3) != 0) {
+ Common::String msg = Common::String::format(_("The '%s' engine data file is corrupt."), SUPERNOVA_DAT);
+ GUIErrorMessage(msg);
+ return Common::kReadingFailed;
+ }
+
+ int version = f.readByte();
+ if (version != SUPERNOVA_DAT_VERSION) {
+ Common::String msg = Common::String::format(
+ _("Incorrect version of the '%s' engine data file found. Expected %d but got %d."),
+ SUPERNOVA_DAT, SUPERNOVA_DAT_VERSION, version);
+ GUIErrorMessage(msg);
+ return Common::kReadingFailed;
+ }
+
+ while (!f.eos()) {
+ f.read(id, 4);
+ f.read(lang, 4);
+ uint32 size = f.readUint32LE();
+ if (f.eos())
+ break;
+ if (string_id == id && cur_lang == lang) {
+ while (size > 0) {
+ Common::String s;
+ char ch;
+ while ((ch = (char)f.readByte()) != '\0')
+ s += ch;
+ _gameStrings.push_back(s);
+ size -= s.size() + 1;
+ }
+ return Common::kNoError;
+ } else
+ f.skip(size);
+ }
+
+ Common::Language l = Common::parseLanguage(cur_lang);
+ Common::String msg = Common::String::format(_("Unable to locate the text for %s language in '%s' engine data file."), Common::getLanguageDescription(l), SUPERNOVA_DAT);
+ GUIErrorMessage(msg);
+ return Common::kReadingFailed;
+}
+
+void SupernovaEngine::initData() {
+ // Sound
+ // Note:
+ // - samples start with a header of 6 bytes: 01 SS SS 00 AD 00
+ // where SS SS (LE uint16) is the size of the sound sample + 2
+ // - samples end with a footer of 4 bytes: 00 00
+ // Skip those in the buffer
+ Common::File file;
+
+ for (int i = 0; i < kAudioNumSamples; ++i) {
+ if (!file.open(Common::String::format("msn_data.%03d", audioInfo[i]._filenumber))) {
+ error("File %s could not be read!", file.getName());
+ }
+
+ if (audioInfo[i]._offsetEnd == -1) {
+ file.seek(0, SEEK_END);
+ _soundSamples[i]._length = file.pos() - audioInfo[i]._offsetStart - 10;
+ } else {
+ _soundSamples[i]._length = audioInfo[i]._offsetEnd - audioInfo[i]._offsetStart - 10;
+ }
+ _soundSamples[i]._buffer = new byte[_soundSamples[i]._length];
+ file.seek(audioInfo[i]._offsetStart + 6);
+ file.read(_soundSamples[i]._buffer, _soundSamples[i]._length);
+ file.close();
+ }
+
+ _soundMusicIntro = convertToMod("msn_data.049");
+ _soundMusicOutro = convertToMod("msn_data.052");
+
+ // Cursor
+ const uint16 *bufferNormal = reinterpret_cast<const uint16 *>(mouseNormal);
+ const uint16 *bufferWait = reinterpret_cast<const uint16 *>(mouseWait);
+ for (uint i = 0; i < sizeof(mouseNormal) / 4; ++i) {
+ for (uint bit = 0; bit < 16; ++bit) {
+ uint mask = 0x8000 >> bit;
+ uint bitIndex = i * 16 + bit;
+
+ _mouseNormal[bitIndex] = (READ_LE_UINT16(bufferNormal + i) & mask) ? kColorCursorTransparent : kColorBlack;
+ if (READ_LE_UINT16(bufferNormal + i + 16) & mask)
+ _mouseNormal[bitIndex] = kColorLightRed;
+ _mouseWait[bitIndex] = (READ_LE_UINT16(bufferWait + i) & mask) ? kColorCursorTransparent : kColorBlack;
+ if (READ_LE_UINT16(bufferWait + i + 16) & mask)
+ _mouseWait[bitIndex] = kColorLightRed;
+ }
+ }
+}
+
+void SupernovaEngine::initPalette() {
+ _system->getPaletteManager()->setPalette(initVGAPalette, 0, 256);
+}
+
+void SupernovaEngine::playSound(AudioIndex sample) {
+ if (sample > kAudioNumSamples - 1)
+ return;
+
+ Audio::SeekableAudioStream *audioStream = Audio::makeRawStream(
+ _soundSamples[sample]._buffer, _soundSamples[sample]._length,
+ 11931, Audio::FLAG_UNSIGNED | Audio::FLAG_LITTLE_ENDIAN, DisposeAfterUse::NO);
+ stopSound();
+ _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, audioStream);
+}
+
+void SupernovaEngine::stopSound() {
+ if (_mixer->isSoundHandleActive(_soundHandle))
+ _mixer->stopHandle(_soundHandle);
+}
+
+void SupernovaEngine::playSoundMod(int filenumber)
+{
+ Audio::AudioStream *audioStream;
+ if (filenumber == 49)
+ audioStream = Audio::makeProtrackerStream(_soundMusicIntro);
+ else if (filenumber == 52)
+ audioStream = Audio::makeProtrackerStream(_soundMusicOutro);
+ else
+ return;
+
+ stopSound();
+ _mixer->playStream(Audio::Mixer::kMusicSoundType, &_soundHandle, audioStream,
+ -1, Audio::Mixer::kMaxChannelVolume, 0);
+}
+
+void SupernovaEngine::renderImageSection(int section) {
+ // Note: inverting means we are removing the section. So we should get the rect for that
+ // section but draw the background (section 0) instead.
+ bool invert = false;
+ if (section > 128) {
+ section -= 128;
+ invert = true;
+ }
+ if (!_currentImage || section > _currentImage->_numSections - 1)
+ return;
+
+ Common::Rect sectionRect(_currentImage->_section[section].x1,
+ _currentImage->_section[section].y1,
+ _currentImage->_section[section].x2 + 1,
+ _currentImage->_section[section].y2 + 1) ;
+ if (_currentImage->_filenumber == 1 || _currentImage->_filenumber == 2) {
+ sectionRect.setWidth(640);
+ sectionRect.setHeight(480);
+ if (_screenWidth != 640) {
+ _screenWidth = 640;
+ _screenHeight = 480;
+ initGraphics(_screenWidth, _screenHeight);
+ }
+ } else {
+ if (_screenWidth != 320) {
+ _screenWidth = 320;
+ _screenHeight = 200;
+ initGraphics(_screenWidth, _screenHeight);
+ }
+ }
+
+ uint offset = 0;
+ int pitch = sectionRect.width();
+ if (invert) {
+ pitch = _currentImage->_pitch;
+ offset = _currentImage->_section[section].y1 * pitch + _currentImage->_section[section].x1;
+ section = 0;
+ }
+
+ _system->copyRectToScreen(static_cast<const byte *>(_currentImage->_sectionSurfaces[section]->getPixels()) + offset,
+ pitch,
+ sectionRect.left, sectionRect.top,
+ sectionRect.width(), sectionRect.height());
+}
+
+void SupernovaEngine::renderImage(int section) {
+ if (!_currentImage)
+ return;
+
+ bool sectionVisible = true;
+
+ if (section > 128) {
+ sectionVisible = false;
+ section -= 128;
+ }
+
+ _gm->_currentRoom->setSectionVisible(section, sectionVisible);
+
+ do {
+ if (sectionVisible)
+ renderImageSection(section);
+ else
+ renderImageSection(section + 128);
+ section = _currentImage->_section[section].next;
+ } while (section != 0);
+}
+
+bool SupernovaEngine::setCurrentImage(int filenumber) {
+ if (_currentImage && _currentImage->_filenumber == filenumber)
+ return true;
+
+ delete _currentImage;
+ _currentImage = new MSNImageDecoder();
+ if (!_currentImage->init(filenumber)) {
+ delete _currentImage;
+ _currentImage = NULL;
+ return false;
+ }
+
+ _system->getPaletteManager()->setPalette(_currentImage->getPalette(), 16, 239);
+ paletteBrightness();
+ return true;
+}
+
+void SupernovaEngine::saveScreen(int x, int y, int width, int height) {
+ _screenBuffer.push(x, y, width, height);
+}
+
+void SupernovaEngine::restoreScreen() {
+ _screenBuffer.restore();
+}
+
+void SupernovaEngine::renderRoom(Room &room) {
+ if (room.getId() == INTRO)
+ return;
+
+ if (setCurrentImage(room.getFileNumber())) {
+ for (int i = 0; i < _currentImage->_numSections; ++i) {
+ int section = i;
+ if (room.isSectionVisible(section)) {
+ do {
+ renderImageSection(section);
+ section = _currentImage->_section[section].next;
+ } while (section != 0);
+ }
+ }
+ }
+}
+
+int SupernovaEngine::textWidth(const uint16 key) {
+ char text[2];
+ text[0] = key & 0xFF;
+ text[1] = 0;
+ return textWidth(text);
+}
+
+int SupernovaEngine::textWidth(const char *text) {
+ int charWidth = 0;
+ while (*text != '\0') {
+ byte c = *text++;
+ if (c < 32) {
+ continue;
+ } else if (c == 225) {
+ c = 35;
+ }
+
+ for (uint i = 0; i < 5; ++i) {
+ if (font[c - 32][i] == 0xff) {
+ break;
+ }
+ ++charWidth;
+ }
+ ++charWidth;
+ }
+
+ return charWidth;
+}
+
+void SupernovaEngine::renderMessage(const char *text, MessagePosition position) {
+ Common::String t(text);
+ char *row[20];
+ Common::String::iterator p = t.begin();
+ uint numRows = 0;
+ int rowWidthMax = 0;
+ int x = 0;
+ int y = 0;
+ byte textColor = 0;
+
+ while (*p != '\0') {
+ row[numRows] = p;
+ ++numRows;
+ while ((*p != '\0') && (*p != '|')) {
+ ++p;
+ }
+ if (*p == '|') {
+ *p = '\0';
+ ++p;
+ }
+ }
+ for (uint i = 0; i < numRows; ++i) {
+ int rowWidth = textWidth(row[i]);
+ if (rowWidth > rowWidthMax)
+ rowWidthMax = rowWidth;
+ }
+
+ switch (position) {
+ case kMessageNormal:
+ x = 160 - rowWidthMax / 2;
+ textColor = kColorWhite99;
+ break;
+ case kMessageTop:
+ x = 160 - rowWidthMax / 2;
+ textColor = kColorLightYellow;
+ break;
+ case kMessageCenter:
+ x = 160 - rowWidthMax / 2;
+ textColor = kColorLightRed;
+ break;
+ case kMessageLeft:
+ x = 3;
+ textColor = kColorLightYellow;
+ break;
+ case kMessageRight:
+ x = 317 - rowWidthMax;
+ textColor = kColorLightGreen;
+ break;
+ }
+
+ if (position == kMessageNormal) {
+ y = 70 - ((numRows * 9) / 2);
+ } else if (position == kMessageTop) {
+ y = 5;
+ } else {
+ y = 142;
+ }
+
+ int message_columns = x - 3;
+ int message_rows = y - 3;
+ int message_width = rowWidthMax + 6;
+ int message_height = numRows * 9 + 5;
+ saveScreen(message_columns, message_rows, message_width, message_height);
+ renderBox(message_columns, message_rows, message_width, message_height, kColorWhite35);
+ for (uint i = 0; i < numRows; ++i) {
+ renderText(row[i], x, y, textColor);
+ y += 9;
+ }
+
+ _messageDisplayed = true;
+ _gm->_timer1 = (Common::strnlen(text, 512) + 20) * _textSpeed / 10;
+}
+
+void SupernovaEngine::removeMessage() {
+ if (_messageDisplayed) {
+ restoreScreen();
+ _messageDisplayed = false;
+ }
+}
+
+void SupernovaEngine::renderText(const char *text, int x, int y, byte color) {
+ Graphics::Surface *screen = _system->lockScreen();
+ byte *cursor = static_cast<byte *>(screen->getBasePtr(x, y));
+ const byte *basePtr = cursor;
+
+ byte c;
+ while ((c = *text++) != '\0') {
+ if (c < 32) {
+ continue;
+ } else if (c == 225) {
+ c = 128;
+ }
+
+ for (uint i = 0; i < 5; ++i) {
+ if (font[c - 32][i] == 0xff) {
+ break;
+ }
+
+ byte *ascentLine = cursor;
+ for (byte j = font[c - 32][i]; j != 0; j >>= 1) {
+ if (j & 1) {
+ *cursor = color;
+ }
+ cursor += kScreenWidth;
+ }
+ cursor = ++ascentLine;
+ }
+ ++cursor;
+ }
+ _system->unlockScreen();
+
+ uint numChars = cursor - basePtr;
+ uint absPosition = y * kScreenWidth + x + numChars;
+ _textCursorX = absPosition % kScreenWidth;
+ _textCursorY = absPosition / kScreenWidth;
+ _textColor = color;
+}
+
+void SupernovaEngine::renderText(const uint16 character, int x, int y, byte color) {
+ char text[2];
+ text[0] = character & 0xFF;
+ text[1] = 0;
+ renderText(text, x, y, color);
+}
+
+void SupernovaEngine::renderText(const char *text) {
+ renderText(text, _textCursorX, _textCursorY, _textColor);
+}
+
+void SupernovaEngine::renderText(const uint16 character) {
+ char text[2];
+ text[0] = character & 0xFF;
+ text[1] = 0;
+ renderText(text, _textCursorX, _textCursorY, _textColor);
+}
+
+void SupernovaEngine::renderBox(int x, int y, int width, int height, byte color) {
+ Graphics::Surface *screen = _system->lockScreen();
+ screen->fillRect(Common::Rect(x, y, x + width, y + height), color);
+ _system->unlockScreen();
+}
+
+void SupernovaEngine::paletteBrightness() {
+ byte palette[768];
+
+ _system->getPaletteManager()->grabPalette(palette, 0, 255);
+ for (uint i = 0; i < 48; ++i) {
+ palette[i] = (initVGAPalette[i] * _menuBrightness) >> 8;
+ }
+ for (uint i = 0; i < 717; ++i) {
+ const byte *imagePalette;
+ if (_currentImage && _currentImage->getPalette()) {
+ imagePalette = _currentImage->getPalette();
+ } else {
+ imagePalette = palette + 48;
+ }
+ palette[i + 48] = (imagePalette[i] * _brightness) >> 8;
+ }
+ _system->getPaletteManager()->setPalette(palette, 0, 255);
+}
+
+void SupernovaEngine::paletteFadeOut() {
+ while (_menuBrightness > 10) {
+ _menuBrightness -= 10;
+ if (_brightness > _menuBrightness)
+ _brightness = _menuBrightness;
+ paletteBrightness();
+ _system->updateScreen();
+ _system->delayMillis(_delay);
+ }
+ _menuBrightness = 0;
+ _brightness = 0;
+ paletteBrightness();
+ _system->updateScreen();
+}
+
+void SupernovaEngine::paletteFadeIn() {
+ while (_menuBrightness < 245) {
+ if (_brightness < _gm->_roomBrightness)
+ _brightness += 10;
+ _menuBrightness += 10;
+ paletteBrightness();
+ _system->updateScreen();
+ _system->delayMillis(_delay);
+ }
+ _menuBrightness = 255;
+ _brightness = _gm->_roomBrightness;
+ paletteBrightness();
+ _system->updateScreen();
+}
+
+void SupernovaEngine::setColor63(byte value) {
+ byte color[3] = {value, value, value};
+ _system->getPaletteManager()->setPalette(color, 63, 1);
+}
+
+void SupernovaEngine::setTextSpeed() {
+ const Common::String& textSpeedString = getGameString(kStringTextSpeed);
+ int stringWidth = textWidth(textSpeedString);
+ int textX = (320 - stringWidth) / 2;
+ int textY = 100;
+ stringWidth += 4;
+ int boxX = stringWidth > 110 ? (320 - stringWidth) / 2 : 105;
+ int boxY = 97;
+ int boxWidth = stringWidth > 110 ? stringWidth : 110;
+ int boxHeight = 27;
+
+ _gm->animationOff();
+ _gm->saveTime();
+ saveScreen(boxX, boxY, boxWidth, boxHeight);
+
+ renderBox(boxX, boxY, boxWidth, boxHeight, kColorBlue);
+ renderText(textSpeedString, textX, textY, kColorWhite99); // Text speed
+
+ // Find the closest index in kTextSpeed for the current _textSpeed.
+ // Important note: values in kTextSpeed decrease with the index.
+ int speedIndex = 0;
+ while (speedIndex < 4 && _textSpeed < (kTextSpeed[speedIndex] + kTextSpeed[speedIndex+1]) / 2)
+ ++speedIndex;
+
+ char nbString[2];
+ nbString[1] = 0;
+ for (int i = 0; i < 5; ++i) {
+ byte color = i == speedIndex ? kColorWhite63 : kColorWhite35;
+ renderBox(110 + 21 * i, 111, 16, 10, color);
+
+ nbString[0] = '1' + i;
+ renderText(nbString, 115 + 21 * i, 112, kColorWhite99);
+ }
+ do {
+ _gm->getInput();
+ int key = _gm->_keyPressed ? _gm->_key.keycode : Common::KEYCODE_INVALID;
+ if (!_gm->_keyPressed && _gm->_mouseClicked && _gm->_mouseY >= 111 && _gm->_mouseY < 121 && (_gm->_mouseX + 16) % 21 < 16)
+ key = Common::KEYCODE_0 - 5 + (_gm->_mouseX + 16) / 21;
+ if (key == Common::KEYCODE_ESCAPE)
+ break;
+ else if (key >= Common::KEYCODE_1 && key <= Common::KEYCODE_5) {
+ speedIndex = key - Common::KEYCODE_1;
+ _textSpeed = kTextSpeed[speedIndex];
+ ConfMan.setInt("textspeed", _textSpeed);
+ break;
+ }
+ } while (!shouldQuit());
+ _gm->resetInputState();
+
+ restoreScreen();
+ _gm->loadTime();
+ _gm->animationOn();
+}
+
+Common::MemoryReadStream *SupernovaEngine::convertToMod(const char *filename, int version) {
+ // MSN format
+ struct {
+ uint16 seg;
+ uint16 start;
+ uint16 end;
+ uint16 loopStart;
+ uint16 loopEnd;
+ char volume;
+ char dummy[5];
+ } instr2[22];
+ int nbInstr2; // 22 for version1, 15 for version 2
+ int16 songLength;
+ char arrangement[128];
+ int16 patternNumber;
+ int32 note2[28][64][4];
+
+ nbInstr2 = ((version == 1) ? 22 : 15);
+
+ Common::File msnFile;
+ msnFile.open(filename);
+ if (!msnFile.isOpen()) {
+ warning("Data file '%s' not found", msnFile.getName());
+ return NULL;
+ }
+
+ for (int i = 0 ; i < nbInstr2 ; ++i) {
+ instr2[i].seg = msnFile.readUint16LE();
+ instr2[i].start = msnFile.readUint16LE();
+ instr2[i].end = msnFile.readUint16LE();
+ instr2[i].loopStart = msnFile.readUint16LE();
+ instr2[i].loopEnd = msnFile.readUint16LE();
+ instr2[i].volume = msnFile.readByte();
+ msnFile.read(instr2[i].dummy, 5);
+ }
+ songLength = msnFile.readSint16LE();
+ msnFile.read(arrangement, 128);
+ patternNumber = msnFile.readSint16LE();
+ for (int p = 0 ; p < patternNumber ; ++p) {
+ for (int n = 0 ; n < 64 ; ++n) {
+ for (int k = 0 ; k < 4 ; ++k) {
+ note2[p][n][k] = msnFile.readSint32LE();
+ }
+ }
+ }
+
+ /* MOD format */
+ struct {
+ char iname[22];
+ uint16 length;
+ char finetune;
+ char volume;
+ uint16 loopStart;
+ uint16 loopLength;
+ } instr[31];
+ int32 note[28][64][4];
+
+ // We can't recover some MOD effects since several of them are mapped to 0.
+ // Assume the MSN effect of value 0 is Arpeggio (MOD effect of value 0).
+ const char invConvEff[8] = {0, 1, 2, 3, 10, 12, 13 ,15};
+
+ // Reminder from convertToMsn
+ // 31 30 29 28 27 26 25 24 - 23 22 21 20 19 18 17 16 - 15 14 13 12 11 10 09 08 - 07 06 05 04 03 02 01 00
+ // h h h h g g g g f f f f e e e e d d d d c c c c b b b b a a a a
+ //
+ // MSN:
+ // hhhh (4 bits) Cleared to 0
+ // dddd c (5 bits) Sample index | after mapping through convInstr
+ // ccc (3 bits) Effect type | after mapping through convEff
+ // bbbb aaaa (8 bits) Effect value | unmodified
+ // gggg ffff eeee (12 bits) Sample period | unmodified
+ //
+ // MS2:
+ // hhhh (4 bits) Cleared to 0
+ // dddd (4 bits) Sample index | after mapping through convInstr
+ // cccc (4 bits) Effect type | unmodified
+ // bbbb aaaa (8 bits) Effect value | unmodified
+ // gggg ffff eeee (12 bits) Sample period | transformed (0xE000 / p) - 256
+ //
+ // MOD:
+ // hhhh dddd (8 bits) Sample index
+ // cccc (4 bits) Effect type for this channel/division
+ // bbbb aaaa (8 bits) Effect value
+ // gggg ffff eeee (12 bits) Sample period
+
+ // Can we recover the instruments mapping? I don't think so as part of the original instrument index is cleared.
+ // And it doesn't really matter as long as we are consistent.
+ // However we need to make sure 31 (or 15 in MS2) is mapped to 0 in MOD.
+ // We just add 1 to all other values, and this means a 1 <-> 1 mapping for the instruments
+ for (int p = 0; p < patternNumber; ++p) {
+ for (int n = 0; n < 64; ++n) {
+ for (int k = 0; k < 4; ++k) {
+ int32* l = &(note[p][n][k]);
+ *l = note2[p][n][k];
+ int32 i = 0;
+ if (nbInstr2 == 22) { // version 1
+ i = ((*l & 0xF800) >> 11);
+ int32 e = ((*l & 0x0700) >> 8);
+ int32 e1 = invConvEff[e];
+ *l &= 0x0FFF00FF;
+ *l |= (e1 << 8);
+ } else { // version 2
+ int32 h = (*l >> 16);
+ i = ((*l & 0xF000) >> 12);
+ *l &= 0x00000FFF;
+ if (h)
+ h = 0xE000 / (h + 256);
+ *l |= (h << 16);
+ if (i == 15)
+ i = 31;
+ }
+
+ // Add back index in note
+ if (i != 31) {
+ ++i;
+ *l |= ((i & 0x0F) << 12);
+ *l |= ((i & 0xF0) << 24);
+ }
+ }
+ }
+ }
+
+ for (int i = 0; i < 31; ++i) {
+ // iname is not stored in the mod file. Just set it to 'instrument#'
+ // finetune is not stored either. Assume 0.
+ memset(instr[i].iname, 0, 22);
+ sprintf(instr[i].iname, "instrument%d", i+1);
+ instr[i].length = 0;
+ instr[i].finetune = 0;
+ instr[i].volume = 0;
+ instr[i].loopStart = 0;
+ instr[i].loopLength = 0;
+
+ if (i < nbInstr2) {
+ instr[i].length = ((instr2[i].end - instr2[i].start) >> 1);
+ instr[i].loopStart = ((instr2[i].loopStart - instr2[i].start) >> 1);
+ instr[i].loopLength = (( instr2[i].loopEnd - instr2[i].loopStart) >> 1);
+ instr[i].volume = instr2[i].volume;
+ }
+ }
+
+ // The ciaaSpeed is kind of useless and not present in the MSN file.
+ // Traditionally 0x78 in SoundTracker. Was used in NoiseTracker as a restart point.
+ // ProTracker uses 0x7F. FastTracker uses it as a restart point, whereas ScreamTracker 3 uses 0x7F like ProTracker.
+ // You can use this to roughly detect which tracker made a MOD, and detection gets more accurate for more obscure MOD types.
+ char ciaaSpeed = 0x7F;
+
+ // The mark cannot be recovered either. Since we have 4 channels and 31 instrument it can be either ID='M.K.' or ID='4CHN'.
+ // Assume 'M.K.'
+ const char mark[4] = { 'M', '.', 'K', '.' };
+
+ Common::MemoryWriteStreamDynamic buffer(DisposeAfterUse::NO);
+
+ buffer.write(msnFile.getName(), 19);
+ buffer.writeByte(0);
+
+ for (int i = 0 ; i < 31 ; ++i) {
+ buffer.write(instr[i].iname, 22);
+ buffer.writeUint16BE(instr[i].length);
+ buffer.writeByte(instr[i].finetune);
+ buffer.writeByte(instr[i].volume);
+ buffer.writeUint16BE(instr[i].loopStart);
+ buffer.writeUint16BE(instr[i].loopLength);
+ }
+ buffer.writeByte((char)songLength);
+ buffer.writeByte(ciaaSpeed);
+ buffer.write(arrangement, 128);
+ buffer.write(mark, 4);
+
+ for (int p = 0 ; p < patternNumber ; ++p) {
+ for (int n = 0 ; n < 64 ; ++n) {
+ for (int k = 0 ; k < 4 ; ++k) {
+// buffer.writeUint32BE(*((uint32*)(note[p][n]+k)));
+ buffer.writeSint32BE(note[p][n][k]);
+ }
+ }
+ }
+
+ uint nb;
+ char buf[4096];
+ while ((nb = msnFile.read(buf, 4096)) > 0)
+ buffer.write(buf, nb);
+
+ return new Common::MemoryReadStream(buffer.getData(), buffer.size(), DisposeAfterUse::YES);
+}
+
+bool SupernovaEngine::canLoadGameStateCurrently() {
+ return _allowLoadGame;
+}
+
+Common::Error SupernovaEngine::loadGameState(int slot) {
+ return (loadGame(slot) ? Common::kNoError : Common::kReadingFailed);
+}
+
+bool SupernovaEngine::canSaveGameStateCurrently() {
+ // Do not allow saving when either _allowSaveGame, _animationEnabled or _guiEnabled is false
+ return _allowSaveGame && _gm->_animationEnabled && _gm->_guiEnabled;
+}
+
+Common::Error SupernovaEngine::saveGameState(int slot, const Common::String &desc) {
+ return (saveGame(slot, desc) ? Common::kNoError : Common::kWritingFailed);
+}
+
+bool SupernovaEngine::loadGame(int slot) {
+ if (slot < 0)
+ return false;
+
+ Common::String filename = Common::String::format("msn_save.%03d", slot);
+ Common::InSaveFile *savefile = _saveFileMan->openForLoading(filename);
+ if (!savefile)
+ return false;
+
+ uint saveHeader = savefile->readUint32LE();
+ if (saveHeader != SAVEGAME_HEADER) {
+ warning("No header found in '%s'", filename.c_str());
+ delete savefile;
+ return false; //Common::kUnknownError
+ }
+
+ byte saveVersion = savefile->readByte();
+ // Save version 1 was used during development and is no longer supported
+ if (saveVersion > SAVEGAME_VERSION || saveVersion == 1) {
+ warning("Save game version %i not supported", saveVersion);
+ delete savefile;
+ return false; //Common::kUnknownError;
+ }
+
+ // Make sure no message is displayed as this would otherwise delay the
+ // switch to the new location until a mouse click.
+ removeMessage();
+
+ int descriptionSize = savefile->readSint16LE();
+ savefile->skip(descriptionSize);
+ savefile->skip(6);
+ setTotalPlayTime(savefile->readUint32LE() * 1000);
+ Graphics::skipThumbnail(*savefile);
+ _gm->deserialize(savefile, saveVersion);
+
+ if (saveVersion >= 5) {
+ _menuBrightness = savefile->readByte();
+ _brightness = savefile->readByte();
+ } else {
+ _menuBrightness = _brightness = 255;
+ }
+
+ delete savefile;
+
+ return true;
+}
+
+bool SupernovaEngine::saveGame(int slot, const Common::String &description) {
+ if (slot < 0)
+ return false;
+
+ Common::String filename = Common::String::format("msn_save.%03d", slot);
+ Common::OutSaveFile *savefile = _saveFileMan->openForSaving(filename);
+ if (!savefile)
+ return false;
+
+ savefile->writeUint32LE(SAVEGAME_HEADER);
+ savefile->writeByte(SAVEGAME_VERSION);
+
+ TimeDate currentDate;
+ _system->getTimeAndDate(currentDate);
+ uint32 saveDate = (currentDate.tm_mday & 0xFF) << 24 | ((currentDate.tm_mon + 1) & 0xFF) << 16 | ((currentDate.tm_year + 1900) & 0xFFFF);
+ uint16 saveTime = (currentDate.tm_hour & 0xFF) << 8 | ((currentDate.tm_min) & 0xFF);
+
+ savefile->writeSint16LE(description.size() + 1);
+ savefile->write(description.c_str(), description.size() + 1);
+ savefile->writeUint32LE(saveDate);
+ savefile->writeUint16LE(saveTime);
+ savefile->writeUint32LE(getTotalPlayTime() / 1000);
+ Graphics::saveThumbnail(*savefile);
+ _gm->serialize(savefile);
+
+ savefile->writeByte(_menuBrightness);
+ savefile->writeByte(_brightness);
+
+ savefile->finalize();
+ delete savefile;
+
+ return true;
+}
+
+void SupernovaEngine::errorTempSave(bool saving) {
+ GUIErrorMessage(saving
+ ? "Failed to save temporary game state. Make sure your save game directory is set in ScummVM and that you can write to it."
+ : "Failed to load temporary game state.");
+ error("Unrecoverable error");
+}
+
+ScreenBufferStack::ScreenBufferStack()
+ : _last(_buffer) {
+}
+
+void ScreenBufferStack::push(int x, int y, int width, int height) {
+ if (_last == ARRAYEND(_buffer))
+ return;
+
+ Graphics::Surface* screenSurface = g_system->lockScreen();
+
+ if (x < 0) {
+ width += x;
+ x = 0;
+ }
+ if (x + width > screenSurface->w)
+ width = screenSurface->w - x;
+
+ if (y < 0) {
+ height += y;
+ y = 0;
+ }
+ if (y + height > screenSurface->h)
+ height = screenSurface->h - y;
+
+ _last->_pixels = new byte[width * height];
+ byte *pixels = _last->_pixels;
+ const byte *screen = static_cast<const byte *>(screenSurface->getBasePtr(x, y));
+ for (int i = 0; i < height; ++i) {
+ Common::copy(screen, screen + width, pixels);
+ screen += screenSurface->pitch;
+ pixels += width;
+ }
+ g_system->unlockScreen();
+
+ _last->_x = x;
+ _last->_y = y;
+ _last->_width = width;
+ _last->_height = height;
+
+ ++_last;
+}
+
+void ScreenBufferStack::restore() {
+ if (_last == _buffer)
+ return;
+
+ --_last;
+ g_system->lockScreen()->copyRectToSurface(
+ _last->_pixels, _last->_width, _last->_x, _last->_y,
+ _last->_width, _last->_height);
+ g_system->unlockScreen();
+
+ delete[] _last->_pixels;
+}
+
+}
diff --git a/engines/supernova/supernova.h b/engines/supernova/supernova.h
new file mode 100644
index 0000000000..90ea884f0b
--- /dev/null
+++ b/engines/supernova/supernova.h
@@ -0,0 +1,218 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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.
+ *
+ */
+
+#ifndef SUPERNOVA_SUPERNOVA_H
+#define SUPERNOVA_SUPERNOVA_H
+
+#include "audio/audiostream.h"
+#include "audio/mixer.h"
+#include "audio/decoders/raw.h"
+#include "common/array.h"
+#include "common/events.h"
+#include "common/random.h"
+#include "common/scummsys.h"
+#include "engines/engine.h"
+#include "common/file.h"
+#include "common/memstream.h"
+
+#include "supernova/console.h"
+#include "supernova/graphics.h"
+#include "supernova/msn_def.h"
+#include "supernova/rooms.h"
+
+
+namespace Supernova {
+
+#define SAVEGAME_HEADER MKTAG('M','S','N','1')
+#define SAVEGAME_VERSION 8
+
+#define SUPERNOVA_DAT "supernova.dat"
+#define SUPERNOVA_DAT_VERSION 1
+
+
+struct ScreenBuffer {
+ ScreenBuffer()
+ : _x(0)
+ , _y(0)
+ , _width(0)
+ , _height(0)
+ , _pixels(NULL)
+ {}
+
+ byte *_pixels;
+ int _x;
+ int _y;
+ int _width;
+ int _height;
+};
+class ScreenBufferStack {
+public:
+ ScreenBufferStack();
+
+ void push(int x, int y, int width, int height);
+ void restore();
+
+private:
+ ScreenBuffer _buffer[8];
+ ScreenBuffer *_last;
+};
+
+struct SoundSample {
+ SoundSample()
+ : _buffer(NULL)
+ , _length(0)
+ {}
+
+ ~SoundSample() {
+ delete[] _buffer;
+ }
+
+ byte *_buffer;
+ int _length;
+};
+
+class SupernovaEngine : public Engine {
+public:
+ explicit SupernovaEngine(OSystem *syst);
+ ~SupernovaEngine();
+
+ virtual Common::Error run();
+
+ Common::RandomSource _rnd;
+ GameManager *_gm;
+ Console *_console;
+ Audio::SoundHandle _soundHandle;
+ ScreenBufferStack _screenBuffer;
+ byte _mouseNormal[256];
+ byte _mouseWait[256];
+ MSNImageDecoder *_currentImage;
+ SoundSample _soundSamples[kAudioNumSamples];
+ Common::MemoryReadStream *_soundMusicIntro;
+ Common::MemoryReadStream *_soundMusicOutro;
+ int _screenWidth;
+ int _screenHeight;
+ bool _allowLoadGame;
+ bool _allowSaveGame;
+ Common::StringArray _gameStrings;
+ Common::String _nullString;
+
+ byte _menuBrightness;
+ byte _brightness;
+ uint _delay;
+ bool _messageDisplayed;
+ int _textSpeed;
+ int _textCursorX;
+ int _textCursorY;
+ int _textColor;
+
+ int textWidth(const char *text);
+ int textWidth(const uint16 key);
+ Common::Error loadGameStrings();
+ void initData();
+ void initPalette();
+ void paletteFadeIn();
+ void paletteFadeOut();
+ void paletteBrightness();
+ void updateEvents();
+ void playSound(AudioIndex sample);
+ void playSoundMod(int filenumber);
+ void stopSound();
+ void renderImageSection(int section);
+ void renderImage(int section);
+ bool setCurrentImage(int filenumber);
+ void saveScreen(int x, int y, int width, int height);
+ void restoreScreen();
+ void renderRoom(Room &room);
+ void renderMessage(const char *text, MessagePosition position = kMessageNormal);
+ void removeMessage();
+ void renderText(const char *text, int x, int y, byte color);
+ void renderText(const uint16 character, int x, int y, byte color);
+ void renderText(const char *text);
+ void renderText(const uint16 character);
+ void renderBox(int x, int y, int width, int height, byte color);
+ void setColor63(byte value);
+ bool loadGame(int slot);
+ bool saveGame(int slot, const Common::String &description);
+ void errorTempSave(bool saving);
+ void setTextSpeed();
+
+ const Common::String &getGameString(int idx) const {
+ if (idx < 0 || idx >= (int)_gameStrings.size())
+ return _nullString;
+ return _gameStrings[idx];
+ }
+
+ void setGameString(int idx, const Common::String &string) {
+ if (idx < 0)
+ return;
+ while ((int)_gameStrings.size() <= idx)
+ _gameStrings.push_back(Common::String());
+ _gameStrings[idx] = string;
+ }
+
+ int textWidth(const Common::String &text) {
+ if (text.empty())
+ return 0;
+ return textWidth(text.c_str());
+ }
+ void renderMessage(StringID stringId, MessagePosition position = kMessageNormal, Common::String var1 = "", Common::String var2 = "") {
+ Common::String text = getGameString(stringId);
+ if (!var1.empty()) {
+ if (!var2.empty())
+ text = Common::String::format(text.c_str(), var1.c_str(), var2.c_str());
+ else
+ text = Common::String::format(text.c_str(), var1.c_str());
+ }
+ renderMessage(text, position);
+ }
+ void renderMessage(const Common::String &text, MessagePosition position = kMessageNormal) {
+ if (!text.empty())
+ renderMessage(text.c_str(), position);
+ }
+ void renderText(StringID stringId, int x, int y, byte color) {
+ renderText(getGameString(stringId), x, y, color);
+ }
+ void renderText(const Common::String &text, int x, int y, byte color) {
+ if (!text.empty())
+ renderText(text.c_str(), x, y, color);
+ }
+ void renderText(StringID stringId) {
+ renderText(getGameString(stringId));
+ }
+ void renderText(const Common::String &text) {
+ if (!text.empty())
+ renderText(text.c_str());
+ }
+
+ Common::MemoryReadStream *convertToMod(const char *filename, int version = 1);
+
+ virtual Common::Error loadGameState(int slot);
+ virtual bool canLoadGameStateCurrently();
+ virtual Common::Error saveGameState(int slot, const Common::String &desc);
+ virtual bool canSaveGameStateCurrently();
+ virtual bool hasFeature(EngineFeature f) const;
+ virtual void pauseEngineIntern(bool pause);
+};
+
+}
+
+#endif