aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--devtools/create_supernova/create_supernova.cpp196
-rw-r--r--devtools/create_supernova/create_supernova.h33
-rw-r--r--devtools/create_supernova/file.cpp72
-rw-r--r--devtools/create_supernova/file.h59
-rw-r--r--devtools/create_supernova/gametext.h823
-rw-r--r--devtools/create_supernova/img1-en.pbmbin0 -> 38450 bytes
-rw-r--r--devtools/create_supernova/img1-en.xcfbin0 -> 124617 bytes
-rw-r--r--devtools/create_supernova/module.mk12
-rw-r--r--devtools/create_supernova/po_parser.cpp221
-rw-r--r--devtools/create_supernova/po_parser.h78
-rw-r--r--devtools/create_supernova/strings-en.po2905
-rw-r--r--dists/engine-data/supernova.datbin0 -> 77779 bytes
-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
28 files changed, 14502 insertions, 0 deletions
diff --git a/devtools/create_supernova/create_supernova.cpp b/devtools/create_supernova/create_supernova.cpp
new file mode 100644
index 0000000000..bf04004b1a
--- /dev/null
+++ b/devtools/create_supernova/create_supernova.cpp
@@ -0,0 +1,196 @@
+#include "create_supernova.h"
+#include "gametext.h"
+#include "file.h"
+#include "po_parser.h"
+
+// HACK to allow building with the SDL backend on MinGW
+// see bug #1800764 "TOOLS: MinGW tools building broken"
+#ifdef main
+#undef main
+#endif // main
+
+// List of languages to look for. To add new languages you only need to change the array below
+// and add the supporting files:
+// - 640x480 bitmap picture for the newpaper named 'img1-##.pbm' and 'img2-##.pbm'
+// in pbm binary format (you can use gimp to generate those)
+// - strings in a po file named 'strings-##.po' that uses CP850 encoding
+
+const char *lang[] = {
+ "en",
+ NULL
+};
+
+void writeImage(File& outputFile, const char *name, const char* language) {
+ File imgFile;
+ char fileName[16];
+ sprintf(fileName, "%s-%s.pbm", name, language);
+ if (!imgFile.open(fileName, kFileReadMode)) {
+ printf("Cannot find image '%s' for language '%s'. This image will be skipped.\n", name, language);
+ return;
+ }
+
+ char str[256];
+
+ // Read header (and check we have a binary PBM file)
+ imgFile.readString(str, 256);
+ if (strcmp(str, "P4") != 0) {
+ imgFile.close();
+ printf("File '%s' doesn't seem to be a binary pbm file! This image will be skipped.\n", fileName);
+ return;
+ }
+
+ // Skip comments and then read and check size
+ do {
+ imgFile.readString(str, 256);
+ } while (str[0] == '#');
+ int w = 0, h = 0;
+ if (sscanf(str, "%d %d", &w, &h) != 2 || w != 640 || h != 480) {
+ imgFile.close();
+ printf("Binary pbm file '%s' doesn't have the expected size (expected: 640x480, read: %dx%d). This image will be skipped.\n", fileName, w, h);
+ return;
+ }
+
+ // Write block header in output file (4 bytes).
+ // We convert the image name to upper case.
+ for (int i = 0 ; i < 4 ; ++i) {
+ if (name[i] >= 97 && name[i] <= 122)
+ outputFile.writeByte(name[i] - 32);
+ else
+ outputFile.writeByte(name[i]);
+ }
+ // And write the language code on 4 bytes as well (padded with 0 if needed).
+ int languageLength = strlen(language);
+ for (int i = 0 ; i < 4 ; ++i) {
+ if (i < languageLength)
+ outputFile.writeByte(language[i]);
+ else
+ outputFile.writeByte(0);
+ }
+
+ // Write block size (640*480 / 8)
+ outputFile.writeLong(38400);
+
+ // Write all the bytes. We should have 38400 bytes (640 * 480 / 8)
+ // However we need to invert the bits has the engine expects 1 for the background and 0 for the text (black)
+ // but pbm uses 0 for white and 1 for black.
+ for (int i = 0 ; i < 38400 ; ++i) {
+ byte b = imgFile.readByte();
+ outputFile.writeByte(~b);
+ }
+
+ imgFile.close();
+}
+
+void writeGermanStrings(File& outputFile) {
+ // Write header and language
+ outputFile.write("TEXT", 4);
+ outputFile.write("de\0\0", 4);
+
+ // Reserve the size for the block size, but we will write it at the end once we know what it is.
+ uint32 blockSizePos = outputFile.pos();
+ uint32 blockSize = 0;
+ outputFile.writeLong(blockSize);
+
+ // Write all the strings
+ const char **s = &gameText[0];
+ while (*s) {
+ outputFile.writeString(*s);
+ blockSize += strlen(*s) + 1;
+ ++s;
+ }
+
+ // Now write the block size and then go back to the end of the file.
+ outputFile.seek(blockSizePos, SEEK_SET);
+ outputFile.writeLong(blockSize);
+ outputFile.seek(0, SEEK_END);
+}
+
+void writeStrings(File& outputFile, const char* language) {
+ char fileName[16];
+ sprintf(fileName, "strings-%s.po", language);
+ PoMessageList* poList = parsePoFile(fileName);
+ if (!poList) {
+ printf("Cannot find strings file for language '%s'.\n", language);
+ return;
+ }
+
+ // Write block header
+ outputFile.write("TEXT", 4);
+
+ // And write the language code on 4 bytes as well (padded with 0 if needed).
+ int languageLength = strlen(language);
+ for (int i = 0 ; i < 4 ; ++i) {
+ if (i < languageLength)
+ outputFile.writeByte(language[i]);
+ else
+ outputFile.writeByte(0);
+ }
+
+ // Reserve the size for the block size, but we will write it at the end once we know what it is.
+ uint32 blockSizePos = outputFile.pos();
+ uint32 blockSize = 0;
+ outputFile.writeLong(blockSize);
+
+ // Write all the strings.
+ // If a string is not translated we use the German one.
+ const char **s = &gameText[0];
+ while (*s) {
+ const char* translation = poList->findTranslation(*s);
+ if (translation) {
+ outputFile.writeString(translation);
+ blockSize += strlen(translation) + 1;
+ } else {
+ outputFile.writeString(*s);
+ blockSize += strlen(*s) + 1;
+ }
+ ++s;
+ }
+ delete poList;
+
+ // Now write the block size and then go back to the end of the file.
+ outputFile.seek(blockSizePos, SEEK_SET);
+ outputFile.writeLong(blockSize);
+ outputFile.seek(0, SEEK_END);
+}
+
+
+/**
+ * Main method
+ */
+int main(int argc, char *argv[]) {
+ File outputFile;
+ if (!outputFile.open("supernova.dat", kFileWriteMode)) {
+ printf("Cannot create file 'supernova.dat' in current directory.\n");
+ exit(0);
+ }
+
+ // The generated file is of the form:
+ // 3 bytes: 'MSN'
+ // 1 byte: version
+ // -- data blocks
+ // 4 bytes: header 'IMG1' and 'IMG2' for newspaper images (for file 1 and file 2 respectively),
+ // 'TEXT' for strings
+ // 4 bytes: language code ('en\0', 'de\0'- see common/language.cpp)
+ // 4 bytes: block size n (uint32)
+ // n bytes: data
+ // ---
+
+ // Header
+ outputFile.write("MSN", 3);
+ outputFile.writeByte(VERSION);
+
+ // German strings
+ writeGermanStrings(outputFile);
+
+ // Other languages
+ const char **l = &lang[0];
+ while(*l) {
+ writeImage(outputFile, "img1", *l);
+ writeImage(outputFile, "img2", *l);
+ writeStrings(outputFile, *l);
+ ++l;
+ }
+
+ outputFile.close();
+ return 0;
+}
diff --git a/devtools/create_supernova/create_supernova.h b/devtools/create_supernova/create_supernova.h
new file mode 100644
index 0000000000..7447a7ece6
--- /dev/null
+++ b/devtools/create_supernova/create_supernova.h
@@ -0,0 +1,33 @@
+/* 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.
+ *
+ * This is a utility for generating a data file for the supernova engine.
+ * It contains strings extracted from the original executable as well
+ * as translations and is required for the engine to work properly.
+ */
+
+#ifndef CREATE_SUPERNOVA_H
+#define CREATE_SUPERNOVA_H
+
+#define VERSION 1
+
+
+
+#endif // CREATE_SUPERNOVA_H
diff --git a/devtools/create_supernova/file.cpp b/devtools/create_supernova/file.cpp
new file mode 100644
index 0000000000..5fb842aff6
--- /dev/null
+++ b/devtools/create_supernova/file.cpp
@@ -0,0 +1,72 @@
+#include "file.h"
+
+bool File::open(const char *filename, AccessMode mode) {
+ f = fopen(filename, (mode == kFileReadMode) ? "rb" : "wb");
+ return (f != NULL);
+}
+
+void File::close() {
+ fclose(f);
+ f = NULL;
+}
+
+int File::seek(int32 offset, int whence) {
+ return fseek(f, offset, whence);
+}
+
+long File::read(void *buffer, int len) {
+ return fread(buffer, 1, len, f);
+}
+void File::write(const void *buffer, int len) {
+ fwrite(buffer, 1, len, f);
+}
+
+byte File::readByte() {
+ byte v;
+ read(&v, sizeof(byte));
+ return v;
+}
+
+uint16 File::readWord() {
+ uint16 v;
+ read(&v, sizeof(uint16));
+ return FROM_LE_16(v);
+}
+
+uint32 File::readLong() {
+ uint32 v;
+ read(&v, sizeof(uint32));
+ return FROM_LE_32(v);
+}
+
+void File::readString(char* string, int bufferLength) {
+ int i = 0;
+ while (i < bufferLength - 1 && fread(string + i, 1, 1, f) == 1) {
+ if (string[i] == '\n' || string[i] == 0)
+ break;
+ ++ i;
+ }
+ string[i] = 0;
+}
+
+void File::writeByte(byte v) {
+ write(&v, sizeof(byte));
+}
+
+void File::writeWord(uint16 v) {
+ uint16 vTemp = TO_LE_16(v);
+ write(&vTemp, sizeof(uint16));
+}
+
+void File::writeLong(uint32 v) {
+ uint32 vTemp = TO_LE_32(v);
+ write(&vTemp, sizeof(uint32));
+}
+
+void File::writeString(const char *s) {
+ write(s, strlen(s) + 1);
+}
+
+uint32 File::pos() {
+ return ftell(f);
+}
diff --git a/devtools/create_supernova/file.h b/devtools/create_supernova/file.h
new file mode 100644
index 0000000000..dd33e410f9
--- /dev/null
+++ b/devtools/create_supernova/file.h
@@ -0,0 +1,59 @@
+/* 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.
+ *
+ * This is a utility for generating a data file for the supernova engine.
+ * It contains strings extracted from the original executable as well
+ * as translations and is required for the engine to work properly.
+ */
+
+#ifndef FILE_H
+#define FILE_H
+
+// Disable symbol overrides so that we can use system headers.
+#define FORBIDDEN_SYMBOL_ALLOW_ALL
+#include "common/endian.h"
+
+enum AccessMode {
+ kFileReadMode = 1,
+ kFileWriteMode = 2
+};
+
+class File {
+private:
+ FILE *f;
+public:
+ bool open(const char *filename, AccessMode mode = kFileReadMode);
+ void close();
+ int seek(int32 offset, int whence = SEEK_SET);
+ uint32 pos();
+ long read(void *buffer, int len);
+ void write(const void *buffer, int len);
+
+ byte readByte();
+ uint16 readWord();
+ uint32 readLong();
+ void readString(char*, int bufferLength);
+ void writeByte(byte v);
+ void writeWord(uint16 v);
+ void writeLong(uint32 v);
+ void writeString(const char *s);
+};
+
+#endif // FILE_H
diff --git a/devtools/create_supernova/gametext.h b/devtools/create_supernova/gametext.h
new file mode 100644
index 0000000000..398e210c54
--- /dev/null
+++ b/devtools/create_supernova/gametext.h
@@ -0,0 +1,823 @@
+/* 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.
+ *
+ * This is a utility for generating a data file for the supernova engine.
+ * It contains strings extracted from the original executable as well
+ * as translations and is required for the engine to work properly.
+ */
+
+#ifndef GAMETEXT_H
+#define GAMETEXT_H
+
+#include <stddef.h>
+
+// This file contains the strings in German and is encoded using CP850 encoding.
+// Other language should be provided as po files also using the CP850 encoding.
+
+// TODO: add the strings from the engine here, add an Id string in comment.
+// And in the engine add a StringId enum with all the Ids = index in this array.
+
+const char *gameText[] = {
+ // 0
+ "Gehe", // kStringCommandGo
+ "Schau", // kStringCommandLook
+ "Nimm", // kStringCommandTake
+ "\231ffne", // kStringCommandOpen
+ "Schlie\341e", // kStringCommandClose
+ // 5
+ "Dr\201cke", // kStringCommandPress
+ "Ziehe", // kStringCommandPull
+ "Benutze", // kStringCommandUse
+ "Rede", // kStringCommandTalk
+ "Gib", // kStringCommandGive
+ // 10
+ "Gehe zu ", // kStringStatusCommandGo
+ "Schau ", // kStringStatusCommandLook
+ "Nimm ", // kStringStatusCommandTake
+ "\231ffne ", // kStringStatusCommandOpen
+ "Schlie\341e ", // kStringStatusCommandClose
+ // 15
+ "Dr\201cke ", // kStringStatusCommandPress
+ "Ziehe ", // kStringStatusCommandPull
+ "Benutze ", // kStringStatusCommandUse
+ "Rede mit ", // kStringStatusCommandTalk
+ "Gib ", // kStringStatusCommandGive
+ // 20
+ "V2.02", // kStringTitleVersion
+ "Teil 1:", // kStringTitle1
+ "Das Schicksal", // kStringTitle2
+ "des Horst Hummel", // kStringTitle3
+ "^(C) 1994 Thomas und Steffen Dingel#", // kStringIntro1
+ // 25
+ "Story und Grafik:^ Thomas Dingel#", // kStringIntro2
+ "Programmierung:^ Steffen Dingel#", // kStringIntro3
+ "Musik:^ Bernd Hoffmann#", // kStringIntro4
+ "Getestet von ...#", // kStringIntro5
+ "^Matthias Neef#", // kStringIntro6
+ // 30
+ "^Sascha Otterbach#", // kStringIntro7
+ "^Thomas Mazzoni#", // kStringIntro8
+ "^Matthias Klein#", // kStringIntro9
+ "^Gerrit Rothmaier#", // kStringIntro10
+ "^Thomas Hassler#", // kStringIntro11
+ // 35
+ "^Rene Koch#", // kStringIntro12
+ "\233", // kStringIntro13
+ "Hmm, er scheint kaputt zu sein.", // kStringBroken
+ "Es ist nichts Besonderes daran.", // kStringDefaultDescription
+ "Das mu\341t du erst nehmen.", // kStringTakeMessage
+ // 40
+ "Keycard", // kStringKeycard
+ "Die Keycard f\224r deine Schr\204nke.", // kStringKeycardDescription
+ "Taschenmesser", // kStringKnife
+ "Es ist nicht mehr das sch\204rfste.", // kStringKnifeDescription
+ "Armbanduhr", // kStringWatch
+ // 45
+ "Discman", // kStringDiscman
+ "Es ist eine \"Mad Monkeys\"-CD darin.", // kStringDiscmanDescription
+ "Luke", // kStringHatch
+ "Knopf", // kStringButton
+ "Er geh\224rt zu der gro\341en Luke.", // kStringHatchButtonDescription
+ // 50
+ "Leiter", // kStringLadder
+ "Ausgang", // kStringExit
+ "Sie f\201hrt ins Cockpit.", // kStringCockpitHatchDescription
+ "Sie f\201hrt zur K\201che.", // kStringKitchenHatchDescription
+ "Sie f\201hrt zu den Tiefschlafkammern.", // kStringStasisHatchDescription
+ // 55
+ "Dies ist eine der Tiefschlafkammern.", // kStringStasisHatchDescription2
+ "Schlitz", // kStringSlot
+ "Es ist ein Keycard-Leser.", // kStringSlotDescription
+ "Gang", // kStringCorridor
+ "Computer", // kStringComputer
+ // 60
+ "ZWEIUNDVIERZIG", // kStringComputerPassword
+ "Instrumente", // kStringInstruments
+ "Hmm, sieht ziemlich kompliziert aus.", // kStringInstrumentsDescription1
+ "Monitor", // kStringMonitor
+ "Dieser Monitor sagt dir nichts.", // kStringMonitorDescription
+ // 65
+ "Bild", // kStringImage
+ "Herb!", // kStringGenericDescription1
+ "Toll!", // kStringGenericDescription2
+ "Genial!", // kStringGenericDescription3
+ "Es scheint noch nicht fertig zu sein.", // kStringGenericDescription4
+ // 70
+ "Magnete", // kStringMagnete
+ "Damit werden Sachen auf|dem Tisch festgehalten.", // kStringMagneteDescription
+ "Stift", // kStringPen
+ "Ein Kugelschreiber.", // kStringPenDescription
+ "Schrank", // kStringShelf
+ // 75
+ "Fach", // kStringCompartment
+ "Steckdose", // kStringSocket
+ "Toilette", // kStringToilet
+ "Pistole", // kStringPistol
+ "Es ist keine Munition drin.", // kStringPistolDescription
+ // 80
+ "B\201cher", // kStringBooks
+ "Lauter wissenschaftliche B\201cher.", // kStringBooksDescription
+ "Kabelrolle", // kStringSpool
+ "Da sind mindestens zwanzig Meter drauf.", // kStringSpoolDescription
+ "Buch", // kStringBook
+ // 85
+ "Unterw\204sche", // kStringUnderwear
+ "Ich habe keine Lust, in|der Unterw\204sche des|Commanders rumzuw\201hlen.", // kStringUnderwearDescription
+ "Kleider", // kStringClothes
+ "Krimskram", // kStringJunk
+ "Es ist nichts brauchbares dabei.", // kStringJunkDescription
+ // 90
+ "Ordner", // kStringFolders
+ "Darauf steht \"Dienstanweisungen|zur Mission Supernova\".|Es steht nichts wichtiges drin.", // kStringFoldersDescription
+ "Poster", // kStringPoster
+ "Ein Poster von \"Big Boss\".", // kStringPosterDescription1
+ "Ein Poster von \"Rock Desaster\".", // kStringPosterDescription2
+ // 95
+ "Box", // kStringSpeaker
+ "Schallplatte", // kStringRecord
+ "Die Platte ist von \"Big Boss\".", // kStringRecordDescription
+ "Schallplattenst\204nder", // kStringRecordStand
+ "Du hast jetzt keine Zeit, in|der Plattensammlung rumzust\224bern.", // kStringRecordStandDescription
+ // 100
+ "Plattenspieler", // kStringTurntable
+ "Sieht aus, als k\204me|er aus dem Museum.", // kStringTurntableDescription
+ "Leitung", // kStringWire
+ "Stecker", // kStringPlug
+ "Manche Leute haben schon|einen komischen Geschmack.", // kStringImageDescription1
+ // 105
+ "Zeichenger\204te", // kStringDrawingInstruments
+ "Auf dem Zettel sind lauter|unverst\204ndliche Skizzen und Berechnungen.|(Jedenfalls f\201r dich unverst\204ndlich.)", // kStringDrawingInstrumentsDescription
+ "Schachspiel", // kStringChessGame
+ "Es macht wohl Spa\341, an|der Decke Schach zu spielen.", // kStringChessGameDescription1
+ "Tennisschl\204ger", // kStringTennisRacket
+ // 110
+ "Fliegt Boris Becker auch mit?", // kStringTennisRacketDescription
+ "Tennisball", // kStringTennisBall
+ "Dein Magnetschachspiel. Schach war|schon immer deine Leidenschaft.", // kStringChessGameDescription2
+ "Bett", // kStringBed
+ "Das ist dein Bett. Toll, nicht wahr?", // kStringBedDescription
+ // 115
+ "Das ist eins deiner drei F\204cher.", // kStringCompartmentDescription
+ "Alben", // kStringAlbums
+ "Deine Briefmarkensammlung.", // kStringAlbumsDescription
+ "Seil", // kStringRope
+ "Es ist ungef\204hr 10 m lang und 4 cm dick.", // kStringRopeDescription
+ // 120
+ "Das ist dein Schrank.", // kStringShelfDescription
+ "Es sind Standard-Weltraum-Klamotten.", // kStringClothesDescription
+ "Str\201mpfe", // kStringSocks
+ "Es ist|\"Per Anhalter durch die Galaxis\"|von Douglas Adams.", // kStringBookHitchhiker
+ "Klo", // kStringBathroom
+ // 125
+ "Ein Klo mit Saugmechanismus.", // kStringBathroomDescription
+ "Dusche", // kStringShower
+ "Das ist eine Luke !!!", // kStringHatchDescription1
+ "Dies ist eine Luke !!!", // kStringHatchDescription2
+ "Helm", // kStringHelmet
+ // 130
+ "Es ist der Helm zum Raumanzug.", // kStringHelmetDescription
+ "Raumanzug", // kStringSuit
+ "Der einzige Raumanzug, den die|anderen hiergelassen haben ...", // kStringSuitDescription
+ "Versorgung", // kStringLifeSupport
+ "Es ist der Versorgungsteil zum Raumanzug.", // kStringLifeSupportDescription
+ // 135
+ "Schrott", // kStringScrap
+ "Da ist eine L\201sterklemme dran, die|noch ganz brauchbar aussieht.|Ich nehme sie mit.", // kStringScrapDescription1
+ "L\201sterklemme", // kStringTerminalStrip
+ "Junge, Junge! Die Explosion hat ein|ganz sch\224nes Durcheinander angerichtet.", // kStringScrapDescription2
+ "Reaktor", // kStringReactor
+ // 140
+ "Das war einmal der Reaktor.", // kStringReactorDescription
+ "D\201se", // kStringNozzle
+ "blauer K\201rbis", // kStringPumpkin
+ "Keine Ahnung, was das ist.", // kStringPumpkinDescription
+ "Landef\204hre", // kStringLandingModule
+ // 145
+ "Sie war eigentlich f\201r Bodenuntersuchungen|auf Arsano 3 gedacht.", // kStringLandingModuleDescription
+ "Sie f\201hrt nach drau\341en.", // kStringHatchDescription3
+ "Generator", // kStringGenerator
+ "Er versorgt das Raumschiff mit Strom.", // kStringGeneratorDescription
+ "Ein St\201ck Schrott.", // kStringScrapDescription3
+ // 150
+ "Es ist ein Sicherheitsknopf.|Er kann nur mit einem spitzen|Gegenstand gedr\201ckt werden.", // kSafetyButtonDescription
+ "Tastatur", // kStringKeyboard
+ "langes Kabel mit Stecker", // kStringGeneratorWire
+ "leere Kabelrolle", // kStringEmptySpool
+ "Keycard des Commanders", // kStringKeycard2
+ // 155
+ "Hey, das ist die Keycard des Commanders!|Er mu\341 sie bei dem \201berst\201rzten|Aufbruch verloren haben.", // kStringKeycard2Description
+ "Klappe", // kStringTrap
+ "Spannungmessger\204t", // kStringVoltmeter
+ "Klemme", // kStringClip
+ "Sie f\201hrt vom Generator zum Spannungmessger\204t.", // kStringWireDescription
+ // 160
+ "Stein", // kStringStone
+ "Loch", // kStringCaveOpening
+ "Es scheint eine H\224hle zu sein.", // kStringCaveOpeningDescription
+ "Hier bist du gerade hergekommen.", // kStringExitDescription
+ "H\224hle", // kStringCave
+ // 165
+ "Schild", // kStringSign
+ "Diese Schrift kannst du nicht lesen.", // kStringSignDescription
+ "Eingang", // kStringEntrance
+ "Stern", // kStringStar
+ "Raumschiff", // kStringSpaceshift
+ // 170
+ "Portier", // kStringPorter
+ "Du siehst doch selbst, wie er aussieht.", // kStringPorterDescription
+ "T\201r", // kStringDoor
+ "Kaugummi", // kStringChewingGum
+ "Gummib\204rchen", // kStringGummyBears
+ // 175
+ "Schokokugel", // kStringChocolateBall
+ "\232berraschungsei", // kStringEgg
+ "Lakritz", // kStringLiquorice
+ "Tablette", // kStringPill
+ "Die Plastikh\201lle zeigt einen|Mund mit einer Sprechblase. Was|darin steht, kannst du nicht lesen.", // kStringPillDescription
+ // 180
+ "Automat", // kStringVendingMachine
+ "Sieht aus wie ein Kaugummiautomat.", // kStringVendingMachineDescription
+ "Die Toiletten sind denen|auf der Erde sehr \204hnlich.", // kStringToiletDescription
+ "Treppe", // kStringStaircase
+ "M\201nzen", // kStringCoins
+ // 185
+ "Es sind seltsame|K\224pfe darauf abgebildet.", // kStringCoinsDescription
+ "Tablettenh\201lle", // kStringTabletPackage
+ "Darauf steht:\"Wenn Sie diese|Schrift jetzt lesen k\224nnen,|hat die Tablette gewirkt.\"", // kStringTabletPackageDescription
+ "Stuhl", // kStringChair
+ "Schuhe", // kStringShoes
+ // 190
+ "Wie ist der denn mit|Schuhen hier reingekommen?", // kStringShoesDescription
+ "Froschgesicht", // kStringFrogFace
+ "Gekritzel", // kStringScrible
+ "\"Mr Spock was here\"", // kStringScribleDescription
+ "Brieftasche", // kStringWallet
+ // 195
+ "Speisekarte", // kStringMenu
+ "\"Heute empfehlen wir:|Fonua Opra mit Ulk.\"", // kStringMenuDescription
+ "Tasse", // kStringCup
+ "Sie enth\204lt eine gr\201nliche Fl\201ssigkeit.", // kStringCupDescription
+ "10-Buckazoid-Schein", // kStringBill
+ // 200
+ "Nicht gerade sehr viel Geld.", // kStringBillDescription
+ "Keycard von Roger", // kStringKeycard3
+ "Anzeige", // kStringAnnouncement
+ "Hmm, seltsame Anzeigen.", // kStringAnnouncementDescription
+ "Roger W.", // kStringRoger
+ // 205
+ "Ufo", // kStringUfo
+ "Der Eingang scheint offen zu sein.", // kStringUfoDescription
+ "Tablett", // kStringTray
+ "Es ist irgendein Fra\341 und|etwas zu Trinken darauf.", // kStringTrayDescription
+ "Stange", // kStringLamp
+ // 210
+ "Es scheint eine Lampe zu sein.", // kStringLampDescription
+ "Augen", // kStringEyes
+ "Es ist nur ein Bild.", // kStringEyesDescription
+ "Sieht etwas anders aus als auf der Erde.", // kStringSocketDescription
+ "Metallblock", // kStringMetalBlock
+ // 215
+ "Er ist ziemlich schwer.", // kStringMetalBlockDescription
+ "Roboter", // kStringRobot
+ "Den hast du erledigt.", // kStringRobotDescription
+ "Tisch", // kStringTable
+ "Ein kleiner Metalltisch.", // kStringTableDescription
+ // 220
+ "Zellent\201r", // kStringCellDoor
+ "Hier warst du eingesperrt.", // kStringCellDoorDescription
+ "Laptop", // kStringLaptop
+ "Armbanduhr", // kStringWristwatch
+ "S\204ule", // kStringPillar
+ // 225
+ "Auf einem Schild an der T\201r steht \"Dr. Alab Hansi\".", // kStringDoorDescription1
+ "Auf einem Schild an der T\201r steht \"Saval Lun\".", // kStringDoorDescription2
+ "Auf einem Schild an der T\201r steht \"Prof. Dr. Ugnul Tschabb\".", // kStringDoorDescription3
+ "Auf einem Schild an der T\201r steht \"Alga Hurz Li\".", // kStringDoorDescription4
+ "Diese T\201r w\201rde ich lieber|nicht \224ffnen. Nach dem Schild zu|urteilen, ist jemand in dem Raum.", // kStringDontEnter
+ // 230
+ "Axacussaner", // kStringAxacussan
+ "Du m\201\341test ihn irgendwie ablenken.", // kStringAxacussanDescription
+ "Komisches Bild.", // kStringImageDescription2
+ "Karte", // kStringMastercard
+ "Darauf steht: \"Generalkarte\".", // kStringMastercardDescription
+ // 235
+ "Lampe", // kStringLamp2
+ "Seltsam!", // kStringGenericDescription5
+ "Geld", // kStringMoney
+ "Es sind 500 Xa.", // kStringMoneyDescription1
+ "Schlie\341fach", // kStringLocker
+ // 240
+ "Es hat ein elektronisches Zahlenschlo\341.", // kStringLockerDescription
+ "Brief", // kStringLetter
+ "W\201rfel", // kStringCube
+ "Sonderbar!", // kStringGenericDescription6
+ "Affenstark!", // kStringGenericDescription7
+ // 245
+ "Komisches Ding", // kStringStrangeThing
+ "Wundersam", // kStringGenericDescription8
+ "Es ist ein Axacussanerkopf auf dem Bild.", // kStringImageDescription3
+ "Pflanze", // kStringPlant
+ "Figur", // kStringStatue
+ // 250
+ "Stark!", // kStringStatueDescription
+ "Sie ist den Pflanzen auf der Erde sehr \204hnlich.", // kStringPlantDescription
+ "Er funktioniert nicht.", // kStringComputerDescription
+ "Graffiti", // kStringGraffiti
+ "Seltsamer B\201roschmuck!", // kStringGraffitiDescription
+ // 255
+ "Es sind 350 Xa.", // kStringMoneyDescription2
+ "Dschungel", // kStringJungle
+ "Lauter B\204ume.", // kStringJungleDescription
+ "^ E#N#D#E ...########", // kStringOutro1
+ "# ... des ersten Teils!########", // kStringOutro2
+ // 260
+ "#########", // kStringOutro3
+ "^Aber:#", // kStringOutro4
+ "Das Abenteuer geht weiter, ...##", // kStringOutro5
+ "... wenn Sie sich f\201r 30,- DM registrieren lassen!##", // kStringOutro6
+ "(Falls Sie das nicht schon l\204ngst getan haben.)##", // kStringOutro7
+ // 265
+ "In^ Teil 2 - Der Doppelg\204nger^ erwarten Sie:##", // kStringOutro8
+ "Knifflige Puzzles,##", // kStringOutro9
+ "noch mehr Grafik und Sound,##", // kStringOutro10
+ "ein perfekt geplanter Museumseinbruch,##", // kStringOutro11
+ "das Virtual-Reality-Spiel \"Indiana Joe\"##", // kStringOutro12
+ // 270
+ "und vieles mehr!##", // kStringOutro13
+ "\233", // kStringOutro14
+ "Leitung mit Stecker", // kStringWireAndPlug
+ "Leitung mit L\201sterklemme", // kStringWireAndClip
+ "langes Kabel mit Stecker", // kStringWireAndPlug2
+ // 275
+ "Darauf steht:|\"Treffpunkt Galactica\".", // kStringSignDescription2
+ "M\201nze", // kStringCoin
+ "Darauf steht:|\"Zutritt nur f\201r Personal\".", // kStringDoorDescription5
+ "Darauf steht:|\"Toilette\".", // kStringDoorDescription6
+ "Es ist die Keycard des Commanders.", // kStringKeycard2Description2
+ // 280
+ "Kabelrolle mit L\201sterklemme", // kSringSpoolAndClip
+ "Zwei Tage nach dem Start|im Cockpit der \"Supernova\" ...", // kStringIntroCutscene1
+ "Entferung von der Sonne: 1 500 000 km.|Gehen Sie auf 8000 hpm, Captain!", // kStringIntroCutscene2
+ "Ok, Sir.", // kStringIntroCutscene3
+ "Geschwindigkeit:", // kStringIntroCutscene4
+ // 285
+ "Zweitausend hpm", // kStringIntroCutscene5
+ "Dreitausend", // kStringIntroCutscene6
+ "Viertausend", // kStringIntroCutscene7
+ "F\201nftausend", // kStringIntroCutscene8
+ "Sechstausend", // kStringIntroCutscene9
+ // 290
+ "Siebentausend", // kStringIntroCutscene10
+ "Achttau...", // kStringIntroCutscene11
+ "Was war das?", // kStringIntroCutscene12
+ "Keine Ahnung, Sir.", // kStringIntroCutscene13
+ "Ingenieur an Commander, bitte kommen!", // kStringIntroCutscene14
+ // 295
+ "Was ist los?", // kStringIntroCutscene15
+ "Wir haben einen Druckabfall im Hauptantriebssystem, Sir.|Einen Moment, ich schaue sofort nach, woran es liegt.", // kStringIntroCutscene16
+ "Schei\341e, der Ionenantrieb ist explodiert!|Die Teile sind \201ber den ganzen|Maschinenraum verstreut.", // kStringIntroCutscene17
+ "Ach, du meine G\201te!|Gibt es irgendeine M\224glichkeit,|den Schaden schnell zu beheben?", // kStringIntroCutscene18
+ "Nein, Sir. Es sieht schlecht aus.", // kStringIntroCutscene19
+ // 300
+ "Hmm, die Erde zu alarmieren, w\201rde zu lange dauern.", // kStringIntroCutscene20
+ "Ich darf kein Risiko eingehen.|Captain, geben Sie sofort Alarm!", // kStringIntroCutscene21
+ "Commander an alle! Achtung, Achtung!|Begeben Sie sich sofort zum Notraumschiff!", // kStringIntroCutscene22
+ "Ich wiederhole:|Begeben Sie sich sofort zum Notraumschiff!", // kStringIntroCutscene23
+ "Captain, bereiten Sie alles f\201r den Start vor!|Wir m\201ssen zur\201ck zur Erde!", // kStringIntroCutscene24
+ // 305
+ "Eine Stunde sp\204ter ...", // kStringIntroCutscene25
+ "Die Besatzung hat die \"Supernova\" verlassen.", // kStringIntroCutscene26
+ "Das Schiff wird zwar in acht Jahren sein Ziel|erreichen, allerdings ohne Mannschaft.", // kStringIntroCutscene27
+ "Das ist das kl\204gliche Ende|der Mission Supernova.", // kStringIntroCutscene28
+ "Sie k\224nnen jetzt ihren Computer ausschalten.", // kStringIntroCutscene29
+ // 310
+ "Halt!", // kStringIntroCutscene30
+ "Warten Sie!", // kStringIntroCutscene31
+ "Es regt sich etwas im Schiff.", // kStringIntroCutscene32
+ "Uuuuaaaahhhhh", // kStringIntroCutscene33
+ "Huch, ich bin ja gefesselt!|Wo bin ich?", // kStringIntroCutscene34
+ // 315
+ "Ach so, das sind ja die Sicherheitsgurte.|Ich arbeite ja jetzt in diesem Raumschiff hier.", // kStringIntroCutscene35
+ "Was? Schon zwei Uhr! Wieso|hat mich denn noch keiner|aus dem Bett geschmissen?", // kStringIntroCutscene36
+ "Ich werde mal nachsehen.", // kStringIntroCutscene37
+ "Autsch!", // kStringIntroCutscene38
+ "Schei\341etagenbett!", // kStringIntroCutscene39
+ // 320
+ "Erst mal den Lichtschalter finden.", // kStringIntroCutscene40
+ "Hmm, gar nicht so einfach|bei Schwerelosigkeit.", // kStringIntroCutscene41
+ "Ah, hier ist er.", // kStringIntroCutscene42
+ "In der K\201che warst du schon|oft genug, im Moment hast|du keinen Appetit.", // kStringShipHall1
+ "Flugziel erreicht", // kStringShipSleepCabin1
+ // 325
+ "Energie ersch\224pft", // kStringShipSleepCabin2
+ "Tiefschlafprozess abgebrochen", // kStringShipSleepCabin3
+ "Schlafdauer in Tagen:", // kStringShipSleepCabin4
+ "Bitte legen Sie sich in die angezeigte Schlafkammer.", // kStringShipSleepCabin5
+ "Bitte Passwort eingeben:", // kStringShipSleepCabin6
+ // 330
+ "Schlafdauer in Tagen:", // kStringShipSleepCabin7
+ "Bitte legen Sie sich in die angezeigte Schlafkammer.", // kStringShipSleepCabin8
+ "Falsches Passwort", // kStringShipSleepCabin9
+ "Es w\201rde wenig bringen,|sich in eine Schlafkammer zu legen,|die nicht eingeschaltet ist.", // kStringShipSleepCabin10
+ "Dazu mu\341t du erst den Raumanzug ausziehen.", // kStringShipSleepCabin11
+ // 335
+ "Was war das?", // kStringShipSleepCabin12
+ "Achtung", // kStringShipSleepCabin13
+ "Du wachst mit brummendem Sch\204del auf|und merkst, da\341 du nur getr\204umt hast.", // kStringShipSleepCabin14
+ "Beim Aufprall des Raumschiffs|mu\341t du mit dem Kopf aufgeschlagen|und bewu\341tlos geworden sein.", // kStringShipSleepCabin15
+ "Was steht dir jetzt wohl wirklich bevor?", // kStringShipSleepCabin16
+ // 340
+ "Geschwindigkeit: ", // kStringShipCockpit1
+ "8000 hpm", // kStringShipCockpit2
+ "0 hpm", // kStringShipCockpit3
+ "Ziel: Arsano 3", // kStringShipCockpit4
+ "Entfernung: ", // kStringShipCockpit5
+ //345
+ " Lichtjahre", // kStringShipCockpit6
+ "Dauer der Reise bei momentaner Geschwindigkeit:", // kStringShipCockpit7
+ " Tage", // kStringShipCockpit8
+ "Vergi\341 nicht, du bist nur der|Schiffskoch und hast keine Ahnung,|wie man ein Raumschiff fliegt.", // kStringShipCockpit9
+ "Achtung: Triebwerke funktionsunf\204hig", // kStringShipCockpit10
+ //350
+ "Energievorrat ersch\224pft", // kStringShipCockpit11
+ "Notstromversorgung aktiv", // kStringShipCockpit12
+ "Was?! Keiner im Cockpit!|Die sind wohl verr\201ckt!", // kStringShipCockpit13
+ "Du hast die Platte schon aufgelegt.", // kStringShipCabinL3_1
+ "Es ist doch gar keine Platte aufgelegt.", // kStringShipCabinL3_2
+ //355
+ "Die Platte scheint einen Sprung zu haben.", // kStringShipCabinL3_3
+ "Schneid doch besser ein|l\204ngeres St\201ck Kabel ab!", // kStringShipCabinL3_4
+ "Das ist befestigt.", // kStringShipCabinL3_5
+ "Zu niedriger Luftdruck soll ungesund sein.", // kStringShipAirlock1
+ "Er zeigt Null an.", // kStringShipAirlock2
+ //360
+ "Er zeigt Normaldruck an.", // kStringShipAirlock3
+ "Komisch, es ist nur|noch ein Raumanzug da.", // kStringShipAirlock4
+ "Du mu\341t erst hingehen.", // kStringShipHold1
+ "Das Kabel ist im Weg.", // kStringCable1
+ "Das Kabel ist schon ganz|richtig an dieser Stelle.", // kStringCable2
+ //365
+ "Womit denn?", // kStringCable3
+ "Die Leitung ist zu kurz.", // kStringCable4
+ "Was ist denn das f\201r ein Chaos?|Und au\341erdem fehlt das Notraumschiff!|Jetzt wird mir einiges klar.|Die anderen sind gefl\201chtet,|und ich habe es verpennt.", // kStringShipHold2
+ "Es ist nicht spitz genug.", // kStringShipHold3
+ "Du wirst aus den Anzeigen nicht schlau.", // kStringShipHold4
+ //370
+ "La\341 lieber die Finger davon!", // kStringShipHold5
+ "An dem Kabel ist doch gar kein Stecker.", // kStringShipHold6
+ "Du solltest die Luke vielleicht erst \224ffnen.", // kStringShipHold7
+ "Das Seil ist im Weg.", // kStringShipHold8
+ "Das ist geschlossen.", // kStringShipHold9
+ //375
+ "Das geht nicht.|Die Luke ist mindestens|5 Meter \201ber dem Boden.", // kStringShipHold10
+ "Was n\201tzt dir der Anschlu\341|ohne eine Stromquelle?!", // kStringShipHold11
+ "Die Spannung ist auf Null abgesunken.", // kStringShipHold12
+ "Es zeigt volle Spannung an.", // kStringShipHold13
+ "Du mu\341t die Luke erst \224ffnen.", // kStringShipHold14
+ //380
+ "Das Seil ist hier schon ganz richtig.", // kStringShipHold15
+ "Das Kabel ist zu kurz.", // kStringShipHold16
+ "Die Raumschiffe sind alle verschlossen.", // kStringArsanoMeetup1
+ "Unsinn!", // kStringArsanoMeetup2
+ "Komisch! Auf einmal kannst du|das Schild lesen! Darauf steht:|\"Treffpunkt Galactica\".", // kStringArsanoMeetup3
+ //385
+ "Durch deinen Helm kannst|du nicht sprechen.", // kStringArsanoEntrance1
+ "Wo soll ich die Schuhe ablegen?", // kStringArsanoEntrance2
+ "Was, das wissen Sie nicht?", // kStringArsanoEntrance3
+ "Sie befinden sich im Restaurant|\"Treffpunkt Galactica\".", // kStringArsanoEntrance4
+ "Wir sind bei den interessantesten|Ereignissen in der Galaxis|immer zur Stelle.", // kStringArsanoEntrance5
+ //390
+ "Wenn Sie meinen.", // kStringArsanoEntrance6
+ "In der Toilette gibt es|Schlie\341f\204cher f\201r Schuhe.", // kStringArsanoEntrance7
+ "Wenn Sie das Lokal betreten|wollen, m\201ssen Sie erst|ihre Schuhe ausziehen.", // kStringArsanoEntrance8
+ "Wollen Sie, da\341 ich Sie rau\341schmei\341e?", // kStringArsanoEntrance9
+ "Hhius otgfh Dgfdrkjlh Fokj gf.", // kStringArsanoEntrance10
+ //395
+ "Halt!", // kStringArsanoEntrance11
+ "Uhwdejkt!", // kStringArsanoEntrance12
+ "Sie m\201ssen erst ihre Schuhe ausziehen, Sie Trottel!", // kStringArsanoEntrance13
+ "Was f\204llt ihnen ein!|Sie k\224nnen doch ein Lokal|nicht mit Schuhen betreten!", // kStringArsanoEntrance14
+ "Fragen Sie nicht so doof!", // kStringArsanoEntrance15
+ // 400
+ "Das w\201rde ich an ihrer|Stelle nicht versuchen!", // kStringArsanoEntrance16
+ "Du ziehst deine Schuhe|aus und legst sie in|eins der Schlie\341f\204cher.", // kStringArsanoEntrance17
+ "Du ziehst deine Schuhe wieder an.", // kStringArsanoEntrance18
+ "Du durchsuchst die Klos nach|anderen brauchbaren Sachen,|findest aber nichts.", // kStringArsanoEntrance19
+ "Bevor du aufs Klo gehst,|solltest du besser deinen|Raumanzug ausziehen.", // kStringArsanoEntrance20
+ // 405
+ "Du gehst seit sieben Jahren das|erste Mal wieder aufs Klo!", // kStringArsanoEntrance21
+ "In einem der Schlie\341f\204cher,|die sich auch im Raum befinden,|findest du einige M\201nzen.", // kStringArsanoEntrance22
+ "Mach doch zuerst das Fach leer!", // kStringArsanoEntrance23
+ "Komisch! Auf einmal kannst du|das Schild lesen! Darauf steht:|\"Zutritt nur f\201r Personal\".", // kStringArsanoEntrance24
+ "Komisch! Auf einmal kannst|du das Schild lesen!|Darauf steht:\"Toilette\".", // kStringArsanoEntrance25
+ // 410
+ "Du ziehst den Raumanzug wieder an.", // kStringArsanoEntrance26
+ "Nicht so gewaltt\204tig!", // kStringArsanoEntrance27
+ "Wo bin ich hier?", // kStringArsanoDialog1
+ "Sch\224nes Wetter heute, nicht wahr?", // kStringArsanoDialog2
+ "W\201rden Sie mich bitte durchlassen.", // kStringArsanoDialog3
+ // 415
+ "Hey Alter, la\341 mich durch!", // kStringArsanoDialog4
+ "Was haben Sie gesagt?", // kStringArsanoDialog5
+ "Sprechen Sie bitte etwas deutlicher!", // kStringArsanoDialog6
+ "Wieso das denn nicht?", // kStringArsanoDialog7
+ "Wo soll ich die Schuhe ablegen?", // kStringArsanoDialog8
+ // 420
+ "Schwachsinn! Ich gehe jetzt nach oben!", // kStringArsanoDialog9
+ "|", // kStringDialogSeparator
+ "K\224nnten Sie mir ein Gericht empfehlen?", // kStringDialogArsanoRoger1
+ "Wie lange dauert es denn noch bis zur Supernova?", // kStringDialogArsanoRoger2
+ "Sie kommen mir irgendwie bekannt vor.", // kStringDialogArsanoRoger3
+ // 425
+ "Was wollen Sie von mir?", // kStringDialogArsanoMeetup3_1
+ "Hilfe!!", // kStringDialogArsanoMeetup3_2
+ "Warum sprechen Sie meine Sprache?", // kStringDialogArsanoMeetup3_3
+ "Ja, ich bin einverstanden.", // kStringDialogArsanoMeetup3_4
+ "Nein, lieber bleibe ich hier, als mit Ihnen zu fliegen.", // kStringDialogArsanoMeetup3_5
+ // 430
+ "Darf ich hier Platz nehmen?", // kStringArsanoRoger1
+ "Klar!", // kStringArsanoRoger2
+ "Hey, Witzkeks, la\341 die Brieftasche da liegen!", // kStringArsanoRoger3
+ "Das ist nicht deine.", // kStringArsanoRoger4
+ "Roger ist im Moment nicht ansprechbar.", // kStringArsanoRoger5
+ // 435
+ "Bestellen Sie lieber nichts!", // kStringArsanoRoger6
+ "Ich habe vor zwei Stunden mein Essen|bestellt und immer noch nichts bekommen.", // kStringArsanoRoger7
+ "Noch mindestens zwei Stunden.", // kStringArsanoRoger8
+ "Haben Sie keine Idee, womit wir uns|bis dahin die Zeit vertreiben k\224nnen?", // kStringArsanoRoger9
+ "Hmm ... im Moment f\204llt mir nichts ein, aber vielleicht|hat der Spieler des Adventures ja eine Idee.", // kStringArsanoRoger10
+ // 440
+ "Nein, Sie m\201ssen sich irren.|Ich kenne Sie jedenfalls nicht.", // kStringArsanoRoger11
+ "Aber ihre Kleidung habe ich irgendwo schon mal gesehen.", // kStringArsanoRoger12
+ "Ja? Komisch.", // kStringArsanoRoger13
+ "Jetzt wei\341 ich's. Sie sind Roger W. !", // kStringArsanoRoger14
+ "Pssst, nicht so laut, sonst will|gleich jeder ein Autogramm von mir.", // kStringArsanoRoger15
+ // 445
+ "Ich habe extra eine Maske auf, damit|ich nicht von jedem angelabert werde.", // kStringArsanoRoger16
+ "\216h ... ach so.", // kStringArsanoRoger17
+ "Wann kommt denn das n\204chste SQ-Abenteuer raus?", // kStringArsanoRoger18
+ "SQ 127 m\201\341te in einem Monat erscheinen.", // kStringArsanoRoger19
+ "Was, Teil 127 ??", // kStringArsanoRoger20
+ // 450
+ "Bei uns ist gerade Teil 8 erschienen.", // kStringArsanoRoger21
+ "Hmm ... von welchem Planeten sind Sie denn?", // kStringArsanoRoger22
+ "Von der Erde.", // kStringArsanoRoger23
+ "Erde? Nie geh\224rt.", // kStringArsanoRoger24
+ "Wahrscheinlich irgendein Kaff, wo Neuerungen|erst hundert Jahre sp\204ter hingelangen.", // kStringArsanoRoger25
+ // 455
+ "\216h ... kann sein.", // kStringArsanoRoger26
+ "Aber eins m\201ssen Sie mir erkl\204ren!", // kStringArsanoRoger27
+ "Wieso sehen Sie mir so verdammt \204hnlich, wenn|Sie nicht von Xenon stammen, wie ich?", // kStringArsanoRoger28
+ "Keine Ahnung. Bis jetzt dachte ich immer, Sie w\204ren ein|von Programmierern auf der Erde erfundenes Computersprite.", // kStringArsanoRoger29
+ "Was? Lachhaft!", // kStringArsanoRoger30
+ // 460
+ "Wie erkl\204ren Sie sich dann,|da\341 ich ihnen gegen\201bersitze?", // kStringArsanoRoger31
+ "Ja, das ist in der Tat seltsam.", // kStringArsanoRoger32
+ "Halt, jetzt wei\341 ich es. Sie sind von der Konkurrenz,|von \"Georgefilm Games\" und wollen mich verunsichern.", // kStringArsanoRoger33
+ "Nein, ich bin nur ein Ahnungsloser Koch von der Erde.", // kStringArsanoRoger34
+ "Na gut, ich glaube Ihnen. Lassen wir jetzt|dieses Thema, langsam wird es mir zu bunt!", // kStringArsanoRoger35
+ // 465
+ "Eine Partie Schach! Das ist eine gute Idee.", // kStringArsanoRoger36
+ "Schach? Was ist das denn?", // kStringArsanoRoger37
+ "Schach ist ein interessantes Spiel.|Ich werde es Ihnen erkl\204ren.", // kStringArsanoRoger38
+ "Knapp zwei Stunden sp\204ter ...", // kStringArsanoRoger39
+ "Roger W. steht kurz vor dem Schachmatt|und gr\201belt nach einem Ausweg.", // kStringArsanoRoger40
+ // 470
+ "Du tippst auf den Tasten herum,|aber es passiert nichts.", // kStringArsanoGlider1
+ "Alle Raumschiffe haben|den Planeten verlassen.", // kStringArsanoMeetup2_1
+ "Alle Raumschiffe haben den Planeten|verlassen, bis auf eins ...", // kStringArsanoMeetup2_2
+ "Was wollen Sie denn schon wieder?", // kStringArsanoMeetup2_3
+ "Nein.", // kStringArsanoMeetup2_4
+ // 475
+ "Haben Sie zuf\204llig meine Brieftasche gesehen?|Ich mu\341 Sie irgendwo verloren haben.", // kStringArsanoMeetup2_5
+ "Ohne die Brieftasche kann ich nicht|starten, weil meine Keycard darin ist.", // kStringArsanoMeetup2_6
+ "Oh! Vielen Dank.", // kStringArsanoMeetup2_7
+ "Wo ist denn Ihr Raumschiff?|Soll ich Sie ein St\201ck mitnehmen?", // kStringArsanoMeetup2_8
+ "Wo wollen Sie denn hin?", // kStringArsanoMeetup2_9
+ // 480
+ "Ok, steigen Sie ein!", // kStringArsanoMeetup2_10
+ "Wie Sie wollen.", // kStringArsanoMeetup2_11
+ "Huch, du lebst ja noch!", // kStringArsanoMeetup2_12
+ "Das w\201rde ich jetzt nicht tun, schlie\341lich|steht Roger W. neben seinem Schiff.", // kStringArsanoMeetup2_13
+ "Ich glaube, er wacht auf.", // kStringArsanoMeetup3_1
+ // 485
+ "Ja, sieht so aus.", // kStringArsanoMeetup3_2
+ "Sie befinden sich im Raumschiff \"Dexxa\".", // kStringArsanoMeetup3_3
+ "Wir kommen vom Planeten Axacuss und|sind aus dem gleichen Grund hier wie Sie,|n\204mlich zur Erforschung der Supernova.", // kStringArsanoMeetup3_4
+ "Sie k\224nnen beruhigt sein, wir wollen Ihnen nur helfen.", // kStringArsanoMeetup3_5
+ "Und wieso hat der Typ im Raumanzug|eben auf mich geschossen?", // kStringArsanoMeetup3_6
+ // 490
+ "Das war eine Schreckreaktion.", // kStringArsanoMeetup3_7
+ "Schlie\341lich ist es f\201r uns das erste Mal,|da\341 wir auf eine fremde Intelligenz treffen.", // kStringArsanoMeetup3_8
+ "Wie wir festgestellt haben, ist|Ihr Raumschiff v\224llig zerst\224rt.", // kStringArsanoMeetup3_9
+ "Wahrscheinlich k\224nnen Sie nicht|mehr auf ihren Heimatplaneten zur\201ck.", // kStringArsanoMeetup3_10
+ "Wir bieten Ihnen an, Sie|mit nach Axacuss zu nehmen.", // kStringArsanoMeetup3_11
+ // 495
+ "Sind Sie sich da wirklich sicher?", // kStringArsanoMeetup3_12
+ "Wenn ich es mir genau \201berlege,|fliege ich doch lieber mit.", // kStringArsanoMeetup3_13
+ "Gut, wir nehmen Sie unter der|Bedingung mit, da\341 wir Sie jetzt|sofort in Tiefschlaf versetzen d\201rfen.", // kStringArsanoMeetup3_14
+ "Diese Art des Reisens ist Ihnen|ja scheinbar nicht unbekannt.", // kStringArsanoMeetup3_15
+ "Sie werden in vier Jahren nach der|Landung der \"Dexxa\" wieder aufgeweckt.", // kStringArsanoMeetup3_16
+ // 500
+ "Sind Sie damit einverstanden?", // kStringArsanoMeetup3_17
+ "Gut, haben Sie noch irgendwelche Fragen?", // kStringArsanoMeetup3_18
+ "Keine Panik!", // kStringArsanoMeetup3_19
+ "Wir tun Ihnen nichts.", // kStringArsanoMeetup3_20
+ "Wir sprechen nicht ihre Sprache,|sondern Sie sprechen unsere.", // kStringArsanoMeetup3_21
+ // 505
+ "Nach einer Gehirnanalyse konnten|wir Ihr Gehirn an unsere Sprache anpassen.", // kStringArsanoMeetup3_22
+ "Was? Sie haben in mein Gehirn eingegriffen?", // kStringArsanoMeetup3_23
+ "Keine Angst, wir haben sonst nichts ver\204ndert.", // kStringArsanoMeetup3_24
+ "Ohne diesen Eingriff w\204ren|Sie verloren gewesen.", // kStringArsanoMeetup3_25
+ "Ich habe keine weiteren Fragen mehr.", // kStringArsanoMeetup3_26
+ // 510
+ "Gut, dann versetzen wir Sie jetzt in Tiefschlaf.", // kStringArsanoMeetup3_27
+ "Gute Nacht!", // kStringArsanoMeetup3_28
+ "Du wachst auf und findest dich in|einem geschlossenen Raum wieder.", // kStringAxacussCell_1
+ "Du dr\201ckst den Knopf,|aber nichts passiert.", // kStringAxacussCell_2
+ "Das ist befestigt.", // kStringAxacussCell_3
+ // 515
+ "Bei deinem Fluchtversuch hat|dich der Roboter erschossen.", // kStringAxacussCell_4
+ "Du i\341t etwas, aber|es schmeckt scheu\341lich.", // kStringAxacussCell_5
+ "Ok.", // kStringOk
+ "Ach, Ihnen geh\224rt die. Ich habe sie eben im Sand gefunden.", // kStringDialogArsanoMeetup2_1
+ "Nein, tut mir leid.", // kStringDialogArsanoMeetup2_2
+ // 520
+ "Nein, danke. Ich bleibe lieber hier.", // kStringDialogArsanoMeetup2_3
+ "Ja, das w\204re gut.", // kStringDialogArsanoMeetup2_4
+ "Zur Erde.", // kStringDialogArsanoMeetup2_5
+ "Zum Pr\204sident der Galaxis.", // kStringDialogArsanoMeetup2_6
+ "Nach Xenon.", // kStringDialogArsanoMeetup2_7
+ // 525
+ "Mir egal, setzen Sie mich irgendwo ab!", // kStringDialogArsanoMeetup2_8
+ "Ich habe gerade Ihre Brieftasche gefunden!", // kStringDialogArsanoMeetup2_9
+ "Sie lag da dr\201ben hinter einem Felsen.", // kStringDialogArsanoMeetup2_10
+ "Ich wollte nur wissen, ob Sie die Brieftasche wiederhaben.", // kStringDialogArsanoMeetup2_11
+ "\216h ... nein, mein Name ist M\201ller.", // kStringDialogAxacussCorridor5_1
+ // 530
+ "Oh, ich habe mich im Gang vertan.", // kStringDialogAxacussCorridor5_2
+ "W\201rden Sie mich bitte zum Fahrstuhl lassen?", // kStringDialogAxacussCorridor5_3
+ "Ich gehe wieder.", // kStringDialogAxacussCorridor5_4
+ "Dann gehe ich eben wieder.", // kStringDialogAxacussCorridor5_5
+ "Ach, halten Sie's Maul, ich gehe trotzdem!", // kStringDialogAxacussCorridor5_6
+ // 535
+ "Wenn Sie mich durchlassen gebe ich Ihnen %d Xa.", // kStringDialogAxacussCorridor5_7
+ "Hallo!", // kStringDialogX1
+ "Guten Tag!", // kStringDialogX2
+ "Ich bin's, Horst Hummel.", // kStringDialogX3
+ "Sie schon wieder?", // kStringAxacussCorridor5_1
+ // 540
+ "Halt! Sie sind doch dieser Hummel.|Bleiben Sie sofort stehen!", // kStringAxacussCorridor5_2
+ "Sehr witzig!", // kStringAxacussCorridor5_3
+ "Kann auch sein, auf jeden Fall|sind Sie der Nicht-Axacussaner.", // kStringAxacussCorridor5_4
+ "Nein!", // kStringAxacussCorridor5_5
+ "Das m\201\341te schon ein bi\341chen mehr sein.", // kStringAxacussCorridor5_6
+ // 545
+ "Ok, dann machen Sie da\341 Sie wegkommen!", // kStringAxacussCorridor5_7
+ "Du stellst dich hinter die S\204ule.", // kStringAxacussBcorridor_1
+ "Welche Zahlenkombination willst|du eingeben?", // kStringAxacussOffice1_1
+ "Hmm, das haut nicht ganz hin,|aber irgendwie mu\341 die Zahl|mit dem Code zusammenh\204ngen.", // kStringAxacussOffice1_2
+ "Das war die falsche Kombination.", // kStringAxacussOffice1_3
+ // 550
+ "Streng geheim", // kStringAxacussOffice1_4
+ "418-98", // kStringAxacussOffice1_5
+ "Sehr geehrter Dr. Hansi,", // kStringAxacussOffice1_6
+ "Ich mu\341 Ihren Roboterexperten ein Lob aussprechen. Die", // kStringAxacussOffice1_7
+ "Imitation von Horst Hummel ist perfekt gelungen, wie ich", // kStringAxacussOffice1_8
+ // 555
+ "heute bei der \232bertragung des Interviews feststellen", // kStringAxacussOffice1_9
+ "konnte. Dem Aufschwung Ihrer Firma durch die Werbe-", // kStringAxacussOffice1_10
+ "kampagne mit dem falschen Horst Hummel d\201rfte ja jetzt", // kStringAxacussOffice1_11
+ "nichts mehr im Wege stehen.", // kStringAxacussOffice1_12
+ "PS: Herzlichen zum Geburtstag!", // kStringAxacussOffice1_13
+ // 560
+ "Hochachtungsvoll", // kStringAxacussOffice1_14
+ "Commander Sumoti", // kStringAxacussOffice1_15
+ "Nicht zu fassen!", // kStringAxacussOffice1_16
+ "Hey, hinter dem Bild ist Geld|versteckt. Ich nehme es mit.", // kStringAxacussOffice3_1
+ "Jetzt verschwinden Sie endlich!", // kStringAxacussElevator_1
+ // 565
+ "Huch, ich habe mich vertan.", // kStringAxacussElevator_2
+ "Nachdem du zwei Stunden im|Dschungel herumgeirrt bist,|findest du ein Geb\204ude.", // kStringAxacussElevator_3
+ "Du h\204ttest besser vorher|den Stecker rausgezogen.", // kStringShock
+ "Der Axacussaner hat dich erwischt.", // kStringShot
+ "Das ist schon geschlossen.", // kStringCloseLocker_1
+ // 570
+ "Irgendwie ist ein Raumhelm|beim Essen unpraktisch.", // kStringIsHelmetOff_1
+ "Schmeckt ganz gut.", // kStringGenericInteract_1
+ "Da war irgendetwas drin,|aber jetzt hast du es|mit runtergeschluckt.", // kStringGenericInteract_2
+ "Du hast es doch schon ge\224ffnet.", // kStringGenericInteract_3
+ "In dem Ei ist eine Tablette|in einer Plastikh\201lle.", // kStringGenericInteract_4
+ // 575
+ "Du i\341t die Tablette und merkst,|da\341 sich irgendetwas ver\204ndert hat.", // kStringGenericInteract_5
+ "Komisch! Auf einmal kannst du die Schrift lesen!|Darauf steht:\"Wenn Sie diese Schrift jetzt|lesen k\224nnen, hat die Tablette gewirkt.\"", // kStringGenericInteract_6
+ "Das mu\341t du erst nehmen.", // kStringGenericInteract_7
+ "Sie ist leer.", // kStringGenericInteract_8
+ "Du findest 10 Buckazoids und eine Keycard.", // kStringGenericInteract_9
+ // 580
+ "Es ist eine Art elektronische Zeitung.", // kStringGenericInteract_10
+ "Halt, hier ist ein interessanter Artikel.", // kStringGenericInteract_11
+ "Hmm, irgendwie komme|ich mir verarscht vor.", // kStringGenericInteract_12
+ " an ", // kPhrasalVerbParticleGiveTo
+ " mit ", // kPhrasalVerbParticleUseWith
+ // 585
+ "Es ist eine Uhr mit extra|lautem Wecker. Sie hat einen|Knopf zum Verstellen der Alarmzeit.|Uhrzeit: %s Alarmzeit: %s", // kStringGenericInteract_13
+ "Neue Alarmzeit (hh:mm) :", // kStringGenericInteract_14
+ "Die Luft hier ist atembar,|du ziehst den Anzug aus.", // kStringGenericInteract_15
+ "Hier drinnen brauchtst du deinen Anzug nicht.", // kStringGenericInteract_16
+ "Du mu\341t erst den Helm abnehmen.", // kStringGenericInteract_17
+ // 590
+ "Du mu\341t erst den Versorgungsteil abnehmen.", // kStringGenericInteract_18
+ "Du ziehst den Raumanzug aus.", // kStringGenericInteract_19
+ "Du ziehst den Raumanzug an.", // kStringGenericInteract_20
+ "Die Luft hier ist atembar,|du ziehst den Anzug aus.", // kStringGenericInteract_21
+ "Hier drinnen brauchtst du deinen Anzug nicht.", // kStringGenericInteract_22
+ // 595
+ "Den Helm h\204ttest du|besser angelassen!", // kStringGenericInteract_23
+ "Du ziehst den Helm ab.", // kStringGenericInteract_24
+ "Du ziehst den Helm auf.", // kStringGenericInteract_25
+ "Du mu\341t erst den Anzug anziehen.", // kStringGenericInteract_26
+ "Den Versorgungsteil h\204ttest du|besser nicht abgenommen!", // kStringGenericInteract_27
+ // 600
+ "Du nimmst den Versorgungsteil ab.", // kStringGenericInteract_28
+ "Du ziehst den Versorgungsteil an.", // kStringGenericInteract_29
+ "Die Leitung ist hier unn\201tz.", // kStringGenericInteract_30
+ "Stark, das ist ja die Fortsetzung zum \"Anhalter\":|\"Das Restaurant am Ende des Universums\".", // kStringGenericInteract_31
+ "Moment mal, es ist ein Lesezeichen drin,|auf dem \"Zweiundvierzig\" steht.", // kStringGenericInteract_32
+ // 605
+ "Das tr\204gst du doch bei dir.", // kStringGenericInteract_33
+ "Du bist doch schon da.", // kStringGenericInteract_34
+ "Das hast du doch schon.", // kStringGenericInteract_35
+ "Das brauchst du nicht.", // kStringGenericInteract_36
+ "Das kannst du nicht nehmen.", // kStringGenericInteract_37
+ // 610
+ "Das l\204\341t sich nicht \224ffnen.", // kStringGenericInteract_38
+ "Das ist schon offen.", // kStringGenericInteract_39
+ "Das ist verschlossen.", // kStringGenericInteract_40
+ "Das l\204\341t sich nicht schlie\341en.", // kStringGenericInteract_41
+ "Behalt es lieber!", // kStringGenericInteract_42
+ // 615
+ "Das geht nicht.", // kStringGenericInteract_43
+ "Gespr\204ch beenden", // kStringConversationEnd
+ "Du hast das komische Gef\201hl,|da\341 drau\341en etwas passiert,|und eilst zum Restaurant.", // kStringSupernova1
+ "Da! Die Supernova!", // kStringSupernova2
+ "Zwei Minuten sp\204ter ...", // kStringSupernova3
+ // 620
+ "Hey, was machen Sie in meinem Raumschiff?!", // kStringSupernova4
+ "Geben Sie mir sofort meine Brieftasche wieder!", // kStringSupernova5
+ "Versuchen Sie das ja nicht nochmal!", // kStringSupernova6
+ "Und jetzt raus mit Ihnen!", // kStringSupernova7
+ "Zehn Minuten sp\204ter ...", // kStringSupernova8
+ // 625
+ "Textgeschwindigkeit:", // kStringTextSpeed
+ "Was war das f\201r ein Ger\204usch?", // kStringGuardNoticed1
+ "Ich werde mal nachsehen.", // kStringGuardNoticed2
+ "Guten Tag, hier ist Horst Hummel.", // kStringTelomat1
+ "Hier ist %s. K\224nnen Sie mal gerade kommen?", // kStringTelomat2
+ // 630
+ "Es ist sehr wichtig.", // kStringTelomat3
+ "Vom Mars.", // kStringTelomat4
+ "Vom Klo.", // kStringTelomat5
+ "Das werde ich kaum erz\204hlen.", // kStringTelomat6
+ "1 B\201romanager", // kStringTelomat7
+ // 635
+ "2 Telomat", // kStringTelomat8
+ "3 ProText", // kStringTelomat9
+ "4 Calculata", // kStringTelomat10
+ "Bitte w\204hlen", // kStringTelomat11
+ "Geben Sie den gew\201nschten Namen ein:", // kStringTelomat12
+ // 640
+ "(Vor- und Nachname)", // kStringTelomat13
+ "Name unbekannt", // kStringTelomat14
+ "Verbindung unm\224glich", // kStringTelomat15
+ "Verbindung wird hergestellt", // kStringTelomat16
+ "%s am Apparat.", // kStringTelomat17
+ // 645
+ "Huch, Sie h\224ren sich aber|nicht gut an. Ich komme sofort.", // kStringTelomat18
+ "Horst Hummel! Von wo rufen Sie an?", // kStringTelomat19
+ "Hmm, keine Antwort.", // kStringTelomat20
+ "Passwort:", // kStringTelomat21
+ "Deine Armbanduhr piepst,|die Alarmzeit ist erreicht.", // kStringAlarm
+ NULL
+};
+
+
+
+#endif // GAMETEXT_H
diff --git a/devtools/create_supernova/img1-en.pbm b/devtools/create_supernova/img1-en.pbm
new file mode 100644
index 0000000000..f1a76940e0
--- /dev/null
+++ b/devtools/create_supernova/img1-en.pbm
Binary files differ
diff --git a/devtools/create_supernova/img1-en.xcf b/devtools/create_supernova/img1-en.xcf
new file mode 100644
index 0000000000..3231a06896
--- /dev/null
+++ b/devtools/create_supernova/img1-en.xcf
Binary files differ
diff --git a/devtools/create_supernova/module.mk b/devtools/create_supernova/module.mk
new file mode 100644
index 0000000000..806cccadaa
--- /dev/null
+++ b/devtools/create_supernova/module.mk
@@ -0,0 +1,12 @@
+MODULE := devtools/create_supernova
+
+MODULE_OBJS := \
+ file.o \
+ po_parser.o \
+ create_supernova.o
+
+# Set the name of the executable
+TOOL_EXECUTABLE := create_supernova
+
+# Include common rules
+include $(srcdir)/rules.mk
diff --git a/devtools/create_supernova/po_parser.cpp b/devtools/create_supernova/po_parser.cpp
new file mode 100644
index 0000000000..f4a9b96388
--- /dev/null
+++ b/devtools/create_supernova/po_parser.cpp
@@ -0,0 +1,221 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "po_parser.h"
+
+PoMessageList::PoMessageList() : _list(NULL), _size(0), _allocated(0) {
+}
+
+PoMessageList::~PoMessageList() {
+ for (int i = 0; i < _size; ++i)
+ delete _list[i];
+ delete[] _list;
+}
+
+int PoMessageList::compareString(const char* left, const char* right) {
+ if (left == NULL && right == NULL)
+ return 0;
+ if (left == NULL)
+ return -1;
+ if (right == NULL)
+ return 1;
+ return strcmp(left, right);
+}
+
+int PoMessageList::compareMessage(const char *msgLeft, const char *contextLeft, const char *msgRight, const char *contextRight) {
+ int compare = compareString(msgLeft, msgRight);
+ if (compare != 0)
+ return compare;
+ return compareString(contextLeft, contextRight);
+}
+
+void PoMessageList::insert(const char *translation, const char *msg, const char *context) {
+ if (msg == NULL || *msg == '\0' || translation == NULL || *translation == '\0')
+ return;
+
+ // binary-search for the insertion index
+ int leftIndex = 0;
+ int rightIndex = _size - 1;
+ while (rightIndex >= leftIndex) {
+ int midIndex = (leftIndex + rightIndex) / 2;
+ int compareResult = compareMessage(msg, context, _list[midIndex]->msgid, _list[midIndex]->msgctxt);
+ if (compareResult == 0)
+ return; // The message is already in this list
+ else if (compareResult < 0)
+ rightIndex = midIndex - 1;
+ else
+ leftIndex = midIndex + 1;
+ }
+ // We now have rightIndex = leftIndex - 1 and we need to insert the new message
+ // between the two (i.a. at leftIndex).
+ if (_size + 1 > _allocated) {
+ _allocated += 100;
+ PoMessage **newList = new PoMessage*[_allocated];
+ for (int i = 0; i < leftIndex; ++i)
+ newList[i] = _list[i];
+ for (int i = leftIndex; i < _size; ++i)
+ newList[i + 1] = _list[i];
+ delete[] _list;
+ _list = newList;
+ } else {
+ for (int i = _size - 1; i >= leftIndex; --i)
+ _list[i + 1] = _list[i];
+ }
+ _list[leftIndex] = new PoMessage(translation, msg, context);
+ ++_size;
+}
+
+const char *PoMessageList::findTranslation(const char *msg, const char *context) {
+ if (msg == NULL || *msg == '\0')
+ NULL;
+
+ // binary-search for the message
+ int leftIndex = 0;
+ int rightIndex = _size - 1;
+ while (rightIndex >= leftIndex) {
+ int midIndex = (leftIndex + rightIndex) / 2;
+ int compareResult = compareMessage(msg, context, _list[midIndex]->msgid, _list[midIndex]->msgctxt);
+ if (compareResult == 0)
+ return _list[midIndex]->msgstr;
+ else if (compareResult < 0)
+ rightIndex = midIndex - 1;
+ else
+ leftIndex = midIndex + 1;
+ }
+ return NULL;
+}
+
+PoMessageList *parsePoFile(const char *file) {
+ FILE *inFile = fopen(file, "r");
+ if (!inFile)
+ return NULL;
+
+ char msgidBuf[1024], msgctxtBuf[1024], msgstrBuf[1024];
+ char line[1024], *currentBuf = msgstrBuf;
+
+ PoMessageList *list = new PoMessageList();
+
+ // Initialize the message attributes.
+ bool fuzzy = false;
+ bool fuzzy_next = false;
+
+ // Parse the file line by line.
+ // The msgstr is always the last line of an entry (i.e. msgid and msgctxt always
+ // precede the corresponding msgstr).
+ msgidBuf[0] = msgstrBuf[0] = msgctxtBuf[0] = '\0';
+ while (!feof(inFile) && fgets(line, 1024, inFile)) {
+ if (line[0] == '#' && line[1] == ',') {
+ // Handle message attributes.
+ if (strstr(line, "fuzzy")) {
+ fuzzy_next = true;
+ continue;
+ }
+ }
+ // Skip empty and comment line
+ if (*line == '\n' || *line == '#')
+ continue;
+ if (strncmp(line, "msgid", 5) == 0) {
+ if (currentBuf == msgstrBuf) {
+ // add previous entry
+ if (*msgstrBuf != '\0' && !fuzzy)
+ list->insert(msgstrBuf, msgidBuf, msgctxtBuf);
+ msgidBuf[0] = msgstrBuf[0] = msgctxtBuf[0] = '\0';
+
+ // Reset the attribute flags.
+ fuzzy = fuzzy_next;
+ fuzzy_next = false;
+ }
+ strcpy(msgidBuf, stripLine(line));
+ currentBuf = msgidBuf;
+ } else if (strncmp(line, "msgctxt", 7) == 0) {
+ if (currentBuf == msgstrBuf) {
+ // add previous entry
+ if (*msgstrBuf != '\0' && !fuzzy)
+ list->insert(msgstrBuf, msgidBuf, msgctxtBuf);
+ msgidBuf[0] = msgstrBuf[0] = msgctxtBuf[0] = '\0';
+
+ // Reset the attribute flags
+ fuzzy = fuzzy_next;
+ fuzzy_next = false;
+ }
+ strcpy(msgctxtBuf, stripLine(line));
+ currentBuf = msgctxtBuf;
+ } else if (strncmp(line, "msgstr", 6) == 0) {
+ strcpy(msgstrBuf, stripLine(line));
+ currentBuf = msgstrBuf;
+ } else {
+ // concatenate the string at the end of the current buffer
+ if (currentBuf)
+ strcat(currentBuf, stripLine(line));
+ }
+ }
+ if (currentBuf == msgstrBuf) {
+ // add last entry
+ if (*msgstrBuf != '\0' && !fuzzy)
+ list->insert(msgstrBuf, msgidBuf, msgctxtBuf);
+ }
+
+ fclose(inFile);
+ return list;
+}
+
+char *stripLine(char *const line) {
+ // This function modifies line in place and return it.
+ // Keep only the text between the first two unprotected quotes.
+ // It also look for literal special characters (e.g. preceded by '\n', '\\', '\"', '\'', '\t')
+ // and replace them by the special character so that strcmp() can match them at run time.
+ // Look for the first quote
+ char const *src = line;
+ while (*src != '\0' && *src++ != '"') {}
+ // shift characters until we reach the end of the string or an unprotected quote
+ char *dst = line;
+ while (*src != '\0' && *src != '"') {
+ char c = *src++;
+ if (c == '\\') {
+ switch (c = *src++) {
+ case 'n': c = '\n'; break;
+ case 't': c = '\t'; break;
+ case '\"': c = '\"'; break;
+ case '\'': c = '\''; break;
+ case '\\': c = '\\'; break;
+ default:
+ // Just skip
+ fprintf(stderr, "Unsupported special character \"\\%c\" in string. Please contact ScummVM developers.\n", c);
+ continue;
+ }
+ }
+ *dst++ = c;
+ }
+ *dst = '\0';
+ return line;
+}
+
+char *parseLine(const char *line, const char *field) {
+ // This function allocate and return a new char*.
+ // It will return a NULL pointer if the field is not found.
+ // It is used to parse the header of the po files to find the language name
+ // and the charset.
+ const char *str = strstr(line, field);
+ if (str == NULL)
+ return NULL;
+ str += strlen(field);
+ // Skip spaces
+ while (*str != '\0' && isspace(*str)) {
+ ++str;
+ }
+ // Find string length (stop at the first '\n')
+ int len = 0;
+ while (str[len] != '\0' && str[len] != '\n') {
+ ++len;
+ }
+ if (len == 0)
+ return NULL;
+ // Create result string
+ char *result = new char[len + 1];
+ strncpy(result, str, len);
+ result[len] = '\0';
+ return result;
+}
+
diff --git a/devtools/create_supernova/po_parser.h b/devtools/create_supernova/po_parser.h
new file mode 100644
index 0000000000..7c358e32f6
--- /dev/null
+++ b/devtools/create_supernova/po_parser.h
@@ -0,0 +1,78 @@
+/* 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.
+ *
+ * This is a utility for generating a data file for the supernova engine.
+ * It contains strings extracted from the original executable as well
+ * as translations and is required for the engine to work properly.
+ */
+
+#ifndef PO_PARSER_H
+#define PO_PARSER_H
+
+struct PoMessage {
+ char *msgstr;
+ char *msgid;
+ char *msgctxt;
+
+ PoMessage(const char *translation, const char *message, const char *context = NULL) :
+ msgstr(NULL), msgid(NULL), msgctxt(NULL)
+ {
+ if (translation != NULL && *translation != '\0') {
+ msgstr = new char[1 + strlen(translation)];
+ strcpy(msgstr, translation);
+ }
+ if (message != NULL && *message != '\0') {
+ msgid = new char[1 + strlen(message)];
+ strcpy(msgid, message);
+ }
+ if (context != NULL && *context != '\0') {
+ msgctxt = new char[1 + strlen(context)];
+ strcpy(msgctxt, context);
+ }
+ }
+ ~PoMessage() {
+ delete[] msgstr;
+ delete[] msgid;
+ delete[] msgctxt;
+ }
+};
+
+class PoMessageList {
+public:
+ PoMessageList();
+ ~PoMessageList();
+
+ void insert(const char *translation, const char *msg, const char *context = NULL);
+ const char *findTranslation(const char *msg, const char *context = NULL);
+
+private:
+ int compareString(const char *left, const char *right);
+ int compareMessage(const char *msgLeft, const char *contextLeft, const char *msgRight, const char *contextRight);
+
+ PoMessage **_list;
+ int _size;
+ int _allocated;
+};
+
+PoMessageList *parsePoFile(const char *file);
+char *stripLine(char *);
+char *parseLine(const char *line, const char *field);
+
+#endif /* PO_PARSER_H */
diff --git a/devtools/create_supernova/strings-en.po b/devtools/create_supernova/strings-en.po
new file mode 100644
index 0000000000..f1c9d2fae2
--- /dev/null
+++ b/devtools/create_supernova/strings-en.po
@@ -0,0 +1,2905 @@
+# Mission Supernova Translation.
+# Copyright (C) YEAR ScummVM Team
+# This file is distributed under the same license as the ScummVM package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Mission Supernova 1.0\n"
+"Report-Msgid-Bugs-To: scummvm-devel@lists.scummvm.org\n"
+"POT-Creation-Date: 2017-07-22 19:53+0100\n"
+"PO-Revision-Date: 2018-01-07 18:01+0000\n"
+"Last-Translator: Joseph-Eugene Winzer <Joe.Winzer@gmx.de>\n"
+"Language-Team: none\n"
+"Language: en\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CP850\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Generator: Weblate 2.9\n"
+
+#. I18N: Go
+#: ../../msn/msn.c:1610
+msgid "Gehe"
+msgstr "Go"
+
+#. I18N: Look
+#: ../../msn/msn.c:1612
+msgid "Schau"
+msgstr "Look"
+
+#. I18N: Take
+#: ../../msn/msn.c:1614
+msgid "Nimm"
+msgstr "Take"
+
+#. I18N: Open
+#: ../../msn/msn.c:1616
+msgid "™ffne"
+msgstr "Open"
+
+#. I18N: Close
+#: ../../msn/msn.c:1618
+msgid "Schlieáe"
+msgstr "Close"
+
+#. I18N: Push
+#: ../../msn/msn.c:1620
+msgid "Drcke"
+msgstr "Push"
+
+#. I18N: Pull
+#: ../../msn/msn.c:1622
+msgid "Ziehe"
+msgstr "Pull"
+
+#. I18N: Use
+#: ../../msn/msn.c:1624
+msgid "Benutze"
+msgstr "Use"
+
+#. I18N: Talk
+#: ../../msn/msn.c:1626
+msgid "Rede"
+msgstr "Talk"
+
+#. I18N: Give
+#: ../../msn/msn.c:1628
+msgid "Gib"
+msgstr "Give"
+
+#. I18N: End of conversation
+#: ../../msn/msn.c:2204
+msgid "Gespr„ch beenden"
+msgstr "End of conversation"
+
+#. I18N: Go to
+#: ../../msn/msn.c:2334
+msgid "Gehe zu "
+msgstr "Go to "
+
+#. I18N: Look at
+#: ../../msn/msn.c:2336
+msgid "Schau "
+msgstr "Look at "
+
+#. I18N: Take
+#: ../../msn/msn.c:2338
+msgid "Nimm "
+msgstr "Take "
+
+#. I18N: Open
+#: ../../msn/msn.c:2340
+msgid "™ffne "
+msgstr "Open "
+
+#. I18N: Close
+#: ../../msn/msn.c:2342
+msgid "Schlieáe "
+msgstr "Close "
+
+#. I18N: Push
+#: ../../msn/msn.c:2344
+msgid "Drcke "
+msgstr "Push "
+
+#. I18N: Pull
+#: ../../msn/msn.c:2346
+msgid "Ziehe "
+msgstr "Pull "
+
+#. I18N: Use
+#: ../../msn/msn.c:2348
+msgid "Benutze "
+msgstr "Use "
+
+#. I18N: Talk to
+#: ../../msn/msn.c:2350
+msgid "Rede mit "
+msgstr "Talk to "
+
+#. I18N: Give
+#: ../../msn/msn.c:2352
+msgid "Gib "
+msgstr "Give "
+
+#: ../../msn/msn.c:2368
+msgid " an "
+msgstr " to "
+
+#: ../../msn/msn.c:2371
+msgid " mit "
+msgstr " with "
+
+#. I18N: Load
+#: ../../msn/msn.c:2880
+msgid "Laden"
+msgstr "Load"
+
+#. I18N: Save
+#: ../../msn/msn.c:2883
+msgid "Speichern"
+msgstr "Save"
+
+#. I18N: Back
+#: ../../msn/msn.c:2886
+msgid "Zurck"
+msgstr "Back"
+
+#. I18N: Restart
+#: ../../msn/msn.c:2889
+msgid "Neustart"
+msgstr "Restart"
+
+#. I18N: Help
+#: ../../msn/msn.c:3163
+msgid "F1 Hilfe"
+msgstr "F1 Help"
+
+#. I18N: Instructions
+#: ../../msn/msn.c:3165
+msgid "F2 Anleitung"
+msgstr "F2 Instructions"
+
+#. I18N: Program information
+#: ../../msn/msn.c:3167
+msgid "F3 Programminformationen"
+msgstr "F3 Program information"
+
+#. I18N: Text Speed
+#: ../../msn/msn.c:3169
+msgid "F4 Textgeschwindigkeit"
+msgstr "F4 Text speed"
+
+#. I18N: Load / Save
+#: ../../msn/msn.c:3171
+msgid "F5 Laden / Speichern"
+msgstr "F5 Load / Save"
+
+#. I18N: Skip intro
+#: ../../msn/msn.c:3173
+msgid "ESC Vorspann berspringen"
+msgstr "ESC Skip intro"
+
+#. I18N: Exit program
+#: ../../msn/msn.c:3175
+msgid "Alt-X Programm abbrechen"
+msgstr "Alt-X Exit program"
+
+#. I18N: Text Speed
+#: ../../msn/msn.c:3219
+msgid "Textgeschwindigkeit:"
+msgstr "Text speed:"
+
+#. I18N: Leave game?
+#: ../../msn/msn.c:3267
+msgid "Spiel abbrechen?"
+msgstr "Leave game?"
+
+#: ../../msn/msn.c:3270
+msgid "Ja"
+msgstr "Yes"
+
+#: ../../msn/msn.c:3271
+msgid "Nein"
+msgstr "No"
+
+#. I18N: You already carry this.
+#: ../../msn/msn.c:3341
+msgid "Das tr„gst du doch bei dir."
+msgstr "You already carry this."
+
+#. I18N: You're already there.
+#: ../../msn/msn.c:3344
+msgid "Du bist doch schon da."
+msgstr "You are already there."
+
+#. I18N: This is closed
+#: ../../msn/msn.c:3347 ../../msn/msn_r1.c:683
+msgid "Das ist geschlossen."
+msgstr "This is closed."
+
+#. I18N: You already have that
+#: ../../msn/msn.c:3357
+msgid "Das hast du doch schon."
+msgstr "You already have that."
+
+#. I18N: You do not need that.
+#: ../../msn/msn.c:3360
+msgid "Das brauchst du nicht."
+msgstr "You don't need that."
+
+#. I18N: You can't take that.
+#: ../../msn/msn.c:3363
+msgid "Das kannst du nicht nehmen."
+msgstr "You can't take that."
+
+#. I18N: This can't be opened
+#: ../../msn/msn.c:3370
+msgid "Das l„át sich nicht ”ffnen."
+msgstr "This cannot be opened."
+
+#. I18N: This is already opened.
+#: ../../msn/msn.c:3373
+msgid "Das ist schon offen."
+msgstr "This is already opened."
+
+#. I18N: This is locked.
+#: ../../msn/msn.c:3376
+msgid "Das ist verschlossen."
+msgstr "This is locked."
+
+#. I18N: This can't be closed.
+#: ../../msn/msn.c:3393
+msgid "Das l„át sich nicht schlieáen."
+msgstr "This cannot be closed."
+
+#. I18N: This is already closed.
+#: ../../msn/msn.c:3396 ../../msn/msn_r1.c:829
+msgid "Das ist schon geschlossen."
+msgstr "This is already closed."
+
+#. I18N: Better keep it!
+#: ../../msn/msn.c:3412
+msgid "Behalt es lieber!"
+msgstr "Better keep it!"
+
+#. I18N: This is not possible.
+#: ../../msn/msn.c:3418
+msgid "Das geht nicht."
+msgstr "You can't do that."
+
+#: ../../msn/msn_mod.c:573
+msgid "^(C) 1994 Thomas und Steffen Dingel#"
+msgstr "^(C) 1994 Thomas and Steffen Dingel#"
+
+#: ../../msn/msn_mod.c:574
+msgid "Story und Grafik:^ Thomas Dingel#"
+msgstr "Story and Graphics:^ Thomas Dingel#"
+
+#: ../../msn/msn_mod.c:575
+msgid "Programmierung:^ Steffen Dingel#"
+msgstr "Programming:^ Steffen Dingel#"
+
+#: ../../msn/msn_mod.c:576
+msgid "Musik:^ Bernd Hoffmann#"
+msgstr "Music:^ Bernd Hoffmann#"
+
+#: ../../msn/msn_mod.c:577
+msgid "Getestet von ...#"
+msgstr "Tested by ...#"
+
+#: ../../msn/msn_mod.c:587
+msgid "^ E#N#D#E ...########"
+msgstr "^ T#H#E E#N#D ...########"
+
+#: ../../msn/msn_mod.c:588
+msgid "# ... des ersten Teils!########"
+msgstr "# ... of the first part!########"
+
+#: ../../msn/msn_mod.c:590
+msgid "^Aber:#"
+msgstr "^But:#"
+
+#: ../../msn/msn_mod.c:591
+msgid "Das Abenteuer geht weiter, ...##"
+msgstr "The adventure continues ...##"
+
+#: ../../msn/msn_mod.c:592
+msgid "... wenn Sie sich fr 30,- DM registrieren lassen!##"
+msgstr "... if you register for 30, - DM!##"
+
+#: ../../msn/msn_mod.c:593
+msgid "(Falls Sie das nicht schon l„ngst getan haben.)##"
+msgstr "(If you have not already done so.)##"
+
+#: ../../msn/msn_mod.c:594
+msgid "In^ Teil 2 - Der Doppelg„nger^ erwarten Sie:##"
+msgstr "In^ Part 2 - The Doppelganger^ you can expect:##"
+
+#: ../../msn/msn_mod.c:595
+msgid "Knifflige Puzzles,##"
+msgstr "tricky puzzles,##"
+
+#: ../../msn/msn_mod.c:596
+msgid "noch mehr Grafik und Sound,##"
+msgstr "even more graphics and sound,##"
+
+#: ../../msn/msn_mod.c:597
+msgid "ein perfekt geplanter Museumseinbruch,##"
+msgstr "a perfectly planned museum burglary,##"
+
+#: ../../msn/msn_mod.c:598
+msgid "das Virtual-Reality-Spiel \"Indiana Joe\"##"
+msgstr "the virtual reality game \"Indiana Joe\"##"
+
+#: ../../msn/msn_mod.c:599
+msgid "und vieles mehr!##"
+msgstr "and much more!##"
+
+#. I18N: There's nothing special about it
+#: ../../msn/msn_r0.c:26
+msgid "Es ist nichts Besonderes daran."
+msgstr "There's nothing special about it."
+
+#. I18N: You first have to take it
+#: ../../msn/msn_r0.c:28 ../../msn/msn_r0.c:230
+msgid "Das muát du erst nehmen."
+msgstr "You first have to take it."
+
+#. I18N: Hello
+#: ../../msn/msn_r0.c:33
+msgid "Hallo!"
+msgstr "Hello!"
+
+#. I18N: Good day!
+#: ../../msn/msn_r0.c:35
+msgid "Guten Tag!"
+msgstr "Good day!"
+
+#. I18N: It's me, Horst Hummel
+#: ../../msn/msn_r0.c:37
+msgid "Ich bin's, Horst Hummel."
+msgstr "It's me, Horst Hummel."
+
+#: ../../msn/msn_r0.c:127
+#, c-format
+msgid "%d Xa"
+msgstr "%d Xa"
+
+#: ../../msn/msn_r0.c:147
+msgid "Ok."
+msgstr "OK."
+
+#: ../../msn/msn_r0.c:166
+msgid "Irgendwie ist ein Raumhelm|beim Essen unpraktisch."
+msgstr "Somehow, a space helmet is|impractical when eating."
+
+#: ../../msn/msn_r0.c:182 ../../msn/msn_r0.c:192
+msgid "Schmeckt ganz gut."
+msgstr "Tastes good."
+
+#: ../../msn/msn_r0.c:194
+msgid "Da war irgendetwas drin,|aber jetzt hast du es|mit runtergeschluckt."
+msgstr "There was something in it, but now you swallowed it."
+
+#: ../../msn/msn_r0.c:202
+msgid "Du hast es doch schon ge”ffnet."
+msgstr "You've already opened it."
+
+#: ../../msn/msn_r0.c:206
+msgid "In dem Ei ist eine Tablette|in einer Plastikhlle."
+msgstr "The egg contains a pill|in a plastic sleeve."
+
+#: ../../msn/msn_r0.c:214
+msgid "Du iát die Tablette und merkst,|daá sich irgendetwas ver„ndert hat."
+msgstr "You eat the pill and realize|that something has changed."
+
+#: ../../msn/msn_r0.c:224
+msgid ""
+"Komisch! Auf einmal kannst du die Schrift lesen!|Darauf steht:\"Wenn Sie "
+"diese Schrift jetzt|lesen k”nnen, hat die Tablette gewirkt.\""
+msgstr ""
+"Funny! Now you can read the inscription!|It says, \"If you can read this "
+"text now,|the pill has worked.\""
+
+#: ../../msn/msn_r0.c:232
+msgid "Sie ist leer."
+msgstr "It is empty."
+
+#: ../../msn/msn_r0.c:235
+msgid "Du findest 10 Buckazoids und eine Keycard."
+msgstr "You find 10 buckazoids and a keycard."
+
+#: ../../msn/msn_r0.c:242
+msgid "Es ist eine Art elektronische Zeitung."
+msgstr "This is a kind of electronic newspaper."
+
+#: ../../msn/msn_r0.c:245
+msgid "Halt, hier ist ein interessanter Artikel."
+msgstr "Here, this article looks interesting."
+
+#: ../../msn/msn_r0.c:268
+msgid "Hmm, irgendwie komme|ich mir verarscht vor."
+msgstr "Hmm, somehow|I feel tricked."
+
+#: ../../msn/msn_r0.c:273
+msgid "Es ist die Keycard des Commanders."
+msgstr "This is the keycard of the Commander."
+
+#: ../../msn/msn_r0.c:277
+msgid ""
+"Es ist eine Uhr mit extra|lautem Wecker. Sie hat einen|Knopf zum Verstellen "
+"der Alarmzeit.|Uhrzeit: %s Alarmzeit: %s"
+msgstr ""
+"This is a clock with a very loud alarm. It has a button|for adjusting the "
+"alarm time.|Time: %s Alarm: %s"
+
+#: ../../msn/msn_r0.c:291
+msgid "Neue Alarmzeit (hh:mm) :"
+msgstr "New alarm time (hh:mm):"
+
+#: ../../msn/msn_r0.c:332 ../../msn/msn_r1.c:486 ../../msn/msn_r1.c:595
+msgid "Leitung mit Lsterklemme"
+msgstr "Cable with terminal strip"
+
+#: ../../msn/msn_r0.c:344
+msgid "Kabelrolle mit Lsterklemme"
+msgstr "Cable reel with terminal strip"
+
+#: ../../msn/msn_r0.c:355 ../../msn/msn_r1.c:495 ../../msn/msn_r1.c:604
+msgid "Womit denn?"
+msgstr "With what?"
+
+#: ../../msn/msn_r0.c:366 ../../msn/msn_r1.c:499 ../../msn/msn_r1.c:608
+#: ../../msn/msn_r1_r.c:115
+msgid "langes Kabel mit Stecker"
+msgstr "long cable with plug"
+
+#: ../../msn/msn_r0.c:381 ../../msn/msn_r0.c:418 ../../msn/msn_r0.c:454
+msgid "Die Luft hier ist atembar,|du ziehst den Anzug aus."
+msgstr "The air here is breathable,|you take off your suit."
+
+#: ../../msn/msn_r0.c:387 ../../msn/msn_r0.c:424 ../../msn/msn_r0.c:460
+msgid "Hier drinnen brauchtst du deinen Anzug nicht."
+msgstr "Inside you do not need your suit."
+
+#: ../../msn/msn_r0.c:395
+msgid "Du muát erst den Helm abnehmen."
+msgstr "You must take off your helmet first."
+
+#: ../../msn/msn_r0.c:397
+msgid "Du muát erst den Versorgungsteil abnehmen."
+msgstr "You must take off your oxygen supply unit first."
+
+#: ../../msn/msn_r0.c:401
+msgid "Du ziehst den Raumanzug aus."
+msgstr "Your take off your space suit."
+
+#: ../../msn/msn_r0.c:407
+msgid "Du ziehst den Raumanzug an."
+msgstr "You put on your space suit."
+
+#: ../../msn/msn_r0.c:431
+msgid "Den Helm h„ttest du|besser angelassen!"
+msgstr "You should have kept your helmet on!"
+
+#: ../../msn/msn_r0.c:433
+msgid "Du ziehst den Helm ab."
+msgstr "You take off your helmet."
+
+#: ../../msn/msn_r0.c:441
+msgid "Du ziehst den Helm auf."
+msgstr "You put on your helmet."
+
+#: ../../msn/msn_r0.c:443 ../../msn/msn_r0.c:479
+msgid "Du muát erst den Anzug anziehen."
+msgstr "You must wear the suit first."
+
+#: ../../msn/msn_r0.c:467
+msgid "Den Versorungsteil h„ttest du|besser nicht abgenommen!"
+msgstr "You should not have taken off your oxygen supply unit!"
+
+#: ../../msn/msn_r0.c:469
+msgid "Du nimmst den Versorgungsteil ab."
+msgstr "You take off your oxygen supply unit."
+
+#: ../../msn/msn_r0.c:477
+msgid "Du ziehst den Versorgungsteil an."
+msgstr "You put on your oxygen supply unit."
+
+#: ../../msn/msn_r0.c:489
+msgid "Die Leitung ist hier unntz."
+msgstr "The cable is useless here."
+
+#: ../../msn/msn_r0.c:492
+msgid ""
+"Stark, das ist ja die Fortsetzung zum \"Anhalter\":|\"Das Restaurant am Ende "
+"des Universums\"."
+msgstr ""
+"Great, this is the sequel to the \"Hitchhiker\":|\"The Restaurant at the End "
+"of the Universe\"."
+
+#: ../../msn/msn_r0.c:495
+msgid ""
+"Moment mal, es ist ein Lesezeichen drin,|auf dem \"Zweiundvierzig\" steht."
+msgstr "Wait a minute, there is a bookmark in it|that says \"Forty-two\"."
+
+#: ../../msn/msn_r0.c:507
+msgid "Du h„ttest besser vorher|den Stecker rausgezogen."
+msgstr "You should have pulled|the plug before."
+
+#: ../../msn/msn_r0.c:567
+msgid "Deine Armbanduhr piepst,|die Alarmzeit ist erreicht."
+msgstr "Your watch beeps,|this is the alarm."
+
+#: ../../msn/msn_r0.c:803 ../../msn/msn_r1_r.c:117
+msgid "Keycard"
+msgstr "Keycard"
+
+#: ../../msn/msn_r0.c:803
+msgid "Die Keycard fr deine Schr„nke."
+msgstr "The keycard for your locker."
+
+#: ../../msn/msn_r0.c:805
+msgid "Taschenmesser"
+msgstr "Pocket knife"
+
+#: ../../msn/msn_r0.c:805
+msgid "Es ist nicht mehr das sch„rfste."
+msgstr "It is quite blunt."
+
+#: ../../msn/msn_r0.c:807 ../../msn/msn_r3.c:1527
+msgid "Armbanduhr"
+msgstr "Watch"
+
+#: ../../msn/msn_r0.c:808 ../../msn/msn_r1_r.c:199
+msgid "Discman"
+msgstr "Discman"
+
+#: ../../msn/msn_r0.c:808 ../../msn/msn_r1_r.c:199
+msgid "Es ist eine \"Mad Monkeys\"-CD darin."
+msgstr "There is a \"Mad Monkeys\" CD in it."
+
+#: ../../msn/msn_r1.c:58
+msgid ""
+"In der Kche warst du schon|oft genug, im Moment hast|du keinen Appetit."
+msgstr ""
+"You have been often enough|in the kitchen and you are|no longer hungry."
+
+#. I18N: FORTYTWO
+#: ../../msn/msn_r1.c:91
+msgid "ZWEIUNDVIERZIG"
+msgstr "FORTY-TWO"
+
+#. I18N: Destination reached
+#: ../../msn/msn_r1.c:104
+msgid "Flugziel erreicht"
+msgstr "Destination reached"
+
+#. I18N: Energy depleted
+#: ../../msn/msn_r1.c:110
+msgid "Energie ersch”pft"
+msgstr "Energy depleted"
+
+#. I18N: Artificial coma interrupted
+#: ../../msn/msn_r1.c:112
+msgid "Tiefschlafprozess abgebrochen"
+msgstr "Stasis interrupted"
+
+#: ../../msn/msn_r1.c:120 ../../msn/msn_r1.c:156
+msgid "Bitte legen Sie sich in die angezeigte Schlafkammer."
+msgstr "Please lay down in the indicated stasis pod."
+
+#: ../../msn/msn_r1.c:125
+msgid "Bitte Passwort eingeben:"
+msgstr "Please enter your password:"
+
+#: ../../msn/msn_r1.c:135 ../../msn/msn_r3.c:1171
+msgid "Falsches Passwort"
+msgstr "Password incorrect"
+
+#: ../../msn/msn_r1.c:141
+msgid "Schlafdauer in Tagen:"
+msgstr "Sleep duration in days:"
+
+#: ../../msn/msn_r1.c:172
+msgid ""
+"Es wrde wenig bringen,|sich in eine Schlafkammer zu legen,|die nicht "
+"eingeschaltet ist."
+msgstr ""
+"You are not going to achieve anything|by using a stasis pod that is|not "
+"switched on."
+
+#: ../../msn/msn_r1.c:174
+msgid "Dazu muát du erst den Raumanzug ausziehen."
+msgstr "To do this you have to take off the space suit first."
+
+#: ../../msn/msn_r1.c:248 ../../msn/msn_s.c:210
+msgid "Was war das?"
+msgstr "What was that?"
+
+#: ../../msn/msn_r1.c:266
+msgid "Achtung"
+msgstr "Danger"
+
+#: ../../msn/msn_r1.c:289
+msgid ""
+"Du wachst mit brummendem Sch„del auf|und merkst, daá du nur getr„umt hast."
+msgstr ""
+"You wake up with a buzzing sensation in your head|and realise that it was "
+"only a dream."
+
+#: ../../msn/msn_r1.c:292
+msgid ""
+"Beim Aufprall des Raumschiffs|muát du mit dem Kopf aufgeschlagen|und "
+"bewuátlos geworden sein."
+msgstr ""
+"During the space ship impact|you must have hit your head|and lost "
+"consciousness."
+
+#: ../../msn/msn_r1.c:295
+msgid "Was steht dir jetzt wohl wirklich bevor?"
+msgstr "What is going to happen to you now?"
+
+#: ../../msn/msn_r1.c:307
+msgid "Geschwindigkeit: "
+msgstr "Speed: "
+
+#: ../../msn/msn_r1.c:308
+msgid "8000 hpm"
+msgstr "8000 hpm"
+
+#: ../../msn/msn_r1.c:309
+msgid "0 hpm"
+msgstr "0 hpm"
+
+#: ../../msn/msn_r1.c:310
+msgid "Ziel: Arsano 3"
+msgstr "Destination: Arsano 3"
+
+#: ../../msn/msn_r1.c:311
+msgid "Entfernung: "
+msgstr "Distance: "
+
+#: ../../msn/msn_r1.c:318
+msgid " Lichtjahre"
+msgstr " light years"
+
+#: ../../msn/msn_r1.c:319
+msgid "Dauer der Reise bei momentaner Geschwindigkeit:"
+msgstr "Duration of trip at current speed:"
+
+#: ../../msn/msn_r1.c:321
+msgid " Tage"
+msgstr " days"
+
+#: ../../msn/msn_r1.c:330
+msgid ""
+"Vergiá nicht, du bist nur der|Schiffskoch und hast keine Ahnung,|wie man ein "
+"Raumschiff fliegt."
+msgstr ""
+"Do not forget, you're only the|ship's cook and have no idea|how to fly a "
+"spaceship."
+
+#: ../../msn/msn_r1.c:344
+msgid "Achtung: Triebwerke funktionsunf„hig"
+msgstr "Warning: Engine malfunction"
+
+#: ../../msn/msn_r1.c:357
+msgid "Energievorrat ersch”pft"
+msgstr "Energy supply exhausted"
+
+#: ../../msn/msn_r1.c:358
+msgid "Notstromversorgung aktiv"
+msgstr "Emergency energy supply active"
+
+#: ../../msn/msn_r1.c:447
+msgid "Zu niedriger Luftdruck soll ungesund sein."
+msgstr "Air pressure too low unhealthy is."
+
+#: ../../msn/msn_r1.c:454
+msgid "Er zeigt Null an."
+msgstr "It indicates zero."
+
+#: ../../msn/msn_r1.c:455
+msgid "Er zeigt Normaldruck an."
+msgstr "It indicates normal pressure."
+
+#: ../../msn/msn_r1.c:464
+msgid "Ein Stck Schrott."
+msgstr "Some scrap metal."
+
+#: ../../msn/msn_r1.c:476
+msgid "Du muát erst hingehen."
+msgstr "You must go there first."
+
+#: ../../msn/msn_r1.c:480 ../../msn/msn_r1.c:639 ../../msn/msn_r1.c:728
+msgid "Das Kabel ist im Weg."
+msgstr "The cable is in the way."
+
+#: ../../msn/msn_r1.c:483 ../../msn/msn_r1.c:642 ../../msn/msn_r1.c:698
+msgid "Das Kabel ist schon ganz|richtig an dieser Stelle."
+msgstr "The cable is already in the right place."
+
+#: ../../msn/msn_r1.c:519
+msgid "Die Leitung ist zu kurz."
+msgstr "The line is too short."
+
+#: ../../msn/msn_r1.c:567
+msgid "Es ist nicht spitz genug."
+msgstr "It is not sharp enough."
+
+#: ../../msn/msn_r1.c:570
+msgid "Du wirst aus den Anzeigen nicht schlau."
+msgstr "You cannot make sense of it."
+
+#: ../../msn/msn_r1.c:572
+msgid "Laá lieber die Finger davon!"
+msgstr "You better keep your hands off!"
+
+#: ../../msn/msn_r1.c:591
+msgid "An dem Kabel ist doch gar kein Stecker."
+msgstr "There is no plug on the cable."
+
+#: ../../msn/msn_r1.c:635
+msgid "Du solltest die Luke vielleicht erst ”ffnen."
+msgstr "You should open the hatch first."
+
+#: ../../msn/msn_r1.c:668
+msgid "Das Seil ist im Weg."
+msgstr "The cable is in the way."
+
+#: ../../msn/msn_r1.c:685
+msgid "Das geht nicht.|Die Luke ist mindestens|5 Meter ber dem Boden."
+msgstr "That will not do.|The hatch is at least|5 meters above the ground."
+
+#: ../../msn/msn_r1.c:694
+msgid "Keycard des Commanders"
+msgstr "Keycard of the Commander"
+
+#: ../../msn/msn_r1.c:766
+msgid "Was ntzt dir der Anschluá|ohne eine Stromquelle?!"
+msgstr "What good would come from connecting it|without a power source?!"
+
+#: ../../msn/msn_r1.c:770
+msgid "Die Spannung ist auf Null abgesunken."
+msgstr "The voltage has dropped to zero."
+
+#: ../../msn/msn_r1.c:771
+msgid "Es zeigt volle Spannung an."
+msgstr "It displays full voltage."
+
+#: ../../msn/msn_r1.c:782
+msgid "Du muát die Luke erst ”ffnen."
+msgstr "You must open the hatch first."
+
+#: ../../msn/msn_r1.c:801
+msgid "Das Seil ist hier schon ganz richtig."
+msgstr "The cable is in the right place."
+
+#: ../../msn/msn_r1.c:806
+msgid "Das Kabel ist zu kurz."
+msgstr "The cable is too short."
+
+#: ../../msn/msn_r1.c:913
+msgid "Du hast die Platte schon aufgelegt."
+msgstr "You already put the record on."
+
+#: ../../msn/msn_r1.c:925
+msgid "Es ist doch gar keine Platte aufgelegt."
+msgstr "You haven't put a record on yet."
+
+#: ../../msn/msn_r1.c:960
+msgid "Die Platte scheint einen Sprung zu haben."
+msgstr "The record seems to be scratched."
+
+#: ../../msn/msn_r1.c:981
+msgid "Schneid doch besser ein|l„ngeres Stck Kabel ab!"
+msgstr "You should cut a longer|piece of cable!"
+
+#: ../../msn/msn_r1.c:1003
+msgid "Leitung mit Stecker"
+msgstr "Cable with plug"
+
+#: ../../msn/msn_r1.c:1008 ../../msn/msn_r3.c:75
+msgid "Das ist befestigt."
+msgstr "This is fixed."
+
+#: ../../msn/msn_r1.c:1084
+msgid "Du hast jetzt besseres zu tun."
+msgstr "You have better things to do now."
+
+#: ../../msn/msn_r1.c:1086
+msgid "Wenn du unbedingt aufs Klo|willst, spiel doch Larry 1."
+msgstr "If you absolutely want to go|to the loo, play Larry 1."
+
+#: ../../msn/msn_r1.c:1097
+msgid "Was?! Keiner im Cockpit!|Die sind wohl verrckt!"
+msgstr "What?! No one in the cockpit!|They're crazy!"
+
+#: ../../msn/msn_r1.c:1105
+msgid "Komisch, es ist nur|noch ein Raumanzug da."
+msgstr "Funny, there's only|one space suit."
+
+#: ../../msn/msn_r1.c:1113
+msgid ""
+"Was ist denn das fr ein Chaos?|Und auáerdem fehlt das Notraumschiff!|Jetzt "
+"wird mir einiges klar.|Die anderen sind geflchtet,|und ich habe es verpennt."
+msgstr ""
+"What is that chaos? And also|the escape ship is missing!|Now I understand. "
+"The others|have escaped, and they left|me behind."
+
+#: ../../msn/msn_r1_r.c:16 ../../msn/msn_r1_r.c:17 ../../msn/msn_r1_r.c:18
+#: ../../msn/msn_r1_r.c:19 ../../msn/msn_r1_r.c:20 ../../msn/msn_r1_r.c:21
+#: ../../msn/msn_r1_r.c:22 ../../msn/msn_r1_r.c:31 ../../msn/msn_r1_r.c:32
+#: ../../msn/msn_r1_r.c:34 ../../msn/msn_r1_r.c:44 ../../msn/msn_r1_r.c:45
+#: ../../msn/msn_r1_r.c:63 ../../msn/msn_r1_r.c:65 ../../msn/msn_r1_r.c:89
+#: ../../msn/msn_r1_r.c:93 ../../msn/msn_r1_r.c:108 ../../msn/msn_r1_r.c:120
+#: ../../msn/msn_r1_r.c:122 ../../msn/msn_r1_r.c:136 ../../msn/msn_r1_r.c:150
+#: ../../msn/msn_r1_r.c:165 ../../msn/msn_r1_r.c:201 ../../msn/msn_r1_r.c:219
+#: ../../msn/msn_r1_r.c:245 ../../msn/msn_r1_r.c:279
+msgid "Luke"
+msgstr "Hatch"
+
+#: ../../msn/msn_r1_r.c:23 ../../msn/msn_r1_r.c:67 ../../msn/msn_r1_r.c:68
+#: ../../msn/msn_r1_r.c:103 ../../msn/msn_r1_r.c:239 ../../msn/msn_r2.c:1256
+#: ../../msn/msn_r2.c:1293 ../../msn/msn_r2.c:1294 ../../msn/msn_r2.c:1295
+#: ../../msn/msn_r2.c:1296 ../../msn/msn_r3.c:1479 ../../msn/msn_r3.c:1677
+#: ../../msn/msn_r3.c:1678
+msgid "Knopf"
+msgstr "Button"
+
+#: ../../msn/msn_r1_r.c:23
+msgid "Er geh”rt zu der groáen Luke."
+msgstr "It belongs to the large hatch."
+
+#: ../../msn/msn_r1_r.c:24 ../../msn/msn_r1_r.c:37 ../../msn/msn_r1_r.c:130
+msgid "Leiter"
+msgstr "Ladder"
+
+#: ../../msn/msn_r1_r.c:25 ../../msn/msn_r1_r.c:47 ../../msn/msn_r1_r.c:57
+#: ../../msn/msn_r1_r.c:92 ../../msn/msn_r1_r.c:293 ../../msn/msn_r2.c:1221
+#: ../../msn/msn_r2.c:1223 ../../msn/msn_r2.c:1259 ../../msn/msn_r2.c:1277
+#: ../../msn/msn_r2.c:1292 ../../msn/msn_r3.c:1498 ../../msn/msn_r3.c:1499
+#: ../../msn/msn_r3.c:1506 ../../msn/msn_r3.c:1507 ../../msn/msn_r3.c:1508
+#: ../../msn/msn_r3.c:1515 ../../msn/msn_r3.c:1522 ../../msn/msn_r3.c:1523
+#: ../../msn/msn_r3.c:1535 ../../msn/msn_r3.c:1536 ../../msn/msn_r3.c:1543
+#: ../../msn/msn_r3.c:1544 ../../msn/msn_r3.c:1552 ../../msn/msn_r3.c:1553
+#: ../../msn/msn_r3.c:1561 ../../msn/msn_r3.c:1568 ../../msn/msn_r3.c:1578
+#: ../../msn/msn_r3.c:1579 ../../msn/msn_r3.c:1594 ../../msn/msn_r3.c:1608
+#: ../../msn/msn_r3.c:1679 ../../msn/msn_r3.c:1695
+msgid "Ausgang"
+msgstr "Exit"
+
+#: ../../msn/msn_r1_r.c:31
+msgid "Sie fhrt ins Cockpit."
+msgstr "It leads into the cockpit."
+
+#: ../../msn/msn_r1_r.c:32
+msgid "Sie fhrt zur Kche."
+msgstr "It leads to the kitchen."
+
+#: ../../msn/msn_r1_r.c:34
+msgid "Sie fhrt zu den Tiefschlafkammern."
+msgstr "It leads to the stasis pods."
+
+#: ../../msn/msn_r1_r.c:36 ../../msn/msn_r1_r.c:123 ../../msn/msn_r1_r.c:151
+#: ../../msn/msn_r1_r.c:166 ../../msn/msn_r1_r.c:179 ../../msn/msn_r1_r.c:180
+#: ../../msn/msn_r1_r.c:181 ../../msn/msn_r1_r.c:182 ../../msn/msn_r1_r.c:202
+#: ../../msn/msn_r1_r.c:220 ../../msn/msn_r1_r.c:246 ../../msn/msn_r1_r.c:256
+#: ../../msn/msn_r1_r.c:257 ../../msn/msn_r1_r.c:258 ../../msn/msn_r1_r.c:259
+#: ../../msn/msn_r1_r.c:280 ../../msn/msn_r2.c:1252 ../../msn/msn_r2.c:1298
+#: ../../msn/msn_r3.c:1696
+msgid "Schlitz"
+msgstr "Slot"
+
+#: ../../msn/msn_r1_r.c:36 ../../msn/msn_r1_r.c:123 ../../msn/msn_r1_r.c:151
+#: ../../msn/msn_r1_r.c:166 ../../msn/msn_r1_r.c:179 ../../msn/msn_r1_r.c:180
+#: ../../msn/msn_r1_r.c:181 ../../msn/msn_r1_r.c:182 ../../msn/msn_r1_r.c:202
+#: ../../msn/msn_r1_r.c:220 ../../msn/msn_r1_r.c:246 ../../msn/msn_r1_r.c:256
+#: ../../msn/msn_r1_r.c:257 ../../msn/msn_r1_r.c:258 ../../msn/msn_r1_r.c:259
+#: ../../msn/msn_r1_r.c:280
+msgid "Es ist ein Keycard-Leser."
+msgstr "It is a keycard reader."
+
+#: ../../msn/msn_r1_r.c:38 ../../msn/msn_r3.c:1595
+msgid "Gang"
+msgstr "Corridor"
+
+#: ../../msn/msn_r1_r.c:44 ../../msn/msn_r1_r.c:45
+msgid "Dies ist eine der Tiefschlafkammern."
+msgstr "This is one of the stasis pods."
+
+#: ../../msn/msn_r1_r.c:46 ../../msn/msn_r3.c:1622 ../../msn/msn_r3.c:1634
+#: ../../msn/msn_r3.c:1645 ../../msn/msn_r3.c:1657 ../../msn/msn_r3.c:1668
+msgid "Computer"
+msgstr "Computer"
+
+#: ../../msn/msn_r1_r.c:53 ../../msn/msn_r2.c:1302
+msgid "Instrumente"
+msgstr "Instruments"
+
+#: ../../msn/msn_r1_r.c:53
+msgid "Hmm, sieht ziemlich kompliziert aus."
+msgstr "Hmm, this looks pretty complicated."
+
+#: ../../msn/msn_r1_r.c:55 ../../msn/msn_r1_r.c:56 ../../msn/msn_r1_r.c:105
+msgid "Monitor"
+msgstr "Monitor"
+
+#: ../../msn/msn_r1_r.c:56
+msgid "Dieser Monitor sagt dir nichts."
+msgstr "There is nothing on this monitor."
+
+#: ../../msn/msn_r1_r.c:63
+msgid "Das ist eine Luke !!!"
+msgstr "This is a hatch !!!"
+
+#: ../../msn/msn_r1_r.c:65
+msgid "Dies ist eine Luke !!!"
+msgstr "This is a hatch !!!"
+
+#: ../../msn/msn_r1_r.c:69
+msgid "Helm"
+msgstr "Helmet"
+
+#: ../../msn/msn_r1_r.c:69
+msgid "Es ist der Helm zum Raumanzug."
+msgstr "This is the helmet for the space suit."
+
+#: ../../msn/msn_r1_r.c:70
+msgid "Raumanzug"
+msgstr "Space suit"
+
+#: ../../msn/msn_r1_r.c:70
+msgid "Der einzige Raumanzug, den die|anderen hiergelassen haben ..."
+msgstr "The only space suit left behind by the others..."
+
+#: ../../msn/msn_r1_r.c:72
+msgid "Versorgung"
+msgstr "Oxygen Supply Unit"
+
+#: ../../msn/msn_r1_r.c:72
+msgid "Es ist der Versorgungsteil zum Raumanzug."
+msgstr "It is the oxygen supply unit for the space suit."
+
+#: ../../msn/msn_r1_r.c:74
+msgid "Druckmesser"
+msgstr "Manometer"
+
+#: ../../msn/msn_r1_r.c:81 ../../msn/msn_r1_r.c:84
+msgid "Schrott"
+msgstr "Scrap"
+
+#: ../../msn/msn_r1_r.c:81
+msgid ""
+"Da ist eine Lsterklemme dran, die|noch ganz brauchbar aussieht.|Ich nehme "
+"sie mit."
+msgstr ""
+"There is a terminal strip on it|that looks quite useful.|I will take it with "
+"me."
+
+#: ../../msn/msn_r1_r.c:83
+msgid "Lsterklemme"
+msgstr "Terminal strip"
+
+#: ../../msn/msn_r1_r.c:84
+msgid ""
+"Junge, Junge! Die Explosion hat ein|ganz sch”nes Durcheinander angerichtet."
+msgstr "Boy, oh boy! The explosion created|quite a mess."
+
+#: ../../msn/msn_r1_r.c:86
+msgid "Reaktor"
+msgstr "Reactor"
+
+#: ../../msn/msn_r1_r.c:86
+msgid "Das war einmal der Reaktor."
+msgstr "This was a reactor once."
+
+#: ../../msn/msn_r1_r.c:87
+msgid "Dse"
+msgstr "Thruster"
+
+#: ../../msn/msn_r1_r.c:88
+msgid "blauer Krbis"
+msgstr "blue pumpkin"
+
+#: ../../msn/msn_r1_r.c:88
+msgid "Keine Ahnung, was das ist."
+msgstr "No idea what this is."
+
+#: ../../msn/msn_r1_r.c:90
+msgid "Landef„hre"
+msgstr "Landing module"
+
+#: ../../msn/msn_r1_r.c:90
+msgid "Sie war eigentlich fr Bodenuntersuchungen|auf Arsano 3 gedacht."
+msgstr "It was supposed to be used for soil analysis|on Arsano 3."
+
+#: ../../msn/msn_r1_r.c:93 ../../msn/msn_r1_r.c:120
+msgid "Sie fhrt nach drauáen."
+msgstr "It leads outside."
+
+#: ../../msn/msn_r1_r.c:95
+msgid "Generator"
+msgstr "Generator"
+
+#: ../../msn/msn_r1_r.c:95
+msgid "Er versorgt das Raumschiff mit Strom."
+msgstr "It supplies power to the spaceship."
+
+#: ../../msn/msn_r1_r.c:102 ../../msn/msn_r1_r.c:154 ../../msn/msn_r1_r.c:169
+#: ../../msn/msn_r1_r.c:205 ../../msn/msn_r1_r.c:223 ../../msn/msn_r1_r.c:249
+#: ../../msn/msn_r1_r.c:283 ../../msn/msn_r3.c:1486
+msgid "Steckdose"
+msgstr "Socket"
+
+#: ../../msn/msn_r1_r.c:103
+msgid ""
+"Es ist ein Sicherheitsknopf.|Er kann nur mit einem spitzen|Gegenstand "
+"gedrckt werden."
+msgstr "It's a safety button.|It can only be pushed|with a pointed object."
+
+#: ../../msn/msn_r1_r.c:106 ../../msn/msn_r2.c:1300
+msgid "Tastatur"
+msgstr "Keyboard"
+
+#: ../../msn/msn_r1_r.c:116
+msgid "leere Kabelrolle"
+msgstr "Empty cable reel"
+
+#: ../../msn/msn_r1_r.c:117
+msgid ""
+"Hey, das ist die Keycard des Commanders!|Er muá sie bei dem berstrzten|"
+"Aufbruch verloren haben."
+msgstr ""
+"Hey, that's the commander's keycard!|He must have lost it in the rushed|"
+"departure."
+
+#: ../../msn/msn_r1_r.c:119 ../../msn/msn_r1_r.c:137 ../../msn/msn_r1_r.c:188
+#: ../../msn/msn_r2.c:1212
+msgid "Seil"
+msgstr "Rope"
+
+#: ../../msn/msn_r1_r.c:124
+msgid "Klappe"
+msgstr "Hatch"
+
+#: ../../msn/msn_r1_r.c:125 ../../msn/msn_r1_r.c:128 ../../msn/msn_r1_r.c:242
+#: ../../msn/msn_r1_r.c:243 ../../msn/msn_r3.c:1485
+msgid "Leitung"
+msgstr "Cable"
+
+#: ../../msn/msn_r1_r.c:126
+msgid "Spannungmessger„t"
+msgstr "Voltmeter"
+
+#: ../../msn/msn_r1_r.c:127
+msgid "Klemme"
+msgstr "Clamp"
+
+#: ../../msn/msn_r1_r.c:128
+msgid "Sie fhrt vom Generator zum Spannungmessger„t."
+msgstr "It goes from the generator to the voltage meter."
+
+#: ../../msn/msn_r1_r.c:143 ../../msn/msn_r1_r.c:212 ../../msn/msn_r1_r.c:213
+#: ../../msn/msn_r1_r.c:214 ../../msn/msn_r1_r.c:217 ../../msn/msn_r3.c:1599
+#: ../../msn/msn_r3.c:1614 ../../msn/msn_r3.c:1636 ../../msn/msn_r3.c:1646
+#: ../../msn/msn_r3.c:1647
+msgid "Bild"
+msgstr "Image"
+
+#: ../../msn/msn_r1_r.c:143
+msgid "Manche Leute haben schon|einen komischen Geschmack."
+msgstr "Some people have funny tastes."
+
+#: ../../msn/msn_r1_r.c:145
+msgid "Zeichenger„te"
+msgstr "Drawing instruments"
+
+#: ../../msn/msn_r1_r.c:146
+msgid ""
+"Auf dem Zettel sind lauter|unverst„ndliche Skizzen und Berechnungen.|"
+"(Jedenfalls fr dich unverst„ndlich.)"
+msgstr ""
+"There are incomprehensible sketches|and calculations on that note.|(At "
+"least, it's incomprehensible to you.)"
+
+#: ../../msn/msn_r1_r.c:148 ../../msn/msn_r1_r.c:215 ../../msn/msn_r1_r.c:233
+#: ../../msn/msn_r1_r.c:276
+msgid "Magnete"
+msgstr "Magnets"
+
+#: ../../msn/msn_r1_r.c:148 ../../msn/msn_r1_r.c:215 ../../msn/msn_r1_r.c:233
+#: ../../msn/msn_r1_r.c:276
+msgid "Damit werden Sachen auf|dem Tisch festgehalten."
+msgstr "This keeps things|on the table."
+
+#: ../../msn/msn_r1_r.c:152 ../../msn/msn_r1_r.c:167 ../../msn/msn_r1_r.c:190
+#: ../../msn/msn_r1_r.c:203 ../../msn/msn_r1_r.c:221 ../../msn/msn_r1_r.c:247
+#: ../../msn/msn_r1_r.c:260 ../../msn/msn_r1_r.c:281
+msgid "Schrank"
+msgstr "Cabinet"
+
+#: ../../msn/msn_r1_r.c:153 ../../msn/msn_r1_r.c:168 ../../msn/msn_r1_r.c:183
+#: ../../msn/msn_r1_r.c:186 ../../msn/msn_r1_r.c:195 ../../msn/msn_r1_r.c:204
+#: ../../msn/msn_r1_r.c:222 ../../msn/msn_r1_r.c:248 ../../msn/msn_r1_r.c:262
+#: ../../msn/msn_r1_r.c:264 ../../msn/msn_r1_r.c:267 ../../msn/msn_r1_r.c:282
+#: ../../msn/msn_r2.c:1299
+msgid "Fach"
+msgstr "Storage compartment"
+
+#: ../../msn/msn_r1_r.c:155 ../../msn/msn_r1_r.c:170 ../../msn/msn_r1_r.c:206
+#: ../../msn/msn_r1_r.c:224 ../../msn/msn_r1_r.c:250 ../../msn/msn_r1_r.c:278
+#: ../../msn/msn_r2.c:1254
+msgid "Toilette"
+msgstr "Toilet"
+
+#: ../../msn/msn_r1_r.c:161 ../../msn/msn_r1_r.c:176 ../../msn/msn_r2.c:1283
+msgid "Schachspiel"
+msgstr "Chessboard"
+
+#: ../../msn/msn_r1_r.c:161
+msgid "Es macht wohl Spaá, an|der Decke Schach zu spielen."
+msgstr "I guess it's fun to play|chess on the ceiling."
+
+#: ../../msn/msn_r1_r.c:163
+msgid "Tennisschl„ger"
+msgstr "Tennis racquets"
+
+#: ../../msn/msn_r1_r.c:163
+msgid "Fliegt Boris Becker auch mit?"
+msgstr "Is Boris Becker part of the crew?"
+
+#: ../../msn/msn_r1_r.c:164
+msgid "Tennisball"
+msgstr "Tennis ball"
+
+#: ../../msn/msn_r1_r.c:164 ../../msn/msn_r1_r.c:213
+msgid "Toll!"
+msgstr "Awesome!"
+
+#: ../../msn/msn_r1_r.c:176
+msgid "Dein Magnetschachspiel. Schach war|schon immer deine Leidenschaft."
+msgstr "Your magnetic chess game. Chess|has always been your passion."
+
+#: ../../msn/msn_r1_r.c:178
+msgid "Bett"
+msgstr "Bed"
+
+#: ../../msn/msn_r1_r.c:178
+msgid "Das ist dein Bett. Toll, nicht wahr?"
+msgstr "This is your bed. Great, isn't it?"
+
+#: ../../msn/msn_r1_r.c:183 ../../msn/msn_r1_r.c:186 ../../msn/msn_r1_r.c:195
+msgid "Das ist eins deiner drei F„cher."
+msgstr "It's one of your three storage compartments."
+
+#: ../../msn/msn_r1_r.c:185
+msgid "Alben"
+msgstr "Albums"
+
+#: ../../msn/msn_r1_r.c:185
+msgid "Deine Briefmarkensammlung."
+msgstr "Your stamp collection."
+
+#: ../../msn/msn_r1_r.c:188
+msgid "Es ist ungef„hr 10 m lang und 4 cm dick."
+msgstr "It is about 10 m long and 4 cm thick."
+
+#: ../../msn/msn_r1_r.c:190
+msgid "Das ist dein Schrank."
+msgstr "This is your cabinet."
+
+#: ../../msn/msn_r1_r.c:191 ../../msn/msn_r1_r.c:274 ../../msn/msn_r1_r.c:275
+msgid "Krimskram"
+msgstr "Junk"
+
+#: ../../msn/msn_r1_r.c:191 ../../msn/msn_r1_r.c:274 ../../msn/msn_r1_r.c:275
+msgid "Es ist nichts brauchbares dabei."
+msgstr "There is nothing useful in there."
+
+#: ../../msn/msn_r1_r.c:192 ../../msn/msn_r1_r.c:273
+msgid "Kleider"
+msgstr "Clothes"
+
+#: ../../msn/msn_r1_r.c:192
+msgid "Es sind Standard-Weltraum-Klamotten."
+msgstr "They are standard space gear."
+
+#: ../../msn/msn_r1_r.c:193 ../../msn/msn_r1_r.c:269 ../../msn/msn_r1_r.c:271
+msgid "Unterw„sche"
+msgstr "Underwear"
+
+#: ../../msn/msn_r1_r.c:194
+msgid "Strmpfe"
+msgstr "Socks"
+
+#: ../../msn/msn_r1_r.c:197 ../../msn/msn_r1_r.c:268
+msgid "Buch"
+msgstr "Book"
+
+#: ../../msn/msn_r1_r.c:197
+msgid "Es ist|\"Per Anhalter durch die Galaxis\"|von Douglas Adams."
+msgstr "This is|\"The Hitchhiker's Guide to the Galaxy\"|by Douglas Adams."
+
+#: ../../msn/msn_r1_r.c:212
+msgid "Herb!"
+msgstr "Austere!"
+
+#: ../../msn/msn_r1_r.c:214
+msgid "Genial!"
+msgstr "Brilliant!"
+
+#: ../../msn/msn_r1_r.c:217
+msgid "Es scheint noch nicht fertig zu sein."
+msgstr "It looks like it is not yet finished."
+
+#: ../../msn/msn_r1_r.c:218
+msgid "Stift"
+msgstr "Pen"
+
+#: ../../msn/msn_r1_r.c:218
+msgid "Ein Kugelschreiber."
+msgstr "A ballpoint pen."
+
+#: ../../msn/msn_r1_r.c:230 ../../msn/msn_r1_r.c:231
+msgid "Poster"
+msgstr "Poster"
+
+#: ../../msn/msn_r1_r.c:230
+msgid "Ein Poster von \"Big Boss\"."
+msgstr "A poster of \"Big Boss\"."
+
+#: ../../msn/msn_r1_r.c:231
+msgid "Ein Poster von \"Rock Desaster\"."
+msgstr "A poster for \"Rock Disaster\"."
+
+#: ../../msn/msn_r1_r.c:232
+msgid "Box"
+msgstr "Speaker"
+
+#: ../../msn/msn_r1_r.c:235
+msgid "Schallplatte"
+msgstr "Record"
+
+#: ../../msn/msn_r1_r.c:235
+msgid "Die Platte ist von \"Big Boss\"."
+msgstr "A record from \"Big Boss\"."
+
+#: ../../msn/msn_r1_r.c:237
+msgid "Schallplattenst„nder"
+msgstr "Record stand"
+
+#: ../../msn/msn_r1_r.c:237
+msgid "Du hast jetzt keine Zeit, in|der Plattensammlung rumzust”bern."
+msgstr "You don't have time to rummage|around the record collection now."
+
+#: ../../msn/msn_r1_r.c:240
+msgid "Plattenspieler"
+msgstr "Record player"
+
+#: ../../msn/msn_r1_r.c:240
+msgid "Sieht aus, als k„me|er aus dem Museum."
+msgstr "Looks like something from a museum."
+
+#: ../../msn/msn_r1_r.c:244
+msgid "Stecker"
+msgstr "Male plug"
+
+#: ../../msn/msn_r1_r.c:261
+msgid "Pistole"
+msgstr "Gun"
+
+#: ../../msn/msn_r1_r.c:261
+msgid "Es ist keine Munition drin."
+msgstr "There is no ammunition in it."
+
+#: ../../msn/msn_r1_r.c:263
+msgid "Bcher"
+msgstr "Books"
+
+#: ../../msn/msn_r1_r.c:263
+msgid "Lauter wissenschaftliche Bcher."
+msgstr "All scientific books."
+
+#: ../../msn/msn_r1_r.c:265
+msgid "Kabelrolle"
+msgstr "Cable reel"
+
+#: ../../msn/msn_r1_r.c:265
+msgid "Da sind mindestens zwanzig Meter drauf."
+msgstr "There is at least 20 meters of cable on it."
+
+#: ../../msn/msn_r1_r.c:269 ../../msn/msn_r1_r.c:271
+msgid "Ich habe keine Lust, in|der Unterw„sche des|Commanders rumzuwhlen."
+msgstr "I don't feel like digging around|in the commander's underwear."
+
+#: ../../msn/msn_r1_r.c:284
+msgid "Ordner"
+msgstr "Folders"
+
+#: ../../msn/msn_r1_r.c:284
+msgid ""
+"Darauf steht \"Dienstanweisungen|zur Mission Supernova\".|Es steht nichts "
+"wichtiges drin."
+msgstr ""
+"It says,\"Instructions for the Mission Supernova.\"|There is nothing "
+"important in it."
+
+#: ../../msn/msn_r1_r.c:291
+msgid "Klo"
+msgstr "Loo"
+
+#: ../../msn/msn_r1_r.c:291
+msgid "Ein Klo mit Saugmechanismus."
+msgstr "A toilet with suction mechanism."
+
+#: ../../msn/msn_r1_r.c:292
+msgid "Dusche"
+msgstr "Shower"
+
+#: ../../msn/msn_r2.c:57
+msgid "Die Raumschiffe sind alle verschlossen."
+msgstr "The spaceships are all locked."
+
+#: ../../msn/msn_r2.c:64 ../../msn/msn_r2.c:1098
+msgid "Unsinn!"
+msgstr "Nonsense!"
+
+#: ../../msn/msn_r2.c:91
+msgid ""
+"Komisch! Auf einmal kannst du|das Schild lesen! Darauf steht:|\"Treffpunkt "
+"Galactica\"."
+msgstr "Funny! You can read the sign now!|It says \"Galactica meeting point\"."
+
+#: ../../msn/msn_r2.c:92
+msgid "Darauf steht:|\"Treffpunkt Galactica\"."
+msgstr "It says:|\"Galactica meeting point\"."
+
+#: ../../msn/msn_r2.c:144
+msgid "Wieso das denn nicht?"
+msgstr "Why the hell not?"
+
+#: ../../msn/msn_r2.c:145 ../../msn/msn_r2.c:154 ../../msn/msn_r2.c:1082
+msgid "Wo bin ich hier?"
+msgstr "Where am I here?"
+
+#: ../../msn/msn_r2.c:146 ../../msn/msn_r2.c:183
+msgid "Wo soll ich die Schuhe ablegen?"
+msgstr "Where should I put my shoes?"
+
+#: ../../msn/msn_r2.c:147
+msgid "Schwachsinn! Ich gehe jetzt nach oben!"
+msgstr "Bullshit! I'm going upstairs now!"
+
+#: ../../msn/msn_r2.c:155
+msgid "Sch”nes Wetter heute, nicht wahr?"
+msgstr "Nice weather today, isn't it?"
+
+#: ../../msn/msn_r2.c:156
+msgid "Wrden Sie mich bitte durchlassen."
+msgstr "Would you please let me through?"
+
+#: ../../msn/msn_r2.c:157
+msgid "Hey Alter, laá mich durch!"
+msgstr "Hey, dude, let me through!"
+
+#: ../../msn/msn_r2.c:164
+msgid "Was haben Sie gesagt?"
+msgstr "What did you say?"
+
+#: ../../msn/msn_r2.c:165
+msgid "Sprechen Sie bitte etwas deutlicher!"
+msgstr "Please speak more clearly!"
+
+#: ../../msn/msn_r2.c:174
+msgid "Durch deinen Helm kannst|du nicht sprechen."
+msgstr "You can't talk with your helmet on."
+
+#: ../../msn/msn_r2.c:189 ../../msn/msn_r2.c:251
+msgid "Was, das wissen Sie nicht?"
+msgstr "What, you don't know that?"
+
+#: ../../msn/msn_r2.c:190 ../../msn/msn_r2.c:252
+msgid "Sie befinden sich im Restaurant|\"Treffpunkt Galactica\"."
+msgstr "You are in the restaurant|\"Galactica meeting point\"."
+
+#: ../../msn/msn_r2.c:191 ../../msn/msn_r2.c:253
+msgid ""
+"Wir sind bei den interessantesten|Ereignissen in der Galaxis|immer zur "
+"Stelle."
+msgstr "We are always there when|interesting things happen|in the galaxy."
+
+#: ../../msn/msn_r2.c:194
+msgid "Wenn Sie meinen."
+msgstr "If you say so."
+
+#: ../../msn/msn_r2.c:199 ../../msn/msn_r2.c:256
+msgid "In der Toilette gibt es|Schlieáf„cher fr Schuhe."
+msgstr "There are lockers for shoes|in the restroom."
+
+#: ../../msn/msn_r2.c:204
+msgid ""
+"Wenn Sie das Lokal betreten|wollen, mssen Sie erst|ihre Schuhe ausziehen."
+msgstr ""
+"If you want to enter the restaurant,|you have to take off your shoes first."
+
+#: ../../msn/msn_r2.c:208
+msgid "Wollen Sie, daá ich Sie rauáschmeiáe?"
+msgstr "You want me to kick you out?"
+
+#: ../../msn/msn_r2.c:216 ../../msn/msn_r2.c:274
+msgid "Hhius otgfh Dgfdrkjlh Fokj gf."
+msgstr "Hhius otgfh Dgfdrkjlh Fokj gf."
+
+#: ../../msn/msn_r2.c:230 ../../msn/msn_s.c:289
+msgid "Halt!"
+msgstr "Halt!"
+
+#: ../../msn/msn_r2.c:232
+msgid "Uhwdejkt!"
+msgstr "Uhwdejkt!"
+
+#: ../../msn/msn_r2.c:241
+msgid "Sie mssen erst ihre Schuhe ausziehen, Sie Trottel!"
+msgstr "You have to take off your shoes first, idiot!"
+
+#: ../../msn/msn_r2.c:243
+msgid ""
+"Was f„llt ihnen ein!|Sie k”nnen doch ein Lokal|nicht mit Schuhen betreten!"
+msgstr ""
+"What are you thinking!|You cannot enter a restaurant|with your shoes on!"
+
+#: ../../msn/msn_r2.c:249
+msgid "Fragen Sie nicht so doof!"
+msgstr "Quit asking so stupidly!"
+
+#: ../../msn/msn_r2.c:262
+msgid "Das wrde ich an ihrer|Stelle nicht versuchen!"
+msgstr "I would not try that if I were you!"
+
+#: ../../msn/msn_r2.c:300
+msgid "Du ziehst deine Schuhe|aus und legst sie in|eins der Schlieáf„cher."
+msgstr "You remove your shoes|and put them in one|of the lockers."
+
+#: ../../msn/msn_r2.c:307
+msgid "Du ziehst deine Schuhe wieder an."
+msgstr "You put your shoes on again."
+
+#: ../../msn/msn_r2.c:311
+msgid ""
+"Du durchsuchst die Klos nach|anderen brauchbaren Sachen,|findest aber nichts."
+msgstr "You search the toilet|for other useful items,|but find nothing."
+
+#: ../../msn/msn_r2.c:316
+msgid "Bevor du aufs Klo gehst,|solltest du besser deinen|Raumanzug ausziehen."
+msgstr "Before you use the toilet,| you had better take off|your space suit."
+
+#: ../../msn/msn_r2.c:319
+msgid "Du gehst seit sieben Jahren das|erste Mal wieder aufs Klo!"
+msgstr "You're now back in a lavatory,|for the first time in seven years!"
+
+#: ../../msn/msn_r2.c:322
+msgid ""
+"In einem der Schlieáf„cher,|die sich auch im Raum befinden,|findest du "
+"einige Mnzen."
+msgstr "You find some coins in one of|the lockers in this room."
+
+#: ../../msn/msn_r2.c:332
+msgid "Mach doch zuerst das Fach leer!"
+msgstr "First, empty the drawer!"
+
+#: ../../msn/msn_r2.c:340
+msgid "Mnze"
+msgstr "Coin"
+
+#: ../../msn/msn_r2.c:353
+msgid ""
+"Komisch! Auf einmal kannst du|das Schild lesen! Darauf steht:|\"Zutritt nur "
+"fr Personal\"."
+msgstr ""
+"Strange! Suddenly you can |read the sign! It states:|\"Access Only for "
+"Personnel\"."
+
+#: ../../msn/msn_r2.c:361
+msgid ""
+"Komisch! Auf einmal kannst|du das Schild lesen!|Darauf steht:\"Toilette\"."
+msgstr "Strange! Suddenly you can read the sign!|It says:\"Toilet\"."
+
+#: ../../msn/msn_r2.c:362
+msgid "Darauf steht:|\"Toilette\"."
+msgstr "It says:|\"Toilet\"."
+
+#: ../../msn/msn_r2.c:372
+msgid "Du ziehst den Raumanzug wieder an."
+msgstr "You put the space suit back on."
+
+#: ../../msn/msn_r2.c:382 ../../msn/msn_r3.c:487 ../../msn/msn_r3.c:539
+msgid "Nicht so gewaltt„tig!"
+msgstr "Not so rough!"
+
+#: ../../msn/msn_r2.c:603
+msgid ""
+"Du hast das komische Gefhl,|daá drauáen etwas passiert,|und eilst zum "
+"Restaurant."
+msgstr ""
+"You get the funny feeling,|that something has happened outside,|and hurry to "
+"the restaurant."
+
+#: ../../msn/msn_r2.c:617
+msgid "Da! Die Supernova!"
+msgstr "There! The supernova!"
+
+#: ../../msn/msn_r2.c:630
+msgid "Zwei Minuten sp„ter ..."
+msgstr "Two minutes later ..."
+
+#: ../../msn/msn_r2.c:638
+msgid "Hey, was machen Sie in meinem Raumschiff?!"
+msgstr "Hey, what are you doing in my spaceship?!"
+
+#: ../../msn/msn_r2.c:641
+msgid "Geben Sie mir sofort meine Brieftasche wieder!"
+msgstr "Just give me my wallet back!"
+
+#: ../../msn/msn_r2.c:644
+msgid "Versuchen Sie das ja nicht nochmal!"
+msgstr "Do not try that again!"
+
+#: ../../msn/msn_r2.c:647
+msgid "Und jetzt raus mit Ihnen!"
+msgstr "And now, get out of here!"
+
+#: ../../msn/msn_r2.c:660
+msgid "Zehn Minuten sp„ter ..."
+msgstr "Ten Minutes later ..."
+
+#: ../../msn/msn_r2.c:690
+msgid "K”nnten Sie mir ein Gericht empfehlen?"
+msgstr "Could you recommend a dish for me?"
+
+#: ../../msn/msn_r2.c:691
+msgid "Wie lange dauert es denn noch bis zur Supernova?"
+msgstr "How long do we have before the supernova?"
+
+#: ../../msn/msn_r2.c:692
+msgid "Sie kommen mir irgendwie bekannt vor."
+msgstr "You look kind of familiar to me."
+
+#: ../../msn/msn_r2.c:704
+msgid "Hey, Witzkeks, laá die Brieftasche da liegen!"
+msgstr "Hey, Joker, leave the Wallet there!"
+
+#: ../../msn/msn_r2.c:708
+msgid "Das ist nicht deine."
+msgstr "This is not yours."
+
+#: ../../msn/msn_r2.c:713
+msgid "Roger ist im Moment nicht ansprechbar."
+msgstr "Roger is not available at the moment."
+
+#: ../../msn/msn_r2.c:718
+msgid "Bestellen Sie lieber nichts!"
+msgstr "Do Not order anything!"
+
+#: ../../msn/msn_r2.c:719
+msgid ""
+"Ich habe vor zwei Stunden mein Essen|bestellt und immer noch nichts bekommen."
+msgstr "I ordered my food two hours ago|and I still haven't received it."
+
+#: ../../msn/msn_r2.c:721
+msgid "Noch mindestens zwei Stunden."
+msgstr "At least two more hours."
+
+#: ../../msn/msn_r2.c:722
+msgid ""
+"Haben Sie keine Idee, womit wir uns|bis dahin die Zeit vertreiben k”nnen?"
+msgstr "Do you have an idea what we could|do to pass the time?"
+
+#: ../../msn/msn_r2.c:723
+msgid ""
+"Hmm ... im Moment f„llt mir nichts ein, aber vielleicht|hat der Spieler des "
+"Adventures ja eine Idee."
+msgstr ""
+"Hmm ... at the moment I'm not sure, but maybe|the Adventure Game Player has "
+"an idea."
+
+#: ../../msn/msn_r2.c:725
+msgid "Nein, Sie mssen sich irren.|Ich kenne Sie jedenfalls nicht."
+msgstr "No, you must be mistaken.|I don't know you."
+
+#: ../../msn/msn_r2.c:726
+msgid "Aber ihre Kleidung habe ich irgendwo schon mal gesehen."
+msgstr "However, I've seen your clothes somewhere before."
+
+#: ../../msn/msn_r2.c:727
+msgid "Ja? Komisch."
+msgstr "Yes? Strange."
+
+#: ../../msn/msn_r2.c:728
+msgid "Jetzt weiá ich's. Sie sind Roger W. !"
+msgstr "Now I know. You are Roger W.!"
+
+#: ../../msn/msn_r2.c:729
+msgid "Pssst, nicht so laut, sonst will|gleich jeder ein Autogramm von mir."
+msgstr "Pssst, not so loud, otherwise everyone|will want an autograph from me."
+
+#: ../../msn/msn_r2.c:730
+msgid ""
+"Ich habe extra eine Maske auf, damit|ich nicht von jedem angelabert werde."
+msgstr "I have an extra mask on so I don't|get yakked on by everyone."
+
+#: ../../msn/msn_r2.c:731
+msgid "Žh ... ach so."
+msgstr "Uh... I see."
+
+#: ../../msn/msn_r2.c:732
+msgid "Wann kommt denn das n„chste SQ-Abenteuer raus?"
+msgstr "When does the next SQ adventure come out?"
+
+#: ../../msn/msn_r2.c:733
+msgid "SQ 127 máte in einem Monat erscheinen."
+msgstr "SQ 127 should come out in a month."
+
+#: ../../msn/msn_r2.c:734
+msgid "Was, Teil 127 ??"
+msgstr "What, part 127 ??"
+
+#: ../../msn/msn_r2.c:735
+msgid "Bei uns ist gerade Teil 8 erschienen."
+msgstr "Part 8 has just been released."
+
+#: ../../msn/msn_r2.c:736
+msgid "Hmm ... von welchem Planeten sind Sie denn?"
+msgstr "Hmm ... what planet are you from?"
+
+#: ../../msn/msn_r2.c:737
+msgid "Von der Erde."
+msgstr "From the Earth."
+
+#: ../../msn/msn_r2.c:738
+msgid "Erde? Nie geh”rt."
+msgstr "Earth? Never heard of it."
+
+#: ../../msn/msn_r2.c:739
+msgid ""
+"Wahrscheinlich irgendein Kaff, wo Neuerungen|erst hundert Jahre sp„ter "
+"hingelangen."
+msgstr "Probably some dump, where innovations|happen only a century late."
+
+#: ../../msn/msn_r2.c:740
+msgid "Žh ... kann sein."
+msgstr "Uh ... maybe."
+
+#: ../../msn/msn_r2.c:741
+msgid "Aber eins mssen Sie mir erkl„ren!"
+msgstr "But you must tell me!"
+
+#: ../../msn/msn_r2.c:742
+msgid ""
+"Wieso sehen Sie mir so verdammt „hnlich, wenn|Sie nicht von Xenon stammen, "
+"wie ich?"
+msgstr ""
+"Why do you look so damn similar to me|if you are not from Xenon, like me?"
+
+#: ../../msn/msn_r2.c:743
+msgid ""
+"Keine Ahnung. Bis jetzt dachte ich immer, Sie w„ren ein|von Programmierern "
+"auf der Erde erfundenes Computersprite."
+msgstr ""
+"I have no idea. Until now, I've always thought you were|a computer sprite, "
+"invented by programmers on Earth."
+
+#: ../../msn/msn_r2.c:744
+msgid "Was? Lachhaft!"
+msgstr "What? Ridiculous!"
+
+#: ../../msn/msn_r2.c:745
+msgid "Wie erkl„ren Sie sich dann,|daá ich ihnen gegenbersitze?"
+msgstr "How do you explain then that|I am seated opposite you?"
+
+#: ../../msn/msn_r2.c:746
+msgid "Ja, das ist in der Tat seltsam."
+msgstr "Yes, this is definitely strange."
+
+#: ../../msn/msn_r2.c:747
+msgid ""
+"Halt, jetzt weiá ich es. Sie sind von der Konkurrenz,|von \"Georgefilm Games"
+"\" und wollen mich verunsichern."
+msgstr ""
+"Wait, now I understand! You are from the competition,|\"Georgefilm Games\", "
+"and want to unnerve me."
+
+#: ../../msn/msn_r2.c:748
+msgid "Nein, ich bin nur ein Ahnungsloser Koch von der Erde."
+msgstr "No, I'm just a clueless cook from the Earth."
+
+#: ../../msn/msn_r2.c:749
+msgid ""
+"Na gut, ich glaube Ihnen. Lassen wir jetzt|dieses Thema, langsam wird es mir "
+"zu bunt!"
+msgstr ""
+"OK. I believe you. Let's move away from|this topic before it goes too far!"
+
+#: ../../msn/msn_r2.c:761
+msgid "Eine Partie Schach! Das ist eine gute Idee."
+msgstr "A game of chess! That's a good idea."
+
+#: ../../msn/msn_r2.c:762
+msgid "Schach? Was ist das denn?"
+msgstr "Chess? What is that?"
+
+#: ../../msn/msn_r2.c:763
+msgid "Schach ist ein interessantes Spiel.|Ich werde es Ihnen erkl„ren."
+msgstr "Chess is an interesting game.|I will explain it to you."
+
+#: ../../msn/msn_r2.c:769
+msgid "Knapp zwei Stunden sp„ter ..."
+msgstr "Almost two hours later ..."
+
+#: ../../msn/msn_r2.c:787
+msgid "Roger W. steht kurz vor dem Schachmatt|und grbelt nach einem Ausweg."
+msgstr "Roger W. is on the brink of checkmate|and trying to find a way out."
+
+#: ../../msn/msn_r2.c:831
+msgid "Darf ich hier Platz nehmen?"
+msgstr "Can I sit here?"
+
+#: ../../msn/msn_r2.c:832
+msgid "Klar!"
+msgstr "Sure!"
+
+#: ../../msn/msn_r2.c:892
+msgid "Du tippst auf den Tasten herum,|aber es passiert nichts."
+msgstr "You tap the buttons,|but nothing happens."
+
+#: ../../msn/msn_r2.c:917
+msgid "Ach, Ihnen geh”rt die. Ich habe sie eben im Sand gefunden."
+msgstr "Oh, it is yours. I just found it in the sand."
+
+#: ../../msn/msn_r2.c:918
+msgid "Nein, tut mir leid."
+msgstr "No, I'm sorry."
+
+#: ../../msn/msn_r2.c:924
+msgid "Nein, danke. Ich bleibe lieber hier."
+msgstr "No thanks. I'd rather stay here."
+
+#: ../../msn/msn_r2.c:925
+msgid "Ja, das w„re gut."
+msgstr "Yes, that would be good."
+
+#: ../../msn/msn_r2.c:931
+msgid "Zur Erde."
+msgstr "To Earth."
+
+#: ../../msn/msn_r2.c:932
+msgid "Zum Pr„sident der Galaxis."
+msgstr "To the President of the Galaxy."
+
+#: ../../msn/msn_r2.c:933
+msgid "Nach Xenon."
+msgstr "To Xenon."
+
+#: ../../msn/msn_r2.c:934
+msgid "Mir egal, setzen Sie mich irgendwo ab!"
+msgstr "I don't care, drop me off somewhere!"
+
+#: ../../msn/msn_r2.c:940
+msgid "Ich habe gerade Ihre Brieftasche gefunden!"
+msgstr "I just found your wallet!"
+
+#: ../../msn/msn_r2.c:941
+msgid "Sie lag da drben hinter einem Felsen."
+msgstr "It was over there behind a rock."
+
+#: ../../msn/msn_r2.c:942
+msgid "Ich wollte nur wissen, ob Sie die Brieftasche wiederhaben."
+msgstr "I just wanted to know if you got the wallet back."
+
+#: ../../msn/msn_r2.c:959
+msgid "Was wollen Sie denn schon wieder?"
+msgstr "What do you want again?"
+
+#: ../../msn/msn_r2.c:965
+msgid ""
+"Haben Sie zuf„llig meine Brieftasche gesehen?|Ich muá Sie irgendwo verloren "
+"haben."
+msgstr "Have you seen my wallet, by chance?|I must have lost it somewhere."
+
+#: ../../msn/msn_r2.c:966
+msgid ""
+"Ohne die Brieftasche kann ich nicht|starten, weil meine Keycard darin ist."
+msgstr "Without my wallet I can not take off|because my keycard is in it."
+
+#: ../../msn/msn_r2.c:975
+msgid "Oh! Vielen Dank."
+msgstr "Oh! Many thanks."
+
+#: ../../msn/msn_r2.c:976
+msgid "Wo ist denn Ihr Raumschiff?|Soll ich Sie ein Stck mitnehmen?"
+msgstr "Where is your spaceship?|Shall I give you a lift?"
+
+#: ../../msn/msn_r2.c:979
+msgid "Wo wollen Sie denn hin?"
+msgstr "Where do you want to go?"
+
+#: ../../msn/msn_r2.c:981
+msgid "Ok, steigen Sie ein!"
+msgstr "Ok, get in!"
+
+#: ../../msn/msn_r2.c:983
+msgid "Wie Sie wollen."
+msgstr "As you wish."
+
+#: ../../msn/msn_r2.c:1030
+msgid "Huch, du lebst ja noch!"
+msgstr "Huh, you're still alive!"
+
+#: ../../msn/msn_r2.c:1057
+msgid ""
+"Das wrde ich jetzt nicht tun, schlieálich|steht Roger W. neben seinem "
+"Schiff."
+msgstr "I wouldn't do that now, because|Roger W. is standing beside his ship."
+
+#: ../../msn/msn_r2.c:1069
+msgid "Alle Raumschiffe haben|den Planeten verlassen."
+msgstr "All spaceships|have left the planet."
+
+#: ../../msn/msn_r2.c:1071
+msgid "Alle Raumschiffe haben den Planeten|verlassen, bis auf eins ..."
+msgstr "All spaceships have left the planet,|except for one ..."
+
+#: ../../msn/msn_r2.c:1083
+msgid "Was wollen Sie von mir?"
+msgstr "What do you want from me?"
+
+#: ../../msn/msn_r2.c:1084
+msgid "Hilfe!!"
+msgstr "Help!!"
+
+#: ../../msn/msn_r2.c:1085
+msgid "Warum sprechen Sie meine Sprache?"
+msgstr "Why do you speak my language?"
+
+#: ../../msn/msn_r2.c:1091
+msgid "Ja, ich bin einverstanden."
+msgstr "Yes, I agree."
+
+#: ../../msn/msn_r2.c:1092
+msgid "Nein, lieber bleibe ich hier, als mit Ihnen zu fliegen."
+msgstr "No, I'd rather stay here than fly with you."
+
+#: ../../msn/msn_r2.c:1141
+msgid "Ich glaube, er wacht auf."
+msgstr "I think he's waking up."
+
+#: ../../msn/msn_r2.c:1143
+msgid "Ja, sieht so aus."
+msgstr "Yes, it looks like it."
+
+#: ../../msn/msn_r2.c:1148
+msgid "Sie befinden sich im Raumschiff \"Dexxa\"."
+msgstr "You are in the spaceship \"Dexxa\"."
+
+#: ../../msn/msn_r2.c:1149
+msgid ""
+"Wir kommen vom Planeten Axacuss und|sind aus dem gleichen Grund hier wie "
+"Sie,|n„mlich zur Erforschung der Supernova."
+msgstr ""
+"We come from the planet Axacuss|and are here for the same reason as you,|"
+"namely, to observe the supernova."
+
+#: ../../msn/msn_r2.c:1151
+msgid "Sie k”nnen beruhigt sein, wir wollen Ihnen nur helfen."
+msgstr "Don't worry, we just want to help you."
+
+#: ../../msn/msn_r2.c:1152
+msgid "Und wieso hat der Typ im Raumanzug|eben auf mich geschossen?"
+msgstr "And why did the guy in the space suit|shoot at me?"
+
+#: ../../msn/msn_r2.c:1153
+msgid "Das war eine Schreckreaktion."
+msgstr "It was a reflex."
+
+#: ../../msn/msn_r2.c:1154
+msgid ""
+"Schlieálich ist es fr uns das erste Mal,|daá wir auf eine fremde "
+"Intelligenz treffen."
+msgstr ""
+"After all, this is the first time we have|come across an alien intelligence."
+
+#: ../../msn/msn_r2.c:1155
+msgid "Wie wir festgestellt haben, ist|Ihr Raumschiff v”llig zerst”rt."
+msgstr "As we've established, your spaceship|is completely destroyed."
+
+#: ../../msn/msn_r2.c:1156
+msgid "Wahrscheinlich k”nnen Sie nicht|mehr auf ihren Heimatplaneten zurck."
+msgstr "You may not be able to return to your home planet."
+
+#: ../../msn/msn_r2.c:1157
+msgid "Wir bieten Ihnen an, Sie|mit nach Axacuss zu nehmen."
+msgstr "We offer to take you|with us to Axacuss."
+
+#: ../../msn/msn_r2.c:1160 ../../msn/msn_r2.c:1169
+msgid "Sind Sie sich da wirklich sicher?"
+msgstr "Are you really sure about that?"
+
+#: ../../msn/msn_r2.c:1161 ../../msn/msn_r2.c:1170
+msgid "Wenn ich es mir genau berlege,|fliege ich doch lieber mit."
+msgstr "If I think about it,|I'd rather fly with you."
+
+#: ../../msn/msn_r2.c:1163
+msgid ""
+"Gut, wir nehmen Sie unter der|Bedingung mit, daá wir Sie jetzt|sofort in "
+"Tiefschlaf versetzen drfen."
+msgstr ""
+"All right, we'll take you with us|on condition that we can put you|into a "
+"deep sleep right now."
+
+#: ../../msn/msn_r2.c:1164
+msgid "Diese Art des Reisens ist Ihnen|ja scheinbar nicht unbekannt."
+msgstr "You seem to be familiar with|this kind of traveling."
+
+#: ../../msn/msn_r2.c:1165
+msgid ""
+"Sie werden in vier Jahren nach der|Landung der \"Dexxa\" wieder aufgeweckt."
+msgstr ""
+"You will be woken up again in four years|after the \"Dexxa\" has landed."
+
+#: ../../msn/msn_r2.c:1166
+msgid "Sind Sie damit einverstanden?"
+msgstr "Are you okay with this?"
+
+#: ../../msn/msn_r2.c:1172
+msgid "Gut, haben Sie noch irgendwelche Fragen?"
+msgstr "Good, do you have any questions?"
+
+#: ../../msn/msn_r2.c:1174
+msgid "Keine Panik!"
+msgstr "Don't panic!"
+
+#: ../../msn/msn_r2.c:1175
+msgid "Wir tun Ihnen nichts."
+msgstr "We are not going to hurt you."
+
+#: ../../msn/msn_r2.c:1177
+msgid "Wir sprechen nicht ihre Sprache,|sondern Sie sprechen unsere."
+msgstr "We don't speak your language,|you speak ours."
+
+#: ../../msn/msn_r2.c:1178
+msgid ""
+"Nach einer Gehirnanalyse konnten|wir Ihr Gehirn an unsere Sprache anpassen."
+msgstr ""
+"After a brain analysis, we were able|to adapt your brain to our speech."
+
+#: ../../msn/msn_r2.c:1179
+msgid "Was? Sie haben in mein Gehirn eingegriffen?"
+msgstr "What? You've interfered with my brain?"
+
+#: ../../msn/msn_r2.c:1180
+msgid "Keine Angst, wir haben sonst nichts ver„ndert."
+msgstr "Don't worry, we haven't changed anything else."
+
+#: ../../msn/msn_r2.c:1181
+msgid "Ohne diesen Eingriff w„ren|Sie verloren gewesen."
+msgstr "Without this intervention,|you would have been lost."
+
+#: ../../msn/msn_r2.c:1186
+msgid "Ich habe keine weiteren Fragen mehr."
+msgstr "I have no more questions."
+
+#: ../../msn/msn_r2.c:1187
+msgid "Gut, dann versetzen wir Sie jetzt in Tiefschlaf."
+msgstr "Good, let's put you in a deep sleep now."
+
+#: ../../msn/msn_r2.c:1188
+msgid "Gute Nacht!"
+msgstr "Good night!"
+
+#: ../../msn/msn_r2.c:1213 ../../msn/msn_r2.c:1214
+msgid "Stein"
+msgstr "Stone"
+
+#: ../../msn/msn_r2.c:1215
+msgid "Loch"
+msgstr "Opening"
+
+#: ../../msn/msn_r2.c:1215
+msgid "Es scheint eine H”hle zu sein."
+msgstr "It seems to be a cave."
+
+#: ../../msn/msn_r2.c:1221
+msgid "Hier bist du gerade hergekommen."
+msgstr "You just came from there."
+
+#: ../../msn/msn_r2.c:1229 ../../msn/msn_r2.c:1310 ../../msn/msn_r2.c:1319
+msgid "H”hle"
+msgstr "Cave"
+
+#: ../../msn/msn_r2.c:1230 ../../msn/msn_r2.c:1243 ../../msn/msn_r2.c:1257
+#: ../../msn/msn_r3.c:1687
+msgid "Schild"
+msgstr "Sign"
+
+#: ../../msn/msn_r2.c:1230 ../../msn/msn_r2.c:1243 ../../msn/msn_r2.c:1257
+msgid "Diese Schrift kannst du nicht lesen."
+msgstr "You cannot read these inscriptions."
+
+#: ../../msn/msn_r2.c:1231
+msgid "Eingang"
+msgstr "Entrance"
+
+#: ../../msn/msn_r2.c:1232 ../../msn/msn_r2.c:1318
+msgid "Stern"
+msgstr "Star"
+
+#: ../../msn/msn_r2.c:1233 ../../msn/msn_r2.c:1234 ../../msn/msn_r2.c:1309
+msgid "Raumschiff"
+msgstr "Spaceship"
+
+#: ../../msn/msn_r2.c:1240
+msgid "Portier"
+msgstr "Doorman"
+
+#: ../../msn/msn_r2.c:1240
+msgid "Du siehst doch selbst, wie er aussieht."
+msgstr "You can see for yourself what he looks like."
+
+#: ../../msn/msn_r2.c:1242 ../../msn/msn_r3.c:1480 ../../msn/msn_r3.c:1545
+#: ../../msn/msn_r3.c:1560 ../../msn/msn_r3.c:1569 ../../msn/msn_r3.c:1580
+#: ../../msn/msn_r3.c:1582 ../../msn/msn_r3.c:1584 ../../msn/msn_r3.c:1586
+#: ../../msn/msn_r3.c:1596 ../../msn/msn_r3.c:1609 ../../msn/msn_r3.c:1610
+#: ../../msn/msn_r3.c:1611 ../../msn/msn_r3.c:1621 ../../msn/msn_r3.c:1633
+#: ../../msn/msn_r3.c:1644 ../../msn/msn_r3.c:1656 ../../msn/msn_r3.c:1667
+#: ../../msn/msn_r3.c:1688
+msgid "Tr"
+msgstr "Door"
+
+#: ../../msn/msn_r2.c:1245
+msgid "Kaugummi"
+msgstr "Chewing gum"
+
+#: ../../msn/msn_r2.c:1246
+msgid "Gummib„rchen"
+msgstr "Gummy bear"
+
+#: ../../msn/msn_r2.c:1247
+msgid "Schokokugel"
+msgstr "Chocolate ball"
+
+#: ../../msn/msn_r2.c:1248
+msgid "šberraschungsei"
+msgstr "Surprise egg"
+
+#: ../../msn/msn_r2.c:1249
+msgid "Lakritz"
+msgstr "Liquorice"
+
+#: ../../msn/msn_r2.c:1250
+msgid "Tablette"
+msgstr "Pill"
+
+#: ../../msn/msn_r2.c:1250
+msgid ""
+"Die Plastikhlle zeigt einen|Mund mit einer Sprechblase. Was|darin steht, "
+"kannst du nicht lesen."
+msgstr ""
+"The plastic envelope shows|a mouth with a speech bubble.|You can't read what "
+"it says."
+
+#: ../../msn/msn_r2.c:1253
+msgid "Automat"
+msgstr "Vending machine"
+
+#: ../../msn/msn_r2.c:1253
+msgid "Sieht aus wie ein Kaugummiautomat."
+msgstr "Looks like a gum dispenser."
+
+#: ../../msn/msn_r2.c:1254
+msgid "Die Toiletten sind denen|auf der Erde sehr „hnlich."
+msgstr "The toilets are very similar|to those on Earth."
+
+#: ../../msn/msn_r2.c:1258 ../../msn/msn_r2.c:1269
+msgid "Treppe"
+msgstr "Staircase"
+
+#: ../../msn/msn_r2.c:1260
+msgid "Mnzen"
+msgstr "Coins"
+
+#: ../../msn/msn_r2.c:1260
+msgid "Es sind seltsame|K”pfe darauf abgebildet."
+msgstr "They have strange|heads on them."
+
+#: ../../msn/msn_r2.c:1262
+msgid "Tablettenhlle"
+msgstr "Pill envelope"
+
+#: ../../msn/msn_r2.c:1262
+msgid ""
+"Darauf steht:\"Wenn Sie diese|Schrift jetzt lesen k”nnen,|hat die Tablette "
+"gewirkt.\""
+msgstr "It says,\"If you can read|this writing now,|the pill worked.\""
+
+#: ../../msn/msn_r2.c:1270
+msgid "Stuhl"
+msgstr "Chair"
+
+#: ../../msn/msn_r2.c:1271
+msgid "Schuhe"
+msgstr "Shoes"
+
+#: ../../msn/msn_r2.c:1271
+msgid "Wie ist der denn mit|Schuhen hier reingekommen?"
+msgstr "How did he get in here|with his shoes on?"
+
+#: ../../msn/msn_r2.c:1278
+msgid "Froschgesicht"
+msgstr "Frog face"
+
+#: ../../msn/msn_r2.c:1279
+msgid "Gekritzel"
+msgstr "Scribble"
+
+#: ../../msn/msn_r2.c:1279
+msgid "\"Mr Spock was here\""
+msgstr "\"Mr Spock was here\""
+
+#: ../../msn/msn_r2.c:1280
+msgid "Brieftasche"
+msgstr "Wallet"
+
+#: ../../msn/msn_r2.c:1281
+msgid "Speisekarte"
+msgstr "Menu"
+
+#: ../../msn/msn_r2.c:1281
+msgid "\"Heute empfehlen wir:|Fonua Opra mit Ulk.\""
+msgstr "\"Today we recommend: Fonua Opra with a joke.\""
+
+#: ../../msn/msn_r2.c:1282
+msgid "Tasse"
+msgstr "Cup"
+
+#: ../../msn/msn_r2.c:1282
+msgid "Sie enth„lt eine grnliche Flssigkeit."
+msgstr "It contains a greenish liquid."
+
+#: ../../msn/msn_r2.c:1284
+msgid "10-Buckazoid-Schein"
+msgstr "A 10 buckazoid bill"
+
+#: ../../msn/msn_r2.c:1284
+msgid "Nicht gerade sehr viel Geld."
+msgstr "Not a lot of money."
+
+#: ../../msn/msn_r2.c:1286 ../../msn/msn_r2.c:1297
+msgid "Keycard von Roger"
+msgstr "Roger's keycard"
+
+#: ../../msn/msn_r2.c:1301
+msgid "Anzeige"
+msgstr "Display"
+
+#: ../../msn/msn_r2.c:1301 ../../msn/msn_r2.c:1302
+msgid "Hmm, seltsame Anzeigen."
+msgstr "Hmm, weird instruments."
+
+#: ../../msn/msn_r2.c:1308
+msgid "Roger W."
+msgstr "Roger W."
+
+#: ../../msn/msn_r2.c:1317
+msgid "Ufo"
+msgstr "UFO"
+
+#: ../../msn/msn_r2.c:1317
+msgid "Der Eingang scheint offen zu sein."
+msgstr "The entrance appears to be open."
+
+#: ../../msn/msn_r3.c:27
+msgid "Du drckst den Knopf,|aber nichts passiert."
+msgstr "You push the button,|but nothing happens."
+
+#: ../../msn/msn_r3.c:88
+msgid "Bei deinem Fluchtversuch hat|dich der Roboter erschossen."
+msgstr "When you tried to escape,|the robot shot you."
+
+#: ../../msn/msn_r3.c:91
+msgid "Du iát etwas, aber|es schmeckt scheuálich."
+msgstr "You're eating something,|but it tastes horrible."
+
+#: ../../msn/msn_r3.c:171
+msgid "Du wachst auf und findest dich in|einem geschlossenen Raum wieder."
+msgstr "You wake up and find yourself|in a closed room."
+
+#: ../../msn/msn_r3.c:230
+msgid "Žh ... nein, mein Name ist Mller."
+msgstr "Uh... no, my name is Mller."
+
+#: ../../msn/msn_r3.c:231
+msgid "Oh, ich habe mich im Gang vertan."
+msgstr "Oh, I got lost."
+
+#: ../../msn/msn_r3.c:237
+msgid "Wrden Sie mich bitte zum Fahrstuhl lassen?"
+msgstr "Will you please let me go to the elevator?"
+
+#: ../../msn/msn_r3.c:238
+msgid "Ich gehe wieder."
+msgstr "I'm leaving."
+
+#: ../../msn/msn_r3.c:243
+msgid "Dann gehe ich eben wieder."
+msgstr "Then I will be going."
+
+#: ../../msn/msn_r3.c:244
+msgid "Ach, halten Sie's Maul, ich gehe trotzdem!"
+msgstr "Oh, shut up, I'm leaving anyway!"
+
+#: ../../msn/msn_r3.c:245 ../../msn/msn_r3.c:246
+msgid "Wenn Sie mich durchlassen gebe ich Ihnen %d Xa."
+msgstr "I will give you %d Xa if you let me through."
+
+#: ../../msn/msn_r3.c:258
+msgid "Sie schon wieder?"
+msgstr "You again?"
+
+#: ../../msn/msn_r3.c:264
+msgid "Halt! Sie sind doch dieser Hummel.|Bleiben Sie sofort stehen!"
+msgstr "Stop! You're this Hummel.|Stop right there!"
+
+#: ../../msn/msn_r3.c:266
+msgid "Sehr witzig!"
+msgstr "Very funny!"
+
+#: ../../msn/msn_r3.c:269
+msgid "Kann auch sein, auf jeden Fall|sind Sie der Nicht-Axacussaner."
+msgstr "Well, you're the non-Axacussan,|you know."
+
+#: ../../msn/msn_r3.c:273
+msgid "Nein!"
+msgstr "No!"
+
+#: ../../msn/msn_r3.c:310
+msgid "Das máte schon ein biáchen mehr sein."
+msgstr "It should be a little more than that."
+
+#: ../../msn/msn_r3.c:324
+msgid "Ok, dann machen Sie daá Sie wegkommen!"
+msgstr "Okay, then get out of here!"
+
+#: ../../msn/msn_r3.c:430
+msgid "Der Axacussaner hat dich erwischt."
+msgstr "The Axacussan caught you."
+
+#: ../../msn/msn_r3.c:547
+msgid ""
+"Diese Tr wrde ich lieber|nicht ”ffnen. Nach dem Schild zu|urteilen, ist "
+"jemand in dem Raum."
+msgstr ""
+"I'd rather not open that door.|Judging by the sign, there's|someone in that "
+"room."
+
+#: ../../msn/msn_r3.c:642
+msgid "Du stellst dich hinter die S„ule."
+msgstr "You stand behind the column."
+
+#: ../../msn/msn_r3.c:656
+msgid "Hmm, er scheint kaputt zu sein."
+msgstr "Hmm, it seems to be broken."
+
+#: ../../msn/msn_r3.c:696
+msgid "Welche Zahlenkombination willst|du eingeben?"
+msgstr "Which combination do you want|to enter?"
+
+#: ../../msn/msn_r3.c:708
+msgid ""
+"Hmm, das haut nicht ganz hin,|aber irgendwie muá die Zahl|mit dem Code "
+"zusammenh„ngen."
+msgstr ""
+"Hmm, that doesn't really work,|but somehow the number|must be related to the "
+"code."
+
+#: ../../msn/msn_r3.c:710
+msgid "Das war die falsche Kombination."
+msgstr "That combination is incorrect."
+
+#: ../../msn/msn_r3.c:748
+msgid "Streng geheim"
+msgstr "Strictly secret"
+
+#: ../../msn/msn_r3.c:749
+msgid "418-98"
+msgstr "418-98"
+
+#: ../../msn/msn_r3.c:750
+msgid "Sehr geehrter Dr. Hansi,"
+msgstr "Dear Dr. Hansi,"
+
+#: ../../msn/msn_r3.c:751
+msgid "Ich muá Ihren Roboterexperten ein Lob aussprechen. Die"
+msgstr "I must commend your robot expert. The imitation"
+
+#: ../../msn/msn_r3.c:752
+msgid "Imitation von Horst Hummel ist perfekt gelungen, wie ich"
+msgstr "of Horst Hummel was a perfect success, as I found"
+
+#: ../../msn/msn_r3.c:753
+msgid "heute bei der šbertragung des Interviews feststellen"
+msgstr "out today during the broadcast of the interview."
+
+#: ../../msn/msn_r3.c:754
+msgid "konnte. Dem Aufschwung Ihrer Firma durch die Werbe-"
+msgstr "Nothing should stand in the way of your company's"
+
+#: ../../msn/msn_r3.c:755
+msgid "kampagne mit dem falschen Horst Hummel drfte ja jetzt"
+msgstr "recovery through the advertising campaign with"
+
+#: ../../msn/msn_r3.c:756
+msgid "nichts mehr im Wege stehen."
+msgstr "the false Horst Hummel now."
+
+#: ../../msn/msn_r3.c:757
+msgid "PS: Herzlichen zum Geburtstag!"
+msgstr "PS: Happy Birthday!"
+
+#: ../../msn/msn_r3.c:758
+msgid "Hochachtungsvoll"
+msgstr "Yours sincerely"
+
+#: ../../msn/msn_r3.c:759
+msgid "Commander Sumoti"
+msgstr "Commander Sumoti"
+
+#: ../../msn/msn_r3.c:766
+msgid "Nicht zu fassen!"
+msgstr "I can't believe it!"
+
+#: ../../msn/msn_r3.c:838
+msgid "Hey, hinter dem Bild ist Geld|versteckt. Ich nehme es mit."
+msgstr "Hey, there's money hidden behind that|picture. I'll take it with me."
+
+#: ../../msn/msn_r3.c:1047
+msgid "DR. ALAB HANSI"
+msgstr "DR. ALAB HANSI"
+
+#: ../../msn/msn_r3.c:1047
+msgid "ALAB HANSI"
+msgstr "ALAB HANSI"
+
+#: ../../msn/msn_r3.c:1048
+msgid "SAVAL LUN"
+msgstr "SAVAL LUN"
+
+#: ../../msn/msn_r3.c:1048 ../../msn/msn_r3.c:1050
+msgid "x"
+msgstr "x"
+
+#: ../../msn/msn_r3.c:1049
+msgid "PROF. DR. UGNUL TSCHABB"
+msgstr "PROF. DR. UGNUL TSCHABB"
+
+#: ../../msn/msn_r3.c:1049
+msgid "UGNUL TSCHABB"
+msgstr "UGNUL TSCHABB"
+
+#: ../../msn/msn_r3.c:1050
+msgid "ALGA HURZ LI"
+msgstr "ALGA HURZ LI"
+
+#: ../../msn/msn_r3.c:1054
+msgid "Alab Hansi"
+msgstr "Alab Hansi"
+
+#: ../../msn/msn_r3.c:1054
+msgid "Saval Lun"
+msgstr "Saval Lun"
+
+#: ../../msn/msn_r3.c:1054
+msgid "Ugnul Tschabb"
+msgstr "Ugnul Tschabb"
+
+#: ../../msn/msn_r3.c:1054
+msgid "Alga Hurz Li"
+msgstr "Alga Hurz Li"
+
+#: ../../msn/msn_r3.c:1060
+msgid "Guten Tag, hier ist Horst Hummel."
+msgstr "Hello, I am Horst Hummel."
+
+#: ../../msn/msn_r3.c:1062
+msgid "Es ist sehr wichtig."
+msgstr "It's very important."
+
+#: ../../msn/msn_r3.c:1068
+msgid "Vom Mars."
+msgstr "From Mars."
+
+#: ../../msn/msn_r3.c:1069
+msgid "Vom Klo."
+msgstr "The toilet."
+
+#: ../../msn/msn_r3.c:1070
+msgid "Das werde ich kaum erz„hlen."
+msgstr "I won't tell you that."
+
+#: ../../msn/msn_r3.c:1079
+msgid "1 Bromanager"
+msgstr "1 Office manager"
+
+#: ../../msn/msn_r3.c:1080
+msgid "2 Telomat"
+msgstr "2 Phone"
+
+#: ../../msn/msn_r3.c:1081
+msgid "3 ProText"
+msgstr "3 ProText"
+
+#: ../../msn/msn_r3.c:1082
+msgid "4 Calculata"
+msgstr "4 Calculata"
+
+#: ../../msn/msn_r3.c:1083
+msgid "Bitte w„hlen"
+msgstr "Please select an option"
+
+#: ../../msn/msn_r3.c:1091
+msgid "Geben Sie den gewnschten Namen ein:"
+msgstr "Enter the desired name:"
+
+#: ../../msn/msn_r3.c:1092
+msgid "(Vor- und Nachname)"
+msgstr "(first and last name)"
+
+#: ../../msn/msn_r3.c:1106
+msgid "Name unbekannt"
+msgstr "Name unknown"
+
+#: ../../msn/msn_r3.c:1112
+msgid "Verbindung unm”glich"
+msgstr "Connection not possible"
+
+#: ../../msn/msn_r3.c:1116
+msgid "Verbindung wird hergestellt"
+msgstr "Connection is established"
+
+#. I18N: Here the %s is a name
+#: ../../msn/msn_r3.c:1121
+#, c-format
+msgid "%s am Apparat."
+msgstr "%s speaking."
+
+#: ../../msn/msn_r3.c:1127
+#, c-format
+msgid "Hier ist %s. K”nnen Sie mal gerade kommen?"
+msgstr "This is %s. Can you come over now?"
+
+#: ../../msn/msn_r3.c:1134
+msgid "Huch, Sie h”ren sich aber|nicht gut an. Ich komme sofort."
+msgstr "You don't sound good.|I'll be right there."
+
+#: ../../msn/msn_r3.c:1145
+msgid "Horst Hummel! Von wo rufen Sie an?"
+msgstr "Horst Hummel! Where are you calling from?"
+
+#: ../../msn/msn_r3.c:1151
+msgid "Hmm, keine Antwort."
+msgstr "Hmm, no answer."
+
+#: ../../msn/msn_r3.c:1164
+msgid "Passwort:"
+msgstr "Password:"
+
+#: ../../msn/msn_r3.c:1215
+msgid "Was war das fr ein Ger„usch?"
+msgstr "What was that noise?"
+
+#: ../../msn/msn_r3.c:1217 ../../msn/msn_s.c:312
+msgid "Ich werde mal nachsehen."
+msgstr "Let's find out..."
+
+#: ../../msn/msn_r3.c:1305
+msgid "Jetzt verschwinden Sie endlich!"
+msgstr "Get the hell out of here!"
+
+#: ../../msn/msn_r3.c:1306
+msgid "Huch, ich habe mich vertan."
+msgstr "Oops, I made a mistake."
+
+#: ../../msn/msn_r3.c:1368
+msgid ""
+"Nachdem du zwei Stunden im|Dschungel herumgeirrt bist,|findest du ein "
+"Geb„ude."
+msgstr ""
+"After you've been wandering around|the jungle for two hours,|you find a "
+"building."
+
+#: ../../msn/msn_r3.c:1481
+msgid "Tablett"
+msgstr "Tray"
+
+#: ../../msn/msn_r3.c:1481
+msgid "Es ist irgendein Fraá und|etwas zu Trinken darauf."
+msgstr "There is some kind of food|and a drink on it."
+
+#: ../../msn/msn_r3.c:1483
+msgid "Stange"
+msgstr "Rod"
+
+#: ../../msn/msn_r3.c:1483
+msgid "Es scheint eine Lampe zu sein."
+msgstr "It seems to be a lamp."
+
+#: ../../msn/msn_r3.c:1484
+msgid "Augen"
+msgstr "Eyes"
+
+#: ../../msn/msn_r3.c:1484
+msgid "Es ist nur ein Bild."
+msgstr "It's just a picture."
+
+#: ../../msn/msn_r3.c:1486
+msgid "Sieht etwas anders aus als auf der Erde."
+msgstr "Looks a little different than on Earth."
+
+#: ../../msn/msn_r3.c:1488
+msgid "Metallblock"
+msgstr "Metal block"
+
+#: ../../msn/msn_r3.c:1488
+msgid "Er ist ziemlich schwer."
+msgstr "It's pretty heavy."
+
+#: ../../msn/msn_r3.c:1490
+msgid "Roboter"
+msgstr "Robot"
+
+#: ../../msn/msn_r3.c:1490
+msgid "Den hast du erledigt."
+msgstr "You took care of it."
+
+#: ../../msn/msn_r3.c:1491 ../../msn/msn_r3.c:1528
+msgid "Tisch"
+msgstr "Table"
+
+#: ../../msn/msn_r3.c:1491
+msgid "Ein kleiner Metalltisch."
+msgstr "A small metal table."
+
+#: ../../msn/msn_r3.c:1524
+msgid "Zellentr"
+msgstr "Cell door"
+
+#: ../../msn/msn_r3.c:1524
+msgid "Hier warst du eingesperrt."
+msgstr "You were locked up here."
+
+#: ../../msn/msn_r3.c:1526
+msgid "Laptop"
+msgstr "Laptop"
+
+#: ../../msn/msn_r3.c:1576 ../../msn/msn_r3.c:1577
+msgid "S„ule"
+msgstr "Pillar"
+
+#: ../../msn/msn_r3.c:1580
+msgid "Auf einem Schild an der Tr steht \"Dr. Alab Hansi\"."
+msgstr "A sign on the door says \"Dr. Alab Hansi\"."
+
+#: ../../msn/msn_r3.c:1582
+msgid "Auf einem Schild an der Tr steht \"Saval Lun\"."
+msgstr "A sign on the door says \"Saval Lun\"."
+
+#: ../../msn/msn_r3.c:1584
+msgid "Auf einem Schild an der Tr steht \"Prof. Dr. Ugnul Tschabb\"."
+msgstr "A sign on the door says \"Prof. Dr. Ugnul Tschabb\"."
+
+#: ../../msn/msn_r3.c:1586
+msgid "Auf einem Schild an der Tr steht \"Alga Hurz Li\"."
+msgstr "A sign on the door says \"Alga Hurz Li\"."
+
+#: ../../msn/msn_r3.c:1597 ../../msn/msn_r3.c:1613
+msgid "Axacussaner"
+msgstr "Axacussan"
+
+#: ../../msn/msn_r3.c:1597
+msgid "Du mátest ihn irgendwie ablenken."
+msgstr "You have to distract him somehow."
+
+#: ../../msn/msn_r3.c:1599
+msgid "Komisches Bild."
+msgstr "Funny picture."
+
+#: ../../msn/msn_r3.c:1600
+msgid "Karte"
+msgstr "Keycard"
+
+#: ../../msn/msn_r3.c:1600
+msgid "Darauf steht: \"Generalkarte\"."
+msgstr "It says: \"Master keycard\"."
+
+#: ../../msn/msn_r3.c:1612
+msgid "Lampe"
+msgstr "Lamp"
+
+#: ../../msn/msn_r3.c:1614
+msgid "Seltsam!"
+msgstr "Strange!"
+
+#: ../../msn/msn_r3.c:1623 ../../msn/msn_r3.c:1670
+msgid "Geld"
+msgstr "Cash"
+
+#: ../../msn/msn_r3.c:1623
+msgid "Es sind 500 Xa."
+msgstr "It's 500 Xa."
+
+#: ../../msn/msn_r3.c:1624
+msgid "Schlieáfach"
+msgstr "Locker"
+
+#: ../../msn/msn_r3.c:1624
+msgid "Es hat ein elektronisches Zahlenschloá."
+msgstr "It has an electronic combination lock."
+
+#: ../../msn/msn_r3.c:1626
+msgid "Brief"
+msgstr "Note"
+
+#: ../../msn/msn_r3.c:1635
+msgid "Wrfel"
+msgstr "Cubes"
+
+#: ../../msn/msn_r3.c:1635
+msgid "Sonderbar!"
+msgstr "Quirky!"
+
+#: ../../msn/msn_r3.c:1636
+msgid "Affenstark!"
+msgstr "Awesome!"
+
+#: ../../msn/msn_r3.c:1637
+msgid "Komisches Ding"
+msgstr "Strange thing"
+
+#: ../../msn/msn_r3.c:1637
+msgid "Wundersam!"
+msgstr "Amazing!"
+
+#: ../../msn/msn_r3.c:1646 ../../msn/msn_r3.c:1647
+msgid "Es ist ein Axacussanerkopf auf dem Bild."
+msgstr "There is an Axacussan head in the picture."
+
+#: ../../msn/msn_r3.c:1648 ../../msn/msn_r3.c:1659
+msgid "Pflanze"
+msgstr "Plant"
+
+#: ../../msn/msn_r3.c:1658
+msgid "Figur"
+msgstr "Figure"
+
+#: ../../msn/msn_r3.c:1658
+msgid "Stark!"
+msgstr "Strong!"
+
+#: ../../msn/msn_r3.c:1659
+msgid "Sie ist den Pflanzen auf der Erde sehr „hnlich."
+msgstr "It is very similar to the plants on earth."
+
+#: ../../msn/msn_r3.c:1668
+msgid "Er funktioniert nicht."
+msgstr "It doesn't work."
+
+#: ../../msn/msn_r3.c:1669
+msgid "Graffiti"
+msgstr "Graffiti"
+
+#: ../../msn/msn_r3.c:1669
+msgid "Seltsamer Broschmuck!"
+msgstr "Strange office decoration!"
+
+#: ../../msn/msn_r3.c:1670
+msgid "Es sind 350 Xa."
+msgstr "It's 350 Xa."
+
+#: ../../msn/msn_r3.c:1680
+msgid "Dschungel"
+msgstr "Jungle"
+
+#: ../../msn/msn_r3.c:1680
+msgid "Lauter B„ume."
+msgstr "Nothing but trees."
+
+#: ../../msn/msn_s.c:84
+msgid "Teil 1:"
+msgstr "Part 1:"
+
+#: ../../msn/msn_s.c:85
+msgid "Das Schicksal"
+msgstr "The fate of"
+
+#: ../../msn/msn_s.c:86
+msgid "des Horst Hummel"
+msgstr "Horst Hummel"
+
+#: ../../msn/msn_s.c:131
+msgid "Viertausend"
+msgstr "Four thousand"
+
+#: ../../msn/msn_s.c:131
+msgid "Fnftausend"
+msgstr "Five thousand"
+
+#: ../../msn/msn_s.c:131
+msgid "Sechstausend"
+msgstr "Six thousand"
+
+#: ../../msn/msn_s.c:131
+msgid "Siebentausend"
+msgstr "Seven thousand"
+
+#: ../../msn/msn_s.c:144
+msgid "Zwei Tage nach dem Start|im Cockpit der \"Supernova\" ..."
+msgstr "Two days after take-off|in the cockpit of the \"Supernova\"..."
+
+#: ../../msn/msn_s.c:153
+msgid "Entferung von der Sonne: 1 500 000 km.|Gehen Sie auf 8000 hpm, Captain!"
+msgstr "Distance from the sun: 1 500 000 km.|Go to 8000 hpm, Captain!"
+
+#: ../../msn/msn_s.c:168
+msgid "Geschwindigkeit:"
+msgstr "Speed:"
+
+#: ../../msn/msn_s.c:169
+msgid "Zweitausend hpm"
+msgstr "Two thousand hpm"
+
+#: ../../msn/msn_s.c:172
+msgid "Dreitausend"
+msgstr "Three thousand"
+
+#: ../../msn/msn_s.c:189
+msgid "Achttau..."
+msgstr "Eight thous..."
+
+#: ../../msn/msn_s.c:214
+msgid "Keine Ahnung, Sir."
+msgstr "I have no idea, Sir."
+
+#: ../../msn/msn_s.c:215
+msgid "Ingenieur an Commander, bitte kommen!"
+msgstr "Engineer to Commander, come in!"
+
+#: ../../msn/msn_s.c:221
+msgid "Was ist los?"
+msgstr "What's going on?"
+
+#: ../../msn/msn_s.c:222
+msgid ""
+"Wir haben einen Druckabfall im Hauptantriebssystem, Sir.|Einen Moment, ich "
+"schaue sofort nach, woran es liegt."
+msgstr ""
+"We have a pressure drop in the main propulsion system, sir.|Wait a minute, "
+"I'll have a look."
+
+#: ../../msn/msn_s.c:224
+msgid ""
+"Scheiáe, der Ionenantrieb ist explodiert!|Die Teile sind ber den ganzen|"
+"Maschinenraum verstreut."
+msgstr "Shit, the Ion drive blew up!|The parts are all over the engine room."
+
+#: ../../msn/msn_s.c:225
+msgid ""
+"Ach, du meine Gte!|Gibt es irgendeine M”glichkeit,|den Schaden schnell zu "
+"beheben?"
+msgstr "Oh, my God!|Any way to fix the damage quickly?"
+
+#: ../../msn/msn_s.c:226
+msgid "Nein, Sir. Es sieht schlecht aus."
+msgstr "No, sir. It looks bad."
+
+#: ../../msn/msn_s.c:230
+msgid "Hmm, die Erde zu alarmieren, wrde zu lange dauern."
+msgstr "Hmm, alerting Earth would take too long."
+
+#: ../../msn/msn_s.c:231
+msgid "Ich darf kein Risiko eingehen.|Captain, geben Sie sofort Alarm!"
+msgstr "I can't take any chances.|Captain, sound the alarm!"
+
+#: ../../msn/msn_s.c:232 ../../msn/msn_s.c:264
+msgid "Ok, Sir."
+msgstr "Ok, Sir."
+
+#: ../../msn/msn_s.c:255
+msgid ""
+"Commander an alle! Achtung, Achtung!|Begeben Sie sich sofort zum "
+"Notraumschiff!"
+msgstr ""
+"Commander to all! Attention, attention!|Get to the emergency ship "
+"immediately!"
+
+#: ../../msn/msn_s.c:256
+msgid "Ich wiederhole:|Begeben Sie sich sofort zum Notraumschiff!"
+msgstr "I repeat, proceed immediately|to the emergency spaceship!"
+
+#: ../../msn/msn_s.c:263
+msgid ""
+"Captain, bereiten Sie alles fr den Start vor!|Wir mssen zurck zur Erde!"
+msgstr ""
+"Captain, get everything ready for departure!|We have to get back to Earth!"
+
+#: ../../msn/msn_s.c:277
+msgid "Eine Stunde sp„ter ..."
+msgstr "An hour later..."
+
+#: ../../msn/msn_s.c:284
+msgid "Die Besatzung hat die \"Supernova\" verlassen."
+msgstr "The crew has left the \"Supernova\"."
+
+#: ../../msn/msn_s.c:285
+msgid ""
+"Das Schiff wird zwar in acht Jahren sein Ziel|erreichen, allerdings ohne "
+"Mannschaft."
+msgstr ""
+"The ship will reach its destination in eight years,|but without a crew."
+
+#: ../../msn/msn_s.c:286
+msgid "Das ist das kl„gliche Ende|der Mission Supernova."
+msgstr "This is the pitiful end|of the Supernova mission."
+
+#: ../../msn/msn_s.c:287
+msgid "Sie k”nnen jetzt ihren Computer ausschalten."
+msgstr "You can now turn off your computer."
+
+#: ../../msn/msn_s.c:290
+msgid "Warten Sie!"
+msgstr "Wait, wait!"
+
+#: ../../msn/msn_s.c:291
+msgid "Es regt sich etwas im Schiff."
+msgstr "There's something stirring in the ship."
+
+#: ../../msn/msn_s.c:307
+msgid "Uuuuaaaahhhhh"
+msgstr "Uuuuaaaahhhhh"
+
+#: ../../msn/msn_s.c:309
+msgid "Huch, ich bin ja gefesselt!|Wo bin ich?"
+msgstr "Argh, I'm tied up!|Where am I?"
+
+#: ../../msn/msn_s.c:310
+msgid ""
+"Ach so, das sind ja die Sicherheitsgurte.|Ich arbeite ja jetzt in diesem "
+"Raumschiff hier."
+msgstr "Ah yes, these are the seat belts.|I work in this spaceship now."
+
+#: ../../msn/msn_s.c:311
+msgid ""
+"Was? Schon zwei Uhr! Wieso|hat mich denn noch keiner|aus dem Bett "
+"geschmissen?"
+msgstr "What? It's 2:00 already!|How come no one has kicked me|out of bed yet?"
+
+#: ../../msn/msn_s.c:314
+msgid "Autsch!"
+msgstr "Ouch!"
+
+#: ../../msn/msn_s.c:315
+msgid "Scheiáetagenbett!"
+msgstr "Shitty bunk bed!"
+
+#: ../../msn/msn_s.c:317
+msgid "Erst mal den Lichtschalter finden."
+msgstr "First, find the light switch."
+
+#: ../../msn/msn_s.c:318
+msgid "Hmm, gar nicht so einfach|bei Schwerelosigkeit."
+msgstr "Hmm, not so easy|in weightlessness."
+
+#: ../../msn/msn_s.c:320
+msgid "Ah, hier ist er."
+msgstr "Ah, here it is."
diff --git a/dists/engine-data/supernova.dat b/dists/engine-data/supernova.dat
new file mode 100644
index 0000000000..74d9092aef
--- /dev/null
+++ b/dists/engine-data/supernova.dat
Binary files differ
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