aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--devtools/create_cryo/create_led_dat.cpp105
-rw-r--r--devtools/create_cryo/eden.h51
-rw-r--r--devtools/create_cryo/eden_icons.h236
-rw-r--r--devtools/create_cryo/eden_rooms.h465
-rw-r--r--devtools/create_cryo/module.mk11
-rw-r--r--engines/cryo/ResourceManager.cpp122
-rw-r--r--engines/cryo/ResourceManager.h92
-rw-r--r--engines/cryo/bugs.txt19
-rw-r--r--engines/cryo/configure.engine3
-rw-r--r--engines/cryo/cryo.cpp116
-rw-r--r--engines/cryo/cryo.h100
-rw-r--r--engines/cryo/cryolib.cpp433
-rw-r--r--engines/cryo/cryolib.h175
-rw-r--r--engines/cryo/debugger.cpp64
-rw-r--r--engines/cryo/debugger.h48
-rw-r--r--engines/cryo/defs.h852
-rw-r--r--engines/cryo/detection.cpp166
-rw-r--r--engines/cryo/eden.cpp9364
-rw-r--r--engines/cryo/eden.h742
-rw-r--r--engines/cryo/gameflow.txt24
-rw-r--r--engines/cryo/module.mk19
-rw-r--r--engines/cryo/platdefs.h48
-rw-r--r--engines/cryo/readme.txt72
-rw-r--r--engines/cryo/sound.cpp113
-rw-r--r--engines/cryo/sound.h70
-rw-r--r--engines/cryo/staticdata.cpp495
-rw-r--r--engines/cryo/video.cpp616
-rw-r--r--engines/cryo/video.h106
28 files changed, 14727 insertions, 0 deletions
diff --git a/devtools/create_cryo/create_led_dat.cpp b/devtools/create_cryo/create_led_dat.cpp
new file mode 100644
index 0000000000..e58ee7512d
--- /dev/null
+++ b/devtools/create_cryo/create_led_dat.cpp
@@ -0,0 +1,105 @@
+/* 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 <stdio.h>
+
+#include "eden.h"
+#include "eden_icons.h"
+#include "eden_rooms.h"
+
+template <typename T>
+static void writeLE(FILE *f, T value) {
+ for (int i = 0; i < sizeof(value); i++, value >>= 8) {
+ unsigned char b = value & 0xFF;
+ fwrite(&b, 1, 1, f);
+ }
+}
+
+struct _icon_t : icon_t {
+ void write(FILE *f) {
+ writeLE<int16>(f, sx);
+ writeLE<int16>(f, sy);
+ writeLE<int16>(f, ex);
+ writeLE<int16>(f, ey);
+ writeLE<uint16>(f, cursor_id);
+ writeLE<unsigned int>(f, action_id);
+ writeLE<unsigned int>(f, object_id);
+ }
+};
+
+static void emitIcons(FILE *f) {
+ _icon_t *icons = (_icon_t*)gameIcons;
+ for (int i = 0; i < kNumIcons; i++)
+ icons[i].write(f);
+}
+
+struct _room_t : room_t {
+ void write(FILE *f) {
+ writeLE<byte>(f, ff_0);
+ writeLE<byte>(f, exits[0]);
+ writeLE<byte>(f, exits[1]);
+ writeLE<byte>(f, exits[2]);
+ writeLE<byte>(f, exits[3]);
+ writeLE<byte>(f, flags);
+ writeLE<uint16>(f, bank);
+ writeLE<uint16>(f, party);
+ writeLE<byte>(f, level);
+ writeLE<byte>(f, video);
+ writeLE<byte>(f, location);
+ writeLE<byte>(f, background);
+ }
+};
+
+static void emitRooms(FILE *f) {
+ _room_t *rooms = (_room_t*)gameRooms;
+ for (int i = 0; i < kNumRooms; i++)
+ rooms[i].write(f);
+}
+
+static int emitData(char *outputFilename) {
+ FILE *f = fopen(outputFilename, "w+b");
+ if (!f) {
+ printf("ERROR: Unable to create output file %s\n", outputFilename);
+ return 1;
+ }
+
+ printf("Generating %s...\n", outputFilename);
+
+ emitIcons(f);
+ emitRooms(f);
+
+ fclose(f);
+
+ printf("Done!\n");
+
+ return 0;
+}
+
+int main(int argc, char **argv) {
+
+ if (argc > 1)
+ return emitData(argv[1]);
+ else
+ printf("Usage: %s <output.dat>\n", argv[0]);
+
+ return 0;
+}
diff --git a/devtools/create_cryo/eden.h b/devtools/create_cryo/eden.h
new file mode 100644
index 0000000000..dfbe7cae52
--- /dev/null
+++ b/devtools/create_cryo/eden.h
@@ -0,0 +1,51 @@
+/* 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.
+ *
+ */
+
+#pragma once
+
+typedef unsigned char byte;
+typedef short int16;
+typedef unsigned short uint16;
+
+struct icon_t {
+ int16 sx;
+ int16 sy;
+ int16 ex;
+ int16 ey;
+ uint16 cursor_id; // & 0x8000 - inactive/hidden
+ unsigned int action_id;
+ unsigned int object_id;
+};
+#define END_ICONS {-1, -1, -1, -1, 0, 0, 0}
+
+struct room_t {
+ byte ff_0;
+ byte exits[4];
+ byte flags;
+ uint16 bank;
+ uint16 party;
+ byte level;
+ byte video;
+ byte location;
+ byte background;
+};
+#define END_ROOMS {0xFF, {0xFF, 0xFF, 0xFF, 0xFF}, 0xFF, 0xFFFF, 0xFFFF, 0xFF, 0xFF, 0xFF, 0xFF}
diff --git a/devtools/create_cryo/eden_icons.h b/devtools/create_cryo/eden_icons.h
new file mode 100644
index 0000000000..1feb0a64cf
--- /dev/null
+++ b/devtools/create_cryo/eden_icons.h
@@ -0,0 +1,236 @@
+/* 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.
+ *
+ */
+
+#pragma once
+#include "eden.h"
+
+// Note: the following data can be found in the original game's executable
+
+// NB! this enum must match kActionCursors[] array
+enum kCursors { // offset in the executable
+ cuNone = 0, // 0x51F
+ cu1 = 1, // 0x563
+ cu2 = 2, // 0x556
+ cu3 = 3, // 0x549
+ cu4 = 4, // 0x570
+ cu5 = 5, // 0x57D
+ cuHand = 6, // 0x502
+ cu7 = 7, // 0x52C
+ cu8 = 8, // 0x58A
+ cu9 = 9, // 0x539
+ cuFa = 0xF, // 0x50F
+ cuFinger = 53, // 0x541
+ ICON_HIDDEN = 0x8000
+};
+
+// NB! this enum must match EdenGame::*mouse_actions[] array
+enum kActions { // offset in the executable
+ ac_ret = 27, // 0xD651
+ ac_clicplanval = 139, // 0xE068
+ ac_endFrescoes = 140, // 0xB12A
+ ac_choisir = 141, // 0xDD68
+ ac_parle_moi = 246, // 0xBFE
+ ac_adam = 247, // 0x9E4
+ ac_takeobject = 248, // 0xE66B
+ ac_putobject = 249, // 0xE681
+ ac_clictimbre = 250, // 0xE03F
+ ac_dinaparle = 251, // 0xDF32
+ ac_close_perso = 252, // 0x13EC
+ ac_generique = 260, // 0xAF51
+ ac_choixsubtitle = 261, // 0xACBF
+ ac_EdenQuit = 262, // 0xAF6D
+ ac_restart = 263, // 0xAEE7
+ ac_cancel2 = 264, // 0xACE8
+ ac_testvoice = 265, // 0xACF8
+ ac_reglervol = 266, // 0xAB9E
+ ac_load = 267, // 0xAD76
+ ac_save = 268, // 0xAD40
+ ac_cliccurstape = 269, // 0xB004
+ ac_playtape = 270, // 0x19DB
+ ac_stoptape = 271, // 0xB095
+ ac_rewindtape = 272, // 0xB0C9
+ ac_forwardtape = 273, // 0xB0E3
+ ac_confirmyes = 274, // 0xADAE
+ ac_confirmno = 275, // 0xADC1
+ ac_gotocarte = 276 // 0xE07E
+};
+
+// Indicies in to gotos[] array for World map areas
+enum kTravel { // offset in the executable
+ goMo = 24, // 0x324D
+ goChamaar = 40, // 0x3287
+ goUluru = 51, // 0x32AF
+ goKoto = 65, // 0x32E3
+ goNarim = 70, // 0x32F5
+ goTamara = 75, // 0x3307
+ goCantura = 84, // 0x3329
+ goShandovra = 93, // 0x334B
+ goEmbalmers = 102, // 0x336D
+ goWhiteArch = 111, // 0x338F
+ goMoorkusLair = 120 // 0x33B1
+};
+
+const int kNumIcons = 136;
+const icon_t gameIcons[kNumIcons] = {
+ {90, 50, 220, 150, cu8, ac_parle_moi, 0},
+ {0, 0, 319, 178, cuNone, ac_close_perso, 0},
+ END_ICONS,
+ {220, 16, 310, 176, cu5, ac_adam, 0},
+ {0, 0, 320, 200, cu8, ac_parle_moi, 0},
+ END_ICONS,
+ {215, 140, 245, 176, cuHand, ac_choisir, 0},
+ {245, 140, 275, 176, cuHand, ac_choisir, 1},
+ {275, 140, 305, 176, cuHand, ac_choisir, 2},
+ END_ICONS,
+ {245, 140, 275, 176, cuHand, ac_choisir, 0},
+ {275, 140, 305, 176, cuHand, ac_choisir, 1},
+ END_ICONS,
+ {0, 0, 320, 165, cuFa, ac_dinaparle, 0},
+ {0, 165, 320, 200, cu2, ac_endFrescoes, 0},
+ END_ICONS,
+ {0, 176, 319, 200, ICON_HIDDEN|cu9, ac_putobject, 0},
+ {120, 0, 200, 16, cuFinger, ac_clictimbre, 0},
+ {266, 0, 320, 16, ICON_HIDDEN|cuFinger, ac_clicplanval, 0},
+ // Inventory bar items
+ // Mac version displays only 9 items, with extra margins
+ {0, 178, 28, 200, cuHand, ac_takeobject, 0}, // Not on Mac
+ {30, 178, 57, 200, cuHand, ac_takeobject, 0},
+ {59, 178, 86, 200, cuHand, ac_takeobject, 0},
+ {88, 178, 115, 200, cuHand, ac_takeobject, 0},
+ {117, 178, 144, 200, cuHand, ac_takeobject, 0},
+ {146, 178, 173, 200, cuHand, ac_takeobject, 0},
+ {175, 178, 202, 200, cuHand, ac_takeobject, 0},
+ {204, 178, 231, 200, cuHand, ac_takeobject, 0},
+ {233, 178, 260, 200, cuHand, ac_takeobject, 0},
+ {262, 178, 289, 200, cuHand, ac_takeobject, 0},
+ {290, 178, 317, 200, cuHand, ac_takeobject, 0}, // Not on Mac
+ // reserve for room's icons
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0},
+ END_ICONS,
+ // Menu icons
+ {0, 0, 319, 15, cuFinger, ac_generique, 32},
+ {8, 42, 86, 51, cuFinger, ac_choixsubtitle, 16},
+ {8, 51, 86, 60, cuFinger, ac_choixsubtitle, 17},
+ {8, 60, 86, 69, cuFinger, ac_choixsubtitle, 18},
+ {8, 69, 86, 78, cuFinger, ac_choixsubtitle, 19},
+ {8, 78, 86, 87, cuFinger, ac_choixsubtitle, 20},
+ {8, 87, 86, 96, cuFinger, ac_choixsubtitle, 21},
+ {16, 137, 79, 148, cuFinger, ac_EdenQuit, 34},
+ {129, 137, 192, 148, cuFinger, ac_restart, 35},
+ {239, 137, 302, 148, cuFinger, ac_cancel2, 36},
+ {130, 112, 193, 123, cuFinger, ac_testvoice, 37},
+ {114, 40, 121, 110, cuFinger, ac_reglervol, 48},
+ {121, 40, 128, 110, cuFinger, ac_reglervol, 56},
+ {128, 40, 136, 110, cuFinger, ac_reglervol, 49},
+ {147, 40, 154, 110, cuFinger, ac_reglervol, 50},
+ {154, 40, 161, 110, cuFinger, ac_reglervol, 58},
+ {161, 40, 169, 110, cuFinger, ac_reglervol, 51},
+ {179, 40, 186, 110, cuFinger, ac_reglervol, 52},
+ {186, 40, 193, 110, cuFinger, ac_reglervol, 60},
+ {193, 40, 201, 110, cuFinger, ac_reglervol, 53},
+ {249, 42, 307, 51, cuFinger, ac_load, 65},
+ {249, 51, 307, 60, cuFinger, ac_load, 66},
+ {249, 60, 307, 69, cuFinger, ac_load, 67},
+ {231, 69, 307, 78, cuFinger, ac_load, 68},
+ {230, 104, 307, 112, cuFinger, ac_save, 81},
+ {230, 113, 307, 121, cuFinger, ac_save, 82},
+ {230, 122, 307, 130, cuFinger, ac_save, 83},
+ {0, 176, 0, 185, cuFinger, ac_cliccurstape, 100},
+ {149, 185, 166, 200, cuFinger, ac_playtape, 96},
+ {254, 185, 269, 200, cuFinger, ac_stoptape, 97},
+ {85, 185, 111, 200, cuFinger, ac_rewindtape, 98},
+ {204, 185, 229, 200, cuFinger, ac_forwardtape, 99},
+ {0, 0, 320, 200, cuFinger, ac_ret, 0},
+ END_ICONS,
+ // Yes/No dialog icons
+ {129, 84, 157, 98, cuFinger, ac_confirmyes, 0},
+ {165, 84, 188, 98, cuFinger, ac_confirmno, 113},
+ {0, 0, 320, 200, cuFinger, ac_ret, 0},
+ END_ICONS,
+ // World map hotspots
+ {136, 100, 160, 124, cu5, ac_gotocarte, goMo},
+ {150, 55, 174, 79, cu5, ac_gotocarte, goChamaar},
+ {186, 29, 210, 53, ICON_HIDDEN|cu5, ac_gotocarte, goUluru},
+ {217, 20, 241, 44, ICON_HIDDEN|cu5, ac_gotocarte, goKoto},
+ {248, 45, 272, 69, ICON_HIDDEN|cu5, ac_gotocarte, goNarim},
+ {233, 68, 257, 92, ICON_HIDDEN|cu5, ac_gotocarte, goTamara},
+ {235, 109, 259, 133, ICON_HIDDEN|cu5, ac_gotocarte, goCantura},
+ {163, 137, 187, 161, ICON_HIDDEN|cu5, ac_gotocarte, goEmbalmers},
+ {93, 145, 117, 169, ICON_HIDDEN|cu5, ac_gotocarte, goWhiteArch},
+ {70, 39, 94, 63, ICON_HIDDEN|cu5, ac_gotocarte, goShandovra},
+ {99, 8, 123, 32, ICON_HIDDEN|cu5, ac_gotocarte, goMoorkusLair},
+ {0, 0, 319, 199, cuNone, ac_close_perso, 0},
+ END_ICONS,
+};
diff --git a/devtools/create_cryo/eden_rooms.h b/devtools/create_cryo/eden_rooms.h
new file mode 100644
index 0000000000..e28bc468f4
--- /dev/null
+++ b/devtools/create_cryo/eden_rooms.h
@@ -0,0 +1,465 @@
+/* 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.
+ *
+ */
+
+#pragma once
+#include "eden.h"
+
+// Note: the following data can be found in the original game's executable
+const int kNumRooms = 424;
+const room_t gameRooms[kNumRooms] = {
+ // Mo
+ { 1, {255, 0, 0, 0}, 0, 66, 0xFFFF,29, 93, 1, 4},
+ { 7, { 4, 0, 6, 0}, 4, 72, 0xFFFF, 8,143, 2, 2},
+ { 3, { 24, 0, 5, 0}, 6, 99, 1, 6, 6, 3, 0},
+ { 3, { 24, 0, 5, 0}, 6, 68, 0x21, 6,146, 3, 0},
+ {30, { 24, 0, 5, 0}, 2, 97, 9, 6,147, 3, 0},
+ { 4, { 24, 0, 5, 0}, 2, 69, 0x29, 6,147, 3, 0},
+ {31, { 24, 0, 5, 0}, 2, 98, 8, 6,147, 3, 0},
+ { 2, { 24, 0, 5, 0}, 2, 67, 0, 6,147, 3, 0},
+ { 5, { 5, 20, 2, 8}, 4, 70, 0xFFFF, 7, 64, 4, 72},
+ { 6, { 3, 7, 4, 9}, 4, 71, 0xFFFF, 5, 4, 5, 6},
+ { 8, { 1, 0, 23, 2}, 4, 73, 0x400,23,145, 6, 2},
+ {29, { 1, 0, 0, 2}, 4, 96, 0, 0, 0, 6, 2},
+ { 9, { 0, 0, 5, 0}, 0, 74, 0, 0,112, 7, 8},
+ {10, { 0, 0, 5, 0}, 0, 75, 0x20, 0,112, 7, 8},
+ {28, { 0, 0, 4, 0}, 0, 95, 0, 0, 0, 8, 10},
+ {11, { 0, 0, 4, 0}, 0, 76, 0x10, 5,110, 8, 10},
+ {27, { 11, 0, 5, 0}, 4, 94, 0,37,152, 9, 12},
+ {12, { 11, 0, 5, 0}, 4, 77, 8, 6, 5, 9, 12},
+ {27, { 11, 0, 5, 0}, 4, 94, 0xFFFF,37,152, 9, 12},
+ {13, { 13, 0, 12, 0}, 6, 78, 0,15, 10, 10, 48},
+ {14, { 12, 0, 9, 0}, 4, 79, 0,12, 9, 11, 12},
+ {15, { 10, 0, 11, 0}, 6, 80, 0,14, 12, 12, 16},
+ {16, { 14, 0, 10, 0}, 6, 81, 0,13, 11, 13, 14},
+ {17, { 15, 0, 13, 0}, 4, 82, 0, 0, 0, 14, 16},
+ {18, { 16, 0, 14, 0}, 4, 83, 0,17, 13, 15, 16},
+ {19, { 17, 0, 13, 0}, 0, 84, 0,18, 15, 16, 16},
+ {20, { 18, 0, 9, 0}, 4, 85, 0,19, 16, 17, 16},
+ {21, { 0, 1, 17, 0}, 0, 86, 0,20, 0, 18, 70},
+ {21, { 0, 1, 17, 0}, 6, 87, 2,20, 14, 18, 70},
+ {37, { 0, 0, 9, 0}, 0, 34, 0xFFFF, 0, 0, 19, 12},
+ { 6, { 0, 0, 4, 0}, 4, 53, 0xFFFF, 5,156, 20, 72},
+ {22, {130, 0, 4, 0}, 0, 88, 0, 1, 0, 22, 46},
+ {22, {130, 0, 4, 0}, 4, 89, 2, 5, 8, 22, 46},
+ {23, { 6, 0, 0, 0}, 4, 90, 0xFFFF, 0, 0, 23, 2},
+ {24, {103, 25, 3, 0}, 6, 91, 0, 3, 1, 24, 0},
+ {25, { 0, 26, 3, 24}, 4, 92, 0,24, 2, 25, 0},
+ {26, { 0, 0, 3, 25}, 4, 93, 0,25, 3, 26, 0},
+ {32, { 0, 0, 89, 0}, 6,100, 0xFFFF, 0, 75, 32, 18},
+ {33, { 0, 0, 50, 0}, 6,105, 0xFFFF, 0, 26, 33, 20},
+ {33, { 0, 0, 51, 0}, 6,105, 0xFFFF, 0, 26, 34, 20},
+ {33, { 0, 0, 52, 0}, 6,105, 0xFFFF, 0, 26, 35, 20},
+ {33, { 0, 68, 53, 85}, 6,107, 0xFFFF, 0, 28, 36, 20},
+ {33, { 33, 0, 54, 86}, 6,109, 0xFFFF, 0, 30, 37, 20},
+ {33, { 34, 0, 55, 87}, 6,109, 0xFFFF, 0, 30, 38, 20},
+ {33, { 35, 71, 56, 88}, 6,106, 0xFFFF, 0, 27, 39, 20},
+ {33, { 36, 0, 57, 90}, 6,109, 0xFFFF, 0, 30, 40, 20},
+ {33, { 37, 74, 58, 91}, 6,106, 0xFFFF, 0, 27, 41, 20},
+ {33, { 0, 0, 59, 0}, 6,105, 0xFFFF, 0, 26, 42, 20},
+ {33, { 0, 0, 60, 0}, 6,105, 0xFFFF, 0, 26, 43, 20},
+ {33, { 0, 0, 61, 0}, 6,105, 0xFFFF, 0, 26, 44, 20},
+ {33, { 0, 0, 62, 0}, 6,105, 0xFFFF, 0, 26, 45, 20},
+ {33, { 42, 0, 63, 97}, 6,109, 0xFFFF, 0, 30, 46, 20},
+ {33, { 43, 80, 64, 0}, 6,108, 0xFFFF, 0, 29, 47, 20},
+ {33, { 44, 81, 65, 0}, 6,108, 0xFFFF, 0, 29, 48, 20},
+ {33, { 46, 83, 66,101}, 6,106, 0xFFFF, 0, 27, 49, 20},
+ {33, { 54, 86, 33, 0}, 6,108, 0xFFFF, 0, 29, 50, 20},
+ {33, { 55, 87, 34, 0}, 6,108, 0xFFFF, 0, 29, 51, 20},
+ {33, { 56, 88, 35, 71}, 6,106, 0xFFFF, 0, 27, 52, 20},
+ {33, { 57, 90, 36, 0}, 6,108, 0xFFFF, 0, 29, 53, 20},
+ {33, { 58, 91, 37, 74}, 6,106, 0xFFFF, 0, 27, 54, 20},
+ {33, { 0, 92, 38, 75}, 6,107, 0xFFFF, 0, 28, 55, 20},
+ {33, { 0, 93, 39, 76}, 6,107, 0xFFFF, 0, 28, 56, 20},
+ {33, { 0, 95, 40, 78}, 6,107, 0xFFFF, 0, 28, 57, 20},
+ {33, { 0, 96, 41, 79}, 6,110, 0xFFFF, 0, 59, 58, 20},
+ {33, { 63, 97, 42, 0}, 6,108, 0xFFFF, 0, 29, 59, 20},
+ {33, { 64, 0, 43, 80}, 6,109, 0xFFFF, 0, 30, 60, 20},
+ {33, { 65, 0, 44, 81}, 6,109, 0xFFFF, 0, 30, 61, 20},
+ {33, { 0, 99, 45, 82}, 6,107, 0xFFFF, 0, 28, 62, 20},
+ {33, { 66,100, 46, 83}, 6,106, 0xFFFF, 0, 27, 63, 20},
+ {33, { 0,101, 47, 84}, 6,107, 0xFFFF, 0, 28, 64, 20},
+ {33, { 3, 0, 48, 0}, 6,104, 0xFFFF, 0, 74, 65, 20},
+ {33, { 3, 0, 49, 0}, 6,104, 0xFFFF, 0, 74, 66, 20},
+ {33, { 68, 53, 85, 0}, 6,108, 0xFFFF, 0, 29, 67, 20},
+ {33, { 0, 54, 86, 33}, 6,107, 0xFFFF, 0, 28, 68, 20},
+ {33, { 0, 55, 87, 34}, 6,107, 0xFFFF, 0, 28, 69, 20},
+ {33, { 71, 56, 88, 35}, 6,106, 0xFFFF, 0, 27, 70, 20},
+ {33, { 32, 0, 89, 0}, 6,104, 0xFFFF, 0, 74, 71, 20},
+ {33, { 0, 57, 90, 36}, 6,107, 0xFFFF, 0, 28, 72, 20},
+ {33, { 74, 58, 91, 37}, 6,106, 0xFFFF, 0, 27, 73, 20},
+ {33, { 75, 0, 92, 38}, 6,109, 0xFFFF, 0, 30, 74, 20},
+ {33, { 76, 0, 93, 39}, 6,109, 0xFFFF, 0, 30, 75, 20},
+ {33, { 0, 0, 94, 0}, 6,105, 0xFFFF, 0, 26, 76, 20},
+ {33, { 78, 0, 95, 40}, 6,109, 0xFFFF, 0, 30, 77, 20},
+ {33, { 79, 0, 96, 41}, 6,112, 0xFFFF, 0, 61, 78, 20},
+ {33, { 0, 63, 97, 42}, 6,107, 0xFFFF, 0, 28, 79, 20},
+ {33, { 0, 0, 98, 0}, 6,105, 0xFFFF, 0, 26, 80, 20},
+ {33, { 82, 0, 99, 45}, 6,109, 0xFFFF, 0, 30, 81, 20},
+ {33, { 83, 66,100, 46}, 6,106, 0xFFFF, 0, 27, 82, 20},
+ {33, { 84, 0,101, 47}, 6,109, 0xFFFF, 0, 30, 83, 20},
+ {33, { 0, 0,102, 0}, 6,105, 0xFFFF, 0, 26, 84, 20},
+ {33, { 0, 0, 67, 0}, 6,105, 0xFFFF, 0, 26, 85, 20},
+ {33, { 85, 0, 68, 53}, 6,109, 0xFFFF, 0, 30, 86, 20},
+ {33, { 0, 0, 69, 0}, 6,105, 0xFFFF, 0, 26, 87, 20},
+ {33, { 0, 0, 70, 0}, 6,105, 0xFFFF, 0, 26, 88, 20},
+ {33, { 88, 35, 71, 56}, 6,106, 0xFFFF, 0, 27, 89, 20},
+ {33, { 0, 0, 72, 0}, 6,105, 0xFFFF, 0, 26, 90, 20},
+ {33, { 0, 0, 73, 0}, 6,105, 0xFFFF, 0, 26, 91, 20},
+ {33, { 91, 37, 74, 58}, 6,106, 0xFFFF, 0, 27, 92, 20},
+ {33, { 92, 38, 75, 0}, 6,108, 0xFFFF, 0, 29, 93, 20},
+ {33, { 93, 39, 76, 0}, 6,108, 0xFFFF, 0, 29, 94, 20},
+ {33, { 0, 0, 77, 0}, 6,105, 0xFFFF, 0, 26, 95, 20},
+ {33, { 95, 40, 78, 0}, 6,108, 0xFFFF, 0, 29, 96, 20},
+ {33, { 96, 41, 79, 0}, 6,111, 0xFFFF, 0, 60, 97, 20},
+ {33, { 0, 43, 80, 64}, 6,107, 0xFFFF, 0, 28, 98, 20},
+ {33, { 0, 44, 81, 65}, 6,107, 0xFFFF, 0, 28, 99, 20},
+ {33, { 99, 45, 82, 0}, 6,108, 0xFFFF, 0, 29,100, 20},
+ {33, {100, 46, 83, 66}, 6,106, 0xFFFF, 0, 27,101, 20},
+ {33, {101, 47, 84, 0}, 6,108, 0xFFFF, 0, 29,102, 20},
+ {34, { 49, 0, 3,104}, 0,101, 0xFFFF, 0, 0,103, 20},
+ {35, {105, 0,103, 0}, 0,102, 0xFFFF, 0, 0,104, 20},
+ {36, { 48, 0,104, 0}, 0,103, 0xFFFF, 0, 0,105, 20},
+ END_ROOMS,
+ // Tau's
+ { 1, {2, 0,129, 0}, 4, 118, 0xFFFF, 22, 0, 1, 74},
+ { 2, {0, 0, 1, 0}, 6, 119, 0xFFFF, 1, 34, 2, 56},
+ END_ROOMS,
+ // Narim's
+ { 1, {2, 0,255, 0}, 4, 321, 0xFFFF, 1, 0, 1, 24},
+ { 2, {0, 0, 1, 0}, 6, 324, 0xFFFF, 1, 32, 2, 66},
+ END_ROOMS,
+ // Embalmers
+ { 1, {2, 0,129, 0}, 6, 243, 0xFFFF, 1, 0, 1, 62},
+ { 2, {0, 0, 1, 0}, 4, 244, 0x200, 1, 49, 2, 58},
+ { 2, {0, 0, 1, 0}, 0, 245, 0, 1, 0, 2, 58},
+ END_ROOMS,
+ // White Arch
+ { 1, {0, 0,255, 0}, 6, 120, 0xFFFF, 1, 0, 1, 42},
+ { 2, {3, 0, 0, 0}, 0, 231, 0xFFFF, 0, 0, 2, 20},
+ { 3, {0, 0, 2, 0}, 6, 232, 0xFFFF, 0, 50, 3, 20},
+ { 4, {0, 0, 0, 0}, 6, 233, 0xFFFF, 0, 96, 4, 44},
+ END_ROOMS,
+ // Moorkus Lair
+ { 1, {255, 2, 0, 0}, 4, 121, 0x588, 1, 0, 1, 64},
+ { 1, {255, 2, 0, 0}, 4, 323, 0xFFFF, 1, 0, 1, 64},
+ { 2, { 3, 4, 0, 0}, 0, 122, 0xFFFF, 1, 90, 2, 60},
+ { 3, { 0, 0, 0, 0}, 4, 123, 0xFFFF, 2, 91, 3, 60},
+ { 4, { 0, 0, 2, 0}, 4, 320, 0xFFFF, 2,150, 4, 60},
+ END_ROOMS,
+ // Chamaar
+ { 1, {255, 0, 0, 0}, 0x18, 17, 0xFFFF, 1, 0, 1, 68},
+ { 2, {255, 0, 0, 0}, 0x18, 17, 0xFFFF, 0, 0, 1, 68},
+ { 3, { 0, 17, 32, 0}, 0x81, 124, 0xFFFF, 0, 0, 16, 22},
+ { 3, { 0, 18, 33, 16}, 0x81, 125, 0xFFFF, 0, 0, 17, 22},
+ { 3, { 0, 19, 34, 17}, 0x81, 126, 0xFFFF, 0, 0, 18, 22},
+ { 3, { 0, 20, 35, 18}, 0x86, 143, 0xFFFF, 0, 0, 19, 22},
+ { 3, { 0, 21, 36, 19}, 0x81, 127, 0xFFFF, 0, 0, 20, 22},
+ { 3, { 0, 22, 37, 20}, 0x81, 128, 0xFFFF, 0, 0, 21, 22},
+ { 3, { 0, 23, 38, 21}, 0x81, 129, 0xFFFF, 0, 0, 22, 22},
+ { 3, { 0, 24, 39, 22}, 0x81, 130, 0xFFFF, 0, 0, 23, 22},
+ { 3, { 0, 25, 40, 23}, 0x81, 131, 0xFFFF, 0, 0, 24, 22},
+ { 3, { 0, 26, 41, 24}, 0x81, 132, 0xFFFF, 0, 0, 25, 22},
+ { 3, { 0, 27, 42, 25}, 0x81, 133, 0xFFFF, 0, 0, 26, 22},
+ { 3, { 0, 0, 43, 26}, 0x81, 134, 0xFFFF, 0, 0, 27, 22},
+ { 3, {16, 33, 48, 0}, 0xC1, 193, 0xFFFF, 0, 0, 32, 26},
+ { 3, {17, 34, 49, 32}, 0x81, 135, 0xFFFF, 0, 0, 33, 22},
+ { 3, {18, 35, 50, 33}, 0x81, 136, 0xFFFF, 0, 0, 34, 22},
+ { 3, {19, 36, 51, 34}, 0x81, 137, 0xFFFF, 0, 0, 35, 22},
+ { 3, {20, 37, 52, 35}, 0x81, 138, 0xFFFF, 0, 0, 36, 22},
+ { 3, {21, 38, 53, 36}, 0x81, 139, 0xFFFF, 0, 0, 37, 22},
+ { 3, {22, 39, 54, 37}, 0x81, 140, 0xFFFF, 0, 0, 38, 22},
+ { 3, {23, 40, 55, 38}, 0x81, 141, 0xFFFF, 0, 0, 39, 22},
+ { 3, {24, 41, 56, 39}, 0x81, 142, 0xFFFF, 0, 0, 40, 22},
+ { 3, {25, 42, 57, 40}, 0x81, 143, 0xFFFF, 0, 0, 41, 22},
+ { 3, {26, 43, 58, 41}, 0x81, 144, 0xFFFF, 0, 0, 42, 22},
+ { 3, {27, 0, 59, 42}, 0x81, 145, 0xFFFF, 0, 0, 43, 22},
+ { 3, {32, 49, 64, 0}, 0xC0, 235, 0, 0, 0, 48, 26},
+ { 4, {32, 49, 64, 0}, 0xC6, 234, 0x200, 0,31, 48, 26},
+ { 9, {33, 50, 65, 48}, 0xC0, 277, 0xFFFF, 0, 0, 49, 26},
+ {10, { 0, 0, 49, 0}, 0xC4, 278, 0xFFFF, 0,52, 49, 26},
+ { 3, {34, 51, 66, 49}, 0xC1, 197, 0xFFFF, 0, 0, 50, 26},
+ { 3, {35, 52, 67, 50}, 0xC1, 202, 0xFFFF, 0, 0, 51, 26},
+ { 3, {36, 53, 68, 51}, 0x81, 146, 0xFFFF, 0, 0, 52, 22},
+ { 3, {37, 54, 69, 52}, 1, 173, 0xFFFF, 0, 0, 53, 28},
+ { 3, {38, 55, 70, 53}, 1, 174, 0xFFFF, 0, 0, 54, 28},
+ { 3, {39, 56, 71, 54}, 1, 175, 0xFFFF, 0, 0, 55, 28},
+ { 3, {40, 57, 72, 55}, 1, 176, 0xFFFF, 0, 0, 56, 28},
+ { 3, {41, 58, 73, 56}, 1, 177, 0xFFFF, 0, 0, 57, 28},
+ { 3, {42, 59, 74, 57}, 1, 178, 0xFFFF, 0, 0, 58, 28},
+ { 3, {43, 0, 75, 58}, 1, 181, 0xFFFF, 0, 0, 59, 28},
+ { 5, {48, 65, 1, 0}, 0xC0, 276, 0xFFFF, 0, 0, 64, 26},
+ { 3, {49, 66, 1, 64}, 0xC1, 194, 0xFFFF, 0, 0, 65, 26},
+ { 3, {50, 67, 1, 65}, 0xC1, 200, 0xFFFF, 0, 0, 66, 26},
+ { 3, {51, 68, 1, 66}, 0xC1, 195, 0xFFFF, 0, 0, 67, 26},
+ { 9, {52, 69, 1, 67}, 0xC0, 279, 0xFFFF, 0, 0, 68, 26},
+ {10, { 0, 0, 68, 0}, 0xC4, 280, 0xFFFF, 0,78, 68, 26},
+ { 3, {53, 70, 1, 68}, 1, 163, 0xFFFF, 0, 0, 69, 28},
+ { 3, {54, 71, 1, 69}, 1, 170, 0xFFFF, 0, 0, 70, 28},
+ { 3, {55, 72, 1, 70}, 1, 171, 0xFFFF, 0, 0, 71, 28},
+ { 3, {56, 73, 1, 71}, 1, 167, 0xFFFF, 0, 0, 72, 28},
+ {11, {57, 74, 1, 72}, 0x40, 223, 0xFFFF, 0, 0, 73, 32},
+ {12, {58, 75, 1, 73}, 0x40, 215, 0xFFFF, 0, 0, 74, 32},
+ { 3, {59, 0, 1, 74}, 1, 166, 0xFFFF, 0, 0, 75, 28},
+ END_ROOMS,
+ // Uluru
+ { 1, {255, 0, 0, 0}, 0x18, 41, 0xFFFF, 1, 0, 1, 36},
+ { 2, {255, 0, 0, 0}, 0x18, 41, 0xFFFF, 0, 0, 1, 36},
+ { 3, { 0, 17, 32, 0}, 0x81, 149, 0xFFFF, 0, 0, 16, 24},
+ { 3, { 0, 18, 33, 16}, 0x81, 150, 0xFFFF, 0, 0, 17, 24},
+ { 3, { 0, 19, 34, 17}, 0x81, 151, 0xFFFF, 0, 0, 18, 24},
+ { 3, { 0, 20, 35, 18}, 0x81, 152, 0xFFFF, 0, 0, 19, 24},
+ { 3, { 0, 21, 36, 19}, 0x81, 153, 0xFFFF, 0, 0, 20, 24},
+ { 3, { 0, 22, 37, 20}, 0x81, 149, 0xFFFF, 0, 0, 21, 24},
+ { 3, { 0, 23, 38, 21}, 0x81, 154, 0xFFFF, 0, 0, 22, 24},
+ { 3, { 0, 24, 39, 22}, 0x81, 155, 0xFFFF, 0, 0, 23, 24},
+ { 3, { 0, 25, 40, 23}, 0x81, 156, 0xFFFF, 0, 0, 24, 24},
+ { 3, { 0, 26, 41, 24}, 0x81, 157, 0xFFFF, 0, 0, 25, 24},
+ { 3, { 0, 27, 42, 25}, 0x81, 158, 0xFFFF, 0, 0, 26, 24},
+ { 4, { 0, 0, 43, 26}, 0x86, 238, 0xA00, 0,47, 27, 52},
+ { 4, { 0, 0, 43, 26}, 0x80, 239, 0x800, 0, 0, 27, 52},
+ { 9, { 16, 33, 48, 0}, 0xC0, 277, 0xFFFF, 0, 0, 32, 26},
+ {10, { 0, 0, 32, 0}, 0xC4, 278, 0xFFFF, 0,52, 32, 26},
+ { 3, { 17, 34, 49, 32}, 1, 191, 0xFFFF, 0, 0, 33, 30},
+ { 3, { 18, 35, 50, 33}, 1, 184, 0xFFFF, 0, 0, 34, 30},
+ { 3, { 19, 36, 51, 34}, 1, 185, 0xFFFF, 0, 0, 35, 30},
+ { 3, { 20, 37, 52, 35}, 1, 186, 0xFFFF, 0, 0, 36, 30},
+ { 3, { 21, 38, 53, 36}, 0x81, 161, 0xFFFF, 0, 0, 37, 24},
+ { 3, { 22, 39, 54, 37}, 1, 189, 0xFFFF, 0, 0, 38, 30},
+ { 3, { 23, 40, 55, 38}, 1, 186, 0xFFFF, 0, 0, 39, 30},
+ { 3, { 24, 41, 56, 39}, 1, 185, 0xFFFF, 0, 0, 40, 30},
+ {13, { 25, 42, 57, 40}, 1, 192, 0xFFFF, 0, 0, 41, 30},
+ { 3, { 26, 43, 58, 41}, 0x81, 159, 0xFFFF, 0, 0, 42, 24},
+ { 3, { 27, 0, 59, 42}, 0x81, 160, 0xFFFF, 0, 0, 43, 24},
+ {12, { 32, 49, 0, 0}, 0x40, 205, 0xFFFF, 0, 0, 48, 34},
+ {11, { 33, 50, 0, 48}, 0x40, 210, 0xFFFF, 0, 0, 49, 34},
+ {11, { 34, 51, 0, 49}, 0x40, 212, 0xFFFF, 0, 0, 50, 34},
+ {11, { 35, 52, 0, 50}, 0x40, 211, 0xFFFF, 0, 0, 51, 34},
+ {11, { 36, 53, 68, 51}, 0x40, 207, 0xFFFF, 0, 0, 52, 34},
+ { 3, { 37, 54, 69, 52}, 0xC1, 195, 0xFFFF, 0, 0, 53, 26},
+ { 3, { 38, 55, 70, 53}, 1, 190, 0xFFFF, 0, 0, 54, 30},
+ { 3, { 39, 56, 71, 54}, 1, 182, 0xFFFF, 0, 0, 55, 30},
+ { 3, { 40, 57, 72, 55}, 1, 187, 0xFFFF, 0, 0, 56, 30},
+ { 3, { 41, 58, 73, 56}, 1, 188, 0xFFFF, 0, 0, 57, 30},
+ { 3, { 42, 59, 74, 57}, 1, 190, 0xFFFF, 0, 0, 58, 30},
+ { 3, { 43, 0, 75, 58}, 0xC1, 197, 0xFFFF, 0, 0, 59, 26},
+ {11, { 52, 69, 1, 0}, 0x40, 208, 0xFFFF, 0, 0, 68, 34},
+ { 3, { 53, 70, 1, 68}, 1, 182, 0xFFFF, 0, 0, 69, 30},
+ { 3, { 54, 71, 1, 69}, 1, 187, 0xFFFF, 0, 0, 70, 30},
+ { 3, { 55, 72, 1, 70}, 1, 188, 0xFFFF, 0, 0, 71, 30},
+ { 3, { 56, 73, 1, 71}, 1, 190, 0xFFFF, 0, 0, 72, 30},
+ { 3, { 57, 74, 1, 72}, 1, 187, 0xFFFF, 0, 0, 73, 30},
+ { 3, { 58, 75, 1, 73}, 1, 182, 0xFFFF, 0, 0, 74, 30},
+ { 6, { 59, 0, 1, 74}, 0xC0, 276, 0xFFFF, 0, 0, 75, 26},
+ END_ROOMS,
+ // Koto
+ { 1, {255, 0, 0, 0}, 0x18, 42, 0xFFFF, 1, 0, 1, 40},
+ { 2, {255, 0, 0, 0}, 0x18, 42, 0xFFFF, 0, 0, 1, 40},
+ {13, { 0, 17, 32, 0}, 0x86, 283, 0xFFFF, 0,57, 16, 50},
+ { 3, { 0, 18, 33, 16}, 0x81, 125, 0xFFFF, 0, 0, 17, 22},
+ { 3, { 0, 19, 34, 17}, 0x81, 126, 0xFFFF, 0, 0, 18, 22},
+ { 3, { 0, 20, 35, 18}, 0x81, 127, 0xFFFF, 0, 0, 19, 22},
+ { 3, { 0, 21, 36, 19}, 0x81, 128, 0xFFFF, 0, 0, 20, 22},
+ { 3, { 0, 22, 37, 20}, 0x81, 131, 0xFFFF, 0, 0, 21, 22},
+ { 3, { 0, 23, 38, 21}, 0x81, 129, 0xFFFF, 0, 0, 22, 22},
+ { 3, { 0, 24, 39, 22}, 0x81, 126, 0xFFFF, 0, 0, 23, 22},
+ { 3, { 0, 25, 40, 23}, 0x81, 125, 0xFFFF, 0, 0, 24, 22},
+ { 3, { 0, 26, 41, 24}, 0x81, 127, 0xFFFF, 0, 0, 25, 22},
+ { 3, { 0, 27, 42, 25}, 0x81, 133, 0xFFFF, 0, 0, 26, 22},
+ { 3, { 0, 0, 43, 26}, 0x81, 132, 0xFFFF, 0, 0, 27, 22},
+ { 3, { 16, 33, 48, 0}, 0x81, 133, 0xFFFF, 0, 0, 32, 22},
+ { 3, { 17, 34, 49, 32}, 0x81, 124, 0xFFFF, 0, 0, 33, 22},
+ { 3, { 18, 35, 50, 33}, 0x81, 132, 0xFFFF, 0, 0, 34, 22},
+ { 3, { 19, 36, 51, 34}, 0x81, 131, 0xFFFF, 0, 0, 35, 22},
+ { 3, { 20, 37, 52, 35}, 0x81, 126, 0xFFFF, 0, 0, 36, 22},
+ { 3, { 21, 38, 53, 36}, 0x81, 125, 0xFFFF, 0, 0, 37, 22},
+ { 3, { 22, 39, 54, 37}, 0x81, 126, 0xFFFF, 0, 0, 38, 22},
+ { 3, { 23, 40, 55, 38}, 0x81, 128, 0xFFFF, 0, 0, 39, 22},
+ { 3, { 24, 41, 56, 39}, 0x81, 127, 0xFFFF, 0, 0, 40, 22},
+ { 3, { 25, 42, 57, 40}, 0x81, 133, 0xFFFF, 0, 0, 41, 22},
+ { 3, { 26, 43, 58, 41}, 0x81, 124, 0xFFFF, 0, 0, 42, 22},
+ { 3, { 27, 0, 59, 42}, 0x81, 129, 0xFFFF, 0, 0, 43, 22},
+ {11, { 32, 49, 0, 0}, 0x40, 221, 0xFFFF, 0, 0, 48, 32},
+ {12, { 33, 50, 0, 48}, 0x40, 215, 0xFFFF, 0, 0, 49, 32},
+ {11, { 34, 51, 66, 49}, 0x40, 217, 0xFFFF, 0, 0, 50, 32},
+ {11, { 35, 52, 67, 50}, 0x40, 223, 0xFFFF, 0, 0, 51, 32},
+ { 3, { 36, 53, 68, 51}, 1, 179, 0xFFFF, 0, 0, 52, 28},
+ { 3, { 37, 54, 69, 52}, 1, 180, 0xFFFF, 0, 0, 53, 28},
+ { 3, { 38, 55, 70, 53}, 1, 178, 0xFFFF, 0, 0, 54, 28},
+ { 3, { 39, 56, 71, 54}, 1, 177, 0xFFFF, 0, 0, 55, 28},
+ { 3, { 40, 57, 72, 55}, 0xC1, 196, 0xFFFF, 0, 0, 56, 26},
+ { 3, { 41, 58, 73, 56}, 0xC1, 197, 0xFFFF, 0, 0, 57, 26},
+ { 9, { 42, 59, 74, 57}, 0xC0, 279, 0xFFFF, 0, 0, 58, 26},
+ {10, { 0, 0, 58, 0}, 0xC4, 280, 0xFFFF, 0,78, 58, 26},
+ { 3, { 43, 0, 75, 58}, 0xC0, 237, 0, 0, 0, 59, 26},
+ { 4, { 43, 0, 75, 58}, 0xC6, 236, 0x200, 0,46, 59, 26},
+ {11, { 50, 67, 1, 0}, 0x40, 218, 0xFFFF, 0, 0, 66, 32},
+ {11, { 51, 68, 1, 66}, 0x40, 217, 0xFFFF, 0, 0, 67, 32},
+ { 3, { 52, 69, 1, 67}, 1, 168, 0xFFFF, 0, 0, 68, 28},
+ { 3, { 53, 70, 1, 68}, 1, 172, 0xFFFF, 0, 0, 69, 28},
+ { 3, { 54, 71, 1, 69}, 1, 170, 0xFFFF, 0, 0, 70, 28},
+ { 3, { 55, 72, 1, 70}, 0xC1, 201, 0xFFFF, 0, 0, 71, 26},
+ { 7, { 56, 73, 1, 71}, 0xC0, 276, 0xFFFF, 0, 0, 72, 26},
+ { 3, { 57, 74, 1, 72}, 0xC1, 194, 0xFFFF, 0, 0, 73, 26},
+ { 3, { 58, 75, 1, 73}, 0xC1, 195, 0xFFFF, 0, 0, 74, 26},
+ { 9, { 59, 0, 1, 74}, 0xC0, 277, 0xFFFF, 0, 0, 75, 26},
+ {10, { 0, 0, 75, 0}, 0xC4, 278, 0xFFFF, 0,52, 75, 26},
+ END_ROOMS,
+ // Tamara
+ { 1, {255, 0, 0, 0}, 0x1A, 43, 0xFFFF, 1, 0, 1, 36},
+ { 2, {255, 0, 0, 0}, 0x1A, 43, 0xFFFF, 0, 0, 1, 36},
+ { 3, { 0, 17, 32, 0}, 0x81, 147, 0xFFFF, 0, 0, 16, 24},
+ { 3, { 0, 18, 33, 16}, 0x81, 148, 0xFFFF, 0, 0, 17, 24},
+ { 3, { 0, 19, 34, 17}, 0x81, 149, 0xFFFF, 0, 0, 18, 24},
+ { 3, { 0, 20, 35, 18}, 0x81, 150, 0xFFFF, 0, 0, 19, 24},
+ { 3, { 0, 21, 36, 19}, 0x81, 151, 0xFFFF, 0, 0, 20, 24},
+ { 3, { 0, 22, 37, 20}, 0x81, 152, 0xFFFF, 0, 0, 21, 24},
+ { 3, { 0, 23, 38, 21}, 0x81, 153, 0xFFFF, 0, 0, 22, 24},
+ { 3, { 0, 24, 39, 22}, 0x81, 154, 0xFFFF, 0, 0, 23, 24},
+ { 3, { 0, 0, 40, 23}, 0x81, 155, 0xFFFF, 0, 0, 24, 24},
+ { 3, { 16, 33, 48, 0}, 0x81, 154, 0xFFFF, 0, 0, 32, 24},
+ { 3, { 17, 34, 49, 32}, 0x81, 156, 0xFFFF, 0, 0, 33, 24},
+ { 3, { 18, 35, 50, 33}, 0x81, 157, 0xFFFF, 0, 0, 34, 24},
+ { 3, { 19, 36, 51, 34}, 0x81, 158, 0xFFFF, 0, 0, 35, 24},
+ { 3, { 20, 37, 52, 35}, 0x81, 159, 0xFFFF, 0, 0, 36, 24},
+ { 3, { 21, 38, 53, 36}, 0x81, 160, 0xFFFF, 0, 0, 37, 24},
+ { 3, { 22, 39, 54, 37}, 0x81, 161, 0xFFFF, 0, 0, 38, 24},
+ { 3, { 23, 40, 55, 38}, 0x81, 162, 0xFFFF, 0, 0, 39, 24},
+ { 4, { 24, 41, 56, 39}, 0xC0, 248, 0x280, 0, 0, 40, 26},
+ { 4, { 24, 41, 56, 39}, 0xC0, 247, 0x200, 0, 0, 40, 26},
+ { 4, { 24, 41, 56, 39}, 0xC0, 246, 0xFFFF, 0, 0, 40, 26},
+ {11, { 0, 0, 57, 40}, 0x40, 207, 0xFFFF, 0, 0, 41, 34},
+ { 3, { 32, 49, 64, 0}, 0xC1, 193, 0xFFFF, 0, 0, 48, 26},
+ { 3, { 33, 50, 65, 48}, 0xC1, 200, 0xFFFF, 0, 0, 49, 26},
+ { 3, { 34, 51, 66, 49}, 1, 184, 0xFFFF, 0, 0, 50, 30},
+ { 3, { 35, 52, 67, 50}, 1, 185, 0xFFFF, 0, 0, 51, 30},
+ { 3, { 36, 53, 68, 51}, 0x81, 189, 0xFFFF, 0, 0, 52, 30},
+ { 3, { 37, 54, 69, 52}, 1, 192, 0xFFFF, 0, 0, 53, 30},
+ { 3, { 38, 55, 70, 53}, 1, 191, 0xFFFF, 0, 0, 54, 30},
+ { 9, { 39, 56, 71, 54}, 0xC0, 277, 0xFFFF, 0, 0, 55, 26},
+ {10, { 0, 0, 55, 0}, 0xC4, 278, 0xFFFF, 0,52, 55, 26},
+ { 3, { 40, 57, 72, 55}, 0xC1, 195, 0xFFFF, 0, 0, 56, 26},
+ {11, { 41, 58, 0, 56}, 0x40, 208, 0xFFFF, 0, 0, 57, 34},
+ {11, { 0, 0, 0, 57}, 0x40, 212, 0xFFFF, 0, 0, 58, 34},
+ { 8, { 48, 65, 1, 0}, 0xC1, 276, 0xFFFF, 0, 0, 64, 26},
+ { 3, { 49, 66, 1, 64}, 1, 187, 0xFFFF, 0, 0, 65, 30},
+ { 3, { 50, 67, 1, 65}, 1, 188, 0xFFFF, 0, 0, 66, 30},
+ { 3, { 51, 68, 1, 66}, 1, 190, 0xFFFF, 0, 0, 67, 30},
+ {12, { 52, 69, 1, 67}, 0x40, 205, 0xFFFF, 0, 0, 68, 34},
+ {11, { 53, 70, 1, 68}, 0x40, 203, 0xFFFF, 0, 0, 69, 34},
+ {11, { 54, 71, 1, 69}, 0x40, 211, 0xFFFF, 0, 0, 70, 34},
+ {14, { 55, 72, 1, 70}, 0x40, 213, 2, 0, 0, 71, 34},
+ {11, { 55, 72, 1, 70}, 0x40, 210, 0xFFFF, 0, 0, 71, 34},
+ {11, { 56, 0, 1, 71}, 0x40, 207, 0xFFFF, 0, 0, 72, 34},
+ END_ROOMS,
+ // Cantura
+ { 1, {255, 0, 0, 0}, 0x18, 44, 0xFFFF, 1, 0, 1, 38},
+ { 2, {255, 0, 0, 0}, 0x18, 44, 0xFFFF, 0, 0, 1, 38},
+ { 4, { 0, 0, 18, 0}, 0x86, 240, 0xA00, 0,48, 17, 54},
+ {13, { 0, 0, 18, 0}, 0x80, 241, 0xA80, 0, 0, 17, 54},
+ {14, { 0, 0, 18, 0}, 0x80, 242, 0xA02, 0, 0, 17, 54},
+ {14, { 0, 0, 18, 0}, 0x80, 242, 0xFFFF, 0, 0, 17, 54},
+ {15, { 17, 19, 0, 0}, 0x40, 224, 0xFFFF, 0, 0, 18, 32},
+ { 3, { 0, 20, 0, 18}, 0x40, 225, 0xFFFF, 0, 0, 19, 32},
+ { 3, { 0, 21, 0, 19}, 0x40, 226, 0xFFFF, 0, 0, 20, 32},
+ { 3, { 0, 22, 0, 20}, 0x40, 227, 0xFFFF, 0, 0, 21, 32},
+ { 9, { 0, 23, 38, 21}, 0xC0, 277, 0xFFFF, 0, 0, 22, 26},
+ {10, { 0, 0, 22, 0}, 0xC4, 278, 0xFFFF, 0,52, 22, 26},
+ { 5, { 0, 24, 39, 22}, 0xC0, 276, 0xFFFF, 0, 0, 23, 26},
+ { 3, { 0, 25, 40, 23}, 0x81, 125, 0xFFFF, 0, 0, 24, 22},
+ { 3, { 0, 26, 41, 24}, 0x81, 131, 0xFFFF, 0, 0, 25, 22},
+ { 3, { 0, 27, 42, 25}, 0x81, 133, 0xFFFF, 0, 0, 26, 22},
+ { 3, { 0, 0, 43, 26}, 0x81, 132, 0xFFFF, 0, 0, 27, 22},
+ {11, { 22, 39, 54, 0}, 0x40, 223, 0xFFFF, 0, 0, 38, 32},
+ { 3, { 23, 40, 55, 38}, 1, 167, 0xFFFF, 0, 0, 39, 28},
+ { 3, { 24, 41, 56, 39}, 0x81, 126, 0xFFFF, 0, 0, 40, 22},
+ { 3, { 25, 42, 57, 40}, 1, 172, 0xFFFF, 0, 0, 41, 28},
+ { 3, { 26, 43, 58, 41}, 1, 163, 0xFFFF, 0, 0, 42, 28},
+ { 3, { 27, 0, 59, 42}, 1, 168, 0xFFFF, 0, 0, 43, 28},
+ { 3, { 38, 55, 70, 0}, 1, 164, 0xFFFF, 0, 0, 54, 28},
+ { 3, { 39, 56, 71, 54}, 1, 165, 0xFFFF, 0, 0, 55, 28},
+ { 3, { 40, 57, 72, 55}, 1, 163, 0xFFFF, 0, 0, 56, 28},
+ { 3, { 41, 58, 73, 56}, 1, 167, 0xFFFF, 0, 0, 57, 28},
+ { 3, { 42, 59, 74, 57}, 1, 166, 0xFFFF, 0, 0, 58, 28},
+ { 3, { 43, 0, 75, 58}, 1, 171, 0xFFFF, 0, 0, 59, 28},
+ {12, { 0, 70, 1, 0}, 0x40, 215, 0xFFFF, 0, 0, 69, 32},
+ { 3, { 54, 71, 1, 69}, 1, 173, 0xFFFF, 0, 0, 70, 28},
+ { 3, { 55, 72, 1, 70}, 1, 168, 0xFFFF, 0, 0, 71, 28},
+ { 3, { 56, 73, 1, 71}, 1, 169, 0xFFFF, 0, 0, 72, 28},
+ { 3, { 57, 74, 1, 72}, 1, 170, 0xFFFF, 0, 0, 73, 28},
+ { 3, { 58, 75, 1, 73}, 1, 172, 0xFFFF, 0, 0, 74, 28},
+ { 3, { 59, 0, 1, 74}, 1, 175, 0xFFFF, 0, 0, 75, 28},
+ END_ROOMS,
+ // Shandovra
+ { 1, {255, 0, 0, 0}, 0x18, 45, 0xFFFF, 1, 0, 1, 40},
+ { 2, {255, 0, 0, 0}, 0x18, 45, 0xFFFF, 0, 0, 1, 40},
+ { 3, { 0, 17, 32, 0}, 0xC1, 193, 0xFFFF, 0, 0, 16, 26},
+ { 3, { 0, 18, 33, 16}, 0x81, 125, 0xFFFF, 0, 0, 17, 22},
+ { 3, { 0, 19, 34, 17}, 0x81, 126, 0xFFFF, 0, 0, 18, 22},
+ { 3, { 0, 20, 35, 18}, 0x81, 127, 0xFFFF, 0, 0, 19, 22},
+ { 3, { 0, 21, 36, 19}, 0x81, 128, 0xFFFF, 0, 0, 20, 22},
+ { 3, { 0, 22, 37, 20}, 0x81, 131, 0xFFFF, 0, 0, 21, 22},
+ { 3, { 0, 23, 38, 21}, 0x81, 129, 0xFFFF, 0, 0, 22, 22},
+ { 3, { 0, 24, 39, 22}, 0x81, 130, 0xFFFF, 0, 0, 23, 22},
+ { 3, { 0, 25, 40, 23}, 0x81, 125, 0xFFFF, 0, 0, 24, 22},
+ { 3, { 0, 26, 41, 24}, 0x81, 124, 0xFFFF, 0, 0, 25, 22},
+ { 4, { 0, 27, 42, 25}, 0x80, 250, 0x100, 0, 0, 26, 22},
+ { 4, { 0, 27, 42, 25}, 0x80, 250, 0x300, 0, 0, 26, 22},
+ { 4, { 0, 27, 42, 25}, 0x80, 251, 0x200, 0, 0, 26, 22},
+ { 4, { 0, 27, 42, 25}, 0x80, 249, 0xFFFF, 0, 0, 26, 22},
+ { 3, { 0, 0, 43, 26}, 0x81, 132, 0xFFFF, 0, 0, 27, 22},
+ { 3, {16, 33, 48, 0}, 0xC1, 193, 0xFFFF, 0, 0, 32, 26},
+ { 3, {17, 34, 49, 32}, 0xC1, 193, 0xFFFF, 0, 0, 33, 26},
+ { 3, {18, 35, 50, 33}, 0xC1, 201, 0xFFFF, 0, 0, 34, 26},
+ { 3, {19, 36, 51, 34}, 1, 170, 0xFFFF, 0, 0, 35, 28},
+ { 3, {20, 37, 52, 35}, 1, 165, 0xFFFF, 0, 0, 36, 28},
+ { 3, {21, 38, 53, 36}, 1, 164, 0xFFFF, 0, 0, 37, 28},
+ { 3, {22, 39, 54, 37}, 0x81, 126, 0xFFFF, 0, 0, 38, 22},
+ { 3, {23, 40, 55, 38}, 1, 167, 0xFFFF, 0, 0, 39, 28},
+ { 3, {24, 41, 56, 39}, 0x81, 126, 0xFFFF, 0, 0, 40, 22},
+ { 3, {25, 42, 0, 40}, 0x81, 132, 0xFFFF, 0, 0, 41, 22},
+ { 3, {26, 43, 58, 41}, 0x81, 124, 0xFFFF, 0, 0, 42, 22},
+ { 3, {27, 0, 59, 42}, 0x81, 129, 0xFFFF, 0, 0, 43, 22},
+ { 6, {32, 49, 64, 0}, 0xC0, 276, 0xFFFF, 0, 0, 48, 26},
+ { 9, {33, 50, 65, 48}, 0xC0, 279, 0xFFFF, 0, 0, 49, 26},
+ {10, { 0, 0, 49, 0}, 0xC4, 280, 0xFFFF, 0, 78, 49, 26},
+ { 3, {34, 51, 66, 49}, 0xC1, 197, 0xFFFF, 0, 0, 50, 26},
+ { 3, {35, 52, 67, 50}, 0xC1, 202, 0xFFFF, 0, 0, 51, 26},
+ { 3, {36, 53, 68, 51}, 1, 177, 0xFFFF, 0, 0, 52, 28},
+ { 3, {37, 54, 69, 52}, 0x81, 124, 0xFFFF, 0, 0, 53, 22},
+ { 3, {38, 55, 70, 53}, 0x81, 125, 0xFFFF, 0, 0, 54, 22},
+ { 3, {39, 56, 71, 54}, 1, 180, 0xFFFF, 0, 0, 55, 28},
+ {12, {40, 0, 72, 55}, 0x40, 215, 0xFFFF, 0, 0, 56, 32},
+ {11, {42, 59, 0, 0}, 0x40, 218, 0xFFFF, 0, 0, 58, 32},
+ {11, {43, 0, 75, 58}, 0x40, 216, 0xFFFF, 0, 0, 59, 32},
+ { 9, {48, 65, 1, 0}, 0xC0, 277, 0xFFFF, 0, 0, 64, 26},
+ {10, { 0, 0, 64, 0}, 0xC4, 278, 0xFFFF, 0, 52, 64, 26},
+ { 3, {49, 66, 1, 64}, 0xC1, 197, 0xFFFF, 0, 0, 65, 26},
+ { 3, {50, 67, 1, 65}, 0xC1, 200, 0xFFFF, 0, 0, 66, 26},
+ { 3, {51, 68, 1, 66}, 0x81, 125, 0xFFFF, 0, 0, 67, 22},
+ { 3, {52, 69, 1, 67}, 0x81, 129, 0xFFFF, 0, 0, 68, 22},
+ { 3, {53, 70, 1, 68}, 0x81, 133, 0xFFFF, 0, 0, 69, 22},
+ { 3, {54, 71, 1, 69}, 1, 179, 0xFFFF, 0, 0, 70, 28},
+ { 3, {55, 72, 1, 70}, 1, 181, 0xFFFF, 0, 0, 71, 28},
+ {11, {56, 0, 1, 71}, 0x40, 214, 0xFFFF, 0, 0, 72, 32},
+ {11, {59, 0, 1, 0}, 0x40, 223, 0xFFFF, 0, 0, 75, 32},
+ END_ROOMS
+};
diff --git a/devtools/create_cryo/module.mk b/devtools/create_cryo/module.mk
new file mode 100644
index 0000000000..f8e350a95d
--- /dev/null
+++ b/devtools/create_cryo/module.mk
@@ -0,0 +1,11 @@
+
+MODULE := devtools/create_cryo
+
+MODULE_OBJS := \
+ create_led_dat.o
+
+# Set the name of the executable
+TOOL_EXECUTABLE := create_led_dat
+
+# Include common rules
+include $(srcdir)/rules.mk
diff --git a/engines/cryo/ResourceManager.cpp b/engines/cryo/ResourceManager.cpp
new file mode 100644
index 0000000000..79218c598c
--- /dev/null
+++ b/engines/cryo/ResourceManager.cpp
@@ -0,0 +1,122 @@
+/* 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 "ResourceManager.h"
+
+namespace Cryo {
+
+ResourceManager::ResourceManager() {
+}
+
+ResourceManager::ResourceManager(const Common::String &datFileName) {
+ LoadDatFile(datFileName);
+}
+
+ResourceManager::~ResourceManager() {
+}
+
+bool ResourceManager::LoadDatFile(const Common::String &datFileName) {
+ if (_datFile.isOpen()) {
+ _datFile.close();
+ _files.clear();
+ }
+
+ assert(_datFile.open(datFileName));
+
+ uint16 numFiles = _datFile.readUint16LE();
+
+ for (uint16 i = 0; i < numFiles; i++) {
+ DatFileEntry entry;
+
+ _datFile.read(entry._name, sizeof(entry._name));
+ entry._size = _datFile.readUint32LE();
+ entry._offset = _datFile.readUint32LE();
+ entry._flag = _datFile.readByte();
+
+ _files.push_back(entry);
+ }
+
+ return true;
+}
+
+Common::SeekableReadStream *ResourceManager::GetFile(const Common::String &resName, unsigned int hintIndex) {
+ // First, try raw disk file so we can support modding/patching
+
+ if (Common::File::exists(resName)) {
+ debug("Loading %s from disk", resName);
+
+ Common::File *resource = new Common::File();
+ resource->open(resName);
+ return resource;
+ }
+
+ // Look inside .dat file
+
+ if (_datFile.isOpen()) {
+ for (unsigned int i = hintIndex; i < _files.size(); i++) {
+ if (!resName.compareToIgnoreCase(_files[i]._name)) {
+ debug("Loading %s from dat file", resName);
+ Common::SeekableSubReadStream *resource = new Common::SeekableSubReadStream(&_datFile, _files[i]._offset, _files[i]._offset + _files[i]._size);
+ return resource;
+ }
+ }
+ }
+
+ debug("Unable to load %s - does't exists", resName);
+ return nullptr;
+}
+
+Common::SeekableReadStream *ResourceManager::GetFile(unsigned int resIndex) {
+ if (_files.size() > resIndex) {
+ return GetFile(Common::String(_files[resIndex]._name), resIndex);
+ }
+
+ return nullptr;
+}
+
+void *ResourceManager::StreamToBuffer(Common::SeekableReadStream *stream, unsigned int *size) {
+ if (!stream)
+ return nullptr;
+
+ unsigned int readSize = stream->size();
+ byte *data = new byte[readSize + 1];
+ readSize = stream->read(data, readSize);
+
+ if (size)
+ *size = readSize;
+ return data;
+}
+
+void *ResourceManager::GetData(const Common::String &resName, unsigned int *size) {
+ Common::SeekableReadStream *resource = GetFile(resName);
+ void *data = StreamToBuffer(resource, size);
+ delete resource;
+ return data;
+}
+
+void *ResourceManager::GetData(int resIndex, unsigned int *size) {
+ Common::SeekableReadStream *resource = GetFile(resIndex);
+ void *data = StreamToBuffer(resource, size);
+ delete resource;
+ return data;
+}
+}
diff --git a/engines/cryo/ResourceManager.h b/engines/cryo/ResourceManager.h
new file mode 100644
index 0000000000..5a587fcaa3
--- /dev/null
+++ b/engines/cryo/ResourceManager.h
@@ -0,0 +1,92 @@
+/* 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.
+ *
+ */
+
+#pragma once
+
+#include "common/array.h"
+#include "common/file.h"
+#include "common/fs.h"
+#include "common/str.h"
+#include "common/substream.h"
+#include "common/debug.h"
+
+namespace Cryo {
+
+template<typename T>
+class CryoArray {
+private:
+ byte *_data;
+ bool _ownData;
+ uint16 ElementOffset(int num) {
+ assert(_data && num < Count())
+ return (static_cast<uint16 *>_data)[num];
+ }
+public:
+ CryoArray(void *data, bool ownData) : _data(data), _ownData(ownData) {
+ }
+ ~CryoArray() {
+ if (_ownData)
+ delete data;
+ }
+ uint16 Count() {
+ return ElementOffset(0) / 2;
+ }
+ const T *operator[](int index) {
+ return static_cast<T *>(_data + ElementOffset(num));
+ }
+};
+
+class ResourceManager {
+private:
+ struct DatFileEntry {
+ char _name[16];
+ unsigned int _size;
+ unsigned int _offset;
+ byte _flag;
+ };
+
+ Common::Array<DatFileEntry> _files;
+ Common::File _datFile;
+
+ static void *StreamToBuffer(Common::SeekableReadStream *stream, unsigned int *size);
+
+public:
+ ResourceManager(const Common::String &datFileName);
+ ResourceManager();
+ ~ResourceManager();
+
+ bool LoadDatFile(const Common::String &datFileName);
+
+ // Load resource as a seekable stream
+ Common::SeekableReadStream *GetFile(const Common::String &resName, unsigned int hintIndex = 0);
+ Common::SeekableReadStream *GetFile(unsigned int resIndex);
+
+ // Load resource as a buffer
+ void *GetData(const Common::String &resName, unsigned int *size = nullptr);
+ void *GetData(int resIndex, unsigned int *size = nullptr);
+ void *operator[](int resIndex) {
+ return GetData(resIndex);
+ }
+
+};
+
+}
diff --git a/engines/cryo/bugs.txt b/engines/cryo/bugs.txt
new file mode 100644
index 0000000000..a69538a449
--- /dev/null
+++ b/engines/cryo/bugs.txt
@@ -0,0 +1,19 @@
+
+1. Open menu and replay last dialog, then press stop. hover over buttons - hint text will be misplaced
+2. During valley location change some junk appears in the bottom half of screen for a brief time (broken transition effect?)
+3. Transitions often show a lot of red colors (bad palette fadein/out?)
+4. After game load in some areas (White Arch) top bar and inventory not redrawn due to (DrawFlags?) initialized incorrectly
+5. Mac reload feature uses hardcoded savefile from eden.dat
+6. First time in Tau's cave, try to take knife. When Dina objects, click on her - Tau's dialog will start (maybe it's original bug?)
+7. Mouse clipping may be lost during FMV scenes
+8. Screen doubling feature probably doesn't work (not really needed, can be replaced with built-in SCUMMVM scaler)
+9. Tons of debug messages spam when hover mouse over party icons or menu buttons
+A. King's bread drawn over inventory bar
+B. PC cursor clipped too agressively
+C. PC logos and credits videos won't play because encoded in old HNM format
+D. Eye blinking works incorrectly?
+E. Bogus hitbox in upper right corner of mirror screen (under mini-map)
+F. Wrong frescoes cursor on PC
+G. Junk on a valley entrance screen on PC
+H. On PC, no sound during first Mungo's dialogue, memory corruption after that
+J. PC intro video is lagging behind of background voice
diff --git a/engines/cryo/configure.engine b/engines/cryo/configure.engine
new file mode 100644
index 0000000000..a0f5a044e9
--- /dev/null
+++ b/engines/cryo/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 cryo "Lost Eden" no "" "" ""
diff --git a/engines/cryo/cryo.cpp b/engines/cryo/cryo.cpp
new file mode 100644
index 0000000000..1538ee4110
--- /dev/null
+++ b/engines/cryo/cryo.cpp
@@ -0,0 +1,116 @@
+/* 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/scummsys.h"
+
+#include "common/config-manager.h"
+#include "common/debug.h"
+#include "common/debug-channels.h"
+#include "common/error.h"
+#include "graphics/surface.h"
+#include "graphics/screen.h"
+#include "graphics/palette.h"
+#include "common/system.h"
+
+#include "engines/util.h"
+
+#include "cryo/cryo.h"
+#include "cryo/eden.h"
+
+namespace Cryo {
+
+CryoEngine *g_ed = nullptr;
+
+CryoEngine::CryoEngine(OSystem *syst, const ADGameDescription *gameDesc) : Engine(syst), _gameDescription(gameDesc) {
+ // Put your engine in a sane state, but do nothing big yet;
+ // in particular, do not load data from files; rather, if you
+ // need to do such things, do them from run().
+
+ // Do not initialize graphics here
+ // Do not initialize audio devices here
+
+ // However this is the place to specify all default directories
+// const Common::FSNode gameDataDir(ConfMan.get("path"));
+// SearchMan.addSubDirectoryMatching(gameDataDir, "sound");
+
+ // Here is the right place to set up the engine specific debug channels
+ DebugMan.addDebugChannel(kCryoDebugExample, "example", "this is just an example for a engine specific debug channel");
+ DebugMan.addDebugChannel(kCryoDebugExample2, "example2", "also an example");
+
+ // Don't forget to register your random source
+ _rnd = new Common::RandomSource("cryo");
+ _debugger = nullptr;
+
+ _game = nullptr;
+ _video = nullptr;
+ _screenView = nullptr;
+
+ _showHotspots = false;
+
+ g_ed = this;
+}
+
+CryoEngine::~CryoEngine() {
+ debug("CryoEngine::~CryoEngine");
+
+ // Dispose your resources here
+ delete _rnd;
+ delete _game;
+ delete _video;
+ delete _screenView;
+ delete _debugger;
+
+ // Remove all of our debug levels here
+ DebugMan.clearAllDebugChannels();
+}
+
+Common::Error CryoEngine::run() {
+ _game = new EdenGame(this);
+ _video = new HnmPlayer(this);
+ _screenView = new View(320, 200);
+ _debugger = new Debugger(this);
+
+ ///// CLTimer
+ _timerTicks = 0; // incremented in realtime
+
+ // Initialize graphics using following:
+ initGraphics(320, 200, false);
+ _screen.create(320, 200, Graphics::PixelFormat::createFormatCLUT8());
+
+ // Additional setup.
+ debug("CryoEngine::init");
+
+ // Your main even loop should be (invoked from) here.
+ debug("CryoEngine::go: Hello, World!");
+
+ // This test will show up if -d1 and --debugflags=example are specified on the commandline
+ debugC(1, kCryoDebugExample, "Example debug call");
+
+ // This test will show up if --debugflags=example or --debugflags=example2 or both of them and -d3 are specified on the commandline
+ debugC(3, kCryoDebugExample | kCryoDebugExample2, "Example debug call two");
+
+ _game->run();
+
+ return Common::kNoError;
+}
+
+} // End of namespace Cryo
diff --git a/engines/cryo/cryo.h b/engines/cryo/cryo.h
new file mode 100644
index 0000000000..515849ffea
--- /dev/null
+++ b/engines/cryo/cryo.h
@@ -0,0 +1,100 @@
+/* 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 CRYO_CRYO_H
+#define CRYO_CRYO_H
+
+#include "common/scummsys.h"
+#include "common/config-manager.h"
+#include "engines/advancedDetector.h"
+#include "common/debug.h"
+#include "common/debug-channels.h"
+#include "common/error.h"
+#include "common/random.h"
+#include "engines/engine.h"
+#include "gui/debugger.h"
+#include "graphics/surface.h"
+#include "graphics/screen.h"
+
+#include "cryo/eden.h"
+#include "cryo/video.h"
+#include "cryo/debugger.h"
+
+namespace Cryo {
+
+class Console;
+
+// our engine debug channels
+enum {
+ kCryoDebugExample = 1 << 0,
+ kCryoDebugExample2 = 1 << 1
+ // next new channel must be 1 << 2 (4)
+ // the current limitation is 32 debug channels (1 << 31 is the last one)
+};
+
+class CryoEngine : public Engine {
+public:
+ CryoEngine(OSystem *syst, const ADGameDescription *gameDesc);
+ ~CryoEngine();
+
+ virtual Common::Error run();
+
+ // Detection related functions
+ const ADGameDescription *_gameDescription;
+ const char *getGameId() const;
+ Common::Platform getPlatform() const;
+ bool isDemo() const;
+
+ // We need random numbers
+ Common::RandomSource *_rnd;
+
+ Graphics::Surface _screen;
+ EdenGame *_game;
+ HnmPlayer *_video;
+ Debugger *_debugger;
+
+ View *_screenView;
+ volatile int32 _timerTicks;
+
+ bool _showHotspots;
+
+ void pollEvents();
+
+ void hideMouse();
+ void showMouse();
+ void getMousePosition(int16 *x, int16 *y);
+ void setMousePosition(int16 x, int16 y);
+ bool isMouseButtonDown();
+};
+
+extern CryoEngine *g_ed;
+
+// Example console class
+class Console : public GUI::Debugger {
+public:
+ Console(CryoEngine *vm) {}
+ virtual ~Console(void) {}
+};
+
+} // End of namespace Cryo
+
+#endif
diff --git a/engines/cryo/cryolib.cpp b/engines/cryo/cryolib.cpp
new file mode 100644
index 0000000000..8b8efad588
--- /dev/null
+++ b/engines/cryo/cryolib.cpp
@@ -0,0 +1,433 @@
+/* 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 "common/events.h"
+#include "common/timer.h"
+
+#include "graphics/palette.h"
+
+#include "cryo/cryo.h"
+#include "cryo/cryolib.h"
+
+namespace Cryo {
+
+///// Mac APIs
+
+void SysBeep(int x) {
+}
+
+void FlushEvents(int16 arg1, int16 arg2) {
+}
+
+///// CLView
+
+View::View(int w, int h) {
+ void *buffer = (byte *)malloc(w * h);
+ if (buffer)
+ initDatas(w, h, buffer);
+ else
+ error("Unable to allocate view buffer");
+}
+
+View::~View() {
+ if (_bufferPtr)
+ free(_bufferPtr);
+}
+
+// Original name: CLView_SetSrcZoomValues
+void View::setSrcZoomValues(int x, int y) {
+ _zoom._srcLeft = x;
+ _zoom._srcTop = y;
+}
+
+// Original name: CLView_SetDisplayZoomValues
+void View::setDisplayZoomValues(int w, int h) {
+ _zoom._width = w;
+ _zoom._height = h;
+}
+
+// Original name: CLView_InitDatas
+void View::initDatas(int w, int h, void *buffer) {
+ _bufferPtr = (byte *)buffer;
+ _width = w;
+ _height = h;
+ _pitch = w;
+ _normal._srcLeft = 0;
+ _normal._srcTop = 0;
+ _normal._dstLeft = 0;
+ _normal._dstTop = 0;
+ _normal._width = w;
+ _normal._height = h;
+ _zoom._srcLeft = 0;
+ _zoom._srcTop = 0;
+ _zoom._dstLeft = 0;
+ _zoom._dstTop = 0;
+ _zoom._width = w;
+ _zoom._height = h;
+}
+
+// Original name: CLView_CenterIn
+void View::centerIn(View *parent) {
+ _normal._dstLeft = (parent->_width - _normal._width) / 2;
+ _normal._dstTop = (parent->_height - _normal._height) / 2;
+ _zoom._dstLeft = (parent->_width - _zoom._width) / 2;
+ _zoom._dstTop = (parent->_height - _zoom._height) / 2;
+}
+
+///// CLPalette
+uint16 gIntervalLast, gIntervalFirst, gIntervalSet;
+int16 gMacintize = 0;
+color_t black_palette[256];
+color_t last_palette[256];
+
+void CLPalette_Init() {
+ for (int16 i = 0; i < 256; i++)
+ black_palette[i].r = black_palette[i].g = black_palette[i].b = 0;
+}
+
+void CLPalette_SetLastPalette(color_t *palette, int16 first, int16 count) {
+ for (int16 i = first; i < first + count; i++)
+ last_palette[i] = palette[i];
+}
+
+void CLPalette_GetLastPalette(color_t *palette) {
+ for (int16 i = 0; i < 256; i++)
+ palette[i] = last_palette[i];
+}
+
+void CLPalette_SetRGBColor(color_t *palette, uint16 index, color3_t *rgb) {
+ palette[index].r = rgb->r;
+ palette[index].g = rgb->g;
+ palette[index].b = rgb->b;
+ palette[index].a = 0;
+}
+
+void CLPalette_Macintize(int16 macintize) {
+ gMacintize = macintize;
+}
+
+void CLPalette_SetInterval(uint16 first, uint16 last) {
+ gIntervalFirst = first;
+ gIntervalSet = 1;
+ gIntervalLast = last;
+}
+
+void CLPalette_DeactivateInterval() {
+ gIntervalSet = 0;
+}
+
+void CLPalette_Send2Screen(struct color_t *palette, uint16 first, uint16 count) {
+ if (gMacintize) {
+ palette[0].r = palette[0].g = palette[0].b = 0xFFFF;
+ palette[255].r = palette[255].g = palette[255].b = 0;
+ }
+ if (gIntervalSet) {
+ if (first < gIntervalFirst)
+ first = gIntervalFirst;
+ if (first + count > gIntervalLast)
+ count = gIntervalLast - first;
+ }
+
+ byte buffer[256 * 3];
+ for (int i = 0; i < 256; i++) {
+ buffer[i * 3] = palette[i].r >> 8;
+ buffer[i * 3 + 1] = palette[i].g >> 8;
+ buffer[i * 3 + 2] = palette[i].b >> 8;
+ }
+
+ g_system->getPaletteManager()->setPalette(buffer, first, count);
+ g_system->updateScreen();
+
+ CLPalette_SetLastPalette(palette, first, count);
+}
+
+void CLPalette_BeSystem() {
+}
+
+///// CLBlitter
+static uint16 newPaletteCount, newPaletteFirst;
+static color_t *pNewPalette;
+static bool useNewPalette;
+
+void CLBlitter_CopyViewRect(View *view1, View *view2, Common::Rect *rect1, Common::Rect *rect2) {
+ int dy = rect2->top;
+ int w = rect1->right - rect1->left + 1;
+ // debug("- Copy rect %3d:%3d-%3d:%3d -> %3d:%3d-%3d:%3d - %s",
+ // rect1->sx, rect1->sy, rect1->ex, rect1->ey,
+ // rect2->sx, rect2->sy, rect2->ex, rect2->ey,
+ // (rect1->ex - rect1->sx == rect2->ex - rect2->sx && rect1->ey - rect1->sy == rect2->ey - rect2->sy) ? "ok" : "BAD");
+ assert(rect1->right - rect1->left == rect2->right - rect2->left && rect1->bottom - rect1->top == rect2->bottom - rect2->top);
+ for (int sy = rect1->top; sy <= rect1->bottom; sy++, dy++) {
+ byte *s = view1->_bufferPtr + sy * view1->_pitch + rect1->left;
+ byte *d = view2->_bufferPtr + dy * view2->_pitch + rect2->left;
+ for (int x = 0; x < w; x++)
+ *d++ = *s++;
+ }
+}
+
+void CLBlitter_Send2ScreenNextCopy(color_t *palette, uint16 first, uint16 count) {
+ pNewPalette = palette;
+ useNewPalette = true;
+ newPaletteFirst = first;
+ newPaletteCount = count;
+}
+
+void CLBlitter_OneBlackFlash() {
+}
+
+void CLBlitter_CopyView2ViewSimpleSize(byte *src, int16 srcw, int16 srcp, int16 srch,
+ byte *dst, int16 dstw, int16 dstp, int16 dsth) {
+ for (int16 y = 0; y < srch; y++) {
+ for (int16 x = 0; x < srcw; x++)
+ *dst++ = *src++;
+ src += srcp - srcw;
+ dst += dstp - dstw;
+ }
+}
+
+void CLBlitter_CopyView2ScreenCUSTOM(View *view) {
+ View *dest = g_ed->_screenView;
+ int16 srcpitch = view->_pitch;
+ int16 dstpitch = dest->_pitch;
+
+ CLBlitter_CopyView2ViewSimpleSize(view->_bufferPtr + view->_normal._srcTop * srcpitch + view->_normal._srcLeft,
+ view->_normal._width, srcpitch, view->_normal._height,
+ dest->_bufferPtr + (dest->_normal._dstTop + view->_normal._dstTop) * dstpitch + dest->_normal._dstLeft + view->_normal._dstLeft,
+ dest->_normal._width, dstpitch, dest->_normal._height);
+}
+
+void CLBlitter_CopyView2Screen(View *view) {
+ if (useNewPalette) {
+ color_t palette[256];
+ CLPalette_GetLastPalette(palette);
+ CLPalette_Send2Screen(pNewPalette, newPaletteFirst, newPaletteCount);
+ useNewPalette = false;
+ }
+
+ //HACK: Quick hack to force screen update
+ if (view)
+ CLBlitter_CopyView2ScreenCUSTOM(view);
+
+ g_system->copyRectToScreen(g_ed->_screenView->_bufferPtr, g_ed->_screenView->_pitch, 0, 0, g_ed->_screenView->_width, g_ed->_screenView->_height);
+ g_system->updateScreen();
+}
+
+void CLBlitter_UpdateScreen() {
+ CLBlitter_CopyView2Screen(nullptr);
+}
+
+void CLBlitter_FillView(View *view, unsigned int fill) {
+ byte *d = view->_bufferPtr;
+ assert((fill & 0xFF) * 0x01010101 == fill);
+
+ for (int16 y = 0; y < view->_height; y++) {
+ for (int16 x = 0; x < view->_width; x++)
+ *d++ = fill;
+ d += view->_pitch - view->_width;
+ }
+}
+
+void CLBlitter_FillScreenView(unsigned int fill) {
+ CLBlitter_FillView(g_ed->_screenView, fill);
+}
+
+///// events wrapper
+int _mouseButton;
+byte _keyState[256];
+
+void CryoEngine::pollEvents() {
+ g_system->delayMillis(10);
+
+ Common::Event event;
+ while (g_system->getEventManager()->pollEvent(event)) {
+ // Handle keypress
+ switch (event.type) {
+ case Common::EVENT_QUIT:
+ case Common::EVENT_RTL:
+ return;
+
+ case Common::EVENT_KEYDOWN:
+ // Check for debugger
+ if ((event.kbd.keycode == Common::KEYCODE_d) && (event.kbd.flags & Common::KBD_CTRL)) {
+ // Attach to the debugger
+ _debugger->attach();
+ _debugger->onFrame();
+ }
+ return;
+ case Common::EVENT_KEYUP:
+ // _keyState[(byte)toupper(event.kbd.ascii)] = false;
+ return;
+ case Common::EVENT_LBUTTONDOWN:
+ _mouseButton = 1;
+ return;
+ case Common::EVENT_RBUTTONDOWN:
+ _mouseButton = 2;
+ return;
+ case Common::EVENT_LBUTTONUP:
+ case Common::EVENT_RBUTTONUP:
+ _mouseButton = 0;
+ return;
+ default:
+ break;
+ }
+ }
+}
+
+void CryoEngine::hideMouse() {
+}
+
+void CryoEngine::showMouse() {
+}
+
+void CryoEngine::getMousePosition(int16 *x, int16 *y) {
+ *x = g_system->getEventManager()->getMousePos().x;
+ *y = g_system->getEventManager()->getMousePos().y;
+}
+
+void CryoEngine::setMousePosition(int16 x, int16 y) {
+ g_system->warpMouse(x, y);
+}
+
+bool CryoEngine::isMouseButtonDown() {
+ pollEvents();
+ return _mouseButton != 0;
+}
+
+///// CLSound
+// base sound
+
+Sound::Sound(int16 length, float rate, int16 sampleSize, int16 mode) {
+ _sndHandle = nullptr;
+ _headerLen = 0;
+ _headerOffset = 0;
+
+ _length = 0;
+ _mode = 0;
+ _volume = 0;
+
+ _maxLength = length;
+ _rate = rate;
+ _sampleSize = sampleSize;
+ _buffer = nullptr;
+ // sndHandle = CLMemory_AllocHandle(arg1 + 100);
+ // if(!sndHandle)
+ // error("CLSoundRaw_New - Not enough memory");
+ // else
+ prepareSample(mode);
+}
+
+Sound::~Sound() {
+}
+
+void CLSoundRaw_AssignBuffer(Sound *sound, void *buffer, int bufferOffs, int length) {
+ sound->_length = length;
+ char *buf = bufferOffs + (char *)buffer;
+ // if(CLSound_GetWantsDesigned())
+ // CLSound_Signed2NonSigned(buf, length);
+ sound->_buffer = buf;
+ // if(sound->reversed && sound->sampleSize == 16)
+ // ReverseBlock16(buf, length);
+}
+
+void Sound::prepareSample(int16 mode) {
+ _mode = mode;
+ _volume = 255;
+}
+
+void Sound::setWantsDesigned(int16 designed) {
+}
+
+///// CLSoundChannel
+/// sound output device that plays queue of sounds
+SoundChannel::SoundChannel(int arg1) {
+ _volumeLeft = _volumeRight = 255;
+ _numSounds = 0;
+
+ for (int16 i = 0; i < kCryoMaxChSounds; i++)
+ _sounds[i] = nullptr;
+}
+
+SoundChannel::~SoundChannel() {
+}
+
+void SoundChannel::stop() {
+ // _vm->_mixer->stopHandle(this);
+}
+
+void SoundChannel::play(Sound *sound) {
+}
+
+int16 SoundChannel::getVolume() {
+ return (_volumeLeft + _volumeRight) / 2;
+}
+
+void SoundChannel::setVolume(int16 volume) {
+ if (volume < 0 || volume > 255)
+ return;
+
+ _volumeLeft = volume;
+ _volumeRight = volume;
+}
+
+void SoundChannel::setVolumeRight(int16 volume) {
+ if (volume < 0 || volume > 255)
+ return;
+
+ _volumeRight = volume;
+}
+
+void SoundChannel::setVolumeLeft(int16 volume) {
+ if (volume < 0 || volume > 255)
+ return;
+
+ _volumeLeft = volume;
+}
+
+///// CLTimer
+void CLTimer_Action(void *arg) {
+ // long& counter = *((long*)arg);
+ // counter++;
+ g_ed->_timerTicks++;
+}
+
+///// CRYOLib
+void CRYOLib_ManagersInit() {
+ g_system->getTimerManager()->installTimerProc(CLTimer_Action, 10000, nullptr, "100hz timer");
+ g_ed->_screenView->initDatas(g_ed->_screen.w, g_ed->_screen.h, g_ed->_screen.getPixels());
+}
+
+void CRYOLib_ManagersDone() {
+ g_system->getTimerManager()->removeTimerProc(CLTimer_Action);
+}
+
+PakHeaderNode::PakHeaderNode(int count) {
+ _count = count;
+ _files = new PakHeaderItem[count];
+}
+
+PakHeaderNode::~PakHeaderNode() {
+ _count = 0;
+ delete[] _files;
+}
+
+} // End of namespace Cryo
diff --git a/engines/cryo/cryolib.h b/engines/cryo/cryolib.h
new file mode 100644
index 0000000000..83fdfee236
--- /dev/null
+++ b/engines/cryo/cryolib.h
@@ -0,0 +1,175 @@
+/* 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 CRYO_CRYOLIB_H
+#define CRYO_CRYOLIB_H
+
+#include "audio/mixer.h"
+#include "common/system.h"
+
+#include "cryo/platdefs.h"
+
+namespace Cryo {
+
+class CryoEngine;
+
+#define SW16(n) ( (((n) & 0xFF) << 8) | (((n) >> 8) & 0xFF) )
+#define SW32(n) ( (((n) & 0xFF) << 24) | (((n) >> 24) & 0xFF) | (((n) & 0xFF00) << 8) | (((n) >> 8) & 0xFF00))
+#ifdef SCUMM_BIG_ENDIAN
+//big-endian host
+#define LE16(n) SW16(n)
+#define LE32(n) SW32(n)
+#define BE16(n) (n)
+#define BE32(n) (n)
+#else
+//little-endian host
+#define LE16(n) (n)
+#define LE32(n) (n)
+#define BE16(n) SW16(n)
+#define BE32(n) SW32(n)
+#endif
+
+enum {
+ fsFromStart = 1
+};
+
+struct BlitView{
+ int _srcLeft;
+ int _srcTop;
+ int _dstLeft;
+ int _dstTop;
+ int _width;
+ int _height;
+};
+
+class View {
+public:
+ View(int w, int h);
+ ~View();
+
+ void setSrcZoomValues(int x, int y);
+ void setDisplayZoomValues(int w, int h);
+ void initDatas(int w, int h, void *buffer);
+ void centerIn(View *parent);
+
+ int _width;
+ int _height;
+ byte *_bufferPtr;
+ int16 _pitch;
+ BlitView _normal;
+ BlitView _zoom;
+};
+
+struct color3_t {
+ uint16 r, g, b;
+};
+
+struct color_t {
+ uint16 a, r, g, b;
+};
+
+struct HNMHeader {
+ int32 _signature;
+ uint16 _width;
+ uint16 _height;
+ int32 _numbFrame;
+ int32 _bufferSize;
+};
+
+class Sound {
+private:
+ int32 _headerOffset;
+ int16 _mode;
+ int16 _volume;
+
+public:
+ Sound(int16 length, float rate, int16 sampleSize, int16 mode);
+ ~Sound();
+
+ void assignBuffer(void *buffer, int bufferOffs, int length);
+ void prepareSample(int16 mode);
+ void setWantsDesigned(int16 designed);
+
+ char *_sndHandle;
+ char *_buffer;
+
+ float _rate;
+
+ int16 _maxLength;
+ int16 _headerLen;
+ int16 _sampleSize;
+
+ int _length;
+};
+
+#define kCryoMaxChSounds 10
+
+class SoundChannel {
+private:
+ int16 _volumeLeft;
+ int16 _volumeRight;
+ int16 _numSounds;
+
+ Sound *_sounds[kCryoMaxChSounds];
+
+public:
+ SoundChannel(int arg1);
+ ~SoundChannel();
+
+ void stop();
+ void play(Sound *sound);
+ int16 getVolume();
+ void setVolume(int16 volume);
+ void setVolumeRight(int16 volume);
+ void setVolumeLeft(int16 volume);
+};
+
+void SysBeep(int x);
+void FlushEvents(int16 arg1, int16 arg2);
+
+void CLBlitter_CopyViewRect(View *view1, View *view2, Common::Rect *rect1, Common::Rect *rect2);
+void CLBlitter_Send2ScreenNextCopy(color_t *palette, uint16 first, uint16 count);
+void CLBlitter_OneBlackFlash();
+void CLBlitter_CopyView2ViewSimpleSize(byte *src, int16 srcw, int16 srcp, int16 srch,
+ byte *dst, int16 dstw, int16 dstp, int16 dsth);
+void CLBlitter_CopyView2ScreenCUSTOM(View *view);
+void CLBlitter_CopyView2Screen(View *view);
+void CLBlitter_UpdateScreen();
+void CLBlitter_FillView(View *view, unsigned int fill);
+void CLBlitter_FillScreenView(unsigned int fill);
+
+void CLPalette_Init();
+void CLPalette_SetLastPalette(color_t *palette, int16 first, int16 count);
+void CLPalette_GetLastPalette(color_t *palette);
+void CLPalette_SetRGBColor(color_t *palette, uint16 index, color3_t *rgb);
+void CLPalette_Macintize(int16 macintize);
+void CLPalette_SetInterval(uint16 first, uint16 last);
+void CLPalette_DeactivateInterval();
+void CLPalette_Send2Screen(struct color_t *palette, uint16 first, uint16 count);
+void CLPalette_BeSystem();
+
+void CRYOLib_ManagersInit();
+void CRYOLib_ManagersDone();
+
+} // End of namespace Cryo
+
+#endif
diff --git a/engines/cryo/debugger.cpp b/engines/cryo/debugger.cpp
new file mode 100644
index 0000000000..f19c616b72
--- /dev/null
+++ b/engines/cryo/debugger.cpp
@@ -0,0 +1,64 @@
+/* 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/coroutines.h"
+#include "cryo/debugger.h"
+#include "cryo/cryo.h"
+
+namespace Cryo {
+
+Debugger::Debugger(CryoEngine *vm) : GUI::Debugger(), _vm(vm) {
+ registerCmd("showHotspots", WRAP_METHOD(Debugger, Cmd_ShowHotspots));
+ registerCmd("fullInventory", WRAP_METHOD(Debugger, Cmd_FullInventory));
+}
+
+/**
+ * This command enables/disables hotspot display
+ */
+bool Debugger::Cmd_ShowHotspots(int argc, const char **argv) {
+ if (argc != 1) {
+ debugPrintf("Usage: %s\n", argv[0]);
+ return true;
+ }
+
+ _vm->_showHotspots ^= 1;
+
+ return false;
+}
+
+bool Debugger::Cmd_FullInventory(int argc, const char **argv) {
+ if (argc != 1) {
+ debugPrintf("Usage: %s\n", argv[0]);
+ return true;
+ }
+
+ for (int i = 0; i < MAX_OBJECTS; i++) {
+ object_t *object = _vm->_game->getObjectPtr(i);
+ object->_flags |= ObjectFlags::ofFlag1;
+ object->_count++;
+ }
+
+ _vm->_game->showObjects();
+
+ return false;
+}
+} // End of namespace Cryo
diff --git a/engines/cryo/debugger.h b/engines/cryo/debugger.h
new file mode 100644
index 0000000000..ee765128ce
--- /dev/null
+++ b/engines/cryo/debugger.h
@@ -0,0 +1,48 @@
+/* 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 CRYO_DEBUGGER_H
+#define CRYO_DEBUGGER_H
+
+#include "common/scummsys.h"
+#include "gui/debugger.h"
+
+namespace Cryo {
+
+class CryoEngine;
+
+class Debugger : public GUI::Debugger {
+private:
+ CryoEngine *_vm;
+
+public:
+ Debugger(CryoEngine *vm);
+ virtual ~Debugger() {}
+
+protected:
+ bool Cmd_ShowHotspots(int argc, const char **argv);
+ bool Cmd_FullInventory(int argc, const char **argv);
+};
+
+} // End of namespace Cryo
+
+#endif
diff --git a/engines/cryo/defs.h b/engines/cryo/defs.h
new file mode 100644
index 0000000000..b7206dc7e4
--- /dev/null
+++ b/engines/cryo/defs.h
@@ -0,0 +1,852 @@
+/* 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 "cryo/cryolib.h"
+
+#ifndef CRYO_DEFS_H
+#define CRYO_DEFS_H
+
+namespace Cryo {
+
+#define getElem(array, idx) \
+ ( (char *)(array) + READ_LE_UINT16((idx) * 2 + (char *)(array)) )
+
+///////////////// Game defs
+
+#define FONT_HEIGHT 9
+
+/*
+Glossary
+ room - a single game world's screen. referenced by 16-bit number 0xAALL, where AA - area# and LL - location#
+ area - geographic area - Mo, Chamaar, etc
+ location - coordinates of particular room in an area. usually in form of 0xXY, where X - map row, Y - map column
+ character - an unique character (human or dino.) Has their own voice/dialog lines
+ person - instance of a character. Usually tied to specific room, but some may travel with you
+ party - a group of characters that travel with you
+ object - inventory item
+ icon - clickable rectangle with some action tied to it
+ dialog - a set of of dialog lines for character. further divided by categories and each entry may have associated
+ condition to be validated
+ global - game-wide storage area. must be preserved when saving/loading
+ phase - current story progress. Incremented by 1 for minor events, by 0x10 for major advancements
+*/
+
+enum Phases {
+ phNewGame = 0
+};
+
+namespace Areas {
+enum Areas {
+ arMo = 1,
+ arTausCave,
+ arChamaar,
+ arUluru,
+ arKoto,
+ arTamara,
+ arCantura,
+ arShandovra,
+ arNarimsCave,
+ arEmbalmersCave,
+ arWhiteArch,
+ arMoorkusLair
+};
+}
+
+#define MKRM(a,l) (((a) << 8) | (l))
+
+enum OBJECT {
+ OBJ_0,
+ OBJ_1,
+ OBJ_2,
+ OBJ_3,
+ OBJ_4,
+ OBJ_PRISME, // 5
+ OBJ_6,
+ OBJ_7,
+ OBJ_OEUF, // 8
+ OBJ_9,
+ OBJ_10,
+ OBJ_CHAMPB, // 11
+ OBJ_CHAMPM, // 12
+ OBJ_COUTEAU, // 13
+ OBJ_NIDV, // 14
+ OBJ_NIDO, // 15
+ OBJ_OR, // 16
+ OBJ_17,
+ OBJ_18,
+ OBJ_SOLEIL, // 19
+ OBJ_CORNE, // 20
+ OBJ_21,
+ OBJ_22,
+ OBJ_23,
+ OBJ_24,
+ OBJ_25,
+ OBJ_26,
+ OBJ_27,
+ OBJ_28,
+ OBJ_29,
+ OBJ_30,
+ OBJ_31,
+ OBJ_32,
+ OBJ_33,
+ OBJ_34,
+ OBJ_35,
+ OBJ_36, // 36 is 1st plaque, 6 total
+ OBJ_37,
+ OBJ_PLAQUE, // 38
+ OBJ_39,
+ OBJ_40,
+ OBJ_41
+};
+
+namespace Objects {
+enum Objects {
+ obNone,
+ obWayStone,
+ obShell,
+ obTalisman,
+ obTooth,
+ obPrism, // 5
+ obFlute,
+ obApple,
+ obEgg, // 8
+ obRoot,
+ obUnused10,
+ obShroom, // 11
+ obBadShroom, // 12
+ obKnife, // 13
+ obNest, // 14
+ obFullNest, // 15
+ obGold, // 16
+ obMoonStone,
+ obBag,
+ obSunStone, // 19
+ obHorn, // 20
+ obSword,
+
+ obMaskOfDeath,
+ obMaskOfBonding,
+ obMaskOfBirth,
+
+ obEyeInTheStorm, // 25
+ obSkyHammer,
+ obFireInTheClouds,
+ obWithinAndWithout,
+ obEyeInTheCyclone,
+ obRiverThatWinds,
+
+ obTrumpet, // 31
+ obUnused32,
+ obDrum,
+ obUnused34,
+ obUnused35,
+ obRing,
+
+ obTablet1, // 37 is 1st plaque, 6 total
+ obTablet2,
+ obTablet3, // 39
+ obTablet4,
+ obTablet5,
+ obTablet6
+};
+}
+
+enum PERSO {
+ PER_KING = 0,
+ PER_DINA, // 0x12
+ PER_TAU, // 0x24
+ PER_MONK, // 0x36
+ PER_JABBER, // 0x48
+ PER_ELOI, // 0x5A
+ PER_MUNGO, // 0x6C
+ PER_EVE, // 0x7E
+ PER_SHAZIA, // 0x90
+ PER_MAMMI, // 0xA2
+ PER_MAMMI_1, // 0xB4
+ PER_MAMMI_2, // 0xC6
+ PER_MAMMI_3, // 0xD8
+ PER_MAMMI_4, // 0xEA
+ PER_MAMMI_5, // 0xFC
+ PER_MAMMI_6, // 0x10E
+ PER_BAMBOO, // 0x120
+ PER_KABUKA, // 0x132
+ PER_GUARDS, // 0x144
+ PER_UNKN_156, // 0x156
+ PER_FISHER, // 0x168
+ PER_MORKUS, // 0x17A
+ PER_UNKN_18C, // 0x18C
+ PER_UNKN_19E, // 0x19E
+ PER_UNKN_1B0, // 0x1B0
+ PER_UNKN_1C2, // 0x1C2
+ PER_UNKN_1D4, // 0x1D4
+ PER_UNKN_1E6, // 0x1E6
+ PER_UNKN_1F8, // 0x1F8
+ PER_UNKN_20A, // 0x20A
+ PER_UNKN_21C, // 0x21C
+ PER_UNKN_22E, // 0x22E
+ PER_UNKN_240, // 0x240
+ PER_UNKN_252, // 0x252
+ PER_UNKN_264, // 0x264
+ PER_UNKN_276, // 0x276
+ PER_UNKN_288, // 0x288
+ PER_UNKN_29A, // 0x29A
+ PER_UNKN_2AC, // 0x2AC
+ PER_UNKN_2BE, // 0x2BE
+ PER_UNKN_2D0, // 0x2D0
+ PER_UNKN_2E2, // 0x2E2
+ PER_UNKN_2F4, // 0x2F4
+ PER_UNKN_306, // 0x306
+ PER_UNKN_318, // 0x318
+ PER_UNKN_32A, // 0x32A
+ PER_UNKN_33C, // 0x33C
+ PER_UNKN_34E, // 0x34E
+ PER_UNKN_360, // 0x360
+ PER_UNKN_372, // 0x372
+ PER_UNKN_384, // 0x384
+ PER_UNKN_396, // 0x396
+ PER_UNKN_3A8, // 0x3A8
+ PER_UNKN_3BA, // 0x3BA
+ PER_UNKN_3CC, // 0x3CC
+ PER_UNKN_3DE, // 0x3DE
+ PER_UNKN_3F0, // 0x3F0
+ PER_UNKN_402 // 0x402
+};
+
+namespace PersonId {
+enum PersonId {
+ pidGregor = 0, // The King
+ pidDina, // Pink dino
+ pidTau, // Late grandpa
+ pidMonk, // Old wizard
+ pidJabber, // Executioner
+ pidEloi, // Evergreen ptero
+ pidMungo, // Dina's husband
+ pidEve, // Blonde girl
+ pidShazia, // Big boobs sis
+ pidLeadersBegin, // 9
+ pidChongOfChamaar = pidLeadersBegin, // Dogface
+ pidKommalaOfKoto, // Clones
+ pidUlanOfUlele, // Shaman
+ pidCabukaOfCantura, // Stone people
+ pidMarindaOfEmbalmers, // Gods
+ pidFuggOfTamara, // Boar-like
+ pidThugg, // Bodyguard
+ pidNarrator, // 16, Old Eloi, also BGM
+ pidNarrim, // Sea snake
+ pidMorkus, // Vicious tyran
+ pidDinosaur, // different species of friendly dino
+ pidEnemy // different species of enemy dino
+};
+}
+
+// person in room mask bits
+namespace PersonMask {
+enum PersonMask {
+ pmGregor = 1,
+ pmDina = 2,
+ pmTau = 4,
+ pmMonk = 8,
+ pmJabber = 0x10,
+ pmEloi = 0x20,
+ pmMungo = 0x40,
+ pmEve = 0x80,
+ pmShazia = 0x100,
+ pmLeader = 0x200, // valley tribe leader
+ pmThugg = 0x400,
+ pmQuest = 0x800, // special quest person
+ pmDino = 0x1000,
+ pmEnemy = 0x2000,
+ pmMorkus = 0x4000
+};
+}
+
+namespace PersonFlags {
+enum PersonFlags {
+ pfType0 = 0,
+ pftTyrann,
+ pfType2,
+ pfType3,
+ pfType4,
+ pfType5,
+ pfType6,
+ pfType7,
+ pfType8,
+ pftMosasaurus,
+ pftTriceraptor,
+ pftVelociraptor,
+ pfType12,
+ pfType13,
+ pfType14,
+ pfType15,
+ pfTypeMask = 0xF,
+ pf10 = 0x10,
+ pf20 = 0x20,
+ pfInParty = 0x40,
+ pf80 = 0x80
+};
+}
+
+#pragma pack(push, 1)
+struct perso_t {
+ uint16 _roomNum; // room this person currently in
+ uint16 _actionId; // TODO: checkme
+ uint16 _partyMask; // party bit mask
+ byte _id; // character
+ byte _flags; // flags and kind
+ byte _roomBankId;// index in kPersoRoomBankTable for specific room banks
+ byte _spriteBank; // sprite bank
+ uint16 _items; // inventory
+ uint16 _powers; // obj of power bitmask
+ byte _targetLoc; // For party member this is mini sprite index
+ byte _lastLoc; // For party member this is mini sprite x offset
+ byte _speed; // num ticks per step
+ byte _steps; // current ticks
+};
+
+class EdenGame;
+
+struct phase_t {
+ int16 _id;
+ void (EdenGame::*disp)();
+};
+
+namespace ObjectFlags {
+enum ObjectFlags {
+ ofFlag1 = 1,
+ ofInHands = 2 // Currently holding this object in hands
+};
+}
+
+#define MAX_OBJECTS 42
+struct object_t {
+ byte _id;
+ byte _flags;
+ int _locations; // index in kObjectLocations
+ uint16 _itemMask;
+ uint16 _powerMask; // object of power bitmask
+ int16 _count;
+};
+
+namespace DialogFlags {
+enum DialogFlags {
+ df20 = 0x20,
+ dfRepeatable = 0x40,
+ dfSpoken = 0x80
+};
+}
+
+namespace DialogType {
+enum DialogType {
+ dtTalk = 0,
+ dtDinoAction,
+ dtDinoItem,
+ dtItem,
+ dtEvent,
+ dtInspect,
+ dtHint
+};
+}
+
+struct Dialog {
+ char _flags; // 0-3 - action index, 4 - highest bit of contidion index, rest is DialogFlags
+ char _condNumLow; // condition index low bits
+ char _textCondHiMask; // 0-1 text index hi bits, 2-5 - perso mask num, 6-7 condition index hi bits
+ char _textNumLow; // text line index low bits
+};
+
+struct tape_t {
+ int16 _textNum;
+ perso_t *_perso;
+ int16 _party;
+ int16 _roomNum;
+ int16 _backgroundBankNum;
+ Dialog *_dialog;
+};
+
+struct Follower { // Characters on Mirror screen
+ char _id; // character
+ char _spriteNum; // sprite number
+ int16 sx;
+ int16 sy;
+ int16 ex;
+ int16 ey;
+ int16 _spriteBank;
+ int16 ff_C;
+ int16 ff_E;
+};
+
+struct Icon {
+ int16 sx;
+ int16 sy;
+ int16 ex;
+ int16 ey;
+ uint16 _cursorId; // & 0x8000 - inactive/hidden
+ uint32 _actionId;
+ uint32 _objectId;
+};
+
+struct Goto {
+ byte _areaNum; // target area
+ byte _curAreaNum; // current area
+ byte _enterVideoNum;
+ byte _travelTime; // time to skip while in travel
+ byte _arriveVideoNum;
+};
+
+namespace RoomFlags {
+enum RoomFlags {
+ rf01 = 1,
+ rf02 = 2,
+ rf04 = 4,
+ rf08 = 8,
+ rfPanable = 0x10,
+ rfHasCitadel = 0x20,
+ rf40 = 0x40,
+ rf80 = 0x80
+};
+}
+
+struct Room {
+ byte _id;
+ byte _exits[4]; //TODO: signed?
+ byte _flags;
+ uint16 _bank;
+ uint16 _party;
+ byte _level; // Citadel level
+ byte _video;
+ byte _location;
+ byte _backgroundBankNum; // bg/mirror image number (relative)
+};
+
+namespace AreaFlags {
+enum AreaFlags {
+ afFlag1 = 1,
+ afFlag2 = 2,
+ afFlag4 = 4,
+ afFlag8 = 8,
+ afGaveGold = 0x10,
+ afFlag20 = 0x20,
+
+ HasTriceraptors = 0x100,
+ HasVelociraptors = 0x200,
+ HasTyrann = 0x400,
+
+ TyrannSighted = 0x4000,
+ afFlag8000 = 0x8000
+};
+}
+
+namespace AreaType {
+enum AreaType {
+ atCitadel = 1,
+ atValley = 2,
+ atCave = 3
+};
+}
+
+struct Area {
+ byte _num;
+ byte _type;
+ uint16 _flags;
+ uint16 _firstRoomIdx;
+ byte _citadelLevel;
+ byte _placeNum;
+ Room *_citadelRoomPtr;
+ int16 _visitCount;
+};
+
+namespace ValleyNews {
+enum ValleyNews {
+ vnAreaMask = 0xF,
+
+ vnTriceraptorsIn = 0x10,
+ vnVelociraptorsIn = 0x20,
+ vnTyrannIn = 0x30,
+ vnTyrannLost = 0x40,
+ vnCitadelLost = 0x50,
+ vnVelociraptorsLost = 0x60,
+
+ vnFree = 0,
+ vnHidden = 0x80,
+ vnEnd = 0xFF
+};
+}
+
+namespace DisplayFlags {
+enum DisplayFlags {
+ dfFlag1 = 1,
+ dfFlag2 = 2,
+ dfMirror = 4,
+ dfPerson = 8,
+ dfFrescoes = 0x10,
+ dfPanable = 0x20,
+ dfFlag40 = 0x40,
+ dfFlag80 = 0x80
+};
+}
+
+namespace DrawFlags {
+enum DrawFlags {
+ drDrawInventory = 1,
+ drDrawFlag2 = 2,
+ drDrawTopScreen = 4,
+ drDrawFlag8 = 8,
+ drDrawMenu = 0x10,
+ drDrawFlag20 = 0x20
+};
+}
+
+namespace MenuFlags {
+enum MenuFlags {
+ mfFlag1 = 1,
+ mfFlag2 = 2,
+ mfFlag4 = 4,
+ mfFlag8 = 8,
+ mfFlag10 = 0x10
+};
+}
+
+namespace MusicType {
+enum MusicType { //TODO: same as DialogType?
+ mtDontChange = 0,
+ mtNormal = 1,
+ mt2 = 2,
+ mtEvent = 4,
+ mtFF = 0xFF
+};
+}
+
+namespace EventType {
+enum EventType {
+ etEvent1 = 1,
+ etEvent2 = 2,
+ etEvent3 = 3,
+ etEvent4 = 4,
+ etEvent5 = 5,
+ etEvent6 = 6,
+ etEvent7 = 7,
+ etEvent8 = 8,
+ etEvent9 = 9,
+ etEventB = 11,
+ etEventC = 12,
+ etEventD = 13,
+ etEventE = 14,
+ etEventF = 15,
+ etEvent10 = 16,
+ etEvent12 = 18,
+ etGotoArea = 0x80 // + area id
+};
+}
+
+namespace GameFlags {
+enum GameFlags {
+ gfNone = 0,
+ gfMummyOpened = 1,
+ gfFlag2 = 2,
+ gfFlag4 = 4,
+ gfFlag8 = 8,
+ gfFlag10 = 0x10,
+ gfFlag20 = 0x20,
+ gfFlag40 = 0x40,
+ gfFlag80 = 0x80,
+ gfFlag100 = 0x100,
+ gfFlag200 = 0x200,
+ gfFlag400 = 0x400,
+ gfPrismAndMonk = 0x800,
+ gfFlag1000 = 0x1000,
+ gfFlag2000 = 0x2000,
+ gfFlag4000 = 0x4000,
+ gfFlag8000 = 0x8000
+};
+}
+
+struct global_t {
+ byte _areaNum;
+ byte _areaVisitCount;
+ byte _menuItemIdLo;
+ byte _menuItemIdHi; //TODO: pad?
+ uint16 _randomNumber; //TODO: this is randomized in pc ver and used by some conds. always zero on mac
+ uint16 _gameTime;
+ uint16 _gameDays;
+ uint16 _chrono;
+ uint16 _eloiDepartureDay;
+ uint16 _roomNum; // current room number
+ uint16 _newRoomNum; // target room number selected on world map
+ uint16 _phaseNum;
+ uint16 _metPersonsMask1;
+ uint16 _party;
+ uint16 _partyOutside;
+ uint16 _metPersonsMask2;
+ uint16 _var1C; //TODO: write-only?
+ uint16 _phaseActionsCount;
+ uint16 _curAreaFlags;
+ uint16 _curItemsMask;
+ uint16 _curPowersMask;
+ uint16 _curPersoItems;
+ uint16 _curCharacterPowers;
+ uint16 _wonItemsMask;
+ uint16 _wonPowersMask;
+ uint16 _stepsToFindAppleFast;
+ uint16 _stepsToFindAppleNormal;
+ uint16 _roomPersoItems; //TODO: write-only?
+ uint16 _roomCharacterPowers; //TODO: write-only?
+ uint16 _gameFlags;
+ uint16 _curVideoNum;
+ uint16 _morkusSpyVideoNum1; //TODO: pad?
+ uint16 _morkusSpyVideoNum2; //TODO: pad?
+ uint16 _morkusSpyVideoNum3; //TODO: pad?
+ uint16 _morkusSpyVideoNum4; //TODO: pad?
+ byte _newMusicType;
+ byte _var43;
+ byte _videoSubtitleIndex;
+ byte _partyInstruments; // &1 - Bell for Monk, &2 - Drum for Thugg
+ byte _monkGotRing;
+ byte _chronoFlag;
+ byte _curRoomFlags;
+ byte _endGameFlag;
+ byte _lastInfo;
+ bool _autoDialog;
+ byte _worldTyranSighted;
+ byte _var4D;
+ byte _var4E;
+ byte _worldGaveGold;
+ byte _worldHasTriceraptors;
+ byte _worldHasVelociraptors;
+ byte _worldHasTyran;
+ byte _var53;
+ byte _var54; //CHEKME: Used?
+ byte _var55; //TODO: pad?
+ byte _gameHours;
+ byte _textToken1;
+ byte _textToken2; //TODO: pad?
+ byte _eloiHaveNews;
+ byte _dialogFlags;
+ byte _curAreaType;
+ byte _curCitadelLevel;
+ byte _newLocation;
+ byte _prevLocation;
+ byte _curPersoFlags;
+ byte _var60;
+ byte _eventType;
+ byte _var62; //TODO: pad?
+ byte _curObjectId;
+ byte _curObjectFlags;
+ byte _var65; //TODO: pad?
+ byte _roomCharacterType;
+ byte _roomCharacterFlags;
+ byte _narratorSequence;
+ byte _var69;
+ byte _var6A;
+ byte _frescoNumber;
+ byte _var6C; //TODO: pad?
+ byte _var6D; //TODO: pad?
+ byte _labyrinthDirections;
+ byte _labyrinthRoom;
+ Dialog *_dialogPtr;
+ tape_t *_tapePtr;
+ Dialog *_nextDialogPtr;
+ Dialog *_narratorDialogPtr;
+ Dialog *_lastDialogPtr;
+ Icon *_nextRoomIcon;
+ byte *_sentenceBufferPtr;
+ Room *_roomPtr;
+ Area *_areaPtr;
+ Area *_lastAreaPtr;
+ Area *_curAreaPtr;
+ Room *_citaAreaFirstRoom;
+ perso_t *_characterPtr;
+ perso_t *_roomCharacterPtr;
+ byte _lastInfoIdx;
+ byte _nextInfoIdx;
+ byte *_persoSpritePtr;
+ byte *_persoSpritePtr2;
+ byte *_curCharacterAnimPtr;
+ byte *_varC2; //TODO: image desc arr
+ int16 _iconsIndex;
+ int16 _curObjectCursor; // TODO: useless?
+ int16 _varCA;
+ int16 _varCC; //TODO: unused/pad
+ int16 _characterImageBank; //TODO: unsigned?
+ uint16 _roomImgBank;
+ uint16 _characterBackgroundBankIdx;
+ uint16 _varD4; //TODO: unsigned?
+ uint16 _frescoeWidth;
+ uint16 _frescoeImgBank;
+ uint16 _varDA; //TODO: pad?
+ uint16 _varDC; //TODO: pad?
+ uint16 _roomBaseX;
+ uint16 _varE0; //TODO: pad?
+ uint16 _dialogType;
+ uint16 _varE4; //TODO: pad?
+ uint16 _currMusicNum;
+ int16 _textNum;
+ uint16 _travelTime;
+ uint16 _varEC; //TODO: pad?
+ byte _displayFlags;
+ byte _oldDisplayFlags;
+ byte _drawFlags;
+ byte _varF1;
+ byte _varF2;
+ byte _menuFlags;
+ byte _varF4; //TODO: write-only?
+ byte _varF5;
+ byte _varF6;
+ byte _varF7;
+ byte _varF8; //TODO: pad?
+ byte _varF9; //TODO: pad?
+ byte _varFA; //TODO: pad?
+ byte _animationFlags;
+ byte _giveObj1;
+ byte _giveObj2;
+ byte _giveObj3;
+ byte _var100;
+ byte _roomVidNum;
+ byte _mirrorEffect;
+ byte _var103;
+ byte _roomBackgroundBankNum;
+ byte _valleyVidNum;
+ byte _updatePaletteFlag;
+ byte _inventoryScrollPos;
+ byte _objCount;
+ byte _textBankIndex;
+ byte _prefLanguage;
+ byte _prefMusicVol[2];
+ byte _prefVoiceVol[2];
+ byte _prefSoundVolume[2];
+ byte _citadelAreaNum;
+ byte _var113;
+ byte _lastPlaceNum;
+ byte _saveEnd; // TODO: This has to be removed
+ int16 _textWidthLimit;
+ byte _numGiveObjs;
+ byte _var119; // unused
+};
+
+struct PakHeaderItem {
+ Common::String _name; //[16];
+ int32 _size;
+ int32 _offs;
+ char _flag;
+};
+
+class PakHeaderNode {
+public:
+ PakHeaderNode(int count);
+ ~PakHeaderNode();
+
+ uint16 _count;
+ PakHeaderItem* _files;
+};
+#pragma pack(pop)
+
+struct Citadel {
+ int16 _id;
+ int16 _bank[8];
+ int16 _video[8];
+};
+
+/////////////// vars
+
+extern Follower followerList[];
+
+
+/*
+ Labyrinth of Mo
+
+ | | | | | | | |
+
+*/
+
+enum {
+ LAB_N = 1,
+ LAB_E,
+ LAB_S,
+ LAB_W
+};
+
+extern byte kLabyrinthPath[];
+
+extern char kDinoSpeedForCitaLevel[16];
+
+extern char kTabletView[];
+
+// special character backgrounds for specific rooms
+extern char kPersoRoomBankTable[];
+
+// area transition descriptors
+extern Goto gotos[];
+extern object_t _objects[];
+extern uint16 kObjectLocations[100];
+extern perso_t kPersons[];
+extern Citadel _citadelList[];
+
+struct prect_t {
+ int16 left, top, right, bottom;
+};
+
+extern prect_t _characterRects[];
+extern byte _characterArray[][5];
+extern Area kAreasTable[];
+extern int16 tab_2CEF0[64];
+extern int16 tab_2CF70[64];
+extern int16 kActionCursors[299];
+
+struct CubeFace {
+ int tri;
+ char ff_4;
+ char ff_5;
+
+ byte *_texturePtr;
+ uint16 *_indices;
+ int16 *_uv;
+};
+
+struct Point3D {
+ int16 x;
+ int16 y;
+ int16 z;
+};
+
+struct Cube {
+ int _num;
+ CubeFace **_faces;
+ Point3D *_projection; // projected XYZ coords
+ Point3D *_vertices;
+};
+
+extern float _translationZ;
+extern float flt_2DF80;
+extern float flt_2DF84;
+
+struct XYZ {
+ signed short x, y, z;
+};
+
+struct CubeCursor {
+ uint8 _sides[6]; // spr idx for each side
+ uint8 _kind;
+ int8 _speed;
+};
+
+} // End of namespace Cryo
+
+#endif
diff --git a/engines/cryo/detection.cpp b/engines/cryo/detection.cpp
new file mode 100644
index 0000000000..2ae01f41dd
--- /dev/null
+++ b/engines/cryo/detection.cpp
@@ -0,0 +1,166 @@
+/* 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 "engines/advancedDetector.h"
+#include "common/file.h"
+
+#include "cryo/cryo.h"
+
+
+namespace Cryo {
+
+const char *CryoEngine::getGameId() const { return _gameDescription->gameId; }
+bool CryoEngine::isDemo() const { return _gameDescription->flags & ADGF_DEMO; }
+Common::Platform CryoEngine::getPlatform() const { return _gameDescription->platform; }
+
+}
+
+static const PlainGameDescriptor cryoGames[] = {
+ {"losteden", "Lost Eden"},
+ {0, 0}
+};
+
+namespace Cryo {
+
+static const ADGameDescription gameDescriptions[] = {
+
+ // Lost Eden PC non-interactive demo version
+ // Probably not worth it
+ {
+ "losteden",
+ 0,
+ AD_ENTRY1s("EDEN6.HSQ", 0, 17093),
+ Common::EN_ANY,
+ Common::kPlatformDOS,
+ ADGF_DEMO,
+ GUIO1(GUIO_NONE)
+ },
+
+ // Lost Eden PC interactive demo version
+ {
+ "losteden",
+ 0,
+ AD_ENTRY1s("EDEN.DAT", 0, 205473728),
+ Common::EN_ANY,
+ Common::kPlatformDOS,
+ ADGF_DEMO,
+ GUIO1(GUIO_NONE)
+ },
+
+ // Lost Eden PC version
+ {
+ "losteden",
+ 0,
+ AD_ENTRY1s("EDEN.DAT", 0, 449853776),
+ Common::EN_ANY,
+ Common::kPlatformDOS,
+ ADGF_UNSTABLE,
+ GUIO1(GUIO_NONE)
+ },
+
+ // Lost Eden EN PC version
+ // Added by Strangerke
+ {
+ "losteden",
+ 0,
+ AD_ENTRY1s("EDEN.DAT", "2126f14fe38b47c7a132f7937c79a2f0", 451205552),
+ Common::EN_ANY,
+ Common::kPlatformDOS,
+ ADGF_UNSTABLE,
+ GUIO1(GUIO_NONE)
+ },
+
+ // Lost Eden FR PC version
+ // Added by Strangerke
+ {
+ "losteden",
+ 0,
+ AD_ENTRY1s("EDEN.DAT", "378b1260ac400ecf35f8843357adcca6", 448040496),
+ Common::FR_FRA,
+ Common::kPlatformDOS,
+ ADGF_UNSTABLE,
+ GUIO1(GUIO_NONE)
+ },
+
+ // Lost Eden DE PC version
+ {
+ "losteden",
+ 0,
+ AD_ENTRY1s("EDEN.DAT", 0, 457719104),
+ Common::DE_DEU,
+ Common::kPlatformDOS,
+ ADGF_UNSTABLE,
+ GUIO1(GUIO_NONE)
+ },
+
+ // Lost Eden Mac version
+ {
+ "losteden",
+ 0,
+ AD_ENTRY1s("EDEN.DAT", 0, 489739536),
+ Common::EN_ANY,
+ Common::kPlatformMacintosh,
+ ADGF_UNSTABLE,
+ GUIO1(GUIO_NONE)
+ },
+
+ AD_TABLE_END_MARKER
+};
+
+} // End of namespace Cryo
+
+class CryoMetaEngine : public AdvancedMetaEngine {
+public:
+ CryoMetaEngine() : AdvancedMetaEngine(Cryo::gameDescriptions, sizeof(ADGameDescription), cryoGames) {
+ _singleId = "losteden";
+ }
+
+ virtual const char *getName() const {
+ return "Cryo Engine";
+ }
+
+ virtual const char *getOriginalCopyright() const {
+ return "Cryo Engine (C) Cryo Interactive";
+ }
+
+ virtual bool hasFeature(MetaEngineFeature f) const;
+ virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
+};
+
+bool CryoMetaEngine::hasFeature(MetaEngineFeature f) const {
+ return false;
+}
+
+bool CryoMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
+ if (desc) {
+ *engine = new Cryo::CryoEngine(syst, desc);
+ }
+ return desc != 0;
+}
+
+#if PLUGIN_ENABLED_DYNAMIC(CRYO)
+REGISTER_PLUGIN_DYNAMIC(CRYO, PLUGIN_TYPE_ENGINE, CryoMetaEngine);
+#else
+REGISTER_PLUGIN_STATIC(CRYO, PLUGIN_TYPE_ENGINE, CryoMetaEngine);
+#endif
diff --git a/engines/cryo/eden.cpp b/engines/cryo/eden.cpp
new file mode 100644
index 0000000000..08509e4c11
--- /dev/null
+++ b/engines/cryo/eden.cpp
@@ -0,0 +1,9364 @@
+/* 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/scummsys.h"
+
+#include "common/config-manager.h"
+#include "common/debug.h"
+#include "common/debug-channels.h"
+#include "common/error.h"
+#include "gui/EventRecorder.h"
+#include "common/file.h"
+#include "common/savefile.h"
+#include "common/fs.h"
+#include "common/system.h"
+#include "graphics/surface.h"
+#include "graphics/screen.h"
+#include "graphics/palette.h"
+#include "common/timer.h"
+
+//#include "audio/audiostream.h"
+#include "audio/mixer.h"
+
+#include "cryo/defs.h"
+#include "cryo/cryo.h"
+#include "cryo/platdefs.h"
+#include "cryo/cryolib.h"
+#include "cryo/eden.h"
+#include "cryo/sound.h"
+
+namespace Cryo {
+
+int16 _torchTick = 0;
+int16 _glowIndex = 0;
+int16 _torchCurIndex = 0;
+
+bool _allowDoubled = true;
+int _cursCenter = 11;
+
+EdenGame::EdenGame(CryoEngine *vm) : _vm(vm), kMaxMusicSize(2200000) {
+ static uint8 statTab2CB1E[8][4] = {
+ { 0x10, 0x81, 1, 0x90},
+ { 0x90, 1, 0x81, 0x10},
+ { 1, 0x90, 0x10, 0x81},
+ { 1, 0x10, 0x90, 0x81},
+ { 1, 0x90, 0x10, 0x81},
+ { 0x81, 0x10, 0x90, 1},
+ { 0x81, 0x10, 0x90, 1},
+ { 0x81, 0x90, 1, 0x10}
+ };
+
+ _adamMapMarkPos = Common::Point(-1, -1);
+
+ _scrollPos = _oldScrollPos = 0;
+ _frescoTalk = false;
+ _torchCursor = false;
+ _curBankNum = 0;
+ _glowH = _glowW = _glowY = _glowX = 0;
+ _paletteUpdateRequired = false;
+ _cursorSaved = false;
+ _showBlackBars = false;
+ _backgroundSaved = false;
+ _bankData = nullptr;
+ _tyranPtr = nullptr;
+ _lastAnimFrameNumb = _curAnimFrameNumb = 0;
+ _lastAnimTicks = 0;
+ _curCharacterRect = nullptr;
+ _numAnimFrames = _maxPersoDesc = _numImgDesc = 0;
+ _restartAnimation = _animationActive = false;
+ _animationDelay = _animationIndex = _lastAnimationIndex = 0;
+ dword_30724 = dword_30728 = _mouthAnimations = _animationTable = nullptr;
+ _characterBankData = nullptr;
+ _savedUnderSubtitles = false;
+ _numTextLines = 0;
+ _textOutPtr = textout = nullptr;
+ _curSpecialObject = nullptr;
+ _lastDialogChoice = false;
+ parlemoiNormalFlag = false;
+ _closeCharacterDialog = false;
+ dword_30B04 = 0;
+ _lastPhrasesFile = 0;
+ _dialogSkipFlags = 0;
+ _voiceSamplesBuffer = nullptr;
+ _needToFade = false;
+ _mainBankBuf = nullptr;
+ _musicBuf = nullptr;
+ _gameLipsync = nullptr;
+ _gamePhrases = nullptr;
+ _gameDialogs = nullptr;
+ _gameConditions = nullptr;
+ _placeRawBuf = nullptr;
+ _bankDataBuf = nullptr;
+ _gameIcons = nullptr;
+ _gameRooms = nullptr;
+ _glowBuffer = nullptr;
+ _gameFont = nullptr;
+ _globals = nullptr;
+ _mouseCenterY = _mouseCenterX = 0;
+ _bufferAllocationErrorFl = _quitFlag2 = _quitFlag3 = false;
+ _gameStarted = false;
+ _soundAllocated = false;
+ _musicChannel = _voiceChannel = nullptr;
+ _hnmSoundChannel = nullptr;
+ _voiceSound = nullptr;
+ _view2 = _underSubtitlesView = _subtitlesView = _underBarsView = _mainView = _hnmView = nullptr;
+ _cirsorPanX = 0;
+ _inventoryScrollDelay = 0;
+ _cursorPosY = _cursorPosX = 0;
+ _currCursor = 0;
+ _currSpot = _curSpot2 = nullptr;
+ _keyboardHeld = false;
+ _mouseHeld = false;
+ _normalCursor = false;
+ _showVideoSubtitle = false;
+ _specialTextMode = false;
+ _voiceSamplesSize = 0;
+ _animateTalking = false;
+ _personTalking = false;
+ _musicFadeFlag = 0;
+ _musicPlayingFlag = false;
+ _musicSamplesPtr = _musicPatternsPtr = _musSequencePtr = nullptr;
+ _musicEnabledFlag = false;
+ _currentObjectLocation = nullptr;
+ byte_31D64 = false;
+ _noPalette = false;
+ _gameLoaded = false;
+ memset(_tapes, 0, sizeof(_tapes));
+ _confirmMode = 0;
+ _curSliderValuePtr = nullptr;
+ _lastMenuItemIdLo = 0;
+ _lastTapeRoomNum = 0;
+ _curSliderX = _curSliderY = 0;
+ _destinationRoom = 0;
+ word_31E7A = 0;
+ word_378CC = 0; //TODO: set by CLComputer_Init to 0
+ word_378CE = 0;
+
+ _rotationAngleY = _rotationAngleX = _rotationAngleZ = 0;
+ _translationY = _translationX = 0.0; //TODO: never changed, make consts?
+ _cursorOldTick = 0;
+
+ _invIconsBase = 19;
+// invIconsCount = (_vm->getPlatform() == Common::kPlatformMacintosh) ? 9 : 11;
+ _invIconsCount = 11;
+ _roomIconsBase = _invIconsBase + _invIconsCount;
+
+ _codePtr = nullptr;
+
+ for (int i = 0; i < 8; i++) {
+ for (int j = 0; j < 4; j++)
+ tab_2CB1E[i][j] = statTab2CB1E[i][j];
+ }
+}
+
+void EdenGame::removeConsole() {
+}
+
+void EdenGame::scroll() {
+ restoreFriezes();
+ _mainView->_normal._srcLeft = _scrollPos;
+ _mainView->_zoom._srcLeft = _scrollPos;
+}
+
+void EdenGame::resetScroll() {
+ _oldScrollPos = _scrollPos;
+ _scrollPos = 0;
+ restoreFriezes(); //TODO: inlined scroll() ?
+ _mainView->_normal._srcLeft = 0;
+ _mainView->_zoom._srcLeft = 0;
+}
+
+void EdenGame::scrollFrescoes() {
+ if (_cursorPosY > 16 && _cursorPosY < 176) {
+ if (_cursorPosX >= 0 && _cursorPosX < 32 && _scrollPos > 3)
+ _scrollPos -= 4;
+ else if (_cursorPosX > 288 && _cursorPosX < 320 && _scrollPos < _globals->_frescoeWidth)
+ _scrollPos += 4;
+ }
+ scroll();
+}
+
+// Original name: afffresques
+void EdenGame::displayFrescoes() {
+ useBank(_globals->_frescoeImgBank);
+ noclipax(0, 0, 16);
+ useBank(_globals->_frescoeImgBank + 1);
+ noclipax(0, 320, 16);
+ _paletteUpdateRequired = true;
+}
+
+void EdenGame::gametofresques() {
+ _frescoTalk = false;
+ rundcurs();
+ saveFriezes();
+ displayFrescoes();
+ _globals->_displayFlags = DisplayFlags::dfFrescoes;
+}
+
+// Original name: dofresques
+void EdenGame::doFrescoes() {
+ _cursorSaved = false;
+ _torchCursor = true;
+ _glowX = -1;
+ _glowY = -1;
+ _globals->_gameFlags |= GameFlags::gfFlag20;
+ _globals->_varD4 = 0;
+ _globals->_curObjectId = 0;
+ _globals->_iconsIndex = 13;
+ _globals->_autoDialog = false;
+ gametofresques();
+ _globals->_frescoNumber = 3;
+}
+
+// Original name: finfresques
+void EdenGame::actionEndFrescoes() {
+ _torchCursor = false;
+ _cursorSaved = true;
+ _globals->_displayFlags = DisplayFlags::dfFlag1;
+ resetScroll();
+ _globals->_var100 = 0xFF;
+ updateRoom(_globals->_roomNum);
+ if (_globals->_phaseNum == 114)
+ _globals->_narratorSequence = 1;
+ _globals->_eventType = EventType::etEvent8;
+ showEvents();
+}
+
+void EdenGame::scrollMirror() {
+ if (_cursorPosY > 16 && _cursorPosY < 165) {
+ if (_cursorPosX >= 0 && _cursorPosX < 16) {
+ if (_scrollPos > 3) {
+ _scrollPos--;
+ scroll();
+ }
+ } else if (_cursorPosX > 290 && _cursorPosX < 320) {
+ if (_scrollPos < 320) {
+ _scrollPos++;
+ scroll();
+ }
+ }
+ }
+}
+
+// Original name: scrollpano
+void EdenGame::scrollPanel() {
+ if (_cursorPosY > 16 && _cursorPosY < 165) {
+ if (_cursorPosX >= 0 && _cursorPosX < 16 && _scrollPos > 3)
+ _scrollPos--;
+ else if (_cursorPosX > 290 && _cursorPosX < 320 && _scrollPos < 320)
+ _scrollPos++;
+ }
+ scroll();
+}
+
+// Original name: affsuiveur
+void EdenGame::displayFollower(Follower *follower, int16 x, int16 y) {
+ useBank(follower->_spriteBank);
+ noclipax(follower->_spriteNum, x, y + 16);
+}
+
+// Original name: persoinmiroir
+void EdenGame::characterInMirror() {
+ Icon *icon1 = &_gameIcons[3];
+ Icon *icon = &_gameIcons[_roomIconsBase];
+ Follower *suiveur = followerList;
+ int16 num = 1;
+ for (int i = 0; i < 16; i++) {
+ if (_globals->_party & (1 << i))
+ num++;
+ }
+ icon += num;
+ icon->sx = -1;
+ icon--;
+ icon->sx = icon1->sx;
+ icon->sy = icon1->sy;
+ icon->ex = icon1->ex;
+ icon->ey = 170;
+ icon->_cursorId = icon1->_cursorId;
+ icon->_actionId = icon1->_actionId;
+ icon->_objectId = icon1->_objectId;
+ icon--;
+ displayFollower(suiveur, suiveur->sx, suiveur->sy);
+ for (; suiveur->_id != -1; suiveur++) {
+ perso_t *perso;
+ for (perso = kPersons; perso != &kPersons[PER_UNKN_156]; perso++) {
+ if (perso->_id != suiveur->_id)
+ continue;
+
+ if (perso->_flags & PersonFlags::pf80)
+ continue;
+
+ if ((perso->_flags & PersonFlags::pfInParty) == 0)
+ continue;
+
+ if (perso->_roomNum != _globals->_roomNum)
+ continue;
+
+ icon->sx = suiveur->sx;
+ icon->sy = suiveur->sy;
+ icon->ex = suiveur->ex;
+ icon->ey = suiveur->ey;
+ icon->_cursorId = 8;
+ icon->_actionId = perso->_actionId;
+ icon--;
+ displayFollower(suiveur, suiveur->sx, suiveur->sy);
+ break;
+ }
+ }
+}
+
+// Original name: gametomiroir
+void EdenGame::gameToMirror(byte arg1) {
+ if (_globals->_displayFlags != DisplayFlags::dfFlag2) {
+ rundcurs();
+ restoreFriezes();
+ drawTopScreen();
+ showObjects();
+ saveFriezes();
+ }
+ int16 bank = _globals->_roomBackgroundBankNum;
+ uint16 resNum = bank + 326;
+ if ((_vm->getPlatform() == Common::kPlatformMacintosh) && (bank == 76 || bank == 128))
+ resNum = 2487; // PCIMG.HSQ
+
+ useBank(resNum);
+ noclipax(0, 0, 16);
+ useBank(resNum + 1);
+ noclipax(0, 320, 16);
+ characterInMirror();
+ _paletteUpdateRequired = true;
+ _globals->_iconsIndex = 16;
+ _globals->_autoDialog = false;
+ _globals->_displayFlags = DisplayFlags::dfMirror;
+ _globals->_mirrorEffect = arg1;
+}
+
+void EdenGame::flipMode() {
+ if (_personTalking) {
+ endCharacterSpeech();
+ if (_globals->_displayFlags == DisplayFlags::dfPerson) {
+ if (_globals->_characterPtr == &kPersons[PER_TAU] && _globals->_phaseNum >= 80)
+ displaySubtitles();
+ else {
+ getDataSync();
+ loadCurrCharacter();
+ addanim();
+ _restartAnimation = true;
+ animCharacter();
+ }
+ } else
+ displaySubtitles();
+ persovox();
+ } else {
+ if (_globals->_displayFlags != DisplayFlags::dfFrescoes && _globals->_displayFlags != DisplayFlags::dfFlag2) {
+ closeRoom();
+ if (_globals->_displayFlags & DisplayFlags::dfFlag1)
+ gameToMirror(1);
+ else {
+ quitMirror();
+ updateRoom(_globals->_roomNum);
+ if (byte_31D64) {
+ dialautoon();
+ parle_moi();
+ byte_31D64 = false;
+ }
+ }
+ }
+ }
+}
+
+// Original name: quitmiroir
+void EdenGame::quitMirror() {
+ rundcurs();
+ display();
+ resetScroll();
+ saveFriezes();
+ _globals->_displayFlags = DisplayFlags::dfFlag1;
+ _globals->_var100 = 0xFF;
+ _globals->_eventType = EventType::etEventC;
+ _globals->_mirrorEffect = 1;
+}
+
+void EdenGame::clictimbre() {
+ flipMode();
+}
+
+// Original name: clicplanval
+void EdenGame::actionClickValleyPlan() {
+ if ((_globals->_partyOutside & PersonMask::pmDina) && _globals->_phaseNum == 371) {
+ quitMirror();
+ updateRoom(_globals->_roomNum);
+ return;
+ }
+ if (_globals->_roomNum == 8 || _globals->_roomNum < 16)
+ return;
+
+ rundcurs();
+ display();
+ if (_globals->_displayFlags == DisplayFlags::dfMirror)
+ quitMirror();
+ deplaval((_globals->_roomNum & 0xFF00) | 1); //TODO: check me
+}
+
+// Original name: gotolieu
+void EdenGame::gotoPlace(Goto *go) {
+ _globals->_valleyVidNum = go->_arriveVideoNum;
+ _globals->_travelTime = go->_travelTime * 256;
+ _globals->_stepsToFindAppleFast = 0;
+ _globals->_eventType = EventType::etEvent2;
+ setChoiceYes();
+ showEvents();
+ if (!isAnswerYes())
+ return;
+
+ if (_globals->_var113) {
+ waitEndSpeak();
+ if (!_vm->shouldQuit())
+ closeCharacterScreen();
+ }
+ if (go->_enterVideoNum) {
+ hideBars();
+ playHNM(go->_enterVideoNum);
+ _needToFade = true;
+ }
+ initPlace(_globals->_newRoomNum);
+ specialoutside();
+ faire_suivre(_globals->_newRoomNum);
+ closeRoom();
+ _adamMapMarkPos.x = -1;
+ _adamMapMarkPos.y = -1;
+ addTime(_globals->_travelTime);
+ _globals->_var100 = _globals->_roomPtr->_id;
+ _globals->_roomNum = _globals->_newRoomNum;
+ _globals->_areaNum = _globals->_roomNum >> 8;
+ _globals->_eventType = EventType::etEvent5;
+ _globals->_newMusicType = MusicType::mt2;
+ setCharacterHere();
+ musique();
+ updateRoom1(_globals->_roomNum);
+ drawTopScreen();
+ _adamMapMarkPos.x = -1;
+ _adamMapMarkPos.y = -1;
+}
+
+void EdenGame::deplaval(uint16 roomNum) {
+ _globals->_newLocation = roomNum & 0xFF;
+ _globals->_valleyVidNum = 0;
+ _globals->_phaseActionsCount++;
+ closeRoom();
+ endCharacterSpeech();
+ byte c1 = roomNum & 0xFF;
+ if (c1 == 0)
+ return;
+
+ if (c1 < 0x80) {
+ _globals->_displayFlags = DisplayFlags::dfFlag1;
+ setChoiceYes();
+ _globals->_eventType = EventType::etEvent1;
+ showEvents();
+ if (!isAnswerYes())
+ return;
+
+ if (_globals->_var113) {
+ waitEndSpeak();
+ if (!_vm->shouldQuit())
+ closeCharacterScreen();
+ }
+ specialout();
+ if (_globals->_areaPtr->_type == AreaType::atValley) {
+ addTime(32);
+ _globals->_stepsToFindAppleFast++;
+ _globals->_stepsToFindAppleNormal++;
+ }
+ faire_suivre((roomNum & 0xFF00) | _globals->_newLocation);
+ _globals->_var100 = _globals->_roomPtr->_id;
+ _globals->_roomNum = roomNum;
+ _globals->_areaNum = roomNum >> 8;
+ _globals->_eventType = EventType::etEvent5;
+ setCharacterHere();
+ _globals->_newMusicType = MusicType::mtNormal;
+ musique();
+ updateRoom1(roomNum);
+ _globals->_chronoFlag = 0;
+ _globals->_chrono = 0;
+ _globals->_var54 = 0;
+ if (_globals->_roomCharacterType == PersonFlags::pftTyrann)
+ setChrono(3000);
+ return;
+ }
+ if (c1 == 0xFF) {
+ _globals->_eventType = EventType::etEventE;
+ showEvents();
+ if (!kPersons[PER_ELOI]._roomNum && checkEloiReturn())
+ setChrono(800);
+ return;
+ }
+ _globals->_stepsToFindAppleFast = 0;
+ byte newAreaNum = c1 & 0x7F;
+ byte curAreaNum = _globals->_roomNum >> 8;
+ int16 newRoomNum = newAreaNum << 8;
+ if (curAreaNum == Areas::arTausCave && newAreaNum == Areas::arMo)
+ newRoomNum |= 0x16;
+ else if (curAreaNum == Areas::arMoorkusLair)
+ newRoomNum |= 4;
+ else
+ newRoomNum |= 1;
+ _globals->_newRoomNum = newRoomNum;
+ if (newAreaNum == Areas::arTausCave)
+ gotoPlace(&gotos[0]);
+ else {
+ for (Goto *go = gotos + 1; go->_curAreaNum != 0xFF; go++) {
+ if (go->_curAreaNum == curAreaNum) {
+ gotoPlace(go);
+ break;
+ }
+ }
+ }
+}
+
+// Original name: deplacement
+void EdenGame::move(Direction dir) {
+ Room *room = _globals->_roomPtr;
+ int16 roomNum = _globals->_roomNum;
+ debug("move: from room %4X", roomNum);
+ char newLoc = 0;
+ rundcurs();
+ display();
+ _globals->_prevLocation = roomNum & 0xFF;
+ switch (dir) {
+ case kCryoNorth:
+ newLoc = room->_exits[0];
+ break;
+ case kCryoEast:
+ newLoc = room->_exits[1];
+ break;
+ case kCryoSouth:
+ newLoc = room->_exits[2];
+ break;
+ case kCryoWest:
+ newLoc = room->_exits[3];
+ break;
+ }
+ deplaval((roomNum & 0xFF00) | newLoc);
+}
+
+// Original name: deplacement2
+void EdenGame::move2(Direction dir) {
+ Room *room = _globals->_roomPtr;
+ int16 roomNum = _globals->_roomNum;
+ char newLoc = 0;
+ _globals->_prevLocation = roomNum & 0xFF;
+ switch (dir) {
+ case kCryoNorth:
+ newLoc = room->_exits[0];
+ break;
+ case kCryoEast:
+ newLoc = room->_exits[1];
+ break;
+ case kCryoSouth:
+ newLoc = room->_exits[2];
+ break;
+ case kCryoWest:
+ newLoc = room->_exits[3];
+ break;
+ }
+ deplaval((roomNum & 0xFF00) | newLoc);
+}
+
+// Original name: dinosoufle
+void EdenGame::actionDinoBlow() {
+ if (_globals->_curObjectId == 0) {
+ hideBars();
+ playHNM(148);
+ maj2();
+ }
+}
+
+// Original name: plaquemonk
+void EdenGame::actionPlateMonk() {
+ if (_globals->_curObjectId != 0) {
+ if (_globals->_curObjectId == Objects::obPrism) {
+ loseObject(Objects::obPrism);
+ hideBars();
+ _specialTextMode = true;
+ playHNM(89);
+ // CHECKME: Unused code
+ // word_2F514 |= 0x8000;
+ maj2();
+ _globals->_eventType = EventType::etEventB;
+ showEvents();
+ }
+ } else {
+ hideBars();
+ playHNM(7);
+ maj2();
+ _globals->_eventType = EventType::etEvent4;
+ showEvents();
+ }
+}
+
+// Original name: fresquesgraa
+void EdenGame::actionGraaFrescoe() {
+ if (_globals->_curObjectId == 0) {
+ _globals->_frescoeWidth = 320;
+ _globals->_frescoeImgBank = 113;
+ doFrescoes();
+ handleDinaDialog();
+ }
+}
+
+// Original name: fresqueslasc
+void EdenGame::actionLascFrescoe() {
+ if (_globals->_curObjectId == 0) {
+ _globals->_frescoeWidth = 112;
+ _globals->_frescoeImgBank = 315;
+ doFrescoes();
+ }
+}
+
+// Original name: pushpierre
+void EdenGame::actionPushStone() {
+ if (_globals->_curObjectId == 0) {
+ _gameRooms[22]._exits[0] = 17;
+ _gameRooms[26]._exits[2] = 9;
+ move(kCryoNorth);
+ }
+}
+
+// Original name: tetemomie
+void EdenGame::actionMummyHead() {
+ if (_globals->_curObjectId == Objects::obTooth) {
+ _globals->_gameFlags |= GameFlags::gfMummyOpened;
+ move(kCryoNorth);
+ } else if (_globals->_curObjectId == 0) {
+ if (_globals->_gameFlags & GameFlags::gfMummyOpened)
+ move(kCryoNorth);
+ else {
+ _globals->_eventType = EventType::etEvent6;
+ handleCharacterDialog(PersonId::pidMonk);
+ _globals->_eventType = 0;
+ }
+ }
+}
+
+// Original name: tetesquel
+void EdenGame::actionSkelettonHead() {
+ if (_globals->_curObjectId == Objects::obTooth) {
+ _gameRooms[22]._exits[0] = 16;
+ _gameRooms[26]._exits[2] = 13;
+ _gameIcons[16]._cursorId |= 0x8000;
+ loseObject(Objects::obTooth);
+ move(kCryoNorth);
+ }
+}
+
+// Original name: squelmoorkong
+void EdenGame::actionSkelettonMoorkong() {
+ _globals->_eventType = EventType::etEvent9;
+ showEvents();
+}
+
+// Original name: choisir
+void EdenGame::actionChoose() {
+ byte objid = _curSpot2->_objectId;
+ byte obj;
+ switch (objid) {
+ case 0:
+ obj = _globals->_giveObj1;
+ break;
+ case 1:
+ obj = _globals->_giveObj2;
+ break;
+ case 2:
+ obj = _globals->_giveObj3;
+ break;
+ default:
+ warning("Unexpected objid in actionChoose()");
+ return;
+ }
+ objectmain(obj);
+ winObject(obj);
+ _globals->_iconsIndex = 16;
+ _globals->_autoDialog = false;
+ _globals->_var60 = 0;
+ parle_moi();
+}
+
+// Original name: dinaparle
+void EdenGame::handleDinaDialog() {
+ perso_t *perso = &kPersons[PER_DINA];
+ if (perso->_partyMask & (_globals->_party | _globals->_partyOutside)) {
+ if (_globals->_frescoNumber < 3)
+ _globals->_frescoNumber = 3;
+ _globals->_frescoNumber++;
+ if (_globals->_frescoNumber < 15) {
+ endCharacterSpeech();
+ if (_globals->_frescoNumber == 7 && _globals->_phaseNum == 113)
+ incPhase();
+ _globals->_characterPtr = perso;
+ _globals->_dialogType = DialogType::dtInspect;
+ int16 num = (perso->_id << 3) | DialogType::dtInspect; //TODO: combine
+ bool res = dialoscansvmas((Dialog *)getElem(_gameDialogs, num));
+ _frescoTalk = false;
+ if (res) {
+ restoreUnderSubtitles();
+ _frescoTalk = true;
+ persovox();
+ }
+ _globals->_varCA = 0;
+ _globals->_dialogType = DialogType::dtTalk;
+ } else
+ actionEndFrescoes();
+ }
+}
+
+// Original name: roiparle
+void EdenGame::handleKingDialog() {
+ if (_globals->_phaseNum <= 400)
+ handleCharacterDialog(0);
+}
+
+// Original name: roiparle1
+void EdenGame::actionKingDialog1() {
+ if (_globals->_curObjectId == Objects::obSword) {
+ _globals->_gameFlags |= GameFlags::gfFlag80;
+ hideBars();
+ playHNM(76);
+ move2(kCryoNorth);
+ } else {
+ _globals->_frescoNumber = 1;
+ handleKingDialog();
+ }
+}
+
+// Original name: roiparle2
+void EdenGame::actionKingDialog2() {
+ _globals->_frescoNumber = 2;
+ handleKingDialog();
+}
+
+// Original name: roiparle3
+void EdenGame::actionKingDialog3() {
+ _globals->_frescoNumber = 3;
+ handleKingDialog();
+}
+
+// Original name: getcouteau
+void EdenGame::actionGetKnife() {
+ if (_globals->_phaseNum >= 80) {
+ _gameRooms[113]._video = 0;
+ getObject(Objects::obKnife);
+ }
+ _globals->_eventType = EventType::etEvent7;
+ showEvents();
+}
+
+// Original name: getprisme
+void EdenGame::actionGetPrism() {
+ getObject(Objects::obPrism);
+ _globals->_eventType = EventType::etEvent7;
+ showEvents();
+}
+
+// Original name: getchampb
+void EdenGame::actionGetMushroom() {
+ getObject(Objects::obShroom);
+}
+
+// Original name: getchampm
+void EdenGame::actionGetBadMushroom() {
+ getObject(Objects::obBadShroom);
+}
+
+// Original name: getor
+void EdenGame::actionGetGold() {
+ getObject(Objects::obGold);
+}
+
+// Original name: getnido
+void EdenGame::actionGetFullNest() {
+ if (_globals->_curObjectId != 0)
+ return;
+ _globals->_roomPtr->_bank = 282; //TODO: fix me
+ _globals->_roomPtr--;
+ _globals->_roomPtr->_bank = 281; //TODO: fix me
+ _globals->_roomPtr->_id = 3;
+ getObject(Objects::obFullNest);
+}
+
+// Original name: getnidv
+void EdenGame::actionGetEmptyNest() {
+ if (_globals->_curObjectId != 0)
+ return;
+ _globals->_roomPtr->_bank = 282; //TODO: fix me
+ _globals->_roomPtr--;
+ _globals->_roomPtr->_bank = 281; //TODO: fix me
+ _globals->_roomPtr->_id = 3;
+ getObject(Objects::obNest);
+}
+
+// Original name: getcorne
+void EdenGame::actionGetHorn() {
+ if (_globals->_curObjectId != 0)
+ return;
+ getObject(Objects::obHorn);
+ _globals->_eventType = EventType::etEvent7;
+ showEvents();
+ bigphase1();
+ setCharacterHere();
+ _globals->_roomPtr = getRoom(_globals->_roomNum);
+}
+
+// Original name: getsoleil
+void EdenGame::actionGetSunStone() {
+ if (_globals->_curObjectId != 0)
+ return;
+ _gameRooms[238]._video = 0;
+ _gameRooms[238]._flags = RoomFlags::rf80;
+ getObject(Objects::obSunStone);
+}
+
+// Original name: getoueuf
+void EdenGame::actionGetEgg() {
+ if (_globals->_curObjectId != 0)
+ return;
+ _globals->_roomPtr->_flags = 0;
+ _globals->_roomPtr->_video = 0;
+ getObject(Objects::obEgg);
+}
+
+// Original name: getplaque
+void EdenGame::actionGetTablet() {
+ if (_globals->_curObjectId != 0 && _globals->_curObjectId < Objects::obTablet1)
+ return;
+ _globals->_curObjectId = 0;
+ getObject(Objects::obTablet2);
+ putObject();
+ for (int i = 0; i < 6; i++)
+ _objects[Objects::obTablet1 - 1 + i]._count = 0;
+ _globals->_curObjectFlags = 0;
+ _globals->_inventoryScrollPos = 0;
+ _globals->_curObjectCursor = 9;
+ _gameIcons[16]._cursorId |= 0x8000;
+ showObjects();
+ _gameRooms[131]._video = 0;
+ hideBars();
+ playHNM(149);
+ _globals->_varF1 = RoomFlags::rf04;
+ _globals->_drawFlags = DrawFlags::drDrawFlag20;
+ _normalCursor = true;
+ maj2();
+}
+
+// Original name: voirlac
+void EdenGame::actionLookLake() {
+ perso_t *perso = &kPersons[PER_MORKUS];
+ Room *room = _globals->_roomPtr;
+ Area *area = _globals->_areaPtr;
+ int16 vid = _globals->_curObjectId == Objects::obApple ? 81 : 54;
+ for (++perso; perso->_roomNum != 0xFFFF; perso++) {
+ if (perso->_roomNum != _globals->_roomNum)
+ continue;
+ vid++;
+ if (_globals->_curObjectId != Objects::obApple)
+ continue; //TODO: pc breaks here
+ if ((perso->_flags & PersonFlags::pfTypeMask) != PersonFlags::pftMosasaurus)
+ continue;
+ if (!(perso->_flags & PersonFlags::pf80))
+ return;
+ perso->_flags &= ~PersonFlags::pf80; //TODO: useless? see above
+ area->_flags |= AreaFlags::afFlag8;
+ _globals->_curAreaFlags |= AreaFlags::afFlag8;
+ room->_id = 3;
+ }
+ debug("sea monster: room = %X, d0 = %X\n", _globals->_roomNum, _globals->_roomImgBank);
+ hideBars();
+ playHNM(vid);
+ updateRoom(_globals->_roomNum); //TODO: getting memory trashed here?
+ if (_globals->_curObjectId == Objects::obApple)
+ loseObject(Objects::obApple);
+ _globals->_eventType = EventType::etEventF;
+ showEvents();
+}
+
+// Original name: gotohall
+void EdenGame::actionGotoHall() {
+ _globals->_prevLocation = _globals->_roomNum & 0xFF;
+ deplaval((_globals->_roomNum & 0xFF00) | 6);
+}
+
+// Original name: demitourlabi
+void EdenGame::actionLabyrinthTurnAround() {
+ _globals->_prevLocation = _globals->_roomNum & 0xFF;
+ _globals->_var100 = 0xFF;
+ uint16 target = (_globals->_roomNum & 0xFF00) | _globals->_roomPtr->_exits[2];
+ faire_suivre(target);
+ _globals->_roomNum = target;
+ _globals->_eventType = EventType::etEvent5;
+ updateRoom(_globals->_roomNum);
+}
+
+// Original name: gotonido
+void EdenGame::actionGotoFullNest() {
+ _globals->_roomPtr++;
+ _globals->_eventType = 0;
+ _globals->_roomImgBank = _globals->_roomPtr->_bank;
+ _globals->_roomVidNum = _globals->_roomPtr->_video;
+ _globals->_curRoomFlags = _globals->_roomPtr->_flags;
+ _globals->_varF1 = _globals->_roomPtr->_flags;
+ animpiece();
+ _globals->_var100 = 0;
+ maj2();
+}
+
+// Original name: gotoval
+void EdenGame::actionGotoVal() {
+ uint16 target = _globals->_roomNum;
+ rundcurs();
+ display();
+ _scrollPos = 0;
+ char obj = _curSpot2->_objectId - 14; //TODO
+ _globals->_prevLocation = target & 0xFF;
+ deplaval((target & 0xFF00) | obj);
+}
+
+// Original name: visiter
+void EdenGame::actionVisit() {
+ hideBars();
+ playHNM(144);
+ _globals->_varF1 = RoomFlags::rf04;
+ maj2();
+}
+
+// Original name: final
+void EdenGame::actionFinal() {
+ if (_globals->_curObjectId != 0)
+ return;
+
+ hideBars();
+ *(int16 *)(_gameRooms + 0x6DC) = 319; //TODO
+ _globals->_roomImgBank = 319;
+ playHNM(97);
+ maj2();
+ _globals->_eventType = EventType::etEvent12;
+ showEvents();
+ _globals->_narratorSequence = 54;
+}
+
+// Original name: goto_nord
+void EdenGame::actionMoveNorth() {
+ if (_globals->_curObjectId == 0)
+ move(kCryoNorth);
+}
+
+// Original name: goto_est
+void EdenGame::actionMoveEast() {
+ if (_globals->_curObjectId == 0)
+ move(kCryoEast);
+}
+
+// Original name: goto_sud
+void EdenGame::actionMoveSouth() {
+ if (_globals->_curObjectId == 0)
+ move(kCryoSouth);
+}
+
+// Original name: goto_ouest
+void EdenGame::actionMoveWest() {
+ if (_globals->_curObjectId == 0)
+ move(kCryoWest);
+}
+
+// Original name: afficher
+void EdenGame::display() {
+ if (!_globals->_mirrorEffect && !_globals->_var103) {
+ if (_paletteUpdateRequired) {
+ _paletteUpdateRequired = false;
+ CLPalette_Send2Screen(_globalPalette, 0, 256);
+ }
+ CLBlitter_CopyView2Screen(_mainView);
+ } else {
+ if (_globals->_mirrorEffect)
+ displayEffect3();
+ else
+ displayEffect2();
+
+ _globals->_var103 = 0;
+ _globals->_mirrorEffect = 0;
+ }
+}
+
+void EdenGame::afficher128() {
+ if (_globals->_updatePaletteFlag == 16) {
+ CLPalette_Send2Screen(_globalPalette, 0, 129);
+ CLBlitter_CopyView2Screen(_mainView);
+ _globals->_updatePaletteFlag = 0;
+ } else {
+ clearScreen();
+ fadeToBlackLowPalette(1);
+ if (_showBlackBars)
+ drawBlackBars();
+ CLBlitter_CopyView2Screen(_mainView);
+ fadeFromBlackLowPalette(1);
+ }
+}
+
+// Original name: sauvefrises
+void EdenGame::saveFriezes() {
+ saveTopFrieze(0);
+ saveBottomFrieze();
+}
+
+// Original name: sauvefriseshaut
+void EdenGame::saveTopFrieze(int16 x) { // Save top bar
+ _underTopBarScreenRect = Common::Rect(x, 0, x + 320 - 1, 15);
+ _underTopBarBackupRect = Common::Rect(0, 0, 320 - 1, 15);
+ CLBlitter_CopyViewRect(_mainView, _underBarsView, &_underTopBarScreenRect, &_underTopBarBackupRect);
+}
+
+// Original name: sauvefrisesbas
+void EdenGame::saveBottomFrieze() { // Save bottom bar
+ _underBottomBarScreenRect.left = 0;
+ _underBottomBarScreenRect.right = 320 - 1;
+ CLBlitter_CopyViewRect(_mainView, _underBarsView, &_underBottomBarScreenRect, &_underBottomBarBackupRect);
+}
+
+// Original name: restaurefrises
+void EdenGame::restoreFriezes() {
+ restoreTopFrieze();
+ restoreBottomFrieze();
+}
+
+// Original name: restaurefriseshaut
+void EdenGame::restoreTopFrieze() {
+ _underTopBarScreenRect.left = _scrollPos;
+ _underTopBarScreenRect.right = _scrollPos + 320 - 1;
+ CLBlitter_CopyViewRect(_underBarsView, _mainView, &_underTopBarBackupRect, &_underTopBarScreenRect);
+}
+
+// Original name: restaurefrisesbas
+void EdenGame::restoreBottomFrieze() {
+ _underBottomBarScreenRect.left = _scrollPos;
+ _underBottomBarScreenRect.right = _scrollPos + 320 - 1;
+ CLBlitter_CopyViewRect(_underBarsView, _mainView, &_underBottomBarBackupRect, &_underBottomBarScreenRect);
+}
+
+void EdenGame::useMainBank() {
+ _bankData = _mainBankBuf;
+}
+
+void EdenGame::useCharacterBank() {
+ _bankData = _characterBankData;
+}
+
+// Original name: use_bank
+void EdenGame::useBank(int16 bank) {
+ if (bank > 2500)
+ error("attempt to load bad bank %d", bank);
+
+ _bankData = _bankDataBuf;
+ if (_curBankNum != bank) {
+ loadRawFile(bank, _bankDataBuf);
+ verifh(_bankDataBuf);
+ _curBankNum = bank;
+ }
+}
+
+void EdenGame::sundcurs(int16 x, int16 y) {
+ byte *keep = _cursKeepBuf;
+ x = CLIP<int16>(x - 4, 0, 640 - 48);
+ y = CLIP<int16>(y - 4, 0, 200 - 48);
+ _cursKeepPos = Common::Point(x, y);
+ byte *scr = _mainViewBuf + _cursKeepPos.x + _cursKeepPos.y * 640;
+ for (int16 h = 48; h--;) {
+ for (int16 w = 48; w--;)
+ *keep++ = *scr++;
+ scr += 640 - 48;
+ }
+ _cursorSaved = true;
+}
+
+void EdenGame::rundcurs() {
+ byte *keep = _cursKeepBuf;
+ byte *scr = _mainViewBuf + _cursKeepPos.x + _cursKeepPos.y * 640;
+ if (!_cursorSaved || (_cursKeepPos == Common::Point(-1, -1))) //TODO ...
+ return;
+
+ for (int16 h = 48; h--;) {
+ for (int16 w = 48; w--;)
+ *scr++ = *keep++;
+ scr += 640 - 48;
+ }
+
+}
+
+void EdenGame::noclipax(int16 index, int16 x, int16 y) {
+ byte *pix = _bankData;
+ byte *scr = _mainViewBuf + x + y * 640;
+ if (_curBankNum != 117 && !_noPalette) {
+ if (READ_LE_UINT16(pix) > 2)
+ readPalette(pix + 2);
+ }
+ pix += READ_LE_UINT16(pix);
+ pix += READ_LE_UINT16(pix + index * 2);
+ // int16 height:9
+ // int16 pad:6;
+ // int16 flag:1;
+ byte h0 = *pix++;
+ byte h1 = *pix++;
+ int16 w = ((h1 & 1) << 8) | h0;
+ int16 h = *pix++;
+ byte mode = *pix++;
+ debug("- draw sprite %d at %d:%d, %dx%d", index, x, y, w, h);
+ if (mode != 0xFF && mode != 0xFE)
+ return;
+ if (y + h > 200)
+ h -= (y + h - 200);
+ if (h1 & 0x80) {
+ // compressed
+ for (; h-- > 0;) {
+ for (int16 ww = w; ww > 0;) {
+ byte c = *pix++;
+ if (c >= 0x80) {
+ if (c == 0x80) {
+ byte fill = *pix++;
+ if (fill == 0) {
+ scr += 128 + 1;
+ ww -= 128 + 1;
+ } else {
+ byte run;
+ *scr++ = fill; //TODO: wha?
+ *scr++ = fill;
+ ww -= 128 + 1;
+ for (run = 127; run--;)
+ *scr++ = fill;
+ }
+ } else {
+ byte fill = *pix++;
+ byte run = 255 - c + 2;
+ ww -= run;
+ if (fill == 0)
+ scr += run;
+ else
+ for (; run--;)
+ *scr++ = fill;
+ }
+ } else {
+ byte run = c + 1;
+ ww -= run;
+ for (; run--;) {
+ byte p = *pix++;
+ if (p == 0)
+ scr++;
+ else
+ *scr++ = p;
+ }
+ }
+ }
+ scr += 640 - w;
+ }
+ } else {
+ // uncompressed
+ for (; h--;) {
+ for (int16 ww = w; ww--;) {
+ byte p = *pix++;
+ if (p == 0)
+ scr++;
+ else
+ *scr++ = p;
+ }
+ scr += 640 - w;
+ }
+ }
+}
+
+void EdenGame::noclipax_avecnoir(int16 index, int16 x, int16 y) {
+ byte *pix = _bankData;
+ byte *scr = _mainViewBuf + x + y * 640;
+ if (_curBankNum != 117) {
+ if (READ_LE_UINT16(pix) > 2)
+ readPalette(pix + 2);
+ }
+ pix += READ_LE_UINT16(pix);
+ pix += READ_LE_UINT16(pix + index * 2);
+ // int16 height:9
+ // int16 pad:6;
+ // int16 flag:1;
+ byte h0 = *pix++;
+ byte h1 = *pix++;
+ int16 w = ((h1 & 1) << 8) | h0;
+ int16 h = *pix++;
+ byte mode = *pix++;
+ if (mode != 0xFF && mode != 0xFE)
+ return;
+ if (y + h > 200)
+ h -= (y + h - 200);
+ if (h1 & 0x80) {
+ // compressed
+ for (; h-- > 0;) {
+ for (int16 ww = w; ww > 0;) {
+ byte c = *pix++;
+ if (c >= 0x80) {
+ if (c == 0x80) {
+ byte fill = *pix++;
+ byte run;
+ *scr++ = fill; //TODO: wha?
+ *scr++ = fill;
+ ww -= 128 + 1;
+ for (run = 127; run--;)
+ *scr++ = fill;
+ } else {
+ byte fill = *pix++;
+ byte run = 255 - c + 2;
+ ww -= run;
+ for (; run--;)
+ *scr++ = fill;
+ }
+ } else {
+ byte run = c + 1;
+ ww -= run;
+ for (; run--;) {
+ byte p = *pix++;
+ *scr++ = p;
+ }
+ }
+ }
+ scr += 640 - w;
+ }
+ } else {
+ // uncompressed
+ for (; h--;) {
+ for (int16 ww = w; ww--;) {
+ byte p = *pix++;
+ *scr++ = p;
+ }
+ scr += 640 - w;
+ }
+ }
+}
+
+void EdenGame::getglow(int16 x, int16 y, int16 w, int16 h) {
+ byte *scr = _mainViewBuf + x + y * 640;
+ byte *gl = _glowBuffer;
+ _glowX = x;
+ _glowY = y;
+ _glowW = w;
+ _glowH = h;
+ for (; h--;) {
+ for (int16 ww = w; ww--;)
+ *gl++ = *scr++;
+ scr += 640 - w;
+ }
+}
+
+void EdenGame::unglow() {
+ byte *gl = _glowBuffer;
+ byte *scr = _mainViewBuf + _glowX + _glowY * 640;
+ if (_glowX < 0 || _glowY < 0) //TODO: move it up
+ return;
+ for (; _glowH--;) {
+ for (int16 ww = _glowW; ww--;)
+ *scr++ = *gl++;
+ scr += 640 - _glowW;
+ }
+}
+
+void EdenGame::glow(int16 index) {
+ // byte pixbase;
+ byte *pix = _bankData;
+
+ index += 9;
+ pix += READ_LE_UINT16(pix);
+ pix += READ_LE_UINT16(pix + index * 2);
+ // int16 height:9
+ // int16 pad:6;
+ // int16 flag:1;
+ byte h0 = *pix++;
+ byte h1 = *pix++;
+ int16 w = ((h1 & 1) << 8) | h0;
+ int16 h = *pix++;
+ byte mode = *pix++;
+ if (mode != 0xFF && mode != 0xFE)
+ return;
+
+ int16 x = _cursorPosX + _scrollPos - 38;
+ int16 y = _cursorPosY - 28;
+ int16 ex = _globals->_frescoeWidth + 320;
+
+ if (x + w <= 0 || x >= ex || y + h <= 0 || y >= 176)
+ return;
+
+ int16 dx;
+ if (x < 0) {
+ dx = -x;
+ x = 0;
+ } else if (x + w > ex)
+ dx = x + w - ex;
+ else
+ dx = 0;
+
+ int16 dy = 0;
+ if (y < 16) {
+ dy = 16 - y;
+ y = 16;
+ } else if (y + h > 175)
+ dy = y + h - 175;
+
+ int16 pstride = dx;
+ int16 sstride = 640 - (w - dx);
+ if (y == 16)
+ pix += w * dy;
+ if (x == 0)
+ pix += dx;
+
+ byte *scr = _mainViewBuf + x + y * 640;
+
+ w -= dx;
+ h -= dy;
+
+ getglow(x, y, w, h);
+
+ for (; h--;) {
+ for (int16 ww = w; ww--;) {
+ byte p = *pix++;
+ if (p == 0)
+ scr++;
+ else
+ *scr++ += p << 4;
+ }
+ pix += pstride;
+ scr += sstride;
+ }
+}
+
+void EdenGame::readPalette(byte *ptr) {
+ bool doit = true;
+ color3_t pal_entry;
+ while (doit) {
+ uint16 idx = *ptr++;
+ if (idx != 0xFF) {
+ uint16 cnt = *ptr++;
+ while (cnt--) {
+ if (idx == 0) {
+ pal_entry.r = 0;
+ pal_entry.g = 0;
+ pal_entry.b = 0;
+ ptr += 3;
+ } else {
+ pal_entry.r = *ptr++ << 10;
+ pal_entry.g = *ptr++ << 10;
+ pal_entry.b = *ptr++ << 10;
+ }
+ CLPalette_SetRGBColor(_globalPalette, idx, &pal_entry);
+ idx++;
+ }
+ } else
+ doit = false;
+ }
+}
+
+// Original name: spritesurbulle
+void EdenGame::spriteOnSubtitle(int16 index, int16 x, int16 y) {
+ byte *pix = _bankData;
+ byte *scr = _subtitlesViewBuf + x + y * _subtitlesXWidth;
+ if ((_curBankNum != 117) && (READ_LE_UINT16(pix) > 2))
+ readPalette(pix + 2);
+
+ pix += READ_LE_UINT16(pix);
+ pix += READ_LE_UINT16(pix + index * 2);
+ // int16 height:9
+ // int16 pad:6;
+ // int16 flag:1;
+ byte h0 = *pix++;
+ byte h1 = *pix++;
+ int16 w = ((h1 & 1) << 8) | h0;
+ int16 h = *pix++;
+ byte mode = *pix++;
+ if (mode != 0xFF && mode != 0xFE)
+ return;
+ if (h1 & 0x80) {
+ // compressed
+ for (; h-- > 0;) {
+ for (int16 ww = w; ww > 0;) {
+ byte c = *pix++;
+ if (c >= 0x80) {
+ if (c == 0x80) {
+ byte fill = *pix++;
+ if (fill == 0) {
+ scr += 128 + 1;
+ ww -= 128 + 1;
+ } else {
+ byte run;
+ *scr++ = fill; //TODO: wha?
+ *scr++ = fill;
+ ww -= 128 + 1;
+ for (run = 127; run--;)
+ *scr++ = fill;
+ }
+ } else {
+ byte fill = *pix++;
+ byte run = 255 - c + 2;
+ ww -= run;
+ if (fill == 0)
+ scr += run;
+ else {
+ for (; run--;)
+ *scr++ = fill;
+ }
+ }
+ } else {
+ byte run = c + 1;
+ ww -= run;
+ for (; run--;) {
+ byte p = *pix++;
+ if (p == 0)
+ scr++;
+ else
+ *scr++ = p;
+ }
+ }
+ }
+ scr += _subtitlesXWidth - w;
+ }
+ } else {
+ // uncompressed
+ for (; h--;) {
+ for (int16 ww = w; ww--;) {
+ byte p = *pix++;
+ if (p == 0)
+ scr++;
+ else
+ *scr++ = p;
+ }
+ scr += _subtitlesXWidth - w;
+ }
+ }
+}
+
+// Original name: bars_out
+void EdenGame::hideBars() {
+ if (_showBlackBars)
+ return;
+
+ display();
+ _underTopBarScreenRect.left = _scrollPos;
+ _underTopBarScreenRect.right = _scrollPos + 320 - 1;
+ CLBlitter_CopyViewRect(_mainView, _underBarsView, &_underTopBarScreenRect, &_underTopBarBackupRect);
+ _underBottomBarScreenRect.left = _underTopBarScreenRect.left;
+ _underBottomBarScreenRect.right = _underTopBarScreenRect.right;
+ CLBlitter_CopyViewRect(_mainView, _underBarsView, &_underBottomBarScreenRect, &_underBottomBarBackupRect);
+ int16 r19 = 14; // TODO - init in decl?
+ int16 r20 = 176;
+ int16 r25 = 14;
+ int16 r24 = 21;
+ _underTopBarScreenRect.left = 0;
+ _underTopBarScreenRect.right = 320 - 1;
+ _underTopBarBackupRect.left = _scrollPos;
+ _underTopBarBackupRect.right = _scrollPos + 320 - 1;
+ unsigned int *scr40, *scr41, *scr42;
+ while (r24 > 0) {
+ if (r25 > 0) {
+ _underTopBarScreenRect.top = 16 - r25;
+ _underTopBarScreenRect.bottom = 16 - 1;
+ _underTopBarBackupRect.top = 0;
+ _underTopBarBackupRect.bottom = r25 - 1;
+ CLBlitter_CopyViewRect(_underBarsView, _mainView, &_underTopBarScreenRect, &_underTopBarBackupRect);
+ scr40 = ((unsigned int *)_mainViewBuf) + r19 * 640 / 4;
+ scr41 = scr40 + 640 / 4;
+ for (int i = 0; i < 320; i += 4) {
+ *scr40++ = 0;
+ *scr41++ = 0;
+ }
+ }
+ _underTopBarScreenRect.top = 16;
+ _underTopBarScreenRect.bottom = r24 + 16 - 1;
+ _underTopBarBackupRect.top = 200 - r24;
+ _underTopBarBackupRect.bottom = 200 - 1;
+ CLBlitter_CopyViewRect(_underBarsView, _mainView, &_underTopBarScreenRect, &_underTopBarBackupRect);
+ scr40 = ((unsigned int *)_mainViewBuf) + r20 * 640 / 4;
+ scr41 = scr40 + 640 / 4;
+ scr42 = scr41 + 640 / 4;
+ for (int i = 0; i < 320; i += 4) {
+ *scr40++ = 0;
+ *scr41++ = 0;
+ *scr42++ = 0;
+ }
+ r19 -= 2;
+ r20 += 3;
+ r25 -= 2;
+ r24 -= 3;
+ display();
+ }
+ scr40 = (unsigned int *)_mainViewBuf;
+ scr41 = scr40 + 640 / 4;
+ for (int i = 0; i < 320; i += 4) {
+ *scr40++ = 0;
+ *scr41++ = 0;
+ }
+ scr40 = ((unsigned int *)_mainViewBuf) + r20 * 640 / 4;
+ scr41 = scr40 + 640 / 4;
+ scr42 = scr41 + 640 / 4;
+ for (int i = 0; i < 320; i += 4) {
+ *scr40++ = 0;
+ *scr41++ = 0;
+ *scr42++ = 0;
+ }
+ display();
+ initRects();
+ _showBlackBars = true;
+}
+
+// Original name: bars_in
+void EdenGame::showBars() {
+ if (!_showBlackBars)
+ return;
+
+ drawBlackBars();
+ int16 r29 = 2;
+ int16 r28 = 2;
+ _underTopBarScreenRect.left = 0;
+ _underTopBarScreenRect.right = 320 - 1;
+ _underTopBarBackupRect.left = _scrollPos;
+ _underTopBarBackupRect.right = _scrollPos + 320 - 1;
+ while (r28 < 24) {
+ if (r29 <= 16) {
+ _underTopBarScreenRect.top = 16 - r29;
+ _underTopBarScreenRect.bottom = 16 - 1;
+ _underTopBarBackupRect.top = 0;
+ _underTopBarBackupRect.bottom = r29 - 1;
+ CLBlitter_CopyViewRect(_underBarsView, _mainView, &_underTopBarScreenRect, &_underTopBarBackupRect);
+ }
+ _underTopBarScreenRect.top = 16;
+ _underTopBarScreenRect.bottom = 16 + r28;
+ _underTopBarBackupRect.top = 200 - 1 - r28;
+ _underTopBarBackupRect.bottom = 200 - 1;
+ CLBlitter_CopyViewRect(_underBarsView, _mainView, &_underTopBarScreenRect, &_underTopBarBackupRect);
+ r29 += 2;
+ r28 += 3;
+ display();
+ }
+ initRects();
+ _showBlackBars = false;
+}
+
+// Original name: sauvefondbouche
+void EdenGame::saveMouthBackground() {
+ rect_src.left = _curCharacterRect->left;
+ rect_src.top = _curCharacterRect->top;
+ rect_src.right = _curCharacterRect->right;
+ rect_src.bottom = _curCharacterRect->bottom;
+ rect_dst.left = _curCharacterRect->left + 320;
+ rect_dst.top = _curCharacterRect->top;
+ rect_dst.right = _curCharacterRect->right + 320;
+ rect_dst.bottom = _curCharacterRect->bottom;
+ CLBlitter_CopyViewRect(_mainView, _mainView, &rect_src, &rect_dst);
+ _backgroundSaved = true;
+}
+
+// Original name: restaurefondbouche
+void EdenGame::restoreMouthBackground() {
+ rect_src.left = _curCharacterRect->left;
+ rect_src.top = _curCharacterRect->top;
+ rect_src.right = _curCharacterRect->right;
+ rect_src.bottom = _curCharacterRect->bottom;
+ rect_dst.left = _curCharacterRect->left + 320;
+ rect_dst.top = _curCharacterRect->top;
+ rect_dst.right = _curCharacterRect->right + 320;
+ rect_dst.bottom = _curCharacterRect->bottom;
+ CLBlitter_CopyViewRect(_mainView, _mainView, &rect_dst, &rect_src);
+}
+
+// Original name : blackbars
+void EdenGame::drawBlackBars() {
+ byte *scr = _mainViewBuf;
+ for (int16 y = 0; y < 16; y++) {
+ for (int16 x = 0; x < 640; x++)
+ *scr++ = 0;
+ }
+
+ scr += 640 * (200 - 16 - 24);
+ for (int16 y = 0; y < 24; y++) {
+ for (int16 x = 0; x < 640; x++)
+ *scr++ = 0;
+ }
+}
+
+void EdenGame::drawTopScreen() { // Draw top bar (location / party / map)
+ _globals->_drawFlags &= ~DrawFlags::drDrawTopScreen;
+ useBank(314);
+ noclipax(36, 83, 0);
+ noclipax(_globals->_areaPtr->_num - 1, 0, 0);
+ noclipax(23, 145, 0);
+ for (perso_t *perso = &kPersons[PER_DINA]; perso != &kPersons[PER_UNKN_156]; perso++) {
+ if ((perso->_flags & PersonFlags::pfInParty) && !(perso->_flags & PersonFlags::pf80))
+ noclipax(perso->_targetLoc + 18, perso->_lastLoc + 120, 0);
+ }
+ _adamMapMarkPos.x = -1;
+ _adamMapMarkPos.y = -1;
+ displayValleyMap();
+ _paletteUpdateRequired = true;
+}
+
+// Original name: affplanval
+void EdenGame::displayValleyMap() { // Draw mini-map
+ if (_globals->_areaPtr->_type == AreaType::atValley) {
+ noclipax(_globals->_areaPtr->_num + 9, 266, 1);
+ for (perso_t *perso = &kPersons[PER_UNKN_18C]; perso->_roomNum != 0xFFFF; perso++) {
+ if (((perso->_roomNum >> 8) == _globals->_areaNum)
+ && !(perso->_flags & PersonFlags::pf80) && (perso->_flags & PersonFlags::pf20))
+ displayMapMark(33, perso->_roomNum & 0xFF);
+ }
+ if (_globals->_areaPtr->_citadelLevel)
+ displayMapMark(34, _globals->_areaPtr->_citadelRoomPtr->_location);
+ saveTopFrieze(0);
+ int16 loc = _globals->_roomNum & 0xFF;
+ if (loc >= 16)
+ displayAdamMapMark(loc);
+ restoreTopFrieze();
+ } else {
+ saveTopFrieze(0);
+ restoreTopFrieze();
+ }
+}
+
+// Original name: affrepere
+void EdenGame::displayMapMark(int16 index, int16 location) {
+ noclipax(index, 269 + location % 16 * 4, 2 + (location - 16) / 16 * 3);
+}
+
+// Original name: affrepereadam
+void EdenGame::displayAdamMapMark(int16 location) {
+ int16 x = 269;
+ int16 y = 2;
+ restoreAdamMapMark();
+ if (location > 15 && location < 76) {
+ x += (location & 15) * 4;
+ y += ((location - 16) >> 4) * 3;
+ saveAdamMapMark(x, y);
+ byte *pix = _underBarsView->_bufferPtr;
+ int16 w = _underBarsView->_width;
+ pix += x + w * y;
+ pix[1] = 0xC3;
+ pix[2] = 0xC3;
+ pix += w;
+ pix[0] = 0xC3;
+ pix[1] = 0xC3;
+ pix[2] = 0xC3;
+ pix[3] = 0xC3;
+ pix += w;
+ pix[1] = 0xC3;
+ pix[2] = 0xC3;
+ }
+}
+
+// Original name: rest_repadam
+void EdenGame::restoreAdamMapMark() {
+ if (_adamMapMarkPos.x == -1 && _adamMapMarkPos.y == -1)
+ return;
+
+ int16 x = _adamMapMarkPos.x;
+ int16 y = _adamMapMarkPos.y;
+ byte *pix = _underBarsView->_bufferPtr;
+ int16 w = _underBarsView->_width;
+ pix += x + w * y;
+ pix[1] = _oldPix[0];
+ pix[2] = _oldPix[1];
+ pix += w;
+ pix[0] = _oldPix[2];
+ pix[1] = _oldPix[3];
+ pix[2] = _oldPix[4];
+ pix[3] = _oldPix[5];
+ pix += w;
+ pix[1] = _oldPix[6];
+ pix[2] = _oldPix[7];
+}
+
+// Original name: save_repadam
+void EdenGame::saveAdamMapMark(int16 x, int16 y) {
+ _adamMapMarkPos.x = x;
+ _adamMapMarkPos.y = y;
+ byte *pix = _underBarsView->_bufferPtr;
+ int16 w = _underBarsView->_width;
+ pix += x + w * y;
+ _oldPix[0] = pix[1];
+ _oldPix[1] = pix[2];
+ pix += w;
+ _oldPix[2] = pix[0];
+ _oldPix[3] = pix[1];
+ _oldPix[4] = pix[2];
+ _oldPix[5] = pix[3];
+ pix += w;
+ _oldPix[6] = pix[1];
+ _oldPix[7] = pix[2];
+}
+
+bool EdenGame::istrice(int16 roomNum) {
+ char loc = roomNum & 0xFF;
+ int16 area = roomNum & 0xFF00;
+ for (perso_t *perso = &kPersons[PER_UNKN_18C]; perso != &kPersons[PER_UNKN_372]; perso++) {
+ if ((perso->_flags & PersonFlags::pf80) || (perso->_flags & PersonFlags::pfTypeMask) != PersonFlags::pftTriceraptor)
+ continue;
+ if (perso->_roomNum == (area | (loc - 16)))
+ return true;
+ if (perso->_roomNum == (area | (loc + 16)))
+ return true;
+ if (perso->_roomNum == (area | (loc - 1)))
+ return true;
+ if (perso->_roomNum == (area | (loc + 1)))
+ return true;
+ }
+ return false;
+}
+
+bool EdenGame::istyran(int16 roomNum) {
+ char loc = roomNum & 0xFF;
+ int16 area = roomNum & 0xFF00;
+ // TODO: orig bug: this ptr is not initialized when first called from getsalle
+ // PC version scans kPersons[] directly and is not affected
+ if (!_tyranPtr)
+ return false;
+
+ for (; _tyranPtr->_roomNum != 0xFFFF; _tyranPtr++) {
+ if (_tyranPtr->_flags & PersonFlags::pf80)
+ continue;
+ if (_tyranPtr->_roomNum == (area | (loc - 16)))
+ return true;
+ if (_tyranPtr->_roomNum == (area | (loc + 16)))
+ return true;
+ if (_tyranPtr->_roomNum == (area | (loc - 1)))
+ return true;
+ if (_tyranPtr->_roomNum == (area | (loc + 1)))
+ return true;
+ }
+ return false;
+}
+
+void EdenGame::istyranval(Area *area) {
+ byte areaNum = area->_num;
+ area->_flags &= ~AreaFlags::HasTyrann;
+ for (perso_t *perso = &kPersons[PER_UNKN_372]; perso->_roomNum != 0xFFFF; perso++) {
+ if (perso->_flags & PersonFlags::pf80)
+ continue;
+
+ if ((perso->_roomNum >> 8) == areaNum) {
+ area->_flags |= AreaFlags::HasTyrann;
+ break;
+ }
+ }
+}
+
+char EdenGame::getDirection(perso_t *perso) {
+ char dir = -1;
+ byte trgLoc = perso->_targetLoc;
+ byte curLoc = perso->_roomNum & 0xFF; //TODO name
+ if (curLoc != trgLoc) {
+ curLoc &= 0xF;
+ trgLoc &= 0xF;
+ if (curLoc != trgLoc) {
+ dir = 2;
+ if (curLoc > trgLoc)
+ dir = 5;
+ }
+ trgLoc = perso->_targetLoc;
+ curLoc = perso->_roomNum & 0xFF;
+ curLoc &= 0xF0;
+ trgLoc &= 0xF0;
+ if (curLoc != trgLoc) {
+ if (curLoc > trgLoc)
+ dir++;
+ dir++;
+ }
+ }
+ return dir;
+}
+
+// Original name: caselibre
+bool EdenGame::canMoveThere(char loc, perso_t *perso) {
+ Room *room = _globals->_citaAreaFirstRoom;
+ if (loc <= 0x10 || loc > 76 || (loc & 0xF) >= 12 || loc == perso->_lastLoc)
+ return false;
+
+ int16 roomNum = (perso->_roomNum & ~0xFF) | loc; //TODO: danger! signed
+ if (roomNum == _globals->_roomNum)
+ return false;
+
+ for (; room->_id != 0xFF; room++) {
+ if (room->_location != loc)
+ continue;
+ if (!(room->_flags & RoomFlags::rf01))
+ return false;
+ for (perso = &kPersons[PER_UNKN_18C]; perso->_roomNum != 0xFFFF; perso++) {
+ if (perso->_flags & PersonFlags::pf80)
+ continue;
+ if (perso->_roomNum == roomNum)
+ break;
+ }
+ if (perso->_roomNum != 0xFFFF)
+ return false;
+ return true;
+ }
+ return false;
+}
+
+// Original name: melange1
+void EdenGame::scramble1(uint8 elem[4]) {
+ if (_vm->_rnd->getRandomNumber(1) & 1)
+ SWAP(elem[1], elem[2]);
+}
+
+// Original name melange2
+void EdenGame::scramble2(uint8 elem[4]) {
+ if (_vm->_rnd->getRandomNumber(1) & 1)
+ SWAP(elem[0], elem[1]);
+
+ if (_vm->_rnd->getRandomNumber(1) & 1)
+ SWAP(elem[2], elem[3]);
+}
+
+// Original name: melangedir
+void EdenGame::scrambleDirections() {
+ scramble1(tab_2CB1E[0]);
+ scramble1(tab_2CB1E[1]);
+ scramble1(tab_2CB1E[2]);
+ scramble2(tab_2CB1E[3]);
+ scramble2(tab_2CB1E[4]);
+ scramble1(tab_2CB1E[5]);
+ scramble2(tab_2CB1E[6]);
+ scramble2(tab_2CB1E[7]);
+}
+
+bool EdenGame::naitredino(char persoType) {
+ for (perso_t *perso = &kPersons[PER_MORKUS]; (++perso)->_roomNum != 0xFFFF;) {
+ char areaNum = perso->_roomNum >> 8;
+ if (areaNum != _globals->_citadelAreaNum)
+ continue;
+ if ((perso->_flags & PersonFlags::pf80) && (perso->_flags & PersonFlags::pfTypeMask) == persoType) {
+ perso->_flags &= ~PersonFlags::pf80;
+ return true;
+ }
+ }
+ return false;
+}
+
+// Original name: newcita
+void EdenGame::newCitadel(char area, int16 level, Room *room) {
+ Citadel *cita = _citadelList;
+ while (cita->_id < level)
+ cita++;
+
+ uint16 index = ((room->_flags & 0xC0) >> 6); //TODO: this is very wrong
+ if (area == 4 || area == 6)
+ index++;
+
+ room->_bank = cita->_bank[index];
+ room->_video = cita->_video[index];
+ room->_flags |= RoomFlags::rf02;
+}
+
+// Original name: citaevol
+void EdenGame::evolveCitadel(int16 level) {
+ Room *room = _globals->_curAreaPtr->_citadelRoomPtr;
+ perso_t *perso = &kPersons[PER_UNKN_372];
+ byte loc = room->_location;
+ if (level >= 80 && !istrice((_globals->_citadelAreaNum << 8) | loc)) {
+ room->_level = 79;
+ return;
+ }
+
+ if (level > 160)
+ level = 160;
+
+ if (room->_level < 64 && level >= 64 && naitredino(PersonFlags::pftTriceraptor)) {
+ _globals->_curAreaPtr->_flags |= AreaFlags::HasTriceraptors;
+ addInfo(_globals->_citadelAreaNum + ValleyNews::vnTriceraptorsIn);
+ }
+ if (room->_level < 40 && level >= 40 && naitredino(PersonFlags::pftVelociraptor)) {
+ _globals->_curAreaPtr->_flags |= AreaFlags::HasVelociraptors;
+ addInfo(_globals->_citadelAreaNum + ValleyNews::vnVelociraptorsIn);
+ }
+ room->_level = level;
+ newCitadel(_globals->_citadelAreaNum, level, room);
+ byte speed = kDinoSpeedForCitaLevel[room->_level >> 4];
+ for (; perso->_roomNum != 0xFFFF; perso++) {
+ if (perso->_flags & PersonFlags::pf80)
+ continue;
+ if ((perso->_roomNum >> 8) == _globals->_citadelAreaNum && perso->_targetLoc == loc)
+ perso->_speed = speed;
+ }
+}
+
+// Original name: citacapoute
+void EdenGame::destroyCitadelRoom(int16 roomNum) {
+ perso_t *perso = &kPersons[PER_UNKN_18C];
+ Room *room = _globals->_curAreaPtr->_citadelRoomPtr;
+ room->_flags |= RoomFlags::rf01;
+ room->_flags &= ~RoomFlags::rfHasCitadel;
+ room->_bank = 193;
+ room->_video = 0;
+ room->_level = 0;
+ _globals->_curAreaPtr->_citadelLevel = 0;
+ _globals->_curAreaPtr->_citadelRoomPtr = 0;
+ roomNum = (roomNum & ~0xFF) | room->_location;
+ for (; perso->_roomNum != 0xFFFF; perso++) {
+ if (perso->_roomNum == roomNum) {
+ perso->_flags &= ~PersonFlags::pf80;
+ removeInfo((roomNum >> 8) + ValleyNews::vnTyrannIn);
+ break;
+ }
+ }
+}
+
+// Original name: buildcita
+void EdenGame::narratorBuildCitadel() {
+ Area *area = _globals->_areaPtr;
+ _globals->_curAreaPtr = _globals->_areaPtr;
+ if (area->_citadelRoomPtr)
+ destroyCitadelRoom(_globals->_roomNum);
+ _globals->_var6A = _globals->_var69;
+ _globals->_narratorSequence = _globals->_var69 | 0x80;
+ area->_citadelRoomPtr = _globals->_roomPtr;
+ _globals->_roomPtr->_flags &= ~RoomFlags::rf01;
+ _globals->_roomPtr->_flags |= RoomFlags::rfHasCitadel;
+ _globals->_roomPtr->_level = 32;
+ newCitadel(_globals->_areaNum, 32, _globals->_roomPtr);
+ area->_flags &= ~AreaFlags::TyrannSighted;
+ if (!(area->_flags & AreaFlags::afFlag8000)) {
+ if (_globals->_phaseNum == 304 || _globals->_phaseNum != 384) //TODO: wha
+ handleEloiReturn();
+ area->_flags |= AreaFlags::afFlag8000;
+ }
+ _globals->_roomCharacterPtr->_flags |= PersonFlags::pf80;
+ _globals->_citadelAreaNum = _globals->_areaNum;
+ naitredino(1);
+ removeInfo(_globals->_areaNum + ValleyNews::vnCitadelLost);
+ removeInfo(_globals->_areaNum + ValleyNews::vnTyrannLost);
+ if (_globals->_phaseNum == 193 && _globals->_areaNum == Areas::arUluru)
+ bigphase1();
+}
+
+// Original name: citatombe
+void EdenGame::citadelFalls(char level) {
+ if (level)
+ newCitadel(_globals->_citadelAreaNum, level, _globals->_curAreaPtr->_citadelRoomPtr);
+ else {
+ destroyCitadelRoom(_globals->_citadelAreaNum << 8);
+ addInfo(_globals->_citadelAreaNum + ValleyNews::vnCitadelLost);
+ }
+}
+
+// Original name: constcita
+void EdenGame::buildCitadel() {
+ if (!_globals->_curAreaPtr->_citadelLevel || !_globals->_curAreaPtr->_citadelRoomPtr)
+ return;
+
+ Room *room = _globals->_curAreaPtr->_citadelRoomPtr;
+ byte loc = room->_location;
+ _tyranPtr = &kPersons[PER_UNKN_372];
+ if (istyran((_globals->_citadelAreaNum << 8) | loc)) {
+ if (!(_globals->_curAreaPtr->_flags & AreaFlags::TyrannSighted)) {
+ addInfo(_globals->_citadelAreaNum + ValleyNews::vnTyrannIn);
+ _globals->_curAreaPtr->_flags |= AreaFlags::TyrannSighted;
+ }
+ byte level = room->_level - 1;
+ if (level < 32)
+ level = 32;
+ room->_level = level;
+ citadelFalls(level);
+ } else {
+ _globals->_curAreaPtr->_flags &= ~AreaFlags::TyrannSighted;
+ evolveCitadel(room->_level + 1);
+ }
+}
+
+// Original name: depladino
+void EdenGame::moveDino(perso_t *perso) {
+ int dir = getDirection(perso);
+ if (dir != -1) {
+ scrambleDirections();
+ uint8 *dirs = tab_2CB1E[dir];
+ byte loc = perso->_roomNum & 0xFF;
+ uint8 dir2 = dirs[0];
+ if (dir2 & 0x80)
+ dir2 = -(dir2 & ~0x80);
+ dir2 += loc;
+ if (!canMoveThere(dir2, perso)) {
+ dir2 = dirs[1];
+ if (dir2 & 0x80)
+ dir2 = -(dir2 & ~0x80);
+ dir2 += loc;
+ if (!canMoveThere(dir2, perso)) {
+ dir2 = dirs[2];
+ if (dir2 & 0x80)
+ dir2 = -(dir2 & ~0x80);
+ dir2 += loc;
+ if (!canMoveThere(dir2, perso)) {
+ dir2 = dirs[3];
+ if (dir2 & 0x80)
+ dir2 = -(dir2 & ~0x80);
+ dir2 += loc;
+ if (!canMoveThere(dir2, perso)) {
+ dir2 = perso->_lastLoc;
+ perso->_lastLoc = 0;
+ if (!canMoveThere(dir2, perso))
+ return;
+ }
+ }
+ }
+ }
+
+ perso->_lastLoc = perso->_roomNum & 0xFF;
+ perso->_roomNum &= ~0xFF;
+ perso->_roomNum |= dir2 & 0xFF;
+ if ((perso->_targetLoc - 16 == (perso->_roomNum & 0xFF))
+ || (perso->_targetLoc + 16 == (perso->_roomNum & 0xFF))
+ || (perso->_targetLoc - 1 == (perso->_roomNum & 0xFF))
+ || (perso->_targetLoc + 1 == (perso->_roomNum & 0xFF)))
+ perso->_targetLoc = 0;
+ } else
+ perso->_targetLoc = 0;
+}
+
+// Original name: deplaalldino
+void EdenGame::moveAllDino() {
+ for (perso_t *perso = &kPersons[PER_UNKN_18C]; perso->_roomNum != 0xFFFF; perso++) {
+ if (((perso->_roomNum >> 8) & 0xFF) != _globals->_citadelAreaNum)
+ continue;
+ if ((perso->_flags & PersonFlags::pf80) || !perso->_targetLoc)
+ continue;
+ if (--perso->_steps)
+ continue;
+ perso->_steps = 1;
+ if (perso->_roomNum == _globals->_roomNum)
+ continue;
+ perso->_steps = perso->_speed;
+ moveDino(perso);
+ }
+}
+
+// Original name: newvallee
+void EdenGame::newValley() {
+ static int16 roomNumList[] = { 2075, 2080, 2119, -1};
+
+ perso_t *perso = &kPersons[PER_UNKN_372];
+ int16 *ptr = roomNumList;
+ int16 roomNum = *ptr++;
+ while (roomNum != -1) {
+ perso->_roomNum = roomNum;
+ perso->_flags &= ~PersonFlags::pf80;
+ perso->_flags &= ~PersonFlags::pf20;
+ perso++;
+ roomNum = *ptr++;
+ }
+ perso->_roomNum = 0xFFFF;
+ kAreasTable[7]._flags |= AreaFlags::HasTyrann;
+ _globals->_worldHasTyran = 32;
+}
+
+char EdenGame::whereIsCita() {
+ char res = -1;
+ for (Room *room = _globals->_citaAreaFirstRoom; room->_id != 0xFF; room++) {
+ if (!(room->_flags & RoomFlags::rfHasCitadel))
+ continue;
+ res = room->_location;
+ break;
+ }
+ return res;
+}
+
+bool EdenGame::isCita(int16 loc) {
+ loc &= 0xFF;
+ for (Room *room = _globals->_citaAreaFirstRoom; room->_id != 0xFF; room++) {
+ if (!(room->_flags & RoomFlags::rfHasCitadel))
+ continue;
+
+ if ((room->_location == loc + 16)
+ || (room->_location == loc - 16)
+ || (room->_location == loc - 1)
+ || (room->_location == loc + 1))
+ return true;
+ }
+ return false;
+}
+
+// Original name: lieuvava
+void EdenGame::placeVava(Area *area) {
+ if (area->_type == AreaType::atValley) {
+ istyranval(area);
+ area->_citadelLevel = 0;
+ if (area->_citadelRoomPtr)
+ area->_citadelLevel = _globals->_citaAreaFirstRoom->_level; //TODO: no search?
+ byte mask = ~(1 << (area->_num - Areas::arChamaar));
+ _globals->_worldTyranSighted &= mask;
+ _globals->_var4E &= mask;
+ _globals->_worldGaveGold &= mask;
+ _globals->_worldHasVelociraptors &= mask;
+ _globals->_worldHasTriceraptors &= mask;
+ _globals->_worldHasTyran &= mask;
+ _globals->_var53 &= mask;
+ mask = ~mask;
+ if (area->_flags & AreaFlags::TyrannSighted)
+ _globals->_worldTyranSighted |= mask;
+ if (area->_flags & AreaFlags::afFlag4)
+ _globals->_var4E |= mask;
+ if (area->_flags & AreaFlags::HasTriceraptors)
+ _globals->_worldHasTriceraptors |= mask;
+ if (area->_flags & AreaFlags::afGaveGold)
+ _globals->_worldGaveGold |= mask;
+ if (area->_flags & AreaFlags::HasVelociraptors)
+ _globals->_worldHasVelociraptors |= mask;
+ if (area->_flags & AreaFlags::HasTyrann)
+ _globals->_worldHasTyran |= mask;
+ if (area->_flags & AreaFlags::afFlag20)
+ _globals->_var53 |= mask;
+ if (area == _globals->_areaPtr) {
+ _globals->_curAreaFlags = area->_flags;
+ _globals->_curCitadelLevel = area->_citadelLevel;
+ }
+ }
+ _globals->_var4D &= _globals->_worldTyranSighted;
+}
+
+void EdenGame::vivredino() {
+ for (perso_t *perso = &kPersons[PER_UNKN_18C]; perso->_roomNum != 0xFFFF; perso++) {
+ if (((perso->_roomNum >> 8) & 0xFF) != _globals->_citadelAreaNum)
+ continue;
+ if (perso->_flags & PersonFlags::pf80)
+ continue;
+ switch (perso->_flags & PersonFlags::pfTypeMask) {
+ case PersonFlags::pftTyrann:
+ if (isCita(perso->_roomNum))
+ perso->_targetLoc = 0;
+ else if (!perso->_targetLoc) {
+ char cita = whereIsCita();
+ if (cita != -1) {
+ perso->_targetLoc = cita;
+ perso->_speed = 2;
+ perso->_steps = 1;
+ }
+ }
+ break;
+ case PersonFlags::pftTriceraptor:
+ if (perso->_flags & PersonFlags::pfInParty) {
+ if (isCita(perso->_roomNum))
+ perso->_targetLoc = 0;
+ else if (!perso->_targetLoc) {
+ char cita = whereIsCita();
+ if (cita != -1) {
+ perso->_targetLoc = cita;
+ perso->_speed = 3;
+ perso->_steps = 1;
+ }
+ }
+ }
+ break;
+ case PersonFlags::pftVelociraptor:
+ if (perso->_flags & PersonFlags::pf10) {
+ if (perso->_roomNum == _globals->_roomNum) {
+ perso_t *perso2 = &kPersons[PER_UNKN_372];
+ bool found = false;
+ for (; perso2->_roomNum != 0xFFFF; perso2++) {
+ if ((perso->_roomNum & ~0xFF) == (perso2->_roomNum & ~0xFF)) {
+ if (perso2->_flags & PersonFlags::pf80)
+ continue;
+ perso->_targetLoc = perso2->_roomNum & 0xFF;
+ perso->_steps = 1;
+ found = true;
+ break;
+ }
+ }
+ if (found)
+ continue;
+ } else {
+ _tyranPtr = &kPersons[PER_UNKN_372];
+ if (istyran(perso->_roomNum)) {
+ if (_globals->_phaseNum < 481 && (perso->_powers & (1 << (_globals->_citadelAreaNum - 3)))) {
+ _tyranPtr->_flags |= PersonFlags::pf80;
+ _tyranPtr->_roomNum = 0;
+ perso->_flags &= ~PersonFlags::pf10;
+ perso->_flags |= PersonFlags::pfInParty;
+ addInfo(_globals->_citadelAreaNum + ValleyNews::vnTyrannLost);
+ removeInfo(_globals->_citadelAreaNum + ValleyNews::vnTyrannIn);
+ if (naitredino(PersonFlags::pftTriceraptor))
+ addInfo(_globals->_citadelAreaNum + ValleyNews::vnTriceraptorsIn);
+ buildCitadel();
+ _globals->_curAreaPtr->_flags &= ~AreaFlags::TyrannSighted;
+ } else {
+ perso->_flags &= ~PersonFlags::pf10;
+ perso->_flags &= ~PersonFlags::pfInParty;
+ addInfo(_globals->_citadelAreaNum + ValleyNews::vnVelociraptorsLost);
+ }
+ continue;
+ }
+ }
+ }
+ if (!perso->_targetLoc) {
+ int16 loc;
+ perso->_lastLoc = 0;
+ do {
+ loc = (_vm->_rnd->getRandomNumber(63) & 63) + 16;
+ if ((loc & 0xF) >= 12)
+ loc &= ~4; //TODO: ??? same as -= 4
+ } while (!canMoveThere(loc, perso));
+ perso->_targetLoc = loc;
+ perso->_steps = 1;
+ }
+ break;
+ }
+ }
+}
+
+void EdenGame::vivreval(int16 areaNum) {
+ _globals->_citadelAreaNum = areaNum;
+ _globals->_curAreaPtr = &kAreasTable[areaNum - 1];
+ _globals->_citaAreaFirstRoom = &_gameRooms[_globals->_curAreaPtr->_firstRoomIdx];
+ moveAllDino();
+ buildCitadel();
+ vivredino();
+ newMushroom();
+ newNestWithEggs();
+ newEmptyNest();
+ if (_globals->_phaseNum >= 226)
+ newGold();
+ placeVava(_globals->_curAreaPtr);
+}
+
+// Original name: chaquejour
+void EdenGame::handleDay() {
+ vivreval(3);
+ vivreval(4);
+ vivreval(5);
+ vivreval(6);
+ vivreval(7);
+ vivreval(8);
+ _globals->_drawFlags |= DrawFlags::drDrawTopScreen;
+}
+
+// Original name: temps_passe
+void EdenGame::addTime(int16 t) {
+ int16 days = _globals->_gameDays;
+ int16 lo = _globals->_gameHours + t;
+ if (lo > 255) {
+ days++;
+ lo &= 0xFF;
+ }
+
+ _globals->_gameHours = lo;
+ t = ((t >> 8) & 0xFF) + days;
+ t -= _globals->_gameDays;
+ if (t) {
+ _globals->_gameDays += t;
+ while (t--)
+ handleDay();
+ }
+}
+
+// Original name: anim_perso
+void EdenGame::animCharacter() {
+ if (_curBankNum != _globals->_characterImageBank)
+ loadCharacter(_globals->_characterPtr);
+ restoreUnderSubtitles();
+ if (_restartAnimation) {
+ _lastAnimTicks = _vm->_timerTicks;
+ _restartAnimation = false;
+ }
+ _curAnimFrameNumb = (_vm->_timerTicks - _lastAnimTicks) >> 2; // TODO: check me!!!
+ if (_curAnimFrameNumb > _numAnimFrames) // TODO: bug?
+ _animateTalking = false;
+ if (_globals->_curCharacterAnimPtr && !_globals->_animationFlags && _curAnimFrameNumb != _lastAnimFrameNumb) {
+ _lastAnimFrameNumb = _curAnimFrameNumb;
+ if (*_globals->_curCharacterAnimPtr == 0xFF)
+ getanimrnd();
+ useCharacterBank();
+ _numImgDesc = 0;
+ setCharacterSprite(_globals->_curCharacterAnimPtr);
+ _globals->_curCharacterAnimPtr += _numImgDesc + 1;
+ _mouthAnimations = _imageDesc + 200;
+ removeMouthSprite();
+ if (*_mouthAnimations)
+ displayImage();
+ _animationDelay--;
+ if (!_animationDelay) {
+ _globals->_animationFlags = 1;
+ _animationDelay = 8;
+ }
+ }
+
+ _animationDelay--;
+ if (!_animationDelay) {
+ getanimrnd();
+ //TODO: no reload?
+ }
+ if (_animateTalking) {
+ if (!_animationTable) {
+ _animationTable = _gameLipsync + 7262; //TODO: fix me
+ if (!_backgroundSaved)
+ saveMouthBackground();
+ }
+ if (!_personTalking)
+ _curAnimFrameNumb = _numAnimFrames - 1;
+ _animationIndex = _animationTable[_curAnimFrameNumb];
+ if (_animationIndex == 0xFF)
+ _animateTalking = false;
+ else if (_animationIndex != _lastAnimationIndex) {
+ useCharacterBank();
+ restoreMouthBackground();
+// debug("perso spr %d", animationIndex);
+ setCharacterSprite(_globals->_persoSpritePtr2 + _animationIndex * 2); //TODO: int16s?
+ _mouthAnimations = _imageDesc + 200;
+ if (*_mouthAnimations)
+ displayImage();
+ _lastAnimationIndex = _animationIndex;
+ }
+ }
+ displaySubtitles();
+}
+
+void EdenGame::getanimrnd() {
+ _animationDelay = 8;
+ int16 rnd = _vm->_rnd->getRandomNumber(65535) & (byte)~0x18; //TODO
+ dword_30724 = _globals->_persoSpritePtr + 16; //TODO
+ _globals->_curCharacterAnimPtr = _globals->_persoSpritePtr + ((dword_30724[1] << 8) + dword_30724[0]);
+ _globals->_animationFlags = 1;
+ if (rnd >= 8)
+ return;
+ _globals->_animationFlags = 0;
+ if (rnd <= 0)
+ return;
+ for (rnd *= 8; rnd > 0; rnd--) {
+ while (*_globals->_curCharacterAnimPtr)
+ _globals->_curCharacterAnimPtr++;
+ _globals->_curCharacterAnimPtr++;
+ }
+}
+
+void EdenGame::addanim() {
+ _lastAnimationIndex = 0xFF;
+ _lastAnimTicks = 0;
+ _globals->_animationFlags = 0xC0;
+ _globals->_curCharacterAnimPtr = _globals->_persoSpritePtr;
+ getanimrnd();
+ _animationActive = true;
+ if (_globals->_characterPtr == &kPersons[PER_KING])
+ return;
+ setCharacterSprite(_globals->_persoSpritePtr + READ_LE_UINT16(_globals->_persoSpritePtr)); //TODO: GetElem(0)
+ _mouthAnimations = _imageDesc + 200;
+ if (_globals->_characterPtr->_id != PersonId::pidCabukaOfCantura && _globals->_characterPtr->_targetLoc != 7) //TODO: targetLoc is minisprite idx
+ removeMouthSprite();
+ if (*_mouthAnimations)
+ displayImage();
+}
+
+// Original name: virespritebouche
+void EdenGame::removeMouthSprite() {
+ byte *src = _mouthAnimations + 2;
+ byte *dst = src;
+ char cnt = _mouthAnimations[0];
+ while (cnt--) {
+ byte a = *src++;
+ byte b = *src++;
+ byte c = *src++;
+ dst[0] = a;
+ dst[1] = b;
+ dst[2] = c;
+ if (dword_30728[0] != 0xFF) {
+ if ((a < dword_30728[0] || a > dword_30728[1])
+ && (a < dword_30728[2] || a > dword_30728[3]))
+ dst += 3;
+ else
+ _mouthAnimations[0]--;
+ } else
+ dst += 3;
+ }
+}
+
+// Original name: anim_perfin
+void EdenGame::AnimEndCharacter() {
+ _globals->_animationFlags &= ~0x80;
+ _animationDelay = 0;
+ _animationActive = false;
+}
+
+// Original name: perso_spr
+void EdenGame::setCharacterSprite(byte *spr) {
+ byte *img = _imageDesc + 200 + 2;
+ int16 count = 0;
+ byte c;
+ while ((c = *spr++)) {
+ byte *src;
+ int16 index = 0;
+ byte cc = 0;
+ if (c == 1) {
+ cc = index;
+ c = *spr++;
+ }
+ _numImgDesc++;
+ index = (cc << 8) | c;
+ index -= 2;
+
+ if (index > _maxPersoDesc)
+ index = _maxPersoDesc;
+ index *= 2; //TODO: src = GetElem(ff_C2, index)
+ src = _globals->_varC2;
+ src += READ_LE_UINT16(src + index);
+ while ((c = *src++)) {
+ *img++ = c;
+ *img++ = *src++;
+ *img++ = *src++;
+ count++;
+ }
+ }
+ _imageDesc[200] = count & 0xFF;
+ _imageDesc[201] = count >> 8;
+}
+
+// Original name: af_image
+void EdenGame::displayImage() {
+ byte *img = _imageDesc + 200;
+
+ int16 count = READ_LE_UINT16(img);
+ if (!count)
+ return;
+
+ byte *img_start = img;
+ byte *curimg = _imageDesc;
+
+ img += 2;
+ count *= 3;
+ while (count--)
+ *curimg++ = *img++;
+ img = img_start;
+ count = READ_LE_UINT16(img);
+ img += 2;
+ /////// draw it
+ while (count--) {
+ uint16 index = *img++;
+ uint16 x = *img++ + _gameIcons[0].sx;
+ uint16 y = *img++ + _gameIcons[0].sy;
+ byte *pix = _bankData;
+ byte *scr = _mainViewBuf + x + y * 640;
+ index--;
+ if (READ_LE_UINT16(pix) > 2)
+ readPalette(pix + 2);
+ pix += READ_LE_UINT16(pix);
+ pix += READ_LE_UINT16(pix + index * 2);
+ // int16 height:9
+ // int16 pad:6;
+ // int16 flag:1;
+ byte h0 = *pix++;
+ byte h1 = *pix++;
+ int16 w = ((h1 & 1) << 8) | h0;
+ int16 h = *pix++;
+ byte mode = *pix++;
+ if (mode != 0xFF && mode != 0xFE)
+ continue; //TODO: enclosing block?
+ if (h1 & 0x80) {
+ // compressed
+ for (; h-- > 0;) {
+ for (int16 ww = w; ww > 0;) {
+ byte c = *pix++;
+ if (c >= 0x80) {
+ if (c == 0x80) {
+ byte fill = *pix++;
+ if (fill == 0) {
+ scr += 128 + 1;
+ ww -= 128 + 1;
+ } else {
+ byte run;
+ *scr++ = fill; //TODO: wha?
+ *scr++ = fill;
+ ww -= 128 + 1;
+ for (run = 127; run--;)
+ *scr++ = fill;
+ }
+ } else {
+ byte fill = *pix++;
+ byte run = 255 - c + 2;
+ ww -= run;
+ if (fill == 0)
+ scr += run;
+ else {
+ for (; run--;)
+ *scr++ = fill;
+ }
+ }
+ } else {
+ byte run = c + 1;
+ ww -= run;
+ for (; run--;) {
+ byte p = *pix++;
+ if (p == 0)
+ scr++;
+ else
+ *scr++ = p;
+ }
+ }
+ }
+ scr += 640 - w;
+ }
+ } else {
+ // uncompressed
+ for (; h--;) {
+ for (int16 ww = w; ww--;) {
+ byte p = *pix++;
+ if (p == 0)
+ scr++;
+ else
+ *scr++ = p;
+ }
+ scr += 640 - w;
+ }
+ }
+ }
+}
+
+// Original name: af_perso1
+void EdenGame::displayCharacter1() {
+ setCharacterSprite(_globals->_persoSpritePtr + READ_LE_UINT16(_globals->_persoSpritePtr));
+ displayImage();
+}
+
+// Original name: af_perso
+void EdenGame::displayCharacter() {
+ loadCurrCharacter();
+ displayCharacter1();
+}
+
+void EdenGame::ef_perso() {
+ _globals->_animationFlags &= 0x3F;
+}
+
+// Original name: load_perso
+void EdenGame::loadCharacter(perso_t *perso) {
+ _characterBankData = nullptr;
+ if (!perso->_spriteBank)
+ return;
+
+ if (perso->_spriteBank != _globals->_characterImageBank) {
+ _curCharacterRect = &_characterRects[perso->_id]; //TODO: array of int16?
+ dword_30728 = _characterArray[perso->_id];
+ ef_perso();
+ _globals->_characterImageBank = perso->_spriteBank;
+ useBank(_globals->_characterImageBank);
+ _characterBankData = _bankData;
+ byte *ptr = _bankData;
+ ptr += READ_LE_UINT16(ptr);
+ byte *baseptr = ptr;
+ ptr += READ_LE_UINT16(ptr) - 2;
+ ptr = baseptr + READ_LE_UINT16(ptr) + 4;
+ _gameIcons[0].sx = READ_LE_UINT16(ptr);
+ _gameIcons[0].sy = READ_LE_UINT16(ptr + 2);
+ _gameIcons[0].ex = READ_LE_UINT16(ptr + 4);
+ _gameIcons[0].ey = READ_LE_UINT16(ptr + 6);
+ ptr += 8;
+ _globals->_varC2 = ptr + 2;
+ _maxPersoDesc = READ_LE_UINT16(ptr) / 2;
+ ptr += READ_LE_UINT16(ptr);
+ baseptr = ptr;
+ ptr += READ_LE_UINT16(ptr) - 2;
+ _globals->_persoSpritePtr = baseptr;
+ _globals->_persoSpritePtr2 = baseptr + READ_LE_UINT16(ptr);
+ debug("load perso: b6 len is %ld", _globals->_persoSpritePtr2 - _globals->_persoSpritePtr);
+ } else {
+ useBank(_globals->_characterImageBank);
+ _characterBankData = _bankData;
+ }
+}
+
+// Original name: load_perso_cour
+void EdenGame::loadCurrCharacter() {
+ loadCharacter(_globals->_characterPtr);
+}
+
+void EdenGame::fin_perso() {
+ _globals->_animationFlags &= 0x3F;
+ _globals->_curCharacterAnimPtr = nullptr;
+ _globals->_varCA = 0;
+ _globals->_characterImageBank = -1;
+ AnimEndCharacter();
+}
+
+void EdenGame::no_perso() {
+ if (_globals->_displayFlags == DisplayFlags::dfPerson) {
+ _globals->_displayFlags = _globals->_oldDisplayFlags;
+ fin_perso();
+ }
+ endCharacterSpeech();
+}
+
+// Original name: close_perso
+void EdenGame::closeCharacterScreen() {
+ endCharacterSpeech();
+ if (_globals->_displayFlags == DisplayFlags::dfPerson && _globals->_characterPtr->_id != PersonId::pidNarrator && _globals->_eventType != EventType::etEventE) {
+ rundcurs();
+ _savedUnderSubtitles = true;
+ restoreUnderSubtitles();
+ display();
+ _globals->_var103 = 16;
+ }
+ if (_globals->_characterPtr->_id == PersonId::pidNarrator)
+ _globals->_var103 = 69;
+ _globals->_eloiHaveNews &= 1;
+ _globals->_varCA = 0;
+ _globals->_varF6 = 0;
+ if (_globals->_displayFlags == DisplayFlags::dfPerson) {
+ _globals->_displayFlags = _globals->_oldDisplayFlags;
+ _globals->_animationFlags &= 0x3F;
+ _globals->_curCharacterAnimPtr = nullptr;
+ AnimEndCharacter();
+ if (_globals->_displayFlags & DisplayFlags::dfMirror) {
+ gameToMirror(1);
+ _scrollPos = _oldScrollPos;
+ scroll();
+ return;
+ }
+ if (_globals->_numGiveObjs) {
+ if (!(_globals->_displayFlags & DisplayFlags::dfFlag2))
+ showObjects();
+ _globals->_numGiveObjs = 0;
+ }
+ if (_globals->_varF2 & 1) {
+ _globals->_mirrorEffect = 6; // CHECKME: Verify the value
+ _globals->_varF2 &= ~1;
+ }
+ char oldLoc = _globals->_newLocation;
+ _globals->_newLocation = 0;
+ if (!(_globals->_narratorSequence & 0x80))
+ _globals->_var100 = 0xFF;
+ updateRoom(_globals->_roomNum);
+ _globals->_newLocation = oldLoc;
+ }
+
+ if (_globals->_chrono)
+ _globals->_chronoFlag = 1;
+}
+
+// Original name: af_fondsuiveur
+void EdenGame::displayBackgroundFollower() {
+ char id = _globals->_characterPtr->_id;
+ for (Follower *follower = followerList; follower->_id != -1; follower++) {
+ if (follower->_id == id) {
+ int bank = 326;
+ if (follower->sx >= 320)
+ bank = 327;
+ useBank(bank + _globals->_roomBackgroundBankNum);
+ noclipax_avecnoir(0, 0, 16);
+ break;
+ }
+ }
+}
+
+void EdenGame::displayNoFollower(int16 bank) {
+ if (bank) {
+ useBank(bank);
+ if (_globals->_characterPtr == &kPersons[PER_UNKN_156])
+ noclipax_avecnoir(0, 0, 16);
+ else
+ noclipax(0, 0, 16);
+ }
+}
+
+// Original name: af_fondperso1
+void EdenGame::displayCharacterBackground1() {
+ byte bank;
+ char *ptab;
+ if (_globals->_characterPtr == &kPersons[PER_ELOI]) {
+ _gameIcons[0].sx = 0;
+ _characterRects[PER_ELOI].left = 2;
+ bank = _globals->_characterBackgroundBankIdx;
+ if (_globals->_eventType == EventType::etEventE) {
+ _globals->_var103 = 1;
+ displayNoFollower(bank);
+ return;
+ }
+ _gameIcons[0].sx = 60;
+ _characterRects[PER_ELOI].left = 62;
+ }
+ if (_globals->_characterPtr == &kPersons[PER_TAU]) {
+ bank = 37;
+ if (_globals->_curObjectId == Objects::obShell) {
+ displayNoFollower(bank);
+ return;
+ }
+ }
+ ptab = kPersoRoomBankTable + _globals->_characterPtr->_roomBankId;
+ bank = *ptab++;
+ if (!(_globals->_characterPtr->_partyMask & _globals->_party)) {
+ while ((bank = *ptab++) != 0xFF) {
+ if (bank == (_globals->_roomNum & 0xFF)) { //TODO: signed vs unsigned - chg bank to uns?
+ bank = *ptab;
+ break;
+ }
+ ptab++;
+ }
+ if (bank == 0xFF) {
+ ptab = kPersoRoomBankTable + _globals->_characterPtr->_roomBankId;
+ bank = *ptab++;
+ }
+ }
+ displayBackgroundFollower();
+ displayNoFollower(bank);
+}
+
+// Original name: af_fondperso
+void EdenGame::displayCharacterBackground() {
+ if (_globals->_characterPtr->_spriteBank) {
+ _backgroundSaved = false;
+ displayCharacterBackground1();
+ }
+}
+
+// Original name: setpersoicon
+void EdenGame::setCharacterIcon() {
+ if (_globals->_iconsIndex == 4)
+ return;
+
+ if (_globals->_characterPtr == &kPersons[PER_ELOI] && _globals->_eventType == EventType::etEventE) {
+ _globals->_iconsIndex = 123;
+ return;
+ }
+ Icon *icon = _gameIcons;
+ Icon *icon2 = &_gameIcons[_roomIconsBase];
+
+ *icon2++ = *icon++; //TODO: is this ok?
+ *icon2++ = *icon++;
+ icon2->sx = -1;
+}
+
+// Original name: show_perso
+void EdenGame::showCharacter() {
+ perso_t *perso = _globals->_characterPtr;
+ if (perso->_spriteBank) {
+ closeRoom();
+ if (_globals->_displayFlags != DisplayFlags::dfPerson) {
+ if (_globals->_displayFlags & DisplayFlags::dfMirror)
+ resetScroll();
+ _globals->_oldDisplayFlags = _globals->_displayFlags;
+ _globals->_displayFlags = DisplayFlags::dfPerson;
+ loadCharacter(perso);
+ setCharacterIcon();
+ displayCharacterBackground();
+ if (perso == &kPersons[PER_TAU] && _globals->_curObjectId == Objects::obShell) {
+ displaySubtitles();
+ updateCursor();
+ _paletteUpdateRequired = true;
+ display();
+ rundcurs();
+ return;
+ }
+ }
+ loadCurrCharacter();
+ addanim();
+ if (!_globals->_curCharacterAnimPtr) {
+ displayCharacter();
+ displaySubtitles();
+ }
+ _restartAnimation = true;
+ animCharacter();
+ if (perso != &kPersons[PER_UNKN_156])
+ updateCursor();
+ _paletteUpdateRequired = true;
+ if (perso != &kPersons[PER_UNKN_156])
+ rundcurs();
+ display();
+ } else {
+ displayPlace();
+ displaySubtitles();
+ }
+}
+
+// Original name: showpersopanel
+void EdenGame::displayCharacterPanel() {
+ perso_t *perso = _globals->_characterPtr;
+ loadCurrCharacter();
+ addanim();
+ if (!_globals->_curCharacterAnimPtr) {
+ displayCharacter();
+ displaySubtitles();
+ }
+ _restartAnimation = true;
+ _paletteUpdateRequired = true;
+ if (_globals->_drawFlags & DrawFlags::drDrawFlag8)
+ return;
+ animCharacter();
+ if (perso != &kPersons[PER_UNKN_156])
+ updateCursor();
+ display();
+ if (perso != &kPersons[PER_UNKN_156])
+ rundcurs();
+ _globals->_drawFlags |= DrawFlags::drDrawFlag8;
+ _globals->_iconsIndex = 112;
+}
+
+void EdenGame::getDataSync() {
+ int16 num = _globals->_textNum;
+ if (_globals->_textBankIndex != 1)
+ num += 565;
+ if (_globals->_textBankIndex == 3)
+ num += 707;
+ if (num == 144)
+ num = 142;
+ _animateTalking = ReadDataSync(num - 1);
+ if (_animateTalking)
+ _numAnimFrames = readFrameNumber();
+ else
+ _numAnimFrames = 0;
+ if (_globals->_textNum == 144)
+ _numAnimFrames = 48;
+ _animationTable = 0;
+}
+
+// Original name: ReadNombreFrames
+int16 EdenGame::readFrameNumber() {
+ int16 num = 0;
+ _animationTable = _gameLipsync + 7260 + 2; //TODO: fix me
+ while (*_animationTable++ != 0xFF)
+ num++;
+ return num;
+}
+
+void EdenGame::waitEndSpeak() {
+ for (;;) {
+ if (_animationActive)
+ animCharacter();
+ musicspy();
+ display();
+ _vm->pollEvents();
+ if (_vm->shouldQuit()) {
+ closeCharacterScreen();
+ edenShudown();
+ break;
+ }
+ if (!_mouseHeld)
+ if (_vm->isMouseButtonDown())
+ break;
+ if (_mouseHeld)
+ if (!_vm->isMouseButtonDown())
+ _mouseHeld = false;
+ }
+ _mouseHeld = true;
+}
+
+void EdenGame::my_bulle() {
+ if (!_globals->_textNum)
+ return;
+
+ byte *icons = phraseIconsBuffer;
+ byte *linesp = _sentenceCoordsBuffer;
+ byte *sentencePtr = _sentenceBuffer;
+ _globals->_numGiveObjs = 0;
+ _globals->_giveObj1 = 0;
+ _globals->_giveObj2 = 0;
+ _globals->_giveObj3 = 0;
+ _globals->_textWidthLimit = _subtitlesXWidth;
+ byte *textPtr = getPhrase(_globals->_textNum);
+ _numTextLines = 0;
+ int16 wordsOnLine = 0;
+ int16 wordWidth = 0;
+ int16 lineWidth = 0;
+ byte c;
+ while ((c = *textPtr++) != 0xFF) {
+ if (c == 0x11 || c == 0x13) {
+ if (_globals->_phaseNum <= 272 || _globals->_phaseNum == 386) {
+ _globals->_eloiHaveNews = c & 0xF;
+ _globals->_var4D = _globals->_worldTyranSighted;
+ }
+ } else if (c >= 0x80 && c < 0x90)
+ SysBeep(1);
+ else if (c >= 0x90 && c < 0xA0) {
+ while (*textPtr++ != 0xFF) ;
+ textPtr--;
+ } else if (c >= 0xA0 && c < 0xC0)
+ _globals->_textToken1 = c & 0xF;
+ else if (c >= 0xC0 && c < 0xD0)
+ _globals->_textToken2 = c & 0xF;
+ else if (c >= 0xD0 && c < 0xE0) {
+ byte c1 = *textPtr++;
+ if (c == 0xD2)
+#ifdef FAKE_DOS_VERSION
+ _globals->_textWidthLimit = c1 + 160;
+#else
+ _globals->_textWidthLimit = c1 + _subtitlesXCenter; //TODO: signed? 160 in pc ver
+#endif
+ else {
+ byte c2 = *textPtr++;
+ switch (_globals->_numGiveObjs) {
+ case 0:
+ _globals->_giveObj1 = c2;
+ break;
+ case 1:
+ _globals->_giveObj2 = c2;
+ break;
+ case 2:
+ _globals->_giveObj3 = c2;
+ break;
+ }
+ _globals->_numGiveObjs++;
+ *icons++ = *textPtr++;
+ *icons++ = *textPtr++;
+ *icons++ = c2;
+ }
+ } else if (c >= 0xE0 && c < 0xFF)
+ SysBeep(1);
+ else if (c != '\r') {
+ *sentencePtr++ = c;
+ byte width = _gameFont[c];
+#ifdef FAKE_DOS_VERSION
+ if (c == ' ')
+ width = _spaceWidth;
+#endif
+ wordWidth += width;
+ lineWidth += width;
+ int16 overrun = lineWidth - _globals->_textWidthLimit;
+ if (overrun > 0) {
+ _numTextLines++;
+ if (c != ' ') {
+ *linesp++ = wordsOnLine;
+ *linesp++ = wordWidth + _spaceWidth - overrun;
+ lineWidth = wordWidth;
+ } else {
+ *linesp++ = wordsOnLine + 1;
+ *linesp++ = _spaceWidth - overrun; //TODO: checkme
+ lineWidth = 0;
+ }
+ wordWidth = 0;
+ wordsOnLine = 0;
+ } else {
+ if (c == ' ') {
+ wordsOnLine++;
+ wordWidth = 0;
+ }
+ }
+ }
+ }
+ _numTextLines++;
+ *linesp++ = wordsOnLine + 1;
+ *linesp++ = wordWidth;
+ *sentencePtr = c;
+ if (_globals->_textBankIndex == 2 && _globals->_textNum == 101 && _globals->_prefLanguage == 1)
+ patchSentence();
+ my_pr_bulle();
+ if (!_globals->_numGiveObjs)
+ return;
+ useMainBank();
+ if (_numTextLines < 3)
+ _numTextLines = 3;
+ icons = phraseIconsBuffer;
+ for (byte i = 0; i < _globals->_numGiveObjs; i++) {
+ byte x = *icons++;
+ byte y = *icons++;
+ byte s = *icons++;
+ spriteOnSubtitle(52, x + _subtitlesXCenter, y - 1);
+ spriteOnSubtitle(s + 9, x + _subtitlesXCenter + 1, y);
+ }
+}
+
+void EdenGame::my_pr_bulle() {
+ CLBlitter_FillView(_subtitlesView, 0);
+ if (_globals->_prefLanguage == 0)
+ return;
+
+ byte *coo = _sentenceCoordsBuffer;
+ bool done = false;
+ textout = _subtitlesViewBuf;
+ byte *textPtr = _sentenceBuffer;
+ int16 lines = 1;
+ while (!done) {
+ int16 numWords = *coo++; // num words on line
+ int16 padSize = *coo++; // amount of extra spacing
+ byte *currOut = textout;
+ int16 extraSpacing = numWords > 1 ? padSize / (numWords - 1) + 1 : 0;
+ if (lines == _numTextLines)
+ extraSpacing = 0;
+ byte c = *textPtr++;
+ while (!done && (numWords > 0)) {
+ if (c < 0x80 && c != '\r') {
+ if (c == ' ') {
+ numWords--;
+ if (padSize >= extraSpacing) {
+ textout += extraSpacing + _spaceWidth;
+ padSize -= extraSpacing;
+ } else {
+ textout += padSize + _spaceWidth;
+ padSize = 0;
+ }
+ } else {
+ int16 charWidth = _gameFont[c];
+ if (!(_globals->_drawFlags & DrawFlags::drDrawMenu)) {
+ textout += _subtitlesXWidth;
+ if (!_specialTextMode)
+ drawSubtitleChar(c, 195, charWidth);
+ textout++;
+ if (!_specialTextMode)
+ drawSubtitleChar(c, 195, charWidth);
+ textout -= _subtitlesXWidth + 1;
+ }
+ if (_specialTextMode)
+ drawSubtitleChar(c, 250, charWidth);
+ else
+ drawSubtitleChar(c, 230, charWidth);
+ textout += charWidth;
+ }
+ } else
+ error("my_pr_bulle: Unexpected format");
+
+ c = *textPtr++;
+ if (c == 0xFF)
+ done = true;
+ }
+ textout = currOut + _subtitlesXWidth * FONT_HEIGHT;
+ lines++;
+ textPtr--;
+ }
+}
+
+// Original name: charsurbulle
+void EdenGame::drawSubtitleChar(byte c, byte color, int16 width) {
+ byte *glyph = _gameFont + 256 + c * FONT_HEIGHT;
+ _textOutPtr = textout;
+ for (int16 h = 0; h < FONT_HEIGHT; h++) {
+ byte bits = *glyph++;
+ int16 mask = 0x80;
+ for (int16 w = 0; w < width; w++) {
+ if (bits & mask)
+ *_textOutPtr = color;
+ _textOutPtr++;
+ mask >>= 1;
+ }
+ _textOutPtr += _subtitlesXWidth - width;
+ }
+}
+
+// Original name: af_subtitle
+void EdenGame::displaySubtitles() {
+ byte *src = _subtitlesViewBuf;
+ byte *dst = _mainViewBuf;
+ int16 y;
+ if (_globals->_displayFlags & DisplayFlags::dfFlag2) {
+ y = 174;
+ if ((_globals->_drawFlags & DrawFlags::drDrawMenu) && _numTextLines == 1)
+ y = 167;
+ dst += 640 * (y - _numTextLines * FONT_HEIGHT) + _subtitlesXScrMargin;
+ } else {
+ y = 174;
+ dst += 640 * (y - _numTextLines * FONT_HEIGHT) + _scrollPos + _subtitlesXScrMargin;
+ }
+ if (_animationActive && !_personTalking)
+ return;
+ saveUnderSubtitles(y);
+ for (int16 h = 0; h < _numTextLines * FONT_HEIGHT + 1; h++) {
+ for (int16 w = 0; w < _subtitlesXWidth; w++) {
+ byte c = *src++;
+ if (c)
+ *dst = c;
+ dst++;
+ }
+ dst += 640 - _subtitlesXWidth;
+ }
+}
+
+// Original name: sauvefondbulle
+void EdenGame::saveUnderSubtitles(int16 y) {
+ _underSubtitlesScreenRect.top = y - _numTextLines * FONT_HEIGHT;
+ _underSubtitlesScreenRect.left = _scrollPos + _subtitlesXScrMargin;
+ _underSubtitlesScreenRect.right = _scrollPos + _subtitlesXScrMargin + _subtitlesXWidth - 1;
+ _underSubtitlesScreenRect.bottom = y;
+ _underSubtitlesBackupRect.top = 0;
+ _underSubtitlesBackupRect.bottom = _numTextLines * FONT_HEIGHT;
+ CLBlitter_CopyViewRect(_mainView, _underSubtitlesView, &_underSubtitlesScreenRect, &_underSubtitlesBackupRect);
+ _savedUnderSubtitles = true;
+}
+
+// Original name: restaurefondbulle
+void EdenGame::restoreUnderSubtitles() {
+ if (!_savedUnderSubtitles)
+ return;
+ CLBlitter_CopyViewRect(_underSubtitlesView, _mainView, &_underSubtitlesBackupRect, &_underSubtitlesScreenRect);
+ _savedUnderSubtitles = false;
+}
+
+// Original name: af_subtitlehnm
+void EdenGame::displayHNMSubtitle() {
+ byte *src = _subtitlesViewBuf;
+ byte *dst = _hnmViewBuf + _subtitlesXScrMargin + (158 - _numTextLines * FONT_HEIGHT) * 320;
+ for (int16 y = 0; y < _numTextLines * FONT_HEIGHT; y++) {
+ for (int16 x = 0; x < _subtitlesXWidth; x++) {
+ char c = *src++;
+ if (c)
+ *dst = c;
+ dst++;
+ }
+ dst += 320 - _subtitlesXWidth;
+ }
+}
+
+// Original name: patchPhrase
+void EdenGame::patchSentence() {
+ _sentenceBuffer[36] = 'c';
+}
+
+void EdenGame::vavapers() {
+ perso_t *perso = _globals->_characterPtr;
+ _globals->_curPersoFlags = perso->_flags;
+ _globals->_curPersoItems = perso->_items;
+ _globals->_curCharacterPowers = perso->_powers;
+}
+
+void EdenGame::citadelle() {
+ _globals->_var69++;
+ _globals->_varF6++;
+ parlemoiNormalFlag = true;
+ _closeCharacterDialog = true;
+}
+
+// Original name: choixzone
+void EdenGame::selectZone() {
+ if (_globals->_giveObj3)
+ _globals->_iconsIndex = 6;
+ else
+ _globals->_iconsIndex = 10;
+ _globals->_autoDialog = false;
+ putObject();
+}
+
+void EdenGame::showEvents1() {
+ _globals->_var113 = 0;
+ perso_ici(3);
+}
+
+void EdenGame::showEvents() {
+ if (_globals->_eventType && _globals->_displayFlags != DisplayFlags::dfPerson)
+ showEvents1();
+}
+
+void EdenGame::parle_mfin() {
+ perso_t *perso = _globals->_characterPtr;
+ if (_globals->_curObjectId) {
+ char curobj = _globals->_curObjectId;
+ if (_globals->_dialogType == DialogType::dtHint)
+ return;
+ object_t *obj = getObjectPtr(_globals->_curObjectId);
+ if (_globals->_dialogType == DialogType::dtDinoItem)
+ perso = _globals->_roomCharacterPtr;
+ if (isAnswerYes()) {
+ loseObject(_globals->_curObjectId);
+ perso->_powers |= obj->_powerMask;
+ }
+ perso->_items |= obj->_itemMask;
+ specialObjects(perso, curobj);
+ return;
+ }
+ if (!isAnswerYes())
+ return;
+ nextInfo();
+ if (!_globals->_lastInfo)
+ _closeCharacterDialog = true;
+ else {
+ _globals->_nextDialogPtr = nullptr;
+ _closeCharacterDialog = false;
+ }
+}
+
+void EdenGame::parlemoi_normal() {
+ Dialog *dial;
+ if (!_globals->_nextDialogPtr) {
+ perso_t *perso = _globals->_characterPtr;
+ if (perso) {
+ int16 num = (perso->_id << 3) | _globals->_dialogType;
+ dial = (Dialog *)getElem(_gameDialogs, num);
+ } else {
+ closeCharacterScreen();
+ return;
+ }
+ } else {
+ if (_closeCharacterDialog) {
+ closeCharacterScreen();
+ return;
+ }
+ dial = _globals->_nextDialogPtr;
+ }
+ char ok = dial_scan(dial);
+ _globals->_nextDialogPtr = _globals->_dialogPtr;
+ _closeCharacterDialog = false;
+ if (!ok)
+ closeCharacterScreen();
+ else
+ parle_mfin();
+}
+
+void EdenGame::parle_moi() {
+ endCharacterSpeech();
+ byte r28 = _globals->_varF6;
+ _globals->_varF6 = 0;
+ if (!r28) {
+ setChoiceNo();
+ if (_globals->_drawFlags & DrawFlags::drDrawInventory)
+ showObjects();
+ if (_globals->_drawFlags & DrawFlags::drDrawTopScreen)
+ drawTopScreen();
+ if (_globals->_curObjectId) {
+ if (_globals->_dialogType == DialogType::dtTalk) {
+ _globals->_dialogType = DialogType::dtItem;
+ _globals->_nextDialogPtr = nullptr;
+ _closeCharacterDialog = false;
+ }
+ parlemoi_normal();
+ return;
+ }
+ if (_globals->_dialogType == DialogType::dtItem) {
+ _globals->_dialogType = DialogType::dtTalk;
+ if (!_closeCharacterDialog)
+ _globals->_nextDialogPtr = nullptr;
+ }
+ if (parlemoiNormalFlag) {
+ parlemoi_normal();
+ return;
+ }
+ Dialog *dial;
+
+ if (!_globals->_lastDialogPtr) {
+ int16 num = 160;
+ if (_globals->_phaseNum >= 400)
+ num++;
+ dial = (Dialog *)getElem(_gameDialogs, num);
+ } else
+ dial = _globals->_lastDialogPtr;
+ char ok = dial_scan(dial);
+ _globals->_lastDialogPtr = _globals->_dialogPtr;
+ parlemoiNormalFlag = false;
+ if (!ok) {
+ parlemoiNormalFlag = true;
+ if (_globals->_var60) {
+ if (_globals->_characterPtr == &kPersons[PER_ELOI]) {
+ _globals->_dialogType = DialogType::dtTalk;
+ if (_globals->_eloiHaveNews)
+ parlemoi_normal();
+ else
+ closeCharacterScreen();
+ } else
+ closeCharacterScreen();
+ } else
+ parlemoi_normal();
+ } else
+ parle_mfin();
+ } else
+ closeCharacterScreen();
+}
+
+// Original name: init_perso_ptr
+void EdenGame::initCharacterPointers(perso_t *perso) {
+ _globals->_metPersonsMask1 |= perso->_partyMask;
+ _globals->_metPersonsMask2 |= perso->_partyMask;
+ _globals->_nextDialogPtr = nullptr;
+ _closeCharacterDialog = false;
+ _dialogSkipFlags = DialogFlags::dfSpoken;
+ _globals->_var60 = 0;
+ _globals->_textToken1 = 0;
+}
+
+void EdenGame::perso1(perso_t *perso) {
+ _globals->_phaseActionsCount++;
+ if (perso == &kPersons[PER_TAU])
+ _globals->_phaseActionsCount--;
+ _globals->_characterPtr = perso;
+ initCharacterPointers(perso);
+ parle_moi();
+}
+
+void EdenGame::perso_normal(perso_t *perso) {
+ _globals->_lastDialogPtr = nullptr;
+ _globals->_dialogType = DialogType::dtTalk;
+ parlemoiNormalFlag = false;
+ perso1(perso);
+}
+
+// Original name: persoparle
+void EdenGame::handleCharacterDialog(int16 pers) {
+ perso_t *perso = &kPersons[pers];
+ _globals->_characterPtr = perso;
+ _globals->_dialogType = DialogType::dtInspect;
+ uint16 idx = perso->_id * 8 | _globals->_dialogType;
+ dialoscansvmas((Dialog *)getElem(_gameDialogs, idx));
+ displayPlace();
+ displaySubtitles();
+ persovox();
+ _globals->_varCA = 0;
+ _globals->_dialogType = DialogType::dtTalk;
+}
+
+// Original name: roi
+void EdenGame::actionKing() {
+ perso_normal(&kPersons[PER_KING]);
+}
+
+// Original name: dina
+void EdenGame::actionDina() {
+ perso_normal(&kPersons[PER_DINA]);
+}
+
+// Original name: thoo
+void EdenGame::actionThoo() {
+ perso_normal(&kPersons[PER_TAU]);
+}
+
+// Original name: monk
+void EdenGame::actionMonk() {
+ perso_normal(&kPersons[PER_MONK]);
+}
+
+// Original name: bourreau
+void EdenGame::actionTormentor() {
+ perso_normal(&kPersons[PER_JABBER]);
+}
+
+// Original name: messager
+void EdenGame::actionMessenger() {
+ perso_normal(&kPersons[PER_ELOI]);
+}
+
+// Original name: mango
+void EdenGame::actionMango() {
+ perso_normal(&kPersons[PER_MUNGO]);
+}
+
+// Original name: eve
+void EdenGame::actionEve() {
+ perso_normal(&kPersons[PER_EVE]);
+}
+
+// Original name: azia
+void EdenGame::actionAzia() {
+ perso_normal(&kPersons[PER_SHAZIA]);
+}
+
+// Original name: mammi
+void EdenGame::actionMammi() {
+ perso_t *perso;
+ for (perso = &kPersons[PER_MAMMI]; perso->_partyMask == PersonMask::pmLeader; perso++) {
+ if (perso->_roomNum == _globals->_roomNum) {
+ perso_normal(perso);
+ break;
+ }
+ }
+}
+
+// Original name: gardes
+void EdenGame::actionGuards() {
+ perso_normal(&kPersons[PER_GUARDS]);
+}
+
+// Original name: bambou
+void EdenGame::actionBamboo() {
+ perso_normal(&kPersons[PER_BAMBOO]);
+}
+
+// Original name: kabuka
+void EdenGame::actionKabuka() {
+ if (_globals->_roomNum == 0x711) perso_normal(&kPersons[PER_KABUKA]);
+ else actionBamboo();
+}
+
+// Original name: fisher
+void EdenGame::actionFisher() {
+ if (_globals->_roomNum == 0x902) perso_normal(&kPersons[PER_FISHER]);
+ else actionKabuka();
+}
+
+// Original name: dino
+void EdenGame::actionDino() {
+ perso_t *perso = _globals->_roomCharacterPtr;
+ if (!perso)
+ return;
+ parlemoiNormalFlag = true;
+ _globals->_dialogType = DialogType::dtTalk;
+ _globals->_roomCharacterFlags = perso->_flags;
+ _globals->_roomPersoItems = perso->_items;
+ _globals->_roomCharacterPowers = perso->_powers;
+ _globals->_characterPtr = perso;
+ initCharacterPointers(perso);
+ debug("beg dino talk");
+ parle_moi();
+ debug("end dino talk");
+ if (_globals->_areaNum == Areas::arWhiteArch)
+ return;
+ if (_globals->_var60)
+ waitEndSpeak();
+ if (_vm->shouldQuit())
+ return;
+ perso = &kPersons[PER_MUNGO];
+ if (!(_globals->_party & PersonMask::pmMungo)) {
+ perso = &kPersons[PER_DINA];
+ if (!(_globals->_party & PersonMask::pmDina)) {
+ perso = &kPersons[PER_EVE];
+ if (!(_globals->_party & PersonMask::pmEve)) {
+ perso = &kPersons[PER_GUARDS];
+ }
+ }
+ }
+ _globals->_dialogType = DialogType::dtDinoAction;
+ if (_globals->_curObjectId)
+ _globals->_dialogType = DialogType::dtDinoItem;
+ perso1(perso);
+ if (_globals->_roomCharacterType == PersonFlags::pftMosasaurus && !_globals->_curObjectId) {
+ _globals->_areaPtr->_flags |= AreaFlags::afFlag20;
+ placeVava(_globals->_areaPtr);
+ }
+}
+
+// Original name: tyran
+void EdenGame::actionTyran() {
+ perso_t *perso = _globals->_roomCharacterPtr;
+ if (!perso)
+ return;
+
+ parlemoiNormalFlag = true;
+ _globals->_dialogType = DialogType::dtTalk;
+ _globals->_roomCharacterFlags = perso->_flags;
+ _globals->_characterPtr = perso;
+ initCharacterPointers(perso);
+ perso = &kPersons[PER_MUNGO];
+ if (!(_globals->_party & PersonMask::pmMungo)) {
+ perso = &kPersons[PER_DINA];
+ if (!(_globals->_party & PersonMask::pmDina)) {
+ perso = &kPersons[PER_EVE];
+ if (!(_globals->_party & PersonMask::pmEve)) {
+ perso = &kPersons[PER_GUARDS];
+ }
+ }
+ }
+ _globals->_dialogType = DialogType::dtDinoAction;
+ if (_globals->_curObjectId)
+ _globals->_dialogType = DialogType::dtDinoItem;
+ perso1(perso);
+}
+
+// Original name: morkus
+void EdenGame::actionMorkus() {
+ perso_normal(&kPersons[PER_MORKUS]);
+}
+
+void EdenGame::comment() {
+ perso_t *perso = &kPersons[PER_DINA];
+ if (!(_globals->_party & PersonMask::pmDina)) {
+ perso = &kPersons[PER_EVE];
+ if (!(_globals->_party & PersonMask::pmEve)) {
+ perso = &kPersons[PER_GUARDS];
+ if (!(_globals->_party & PersonMask::pmThugg))
+ return;
+ }
+ }
+ _globals->_dialogType = DialogType::dtHint;
+ perso1(perso);
+}
+
+// Original name: adam
+void EdenGame::actionAdam() {
+ resetScroll();
+ switch (_globals->_curObjectId) {
+ case Objects::obNone:
+ gotoPanel();
+ break;
+ case Objects::obRoot:
+ if (_globals->_roomNum == 2817
+ && _globals->_phaseNum > 496 && _globals->_phaseNum < 512) {
+ bigphase1();
+ loseObject(Objects::obRoot);
+ _globals->_var100 = 0xFF;
+ quitMirror();
+ updateRoom(_globals->_roomNum);
+ removeFromParty(PER_ELOI);
+ _globals->_eventType = EventType::etEvent3;
+ showEvents();
+ waitEndSpeak();
+ if (_vm->shouldQuit())
+ return;
+ closeCharacterScreen();
+ removeFromParty(PER_ELOI);
+ _globals->_roomNum = 2818;
+ _globals->_areaNum = Areas::arWhiteArch;
+ _globals->_eventType = EventType::etEvent5;
+ _globals->_valleyVidNum = 0;
+ _globals->_mirrorEffect = 6; // CHECKME: Verify the value
+ _globals->_newMusicType = MusicType::mtNormal;
+ updateRoom(_globals->_roomNum);
+ } else {
+ _globals->_dialogType = DialogType::dtHint;
+ perso1(&kPersons[PER_EVE]);
+ }
+ break;
+ case Objects::obShell:
+ _globals->_dialogType = DialogType::dtHint;
+ perso1(&kPersons[PER_TAU]);
+ break;
+ case Objects::obFlute:
+ case Objects::obTrumpet:
+ if (_globals->_roomCharacterType) {
+ quitMirror();
+ updateRoom(_globals->_roomNum);
+ actionDino();
+ } else
+ comment();
+ break;
+ case Objects::obTablet1:
+ case Objects::obTablet2:
+ case Objects::obTablet3:
+ case Objects::obTablet4:
+ case Objects::obTablet5:
+ case Objects::obTablet6: {
+ if ((_globals->_partyOutside & PersonMask::pmDina)
+ && _globals->_curObjectId == Objects::obTablet1 && _globals->_phaseNum == 370)
+ incPhase();
+ char *objvid = &kTabletView[(_globals->_curObjectId - Objects::obTablet1) * 2];
+ object_t *object = getObjectPtr(*objvid++);
+ int16 vid = 84;
+ if (!object->_count)
+ vid = *objvid;
+ hideBars();
+ _specialTextMode = true;
+ playHNM(vid);
+ _paletteUpdateRequired = true;
+ _globals->_mirrorEffect = 16; // CHECKME: Verify the value
+ showBars();
+ gameToMirror(0);
+ }
+ break;
+ case Objects::obApple:
+ case Objects::obShroom:
+ case Objects::obBadShroom:
+ case Objects::obNest:
+ case Objects::obFullNest:
+ case Objects::obDrum:
+ if (_globals->_party & PersonMask::pmThugg) {
+ _globals->_dialogType = DialogType::dtHint;
+ perso1(&kPersons[PER_GUARDS]);
+ }
+ break;
+ default:
+ comment();
+ }
+}
+
+// Original name: oui and init_oui
+void EdenGame::setChoiceYes() {
+ _lastDialogChoice = true;
+}
+
+// Original name: non and init_non
+void EdenGame::setChoiceNo() {
+ _lastDialogChoice = false;
+}
+
+// Original name: verif_oui
+bool EdenGame::isAnswerYes() {
+ return _lastDialogChoice;
+}
+
+// Original name: SpcChampi
+void EdenGame::specialMushroom(perso_t *perso) {
+ perso->_flags |= PersonFlags::pf10;
+ _globals->_areaPtr->_flags |= AreaFlags::afFlag2;
+ _globals->_curAreaFlags |= AreaFlags::afFlag2;
+}
+
+// Original name: SpcNidv
+void EdenGame::specialEmptyNest(perso_t *perso) {
+ if (!isAnswerYes())
+ return;
+ perso->_flags |= PersonFlags::pf10;
+ _globals->_roomCharacterFlags |= PersonFlags::pf10;
+ _globals->_gameFlags |= GameFlags::gfFlag400;
+ if (_globals->_characterPtr == &kPersons[PER_EVE]) {
+ _globals->_areaPtr->_flags |= AreaFlags::afFlag4;
+ _globals->_curAreaFlags |= AreaFlags::afFlag4;
+ perso->_flags |= PersonFlags::pfInParty;
+ _globals->_roomCharacterFlags |= PersonFlags::pfInParty;
+ placeVava(_globals->_areaPtr);
+ } else {
+ perso->_flags &= ~PersonFlags::pf10;
+ _globals->_roomCharacterFlags &= ~PersonFlags::pf10;
+ }
+}
+
+// Original name: SpcNido
+void EdenGame::specialNestWithEggs(perso_t *perso) {
+ if (perso == &kPersons[PER_GUARDS])
+ giveObject();
+}
+
+// Original name: SpcPomme
+void EdenGame::specialApple(perso_t *perso) {
+ perso->_flags |= PersonFlags::pf10;
+ _globals->_areaPtr->_flags |= AreaFlags::afFlag8;
+ _globals->_curAreaFlags |= AreaFlags::afFlag8;
+ _globals->_gameFlags |= GameFlags::gfFlag200;
+}
+
+// Original name: SpcOr
+void EdenGame::specialGold(perso_t *perso) {
+ if (!isAnswerYes())
+ return;
+ perso->_items = _curSpecialObject->_itemMask;
+ _globals->_roomPersoItems = _curSpecialObject->_itemMask;
+ perso->_flags |= PersonFlags::pf10;
+ perso->_flags &= ~PersonFlags::pfInParty;
+ perso->_targetLoc = 0;
+ _globals->_areaPtr->_flags |= AreaFlags::afGaveGold;
+ _globals->_curAreaFlags |= AreaFlags::afGaveGold;
+ if (_globals->_phaseNum == 226)
+ incPhase();
+}
+
+// Original name: SpcPrisme
+void EdenGame::specialPrism(perso_t *perso) {
+ if (perso == &kPersons[PER_DINA]) {
+ if (_globals->_partyOutside & PersonMask::pmMonk)
+ _globals->_gameFlags |= GameFlags::gfPrismAndMonk;
+ }
+}
+
+// Original name: SpcTalisman
+void EdenGame::specialTalisman(perso_t *perso) {
+ if (perso == &kPersons[PER_DINA])
+ addToParty(PER_DINA);
+}
+
+// Original name: SpcMasque
+void EdenGame::specialMask(perso_t *perso) {
+ if (perso == &kPersons[PER_BAMBOO]) {
+ dialautoon();
+ parlemoiNormalFlag = true;
+ }
+}
+
+// Original name: SpcSac
+void EdenGame::specialBag(perso_t *perso) {
+ if (_globals->_textToken1 != 3)
+ return;
+ if (perso == &kPersons[PER_KABUKA] || perso == &kPersons[PER_MAMMI_3])
+ loseObject(_curSpecialObject->_id);
+}
+
+// Original name: SpcTrompet
+void EdenGame::specialTrumpet(perso_t *perso) {
+ if (!isAnswerYes())
+ return;
+ _globals->_var54 = 4;
+ winObject(Objects::obTrumpet);
+ _globals->_drawFlags |= DrawFlags::drDrawInventory;
+ _closeCharacterDialog = true;
+ tyranDies(_globals->_roomCharacterPtr);
+}
+
+// Original name: SpcArmes
+void EdenGame::specialWeapons(perso_t *perso) {
+ if (!isAnswerYes())
+ return;
+ perso->_powers = _curSpecialObject->_powerMask;
+ _globals->_roomCharacterPowers = _curSpecialObject->_powerMask;
+ giveObject();
+}
+
+// Original name: SpcInstru
+void EdenGame::specialInstrument(perso_t *perso) {
+ if (!isAnswerYes())
+ return;
+ if (perso == &kPersons[PER_MONK]) {
+ _globals->_partyInstruments &= ~1; //TODO: check me
+ if (_curSpecialObject->_id == Objects::obRing) {
+ _globals->_partyInstruments |= 1;
+ _globals->_monkGotRing++; //TODO: |= 1 ?
+ }
+ }
+ if (perso == &kPersons[PER_GUARDS]) {
+ _globals->_partyInstruments &= ~2;
+ if (_curSpecialObject->_id == Objects::obDrum)
+ _globals->_partyInstruments |= 2;
+ }
+ perso->_powers = _curSpecialObject->_powerMask;
+ _globals->_curCharacterPowers = _curSpecialObject->_powerMask;
+ giveObject();
+}
+
+// Original name: SpcOeuf
+void EdenGame::specialEgg(perso_t *perso) {
+ if (!isAnswerYes())
+ return;
+ _gameIcons[131]._cursorId &= ~0x8000;
+ _globals->_characterBackgroundBankIdx = 62;
+ dialautoon();
+}
+
+// Original name: TyranMeurt
+void EdenGame::tyranDies(perso_t *perso) {
+ perso->_flags |= PersonFlags::pf80;
+ perso->_roomNum = 0;
+ removeInfo(_globals->_areaNum + ValleyNews::vnTyrannIn);
+ _globals->_roomCharacterType = 0;
+ _globals->_roomCharacterFlags = 0;
+ _globals->_chronoFlag = 0;
+}
+
+void EdenGame::specialObjects(perso_t *perso, char objid) {
+#pragma pack(push, 1)
+ struct SpecialObject {
+ int8 _characterType;
+ int8 _objectId;
+ void (EdenGame::*dispFct)(perso_t *perso);
+ };
+#pragma pack(pop)
+
+ static SpecialObject kSpecialObjectActions[] = {
+ // persoType, objectId, dispFct
+ { PersonFlags::pfType8, Objects::obShroom, &EdenGame::specialMushroom },
+ { PersonFlags::pftTriceraptor, Objects::obNest, &EdenGame::specialEmptyNest },
+ { PersonFlags::pfType0, Objects::obFullNest, &EdenGame::specialNestWithEggs },
+ { PersonFlags::pftMosasaurus, Objects::obApple, &EdenGame::specialApple },
+ { PersonFlags::pftVelociraptor, Objects::obGold, &EdenGame::specialGold },
+ { PersonFlags::pfType0, Objects::obPrism, &EdenGame::specialPrism },
+ { PersonFlags::pfType0, Objects::obTalisman, &EdenGame::specialTalisman },
+ { PersonFlags::pfType2, Objects::obMaskOfDeath, &EdenGame::specialMask },
+ { PersonFlags::pfType2, Objects::obMaskOfBonding, &EdenGame::specialMask },
+ { PersonFlags::pfType2, Objects::obMaskOfBirth, &EdenGame::specialMask },
+ { PersonFlags::pfType0, Objects::obBag, &EdenGame::specialBag },
+ { PersonFlags::pfType2, Objects::obBag, &EdenGame::specialBag },
+ { PersonFlags::pftTyrann, Objects::obTrumpet, &EdenGame::specialTrumpet },
+ { PersonFlags::pftVelociraptor, Objects::obEyeInTheStorm, &EdenGame::specialWeapons },
+ { PersonFlags::pftVelociraptor, Objects::obSkyHammer, &EdenGame::specialWeapons },
+ { PersonFlags::pftVelociraptor, Objects::obFireInTheClouds, &EdenGame::specialWeapons },
+ { PersonFlags::pftVelociraptor, Objects::obWithinAndWithout, &EdenGame::specialWeapons },
+ { PersonFlags::pftVelociraptor, Objects::obEyeInTheCyclone, &EdenGame::specialWeapons },
+ { PersonFlags::pftVelociraptor, Objects::obRiverThatWinds, &EdenGame::specialWeapons },
+ { PersonFlags::pfType0, Objects::obTrumpet, &EdenGame::specialInstrument },
+ { PersonFlags::pfType0, Objects::obDrum, &EdenGame::specialInstrument },
+ { PersonFlags::pfType0, Objects::obRing, &EdenGame::specialInstrument },
+ { PersonFlags::pfType0, Objects::obEgg, &EdenGame::specialEgg },
+ { -1, -1, nullptr }
+ };
+
+ char characterType = perso->_flags & PersonFlags::pfTypeMask;
+ _curSpecialObject = &_objects[objid - 1];
+ for (SpecialObject *spcObj = kSpecialObjectActions; spcObj->_characterType != -1; spcObj++) {
+ if (spcObj->_objectId == objid && spcObj->_characterType == characterType) {
+ (this->*spcObj->dispFct)(perso);
+ break;
+ }
+ }
+}
+
+void EdenGame::dialautoon() {
+ _globals->_iconsIndex = 4;
+ _globals->_autoDialog = true;
+ putObject();
+}
+
+void EdenGame::dialautooff() {
+ _globals->_iconsIndex = 0x10;
+ _globals->_autoDialog = false;
+}
+
+void EdenGame::follow() {
+ if (_globals->_roomCharacterType == PersonFlags::pfType12) {
+ debug("follow: hiding person %ld", _globals->_roomCharacterPtr - kPersons);
+ _globals->_roomCharacterPtr->_flags |= PersonFlags::pf80;
+ _globals->_roomCharacterPtr->_roomNum = 0;
+ _globals->_gameFlags |= GameFlags::gfFlag8;
+ _gameIcons[123]._objectId = 18;
+ _gameIcons[124]._objectId = 35;
+ _gameIcons[125]._cursorId &= ~0x8000;
+ _globals->_characterBackgroundBankIdx = 56;
+ } else
+ AddCharacterToParty();
+}
+
+void EdenGame::dialonfollow() {
+ _globals->_iconsIndex = 4;
+ _globals->_autoDialog = true;
+ follow();
+}
+
+// Original name: abortdial
+void EdenGame::abortDialogue() {
+ _globals->_varF6++;
+ if (_globals->_roomCharacterType != PersonFlags::pftTriceraptor || _globals->_characterPtr != &kPersons[PER_EVE])
+ return;
+ _globals->_areaPtr->_flags |= AreaFlags::afFlag4;
+ _globals->_curAreaFlags |= AreaFlags::afFlag4;
+ _globals->_roomCharacterPtr->_flags |= PersonFlags::pfInParty;
+ _globals->_roomCharacterFlags |= PersonFlags::pfInParty;
+ placeVava(_globals->_areaPtr);
+}
+
+void EdenGame::subHandleNarrator() {
+ _globals->_varF2 &= ~1; //TODO: check me
+ if (_globals->_narratorSequence > 50 && _globals->_narratorSequence <= 80)
+ _globals->_endGameFlag = 50;
+ if (_globals->_narratorSequence == 3)
+ setChrono(1200);
+ _globals->_narratorSequence = 0;
+}
+
+// Original name: narrateur
+void EdenGame::handleNarrator() {
+ if (!(_globals->_displayFlags & DisplayFlags::dfFlag1))
+ return;
+ if (!_globals->_narratorSequence) {
+ if (_globals->_var6A == _globals->_var69) {
+ subHandleNarrator();
+ return;
+ }
+
+ narratorBuildCitadel();
+ }
+ _globals->_varF5 |= 0x80;
+ _globals->_varF2 &= ~1; //TODO: check me
+ _globals->_characterPtr = &kPersons[PER_UNKN_156];
+ _globals->_var60 = 0;
+ _globals->_eventType = 0;
+ _globals->_var103 = 69;
+ if (dialogEvent(&kPersons[PER_UNKN_156])) {
+ _globals->_narratorDialogPtr = _globals->_dialogPtr;
+ dialautoon();
+ _globals->_varF2 |= 1;
+ waitEndSpeak();
+ if (_vm->shouldQuit())
+ return;
+ endCharacterSpeech();
+ while (dialoscansvmas(_globals->_narratorDialogPtr)) {
+ _globals->_narratorDialogPtr = _globals->_dialogPtr;
+ waitEndSpeak();
+ if (_vm->shouldQuit())
+ return;
+ endCharacterSpeech();
+ }
+ _globals->_narratorDialogPtr = _globals->_dialogPtr;
+ _globals->_mirrorEffect = 0;
+ _globals->_var103 = 0;
+ closeCharacterScreen();
+ placeVava(_globals->_areaPtr);
+ if (_globals->_narratorSequence == 8)
+ deplaval(134);
+ }
+ _globals->_var103 = 0;
+ if (_globals->_narratorSequence == 10) {
+ addToParty(PER_ELOI);
+ addToParty(PER_EVE);
+ addToParty(PER_MONK);
+ addToParty(PER_GUARDS);
+ removeFromParty(PER_MUNGO);
+ _globals->_eloiHaveNews = 0;
+ deplaval(139);
+ }
+ _globals->_eventType = EventType::etEventD;
+ showEvents();
+ _globals->_varF5 &= ~0x80;
+
+ subHandleNarrator();
+}
+
+// Original name: vrf_phrases_file
+void EdenGame::checkPhraseFile() {
+ int16 num = 3;
+ if (_globals->_dialogPtr < (Dialog *)getElem(_gameDialogs, 48))
+ num = 1;
+ else if (_globals->_dialogPtr < (Dialog *)getElem(_gameDialogs, 128))
+ num = 2;
+ _globals->_textBankIndex = num;
+ if (_globals->_prefLanguage)
+ num += (_globals->_prefLanguage - 1) * 3;
+ if (num == _lastPhrasesFile)
+ return;
+ _lastPhrasesFile = num;
+ num += 404;
+ loadRawFile(num, _gamePhrases);
+ verifh(_gamePhrases);
+}
+
+// Original name: gettxtad
+byte *EdenGame::getPhrase(int16 id) {
+ checkPhraseFile();
+ return (byte *)getElem(_gamePhrases, id - 1);
+}
+
+// Original name: gotocarte
+void EdenGame::actionGotoMap() {
+ Goto *go = &gotos[_curSpot2->_objectId];
+ endCharacterSpeech();
+ byte newArea = go->_areaNum;
+ _globals->_newRoomNum = (go->_areaNum << 8) | 1;
+ _globals->_newLocation = 1;
+ _globals->_prevLocation = _globals->_roomNum & 0xFF;
+ char curArea = _globals->_roomNum >> 8;
+ if (curArea == go->_areaNum)
+ newArea = 0;
+ else {
+ for (; go->_curAreaNum != 0xFF; go++) {
+ if (go->_curAreaNum == curArea)
+ break;
+ }
+
+ if (go->_areaNum == 0xFF)
+ return;
+ }
+ _globals->_eventType = EventType::etGotoArea | newArea;
+ setChoiceYes();
+ showEvents1();
+ waitEndSpeak();
+ if (_vm->shouldQuit())
+ return;
+
+ closeCharacterScreen();
+ if (isAnswerYes())
+ gotoPlace(go);
+}
+
+void EdenGame::record() {
+ if (_globals->_curObjectId)
+ return;
+
+ if (_globals->_characterPtr >= &kPersons[PER_UNKN_18C])
+ return;
+
+ if (_globals->_eventType == EventType::etEventE || _globals->_eventType >= EventType::etGotoArea)
+ return;
+
+ for (tape_t *tape = _tapes; tape != _tapes + MAX_TAPES; tape++) {
+ if (tape->_textNum == _globals->_textNum)
+ return;
+ }
+
+ tape_t *tape = _tapes;
+ for (int16 i = 0; i < MAX_TAPES - 1; i++) {
+ tape->_textNum = tape[+1]._textNum;
+ tape->_perso = tape[+1]._perso;
+ tape->_party = tape[+1]._party;
+ tape->_roomNum = tape[+1]._roomNum;
+ tape->_backgroundBankNum = tape[+1]._backgroundBankNum;
+ tape->_dialog = tape[+1]._dialog;
+ tape++;
+ }
+
+ perso_t *perso = _globals->_characterPtr;
+ if (perso == &kPersons[PER_EVE])
+ perso = _globals->_phaseNum >= 352 ? &kPersons[PER_UNKN_372]
+ : &kPersons[PER_UNKN_402];
+ tape->_textNum = _globals->_textNum;
+ tape->_perso = perso;
+ tape->_party = _globals->_party;
+ tape->_roomNum = _globals->_roomNum;
+ tape->_backgroundBankNum = _globals->_roomBackgroundBankNum;
+ tape->_dialog = _globals->_dialogPtr;
+}
+
+bool EdenGame::dial_scan(Dialog *dial) {
+ if (_globals->_numGiveObjs) {
+ if (!(_globals->_displayFlags & DisplayFlags::dfFlag2))
+ showObjects();
+ _globals->_numGiveObjs = 0;
+ }
+ _globals->_dialogPtr = dial;
+ vavapers();
+ _globals->_sentenceBufferPtr = _sentenceBuffer;
+ byte hidx, lidx;
+ uint16 mask = 0;
+ bool skipFl = false;
+ for (;; _globals->_dialogPtr++) {
+ for (;; _globals->_dialogPtr++) {
+ if (_globals->_dialogPtr->_flags == -1 && _globals->_dialogPtr->_condNumLow == -1)
+ return false;
+ byte flags = _globals->_dialogPtr->_flags;
+ _globals->_dialogFlags = flags;
+ if (!(flags & DialogFlags::dfSpoken) || (flags & DialogFlags::dfRepeatable)) {
+ hidx = (_globals->_dialogPtr->_textCondHiMask >> 6) & 3;
+ lidx = _globals->_dialogPtr->_condNumLow;
+ if (flags & 0x10)
+ hidx |= 4;
+ if (testCondition(((hidx << 8) | lidx) & 0x7FF))
+ break;
+ } else {
+ if (flags & _dialogSkipFlags)
+ continue;
+ hidx = (_globals->_dialogPtr->_textCondHiMask >> 6) & 3;
+ lidx = _globals->_dialogPtr->_condNumLow;
+ if (flags & 0x10)
+ hidx |= 4;
+ if (testCondition(((hidx << 8) | lidx) & 0x7FF))
+ break;
+ }
+ }
+ char bidx = (_globals->_dialogPtr->_textCondHiMask >> 2) & 0xF;
+ if (!bidx) {
+ skipFl = true;
+ break;
+ }
+
+ mask = (_globals->_party | _globals->_partyOutside) & (1 << (bidx - 1));
+ if (mask)
+ break;
+ }
+
+ if (!skipFl) {
+ perso_t *perso;
+ for (perso = kPersons; !(perso->_partyMask == mask && perso->_roomNum == _globals->_roomNum); perso++)
+ ; //Find matching
+
+ _globals->_characterPtr = perso;
+ initCharacterPointers(perso);
+ no_perso();
+ }
+
+ hidx = _globals->_dialogPtr->_textCondHiMask;
+ lidx = _globals->_dialogPtr->_textNumLow;
+ _globals->_textNum = ((hidx << 8) | lidx) & 0x3FF;
+ if (_globals->_sentenceBufferPtr != _sentenceBuffer) {
+ for (int16 i = 0; i < 32; i++)
+ SysBeep(1);
+ } else
+ my_bulle();
+ if (!dword_30B04) {
+ static void (EdenGame::*talk_subject[])() = {
+ &EdenGame::setChoiceYes,
+ &EdenGame::setChoiceNo,
+ &EdenGame::handleEloiDeparture,
+ &EdenGame::dialautoon,
+ &EdenGame::dialautooff,
+ &EdenGame::characterStayHere,
+ &EdenGame::follow,
+ &EdenGame::citadelle,
+ &EdenGame::dialonfollow,
+ &EdenGame::abortDialogue,
+ &EdenGame::incPhase,
+ &EdenGame::bigphase,
+ &EdenGame::giveObject,
+ &EdenGame::selectZone,
+ &EdenGame::lostObject
+ };
+ char pnum = _globals->_dialogPtr->_flags & 0xF;
+ if (pnum)
+ (this->*talk_subject[pnum - 1])();
+ _globals->_var60 = 1;
+ _globals->_dialogPtr->_flags |= DialogFlags::dfSpoken;
+ _globals->_dialogPtr++;
+ }
+ if (_globals->_dialogType != DialogType::dtInspect) {
+ record();
+ getDataSync();
+ showCharacter();
+ persovox();
+ }
+ return true;
+}
+
+bool EdenGame::dialoscansvmas(Dialog *dial) {
+ byte oldFlag = _dialogSkipFlags;
+ _dialogSkipFlags = DialogFlags::df20;
+ bool res = dial_scan(dial);
+ _dialogSkipFlags = oldFlag;
+ return res;
+}
+
+// Original name: dialo_even
+bool EdenGame::dialogEvent(perso_t *perso) {
+ _globals->_characterPtr = perso;
+ int num = (perso->_id << 3) | DialogType::dtEvent;
+ Dialog *dial = (Dialog *)getElem(_gameDialogs, num);
+ bool retVal = dialoscansvmas(dial);
+ _globals->_lastDialogPtr = nullptr;
+ parlemoiNormalFlag = false;
+ return retVal;
+}
+
+// Original name: stay_here
+void EdenGame::characterStayHere() {
+ if (_globals->_characterPtr == &kPersons[PER_DINA] && _globals->_roomNum == 260)
+ _globals->_gameFlags |= GameFlags::gfFlag1000;
+ removeCharacterFromParty();
+}
+
+// Original name: mort
+void EdenGame::endDeath(int16 vid) {
+ hideBars();
+ playHNM(vid);
+ fadeToBlack(2);
+ CLBlitter_FillScreenView(0);
+ CLBlitter_FillView(_mainView, 0);
+ showBars();
+ _globals->_narratorSequence = 51;
+ _globals->_newMusicType = MusicType::mtNormal;
+ musique();
+ musicspy();
+}
+
+// Original name: evenchrono
+void EdenGame::chronoEvent() {
+ if (!(_globals->_displayFlags & DisplayFlags::dfFlag1))
+ return;
+
+ uint16 oldGameTime = _globals->_gameTime;
+ _currentTime = _vm->_timerTicks / 100;
+ _globals->_gameTime = _currentTime;
+ if (_globals->_gameTime <= oldGameTime)
+ return;
+ addTime(5);
+ if (!(_globals->_chronoFlag & 1))
+ return;
+ _globals->_chrono -= 200;
+ if (_globals->_chrono == 0)
+ _globals->_chronoFlag |= 2;
+ if (!(_globals->_chronoFlag & 2))
+ return;
+ _globals->_chronoFlag = 0;
+ _globals->_chrono = 0;
+ if (_globals->_roomCharacterType == PersonFlags::pftTyrann) {
+ int16 vid = 272;
+ if (_globals->_curRoomFlags & 0xC0) {
+ vid += 2;
+ if ((_globals->_curRoomFlags & 0xC0) != 0x80) {
+ vid += 2;
+ endDeath(vid);
+ return;
+ }
+ }
+ if (_globals->_areaNum == Areas::arUluru || _globals->_areaNum == Areas::arTamara)
+ endDeath(vid);
+ else
+ endDeath(vid + 1);
+ return;
+ }
+ if (_globals->_roomNum == 2817) {
+ addToParty(PER_ELOI);
+ _globals->_gameFlags |= GameFlags::gfFlag40;
+ dialautoon();
+ } else
+ handleEloiReturn();
+ _globals->_eventType = EventType::etEvent10;
+ showEvents();
+}
+
+// Original name: chronoon
+void EdenGame::setChrono(int16 t) {
+ _globals->_chrono = t;
+ _globals->_chronoFlag = 1;
+}
+
+// Original name: prechargephrases
+void EdenGame::preloadDialogs(int16 vid) {
+ perso_t *perso = &kPersons[PER_MORKUS];
+ if (vid == 170)
+ perso = &kPersons[PER_UNKN_156];
+ _globals->_characterPtr = perso;
+ _globals->_dialogType = DialogType::dtInspect;
+ int num = (perso->_id << 3) | _globals->_dialogType;
+ Dialog *dial = (Dialog *)getElem(_gameDialogs, num);
+ dialoscansvmas(dial);
+}
+
+// Original name: effet1
+void EdenGame::displayEffect1() {
+ blackRect32();
+ setSrcRect(0, 0, 16 - 1, 4 - 1);
+ int y = _mainView->_normal._dstTop;
+ for (int16 i = 16; i <= 96; i += 4) {
+ for (int x = _mainView->_normal._dstLeft; x < _mainView->_normal._dstLeft + 320; x += 16) {
+ setDestRect(x, y + i, x + 16 - 1, y + i + 4 - 1);
+ CLBlitter_CopyViewRect(_view2, _vm->_screenView, &rect_src, &rect_dst);
+ setDestRect(x, y + 192 - i, x + 16 - 1, y + 192 - i + 4 - 1);
+ CLBlitter_CopyViewRect(_view2, _vm->_screenView, &rect_src, &rect_dst);
+ }
+ CLBlitter_UpdateScreen();
+ wait(1);
+ }
+ CLPalette_Send2Screen(_globalPalette, 0, 256);
+ _mainView->_normal._height = 2;
+ _mainView->_zoom._height = 4;
+ int16 ny = _mainView->_normal._dstTop;
+ int16 dy = _mainView->_zoom._dstTop;
+ for (int16 i = 0; i < 100; i += 2) {
+ _mainView->_normal._srcTop = 99 - i;
+ _mainView->_zoom._srcTop = 99 - i;
+ _mainView->_normal._dstTop = 99 - i + ny;
+ _mainView->_zoom._dstTop = (99 - i) * 2 + dy;
+ CLBlitter_CopyView2Screen(_mainView);
+ _mainView->_normal._srcTop = 100 + i;
+ _mainView->_zoom._srcTop = 100 + i;
+ _mainView->_normal._dstTop = 100 + i + ny;
+ _mainView->_zoom._dstTop = (100 + i) * 2 + dy;
+ CLBlitter_CopyView2Screen(_mainView);
+ CLBlitter_UpdateScreen();
+ wait(1);
+ }
+ _mainView->_normal._height = 200;
+ _mainView->_zoom._height = 400;
+ _mainView->_normal._srcTop = 0;
+ _mainView->_zoom._srcTop = 0;
+ _mainView->_normal._dstTop = ny;
+ _mainView->_zoom._dstTop = dy;
+ _globals->_varF1 = 0;
+}
+
+// Original name: effet2
+void EdenGame::displayEffect2() {
+ static int16 pattern1[] = {0, 1, 2, 3, 7, 11, 15, 14, 13, 12, 8, 4, 5, 6, 10, 9};
+ static int16 pattern2[] = {0, 15, 1, 14, 2, 13, 3, 12, 7, 8, 11, 4, 5, 10, 6, 9};
+ static int16 pattern3[] = {0, 2, 5, 7, 8, 10, 13, 15, 1, 3, 4, 6, 9, 11, 12, 14};
+ static int16 pattern4[] = {0, 3, 15, 12, 1, 7, 14, 8, 2, 11, 13, 4, 5, 6, 10, 9};
+
+ static int eff2pat = 0;
+ if (_globals->_var103 == 69) {
+ displayEffect4();
+ return;
+ }
+ switch (++eff2pat) {
+ case 1:
+ colimacon(pattern1);
+ break;
+ case 2:
+ colimacon(pattern2);
+ break;
+ case 3:
+ colimacon(pattern3);
+ break;
+ case 4:
+ colimacon(pattern4);
+ eff2pat = 0;
+ break;
+ }
+}
+
+// Original name: effet3
+void EdenGame::displayEffect3() {
+ CLPalette_GetLastPalette(oldPalette);
+ for (uint16 i = 0; i < 6; i++) {
+ for (uint16 c = 0; c < 256; c++) {
+ newColor.r = oldPalette[c].r >> i;
+ newColor.g = oldPalette[c].g >> i;
+ newColor.b = oldPalette[c].b >> i;
+ CLPalette_SetRGBColor(newPalette, c, &newColor);
+ }
+ CLPalette_Send2Screen(newPalette, 0, 256);
+ wait(1);
+ }
+ CLBlitter_CopyView2Screen(_mainView);
+ for (uint16 i = 0; i < 6; i++) {
+ for (uint16 c = 0; c < 256; c++) {
+ newColor.r = _globalPalette[c].r >> (5 - i);
+ newColor.g = _globalPalette[c].g >> (5 - i);
+ newColor.b = _globalPalette[c].b >> (5 - i);
+ CLPalette_SetRGBColor(newPalette, c, &newColor);
+ }
+ CLPalette_Send2Screen(newPalette, 0, 256);
+ wait(1);
+ }
+}
+
+// Original name: effet4
+void EdenGame::displayEffect4() {
+ byte *scr, *pix, *r24, *r25, *r30, c;
+ int16 r17, r23, r16, r18, r19, r22, r27, r31;
+ CLPalette_Send2Screen(_globalPalette, 0, 256);
+
+ int16 ww = _vm->_screenView->_pitch;
+ int16 x = _mainView->_normal._dstLeft;
+ int16 y = _mainView->_normal._dstTop;
+ for (int16 i = 32; i > 0; i -= 2) {
+ scr = _vm->_screenView->_bufferPtr;
+ scr += (y + 16) * ww + x;
+ pix = _mainView->_bufferPtr + 16 * 640;
+ r17 = 320 / i;
+ r23 = 320 - 320 / i * i; //TODO: 320 % i ?
+ r16 = 160 / i;
+ r18 = 160 - 160 / i * i; //TODO: 160 % i ?
+ for (r19 = r16; r19 > 0; r19--) {
+ r24 = scr;
+ r25 = pix;
+ for (r22 = r17; r22 > 0; r22--) {
+ c = *r25;
+ r25 += i;
+ r30 = r24;
+ for (r27 = i; r27 > 0; r27--) {
+ for (r31 = i; r31 > 0; r31--)
+ *r30++ = c;
+ r30 += ww - i;
+ }
+ r24 += i;
+ }
+ if (r23) {
+ c = *r25;
+ r30 = r24;
+ for (r27 = i; r27 > 0; r27--) {
+ for (r31 = r23; r31 > 0; r31--)
+ *r30++ = c;
+ r30 += ww - r23;
+ }
+ }
+ scr += i * ww;
+ pix += i * 640;
+ }
+ if (r18) {
+ r24 = scr;
+ r25 = pix;
+ for (r22 = r17; r22 > 0; r22--) {
+ c = *r25;
+ r25 += i;
+ r30 = r24;
+ for (r27 = r18; r27 > 0; r27--) {
+ for (r31 = i; r31 > 0; r31--)
+ *r30++ = c;
+ r30 += ww - i;
+ }
+ r24 += i;
+ }
+ if (r23) {
+ c = *r25;
+ r30 = r24;
+ for (r27 = r18; r27 > 0; r27--) {
+ for (r31 = r23; r31 > 0; r31--)
+ *r30++ = c;
+ r30 += ww - r23;
+ }
+ }
+ }
+ CLBlitter_UpdateScreen();
+ wait(3);
+ }
+ CLBlitter_CopyView2Screen(_mainView);
+}
+
+void EdenGame::clearScreen() {
+ int16 ww = _vm->_screenView->_pitch;
+ int16 x = _mainView->_normal._dstLeft;
+ int16 y = _mainView->_normal._dstTop;
+ byte *scr = _vm->_screenView->_bufferPtr;
+ scr += (y + 16) * ww + x;
+ for (int16 yy = 0; yy < 160; yy++) {
+ for (int16 xx = 0; xx < 320; xx++)
+ *scr++ = 0;
+ scr += ww - 320;
+ }
+ CLBlitter_UpdateScreen();
+}
+
+void EdenGame::colimacon(int16 pattern[16]) {
+ int16 p, r27, r25;
+
+ int16 ww = _vm->_screenView->_pitch;
+ int16 x = _mainView->_normal._dstLeft;
+ int16 y = _mainView->_normal._dstTop;
+ byte *scr = _vm->_screenView->_bufferPtr;
+ scr += (y + 16) * ww + x;
+ for (int16 i = 0; i < 16; i++) {
+ p = pattern[i];
+ r27 = p % 4 + p / 4 * ww;
+ for (int16 j = 0; j < 320 * 160 / 16; j++)
+ scr[j / (320 / 4) * ww * 4 + j % (320 / 4) * 4 + r27] = 0;
+ CLBlitter_UpdateScreen();
+ wait(1);
+ }
+ CLPalette_Send2Screen(_globalPalette, 0, 256);
+ byte *pix = _mainView->_bufferPtr;
+ x = _mainView->_normal._dstLeft;
+ y = _mainView->_normal._dstTop;
+ pix += 640 * 16;
+ scr = _vm->_screenView->_bufferPtr;
+ scr += (y + 16) * ww + x;
+ for (int16 i = 0; i < 16; i++) {
+ p = pattern[i];
+ r25 = p % 4 + p / 4 * 640;
+ r27 = p % 4 + p / 4 * ww;
+ for (int16 j = 0; j < 320 * 160 / 16; j++)
+ scr[j / (320 / 4) * ww * 4 + j % (320 / 4) * 4 + r27] =
+ pix[j / (320 / 4) * 640 * 4 + j % (320 / 4) * 4 + r25];
+ CLBlitter_UpdateScreen();
+ wait(1);
+ }
+}
+
+void EdenGame::fadeToBlack(int delay) {
+ CLPalette_GetLastPalette(oldPalette);
+ for (int16 i = 0; i < 6; i++) {
+ for (int16 j = 0; j < 256; j++) {
+ newColor.r = oldPalette[j].r >> i;
+ newColor.g = oldPalette[j].g >> i;
+ newColor.b = oldPalette[j].b >> i;
+ CLPalette_SetRGBColor(newPalette, j, &newColor);
+ }
+ CLPalette_Send2Screen(newPalette, 0, 256);
+ wait(delay);
+ }
+}
+
+// Original name: fadetoblack128
+void EdenGame::fadeToBlackLowPalette(int delay) {
+ CLPalette_GetLastPalette(oldPalette);
+ for (int16 i = 0; i < 6; i++) {
+ for (int16 j = 0; j < 129; j++) { //CHECKME: Should be 128?
+ newColor.r = oldPalette[j].r >> i;
+ newColor.g = oldPalette[j].g >> i;
+ newColor.b = oldPalette[j].b >> i;
+ CLPalette_SetRGBColor(newPalette, j, &newColor);
+ }
+ CLPalette_Send2Screen(newPalette, 0, 128);
+ wait(delay);
+ }
+}
+
+// Original name: fadefromblack128
+void EdenGame::fadeFromBlackLowPalette(int delay) {
+ for (int16 i = 0; i < 6; i++) {
+ for (int16 j = 0; j < 129; j++) { //CHECKME: Should be 128?
+ newColor.r = _globalPalette[j].r >> (5 - i);
+ newColor.g = _globalPalette[j].g >> (5 - i);
+ newColor.b = _globalPalette[j].b >> (5 - i);
+ CLPalette_SetRGBColor(newPalette, j, &newColor);
+ }
+ CLPalette_Send2Screen(newPalette, 0, 128);
+ wait(delay);
+ }
+}
+
+// Original name: rectanglenoir32
+void EdenGame::blackRect32() {
+ // blacken 32x32 rectangle
+ int *pix = (int *)_view2Buf;
+ for (int16 i = 0; i < 32; i++) {
+ pix[0] = 0;
+ pix[1] = 0;
+ pix[2] = 0;
+ pix[3] = 0;
+ pix[4] = 0;
+ pix[5] = 0;
+ pix[6] = 0;
+ pix[7] = 0;
+ pix += 32 / 4;
+ }
+}
+
+void EdenGame::setSrcRect(int16 sx, int16 sy, int16 ex, int16 ey) {
+ rect_src = Common::Rect(sx, sy, ex, ey);
+}
+
+void EdenGame::setDestRect(int16 sx, int16 sy, int16 ex, int16 ey) {
+ rect_dst = Common::Rect(sx, sy, ex, ey);
+}
+
+void EdenGame::wait(int howlong) {
+ int t = g_system->getMillis();
+
+ for (int t2 = t; t2 - t < howlong; t2 = g_system->getMillis())
+ g_system->delayMillis(10); // waste time
+}
+
+void EdenGame::effetpix() {
+ uint16 r25, r18, r31, r30; //TODO: change to xx/yy
+
+ uint16 ww = _vm->_screenView->_pitch;
+ r25 = ww * 80;
+ r18 = 640 * 80;
+ byte *pix = _mainView->_bufferPtr + 16 * 640;
+ int x = _mainView->_normal._dstLeft;
+ int y = _mainView->_normal._dstTop;
+ byte *scr = _vm->_screenView->_bufferPtr;
+ scr += (y + 16) * ww + x;
+ int16 r20 = 0x4400; //TODO
+ int16 r27 = 1;
+ int16 r26 = 0;
+ do {
+ char r8 = r27 & 1;
+ r27 >>= 1;
+ if (r8)
+ r27 ^= r20;
+ if (r27 < 320 * 80) {
+ r31 = r27 / 320;
+ r30 = r27 % 320;
+ scr[r31 * ww + r30] = 0;
+ scr[r31 * ww + r25 + r30] = 0;
+ if (++r26 == 960) {
+ CLBlitter_UpdateScreen();
+ wait(1);
+ r26 = 0;
+ }
+ }
+ } while (r27 != 1);
+ CLPalette_Send2Screen(_globalPalette, 0, 256);
+ r20 = 0x4400;
+ r27 = 1;
+ r26 = 0;
+ do {
+ char r8 = r27 & 1;
+ r27 >>= 1;
+ if (r8)
+ r27 ^= r20;
+ if (r27 < 320 * 80) {
+ r31 = r27 / 320;
+ r30 = r27 % 320;
+ byte p0 = pix[r31 * 640 + r30];
+ byte p1 = pix[r31 * 640 + r18 + r30];
+ scr[r31 * ww + r30] = p0;
+ scr[r31 * ww + r25 + r30] = p1;
+ if (++r26 == 960) {
+ CLBlitter_UpdateScreen();
+ wait(1);
+ r26 = 0;
+ }
+ }
+ } while (r27 != 1);
+ assert(_vm->_screenView->_pitch == 320);
+}
+
+////// datfile.c
+void EdenGame::verifh(byte *ptr) {
+ byte sum = 0;
+ byte *head = ptr;
+
+ for (int8 i = 0; i < 6; i++)
+ sum += *head++;
+
+ if (sum != 0xAB)
+ return;
+
+ debug("* Begin unpacking resource");
+ head -= 6;
+ uint16 h0 = READ_LE_UINT16(head);
+ // 3 = 2 bytes for the uint16 and 1 byte for an unused char
+ head += 3;
+ uint16 h3 = READ_LE_UINT16(head);
+ head += 2;
+ byte *data = h0 + head + 26;
+ h3 -= 6;
+ head += h3;
+ for (; h3; h3--)
+ *data-- = *head--;
+ head = data + 1;
+ data = ptr;
+ expandHSQ(head, data);
+}
+
+void EdenGame::openbigfile() {
+ _bigfile.open("EDEN.DAT");
+
+ char buf[16];
+ int count = _bigfile.readUint16LE();
+ _bigfileHeader = new PakHeaderNode(count);
+ for (int j = 0; j < count; j++) {
+ for (int k = 0; k < 16; k++)
+ buf[k] = _bigfile.readByte();
+ _bigfileHeader->_files[j]._name = Common::String(buf);
+ _bigfileHeader->_files[j]._size = _bigfile.readUint32LE();
+ _bigfileHeader->_files[j]._offs = _bigfile.readUint32LE();
+ _bigfileHeader->_files[j]._flag = _bigfile.readByte();
+ }
+
+ _vm->_video->resetInternals();
+ _vm->_video->setFile(&_bigfile);
+}
+
+void EdenGame::closebigfile() {
+ _bigfile.close();
+}
+
+void EdenGame::loadRawFile(uint16 num, byte *buffer) {
+ if (_vm->getPlatform() == Common::kPlatformDOS) {
+ if ((_vm->isDemo() && num > 2204) || num > 2472)
+ error("Trying to read invalid game resource");
+ }
+
+ assert(num < _bigfileHeader->_count);
+ PakHeaderItem *file = &_bigfileHeader->_files[num];
+ int32 size = file->_size;
+ int32 offs = file->_offs;
+
+ _bigfile.seek(offs, SEEK_SET);
+ _bigfile.read(buffer, size);
+}
+
+void EdenGame::loadIconFile(uint16 num, Icon *buffer) {
+ if (_vm->getPlatform() == Common::kPlatformDOS) {
+ if ((_vm->isDemo() && num > 2204) || num > 2472)
+ error("Trying to read invalid game resource");
+ }
+
+ assert(num < _bigfileHeader->_count);
+ PakHeaderItem *file = &_bigfileHeader->_files[num];
+ int32 size = file->_size;
+ int32 offs = file->_offs;
+ debug("* Loading icon - Resource %d (%s) at 0x%X, %d bytes", num, file->_name.c_str(), offs, size);
+ _bigfile.seek(offs, SEEK_SET);
+
+ int count = size / sizeof(Icon);
+ for (int i = 0; i < count; i++) {
+ if (_vm->getPlatform() == Common::kPlatformMacintosh) {
+ buffer[i].sx = _bigfile.readSint16BE();
+ buffer[i].sy = _bigfile.readSint16BE();
+ buffer[i].ex = _bigfile.readSint16BE();
+ buffer[i].ey = _bigfile.readSint16BE();
+ buffer[i]._cursorId = _bigfile.readUint16BE();;
+ buffer[i]._actionId= _bigfile.readUint32BE();;
+ buffer[i]._objectId= _bigfile.readUint32BE();;
+ } else {
+ buffer[i].sx = _bigfile.readSint16LE();
+ buffer[i].sy = _bigfile.readSint16LE();
+ buffer[i].ex = _bigfile.readSint16LE();
+ buffer[i].ey = _bigfile.readSint16LE();
+ buffer[i]._cursorId = _bigfile.readUint16LE();;
+ buffer[i]._actionId= _bigfile.readUint32LE();;
+ buffer[i]._objectId= _bigfile.readUint32LE();;
+ }
+ }
+}
+
+void EdenGame::loadRoomFile(uint16 num, Room *buffer) {
+ if (_vm->getPlatform() == Common::kPlatformDOS) {
+ if ((_vm->isDemo() && num > 2204) || num > 2472)
+ error("Trying to read invalid game resource");
+ }
+
+ assert(num < _bigfileHeader->_count);
+ PakHeaderItem *file = &_bigfileHeader->_files[num];
+ int32 size = file->_size;
+ int32 offs = file->_offs;
+ debug("* Loading room - Resource %d (%s) at 0x%X, %d bytes", num, file->_name.c_str(), offs, size);
+ _bigfile.seek(offs, SEEK_SET);
+
+ int count = size / sizeof(Room);
+ for (int i = 0; i < count; i++) {
+ buffer[i]._id = _bigfile.readByte();
+ for (int j = 0; j < 4; j++)
+ buffer[i]._exits[j] = _bigfile.readByte();
+ buffer[i]._flags = _bigfile.readByte();
+ if (_vm->getPlatform() == Common::kPlatformMacintosh) {
+ buffer[i]._bank = _bigfile.readUint16BE();
+ buffer[i]._party = _bigfile.readUint16BE();
+ } else {
+ buffer[i]._bank = _bigfile.readUint16LE();
+ buffer[i]._party = _bigfile.readUint16LE();
+ }
+ buffer[i]._level = _bigfile.readByte();
+ buffer[i]._video = _bigfile.readByte();
+ buffer[i]._location = _bigfile.readByte();
+ buffer[i]._backgroundBankNum = _bigfile.readByte();
+ }
+}
+
+// Original name: shnmfl
+void EdenGame::loadHnm(uint16 num) {
+ unsigned int resNum = num - 1 + 485;
+ assert(resNum < _bigfileHeader->_count);
+ PakHeaderItem *file = &_bigfileHeader->_files[resNum];
+ int size = file->_size;
+ int offs = file->_offs;
+ debug("* Loading movie %d (%s) at 0x%X, %d bytes", num, file->_name.c_str(), (uint)offs, size);
+ _vm->_video->_file->seek(offs, SEEK_SET);
+}
+
+// Original name: ssndfl
+int EdenGame::loadSound(uint16 num) {
+ unsigned int resNum = num - 1 + ((_vm->getPlatform() == Common::kPlatformDOS && _vm->isDemo()) ? 656 : 661);
+ assert(resNum < _bigfileHeader->_count);
+ PakHeaderItem *file = &_bigfileHeader->_files[resNum];
+ int32 size = file->_size;
+ int32 offs = file->_offs;
+ debug("* Loading sound %d (%s) at 0x%X, %d bytes", num, file->_name.c_str(), (uint)offs, size);
+ if (_soundAllocated) {
+ free(_voiceSamplesBuffer);
+ _voiceSamplesBuffer = nullptr;
+ _soundAllocated = false; //TODO: bug??? no alloc
+ } else {
+ _voiceSamplesBuffer = (byte *)malloc(size);
+ _soundAllocated = true;
+ }
+
+ _bigfile.seek(offs, SEEK_SET);
+ //For PC loaded data is a VOC file, on Mac version this is a raw samples
+ if (_vm->getPlatform() == Common::kPlatformMacintosh)
+ _bigfile.read(_voiceSamplesBuffer, size);
+ else {
+ // VOC files also include extra information for lipsync
+ // 1. Standard VOC header
+ _bigfile.read(_voiceSamplesBuffer, 0x1A);
+
+ // 2. Lipsync?
+ unsigned char chunkType = _bigfile.readByte();
+
+ uint32 val = 0;
+ _bigfile.read(&val, 3);
+ unsigned int chunkLen = LE32(val);
+
+ if (chunkType == 5) {
+ _bigfile.read(_gameLipsync + 7260, chunkLen);
+ chunkType = _bigfile.readByte();
+ _bigfile.read(&val, 3);
+ chunkLen = LE32(val);
+ }
+
+ // 3. Normal sound data
+ if (chunkType == 1) {
+ _bigfile.readUint16LE();
+ size = chunkLen - 2;
+ _bigfile.read(_voiceSamplesBuffer, size);
+ }
+ }
+
+ return size;
+}
+
+void EdenGame::convertMacToPC() {
+ // Convert all mac (big-endian) resources to native format
+ // Array of longs
+ int *p = (int *)_gameLipsync;
+ for (int i = 0; i < 7240 / 4; i++)
+ p[i] = BE32(p[i]);
+}
+
+void EdenGame::loadpermfiles() {
+ switch (_vm->getPlatform()) {
+ case Common::kPlatformDOS:
+ {
+ // Since PC version stores hotspots and rooms info in the executable, load them from premade resource file
+ Common::File f;
+
+ if (f.open("led.dat")) {
+ const int kNumIcons = 136;
+ const int kNumRooms = 424;
+ if (f.size() != kNumIcons * sizeof(Icon) + kNumRooms * sizeof(Room))
+ error("Mismatching aux data");
+ for (int i = 0; i < kNumIcons; i++) {
+ _gameIcons[i].sx = f.readSint16LE();
+ _gameIcons[i].sy = f.readSint16LE();
+ _gameIcons[i].ex = f.readSint16LE();
+ _gameIcons[i].ey = f.readSint16LE();
+ _gameIcons[i]._cursorId = f.readUint16LE();
+ _gameIcons[i]._actionId = f.readUint32LE();
+ _gameIcons[i]._objectId = f.readUint32LE();
+ }
+
+ for (int i = 0; i <kNumRooms; i++) {
+ _gameRooms[i]._id = f.readByte();
+ for (int j = 0; j < 4; j++)
+ _gameRooms[i]._exits[j] = f.readByte();
+ _gameRooms[i]._flags = f.readByte();
+ _gameRooms[i]._bank = f.readUint16LE();
+ _gameRooms[i]._party = f.readUint16LE();
+ _gameRooms[i]._level = f.readByte();
+ _gameRooms[i]._video = f.readByte();
+ _gameRooms[i]._location = f.readByte();
+ _gameRooms[i]._backgroundBankNum = f.readByte();
+ }
+
+ f.close();
+ } else
+ error("Can not load aux data");
+ }
+ break;
+ case Common::kPlatformMacintosh:
+ loadIconFile(2498, _gameIcons);
+ loadRoomFile(2497, _gameRooms);
+ loadRawFile(2486, _gameLipsync);
+ convertMacToPC();
+ break;
+ default:
+ error("Unsupported platform");
+ }
+
+ loadRawFile(0, _mainBankBuf);
+ loadRawFile(402, _gameFont);
+ loadRawFile(404, _gameDialogs);
+ loadRawFile(403, _gameConditions);
+}
+
+bool EdenGame::ReadDataSyncVOC(unsigned int num) {
+ unsigned int resNum = num - 1 + ((_vm->getPlatform() == Common::kPlatformDOS && _vm->isDemo()) ? 656 : 661);
+ unsigned char vocHeader[0x1A];
+ int filePos = 0;
+ loadpartoffile(resNum, vocHeader, filePos, sizeof(vocHeader));
+ filePos += sizeof(vocHeader);
+ unsigned char chunkType = 0;
+ loadpartoffile(resNum, &chunkType, sizeof(vocHeader), 1);
+ filePos++;
+ if (chunkType == 5) {
+ uint32 chunkLen = 0;
+ loadpartoffile(resNum, &chunkLen, filePos, 3);
+ filePos += 3;
+ chunkLen = LE32(chunkLen);
+ loadpartoffile(resNum, _gameLipsync + 7260, filePos, chunkLen);
+ return true;
+ }
+ return false;
+}
+
+bool EdenGame::ReadDataSync(uint16 num) {
+ if (_vm->getPlatform() == Common::kPlatformMacintosh) {
+ long pos = READ_LE_UINT32(_gameLipsync + num * 4);
+ if (pos != -1) {
+ long len = 1024;
+ loadpartoffile(1936, _gameLipsync + 7260, pos, len);
+ return true;
+ }
+ } else
+ return ReadDataSyncVOC(num + 1); //TODO: remove -1 in caller
+ return false;
+}
+
+void EdenGame::loadpartoffile(uint16 num, void *buffer, int32 pos, int32 len) {
+ assert(num < _bigfileHeader->_count);
+ PakHeaderItem *file = &_bigfileHeader->_files[num];
+ int32 offs = READ_LE_UINT32(&file->_offs);
+ debug("* Loading partial resource %d (%s) at 0x%X(+0x%X), %d bytes", num, file->_name.c_str(), offs, pos, len);
+ _bigfile.seek(offs + pos, SEEK_SET);
+ _bigfile.read(buffer, len);
+}
+
+void EdenGame::expandHSQ(byte *input, byte *output) {
+ byte *src = input;
+ byte *dst = output;
+ byte *ptr;
+ uint16 bit; // bit
+ uint16 queue = 0; // queue
+ uint16 len = 0;
+ int16 ofs;
+#define GetBit \
+ bit = queue & 1; \
+ queue >>= 1; \
+ if (!queue) { \
+ queue = (src[1] << 8) | src[0]; src += 2; \
+ bit = queue & 1; \
+ queue = (queue >> 1) | 0x8000; \
+ }
+
+ for (;;) {
+ GetBit;
+ if (bit)
+ *dst++ = *src++;
+ else {
+ len = 0;
+ GetBit;
+ if (!bit) {
+ GetBit;
+ len = (len << 1) | bit;
+ GetBit;
+ len = (len << 1) | bit;
+ ofs = 0xFF00 | *src++; //TODO: -256
+ } else {
+ ofs = (src[1] << 8) | src[0];
+ src += 2;
+ len = ofs & 7;
+ ofs = (ofs >> 3) | 0xE000;
+ if (!len) {
+ len = *src++;
+ if (!len)
+ break;
+ }
+ }
+ ptr = dst + ofs;
+ len += 2;
+ while (len--)
+ *dst++ = *ptr++;
+ }
+ }
+}
+
+//////
+
+// Original name: ajouinfo
+void EdenGame::addInfo(byte info) {
+ byte idx = _globals->_nextInfoIdx;
+ if (kPersons[PER_ELOI]._roomNum)
+ info |= 0x80;
+ _infoList[idx] = info;
+ if (idx == _globals->_lastInfoIdx)
+ _globals->_lastInfo = info;
+ idx++;
+ if (idx == 16)
+ idx = 0;
+ _globals->_nextInfoIdx = idx;
+}
+
+void EdenGame::unlockInfo() {
+ for (byte idx = 0; idx < 16; idx++) {
+ if (_infoList[idx] != 0xFF)
+ _infoList[idx] &= ~0x80;
+ }
+ _globals->_lastInfo &= ~0x80;
+}
+
+void EdenGame::nextInfo() {
+ do {
+ byte idx = _globals->_lastInfoIdx;
+ _infoList[idx] = 0;
+ idx++;
+ if (idx == 16)
+ idx = 0;
+ _globals->_lastInfoIdx = idx;
+ _globals->_lastInfo = _infoList[idx];
+ } while (_globals->_lastInfo == 0xFF);
+}
+
+// Original name: delinfo
+void EdenGame::removeInfo(byte info) {
+ for (byte idx = 0; idx < 16; idx++) {
+ if ((_infoList[idx] & ~0x80) == info) {
+ _infoList[idx] = 0xFF;
+ if (idx == _globals->_lastInfoIdx)
+ nextInfo();
+ break;
+ }
+ }
+}
+
+void EdenGame::updateInfoList() {
+ for (int idx = 0; idx < 16; idx++)
+ _infoList[idx] = 0;
+}
+
+void EdenGame::initGlobals() {
+ _gameIcons[16]._cursorId |= 0x8000;
+
+ _globals->_areaNum = Areas::arMo;
+ _globals->_areaVisitCount = 1;
+ _globals->_menuItemIdLo = 0;
+ _globals->_menuItemIdHi = 0;
+ _globals->_randomNumber = 0;
+ _globals->_gameTime = 0;
+ _globals->_gameDays = 0;
+ _globals->_chrono = 0;
+ _globals->_eloiDepartureDay = 0;
+ _globals->_roomNum = 259;
+ _globals->_newRoomNum = 0;
+ _globals->_phaseNum = 0;
+ _globals->_metPersonsMask1 = 0;
+ _globals->_party = 0;
+ _globals->_partyOutside = 0;
+ _globals->_metPersonsMask2 = 0;
+ _globals->_phaseActionsCount = 0;
+ _globals->_curAreaFlags = 0;
+ _globals->_curItemsMask = 0;
+ _globals->_curPowersMask = 0;
+ _globals->_curPersoItems = 0;
+ _globals->_curCharacterPowers = 0;
+ _globals->_wonItemsMask = 0;
+ _globals->_wonPowersMask = 0;
+ _globals->_stepsToFindAppleFast = 0;
+ _globals->_stepsToFindAppleNormal = 0;
+ _globals->_roomPersoItems = 0;
+ _globals->_roomCharacterPowers = 0;
+ _globals->_gameFlags = GameFlags::gfNone;
+ _globals->_curVideoNum = 0;
+ _globals->_morkusSpyVideoNum1 = 89;
+ _globals->_morkusSpyVideoNum2 = 88;
+ _globals->_morkusSpyVideoNum3 = 83;
+ _globals->_morkusSpyVideoNum4 = 94;
+ _globals->_newMusicType = MusicType::mtDontChange;
+ _globals->_var43 = 0;
+ _globals->_videoSubtitleIndex = 0;
+ _globals->_partyInstruments = 0;
+ _globals->_monkGotRing = 0;
+ _globals->_chronoFlag = 0;
+ _globals->_curRoomFlags = 0;
+ _globals->_endGameFlag = 0;
+ _globals->_lastInfo = 0;
+ _globals->_autoDialog = false;
+ _globals->_worldTyranSighted = 0;
+ _globals->_var4D = 0;
+ _globals->_var4E = 0;
+ _globals->_worldGaveGold = 0;
+ _globals->_worldHasTriceraptors = 0;
+ _globals->_worldHasVelociraptors = 0;
+ _globals->_worldHasTyran = 0;
+ _globals->_var53 = 0;
+ _globals->_var54 = 0;
+ _globals->_var55 = 0;
+ _globals->_gameHours = 0;
+ _globals->_textToken1 = 0;
+ _globals->_textToken2 = 0;
+ _globals->_eloiHaveNews = 0;
+ _globals->_dialogFlags = 0;
+ _globals->_curAreaType = 0;
+ _globals->_curCitadelLevel = 0;
+ _globals->_newLocation = 0;
+ _globals->_prevLocation = 0;
+ _globals->_curPersoFlags = 0;
+ _globals->_var60 = 0;
+ _globals->_eventType = EventType::etEvent5;
+ _globals->_var62 = 0;
+ _globals->_curObjectId = 0;
+ _globals->_curObjectFlags = 0;
+ _globals->_var65 = 1;
+ _globals->_roomCharacterType = 0;
+ _globals->_roomCharacterFlags = 0;
+ _globals->_narratorSequence = 0;
+ _globals->_var69 = 0;
+ _globals->_var6A = 0;
+ _globals->_frescoNumber = 0;
+ _globals->_var6C = 0;
+ _globals->_var6D = 0;
+ _globals->_labyrinthDirections = 0;
+ _globals->_labyrinthRoom = 0;
+ _globals->_curCharacterAnimPtr = nullptr;
+ _globals->_characterImageBank = 0;
+ _globals->_roomImgBank = 0;
+ _globals->_characterBackgroundBankIdx = 55;
+ _globals->_varD4 = 0;
+ _globals->_frescoeWidth = 0;
+ _globals->_frescoeImgBank = 0;
+ _globals->_varDA = 0;
+ _globals->_varDC = 0;
+ _globals->_roomBaseX = 0;
+ _globals->_varE0 = 0;
+ _globals->_dialogType = DialogType::dtTalk;
+ _globals->_varE4 = 0;
+ _globals->_currMusicNum = 0;
+ _globals->_textNum = 0;
+ _globals->_travelTime = 0;
+ _globals->_varEC = 0;
+ _globals->_displayFlags = DisplayFlags::dfFlag1;
+ _globals->_oldDisplayFlags = 1;
+ _globals->_drawFlags = 0;
+ _globals->_varF1 = 0;
+ _globals->_varF2 = 0;
+ _globals->_menuFlags = 0;
+ _globals->_varF5 = 0;
+ _globals->_varF6 = 0;
+ _globals->_varF7 = 0;
+ _globals->_varF8 = 0;
+ _globals->_varF9 = 0;
+ _globals->_varFA = 0;
+ _globals->_animationFlags = 0;
+ _globals->_giveObj1 = 0;
+ _globals->_giveObj2 = 0;
+ _globals->_giveObj3 = 0;
+ _globals->_var100 = 0;
+ _globals->_roomVidNum = 0;
+ _globals->_mirrorEffect = 0;
+ _globals->_var103 = 0;
+ _globals->_roomBackgroundBankNum = 0;
+ _globals->_valleyVidNum = 0;
+ _globals->_updatePaletteFlag = 0;
+ _globals->_inventoryScrollPos = 0;
+ _globals->_objCount = 0;
+ _globals->_textBankIndex = 69;
+ _globals->_citadelAreaNum = 0;
+ _globals->_var113 = 0;
+ _globals->_lastPlaceNum = 0;
+ _globals->_dialogPtr = nullptr;
+ _globals->_tapePtr = _tapes;
+ _globals->_nextDialogPtr = nullptr;
+ _globals->_narratorDialogPtr = nullptr;
+ _globals->_lastDialogPtr = nullptr;
+ _globals->_nextRoomIcon = nullptr;
+ _globals->_sentenceBufferPtr = nullptr;
+ _globals->_roomPtr = nullptr;
+ _globals->_areaPtr = nullptr;
+ _globals->_lastAreaPtr = nullptr;
+ _globals->_curAreaPtr = nullptr;
+ _globals->_citaAreaFirstRoom = 0;
+ _globals->_characterPtr = nullptr;
+ _globals->_roomCharacterPtr = 0;
+ _globals->_lastInfoIdx = 0;
+ _globals->_nextInfoIdx = 0;
+ _globals->_iconsIndex = 16;
+ _globals->_persoSpritePtr = nullptr;
+ _globals->_numGiveObjs = 0;
+
+ initRects();
+
+ _underSubtitlesScreenRect.top = 0;
+ _underSubtitlesScreenRect.left = _subtitlesXScrMargin;
+ _underSubtitlesScreenRect.right = _subtitlesXScrMargin + _subtitlesXWidth - 1;
+ _underSubtitlesScreenRect.bottom = 176 - 1;
+
+ _underSubtitlesBackupRect.top = 0;
+ _underSubtitlesBackupRect.left = _subtitlesXScrMargin;
+ _underSubtitlesBackupRect.right = _subtitlesXScrMargin + _subtitlesXWidth - 1;
+ _underSubtitlesBackupRect.bottom = 60 - 1;
+}
+
+void EdenGame::initRects() {
+ _underTopBarScreenRect = Common::Rect(0, 0, 320 - 1, 16 - 1);
+ _underTopBarBackupRect = Common::Rect(0, 0, 320 - 1, 16 - 1);
+ _underBottomBarScreenRect = Common::Rect(0, 176, 320 - 1, 200 - 1); //TODO: original bug? this cause crash in copyrect (this, underBottomBarBackupRect)
+ _underBottomBarBackupRect = Common::Rect(0, 16, 320 - 1, 40 - 1);
+}
+
+// Original name: closesalle
+void EdenGame::closeRoom() {
+ if (_globals->_displayFlags & DisplayFlags::dfPanable) {
+ _globals->_displayFlags &= ~DisplayFlags::dfPanable;
+ resetScroll();
+ }
+}
+
+// Original name afsalle1
+void EdenGame::displaySingleRoom(Room *room) {
+ byte *ptr = (byte *)getElem(_placeRawBuf, room->_id - 1);
+ ptr++;
+ for (;;) {
+ byte b0 = *ptr++;
+ byte b1 = *ptr++;
+ int16 index = (b1 << 8) | b0;
+ if (index == -1)
+ break;
+ if (index > 0) {
+ int16 x = *ptr++ | (((b1 & 0x2) >> 1) << 8); //TODO: check me
+ int16 y = *ptr++;
+ ptr++;
+ index &= 0x1FF;
+ if (!(_globals->_displayFlags & 0x80)) {
+ if (index == 1 || _globals->_varF7)
+ noclipax_avecnoir(index - 1, x, y);
+ }
+ _globals->_varF7 = 0;
+ continue;
+ }
+ if (b1 & 0x40) {
+ if (b1 & 0x20) {
+ bool addIcon = false;
+ Icon *icon = _globals->_nextRoomIcon;
+ if (b0 < 4) {
+ if (_globals->_roomPtr->_exits[b0])
+ addIcon = true;
+ } else if (b0 > 229) {
+ if (_globals->_partyOutside & (1 << (b0 - 230)))
+ addIcon = true;
+ } else if (b0 >= 100) {
+ debug("add object %d", b0 - 100);
+ if (isObjectHere(b0 - 100)) {
+ addIcon = true;
+ _globals->_varF7 = 1;
+ }
+ } else
+ addIcon = true;
+ if (addIcon) {
+ icon->_actionId = b0;
+ icon->_objectId = b0;
+ icon->_cursorId = kActionCursors[b0];
+ int16 x = READ_LE_UINT16(ptr);
+ ptr += 2;
+ int16 y = READ_LE_UINT16(ptr);
+ ptr += 2;
+ int16 ex = READ_LE_UINT16(ptr);
+ ptr += 2;
+ int16 ey = READ_LE_UINT16(ptr);
+ ptr += 2;
+ x += _globals->_roomBaseX;
+ ex += _globals->_roomBaseX;
+ debug("add hotspot at %3d:%3d - %3d:%3d, action = %d", x, y, ex, ey, b0);
+
+ if (_vm->_showHotspots) {
+ for (int iii = x; iii < ex; iii++)
+ _mainViewBuf[y * 640 + iii] = _mainViewBuf[ey * 640 + iii] = (iii % 2) ? 0 : 255;
+ for (int iii = y; iii < ey; iii++)
+ _mainViewBuf[iii * 640 + x] = _mainViewBuf[iii * 640 + ex] = (iii % 2) ? 0 : 255;
+ }
+
+ icon->sx = x;
+ icon->sy = y;
+ icon->ex = ex;
+ icon->ey = ey;
+ _globals->_nextRoomIcon = ++icon;
+ icon->sx = -1;
+ } else
+ ptr += 8;
+ } else
+ ptr += 8;
+ } else
+ ptr += 8;
+ }
+}
+
+// Original name: afsalle
+void EdenGame::displayRoom() {
+ Room *room = _globals->_roomPtr;
+ _globals->_displayFlags = DisplayFlags::dfFlag1;
+ _globals->_roomBaseX = 0;
+ _globals->_roomBackgroundBankNum = room->_backgroundBankNum;
+ if (room->_flags & RoomFlags::rf08) {
+ _globals->_displayFlags |= DisplayFlags::dfFlag80;
+ if (room->_flags & RoomFlags::rfPanable) {
+ // Scrollable room on 2 screens
+ _globals->_displayFlags |= DisplayFlags::dfPanable;
+ _globals->_varF4 = 0;
+ rundcurs();
+ saveFriezes();
+ useBank(room->_bank - 1);
+ noclipax_avecnoir(0, 0, 16);
+ useBank(room->_bank);
+ noclipax_avecnoir(0, 320, 16);
+ displaySingleRoom(room);
+ _globals->_roomBaseX = 320;
+ displaySingleRoom(room + 1);
+ } else
+ displaySingleRoom(room);
+ } else {
+ //TODO: roomImgBank is garbage here!
+ debug("displayRoom: room 0x%X using bank %d", _globals->_roomNum, _globals->_roomImgBank);
+ useBank(_globals->_roomImgBank);
+ displaySingleRoom(room);
+ assert(_vm->_screenView->_pitch == 320);
+ }
+}
+
+// Original name: aflieu
+void EdenGame::displayPlace() {
+ no_perso();
+ if (!_vm->shouldQuit()) {
+ _globals->_iconsIndex = 16;
+ _globals->_autoDialog = false;
+ }
+ _globals->_nextRoomIcon = &_gameIcons[_roomIconsBase];
+ displayRoom();
+ _paletteUpdateRequired = true;
+}
+
+// Original name: loadsal
+void EdenGame::loadPlace(int16 num) {
+ if (num == _globals->_lastPlaceNum)
+ return;
+ _globals->_lastPlaceNum = num;
+ loadRawFile(num + 419, _placeRawBuf);
+}
+
+void EdenGame::specialoutside() {
+ if (_globals->_lastAreaPtr->_type == AreaType::atValley && (_globals->_party & PersonMask::pmLeader))
+ perso_ici(5);
+}
+
+void EdenGame::specialout() {
+ if (_globals->_gameDays - _globals->_eloiDepartureDay > 2) {
+ if (checkEloiReturn())
+ handleEloiReturn();
+ }
+
+ if (_globals->_phaseNum >= 32 && _globals->_phaseNum < 48) {
+ if (_globals->_newLocation == 9 || _globals->_newLocation == 4 || _globals->_newLocation == 24) {
+ kPersons[PER_ELOI]._roomNum = 263;
+ return;
+ }
+ }
+
+ if ((_globals->_phaseNum == 434) && (_globals->_newLocation == 5)) {
+ removeFromParty(PER_JABBER);
+ kPersons[PER_JABBER]._roomNum = 264;
+ return;
+ }
+
+ if (_globals->_phaseNum < 400) {
+ if ((_globals->_gameFlags & GameFlags::gfFlag4000) && _globals->_prevLocation == 1
+ && (_globals->_party & PersonMask::pmEloi) && _globals->_curAreaType == AreaType::atValley)
+ handleEloiDeparture();
+ }
+
+ if (_globals->_phaseNum == 386) {
+ if (_globals->_prevLocation == 1
+ && (_globals->_party & PersonMask::pmEloi) && _globals->_areaNum == Areas::arCantura)
+ handleEloiDeparture();
+ }
+}
+
+void EdenGame::specialin() {
+ if (!(_globals->_party & PersonMask::pmEloi) && (_globals->_partyOutside & PersonMask::pmEloi) && (_globals->_roomNum & 0xFF) == 1) {
+ addToParty(PER_ELOI);
+ _globals->_eloiHaveNews = 1;
+ }
+ if (_globals->_roomNum == 288)
+ _globals->_gameFlags |= GameFlags::gfFlag100 | GameFlags::gfFlag2000;
+ if (_globals->_roomNum == 3075 && _globals->_phaseNum == 546) {
+ incPhase();
+ if (_globals->_curItemsMask & 0x2000) { // Morkus' tablet
+ hideBars();
+ playHNM(92);
+ _gameRooms[129]._exits[0] = 0;
+ _gameRooms[129]._exits[2] = 1;
+ _globals->_roomNum = 3074;
+ kPersons[PER_MUNGO]._roomNum = 3074;
+ _globals->_eventType = EventType::etEvent5;
+ updateRoom(_globals->_roomNum);
+ return;
+ }
+ _globals->_narratorSequence = 53;
+ }
+ if (_globals->_roomNum == 1793 && _globals->_phaseNum == 336)
+ handleEloiDeparture();
+ if (_globals->_roomNum == 259 && _globals->_phaseNum == 129)
+ _globals->_narratorSequence = 12;
+ if (_globals->_roomNum >= 289 && _globals->_roomNum < 359)
+ _globals->_labyrinthDirections = kLabyrinthPath[(_globals->_roomNum & 0xFF) - 33];
+ if (_globals->_roomNum == 305 && _globals->_prevLocation == 103)
+ _globals->_gameFlags &= ~GameFlags::gfFlag2000;
+ if (_globals->_roomNum == 304 && _globals->_prevLocation == 105)
+ _globals->_gameFlags &= ~GameFlags::gfFlag2000;
+ if (_globals->_phaseNum < 226) {
+ if (_globals->_roomNum == 842)
+ _globals->_gameFlags |= GameFlags::gfFlag2;
+ if (_globals->_roomNum == 1072)
+ _globals->_gameFlags |= GameFlags::gfFlag4;
+ if (_globals->_roomNum == 1329)
+ _globals->_gameFlags |= GameFlags::gfFlag8000;
+ }
+}
+
+void EdenGame::animpiece() {
+ Room *room = _globals->_roomPtr;
+ if (_globals->_roomVidNum && _globals->_var100 != 0xFF) {
+ if (_globals->_valleyVidNum || !room->_level || (room->_flags & RoomFlags::rfHasCitadel)
+ || room->_level == _globals->_var100) {
+ hideBars();
+ _globals->_updatePaletteFlag = 16;
+ if (!(_globals->_narratorSequence & 0x80)) //TODO: bug? !() @ 100DC
+ _globals->_mirrorEffect = 0;
+ if (!_needToFade)
+ _needToFade = room->_flags & RoomFlags::rf02;
+ playHNM(_globals->_roomVidNum);
+ return;
+ }
+ }
+ _globals->_varF1 &= ~RoomFlags::rf04;
+}
+
+void EdenGame::getdino(Room *room) {
+ assert(tab_2CEF0[4] == 0x25);
+
+ room->_flags &= ~0xC;
+ for (perso_t *perso = &kPersons[PER_UNKN_18C]; perso->_roomNum != 0xFFFF; perso++) {
+ if (perso->_flags & PersonFlags::pf80)
+ continue;
+ if (perso->_roomNum != _globals->_roomNum)
+ continue;
+ byte persoType = perso->_flags & PersonFlags::pfTypeMask;
+ if (persoType == PersonFlags::pftVelociraptor)
+ removeInfo(_globals->_citadelAreaNum + ValleyNews::vnVelociraptorsIn);
+ if (persoType == PersonFlags::pftTriceraptor)
+ removeInfo(_globals->_citadelAreaNum + ValleyNews::vnTriceraptorsIn);
+ perso->_flags |= PersonFlags::pf20;
+ int16 *tab = tab_2CF70;
+ if (_globals->_areaNum != Areas::arUluru && _globals->_areaNum != Areas::arTamara)
+ tab = tab_2CEF0;
+ byte r27 = (room->_flags & 0xC0) >> 2; //TODO: check me (like pc)
+ persoType = perso->_flags & PersonFlags::pfTypeMask;
+ if (persoType == PersonFlags::pftTyrann)
+ persoType = 13;
+ r27 |= (persoType & 7) << 1; //TODO: check me 13 & 7 = ???
+ tab += r27;
+ _globals->_roomVidNum = *tab++;
+ int16 bank = *tab;
+ if (bank & 0x8000) {
+ bank &= ~0x8000;
+ room->_flags |= RoomFlags::rf08;
+ }
+ room->_flags |= RoomFlags::rf04 | RoomFlags::rf02;
+ _globals->_roomImgBank = bank;
+ break;
+ }
+}
+
+// Original name: getsalle
+Room *EdenGame::getRoom(int16 loc) { //TODO: byte?
+ debug("get room for %X, starting from %d, looking for %X", loc, _globals->_areaPtr->_firstRoomIdx, _globals->_partyOutside);
+ Room *room = &_gameRooms[_globals->_areaPtr->_firstRoomIdx];
+ loc &= 0xFF;
+ for (;; room++) {
+ for (; room->_location != loc; room++) {
+ if (room->_id == 0xFF)
+ return nullptr;
+ }
+ if (_globals->_partyOutside == room->_party || room->_party == 0xFFFF)
+ break;
+ }
+ debug("found room: party = %X, bank = %X", room->_party, room->_bank);
+ _globals->_roomImgBank = room->_bank;
+ _globals->_labyrinthRoom = 0;
+ if (_globals->_roomImgBank > 104 && _globals->_roomImgBank <= 112)
+ _globals->_labyrinthRoom = _globals->_roomImgBank - 103;
+ if (_globals->_valleyVidNum)
+ _globals->_roomVidNum = _globals->_valleyVidNum;
+ else
+ _globals->_roomVidNum = room->_video;
+ if ((room->_flags & 0xC0) == RoomFlags::rf40 || (room->_flags & RoomFlags::rf01))
+ getdino(room);
+ if (room->_flags & RoomFlags::rfHasCitadel) {
+ removeInfo(_globals->_areaNum + ValleyNews::vnCitadelLost);
+ removeInfo(_globals->_areaNum + ValleyNews::vnTyrannIn);
+ removeInfo(_globals->_areaNum + ValleyNews::vnTyrannLost);
+ removeInfo(_globals->_areaNum + ValleyNews::vnVelociraptorsLost);
+ }
+ if (istyran(_globals->_roomNum))
+ _globals->_gameFlags |= GameFlags::gfFlag10;
+ else
+ _globals->_gameFlags &= ~GameFlags::gfFlag10;
+ return room;
+}
+
+// Original name: initlieu
+void EdenGame::initPlace(int16 roomNum) {
+ _globals->_gameFlags |= GameFlags::gfFlag4000;
+ _gameIcons[18]._cursorId |= 0x8000;
+ _globals->_lastAreaPtr = _globals->_areaPtr;
+ _globals->_areaPtr = &kAreasTable[((roomNum >> 8) & 0xFF) - 1];
+ Area *area = _globals->_areaPtr;
+ area->_visitCount++;
+ _globals->_areaVisitCount = area->_visitCount;
+ _globals->_curAreaFlags = area->_flags;
+ _globals->_curAreaType = area->_type;
+ _globals->_curCitadelLevel = area->_citadelLevel;
+ if (_globals->_curAreaType == AreaType::atValley)
+ _gameIcons[18]._cursorId &= ~0x8000;
+ loadPlace(area->_placeNum);
+}
+
+void EdenGame::maj2() {
+ displayPlace();
+ assert(_vm->_screenView->_pitch == 320);
+ if (_globals->_roomNum == 273 && _globals->_prevLocation == 18)
+ _globals->_mirrorEffect = 1;
+ if (_globals->_eventType == EventType::etEventC) {
+ drawTopScreen();
+ showObjects();
+ }
+ FRDevents();
+ assert(_vm->_screenView->_pitch == 320);
+ bool r30 = false;
+ if (_globals->_curAreaType == AreaType::atValley && !(_globals->_displayFlags & DisplayFlags::dfPanable))
+ r30 = true;
+ //TODO: ^^ inlined func?
+
+ if (_globals->_mirrorEffect || _globals->_var103)
+ display();
+ else if (_globals->_varF1 == (RoomFlags::rf40 | RoomFlags::rf04 | RoomFlags::rf01)) {
+ drawBlackBars();
+ displayEffect1();
+ } else if (_globals->_varF1 && !(_globals->_varF1 & RoomFlags::rf04) && !r30) {
+ if (!(_globals->_displayFlags & DisplayFlags::dfPanable))
+ drawBlackBars();
+ else if (_globals->_valleyVidNum)
+ drawBlackBars();
+ displayEffect1();
+ } else if (r30 && !(_globals->_varF1 & RoomFlags::rf04))
+ effetpix();
+ else
+ afficher128();
+ musique();
+ if (_globals->_eventType != EventType::etEventC) {
+ drawTopScreen();
+ showObjects();
+ }
+ showBars();
+ showEvents();
+ _globals->_labyrinthDirections = 0;
+ specialin();
+}
+
+// Original name: majsalle1
+void EdenGame::updateRoom1(int16 roomNum) {
+ Room *room = getRoom(roomNum & 0xFF);
+ _globals->_roomPtr = room;
+ debug("DrawRoom: room 0x%X, arg = 0x%X", _globals->_roomNum, roomNum);
+ _globals->_curRoomFlags = room->_flags;
+ _globals->_varF1 = room->_flags;
+ animpiece();
+ _globals->_var100 = 0;
+ maj2();
+}
+
+// Original name: maj_salle
+void EdenGame::updateRoom(uint16 roomNum) {
+ setCharacterHere();
+ updateRoom1(roomNum);
+}
+
+// Original name: initbuf
+void EdenGame::allocateBuffers() {
+#define ALLOC(ptr, size, typ) if (!((ptr) = (typ*)malloc(size))) _bufferAllocationErrorFl = true;
+ ALLOC(_gameRooms, 0x4000, Room);
+ ALLOC(_gameIcons, 0x4000, Icon);
+ ALLOC(_bankDataBuf, 0x10000, byte);
+ ALLOC(_globals, sizeof(*_globals), global_t);
+ ALLOC(_placeRawBuf, 2048, byte);
+ ALLOC(_gameConditions, 0x4800, byte);
+ ALLOC(_gameDialogs, 0x2800, byte);
+ ALLOC(_gamePhrases, 0x10000, byte);
+ ALLOC(_mainBankBuf, 0x9400, byte);
+ ALLOC(_glowBuffer, 0x2800, byte);
+ ALLOC(_gameFont, 0x900, byte);
+ ALLOC(_gameLipsync, 0x205C, byte);
+ ALLOC(_musicBuf, kMaxMusicSize, byte);
+#undef ALLOC
+}
+
+void EdenGame::freebuf() {
+ delete(_bigfileHeader);
+ _bigfileHeader = nullptr;
+
+ free(_gameRooms);
+ free(_gameIcons);
+ free(_bankDataBuf);
+ free(_globals);
+ free(_placeRawBuf);
+ free(_gameConditions);
+ free(_gameDialogs);
+ free(_gamePhrases);
+ free(_mainBankBuf);
+ free(_glowBuffer);
+ free(_gameFont);
+ free(_gameLipsync);
+ free(_musicBuf);
+}
+
+void EdenGame::openWindow() {
+ _underBarsView = new View(320, 40);
+ _underBarsView->_normal._width = 320;
+
+ _view2 = new View(32, 32);
+ _view2Buf = _view2->_bufferPtr;
+
+ _subtitlesView = new View(_subtitlesXWidth, 60);
+ _subtitlesViewBuf = _subtitlesView->_bufferPtr;
+
+ _underSubtitlesView = new View(_subtitlesXWidth, 60);
+ _underSubtitlesViewBuf = _underSubtitlesView->_bufferPtr;
+
+ _mainView = new View(640, 200);
+ _mainView->_normal._width = 320;
+ CLBlitter_FillView(_mainView, 0xFFFFFFFF);
+ _mainView->setSrcZoomValues(0, 0);
+ _mainView->setDisplayZoomValues(640, 400);
+ _mainView->centerIn(_vm->_screenView);
+ _mainViewBuf = _mainView->_bufferPtr;
+
+ _mouseCenterX = _mainView->_normal._dstLeft + _mainView->_normal._width / 2;
+ _mouseCenterY = _mainView->_normal._dstTop + _mainView->_normal._height / 2;
+ _vm->setMousePosition(_mouseCenterX, _mouseCenterY);
+ _vm->hideMouse();
+
+ _cursorPosX = 320 / 2;
+ _cursorPosY = 200 / 2;
+}
+
+void EdenGame::EmergencyExit() {
+ SysBeep(1);
+}
+
+void EdenGame::run() {
+ _invIconsCount = (_vm->getPlatform() == Common::kPlatformMacintosh) ? 9 : 11;
+ _roomIconsBase = _invIconsBase + _invIconsCount;
+
+ word_378CE = 0;
+ CRYOLib_ManagersInit();
+ _vm->_video->setupSound(11025, false, false);
+ _vm->_video->setForceZero2Black(true);
+ _vm->_video->setupTimer(12.5);
+ _voiceSound = new Sound(0, 11025 * 65536.0, 8, 0);
+ _hnmSoundChannel = _vm->_video->getSoundChannel();
+ _voiceSound->setWantsDesigned(1); // CHECKME: Used?
+
+ _musicChannel = new CSoundChannel(_vm->_mixer, 11025, false);
+ _voiceChannel = new CSoundChannel(_vm->_mixer, 11025, false);
+
+ allocateBuffers();
+ openbigfile();
+ openWindow();
+ loadpermfiles();
+
+ if (!_bufferAllocationErrorFl) {
+ LostEdenMac_InitPrefs();
+ if (_vm->getPlatform() == Common::kPlatformMacintosh)
+ initCubeMac();
+ else
+ initCubePC();
+
+ while (!_quitFlag2) {
+ initGlobals();
+ _quitFlag3 = false;
+ _normalCursor = true;
+ _torchCursor = false;
+ _cursKeepPos = Common::Point(-1, -1);
+ if (!_gameLoaded)
+ intro();
+ edmain();
+ startmusique(1);
+ drawBlackBars();
+ display();
+ fadeToBlack(3);
+ clearScreen();
+ playHNM(95);
+ if (_globals->_endGameFlag == 50) {
+ loadrestart();
+ _gameLoaded = false;
+ }
+ fademusica0(2);
+ _musicChannel->stop();
+ _musicPlayingFlag = false;
+ _musicEnabledFlag = false;
+ }
+ // LostEdenMac_SavePrefs();
+ }
+
+ delete _voiceChannel;
+ delete _musicChannel;
+
+ fadeToBlack(4);
+ closebigfile();
+ freebuf();
+ CRYOLib_ManagersDone();
+}
+
+void EdenGame::edmain() {
+ //TODO
+ enterGame();
+ while (!_bufferAllocationErrorFl && !_quitFlag3 && _globals->_endGameFlag != 50) {
+ if (!_gameStarted) {
+ // if in demo mode, reset game after a while
+ _demoCurrentTicks = _vm->_timerTicks;
+ if (_demoCurrentTicks - _demoStartTicks > 3000) {
+ rundcurs();
+ display();
+ fademusica0(2);
+ fadeToBlack(3);
+ CLBlitter_FillScreenView(0);
+ CLBlitter_FillView(_mainView, 0);
+ _musicChannel->stop();
+ _musicPlayingFlag = false;
+ _musicEnabledFlag = false;
+ intro();
+ enterGame();
+ }
+ }
+ rundcurs();
+ musicspy();
+ FRDevents();
+ handleNarrator();
+ chronoEvent();
+ if (_globals->_drawFlags & DrawFlags::drDrawInventory)
+ showObjects();
+ if (_globals->_drawFlags & DrawFlags::drDrawTopScreen)
+ drawTopScreen();
+ if ((_globals->_displayFlags & DisplayFlags::dfPanable) && (_globals->_displayFlags != DisplayFlags::dfPerson))
+ scrollPanel();
+ if ((_globals->_displayFlags & DisplayFlags::dfMirror) && (_globals->_displayFlags != DisplayFlags::dfPerson))
+ scrollMirror();
+ if ((_globals->_displayFlags & DisplayFlags::dfFrescoes) && (_globals->_displayFlags != DisplayFlags::dfPerson))
+ scrollFrescoes();
+ if (_globals->_displayFlags & DisplayFlags::dfFlag2)
+ noclicpanel();
+ if (_animationActive)
+ animCharacter();
+ updateCursor();
+ display();
+ }
+}
+
+void EdenGame::intro() {
+ if (_vm->getPlatform() == Common::kPlatformMacintosh) {
+ // Play intro videos in HQ
+ _hnmSoundChannel->stop();
+ _vm->_video->closeSound();
+ _vm->_video->setupSound(22050, false, true);
+ _hnmSoundChannel = _vm->_video->getSoundChannel();
+ playHNM(2012);
+ playHNM(171);
+ CLBlitter_FillScreenView(0);
+ _specialTextMode = false;
+ playHNM(2001);
+ _hnmSoundChannel->stop();
+ _vm->_video->closeSound();
+ _vm->_video->setupSound(11025, false, false);
+ _hnmSoundChannel = _vm->_video->getSoundChannel();
+ } else {
+ if (_vm->isDemo()) {
+ playHNM(171); // Virgin logo
+ playHNM(98); // Cryo logo
+ }
+ else {
+ playHNM(98); // Cryo logo
+ playHNM(171); // Virgin logo
+ }
+ CLBlitter_FillScreenView(0);
+ _specialTextMode = false;
+ startmusique(2); // INTRO.MUS is played during intro video
+ playHNM(170); // Intro video
+ }
+}
+
+void EdenGame::enterGame() {
+ char flag = 0;
+ _currentTime = _vm->_timerTicks / 100;
+ _globals->_gameTime = _currentTime;
+ _demoStartTicks = _vm->_timerTicks;
+ _gameStarted = false;
+ if (!_gameLoaded) {
+ _globals->_roomNum = 279;
+ _globals->_areaNum = Areas::arMo;
+ _globals->_var100 = 0xFF;
+ initPlace(_globals->_roomNum);
+ _globals->_currMusicNum = 0;
+ startmusique(1);
+ } else {
+ flag = _globals->_autoDialog; //TODO
+ initafterload();
+ byte lastMusicNum = _globals->_currMusicNum; //TODO: ???
+ _globals->_currMusicNum = 0;
+ startmusique(lastMusicNum);
+ _globals->_inventoryScrollPos = 0;
+ _gameStarted = true;
+ }
+ showObjects();
+ drawTopScreen();
+ saveFriezes();
+ _showBlackBars = true;
+ _globals->_mirrorEffect = 1;
+ updateRoom(_globals->_roomNum);
+ if (flag) {
+ _globals->_iconsIndex = 4;
+ _globals->_autoDialog = true;
+ parle_moi();
+ }
+}
+
+void EdenGame::signon(const char *s) {
+}
+
+void EdenGame::FRDevents() {
+ _vm->pollEvents();
+ if (_allowDoubled) {
+#if 0 // CLKeyboard_IsScanCodeDown currently always returns false
+ if (_vm->isScanCodeDown(0x30)) { //TODO: const
+ if (!_keyboardHeld) {
+ _doubledScreen = !_doubledScreen;
+ _mainView->_doubled = _doubledScreen;
+ CLBlitter_FillScreenView(0);
+ _keyboardHeld = true;
+ }
+ } else
+#endif
+ _keyboardHeld = false;
+ }
+
+ int16 mouseY;
+ int16 mouseX;
+ _vm->getMousePosition(&mouseX, &mouseY);
+ mouseX -= _mouseCenterX;
+ mouseY -= _mouseCenterY;
+ _vm->setMousePosition(_mouseCenterX , _mouseCenterY);
+ _cursorPosX += mouseX;
+ _cursorPosX = CLIP<int16>(_cursorPosX, 4, 292);
+ _cursorPosY += mouseY;
+
+ int16 maxY = _globals->_displayFlags == DisplayFlags::dfFlag2 ? 190 : 170;
+ _cursorPosY = CLIP<int16>(_cursorPosY, 4, maxY);
+ _cirsorPanX = _cursorPosX;
+
+ if (_cursorPosY >= 10 && _cursorPosY <= 164 && !(_globals->_displayFlags & DisplayFlags::dfFrescoes))
+ _cirsorPanX += _scrollPos;
+ if (_normalCursor) {
+ _currCursor = 0;
+ _currSpot = scan_icon_list(_cirsorPanX + _cursCenter, _cursorPosY + _cursCenter, _globals->_iconsIndex);
+ if (_currSpot)
+ _currCursor = _currSpot->_cursorId;
+ }
+ if (_cursCenter == 0 && _currCursor != 53) {
+ _cursCenter = 11;
+ _cursorPosX -= 11;
+ }
+ if (_cursCenter == 11 && _currCursor == 53) {
+ _cursCenter = 0;
+ _cursorPosX += 11;
+ }
+ if (_globals->_displayFlags & DisplayFlags::dfPanable) {
+ //TODO: _currSpot may be zero (due to scan_icon_list failure) if cursor slips between hot areas.
+ //fix me here or above?
+ if (_currSpot) { // ok, plug it here
+ _curSpot2 = _currSpot;
+ displayAdamMapMark(_curSpot2->_actionId - 14);
+ }
+ }
+ if (_globals->_displayFlags == DisplayFlags::dfFlag2 && _currSpot)
+ _curSpot2 = _currSpot;
+ if (_globals->_displayFlags & DisplayFlags::dfFrescoes) {
+ if (_frescoTalk)
+ restoreUnderSubtitles();
+ if (_currCursor == 9 && !_torchCursor) {
+ rundcurs();
+ _torchCursor = true;
+ _glowX = -1;
+ }
+ if (_currCursor != 9 && _torchCursor) {
+ unglow();
+ _torchCursor = false;
+ _cursorSaved = false;
+ }
+ }
+ if (_vm->isMouseButtonDown()) {
+ if (!_mouseHeld) {
+ _mouseHeld = true;
+ _gameStarted = true;
+ mouse();
+ }
+ } else
+ _mouseHeld = false;
+ if (_globals->_displayFlags != DisplayFlags::dfFlag2) {
+ if (--_inventoryScrollDelay <= 0) {
+ if (_globals->_objCount > _invIconsCount && _cursorPosY > 164) {
+ if (_cursorPosX > 284 && _globals->_inventoryScrollPos + _invIconsCount < _globals->_objCount) {
+ _globals->_inventoryScrollPos++;
+ _inventoryScrollDelay = 20;
+ showObjects();
+ }
+
+ if (_cursorPosX < 30 && _globals->_inventoryScrollPos != 0) {
+ _globals->_inventoryScrollPos--;
+ _inventoryScrollDelay = 20;
+ showObjects();
+ }
+ }
+ }
+ }
+ if (_inventoryScrollDelay < 0)
+ _inventoryScrollDelay = 0;
+
+ if (_vm->shouldQuit())
+ edenShudown();
+}
+
+Icon *EdenGame::scan_icon_list(int16 x, int16 y, int16 index) {
+ for (Icon *icon = &_gameIcons[index]; icon->sx >= 0; icon++) {
+ if (icon->_cursorId & 0x8000)
+ continue;
+#if 0
+ // MAC version use this check. Same check is present in PC version, but never used
+ // Because of x >= clause two adjacent rooms has 1-pixel wide dead zone between them
+ // On valley view screens if cursor slips in this zone a crash in FRDevents occurs
+ // due to lack of proper checks
+ if (x < icon->ff_0 || x >= icon->ff_4
+ || y < icon->ff_2 || y >= icon->ff_6)
+#else
+ // PC version has this check inlined in FRDevents
+ // Should we keep it or fix edge coordinates in afroom() instead?
+ if (x < icon->sx || x > icon->ex
+ || y < icon->sy || y > icon->ey)
+#endif
+ continue;
+ return icon;
+ }
+ return nullptr;
+}
+
+void EdenGame::updateCursor() {
+ if (++_torchTick > 3)
+ _torchTick = 0;
+ if (!_torchTick) {
+ _torchCurIndex++;
+ _glowIndex++;
+ }
+ if (_torchCurIndex > 8)
+ _torchCurIndex = 0;
+ if (_glowIndex > 4)
+ _glowIndex = 0;
+
+ if (!_torchCursor) {
+ useMainBank();
+ sundcurs(_cursorPosX + _scrollPos, _cursorPosY);
+ if (_currCursor != 53 && _currCursor < 10) { //TODO: cond
+ if (_vm->getPlatform() == Common::kPlatformMacintosh)
+ engineMac();
+ else
+ enginePC();
+ } else
+ noclipax(_currCursor, _cursorPosX + _scrollPos, _cursorPosY);
+ _glowX = 1;
+ } else {
+ useBank(117);
+ if (_cursorPosX > 294)
+ _cursorPosX = 294;
+ unglow();
+ glow(_glowIndex);
+ noclipax(_torchCurIndex, _cursorPosX + _scrollPos, _cursorPosY);
+ if (_frescoTalk)
+ displaySubtitles();
+ }
+}
+
+void EdenGame::mouse() {
+ static void (EdenGame::*mouse_actions[])() = {
+ &EdenGame::actionMoveNorth,
+ &EdenGame::actionMoveEast,
+ &EdenGame::actionMoveSouth,
+ &EdenGame::actionMoveWest,
+ &EdenGame::actionPlateMonk,
+ &EdenGame::actionGraaFrescoe,
+ &EdenGame::actionPushStone,
+ &EdenGame::actionSkelettonHead,
+ &EdenGame::actionMummyHead,
+ &EdenGame::actionMoveNorth,
+ &EdenGame::actionKingDialog1,
+ &EdenGame::actionKingDialog2,
+ &EdenGame::actionKingDialog3,
+ &EdenGame::actionGotoHall,
+ &EdenGame::actionLabyrinthTurnAround,
+ &EdenGame::actionSkelettonMoorkong,
+ &EdenGame::actionGotoFullNest,
+ &EdenGame::actionLookLake,
+ &EdenGame::actionNop,
+ &EdenGame::actionNop,
+ &EdenGame::actionNop,
+ &EdenGame::actionFinal,
+ &EdenGame::actionMoveNorth,
+ &EdenGame::actionMoveSouth,
+ &EdenGame::actionVisit,
+ &EdenGame::actionDinoBlow,
+ &EdenGame::actionLascFrescoe,
+ &EdenGame::actionNop,
+ &EdenGame::actionNop,
+ &EdenGame::actionNop,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ &EdenGame::actionGotoVal,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ &EdenGame::actionNop,
+ &EdenGame::actionNop,
+ &EdenGame::actionNop,
+ &EdenGame::actionNop,
+ &EdenGame::actionNop,
+ &EdenGame::actionGetPrism,
+ &EdenGame::actionNop,
+ &EdenGame::actionNop,
+ &EdenGame::actionGetEgg,
+ &EdenGame::actionNop,
+ &EdenGame::actionNop,
+ &EdenGame::actionGetMushroom,
+ &EdenGame::actionGetBadMushroom,
+ &EdenGame::actionGetKnife,
+ &EdenGame::actionGetEmptyNest,
+ &EdenGame::actionGetFullNest,
+ &EdenGame::actionGetGold,
+ nullptr,
+ &EdenGame::actionNop,
+ &EdenGame::actionGetSunStone,
+ &EdenGame::actionGetHorn,
+ &EdenGame::actionNop,
+ &EdenGame::actionNop,
+ &EdenGame::actionNop,
+ &EdenGame::actionNop,
+ &EdenGame::actionNop,
+ &EdenGame::actionNop,
+ &EdenGame::actionNop,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ &EdenGame::actionGetTablet,
+ &EdenGame::actionClickValleyPlan,
+ &EdenGame::actionEndFrescoes,
+ &EdenGame::actionChoose,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ &EdenGame::actionKing,
+ &EdenGame::actionDina,
+ &EdenGame::actionThoo,
+ &EdenGame::actionMonk,
+ &EdenGame::actionTormentor,
+ &EdenGame::actionMessenger,
+ &EdenGame::actionMango,
+ &EdenGame::actionEve,
+ &EdenGame::actionAzia,
+ &EdenGame::actionMammi,
+ &EdenGame::actionGuards,
+ &EdenGame::actionFisher,
+ &EdenGame::actionDino,
+ &EdenGame::actionTyran,
+ &EdenGame::actionMorkus,
+ &EdenGame::actionNop,
+ &EdenGame::parle_moi,
+ &EdenGame::actionAdam,
+ &EdenGame::actionTakeObject,
+ &EdenGame::putObject,
+ &EdenGame::clictimbre,
+ &EdenGame::handleDinaDialog,
+ &EdenGame::closeCharacterScreen,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ &EdenGame::generique,
+ &EdenGame::choseSubtitleOption,
+ &EdenGame::edenQuit,
+ &EdenGame::restart,
+ &EdenGame::cancel2,
+ &EdenGame::testvoice,
+ &EdenGame::changeVolume,
+ &EdenGame::load,
+ &EdenGame::save,
+ &EdenGame::cliccurstape,
+ &EdenGame::playtape,
+ &EdenGame::stoptape,
+ &EdenGame::rewindtape,
+ &EdenGame::forwardtape,
+ &EdenGame::confirmYes,
+ &EdenGame::confirmNo,
+ &EdenGame::actionGotoMap
+ };
+
+ if (!(_currSpot = scan_icon_list(_cirsorPanX + _cursCenter,
+ _cursorPosY + _cursCenter, _globals->_iconsIndex)))
+ return;
+ _curSpot2 = _currSpot;
+ debug("invoking mouse action %d", _currSpot->_actionId);
+ if (mouse_actions[_currSpot->_actionId])
+ (this->*mouse_actions[_currSpot->_actionId])();
+}
+
+////// film.c
+// Original name: showfilm
+void EdenGame::showMovie(char arg1) {
+ _vm->_video->readHeader();
+ if (_globals->_curVideoNum == 92) {
+ // _hnmContext->_header._unusedFlag2 = 0; CHECKME: Useless?
+ _hnmSoundChannel->setVolumeLeft(0);
+ _hnmSoundChannel->setVolumeRight(0);
+ }
+
+ if (_vm->_video->getVersion() != 4)
+ return;
+
+ bool playing = true;
+ _vm->_video->allocMemory();
+ _hnmView = new View(_vm->_video->_header._width, _vm->_video->_header._height);
+ _hnmView->setSrcZoomValues(0, 0);
+ _hnmView->setDisplayZoomValues(_vm->_video->_header._width * 2, _vm->_video->_header._height * 2);
+ _hnmView->centerIn(_vm->_screenView);
+ _hnmViewBuf = _hnmView->_bufferPtr;
+ if (arg1) {
+ _hnmView->_normal._height = 160;
+ _hnmView->_zoom._height = 320; //TODO: width??
+ _hnmView->_normal._dstTop = _mainView->_normal._dstTop + 16;
+ _hnmView->_zoom._dstTop = _mainView->_zoom._dstTop + 32;
+ }
+ _vm->_video->setFinalBuffer(_hnmView->_bufferPtr);
+ do {
+ _hnmFrameNum = _vm->_video->getFrameNum();
+ _vm->_video->waitLoop();
+ playing = _vm->_video->nextElement();
+ if (_specialTextMode)
+ handleHNMSubtitles();
+ else
+ musicspy();
+ CLBlitter_CopyView2Screen(_hnmView);
+ assert(_vm->_screenView->_pitch == 320);
+ _vm->pollEvents();
+ if (_allowDoubled) {
+#if 0 // CLKeyboard_IsScanCodeDown currently always returns false
+ if (_vm->isScanCodeDown(0x30)) { //TODO: const
+ if (!_keyboardHeld) {
+ _doubledScreen = !_doubledScreen;
+ _hnmView->_doubled = _doubledScreen; //TODO: but mainview ?
+ CLBlitter_FillScreenView(0);
+ _keyboardHeld = true;
+ }
+ } else
+#endif
+ _keyboardHeld = false;
+ }
+ if (arg1) {
+ if (_vm->isMouseButtonDown()) {
+ if (!_mouseHeld) {
+ _mouseHeld = true;
+ _videoCanceledFlag = true;
+ }
+ } else
+ _mouseHeld = false;
+ }
+ } while (playing && !_videoCanceledFlag);
+ delete _hnmView;
+ _vm->_video->deallocMemory();
+}
+
+void EdenGame::playHNM(int16 num) {
+ perso_t *perso = nullptr;
+ int16 oldDialogType = -1;
+ _globals->_curVideoNum = num;
+ if (num != 2001 && num != 2012 && num != 98 && num != 171) {
+ byte oldMusicType = _globals->_newMusicType;
+ _globals->_newMusicType = MusicType::mtEvent;
+ musique();
+ musicspy();
+ _globals->_newMusicType = oldMusicType;
+ }
+ _globals->_videoSubtitleIndex = 1;
+ if (_specialTextMode) {
+ perso = _globals->_characterPtr;
+ oldDialogType = _globals->_dialogType;
+ preloadDialogs(num);
+ fademusica0(1);
+ _musicChannel->stop();
+ }
+ _showVideoSubtitle = false;
+ _videoCanceledFlag = false;
+ loadHnm(num);
+ _vm->_video->reset();
+ if (_needToFade) {
+ fadeToBlack(4);
+ clearScreen();
+ _needToFade = false;
+ }
+ if (num == 2012 || num == 98 || num == 171)
+ showMovie(0);
+ else
+ showMovie(1);
+ _cursKeepPos = Common::Point(-1, -1);
+ if (_specialTextMode) {
+ _musicFadeFlag = 3;
+ musicspy();
+ _globals->_characterPtr = perso;
+ _globals->_dialogType = oldDialogType;
+ _specialTextMode = false;
+ }
+ if (_videoCanceledFlag)
+ _globals->_varF1 = RoomFlags::rf40 | RoomFlags::rf04 | RoomFlags::rf01;
+ if (_globals->_curVideoNum == 167)
+ _globals->_varF1 = RoomFlags::rf40 | RoomFlags::rf04 | RoomFlags::rf01;
+ if (_globals->_curVideoNum == 104)
+ _globals->_varF1 = RoomFlags::rf40 | RoomFlags::rf04 | RoomFlags::rf01;
+ if (_globals->_curVideoNum == 102)
+ _globals->_varF1 = RoomFlags::rf40 | RoomFlags::rf04 | RoomFlags::rf01;
+ if (_globals->_curVideoNum == 77)
+ _globals->_varF1 = RoomFlags::rf40 | RoomFlags::rf04 | RoomFlags::rf01;
+ if (_globals->_curVideoNum == 149)
+ _globals->_varF1 = RoomFlags::rf40 | RoomFlags::rf04 | RoomFlags::rf01;
+}
+
+// Original name bullehnm
+void EdenGame::handleHNMSubtitles() {
+#define SUB_LINE(start, end) \
+ (start), (end) | 0x8000
+
+ static uint16 kFramesVid170[] = {
+ SUB_LINE( 68, 120),
+ SUB_LINE( 123, 196),
+ SUB_LINE( 199, 274),
+ SUB_LINE( 276, 370),
+ SUB_LINE( 799, 885),
+ SUB_LINE( 888, 940),
+ SUB_LINE( 947, 1000),
+ SUB_LINE(1319, 1378),
+ SUB_LINE(1380, 1440),
+ SUB_LINE(1854, 1898),
+ SUB_LINE(1900, 1960),
+ SUB_LINE(2116, 2184),
+ SUB_LINE(2186, 2252),
+ SUB_LINE(2254, 2320),
+ SUB_LINE(3038, 3094),
+ SUB_LINE(3096, 3160),
+ 0xFFFF
+ };
+
+ static uint16 kFramesVid83[] = {
+ SUB_LINE(99, 155),
+ SUB_LINE(157, 256),
+ 0xFFFF
+ };
+
+ static uint16 kFramesVid88[] = {
+ SUB_LINE(106, 173),
+ SUB_LINE(175, 244),
+ SUB_LINE(246, 350),
+ SUB_LINE(352, 467),
+ 0xFFFF
+ };
+
+ static uint16 kFramesVid89[] = {
+ SUB_LINE(126, 176),
+ SUB_LINE(178, 267),
+ SUB_LINE(269, 342),
+ SUB_LINE(344, 398),
+ SUB_LINE(400, 458),
+ SUB_LINE(460, 558),
+ 0xFFFF
+ };
+
+ static uint16 kFramesVid94[] = {
+ SUB_LINE(101, 213),
+ SUB_LINE(215, 353),
+ SUB_LINE(355, 455),
+ SUB_LINE(457, 518),
+ SUB_LINE(520, 660),
+ SUB_LINE(662, 768),
+ 0xFFFF
+ };
+
+#undef SUB_LINE
+
+ uint16 *frames;
+ perso_t *perso;
+ switch (_globals->_curVideoNum) {
+ case 170:
+ frames = kFramesVid170;
+ perso = &kPersons[PER_UNKN_156];
+ break;
+ case 83:
+ frames = kFramesVid83;
+ perso = &kPersons[PER_MORKUS];
+ break;
+ case 88:
+ frames = kFramesVid88;
+ perso = &kPersons[PER_MORKUS];
+ break;
+ case 89:
+ frames = kFramesVid89;
+ perso = &kPersons[PER_MORKUS];
+ break;
+ case 94:
+ frames = kFramesVid94;
+ perso = &kPersons[PER_MORKUS];
+ break;
+ default:
+ return;
+ }
+ uint16 *frames_start = frames;
+ uint16 frame;
+ while ((frame = *frames++) != 0xFFFF) {
+ if ((frame & ~0x8000) == _hnmFrameNum)
+ break;
+ }
+ if (frame == 0xFFFF) {
+ if (_showVideoSubtitle)
+ displayHNMSubtitle();
+ return;
+ }
+ if (frame & 0x8000)
+ _showVideoSubtitle = false;
+ else {
+ _globals->_videoSubtitleIndex = (frames - frames_start) / 2 + 1;
+ _globals->_characterPtr = perso;
+ _globals->_dialogType = DialogType::dtInspect;
+ int16 num = (perso->_id << 3) | _globals->_dialogType;
+ dialoscansvmas((Dialog *)getElem(_gameDialogs, num));
+ _showVideoSubtitle = true;
+ }
+ if (_showVideoSubtitle)
+ displayHNMSubtitle();
+}
+
+////// sound.c
+void EdenGame::musique() {
+ if (_globals->_newMusicType == MusicType::mtDontChange)
+ return;
+
+ Dialog *dial = (Dialog *)getElem(_gameDialogs, 128);
+ for (;;dial++) {
+ if (dial->_flags == -1 && dial->_condNumLow == -1)
+ return;
+ byte flag = dial->_flags;
+ byte hidx = (dial->_textCondHiMask & 0xC0) >> 6;
+ byte lidx = dial->_condNumLow; //TODO: fixme - unsigned = signed
+ if (flag & 0x10)
+ hidx |= 4;
+ if (testCondition(((hidx << 8) | lidx) & 0x7FF))
+ break;
+ }
+ byte mus = dial->_textNumLow;
+ _globals->_newMusicType = MusicType::mtDontChange;
+ if (mus != 0 && mus != 2 && mus < 50)
+ startmusique(mus);
+}
+
+void EdenGame::startmusique(byte num) {
+ if (num == _globals->_currMusicNum)
+ return;
+
+ if (_musicPlayingFlag) {
+ fademusica0(1);
+ _musicChannel->stop();
+ }
+ loadmusicfile(num);
+ _globals->_currMusicNum = num;
+ _musSequencePtr = _musicBuf + 32; //TODO: rewrite it properly
+ int16 seq_size = READ_LE_UINT16(_musicBuf + 30);
+ _musicPatternsPtr = _musicBuf + 30 + seq_size;
+ int16 pat_size = READ_LE_UINT16(_musicBuf + 27);
+ _musicSamplesPtr = _musicBuf + 32 + 4 + pat_size;
+ int16 freq = READ_LE_UINT16(_musicSamplesPtr - 2);
+
+ delete _musicChannel;
+ _musicChannel = new CSoundChannel(_vm->_mixer, freq == 166 ? 11025 : 22050, false);
+ _musicEnabledFlag = true;
+
+ _musicSequencePos = 0;
+ _musicLeftVol = _globals->_prefMusicVol[0];
+ _musicRightVol = _globals->_prefMusicVol[1];
+ _musicChannel->setVolume(_musicLeftVol, _musicRightVol);
+}
+
+void EdenGame::musicspy() {
+ if (!_musicEnabledFlag)
+ return;
+ _musicLeftVol = _globals->_prefMusicVol[0];
+ _musicRightVol = _globals->_prefMusicVol[1];
+ if (_musicFadeFlag & 3)
+ fademusicup();
+ if (_personTalking && !_voiceChannel->numQueued())
+ _musicFadeFlag = 3;
+ if (_musicChannel->numQueued() < 3) {
+ byte patnum = _musSequencePtr[(int)_musicSequencePos];
+ if (patnum == 0xFF) {
+ // rewind
+ _musicSequencePos = 0;
+ patnum = _musSequencePtr[(int)_musicSequencePos];
+ }
+ _musicSequencePos++;
+ byte *patptr = _musicPatternsPtr + patnum * 6;
+ int ofs = patptr[0] + (patptr[1] << 8) + (patptr[2] << 16);
+ int len = patptr[3] + (patptr[4] << 8) + (patptr[5] << 16);
+ _musicChannel->queueBuffer(_musicSamplesPtr + ofs, len);
+ _musicPlayingFlag = true;
+ }
+}
+
+int EdenGame::loadmusicfile(int16 num) {
+ PakHeaderItem *file = &_bigfileHeader->_files[num + 435];
+ int32 size = file->_size;
+ int32 offs = file->_offs;
+ _bigfile.seek(offs, SEEK_SET);
+ uint32 numread = size;
+ if (numread > kMaxMusicSize)
+ error("Music file %s is too big", file->_name.c_str());
+ _bigfile.read(_musicBuf, numread);
+ return size;
+}
+
+void EdenGame::persovox() {
+ int16 num = _globals->_textNum;
+ if (_globals->_textBankIndex != 1)
+ num += 565;
+ if (_globals->_textBankIndex == 3)
+ num += 707;
+ _voiceSamplesSize = loadSound(num);
+ int16 volumeLeft = _globals->_prefSoundVolume[0];
+ int16 volumeRight = _globals->_prefSoundVolume[1];
+ int16 stepLeft = _musicChannel->_volumeLeft < volumeLeft ? stepLeft = 1 : -1;
+ int16 stepRight = _musicChannel->_volumeRight < volumeRight ? stepRight = 1 : -1;
+ do {
+ if (volumeLeft != _musicChannel->_volumeLeft)
+ _musicChannel->setVolumeLeft(_musicChannel->_volumeLeft + stepLeft);
+ if (volumeRight != _musicChannel->_volumeRight)
+ _musicChannel->setVolumeRight(_musicChannel->_volumeRight + stepRight);
+ } while (_musicChannel->_volumeLeft != volumeLeft || _musicChannel->_volumeRight != volumeRight);
+ volumeLeft = _globals->_prefVoiceVol[0];
+ volumeRight = _globals->_prefVoiceVol[1];
+ _voiceChannel->setVolume(volumeLeft, volumeRight);
+ _voiceChannel->queueBuffer(_voiceSamplesBuffer, _voiceSamplesSize, true);
+ _personTalking = true;
+ _musicFadeFlag = 0;
+ _lastAnimTicks = _vm->_timerTicks;
+}
+
+// Original name: endpersovox
+void EdenGame::endCharacterSpeech() {
+ restoreUnderSubtitles();
+ if (_personTalking) {
+ _voiceChannel->stop();
+ _personTalking = false;
+ _musicFadeFlag = 3;
+ }
+
+ if (_soundAllocated) {
+ free(_voiceSamplesBuffer);
+ _voiceSamplesBuffer = nullptr;
+ _soundAllocated = false;
+ }
+}
+
+void EdenGame::fademusicup() {
+ if (_musicFadeFlag & 2) {
+ int16 vol = _musicChannel->_volumeLeft;
+ if (vol < _musicLeftVol) {
+ vol += 8;
+ if (vol > _musicLeftVol)
+ vol = _musicLeftVol;
+ } else {
+ vol -= 8;
+ if (vol < _musicLeftVol)
+ vol = _musicLeftVol;
+ }
+ _musicChannel->setVolumeLeft(vol);
+ if (vol == _musicLeftVol)
+ _musicFadeFlag &= ~2;
+ }
+ if (_musicFadeFlag & 1) {
+ int16 vol = _musicChannel->_volumeRight;
+ if (vol < _musicRightVol) {
+ vol += 8;
+ if (vol > _musicRightVol)
+ vol = _musicRightVol;
+ } else {
+ vol -= 8;
+ if (vol < _musicRightVol)
+ vol = _musicRightVol;
+ }
+ _musicChannel->setVolumeRight(vol);
+ if (vol == _musicRightVol)
+ _musicFadeFlag &= ~1;
+ }
+}
+
+void EdenGame::fademusica0(int16 delay) {
+ int16 volume;
+ while ((volume = _musicChannel->getVolume()) > 2) {
+ volume -= 2;
+ if (volume < 2)
+ volume = 2;
+ _musicChannel->setVolume(volume, volume);
+ wait(delay);
+ }
+}
+
+//// obj.c
+
+// Original name: getobjaddr
+object_t *EdenGame::getObjectPtr(int16 id) {
+ int i;
+ for (i = 0; i < MAX_OBJECTS; i++) {
+ if (_objects[i]._id == id)
+ break;
+ }
+
+ return &_objects[i];
+}
+
+void EdenGame::countObjects() {
+ int16 index = 0;
+ byte total = 0;
+ for (int i = 0; i < MAX_OBJECTS; i++) {
+ int16 count = _objects[i]._count;
+ if (count == 0)
+ continue;
+
+ if (_objects[i]._flags & ObjectFlags::ofInHands)
+ count--;
+
+ if (count) {
+ total += count;
+ while (count--)
+ _ownObjects[index++] = _objects[i]._id;
+ }
+ }
+ _globals->_objCount = total;
+}
+
+void EdenGame::showObjects() {
+ Icon *icon = &_gameIcons[_invIconsBase];
+ _globals->_drawFlags &= ~(DrawFlags::drDrawInventory | DrawFlags::drDrawFlag2);
+ countObjects();
+ int16 total = _globals->_objCount;
+ for (int16 i = _invIconsCount; i--; icon++) {
+ if (total) {
+ icon->_cursorId &= ~0x8000;
+ total--;
+ } else
+ icon->_cursorId |= 0x8000;
+ }
+ useMainBank();
+ noclipax(55, 0, 176);
+ icon = &_gameIcons[_invIconsBase];
+ total = _globals->_objCount;
+ int16 index = _globals->_inventoryScrollPos;
+ for (int16 i = _invIconsCount; total-- && i--; icon++) {
+ char obj = _ownObjects[index++];
+ icon->_objectId = obj;
+ noclipax(obj + 9, icon->sx, 178);
+ }
+ _paletteUpdateRequired = true;
+ if ((_globals->_displayFlags & DisplayFlags::dfMirror) || (_globals->_displayFlags & DisplayFlags::dfPanable)) {
+ saveBottomFrieze();
+ scroll();
+ }
+}
+
+void EdenGame::winObject(int16 id) {
+ object_t *object = getObjectPtr(id);
+ object->_flags |= ObjectFlags::ofFlag1;
+ object->_count++;
+ _globals->_curItemsMask |= object->_itemMask;
+ _globals->_wonItemsMask |= object->_itemMask;
+ _globals->_curPowersMask |= object->_powerMask;
+ _globals->_wonPowersMask |= object->_powerMask;
+}
+
+void EdenGame::loseObject(int16 id) {
+ object_t *object = getObjectPtr(id);
+ if (object->_count > 0)
+ object->_count--;
+ if (!object->_count) {
+ object->_flags &= ~ObjectFlags::ofFlag1;
+ _globals->_curItemsMask &= ~object->_itemMask;
+ _globals->_curPowersMask &= ~object->_powerMask;
+ }
+ _globals->_curObjectId = 0;
+ _globals->_curObjectFlags = 0;
+ _globals->_curObjectCursor = 9;
+ _gameIcons[16]._cursorId |= 0x8000;
+ object->_flags &= ~ObjectFlags::ofInHands;
+ _normalCursor = true;
+ _currCursor = 0;
+ _torchCursor = false;
+}
+
+void EdenGame::lostObject() {
+ parlemoiNormalFlag = true;
+ if (_globals->_curObjectId)
+ loseObject(_globals->_curObjectId);
+}
+
+// Original name: objecthere
+bool EdenGame::isObjectHere(int16 id) {
+ object_t *object = getObjectPtr(id);
+ for (_currentObjectLocation = &kObjectLocations[object->_locations]; *_currentObjectLocation != 0xFFFF; _currentObjectLocation++) {
+ if (*_currentObjectLocation == _globals->_roomNum)
+ return true;
+ }
+ return false;
+}
+
+void EdenGame::objectmain(int16 id) {
+ object_t *object = getObjectPtr(id);
+ _gameIcons[16]._cursorId &= ~0x8000;
+ _globals->_curObjectId = object->_id;
+ _globals->_curObjectCursor = _globals->_curObjectId + 9;
+ object->_flags |= ObjectFlags::ofInHands;
+ _globals->_curObjectFlags = object->_flags;
+ _currCursor = _globals->_curObjectId + 9;
+ _normalCursor = false;
+}
+
+void EdenGame::getObject(int16 id) {
+ Room *room = _globals->_roomPtr;
+ if (_globals->_curObjectId)
+ return;
+ if (!isObjectHere(id))
+ return;
+ *_currentObjectLocation |= 0x8000;
+ objectmain(id);
+ winObject(id);
+ showObjects();
+ _globals->_roomImgBank = room->_bank;
+ _globals->_roomVidNum = room->_video;
+ displayPlace();
+}
+
+void EdenGame::putObject() {
+ if (!_globals->_curObjectId)
+ return;
+ _gameIcons[16]._cursorId |= 0x8000;
+ object_t *object = getObjectPtr(_globals->_curObjectId);
+ _globals->_curObjectCursor = 9;
+ _globals->_curObjectId = 0;
+ _globals->_curObjectFlags = 0;
+ object->_flags &= ~ObjectFlags::ofInHands;
+ _globals->_nextDialogPtr = nullptr;
+ _closeCharacterDialog = false;
+ _globals->_dialogType = DialogType::dtTalk;
+ showObjects();
+ _normalCursor = true;
+}
+
+void EdenGame::newObject(int16 id, int16 arg2) {
+ object_t *object = getObjectPtr(id);
+ uint16 e, *t = &kObjectLocations[object->_locations];
+ while ((e = *t) != 0xFFFF) {
+ e &= ~0x8000;
+ if ((e >> 8) == arg2)
+ *t = e;
+ t++;
+ }
+}
+
+void EdenGame::giveobjectal(int16 id) {
+ if (id == Objects::obKnife)
+ kObjectLocations[2] = 0;
+ if (id == Objects::obApple)
+ _globals->_stepsToFindAppleNormal = 0;
+ if (id >= Objects::obEyeInTheStorm && id < (Objects::obRiverThatWinds + 1) && _globals->_roomCharacterType == PersonFlags::pftVelociraptor) {
+ //TODO: fix that cond above
+ object_t *object = getObjectPtr(id);
+ _globals->_roomCharacterPtr->_powers &= ~object->_powerMask;
+ }
+ winObject(id);
+}
+
+void EdenGame::giveObject() {
+ byte id = _globals->_giveObj1;
+ if (id) {
+ _globals->_giveObj1 = 0;
+ giveobjectal(id);
+ }
+ id = _globals->_giveObj2;
+ if (id) {
+ _globals->_giveObj2 = 0;
+ giveobjectal(id);
+ }
+ id = _globals->_giveObj3;
+ if (id) {
+ _globals->_giveObj3 = 0;
+ giveobjectal(id);
+ }
+}
+
+// Original name: takeObject
+void EdenGame::actionTakeObject() {
+ objectmain(_curSpot2->_objectId);
+ _globals->_nextDialogPtr = nullptr;
+ _closeCharacterDialog = false;
+ _globals->_dialogType = DialogType::dtTalk;
+ if (_globals->_inventoryScrollPos)
+ _globals->_inventoryScrollPos--;
+ showObjects();
+}
+////
+
+// Original name: newchampi
+void EdenGame::newMushroom() {
+ if (_objects[Objects::obShroom - 1]._count == 0) {
+ newObject(Objects::obShroom, _globals->_citadelAreaNum);
+ newObject(Objects::obBadShroom, _globals->_citadelAreaNum);
+ }
+}
+
+// Original name: newnidv
+void EdenGame::newEmptyNest() {
+ Room *room = _globals->_citaAreaFirstRoom;
+ if (_objects[Objects::obNest - 1]._count)
+ return;
+ object_t *obj = getObjectPtr(Objects::obNest);
+ for (uint16 *ptr = kObjectLocations + obj->_locations; *ptr != 0xFFFF; ptr++) {
+ if ((*ptr & ~0x8000) >> 8 != _globals->_citadelAreaNum)
+ continue;
+ *ptr &= ~0x8000;
+ for (; room->_id != 0xFF; room++) {
+ if (room->_location == (*ptr & 0xFF)) {
+ room->_bank = 279;
+ room->_id = 9;
+ room++;
+ room->_bank = 280;
+ return;
+ }
+ }
+ }
+}
+
+// Original name: newnido
+void EdenGame::newNestWithEggs() {
+ Room *room = _globals->_citaAreaFirstRoom;
+ if (_objects[Objects::obFullNest - 1]._count)
+ return;
+ if (_objects[Objects::obNest - 1]._count)
+ return;
+ object_t *obj = getObjectPtr(Objects::obFullNest);
+ for (uint16 *ptr = kObjectLocations + obj->_locations; *ptr != 0xFFFF; ptr++) {
+ if ((*ptr & ~0x8000) >> 8 != _globals->_citadelAreaNum)
+ continue;
+ *ptr &= ~0x8000;
+ for (; room->_id != 0xFF; room++) {
+ if (room->_location == (*ptr & 0xFF)) {
+ room->_bank = 277;
+ room->_id = 9;
+ room++;
+ room->_bank = 278;
+ return;
+ }
+ }
+ }
+}
+
+// Original name: newor
+void EdenGame::newGold() {
+ if (_objects[Objects::obGold - 1]._count == 0)
+ newObject(Objects::obGold, _globals->_citadelAreaNum);
+}
+
+void EdenGame::gotoPanel() {
+ if (_vm->shouldQuit())
+ byte_31D64 = _globals->_autoDialog; //TODO: check me
+ _noPalette = false;
+ _globals->_iconsIndex = 85;
+ _globals->_characterPtr = nullptr;
+ _globals->_drawFlags |= DrawFlags::drDrawMenu;
+ _globals->_displayFlags = DisplayFlags::dfFlag2;
+ _globals->_menuFlags = 0;
+ displayPanel();
+ fadeToBlack(3);
+ displayTopPanel();
+ CLBlitter_CopyView2Screen(_mainView);
+ CLPalette_Send2Screen(_globalPalette, 0, 256);
+ _cursorPosX = 320 / 2;
+ _cursorPosY = 200 / 2;
+ _vm->setMousePosition(_mouseCenterX, _mouseCenterY);
+}
+
+void EdenGame::noclicpanel() {
+ if (_globals->_menuFlags & MenuFlags::mfFlag4) {
+ depcurstape();
+ return;
+ }
+ if (_globals->_drawFlags & DrawFlags::drDrawFlag8)
+ return;
+ if (_globals->_menuFlags & MenuFlags::mfFlag1) {
+ changervol();
+ return;
+ }
+ byte num;
+ if (_curSpot2 >= &_gameIcons[119]) {
+ debug("noclic: objid = %p, glob3,2 = %2X %2X", (void *)_curSpot2, _globals->_menuItemIdHi, _globals->_menuItemIdLo);
+ if (_curSpot2->_objectId == (uint16)((_globals->_menuItemIdLo + _globals->_menuItemIdHi) << 8)) //TODO: check me
+ return;
+ } else {
+ int idx = _curSpot2 - &_gameIcons[105];
+ if (idx == 0) {
+ _globals->_menuItemIdLo = 1;
+ num = 1;
+ goto skip;
+ }
+ num = idx & 0x7F + 1;
+ if (num >= 5)
+ num = 1;
+ if (num == _globals->_var43)
+ return;
+ _globals->_var43 = 0;
+ }
+ num = _globals->_menuItemIdLo;
+ _globals->_menuItemIdLo = _curSpot2->_objectId & 0xFF;
+skip:
+ ;
+ _globals->_menuItemIdHi = (_curSpot2->_objectId & 0xFF00) >> 8;
+ debug("noclic: new glob3,2 = %2X %2X", _globals->_menuItemIdHi, _globals->_menuItemIdLo);
+ displayResult();
+ num &= 0xF0;
+ if (num != 0x30)
+ num = _globals->_menuItemIdLo & 0xF0;
+ if (num == 0x30)
+ displayCursors();
+}
+
+void EdenGame::generique() {
+ drawBlackBars();
+ display();
+ fadeToBlack(3);
+ clearScreen();
+ int oldmusic = _globals->_currMusicNum;
+ playHNM(95);
+ displayPanel();
+ displayTopPanel();
+ _paletteUpdateRequired = true;
+ startmusique(oldmusic);
+}
+
+void EdenGame::cancel2() {
+ drawTopScreen();
+ showObjects();
+ _globals->_iconsIndex = 16;
+ _globals->_drawFlags &= ~DrawFlags::drDrawMenu;
+ gameToMirror(1);
+}
+
+void EdenGame::testvoice() {
+ _globals->_frescoNumber = 0;
+ _globals->_characterPtr = kPersons;
+ _globals->_dialogType = DialogType::dtInspect;
+ int16 num = (kPersons[PER_KING]._id << 3) | _globals->_dialogType;
+ dialoscansvmas((Dialog *)getElem(_gameDialogs, num));
+ restoreUnderSubtitles();
+ displaySubtitles();
+ persovox();
+ waitEndSpeak();
+ endCharacterSpeech();
+ _globals->_varCA = 0;
+ _globals->_dialogType = DialogType::dtTalk;
+}
+
+void EdenGame::load() {
+ char name[132];
+ _gameLoaded = false;
+ byte oldMusic = _globals->_currMusicNum; //TODO: from uint16 to byte?!
+ fademusica0(1);
+ desktopcolors();
+ FlushEvents(-1, 0);
+// if(OpenDialog(0, 0)) //TODO: write me
+ {
+ // TODO
+ strcpy(name, "edsave1.000");
+ loadgame(name);
+ }
+ _vm->hideMouse();
+ CLBlitter_FillScreenView(0xFFFFFFFF);
+ fadeToBlack(3);
+ CLBlitter_FillScreenView(0);
+ if (!_gameLoaded) {
+ _musicFadeFlag = 3;
+ musicspy();
+ _paletteUpdateRequired = true;
+ return;
+ }
+ if ((oldMusic & 0xFF) != _globals->_currMusicNum) { //TODO: r30 is uns char/bug???
+ oldMusic = _globals->_currMusicNum;
+ _globals->_currMusicNum = 0;
+ startmusique(oldMusic);
+ } else {
+ _musicFadeFlag = 3;
+ musicspy();
+ }
+ bool talk = _globals->_autoDialog; //TODO check me
+ initafterload();
+ fadeToBlack(3);
+ CLBlitter_FillScreenView(0);
+ CLBlitter_FillView(_mainView, 0);
+ drawTopScreen();
+ _globals->_inventoryScrollPos = 0;
+ showObjects();
+ updateRoom(_globals->_roomNum);
+ if (talk) {
+ _globals->_iconsIndex = 4;
+ _globals->_autoDialog = true;
+ parle_moi();
+ }
+
+}
+
+void EdenGame::initafterload() {
+ _globals->_characterImageBank = 0;
+ _globals->_lastPlaceNum = 0;
+ loadPlace(_globals->_areaPtr->_placeNum);
+ _gameIcons[18]._cursorId |= 0x8000;
+ if (_globals->_curAreaType == AreaType::atValley)
+ _gameIcons[18]._cursorId &= ~0x8000;
+ kPersoRoomBankTable[30] = 27;
+ if (_globals->_phaseNum >= 352)
+ kPersoRoomBankTable[30] = 26;
+ _animateTalking = false;
+ _animationActive = false;
+ _globals->_var100 = 0;
+ _globals->_eventType = EventType::etEventC;
+ _globals->_valleyVidNum = 0;
+ _globals->_drawFlags &= ~DrawFlags::drDrawMenu;
+ _currentTime = _vm->_timerTicks / 100;
+ _globals->_gameTime = _currentTime;
+ if (_globals->_roomCharacterType == PersonFlags::pftTyrann)
+ setChrono(3000);
+ _adamMapMarkPos.x = -1;
+ _adamMapMarkPos.y = -1;
+}
+
+void EdenGame::save() {
+ char name[260];
+ fademusica0(1);
+ desktopcolors();
+ FlushEvents(-1, 0);
+ //SaveDialog(byte_37150, byte_37196->ff_A);
+ //TODO
+ strcpy(name, "edsave1.000");
+ savegame(name);
+ _vm->hideMouse();
+ CLBlitter_FillScreenView(0xFFFFFFFF);
+ fadeToBlack(3);
+ CLBlitter_FillScreenView(0);
+ _musicFadeFlag = 3;
+ musicspy();
+ _paletteUpdateRequired = true;
+}
+
+void EdenGame::desktopcolors() {
+ fadeToBlack(3);
+ CLBlitter_FillScreenView(0xFFFFFFFF);
+ CLPalette_BeSystem();
+ _vm->showMouse();
+}
+
+void EdenGame::panelrestart() {
+ _gameLoaded = false;
+ byte curmus = _globals->_currMusicNum;
+ byte curlng = _globals->_prefLanguage;
+ loadrestart();
+ _globals->_prefLanguage = curlng;
+ if (!_gameLoaded) //TODO always?
+ return;
+ _globals->_characterImageBank = 0;
+ _globals->_lastPlaceNum = 0;
+ loadPlace(_globals->_areaPtr->_placeNum);
+ _globals->_displayFlags = DisplayFlags::dfFlag1;
+ _gameIcons[18]._cursorId |= 0x8000;
+ if (_globals->_curAreaType == AreaType::atValley)
+ _gameIcons[18]._cursorId &= ~0x8000;
+ kPersoRoomBankTable[30] = 27;
+ if (_globals->_phaseNum >= 352)
+ kPersoRoomBankTable[30] = 26;
+ _animateTalking = false;
+ _animationActive = false;
+ _globals->_var100 = 0;
+ _globals->_eventType = 0;
+ _globals->_valleyVidNum = 0;
+ _globals->_drawFlags &= ~DrawFlags::drDrawMenu;
+ _globals->_inventoryScrollPos = 0;
+ _adamMapMarkPos.x = -1;
+ _adamMapMarkPos.y = -1;
+ if (curmus != _globals->_currMusicNum) {
+ curmus = _globals->_currMusicNum;
+ _globals->_currMusicNum = 0;
+ startmusique(curmus);
+ }
+ fadeToBlack(3);
+ CLBlitter_FillScreenView(0);
+ CLBlitter_FillView(_mainView, 0);
+ drawTopScreen();
+ showObjects();
+ saveFriezes();
+ _showBlackBars = true;
+ updateRoom(_globals->_roomNum);
+}
+
+void EdenGame::reallyquit() {
+ _quitFlag3 = true;
+ _quitFlag2 = true;
+}
+
+void EdenGame::confirmer(char mode, char yesId) {
+ _globals->_iconsIndex = 119;
+ _gameIcons[119]._objectId = yesId;
+ _confirmMode = mode;
+ useBank(65);
+ noclipax(12, 117, 74);
+ _cursorPosX = 156;
+ if (_vm->shouldQuit())
+ _cursorPosX = 136;
+ _cursorPosY = 88;
+}
+
+void EdenGame::confirmYes() {
+ displayPanel();
+ _globals->_iconsIndex = 85;
+ switch (_confirmMode) {
+ case 1:
+ panelrestart();
+ break;
+ case 2:
+ reallyquit();
+ break;
+ }
+}
+
+void EdenGame::confirmNo() {
+ displayPanel();
+ _globals->_iconsIndex = 85;
+// pomme_q = false;
+}
+
+void EdenGame::restart() {
+ confirmer(1, _curSpot2->_objectId);
+}
+
+void EdenGame::edenQuit() {
+ confirmer(2, _curSpot2->_objectId);
+}
+
+// Original name: choixsubtitle
+void EdenGame::choseSubtitleOption() {
+ byte lang = _curSpot2->_objectId & 0xF;
+ if (lang == _globals->_prefLanguage)
+ return;
+ if (lang > 5)
+ return;
+ _globals->_prefLanguage = lang;
+ langbuftopanel();
+ displayLanguage();
+}
+
+// Original name: reglervol
+void EdenGame::changeVolume() {
+ byte *valptr = &_globals->_prefMusicVol[_curSpot2->_objectId & 7];
+ _cursorPosY = 104 - ((*valptr >> 2) & 0x3F); // TODO: check me
+ _curSliderValuePtr = valptr;
+ _globals->_menuFlags |= MenuFlags::mfFlag1;
+ if (_curSpot2->_objectId & 8)
+ _globals->_menuFlags |= MenuFlags::mfFlag2;
+ _curSliderX = _curSpot2->sx;
+ _curSliderY = _cursorPosY;
+}
+
+void EdenGame::changervol() {
+ if (_mouseHeld) {
+ restrictCursorArea(_curSliderX - 1, _curSliderX + 3, 40, 110);
+ int16 delta = _curSliderY - _cursorPosY;
+ if (delta == 0)
+ return;
+ newvol(_curSliderValuePtr, delta);
+ if (_globals->_menuFlags & MenuFlags::mfFlag2)
+ newvol(_curSliderValuePtr + 1, delta);
+ cursbuftopanel();
+ displayCursors();
+ _curSliderY = _cursorPosY;
+ } else
+ _globals->_menuFlags &= ~(MenuFlags::mfFlag1 | MenuFlags::mfFlag2);
+}
+
+void EdenGame::newvol(byte *volptr, int16 delta) {
+ int16 vol = *volptr / 4;
+ vol += delta;
+ if (vol < 0)
+ vol = 0;
+ if (vol > 63)
+ vol = 63;
+ *volptr = vol * 4;
+ _musicChannel->setVolume(_globals->_prefMusicVol[0], _globals->_prefMusicVol[1]);
+}
+
+void EdenGame::playtape() {
+ if (_globals->_menuItemIdHi & 8)
+ _globals->_tapePtr++;
+ for (;; _globals->_tapePtr++) {
+ if (_globals->_tapePtr == &_tapes[MAX_TAPES]) {
+ _globals->_tapePtr--;
+ stoptape();
+ return;
+ }
+ if (_globals->_tapePtr->_textNum)
+ break;
+ }
+ _globals->_menuFlags |= MenuFlags::mfFlag8;
+ _globals->_drawFlags &= ~DrawFlags::drDrawMenu;
+ uint16 oldRoomNum = _globals->_roomNum;
+ uint16 oldParty = _globals->_party;
+ byte oldBack = _globals->_roomBackgroundBankNum;
+ perso_t *oldPerso = _globals->_characterPtr;
+ _globals->_party = _globals->_tapePtr->_party;
+ _globals->_roomNum = _globals->_tapePtr->_roomNum;
+ _globals->_roomBackgroundBankNum = _globals->_tapePtr->_backgroundBankNum;
+ _globals->_dialogPtr = _globals->_tapePtr->_dialog;
+ _globals->_characterPtr = _globals->_tapePtr->_perso;
+ endCharacterSpeech();
+ affcurstape();
+ if (_globals->_characterPtr != oldPerso
+ || _globals->_roomNum != _lastTapeRoomNum) {
+ _lastTapeRoomNum = _globals->_roomNum;
+ _globals->_curCharacterAnimPtr = nullptr;
+ _globals->_varCA = 0;
+ _globals->_characterImageBank = -1;
+ AnimEndCharacter();
+ loadCurrCharacter();
+ }
+ displayCharacterBackground();
+ _globals->_textNum = _globals->_tapePtr->_textNum;
+ my_bulle();
+ getDataSync();
+ displayCharacterPanel();
+ persovox();
+ _globals->_roomBackgroundBankNum = oldBack;
+ _globals->_party = oldParty;
+ _globals->_roomNum = oldRoomNum;
+}
+
+void EdenGame::rewindtape() {
+ if (_globals->_tapePtr > _tapes) {
+ _globals->_tapePtr--;
+ _globals->_menuFlags &= ~MenuFlags::mfFlag8;
+ affcurstape();
+ }
+}
+
+void EdenGame::depcurstape() {
+ if (_mouseHeld) {
+ restrictCursorArea(95, 217, 179, 183);
+ int idx = (_cursorPosX - 97);
+ if (idx < 0)
+ idx = 0;
+
+ idx /= 8;
+ tape_t *tape = _tapes + idx;
+ if (tape >= _tapes + 16)
+ tape = _tapes + 16 - 1;
+
+ if (tape != _globals->_tapePtr) {
+ _globals->_tapePtr = tape;
+ affcurstape();
+ _globals->_menuFlags &= ~MenuFlags::mfFlag8;
+ }
+ } else
+ _globals->_menuFlags &= ~MenuFlags::mfFlag4;
+}
+
+void EdenGame::affcurstape() {
+ if (_globals->_drawFlags & DrawFlags::drDrawFlag8)
+ _noPalette = true;
+ useBank(65);
+ noclipax(2, 0, 176);
+ int x = (_globals->_tapePtr - _tapes) * 8 + 97;
+ _gameIcons[112].sx = x - 3;
+ _gameIcons[112].ex = x + 3;
+ noclipax(5, x, 179);
+ _noPalette = false;
+}
+
+void EdenGame::forwardtape() {
+ if (_globals->_tapePtr < _tapes + 16) {
+ _globals->_tapePtr++;
+ _globals->_menuFlags &= ~MenuFlags::mfFlag8;
+ affcurstape();
+ }
+}
+
+void EdenGame::stoptape() {
+ if (!(_globals->_drawFlags & DrawFlags::drDrawFlag8))
+ return;
+ _globals->_menuFlags &= ~MenuFlags::mfFlag8;
+ _globals->_drawFlags &= ~DrawFlags::drDrawFlag8;
+ _globals->_menuFlags |= MenuFlags::mfFlag10;
+ _globals->_iconsIndex = 85;
+ _globals->_characterPtr = nullptr;
+ _lastTapeRoomNum = 0;
+ endCharacterSpeech();
+ fin_perso();
+ displayPanel();
+ displayTopPanel();
+ _paletteUpdateRequired = true;
+}
+
+void EdenGame::cliccurstape() {
+ _globals->_menuFlags |= MenuFlags::mfFlag4;
+}
+
+void EdenGame::paneltobuf() {
+ setSrcRect(0, 16, 320 - 1, 169 - 1);
+ setDestRect(320, 16, 640 - 1, 169 - 1);
+ CLBlitter_CopyViewRect(_mainView, _mainView, &rect_src, &rect_dst);
+}
+
+void EdenGame::cursbuftopanel() {
+ setSrcRect(434, 40, 525 - 1, 111 - 1);
+ setDestRect(114, 40, 205 - 1, 111 - 1);
+ CLBlitter_CopyViewRect(_mainView, _mainView, &rect_src, &rect_dst);
+}
+
+void EdenGame::langbuftopanel() {
+ setSrcRect(328, 42, 407 - 1, 97 - 1);
+ setDestRect(8, 42, 87 - 1, 97 - 1);
+ CLBlitter_CopyViewRect(_mainView, _mainView, &rect_src, &rect_dst);
+}
+
+// Original name: affpanel
+void EdenGame::displayPanel() {
+ useBank(65);
+ noclipax(0, 0, 16);
+ paneltobuf();
+ displayLanguage();
+ displayCursors();
+ affcurstape();
+}
+
+// Original name: afflangue
+void EdenGame::displayLanguage() {
+ useBank(65);
+ if (_globals->_prefLanguage < 0 //TODO: never happens
+ || _globals->_prefLanguage > 5)
+ return;
+ noclipax(6, 8, _globals->_prefLanguage * 9 + 43); //TODO: * FONT_HEIGHT
+ noclipax(7, 77, _globals->_prefLanguage * 9 + 44);
+}
+
+// Original name: affcursvol
+void EdenGame::displayVolCursor(int16 x, int16 vol1, int16 vol2) {
+ int16 slider = 3;
+ if (_lastMenuItemIdLo && (_lastMenuItemIdLo & 9) != 1) //TODO check me
+ slider = 4;
+ noclipax(slider, x, 104 - vol1);
+ slider = 3;
+ if ((_lastMenuItemIdLo & 9) != 0)
+ slider = 4;
+ noclipax(slider, x + 12, 104 - vol2);
+}
+
+// Original name: affcurseurs
+void EdenGame::displayCursors() {
+ useBank(65);
+ if (_globals->_drawFlags & DrawFlags::drDrawFlag8)
+ return;
+ selectCursor(48);
+ displayVolCursor(114, _globals->_prefMusicVol[0] / 4, _globals->_prefMusicVol[1] / 4);
+ selectCursor(50);
+ displayVolCursor(147, _globals->_prefVoiceVol[0] / 4, _globals->_prefVoiceVol[1] / 4);
+ selectCursor(52);
+ displayVolCursor(179, _globals->_prefSoundVolume[0] / 4, _globals->_prefSoundVolume[1] / 4);
+}
+
+// Original name: curseurselect
+void EdenGame::selectCursor(int itemId) {
+ _lastMenuItemIdLo = _globals->_menuItemIdLo;
+ if ((_lastMenuItemIdLo & ~9) != itemId)
+ _lastMenuItemIdLo = 0;
+}
+
+// Original name: afftoppano
+void EdenGame::displayTopPanel() {
+ noclipax(1, 0, 0);
+}
+
+// Original name: affresult
+void EdenGame::displayResult() {
+ restoreUnderSubtitles();
+ _globals->_characterPtr = &kPersons[19];
+ _globals->_dialogType = DialogType::dtInspect;
+ int16 num = (kPersons[PER_UNKN_156]._id << 3) | _globals->_dialogType;
+ if (dialoscansvmas((Dialog *)getElem(_gameDialogs, num)))
+ displaySubtitles();
+ _globals->_varCA = 0;
+ _globals->_dialogType = DialogType::dtTalk;
+ _globals->_characterPtr = nullptr;
+}
+
+// Original name: limitezonecurs
+void EdenGame::restrictCursorArea(int16 xmin, int16 xmax, int16 ymin, int16 ymax) {
+ _cursorPosX = CLIP(_cursorPosX, xmin, xmax);
+ _cursorPosY = CLIP(_cursorPosY, ymin, ymax);
+}
+
+// Original name: PommeQ
+void EdenGame::edenShudown() {
+ Icon *icon = &_gameIcons[85];
+ if (_globals->_displayFlags & DisplayFlags::dfFrescoes) {
+ _torchCursor = false;
+ _cursorSaved = true;
+ if (_globals->_displayFlags & DisplayFlags::dfPerson)
+ closeCharacterScreen();
+ _globals->_displayFlags = DisplayFlags::dfFlag1;
+ resetScroll();
+ _globals->_var100 = 0xFF;
+ updateRoom(_globals->_roomNum);
+ }
+ if (_globals->_displayFlags & DisplayFlags::dfPerson)
+ closeCharacterScreen();
+ if (_globals->_displayFlags & DisplayFlags::dfPanable)
+ resetScroll();
+ if (_globals->_displayFlags & DisplayFlags::dfMirror)
+ resetScroll();
+ if (_globals->_drawFlags & DrawFlags::drDrawFlag8)
+ stoptape();
+ if (_personTalking)
+ endCharacterSpeech();
+ _globals->_var103 = 0;
+ _globals->_mirrorEffect = 0;
+ putObject();
+ _currCursor = 53;
+ if (_globals->_displayFlags != DisplayFlags::dfFlag2)
+ gotoPanel();
+ _curSpot2 = icon + 7; //TODO
+ edenQuit();
+}
+
+void EdenGame::habitants(perso_t *perso) {
+ char persType = perso->_flags & PersonFlags::pfTypeMask; //TODO rename
+ if (persType && persType != PersonFlags::pfType2) {
+ _globals->_roomCharacterPtr = perso;
+ _globals->_roomCharacterType = persType;
+ _globals->_roomCharacterFlags = perso->_flags;
+ _globals->_roomPersoItems = perso->_items;
+ _globals->_roomCharacterPowers = perso->_powers;
+ _globals->_partyOutside |= perso->_partyMask;
+ if (_globals->_roomCharacterType == PersonFlags::pftTriceraptor)
+ removeInfo(_globals->_areaNum + ValleyNews::vnTriceraptorsIn);
+ else if (_globals->_roomCharacterType == PersonFlags::pftVelociraptor)
+ removeInfo(_globals->_areaNum + ValleyNews::vnVelociraptorsIn);
+ } else if (!(perso->_flags & PersonFlags::pfInParty))
+ _globals->_partyOutside |= perso->_partyMask;
+}
+
+void EdenGame::suiveurs(perso_t *perso) {
+ char persType = perso->_flags & PersonFlags::pfTypeMask;
+ if (persType == 0 || persType == PersonFlags::pfType2) {
+ if (perso->_flags & PersonFlags::pfInParty)
+ _globals->_party |= perso->_partyMask;
+ }
+}
+
+void EdenGame::evenements(perso_t *perso) {
+ if (_globals->_var113)
+ return;
+
+ if (perso >= &kPersons[PER_UNKN_18C])
+ return;
+
+ if (!dialogEvent(perso))
+ return;
+
+ _globals->_var113++;
+ _globals->_oldDisplayFlags = 1;
+ perso = _globals->_characterPtr;
+ initCharacterPointers(perso);
+ if (!(perso->_partyMask & PersonMask::pmLeader))
+ _globals->_var60 = 1;
+ _globals->_eventType = 0;
+}
+
+void EdenGame::followme(perso_t *perso) {
+ if (perso->_flags & PersonFlags::pfTypeMask)
+ return;
+ if (perso->_flags & PersonFlags::pfInParty)
+ perso->_roomNum = _destinationRoom;
+}
+
+void EdenGame::rangermammi(perso_t *perso, Room *room) {
+ Room *found_room = nullptr;
+ if (!(perso->_partyMask & PersonMask::pmLeader))
+ return;
+ for (; room->_id != 0xFF; room++) {
+ if (room->_flags & RoomFlags::rfHasCitadel) {
+ found_room = room;
+ break;
+ }
+ if (room->_party != 0xFFFF && (room->_party & PersonMask::pmLeader))
+ found_room = room; //TODO: no brk?
+ }
+ if (!found_room)
+ return;
+ perso->_roomNum &= ~0xFF;
+ perso->_roomNum |= found_room->_location;
+ perso->_flags &= ~PersonFlags::pfInParty;
+ _globals->_party &= ~perso->_partyMask;
+}
+
+void EdenGame::perso_ici(int16 action) {
+ perso_t *perso = &kPersons[PER_UNKN_156];
+// room_t *room = p_global->last_area_ptr->room_ptr; //TODO: compiler opt bug? causes access to zero ptr??? last_area_ptr == 0
+ switch (action) {
+ case 0:
+ suiveurs(perso);
+ break;
+ case 1:
+ habitants(perso);
+ break;
+ case 3:
+ evenements(perso);
+ break;
+ case 4:
+ followme(perso);
+ break;
+ case 5:
+ rangermammi(perso, _globals->_lastAreaPtr->_citadelRoomPtr);
+ break;
+ }
+ perso = kPersons;
+ do {
+ if (perso->_roomNum == _globals->_roomNum && !(perso->_flags & PersonFlags::pf80)) {
+ switch (action) {
+ case 0:
+ suiveurs(perso);
+ break;
+ case 1:
+ habitants(perso);
+ break;
+ case 3:
+ evenements(perso);
+ break;
+ case 4:
+ followme(perso);
+ break;
+ case 5:
+ rangermammi(perso, _globals->_lastAreaPtr->_citadelRoomPtr);
+ break;
+ }
+ }
+ perso++;
+ } while (perso->_roomNum != 0xFFFF);
+}
+
+// Original name: setpersohere
+void EdenGame::setCharacterHere() {
+ debug("setCharacterHere, perso is %ld", _globals->_characterPtr - kPersons);
+ _globals->_partyOutside = 0;
+ _globals->_party = 0;
+ _globals->_roomCharacterPtr = nullptr;
+ _globals->_roomCharacterType = 0;
+ _globals->_roomCharacterFlags = 0;
+ perso_ici(1);
+ perso_ici(0);
+ if (_globals->_roomCharacterType == PersonFlags::pftTyrann)
+ removeInfo(_globals->_areaNum + ValleyNews::vnTyrannIn);
+ if (_globals->_roomCharacterType == PersonFlags::pftTriceraptor)
+ removeInfo(_globals->_areaNum + ValleyNews::vnTriceraptorsIn);
+ if (_globals->_roomCharacterType == PersonFlags::pftVelociraptor) {
+ removeInfo(_globals->_areaNum + ValleyNews::vnTyrannIn);
+ removeInfo(_globals->_areaNum + ValleyNews::vnTyrannLost);
+ removeInfo(_globals->_areaNum + ValleyNews::vnVelociraptorsLost);
+ }
+}
+
+void EdenGame::faire_suivre(int16 roomNum) {
+ _destinationRoom = roomNum;
+ perso_ici(4);
+}
+
+// Original name: suis_moi5
+void EdenGame::AddCharacterToParty() {
+ debug("adding person %ld to party", _globals->_characterPtr - kPersons);
+ _globals->_characterPtr->_flags |= PersonFlags::pfInParty;
+ _globals->_characterPtr->_roomNum = _globals->_roomNum;
+ _globals->_party |= _globals->_characterPtr->_partyMask;
+ _globals->_drawFlags |= DrawFlags::drDrawTopScreen;
+}
+
+// Original name: suis_moi
+void EdenGame::addToParty(int16 index) {
+ perso_t *old_perso = _globals->_characterPtr;
+ _globals->_characterPtr = &kPersons[index];
+ AddCharacterToParty();
+ _globals->_characterPtr = old_perso;
+}
+
+// Original name: reste_ici5
+void EdenGame::removeCharacterFromParty() {
+ debug("removing person %ld from party", _globals->_characterPtr - kPersons);
+ _globals->_characterPtr->_flags &= ~PersonFlags::pfInParty;
+ _globals->_partyOutside |= _globals->_characterPtr->_partyMask;
+ _globals->_party &= ~_globals->_characterPtr->_partyMask;
+ _globals->_drawFlags |= DrawFlags::drDrawTopScreen;
+}
+
+// Original name: reste_ici
+void EdenGame::removeFromParty(int16 index) {
+ perso_t *old_perso = _globals->_characterPtr;
+ _globals->_characterPtr = &kPersons[index];
+ removeCharacterFromParty();
+ _globals->_characterPtr = old_perso;
+}
+
+// Original name: eloipart
+void EdenGame::handleEloiDeparture() {
+ removeFromParty(PER_ELOI);
+ _globals->_gameFlags &= ~GameFlags::gfFlag4000;
+ kPersons[PER_ELOI]._roomNum = 0;
+ _globals->_partyOutside &= ~kPersons[PER_ELOI]._partyMask;
+ if (_globals->_roomNum == 2817)
+ setChrono(3000);
+ _globals->_eloiDepartureDay = _globals->_gameDays;
+ _globals->_eloiHaveNews = 0;
+ unlockInfo();
+}
+
+// Original name: eloirevientq
+bool EdenGame::checkEloiReturn() {
+ if (_globals->_phaseNum < 304)
+ return true;
+ if ((_globals->_phaseNum <= 353) || (_globals->_phaseNum == 370) || (_globals->_phaseNum == 384))
+ return false;
+ if (_globals->_areaNum != Areas::arShandovra)
+ return true;
+ if (_globals->_phaseNum < 480)
+ return false;
+ return true;
+}
+
+// Original name: eloirevient
+void EdenGame::handleEloiReturn() {
+ if (_globals->_areaPtr->_type == AreaType::atValley && !kPersons[PER_ELOI]._roomNum)
+ kPersons[PER_ELOI]._roomNum = (_globals->_roomNum & 0xFF00) + 1;
+}
+//// phase.c
+void EdenGame::incPhase() {
+ static phase_t phases[] = {
+ { 65, &EdenGame::dialautoon },
+ { 113, &EdenGame::phase113 },
+ { 129, &EdenGame::dialautoon },
+ { 130, &EdenGame::phase130 },
+ { 161, &EdenGame::phase161 },
+ { 211, &EdenGame::dialautoon },
+ { 226, &EdenGame::phase226 },
+ { 257, &EdenGame::phase257 },
+ { 353, &EdenGame::phase353 },
+ { 369, &EdenGame::phase369 },
+ { 371, &EdenGame::phase371 },
+ { 385, &EdenGame::phase385 },
+ { 386, &EdenGame::dialonfollow },
+ { 418, &EdenGame::phase418 },
+ { 433, &EdenGame::phase433 },
+ { 434, &EdenGame::phase434 },
+ { 449, &EdenGame::dialautoon },
+ { 497, &EdenGame::dialautoon },
+ { 513, &EdenGame::phase513 },
+ { 514, &EdenGame::phase514 },
+ { 529, &EdenGame::phase529 },
+ { 545, &EdenGame::phase545 },
+ { 561, &EdenGame::phase561 },
+ { -1, nullptr }
+ };
+
+ _globals->_phaseNum++;
+ debug("!!! next phase - %4X , room %4X", _globals->_phaseNum, _globals->_roomNum);
+ _globals->_phaseActionsCount = 0;
+ for (phase_t *phase = phases; phase->_id != -1; phase++) {
+ if (_globals->_phaseNum == phase->_id) {
+ (this->*phase->disp)();
+ break;
+ }
+ }
+}
+
+void EdenGame::phase113() {
+ removeFromParty(PER_DINA);
+ kPersons[PER_DINA]._roomNum = 274;
+}
+
+void EdenGame::phase130() {
+ dialautoon();
+ removeFromParty(PER_MONK);
+}
+
+void EdenGame::phase161() {
+ Area *area = _globals->_areaPtr;
+ addToParty(PER_MAMMI);
+ kPersons[PER_MAMMI]._flags |= PersonFlags::pf10;
+ area->_flags |= AreaFlags::afFlag1;
+ _globals->_curAreaFlags |= AreaFlags::afFlag1;
+}
+
+void EdenGame::phase226() {
+ newObject(16, 3);
+ newObject(16, 4);
+ newObject(16, 5);
+}
+
+void EdenGame::phase257() {
+ _gameIcons[127]._cursorId &= ~0x8000;
+ _globals->_characterBackgroundBankIdx = 58;
+ dialautooff();
+}
+
+void EdenGame::phase353() {
+ removeFromParty(PER_DINA);
+ kPersons[PER_DINA]._roomNum = 0;
+ kTabletView[1] = 88;
+}
+
+void EdenGame::phase369() {
+ addToParty(PER_ELOI);
+ _globals->_narratorSequence = 2;
+ _gameRooms[334]._exits[0] = 134;
+ _gameRooms[335]._exits[0] = 134;
+}
+
+void EdenGame::phase371() {
+ handleEloiReturn();
+ _gameIcons[128]._cursorId &= ~0x8000;
+ _gameIcons[129]._cursorId &= ~0x8000;
+ _gameIcons[127]._cursorId |= 0x8000;
+ _globals->_characterBackgroundBankIdx = 59;
+ _gameRooms[334]._exits[0] = 0xFF;
+ _gameRooms[335]._exits[0] = 0xFF;
+ _gameIcons[123]._objectId = 9;
+ _gameIcons[124]._objectId = 26;
+ _gameIcons[125]._objectId = 42;
+ _gameIcons[126]._objectId = 56;
+}
+
+void EdenGame::phase385() {
+ dialautooff();
+ handleEloiReturn();
+ _globals->_nextInfoIdx = 0;
+ _globals->_lastInfoIdx = 0;
+ updateInfoList();
+ _globals->_lastInfo = 0;
+}
+
+void EdenGame::phase418() {
+ loseObject(Objects::obHorn);
+ dialautoon();
+ addToParty(PER_JABBER);
+}
+
+void EdenGame::phase433() {
+ dialautoon();
+ kPersons[PER_MAMMI_4]._flags &= ~PersonFlags::pf80;
+ kPersons[PER_JABBER]._flags &= ~PersonFlags::pf80;
+ setCharacterHere();
+ _globals->_chronoFlag = 0;
+ _globals->_chrono = 0;
+}
+
+void EdenGame::phase434() {
+ _globals->_roomNum = 275;
+ _gameRooms[16]._bank = 44;
+ _gameRooms[18]._bank = 44;
+ _gameIcons[132]._cursorId &= ~0x8000;
+ _globals->_characterBackgroundBankIdx = 61;
+ _gameRooms[118]._exits[2] = 0xFF;
+ abortDialogue();
+ _gameRooms[7]._bank = 322;
+ removeFromParty(PER_EVE);
+ removeFromParty(PER_MONK);
+ removeFromParty(PER_ELOI);
+ removeFromParty(PER_GUARDS);
+ removeFromParty(PER_JABBER);
+ _globals->_drawFlags |= DrawFlags::drDrawTopScreen;
+}
+
+void EdenGame::phase513() {
+ _globals->_lastDialogPtr = nullptr;
+ parlemoiNormalFlag = false;
+ dialautoon();
+}
+
+void EdenGame::phase514() {
+ _gameRooms[123]._exits[2] = 1;
+}
+
+void EdenGame::phase529() {
+ _gameIcons[133]._cursorId &= ~0x8000;
+ _globals->_characterBackgroundBankIdx = 63;
+}
+
+void EdenGame::phase545() {
+}
+
+void EdenGame::phase561() {
+ _globals->_narratorSequence = 10;
+}
+
+void EdenGame::bigphase1() {
+ static void (EdenGame::*bigphases[])() = {
+ &EdenGame::phase16,
+ &EdenGame::phase32,
+ &EdenGame::phase48,
+ &EdenGame::phase64,
+ &EdenGame::phase80,
+ &EdenGame::phase96,
+ &EdenGame::phase112,
+ &EdenGame::phase128,
+ &EdenGame::phase144,
+ &EdenGame::phase160,
+ &EdenGame::phase176,
+ &EdenGame::phase192,
+ &EdenGame::phase208,
+ &EdenGame::phase224,
+ &EdenGame::phase240,
+ &EdenGame::phase256,
+ &EdenGame::phase272,
+ &EdenGame::phase288,
+ &EdenGame::phase304,
+ &EdenGame::phase320,
+ &EdenGame::phase336,
+ &EdenGame::phase352,
+ &EdenGame::phase368,
+ &EdenGame::phase384,
+ &EdenGame::phase400,
+ &EdenGame::phase416,
+ &EdenGame::phase432,
+ &EdenGame::phase448,
+ &EdenGame::phase464,
+ &EdenGame::phase480,
+ &EdenGame::phase496,
+ &EdenGame::phase512,
+ &EdenGame::phase528,
+ &EdenGame::phase544,
+ &EdenGame::phase560
+ };
+
+ int16 phase = (_globals->_phaseNum & ~3) + 0x10; //TODO: check me
+ debug("!!! big phase - %4X", phase);
+ _globals->_phaseActionsCount = 0;
+ _globals->_phaseNum = phase;
+ if (phase > 560)
+ return;
+ phase >>= 4;
+ (this->*bigphases[phase - 1])();
+}
+
+void EdenGame::bigphase() {
+ if (!(_globals->_dialogPtr->_flags & DialogFlags::dfSpoken))
+ bigphase1();
+}
+
+void EdenGame::phase16() {
+ dialautoon();
+}
+
+void EdenGame::phase32() {
+ word_31E7A &= ~0x8000;
+}
+
+void EdenGame::phase48() {
+ _gameRooms[8]._exits[1] = 22;
+ dialautoon();
+}
+
+void EdenGame::phase64() {
+ addToParty(PER_DINA);
+ kPersons[PER_ELOI]._roomNum = 259;
+}
+
+void EdenGame::phase80() {
+ kPersons[PER_TAU]._roomNum = 0;
+}
+
+void EdenGame::phase96() {
+}
+
+void EdenGame::phase112() {
+ giveObject();
+}
+
+void EdenGame::phase128() {
+ addToParty(PER_DINA);
+ giveObject();
+}
+
+void EdenGame::phase144() {
+ addToParty(PER_ELOI);
+ _gameRooms[113]._video = 0;
+ _gameRooms[113]._bank = 317;
+}
+
+void EdenGame::phase160() {
+}
+
+void EdenGame::phase176() {
+ dialonfollow();
+}
+
+void EdenGame::phase192() {
+ Area *area = _globals->_areaPtr;
+ addToParty(PER_MAMMI_1);
+ kPersons[PER_MAMMI_1]._flags |= PersonFlags::pf10;
+ dialautoon();
+ area->_flags |= AreaFlags::afFlag1;
+ _globals->_curAreaFlags |= AreaFlags::afFlag1;
+}
+
+void EdenGame::phase208() {
+ handleEloiReturn();
+}
+
+void EdenGame::phase224() {
+ _gameIcons[126]._cursorId &= ~0x8000;
+ _globals->_characterBackgroundBankIdx = 57;
+ dialautooff();
+}
+
+void EdenGame::phase240() {
+ Area *area = _globals->_areaPtr;
+ addToParty(PER_MAMMI_2);
+ kPersons[PER_MAMMI_2]._flags |= PersonFlags::pf10;
+ area->_flags |= AreaFlags::afFlag1;
+ _globals->_curAreaFlags |= AreaFlags::afFlag1;
+}
+
+void EdenGame::phase256() {
+ dialautoon();
+}
+
+void EdenGame::phase272() {
+ dialautoon();
+ _globals->_eloiHaveNews = 0;
+}
+
+void EdenGame::phase288() {
+ setChoiceYes();
+ kPersons[PER_MUNGO]._roomNum = 0;
+ removeFromParty(PER_MUNGO);
+ addToParty(PER_ELOI);
+ _globals->_narratorSequence = 8;
+}
+
+void EdenGame::phase304() {
+ Area *area = _globals->_areaPtr;
+ addToParty(PER_EVE);
+ addToParty(PER_MAMMI_5);
+ kPersons[PER_MAMMI_5]._flags |= PersonFlags::pf10;
+ dialautoon();
+ area->_flags |= AreaFlags::afFlag1;
+ _globals->_curAreaFlags |= AreaFlags::afFlag1;
+}
+
+void EdenGame::phase320() {
+ dialonfollow();
+}
+
+void EdenGame::phase336() {
+ _gameRooms[288]._exits[0] = 135;
+ _gameRooms[289]._exits[0] = 135;
+ loseObject(_globals->_curObjectId);
+ dialautoon();
+}
+
+void EdenGame::phase352() {
+ kPersoRoomBankTable[30] = 26;
+ kPersons[PER_EVE]._spriteBank = 9;
+ kPersons[PER_EVE]._targetLoc = 8;
+ followerList[13]._spriteNum = 2;
+ dialautoon();
+ _gameRooms[288]._exits[0] = 0xFF;
+ _gameRooms[289]._exits[0] = 0xFF;
+ _gameRooms[288]._flags &= ~RoomFlags::rf02;
+ _gameRooms[289]._flags &= ~RoomFlags::rf02;
+}
+
+void EdenGame::phase368() {
+ removeFromParty(PER_EVE);
+ dialautoon();
+ kPersons[PER_ELOI]._roomNum = 1811;
+ kPersons[PER_DINA]._roomNum = 1607;
+}
+
+void EdenGame::phase384() {
+ Area *area = _globals->_areaPtr;
+ addToParty(PER_EVE);
+ removeFromParty(PER_DINA);
+ dialautoon();
+ area->_flags |= AreaFlags::afFlag1;
+ _globals->_curAreaFlags |= AreaFlags::afFlag1;
+ handleEloiDeparture();
+}
+
+void EdenGame::phase400() {
+ dialonfollow();
+ kPersons[PER_KING]._roomNum = 0;
+ kPersons[PER_MONK]._roomNum = 259;
+ _globals->_eloiHaveNews = 0;
+ kObjectLocations[20] = 259;
+}
+
+void EdenGame::phase416() {
+ addToParty(PER_MONK);
+ _gameIcons[130]._cursorId &= ~0x8000;
+ _globals->_characterBackgroundBankIdx = 60;
+ _gameRooms[0]._exits[0] = 138;
+}
+
+void EdenGame::phase432() {
+ _globals->_narratorSequence = 3;
+ kPersons[PER_MAMMI_4]._flags |= PersonFlags::pf80;
+ kPersons[PER_JABBER]._flags |= PersonFlags::pf80;
+ kPersons[PER_ELOI]._roomNum = 257;
+ _gameRooms[0]._exits[0] = 0xFF;
+ _globals->_drawFlags |= DrawFlags::drDrawTopScreen;
+}
+
+void EdenGame::phase448() {
+ dialautoon();
+ handleEloiDeparture();
+}
+
+void EdenGame::phase464() {
+ _globals->_areaPtr->_flags |= AreaFlags::afFlag1;
+ _globals->_curAreaFlags |= AreaFlags::afFlag1;
+ kPersons[PER_MAMMI_6]._flags |= PersonFlags::pf10;
+ addToParty(PER_SHAZIA);
+ _globals->_citadelAreaNum = _globals->_areaNum;
+ naitredino(8);
+}
+
+void EdenGame::phase480() {
+ giveObject();
+ newValley();
+ handleEloiReturn();
+ kTabletView[1] = 94;
+}
+
+void EdenGame::phase496() {
+ dialautoon();
+ _globals->_lastDialogPtr = nullptr;
+ parlemoiNormalFlag = false;
+}
+
+void EdenGame::phase512() {
+ removeFromParty(PER_MONK);
+ removeFromParty(PER_EVE);
+ removeFromParty(PER_SHAZIA);
+ removeFromParty(PER_GUARDS);
+}
+
+void EdenGame::phase528() {
+ _globals->_narratorSequence = 11;
+ addToParty(PER_MONK);
+ addToParty(PER_ELOI);
+ addToParty(PER_EVE);
+ addToParty(PER_SHAZIA);
+ addToParty(PER_GUARDS);
+}
+
+void EdenGame::phase544() {
+ handleEloiDeparture();
+ dialautoon();
+ removeFromParty(PER_SHAZIA);
+ removeFromParty(PER_GUARDS);
+}
+
+void EdenGame::phase560() {
+ kPersons[PER_ELOI]._roomNum = 3073;
+ _gameRooms[127]._exits[1] = 0;
+}
+
+//// saveload.c
+void EdenGame::savegame(char *name) {
+// filespec_t fs;
+// Common::File handle;
+ int32 size;
+// CLFile_MakeStruct(0, 0, name, &fs);
+// CLFile_Create(&fs);
+// CLFile_SetFinderInfos(&fs, 'EDNS', 'LEDN');
+// CLFile_Open(&fs, 3, handle);
+
+ Common::OutSaveFile *handle = g_system->getSavefileManager()->openForSaving(name);
+ if (!handle)
+ return;
+
+#define CLFile_Write(h, ptr, size) \
+debug("writing 0x%X bytes", *size); \
+h->write(ptr, *size);
+
+ vavaoffsetout();
+ size = (char *)(&_globals->_saveEnd) - (char *)(_globals);
+ CLFile_Write(handle, _globals, &size);
+ size = (char *)(&_gameIcons[134]) - (char *)(&_gameIcons[123]);
+ CLFile_Write(handle, &_gameIcons[123], &size);
+ lieuoffsetout();
+ size = (char *)(&kAreasTable[12]) - (char *)(&kAreasTable[0]);
+ CLFile_Write(handle, &kAreasTable[0], &size);
+ size = (char *)(&_gameRooms[423]) - (char *)(&_gameRooms[0]);
+ CLFile_Write(handle, &_gameRooms[0], &size);
+ size = (char *)(&_objects[42]) - (char *)(&_objects[0]);
+ CLFile_Write(handle, &_objects[0], &size);
+ size = (char *)(&kObjectLocations[45]) - (char *)(&kObjectLocations[0]);
+ CLFile_Write(handle, &kObjectLocations[0], &size);
+ size = (char *)(&followerList[14]) - (char *)(&followerList[13]);
+ CLFile_Write(handle, &followerList[13], &size);
+ size = (char *)(&kPersons[PER_UNKN_3DE]) - (char *)(&kPersons[PER_KING]);
+ CLFile_Write(handle, &kPersons[PER_KING], &size);
+ bandeoffsetout();
+ size = (char *)(&_tapes[16]) - (char *)(&_tapes[0]);
+ CLFile_Write(handle, &_tapes[0], &size);
+ size = (char *)(&kTabletView[6]) - (char *)(&kTabletView[0]);
+ CLFile_Write(handle, &kTabletView[0], &size);
+ size = (char *)(&_gameDialogs[10240]) - (char *)(&_gameDialogs[0]); //TODO: const size 10240
+ CLFile_Write(handle, &_gameDialogs[0], &size);
+
+ delete handle;
+
+#undef CLFile_Write
+
+// CLFile_Close(handle);
+
+ vavaoffsetin();
+ lieuoffsetin();
+ bandeoffsetin();
+
+ debug("* Game saved to %s", name);
+}
+
+void EdenGame::loadrestart() {
+ assert(0); //TODO: this won't work atm - all snapshots are BE
+ int32 offs = 0;
+ int32 size;
+ size = (char *)(&_globals->_saveEnd) - (char *)(_globals);
+ loadpartoffile(2495, _globals, offs, size);
+ offs += size;
+ vavaoffsetin();
+ size = (char *)(&_gameIcons[134]) - (char *)(&_gameIcons[123]);
+ loadpartoffile(2495, &_gameIcons[123], offs, size);
+ offs += size;
+ size = (char *)(&kAreasTable[12]) - (char *)(&kAreasTable[0]);
+ loadpartoffile(2495, &kAreasTable[0], offs, size);
+ offs += size;
+ lieuoffsetin();
+ size = (char *)(&_gameRooms[423]) - (char *)(&_gameRooms[0]);
+ loadpartoffile(2495, &_gameRooms[0], offs, size);
+ offs += size;
+ size = (char *)(&_objects[42]) - (char *)(&_objects[0]);
+ loadpartoffile(2495, &_objects[0], offs, size);
+ offs += size;
+ size = (char *)(&kObjectLocations[45]) - (char *)(&kObjectLocations[0]);
+ loadpartoffile(2495, &kObjectLocations[0], offs, size);
+ offs += size;
+ size = (char *)(&followerList[14]) - (char *)(&followerList[13]);
+ loadpartoffile(2495, &followerList[13], offs, size);
+ offs += size;
+ size = (char *)(&kPersons[PER_UNKN_3DE]) - (char *)(&kPersons[PER_KING]);
+ loadpartoffile(2495, &kPersons[PER_KING], offs, size);
+ offs += size;
+ size = (char *)(&_tapes[16]) - (char *)(&_tapes[0]);
+ loadpartoffile(2495, &_tapes[0], offs, size);
+ offs += size;
+ bandeoffsetin();
+ size = (char *)(&kTabletView[6]) - (char *)(&kTabletView[0]);
+ loadpartoffile(2495, &kTabletView[0], offs, size);
+ offs += size;
+ size = (char *)(&_gameDialogs[10240]) - (char *)(&_gameDialogs[0]); //TODO: const size 10240
+ loadpartoffile(2495, &_gameDialogs[0], offs, size);
+ _gameLoaded = true;
+}
+
+void EdenGame::loadgame(char *name) {
+// filespec_t fs;
+// Common::File handle;
+// CLFile_MakeStruct(0, 0, name, &fs);
+// CLFile_Open(&fs, 3, handle);
+
+ Common::InSaveFile *handle = g_system->getSavefileManager()->openForLoading(name);
+ if (!handle)
+ return;
+
+#define CLFile_Read(h, ptr, size) \
+ h->read(ptr, *size);
+
+ int32 size = (char *)(&_globals->_saveEnd) - (char *)(_globals);
+ CLFile_Read(handle, _globals, &size);
+ vavaoffsetin();
+ size = (char *)(&_gameIcons[134]) - (char *)(&_gameIcons[123]);
+ CLFile_Read(handle, &_gameIcons[123], &size);
+ size = (char *)(&kAreasTable[12]) - (char *)(&kAreasTable[0]);
+ CLFile_Read(handle, &kAreasTable[0], &size);
+ lieuoffsetin();
+ size = (char *)(&_gameRooms[423]) - (char *)(&_gameRooms[0]);
+ CLFile_Read(handle, &_gameRooms[0], &size);
+ size = (char *)(&_objects[42]) - (char *)(&_objects[0]);
+ CLFile_Read(handle, &_objects[0], &size);
+ size = (char *)(&kObjectLocations[45]) - (char *)(&kObjectLocations[0]);
+ CLFile_Read(handle, &kObjectLocations[0], &size);
+ size = (char *)(&followerList[14]) - (char *)(&followerList[13]);
+ CLFile_Read(handle, &followerList[13], &size);
+ size = (char *)(&kPersons[55]) - (char *)(&kPersons[0]);
+ CLFile_Read(handle, &kPersons[0], &size);
+ size = (char *)(&_tapes[16]) - (char *)(&_tapes[0]);
+ CLFile_Read(handle, &_tapes[0], &size);
+ bandeoffsetin();
+ size = (char *)(&kTabletView[6]) - (char *)(&kTabletView[0]);
+ CLFile_Read(handle, &kTabletView[0], &size);
+ size = (char *)(&_gameDialogs[10240]) - (char *)(&_gameDialogs[0]); //TODO: const size 10240
+ CLFile_Read(handle, &_gameDialogs[0], &size);
+
+ delete handle;
+#undef CLFile_Read
+
+// CLFile_Close(handle);
+ _gameLoaded = true;
+ debug("* Game loaded from %s", name);
+}
+
+#define NULLPTR (void*)0xFFFFFF
+#define OFSOUT(val, base, typ) if (val) (val) = (typ*)((char*)(val) - (size_t)(base)); else (val) = (typ*)NULLPTR;
+#define OFSIN(val, base, typ) if ((void*)(val) != NULLPTR) (val) = (typ*)((char*)(val) + (size_t)(base)); else (val) = 0;
+
+void EdenGame::vavaoffsetout() {
+ OFSOUT(_globals->_dialogPtr, _gameDialogs, Dialog);
+ OFSOUT(_globals->_nextDialogPtr, _gameDialogs, Dialog);
+ OFSOUT(_globals->_narratorDialogPtr, _gameDialogs, Dialog);
+ OFSOUT(_globals->_lastDialogPtr, _gameDialogs, Dialog);
+ OFSOUT(_globals->_tapePtr, _tapes, tape_t);
+ OFSOUT(_globals->_nextRoomIcon, _gameIcons, Icon);
+ OFSOUT(_globals->_roomPtr, _gameRooms, Room);
+ OFSOUT(_globals->_citaAreaFirstRoom, _gameRooms, Room);
+ OFSOUT(_globals->_areaPtr, kAreasTable, Area);
+ OFSOUT(_globals->_lastAreaPtr, kAreasTable, Area);
+ OFSOUT(_globals->_curAreaPtr, kAreasTable, Area);
+ OFSOUT(_globals->_characterPtr, kPersons, perso_t);
+ OFSOUT(_globals->_roomCharacterPtr, kPersons, perso_t);
+}
+
+void EdenGame::vavaoffsetin() {
+ OFSIN(_globals->_dialogPtr, _gameDialogs, Dialog);
+ OFSIN(_globals->_nextDialogPtr, _gameDialogs, Dialog);
+ OFSIN(_globals->_narratorDialogPtr, _gameDialogs, Dialog);
+ OFSIN(_globals->_lastDialogPtr, _gameDialogs, Dialog);
+ OFSIN(_globals->_tapePtr, _tapes, tape_t);
+ OFSIN(_globals->_nextRoomIcon, _gameIcons, Icon);
+ OFSIN(_globals->_roomPtr, _gameRooms, Room);
+ OFSIN(_globals->_citaAreaFirstRoom, _gameRooms, Room);
+ OFSIN(_globals->_areaPtr, kAreasTable, Area);
+ OFSIN(_globals->_lastAreaPtr, kAreasTable, Area);
+ OFSIN(_globals->_curAreaPtr, kAreasTable, Area);
+ OFSIN(_globals->_characterPtr, kPersons, perso_t);
+ OFSIN(_globals->_roomCharacterPtr, kPersons, perso_t);
+}
+
+void EdenGame::lieuoffsetout() {
+ for (int i = 0; i < 12; i++)
+ OFSOUT(kAreasTable[i]._citadelRoomPtr, _gameRooms, Room);
+}
+
+void EdenGame::lieuoffsetin() {
+ for (int i = 0; i < 12; i++)
+ OFSIN(kAreasTable[i]._citadelRoomPtr, _gameRooms, Room);
+}
+
+void EdenGame::bandeoffsetout() {
+ for (int i = 0; i < 16; i++) {
+ OFSOUT(_tapes[i]._perso, kPersons, perso_t);
+ OFSOUT(_tapes[i]._dialog, _gameDialogs, Dialog);
+ }
+}
+
+void EdenGame::bandeoffsetin() {
+ for (int i = 0; i < 16; i++) {
+ OFSIN(_tapes[i]._perso, kPersons, perso_t);
+ OFSIN(_tapes[i]._dialog, _gameDialogs, Dialog);
+ }
+}
+
+//// cond.c
+
+char EdenGame::testCondition(int16 index) {
+ bool endFl = false;
+ uint16 stack[32];
+ uint16 *sp = stack;
+ assert(index > 0);
+ _codePtr = (byte *)getElem(_gameConditions, (index - 1));
+ uint16 value;
+ do {
+ value = fetchValue();
+ for (;;) {
+ byte op = *_codePtr++;
+ if (op == 0xFF) {
+ endFl = true;
+ break;
+ }
+ if ((op & 0x80) == 0) {
+ uint16 value2 = fetchValue();
+ value = operation(op, value, value2);
+ } else {
+ assert(sp < stack + 32);
+ *sp++ = value;
+ *sp++ = op;
+ break;
+ }
+ }
+ } while (!endFl);
+
+ if (sp != stack) {
+ *sp++ = value;
+ uint16 *sp2 = stack;
+ value = *sp2++;
+ do {
+ byte op = *sp2++;
+ uint16 value2 = *sp2++;
+ value = operation(op, value, value2);
+ } while (sp2 != sp);
+ }
+// if (value)
+ debug("cond %d(-1) returns %s", index, value ? "TRUE" : "false");
+// if (index == 402) debug("(glob_61.b == %X) & (glob_12.w == %X) & (glob_4C.b == %X) & (glob_4E.b == %X)", p_global->eventType, p_global->phaseNum, p_global->worldTyrannSighted, p_global->ff_4E);
+ return value != 0;
+}
+
+// Original name: opera_add
+uint16 EdenGame::operAdd(uint16 v1, uint16 v2) {
+ return v1 + v2;
+}
+
+// Original name: opera_sub
+uint16 EdenGame::operSub(uint16 v1, uint16 v2) {
+ return v1 - v2;
+}
+
+// Original name: opera_and
+uint16 EdenGame::operLogicalAnd(uint16 v1, uint16 v2) {
+ return v1 & v2;
+}
+
+// Original name: opera_or
+uint16 EdenGame::operLogicalOr(uint16 v1, uint16 v2) {
+ return v1 | v2;
+}
+
+// Original name: opera_egal
+uint16 EdenGame::operIsEqual(uint16 v1, uint16 v2) {
+ return v1 == v2 ? -1 : 0;
+}
+
+// Original name: opera_petit
+uint16 EdenGame::operIsSmaller(uint16 v1, uint16 v2) {
+ return v1 < v2 ? -1 : 0; //TODO: all comparisons are unsigned!
+}
+
+// Original name: opera_grand
+uint16 EdenGame::operIsGreater(uint16 v1, uint16 v2) {
+ return v1 > v2 ? -1 : 0;
+}
+
+// Original name: opera_diff
+uint16 EdenGame::operIsDifferent(uint16 v1, uint16 v2) {
+ return v1 != v2 ? -1 : 0;
+}
+
+// Original name: opera_petega
+uint16 EdenGame::operIsSmallerOrEqual(uint16 v1, uint16 v2) {
+ return v1 <= v2 ? -1 : 0;
+}
+
+// Original name: opera_graega
+uint16 EdenGame::operIsGreaterOrEqual(uint16 v1, uint16 v2) {
+ return v1 >= v2 ? -1 : 0;
+}
+
+// Original name: opera_faux
+uint16 EdenGame::operFalse(uint16 v1, uint16 v2) {
+ return 0;
+}
+
+uint16 EdenGame::operation(byte op, uint16 v1, uint16 v2) {
+ static uint16(EdenGame::*operations[16])(uint16, uint16) = {
+ &EdenGame::operIsEqual,
+ &EdenGame::operIsSmaller,
+ &EdenGame::operIsGreater,
+ &EdenGame::operIsDifferent,
+ &EdenGame::operIsSmallerOrEqual,
+ &EdenGame::operIsGreaterOrEqual,
+ &EdenGame::operAdd,
+ &EdenGame::operSub,
+ &EdenGame::operLogicalAnd,
+ &EdenGame::operLogicalOr,
+ &EdenGame::operFalse,
+ &EdenGame::operFalse,
+ &EdenGame::operFalse,
+ &EdenGame::operFalse,
+ &EdenGame::operFalse,
+ &EdenGame::operFalse
+ };
+ return (this->*operations[(op & 0x1F) >> 1])(v1, v2);
+}
+
+#define VAR(ofs, var) case ofs: return _globals->var;
+
+uint8 EdenGame::getByteVar(uint16 offset) {
+ switch (offset) {
+ VAR(0, _areaNum);
+ VAR(1, _areaVisitCount);
+ VAR(2, _menuItemIdLo);
+ VAR(3, _menuItemIdHi); //TODO: pad?
+ VAR(0x42, _newMusicType);
+ VAR(0x43, _var43);
+ VAR(0x44, _videoSubtitleIndex);
+ VAR(0x45, _partyInstruments); // &1 - Bell for Monk, &2 - Drum for Thugg
+ VAR(0x46, _monkGotRing);
+ VAR(0x47, _chronoFlag);
+ VAR(0x48, _curRoomFlags);
+ VAR(0x49, _endGameFlag);
+ VAR(0x4A, _lastInfo);
+ VAR(0x4B, _autoDialog);
+ VAR(0x4C, _worldTyranSighted);
+ VAR(0x4D, _var4D);
+ VAR(0x4E, _var4E);
+ VAR(0x4F, _worldGaveGold);
+ VAR(0x50, _worldHasTriceraptors);
+ VAR(0x51, _worldHasVelociraptors);
+ VAR(0x52, _worldHasTyran);
+ VAR(0x53, _var53);
+ VAR(0x54, _var54); //CHEKME: Used?
+ VAR(0x55, _var55); //TODO: pad?
+ VAR(0x56, _gameHours);
+ VAR(0x57, _textToken1);
+ VAR(0x58, _textToken2); //TODO: pad?
+ VAR(0x59, _eloiHaveNews);
+ VAR(0x5A, _dialogFlags);
+ VAR(0x5B, _curAreaType);
+ VAR(0x5C, _curCitadelLevel);
+ VAR(0x5D, _newLocation);
+ VAR(0x5E, _prevLocation);
+ VAR(0x5F, _curPersoFlags);
+ VAR(0x60, _var60);
+ VAR(0x61, _eventType);
+ VAR(0x62, _var62); //TODO: pad?
+ VAR(0x63, _curObjectId);
+ VAR(0x64, _curObjectFlags);
+ VAR(0x65, _var65); //TODO: pad?
+ VAR(0x66, _roomCharacterType);
+ VAR(0x67, _roomCharacterFlags);
+ VAR(0x68, _narratorSequence);
+ VAR(0x69, _var69);
+ VAR(0x6A, _var6A);
+ VAR(0x6B, _frescoNumber);
+ VAR(0x6C, _var6C); //TODO: pad?
+ VAR(0x6D, _var6D); //TODO: pad?
+ VAR(0x6E, _labyrinthDirections);
+ VAR(0x6F, _labyrinthRoom);
+ default:
+ error("Undefined byte variable access (0x%X)", offset);
+ }
+ return 0;
+}
+
+uint16 EdenGame::getWordVar(uint16 offset) {
+ switch (offset) {
+ VAR(4, _randomNumber); //TODO: this is randomized in pc ver and used by some conds. always zero on mac
+ VAR(6, _gameTime);
+ VAR(8, _gameDays);
+ VAR(0xA, _chrono);
+ VAR(0xC, _eloiDepartureDay);
+ VAR(0xE, _roomNum); // current room number
+ VAR(0x10, _newRoomNum); // target room number selected on world map
+ VAR(0x12, _phaseNum);
+ VAR(0x14, _metPersonsMask1);
+ VAR(0x16, _party);
+ VAR(0x18, _partyOutside);
+ VAR(0x1A, _metPersonsMask2);
+ VAR(0x1C, _var1C); //TODO: write-only?
+ VAR(0x1E, _phaseActionsCount);
+ VAR(0x20, _curAreaFlags);
+ VAR(0x22, _curItemsMask);
+ VAR(0x24, _curPowersMask);
+ VAR(0x26, _curPersoItems);
+ VAR(0x28, _curCharacterPowers);
+ VAR(0x2A, _wonItemsMask);
+ VAR(0x2C, _wonPowersMask);
+ VAR(0x2E, _stepsToFindAppleFast);
+ VAR(0x30, _stepsToFindAppleNormal);
+ VAR(0x32, _roomPersoItems); //TODO: write-only?
+ VAR(0x34, _roomCharacterPowers); //TODO: write-only?
+ VAR(0x36, _gameFlags);
+ VAR(0x38, _curVideoNum);
+ VAR(0x3A, _morkusSpyVideoNum1); //TODO: pad?
+ VAR(0x3C, _morkusSpyVideoNum2); //TODO: pad?
+ VAR(0x3E, _morkusSpyVideoNum3); //TODO: pad?
+ VAR(0x40, _morkusSpyVideoNum4); //TODO: pad?
+ default:
+ error("Undefined word variable access (0x%X)", offset);
+ }
+ return 0;
+}
+
+#undef VAR
+
+// Original name: cher_valeur
+uint16 EdenGame::fetchValue() {
+ uint16 val;
+ byte typ = *_codePtr++;
+ if (typ < 0x80) {
+ byte ofs = *_codePtr++;
+ val = (typ == 1) ? getByteVar(ofs) : getWordVar(ofs);
+ } else if (typ == 0x80)
+ val = *_codePtr++;
+ else {
+ val = READ_LE_UINT16(_codePtr);
+ _codePtr += 2;
+ }
+ return val;
+}
+
+// Original name: ret
+void EdenGame::actionNop() {
+}
+
+//// cube.c
+// Original name: make_tabcos
+void EdenGame::initSinCosTable() {
+ for (int i = 0; i < 361; i++) {
+ _cosTable[i] = (int)(cos(3.1416 * i / 180.0) * 255.0);
+ _sinTable[i] = (int)(sin(3.1416 * i / 180.0) * 255.0);
+ }
+}
+
+void EdenGame::makeMatriceFix() {
+ int16 rotAngleTheta = _rotationAngleX;
+ int16 rotAnglePhi = _rotationAngleY;
+ int16 rotAnglePsi = _rotationAngleZ;
+
+ _passMat31 = (_cosTable[rotAnglePhi] * _cosTable[rotAngleTheta]) >> 8;
+ _passMat32 = (_sinTable[rotAnglePhi] * _cosTable[rotAngleTheta]) >> 8;
+ _passMat33 = -_sinTable[rotAngleTheta];
+ _passMat21 = ((-_sinTable[rotAnglePhi] * _cosTable[rotAnglePsi]) >> 8)
+ + ((_sinTable[rotAnglePsi] * ((_cosTable[rotAnglePhi] * _sinTable[rotAngleTheta]) >> 8)) >> 8);
+ _passMat22 = ((_cosTable[rotAnglePhi] * _cosTable[rotAnglePsi]) >> 8)
+ + ((_sinTable[rotAnglePsi] * ((_sinTable[rotAnglePhi] * _sinTable[rotAngleTheta]) >> 8)) >> 8);
+ _passMat23 = (_cosTable[rotAngleTheta] * _sinTable[rotAnglePsi]) >> 8;
+ _passMat11 = ((_sinTable[rotAnglePhi] * _sinTable[rotAnglePsi]) >> 8)
+ + ((_cosTable[rotAnglePsi] * ((_cosTable[rotAnglePhi] * _sinTable[rotAngleTheta]) >> 8)) >> 8);
+ _passMat12 = ((-_cosTable[rotAnglePhi] * _sinTable[rotAnglePsi]) >> 8)
+ + ((_cosTable[rotAnglePsi] * ((_sinTable[rotAnglePhi] * _sinTable[rotAngleTheta]) >> 8)) >> 8);
+ _passMat13 = (_cosTable[rotAngleTheta] * _cosTable[rotAnglePsi]) >> 8;
+}
+
+void EdenGame::projectionFix(Cube *cubep, int n) {
+ for (int i = 0; i < n; i++) {
+ int x = cubep->_vertices[i].x;
+ int y = cubep->_vertices[i].y;
+ int z = cubep->_vertices[i].z;
+
+ int transformX = _passMat31 * x + _passMat21 * y + _passMat11 * z + (int)(_translationX * 256.0f);
+ int transformY = _passMat32 * x + _passMat22 * y + _passMat12 * z + (int)(_translationY * 256.0f);
+ int transformZ = _passMat33 * x + _passMat23 * y + _passMat13 * z + (int)(_translationZ * 256.0f);
+
+ transformZ >>= 8;
+ if (transformZ == -256)
+ transformZ++;
+ cubep->_projection[i].x = transformX / (transformZ + 256) + _cursorPosX + 14 + _scrollPos;
+ cubep->_projection[i].y = transformY / (transformZ + 256) + _cursorPosY + 14;
+ cubep->_projection[i].z = transformZ;
+ }
+}
+
+// Original name init_cube
+void EdenGame::initCubeMac() {
+ loadMap(2493, _cubeTexture);
+ NEWcharge_objet_mob(&_cube, 2494, _cubeTexture);
+ initSinCosTable();
+}
+
+void EdenGame::engineMac() {
+ Eden_dep_and_rot();
+ makeMatriceFix();
+ projectionFix(&_cube, _cubeFaces);
+ displayObject(&_cube);
+}
+
+// Original name: affiche_objet
+void EdenGame::displayObject(Cube *cubep) {
+ for (int i = 0; i < cubep->_num; i++)
+ displayPolygoneMapping(cubep, cubep->_faces[i]);
+}
+
+// Original name: NEWcharge_map
+void EdenGame::loadMap(int file_id, byte *buffer) {
+ if (_vm->getPlatform() == Common::kPlatformMacintosh) {
+ loadpartoffile(file_id, buffer, 32, 256 * 3);
+
+ for (int i = 0; i < 256; i++) {
+ color3_t color;
+ color.r = buffer[i * 3] << 8;
+ color.g = buffer[i * 3 + 1] << 8;
+ color.b = buffer[i * 3 + 2] << 8;
+ CLPalette_SetRGBColor(_globalPalette, i, &color);
+ }
+ CLPalette_Send2Screen(_globalPalette, 0, 256);
+
+ loadpartoffile(file_id, buffer, 32 + 256 * 3, 0x4000);
+ } else {
+#if 0
+// Fake Mac cursor on PC
+ Common::File f;
+ if (f.open("curs.raw")) {
+ f.seek(32);
+ f.read(buffer, 256 * 3);
+
+ for (i = 0; i < 256; i++) {
+ color3_t color;
+ color.r = buffer[i * 3] << 8;
+ color.g = buffer[i * 3 + 1] << 8;
+ color.b = buffer[i * 3 + 2] << 8;
+ CLPalette_SetRGBColor(global_palette, i, &color);
+ }
+ CLPalette_Send2Screen(global_palette, 0, 256);
+
+ f.read(buffer, 0x4000);
+
+ f.close();
+ }
+ else
+ error("can not load cursor texture");
+#endif
+ }
+}
+
+void EdenGame::NEWcharge_objet_mob(Cube *cubep, int fileNum, byte *texturePtr) {
+ char *tmp1 = (char *)malloc(454);
+ if (_vm->getPlatform() == Common::kPlatformMacintosh)
+ loadpartoffile(fileNum, tmp1, 0, 454);
+ else {
+#if 0
+// Fake Mac cursor on PC
+ Common::File f;
+ if (f.open("curseden.mob")) {
+ f.read(tmp1, 454);
+ f.close();
+ }
+ else
+ ::error("can not load cursor model");
+#endif
+ }
+
+ char *next = tmp1;
+ char error;
+ _cubeFaces = nextVal(&next, &error);
+ Point3D *vertices = (Point3D *)malloc(_cubeFaces * sizeof(*vertices));
+ Point3D *projection = (Point3D *)malloc(_cubeFaces * sizeof(*projection));
+ for (int i = 0; i < _cubeFaces; i++) {
+ vertices[i].x = nextVal(&next, &error);
+ vertices[i].y = nextVal(&next, &error);
+ vertices[i].z = nextVal(&next, &error);
+ }
+ int count2 = nextVal(&next, &error);
+ CubeFace **tmp4 = (CubeFace **)malloc(count2 * sizeof(*tmp4));
+ for (int i = 0; i < count2; i++) {
+ tmp4[i] = (CubeFace *)malloc(sizeof(CubeFace));
+ tmp4[i]->tri = 3;
+ char textured = nextVal(&next, &error);
+ tmp4[i]->ff_5 = nextVal(&next, &error);
+ tmp4[i]->_indices = (uint16 *)malloc(3 * sizeof(*tmp4[i]->_indices));
+ tmp4[i]->_uv = (int16 *)malloc(3 * 2 * sizeof(*tmp4[i]->_uv));
+ for (int j = 0; j < 3; j++) {
+ tmp4[i]->_indices[j] = nextVal(&next, &error);
+ if (textured) {
+ tmp4[i]->_uv[j * 2] = nextVal(&next, &error);
+ tmp4[i]->_uv[j * 2 + 1] = nextVal(&next, &error);
+ }
+ }
+ if (textured) {
+ tmp4[i]->ff_4 = 3;
+ tmp4[i]->_texturePtr = texturePtr;
+ } else
+ tmp4[i]->ff_4 = 0;
+ }
+ free(tmp1);
+ cubep->_num = count2;
+ cubep->_faces = tmp4;
+ cubep->_projection = projection;
+ cubep->_vertices = vertices;
+}
+
+int EdenGame::nextVal(char **ptr, char *error) {
+ char c = 0;
+ char *p = *ptr;
+ int val = strtol(p, 0, 10);
+ while ((*p >= '0' && *p <= '9' && *p != 0) || *p == '-')
+ p++;
+ while ((*p == 13 || *p == 10 || *p == ',' || *p == ' ') && *p)
+ c = *p++;
+ *error = c == 10;
+ *ptr = p;
+ return val;
+}
+
+void EdenGame::selectMap(int16 num) {
+ static const char mapMode[12] = { 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 2, 0 };
+ // Cube faces to texture coords mapping
+ // each entry is num_polys(6) * num_faces_per_poly(2) * vertex_per_face(3) * uv(2)
+
+ static const int16 cube_texcoords[3][6 * 2 * 3 * 2] = {
+ {
+ 32, 32, 0, 32, 0, 0,
+ 32, 32, 0, 0, 32, 0,
+
+ 0, 32, 0, 0, 32, 0,
+ 0, 32, 32, 0, 32, 32,
+
+ 32, 32, 0, 32, 0, 0,
+ 32, 32, 0, 0, 32, 0,
+
+ 32, 0, 32, 32, 0, 32,
+ 32, 0, 0, 32, 0, 0,
+
+ 0, 0, 32, 0, 32, 32,
+ 0, 0, 32, 32, 0, 32,
+
+ 0, 32, 0, 0, 32, 0,
+ 0, 32, 32, 0, 32, 32
+ }, {
+ 32, 32, 0, 32, 0, 0,
+ 32, 32, 0, 0, 32, 0,
+
+ 32, 0, 32, 32, 0, 32,
+ 32, 0, 0, 32, 0, 0,
+
+ 32, 0, 32, 32, 0, 32,
+ 32, 0, 0, 32, 0, 0,
+
+ 0, 32, 0, 0, 32, 0,
+ 0, 32, 32, 0, 32, 32,
+
+ 32, 0, 32, 32, 0, 32,
+ 32, 0, 0, 32, 0, 0,
+
+ 32, 0, 32, 32, 0, 32,
+ 32, 0, 0, 32, 0, 0
+ }, {
+ 30, 30, 2, 30, 2, 2,
+ 30, 30, 2, 2, 30, 2,
+
+ 2, 30, 2, 2, 30, 2,
+ 2, 30, 30, 2, 30, 30,
+
+ 30, 30, 2, 30, 2, 2,
+ 30, 30, 2, 2, 30, 2,
+
+ 30, 2, 30, 30, 2, 30,
+ 30, 2, 2, 30, 2, 2,
+
+ 2, 2, 30, 2, 30, 30,
+ 2, 2, 30, 30, 2, 30,
+
+ 2, 30, 2, 2, 30, 2,
+ 2, 30, 30, 2, 30, 30
+ }
+ };
+
+ _cursCurPCMap = num;
+ int16 k = 0;
+ int mode = mapMode[num];
+ int16 x = (num & 7) * 32;
+ int16 y = (num & 0x18) * 4;
+ for (int i = 0; i < 6 * 2; i++) {
+ for (int j = 0; j < 3; j++) {
+ _cube._faces[i]->_uv[j * 2 ] = x + cube_texcoords[mode][k++];
+ _cube._faces[i]->_uv[j * 2 + 1] = y + cube_texcoords[mode][k++];
+ }
+ }
+}
+
+void EdenGame::Eden_dep_and_rot() {
+ int16 curs = _currCursor;
+ if (_normalCursor && (_globals->_drawFlags & DrawFlags::drDrawFlag20))
+ curs = 10;
+ selectMap(curs);
+ _cursorNewTick = g_system->getMillis();
+ if (_cursorNewTick - _cursorOldTick < 1)
+ return;
+
+ _cursorOldTick = _cursorNewTick;
+ switch (_currCursor) {
+ case 0:
+ _rotationAngleZ = (_rotationAngleZ + 2) % 360;
+ _rotationAngleX = (_rotationAngleX + 2) % 360;
+ restoreZDEP();
+ break;
+ case 1:
+ _rotationAngleZ = 0;
+ _rotationAngleX -= 2;
+ if (_rotationAngleX < 0)
+ _rotationAngleX += 360;
+ restoreZDEP();
+ break;
+ case 2:
+ _rotationAngleZ = (_rotationAngleZ + 2) % 360;
+ _rotationAngleX = 0;
+ restoreZDEP();
+ break;
+ case 3:
+ _rotationAngleZ -= 2;
+ if (_rotationAngleZ < 0)
+ _rotationAngleZ += 360;
+ _rotationAngleX = 0;
+ restoreZDEP();
+ break;
+ case 4:
+ _rotationAngleZ = 0;
+ _rotationAngleX = (_rotationAngleX + 2) % 360;
+ restoreZDEP();
+ break;
+ case 5:
+ _rotationAngleZ = 0;
+ _rotationAngleX = 0;
+ _translationZ += flt_2DF84;
+ if ((_translationZ < -3600.0 + flt_2DF80) || _translationZ > flt_2DF80)
+ flt_2DF84 = -flt_2DF84;
+ break;
+ case 6:
+ _rotationAngleZ = 0;
+ _rotationAngleX = 0;
+ _translationZ = flt_2DF80;
+ break;
+ case 7:
+ _rotationAngleZ -= 2;
+ if (_rotationAngleZ < 0)
+ _rotationAngleZ += 360;
+ _rotationAngleX = 0;
+ restoreZDEP();
+ break;
+ case 8:
+ _rotationAngleZ = 0;
+ _rotationAngleX = 0;
+ _translationZ = flt_2DF80;
+ break;
+ case 9:
+ _rotationAngleZ = 0;
+ _rotationAngleX = 0;
+ _translationZ = flt_2DF80;
+ break;
+ }
+}
+
+void EdenGame::restoreZDEP() {
+ flt_2DF84 = 200.0;
+ if (_translationZ < flt_2DF80)
+ _translationZ += flt_2DF84;
+ if (_translationZ > flt_2DF80)
+ _translationZ -= flt_2DF84;
+}
+
+// Original name: affiche_polygone_mapping
+void EdenGame::displayPolygoneMapping(Cube *cubep, CubeFace *face) {
+ uint16 *indices = face->_indices;
+ int idx = indices[0];
+ int16 projX0 = cubep->_projection[idx].x;
+ int16 projY0 = cubep->_projection[idx].y;
+
+ idx = indices[1];
+ int16 projX1 = cubep->_projection[idx].x;
+ int16 projY1 = cubep->_projection[idx].y;
+
+ idx = indices[2];
+ int16 projX2 = cubep->_projection[idx].x;
+ int16 projY2 = cubep->_projection[idx].y;
+
+ if ((projY1 - projY0) * (projX2 - projX0) - (projY2 - projY0) * (projX1 - projX0) > 0)
+ return;
+
+ int16 *uv = face->_uv;
+ int16 ymin = 200; // min y
+ int16 ymax = 0; // max y
+ idx = indices[0];
+ int16 r20 = cubep->_projection[idx].x;
+ int16 r30 = cubep->_projection[idx].y;
+ int16 r19 = *uv++;
+ int16 r18 = *uv++;
+ indices++;
+ for (int i = 0; i < face->tri - 1; i++, indices++) {
+ idx = indices[0];
+ int16 r26 = cubep->_projection[idx].x;
+ int16 r31 = cubep->_projection[idx].y;
+ uint16 r25 = *uv++; //TODO: unsigned
+ int16 r24 = *uv++; //TODO: unsigned
+ ymin = MIN(r30, ymin);
+ ymax = MAX(r30, ymax);
+ ymin = MIN(r31, ymin);
+ ymax = MAX(r31, ymax);
+ drawMappingLine(r20, r30, r26, r31, r19, r18, r25, r24, _lines);
+ r20 = r26;
+ r30 = r31;
+ r19 = r25;
+ r18 = r24;
+ }
+ idx = face->_indices[0];
+ int16 r26 = cubep->_projection[idx].x;
+ int16 r31 = cubep->_projection[idx].y;
+ uv = face->_uv;
+ uint16 r25 = *uv++;
+ int16 r24 = *uv;
+ ymin = MIN(r30, ymin);
+ ymax = MAX(r30, ymax);
+ ymin = MIN(r31, ymin);
+ ymax = MAX(r31, ymax);
+ drawMappingLine(r20, r30, r26, r31, r19, r18, r25, r24, _lines);
+ displayMappingLine(ymin, ymax, _mainView->_bufferPtr, face->_texturePtr);
+}
+
+// Original name: trace_ligne_mapping
+void EdenGame::drawMappingLine(int16 r3, int16 r4, int16 r5, int16 r6, int16 r7, int16 r8, int16 r9, int16 r10, int16 *linesp) {
+ int16 r26 = r6 - r4;
+ if (r26 <= 0) {
+ if (r26 == 0) {
+ linesp += r4 * 8;
+ if (r5 - r3 > 0) {
+ linesp[0] = r3;
+ linesp[1] = r5;
+ linesp[4] = r7;
+ linesp[5] = r9;
+ linesp[6] = r8;
+ linesp[7] = r10;
+ } else {
+ linesp[0] = r5;
+ linesp[1] = r3;
+ linesp[4] = r9;
+ linesp[5] = r7;
+ linesp[6] = r10;
+ linesp[7] = r8;
+ }
+ return;
+ }
+ int16 t = r3;
+ r3 = r5;
+ r5 = t;
+ t = r7;
+ r7 = r9;
+ r9 = t;
+ t = r8;
+ r8 = r10;
+ r10 = t;
+ linesp += r6 * 8;
+ r26 = -r26;
+ } else
+ linesp += r4 * 8 + 1; //TODO wha???
+
+ int r30 = r3 << 16;
+ int r29 = r7 << 16;
+ int r28 = r8 << 16;
+
+ int r25 = ((r5 - r3) << 16) / r26;
+ int r24 = ((r9 - r7) << 16) / r26;
+ int r23 = ((r10 - r8) << 16) / r26;
+
+ for (int i = 0; i < r26; i++) {
+ linesp[0] = r30 >> 16;
+ linesp[4] = r29 >> 16;
+ linesp[6] = r28 >> 16;
+
+ r30 += r25;
+ r29 += r24;
+ r28 += r23;
+ linesp += 8;
+ }
+}
+
+// Original name: affiche_ligne_mapping
+void EdenGame::displayMappingLine(int16 r3, int16 r4, byte *target, byte *texture) {
+ int16 height = r4 - r3;
+ byte *trg_line = _mainView->_bufferPtr + r3 * 640; //TODO: target??
+ int16 *line = &_lines[r3 * 8];
+ // debug("curs: beg draw %d - %d", r3, r4);
+ for (int r22 = height; r22; r22--, line += 8, trg_line += 640) {
+ int16 r29 = line[0];
+ int16 r28 = line[1];
+ int16 len = r28 - r29;
+ if (len < 0)
+ break;
+ if (len == 0)
+ continue;
+
+ // debug("curs: lin draw %d", r4 - height);
+ uint16 r31 = line[4] << 8;
+ uint16 r30 = line[6] << 8;
+
+ int16 r21 = line[5] - line[4];
+ int16 r20 = line[7] - line[6];
+
+ int16 r26 = (r21 << 8) / len;
+ int16 r25 = (r20 << 8) / len;
+ byte *trg = trg_line + r29;
+#if 1
+ while (r29++ < r28) {
+ *trg++ = texture[(r30 & 0xFF00) | (r31 >> 8)];
+ r31 += r26;
+ r30 += r25;
+ }
+#endif
+ }
+}
+
+// PC cursor
+CubeCursor _cursorsPC[9] = {
+ { { 0, 0, 0, 0, 0, 0 }, 3, 2 },
+ { { 1, 1, 0, 1, 1, 0 }, 2, -2 },
+ { { 2, 2, 2, 2, 2, 2 }, 1, 2 },
+ { { 3, 3, 3, 3, 3, 3 }, 1, -2 },
+ { { 4, 4, 4, 4, 4, 4 }, 2, 2 },
+ { { 5, 5, 5, 5, 5, 5 }, 4, 0 },
+ { { 6, 6, 6, 6, 6, 6 }, 1, 2 },
+ { { 7, 7, 7, 7, 7, 7 }, 1, -2 },
+// { { 0, 8, 0, 0, 8, 8 }, 2, 2 },
+ { { 0, 8, 0, 0, 8, 8 }, 2, 2 }
+};
+
+XYZ _cubePC[6][3] = {
+ { { -15, -15, -15 }, { -15, 15, -15 }, { 15, 15, -15 } },
+ { { -15, -15, 15 }, { -15, 15, 15 }, { -15, 15, -15 } },
+ { { -15, -15, 15 }, { -15, -15, -15 }, { 15, -15, -15 } },
+ { { 15, -15, 15 }, { 15, 15, 15 }, { -15, 15, 15 } },
+ { { 15, -15, -15 }, { 15, 15, -15 }, { 15, 15, 15 } },
+ { { 15, 15, 15 }, { 15, 15, -15 }, { -15, 15, -15 } }
+};
+
+signed short cosineTable[] = {
+ // = cos(n) << 7; n += 10;
+ 128, 126, 120, 111, 98, 82, 64, 44, 22, 0, -22, -44, -64, -82, -98, -111, -120, -126,
+ -128, -126, -120, -111, -98, -82, -64, -44, -22, 0, 22, 44, 64, 82, 98, 111, 120, 126,
+ 128, 126, 120, 111, 98, 82, 64, 44, 22, 0
+};
+
+void EdenGame::makeTables() {
+ for (int i = -15; i < 15; i++) {
+ int v = (i * 11) / 15 + 11;
+ tab1[i + 15] = v;
+ tab2[i + 15] = v * 22;
+ }
+
+ for (int i = 0; i < 36; i++) {
+ for (int j = -35; j < 36; j++)
+ tab3[i][j + 35] = (cosineTable[i] * j) >> 7;
+ }
+}
+
+void EdenGame::getSinCosTables(unsigned short angle, signed char **cos_table, signed char **sin_table) {
+ angle /= 2;
+ *cos_table = tab3[angle] + 35;
+
+ angle += 9;
+ if (angle >= 36)
+ angle -= 36;
+
+ *sin_table = tab3[angle] + 35;
+}
+
+
+void EdenGame::rotatePoint(XYZ *point, XYZ *rpoint) {
+ // see http://www.cprogramming.com/tutorial/3d/rotation.html
+ XYZ xrot;
+
+ xrot.x = point->x;
+ xrot.y = _cosX[point->y] + _sinX[point->z];
+ xrot.z = _sinX[-point->y] + _cosX[point->z];
+
+ rpoint->x = _cosY[xrot.x] + _sinY[-xrot.z];
+ rpoint->y = xrot.y;
+ rpoint->z = _sinY[xrot.x] + _cosY[xrot.z];
+
+ rpoint->z += _zoomZ;
+}
+
+void EdenGame::mapPoint(XYZ *point, short *x, short *y) {
+ *y = ((12800 / point->z) * point->y) >> 7;
+ *x = ((12800 / point->z) * point->x) >> 7;
+}
+
+short EdenGame::calcFaceArea(XYZ *face) {
+ XYZ rpoint;
+ short x[3], y[3];
+
+ for (int i = 0; i < 3; i++) {
+ rotatePoint(&face[i], &rpoint);
+ mapPoint(&rpoint, &x[i], &y[i]);
+ }
+
+ short area = (y[1] - y[0]) * (x[2] - x[0]) - (y[2] - y[0]) * (x[1] - x[0]);
+
+ return area;
+}
+
+void EdenGame::paintPixel(XYZ *point, unsigned char pixel) {
+ short x, y;
+ mapPoint(point, &x, &y);
+ _cursorCenter[y * 40 + x] = pixel;
+}
+
+void EdenGame::paintFace0(XYZ *point) {
+ XYZ rpoint;
+ for (int y = -15; y < 15; y++) {
+ for (int x = -15; x < 15; x++) {
+ point->x = x;
+ point->y = y;
+ rotatePoint(point, &rpoint);
+ paintPixel(&rpoint, _face[0][tab1[x + 15] + tab2[y + 15]]);
+ }
+ }
+}
+
+void EdenGame::paintFace1(XYZ *point) {
+ XYZ rpoint;
+ for (int y = -15; y < 15; y++) {
+ for (int x = -15; x < 15; x++) {
+ point->y = y;
+ point->z = -x;
+ rotatePoint(point, &rpoint);
+ paintPixel(&rpoint, _face[1][tab1[x + 15] + tab2[y + 15]]);
+ }
+ }
+}
+
+void EdenGame::paintFace2(XYZ *point) {
+ XYZ rpoint;
+ for (int y = -15; y < 15; y++) {
+ for (int x = -15; x < 15; x++) {
+ point->x = x;
+ point->z = -y;
+ rotatePoint(point, &rpoint);
+ paintPixel(&rpoint, _face[2][tab1[x + 15] + tab2[y + 15]]);
+ }
+ }
+}
+
+void EdenGame::paintFace3(XYZ *point) {
+ XYZ rpoint;
+ for (int y = -15; y < 15; y++) {
+ for (int x = -15; x < 15; x++) {
+ point->x = -x;
+ point->y = -y;
+ rotatePoint(point, &rpoint);
+ paintPixel(&rpoint, _face[3][tab1[x + 15] + tab2[y + 15]]);
+ }
+ }
+}
+
+void EdenGame::paintFace4(XYZ *point) {
+ XYZ rpoint;
+ for (int y = -15; y < 15; y++) {
+ for (int x = -15; x < 15; x++) {
+ point->y = y;
+ point->z = x;
+ rotatePoint(point, &rpoint);
+ paintPixel(&rpoint, _face[4][tab1[x + 15] + tab2[y + 15]]);
+ }
+ }
+}
+
+void EdenGame::paintFace5(XYZ *point) {
+ XYZ rpoint;
+ for (int y = -15; y < 15; y++) {
+ for (int x = -15; x < 15; x++) {
+ point->x = x;
+ point->z = y;
+ rotatePoint(point, &rpoint);
+ paintPixel(&rpoint, _face[5][tab1[x + 15] + tab2[y + 15]]);
+ }
+ }
+}
+
+void EdenGame::paintFaces() {
+ XYZ point;
+ if (!(_faceSkip & 1)) {
+ point.z = -15;
+ paintFace0(&point);
+ }
+ if (!(_faceSkip & 2)) {
+ point.x = -15;
+ paintFace1(&point);
+ }
+ if (!(_faceSkip & 4)) {
+ point.y = -15;
+ paintFace2(&point);
+ }
+ if (!(_faceSkip & 8)) {
+ point.z = 15;
+ paintFace3(&point);
+ }
+ if (!(_faceSkip & 16)) {
+ point.x = 15;
+ paintFace4(&point);
+ }
+ if (!(_faceSkip & 32)) {
+ point.y = 15;
+ paintFace5(&point);
+ }
+}
+
+void EdenGame::renderCube() {
+ for (int i = 0; i < sizeof(_cursor); i++)
+ _cursor[i] = 0;
+ _cursorCenter = &_cursor[40 * 20 + 20];
+
+ getSinCosTables(_angleX, &_cosX, &_sinX);
+ getSinCosTables(_angleY, &_cosY, &_sinY);
+ getSinCosTables(_angleZ, &_cosZ, &_sinZ);
+
+ for (int i = 0; i < 6; i++) {
+ int area = calcFaceArea(_cubePC[i]);
+ if (area <= 0) {
+ _face[i] = _newface[i]; // set new texture for invisible area,
+ _faceSkip |= 1 << i; // but don't draw it just yet
+ } else
+ _faceSkip &= ~(1 << i);
+ }
+
+ paintFaces();
+
+ const int xshift = -5; // TODO: temporary fix to decrease left margin
+ unsigned char *cur = _cursor;
+ unsigned char *scr = _mainView->_bufferPtr + _cursorPosX + _scrollPos + xshift + _cursorPosY * _mainView->_pitch;
+
+ for (int y = 0; y < 40; y++) {
+ for (int x = 0; x < 40; x++) {
+ if (x + _cursorPosX + _scrollPos + xshift < _mainView->_pitch && y + _cursorPosY < _mainView->_height)
+ if (*cur)
+ *scr = *cur;
+ scr++;
+ cur++;
+ }
+ scr += _mainView->_pitch - 40;
+ }
+}
+
+
+void EdenGame::incAngleX(int step) {
+ _angleX += step;
+ if (_angleX == 70 + 2)
+ _angleX = 0;
+ if (_angleX == 0 - 2)
+ _angleX = 70;
+}
+
+void EdenGame::decAngleX() {
+ if (_angleX != 0)
+ _angleX -= (_angleX > 4) ? 4 : 2;
+}
+
+void EdenGame::incAngleY(int step) {
+ _angleY += step;
+ if (_angleY == 70 + 2)
+ _angleY = 0;
+ if (_angleY == 0 - 2)
+ _angleY = 70;
+}
+
+void EdenGame::decAngleY() {
+ if (_angleY != 0)
+ _angleY -= (_angleY > 4) ? 4 : 2;
+}
+
+void EdenGame::incZoom() {
+ if (_zoomZ == 170)
+ _zoomZStep = 40;
+ else if (_zoomZ == 570)
+ _zoomZStep = -40;
+ _zoomZ += _zoomZStep;
+}
+
+void EdenGame::decZoom() {
+ if (_zoomZ != 170) {
+ if (_zoomZ < 170)
+ _zoomZ = 170;
+ else
+ _zoomZ -= 40;
+ }
+}
+
+void EdenGame::initCubePC() {
+ _zoomZ = 170;
+ _zoomZStep = 40;
+ _angleX = _angleY = _angleZ = 0;
+ _pcCursor = &_cursorsPC[0];
+ _cursCurPCMap = -1;
+ makeTables();
+}
+
+void EdenGame::selectPCMap(int16 num) {
+ if (num != _cursCurPCMap) {
+ _pcCursor = &_cursorsPC[num];
+ unsigned char *bank = _mainBankBuf + READ_LE_UINT16(_mainBankBuf);
+ for (int i = 0; i < 6; i++) {
+ _newface[i] = 4 + (unsigned char*)getElem(bank, _pcCursor->_sides[i]);
+ if (_cursCurPCMap == -1)
+ _face[i] = _newface[i];
+ }
+ _cursCurPCMap = num;
+ }
+}
+
+void EdenGame::enginePC() {
+ int16 curs = _currCursor;
+ if (_normalCursor && (_globals->_drawFlags & DrawFlags::drDrawFlag20))
+ curs = 9;
+ selectPCMap(curs);
+ _cursorNewTick = g_system->getMillis();
+ if (_cursorNewTick - _cursorOldTick < 1)
+ return;
+ _cursorOldTick = _cursorNewTick;
+ int step = _pcCursor->_speed;
+ switch (_pcCursor->_kind) {
+ case 0:
+ break;
+ case 1: // rot up-down
+ decAngleY();
+ decZoom();
+ incAngleX(step);
+ break;
+ case 2: // rot left-right
+ decAngleX();
+ decZoom();
+ incAngleY(step);
+ break;
+ case 3: // rotate random
+ decZoom();
+ incAngleX(step);
+ incAngleY(step);
+ break;
+ case 4: // zoom in-out
+ _face[0] = _newface[0];
+ decAngleY();
+ decAngleX();
+ incZoom();
+ break;
+ }
+ renderCube();
+}
+
+////// macgame.c
+//void MyDlgHook() { }
+//void PrepareReply() { }
+int16 EdenGame::OpenDialog(void *arg1, void *arg2) {
+ //TODO
+ return 0;
+}
+
+//void SaveDialog() { }
+//void LostEdenMac_SavePrefs() { }
+//void LostEdenMac_LoadPrefs() { }
+
+void EdenGame::LostEdenMac_InitPrefs() {
+ _globals->_prefLanguage = 1;
+ _globals->_prefMusicVol[0] = 192;
+ _globals->_prefMusicVol[1] = 192;
+ _globals->_prefVoiceVol[0] = 255;
+ _globals->_prefVoiceVol[1] = 255;
+ _globals->_prefSoundVolume[0] = 32;
+ _globals->_prefSoundVolume[1] = 32;
+}
+
+//void MacGame_DoAbout() { }
+//void MacGame_DoAdjustMenus() { }
+//void LostEdenMac_DoPreferences() { }
+//void MacGame_DoSave() { }
+//void MacGame_DoMenuCommand() { }
+//void MacGame_DoOpen() { }
+//void MacGame_DoSaveAs() { }
+
+} // namespace Cryo
diff --git a/engines/cryo/eden.h b/engines/cryo/eden.h
new file mode 100644
index 0000000000..a470a566be
--- /dev/null
+++ b/engines/cryo/eden.h
@@ -0,0 +1,742 @@
+/* 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 CRYO_EDEN_H
+#define CRYO_EDEN_H
+
+#include "cryo/sound.h"
+#include "cryo/defs.h"
+
+enum Direction {
+ kCryoNorth = 0,
+ kCryoEast = 1,
+ kCryoSouth = 2,
+ kCryoWest = 3
+};
+
+namespace Cryo {
+
+class CryoEngine;
+
+class EdenGame {
+private:
+ CryoEngine *_vm;
+
+public:
+ EdenGame(CryoEngine *vm);
+
+ void run();
+ object_t *getObjectPtr(int16 id);
+ void showObjects();
+
+private:
+ void removeConsole();
+ void scroll();
+ void resetScroll();
+ void scrollFrescoes();
+ void displayFrescoes();
+ void gametofresques();
+ void doFrescoes();
+ void actionEndFrescoes();
+ void scrollMirror();
+ void scrollPanel();
+ void displayFollower(Follower *follower, int16 x, int16 y);
+ void characterInMirror();
+ void gameToMirror(byte arg1);
+ void flipMode();
+ void quitMirror();
+ void clictimbre();
+ void actionClickValleyPlan();
+ void gotoPlace(Goto *go);
+ void deplaval(uint16 roomNum);
+ void move(Direction dir);
+ void move2(Direction dir);
+ void actionDinoBlow();
+ void actionPlateMonk();
+ void actionGraaFrescoe();
+ void actionLascFrescoe();
+ void actionPushStone();
+ void actionMummyHead();
+ void actionSkelettonHead();
+ void actionSkelettonMoorkong();
+ void actionChoose();
+ void handleDinaDialog();
+ void handleKingDialog();
+ void actionKingDialog1();
+ void actionKingDialog2();
+ void actionKingDialog3();
+ void actionGetKnife();
+ void actionGetPrism();
+ void actionGetMushroom();
+ void actionGetBadMushroom();
+ void actionGetGold();
+ void actionGetFullNest();
+ void actionGetEmptyNest();
+ void actionGetHorn();
+ void actionGetSunStone();
+ void actionGetEgg();
+ void actionGetTablet();
+ void actionLookLake();
+ void actionGotoHall();
+ void actionLabyrinthTurnAround();
+ void actionGotoFullNest();
+ void actionGotoVal();
+ void actionVisit();
+ void actionFinal();
+ void actionMoveNorth();
+ void actionMoveEast();
+ void actionMoveSouth();
+ void actionMoveWest();
+ void display();
+ void afficher128();
+ void saveFriezes();
+ void saveTopFrieze(int16 x);
+ void saveBottomFrieze();
+ void restoreFriezes();
+ void restoreTopFrieze();
+ void restoreBottomFrieze();
+ void useMainBank();
+ void useCharacterBank();
+ void useBank(int16 bank);
+ void sundcurs(int16 x, int16 y);
+ void rundcurs();
+ void noclipax(int16 index, int16 x, int16 y);
+ void noclipax_avecnoir(int16 index, int16 x, int16 y);
+ void getglow(int16 x, int16 y, int16 w, int16 h);
+ void unglow();
+ void glow(int16 index);
+ void readPalette(byte *ptr);
+ void spriteOnSubtitle(int16 index, int16 x, int16 y);
+ void hideBars();
+ void showBars();
+ void saveMouthBackground();
+ void restoreMouthBackground();
+ void drawBlackBars();
+ void drawTopScreen();
+ void displayValleyMap();
+ void displayMapMark(int16 index, int16 location);
+ void displayAdamMapMark(int16 location);
+ void restoreAdamMapMark();
+ void saveAdamMapMark(int16 x, int16 y);
+ bool istrice(int16 roomNum);
+ bool istyran(int16 roomNum);
+ void istyranval(Area *area);
+ char getDirection(perso_t *perso);
+ bool canMoveThere(char loc, perso_t *perso);
+ void scramble1(uint8 elem[4]);
+ void scramble2(uint8 elem[4]);
+ void scrambleDirections();
+ bool naitredino(char persoType);
+ void newCitadel(char area, int16 level, Room *room);
+ void evolveCitadel(int16 level);
+ void destroyCitadelRoom(int16 roomNum);
+ void narratorBuildCitadel();
+ void citadelFalls(char level);
+ void buildCitadel();
+ void moveDino(perso_t *perso);
+ void moveAllDino();
+ void newValley();
+ char whereIsCita();
+ bool isCita(int16 loc);
+ void placeVava(Area *area);
+ void vivredino();
+ void vivreval(int16 areaNum);
+ void handleDay();
+ void addTime(int16 t);
+ void animCharacter();
+ void getanimrnd();
+ void addanim();
+ void removeMouthSprite();
+ void AnimEndCharacter();
+ void setCharacterSprite(byte *spr);
+ void displayImage();
+ void displayCharacter1();
+ void displayCharacter();
+ void ef_perso();
+ void loadCharacter(perso_t *perso);
+ void loadCurrCharacter();
+ void fin_perso();
+ void no_perso();
+ void closeCharacterScreen();
+ void displayBackgroundFollower();
+ void displayNoFollower(int16 bank);
+ void displayCharacterBackground1();
+ void displayCharacterBackground();
+ void setCharacterIcon();
+ void showCharacter();
+ void displayCharacterPanel();
+ void getDataSync();
+ int16 readFrameNumber();
+ void waitEndSpeak();
+ void my_bulle();
+ void my_pr_bulle();
+ void drawSubtitleChar(byte c, byte color, int16 width);
+ void displaySubtitles();
+ void saveUnderSubtitles(int16 y);
+ void restoreUnderSubtitles();
+ void displayHNMSubtitle();
+ void patchSentence();
+ void vavapers();
+ void citadelle();
+ void selectZone();
+ void showEvents1();
+ void showEvents();
+ void parle_mfin();
+ void parlemoi_normal();
+ void parle_moi();
+ void initCharacterPointers(perso_t *perso);
+ void perso1(perso_t *perso);
+ void perso_normal(perso_t *perso);
+ void handleCharacterDialog(int16 pers);
+ void actionKing();
+ void actionDina();
+ void actionThoo();
+ void actionMonk();
+ void actionTormentor();
+ void actionMessenger();
+ void actionMango();
+ void actionEve();
+ void actionAzia();
+ void actionMammi();
+ void actionGuards();
+ void actionBamboo();
+ void actionKabuka();
+ void actionFisher();
+ void actionDino();
+ void actionTyran();
+ void actionMorkus();
+ void comment();
+ void actionAdam();
+ void setChoiceYes();
+ void setChoiceNo();
+ bool isAnswerYes();
+ void specialMushroom(perso_t *perso);
+ void specialEmptyNest(perso_t *perso);
+ void specialNestWithEggs(perso_t *perso);
+ void specialApple(perso_t *perso);
+ void specialGold(perso_t *perso);
+ void specialPrism(perso_t *perso);
+ void specialTalisman(perso_t *perso);
+ void specialMask(perso_t *perso);
+ void specialBag(perso_t *perso);
+ void specialTrumpet(perso_t *perso);
+ void specialWeapons(perso_t *perso);
+ void specialInstrument(perso_t *perso);
+ void specialEgg(perso_t *perso);
+ void tyranDies(perso_t *perso);
+ void specialObjects(perso_t *perso, char objid);
+ void dialautoon();
+ void dialautooff();
+ void follow();
+ void dialonfollow();
+ void abortDialogue();
+ void subHandleNarrator();
+ void handleNarrator();
+ void checkPhraseFile();
+ byte *getPhrase(int16 id);
+ void actionGotoMap();
+ void record();
+ bool dial_scan(Dialog *dial);
+ bool dialoscansvmas(Dialog *dial);
+ bool dialogEvent(perso_t *perso);
+ void characterStayHere();
+ void endDeath(int16 vid);
+ void chronoEvent();
+ void setChrono(int16 t);
+ void preloadDialogs(int16 vid);
+ void displayEffect1();
+ void displayEffect2();
+ void displayEffect3();
+ void displayEffect4();
+ void clearScreen();
+ void colimacon(int16 pattern[16]);
+ void fadeToBlack(int delay);
+ void fadeToBlackLowPalette(int delay);
+ void fadeFromBlackLowPalette(int delay);
+ void blackRect32();
+ void setSrcRect(int16 sx, int16 sy, int16 ex, int16 ey);
+ void setDestRect(int16 sx, int16 sy, int16 ex, int16 ey);
+ void wait(int howlong);
+ void effetpix();
+ void verifh(byte *ptr);
+ void openbigfile();
+ void closebigfile();
+ void loadRawFile(uint16 num, byte *buffer);
+ void loadIconFile(uint16 num, Icon *buffer);
+ void loadRoomFile(uint16 num, Room *buffer);
+ void loadHnm(uint16 num);
+ int loadSound(uint16 num);
+ void convertMacToPC();
+ void loadpermfiles();
+ bool ReadDataSyncVOC(unsigned int num);
+ bool ReadDataSync(uint16 num);
+ void loadpartoffile(uint16 num, void *buffer, int32 pos, int32 len);
+ void expandHSQ(byte *input, byte *output);
+ void addInfo(byte info);
+ void unlockInfo();
+ void nextInfo();
+ void removeInfo(byte info);
+ void updateInfoList();
+ void initGlobals();
+ void initRects();
+ void closeRoom();
+ void displaySingleRoom(Room *room);
+ void displayRoom();
+ void displayPlace();
+ void loadPlace(int16 num);
+ void specialoutside();
+ void specialout();
+ void specialin();
+ void animpiece();
+ void getdino(Room *room);
+ Room *getRoom(int16 loc);
+ void initPlace(int16 roomNum);
+ void maj2();
+ void updateRoom1(int16 roomNum);
+ void updateRoom(uint16 roomNum);
+ void allocateBuffers();
+ void freebuf();
+ void openWindow();
+ void EmergencyExit();
+ void edmain();
+ void intro();
+ void enterGame();
+ void signon(const char *s);
+ void FRDevents();
+ Icon *scan_icon_list(int16 x, int16 y, int16 index);
+ void updateCursor();
+ void mouse();
+ void showMovie(char arg1);
+ void playHNM(int16 num);
+ void handleHNMSubtitles();
+ void musique();
+ void startmusique(byte num);
+ void musicspy();
+ int loadmusicfile(int16 num);
+ void persovox();
+ void endCharacterSpeech();
+ void fademusicup();
+ void fademusica0(int16 delay);
+ void countObjects();
+ void winObject(int16 id);
+ void loseObject(int16 id);
+ void lostObject();
+ bool isObjectHere(int16 id);
+ void objectmain(int16 id);
+ void getObject(int16 id);
+ void putObject();
+ void newObject(int16 id, int16 arg2);
+ void giveobjectal(int16 id);
+ void giveObject();
+ void actionTakeObject();
+ void newMushroom();
+ void newEmptyNest();
+ void newNestWithEggs();
+ void newGold();
+ void gotoPanel();
+ void noclicpanel();
+ void generique();
+ void cancel2();
+ void testvoice();
+ void load();
+ void initafterload();
+ void save();
+ void desktopcolors();
+ void panelrestart();
+ void reallyquit();
+ void confirmer(char mode, char yesId);
+ void confirmYes();
+ void confirmNo();
+ void restart();
+ void edenQuit();
+ void choseSubtitleOption();
+ void changeVolume();
+ void changervol();
+ void newvol(byte *volptr, int16 delta);
+ void playtape();
+ void rewindtape();
+ void depcurstape();
+ void affcurstape();
+ void forwardtape();
+ void stoptape();
+ void cliccurstape();
+ void paneltobuf();
+ void cursbuftopanel();
+ void langbuftopanel();
+ void displayPanel();
+ void displayLanguage();
+ void displayVolCursor(int16 x, int16 vol1, int16 vol2);
+ void displayCursors();
+ void selectCursor(int itemId);
+ void displayTopPanel();
+ void displayResult();
+ void restrictCursorArea(int16 xmin, int16 xmax, int16 ymin, int16 ymax);
+ void edenShudown();
+ void habitants(perso_t *perso);
+ void suiveurs(perso_t *perso);
+ void evenements(perso_t *perso);
+ void followme(perso_t *perso);
+ void rangermammi(perso_t *perso, Room *room);
+ void perso_ici(int16 action);
+ void setCharacterHere();
+ void faire_suivre(int16 roomNum);
+ void AddCharacterToParty();
+ void addToParty(int16 index);
+ void removeCharacterFromParty();
+ void removeFromParty(int16 index);
+ void handleEloiDeparture();
+ bool checkEloiReturn();
+ void handleEloiReturn();
+ void incPhase();
+ void phase113();
+ void phase130();
+ void phase161();
+ void phase226();
+ void phase257();
+ void phase353();
+ void phase369();
+ void phase371();
+ void phase385();
+ void phase418();
+ void phase433();
+ void phase434();
+ void phase513();
+ void phase514();
+ void phase529();
+ void phase545();
+ void phase561();
+ void bigphase1();
+ void bigphase();
+ void phase16();
+ void phase32();
+ void phase48();
+ void phase64();
+ void phase80();
+ void phase96();
+ void phase112();
+ void phase128();
+ void phase144();
+ void phase160();
+ void phase176();
+ void phase192();
+ void phase208();
+ void phase224();
+ void phase240();
+ void phase256();
+ void phase272();
+ void phase288();
+ void phase304();
+ void phase320();
+ void phase336();
+ void phase352();
+ void phase368();
+ void phase384();
+ void phase400();
+ void phase416();
+ void phase432();
+ void phase448();
+ void phase464();
+ void phase480();
+ void phase496();
+ void phase512();
+ void phase528();
+ void phase544();
+ void phase560();
+ void savegame(char *name);
+ void loadrestart();
+ void loadgame(char *name);
+ void vavaoffsetout();
+ void vavaoffsetin();
+ void lieuoffsetout();
+ void lieuoffsetin();
+ void bandeoffsetout();
+ void bandeoffsetin();
+ char testCondition(int16 index);
+ uint16 operAdd(uint16 v1, uint16 v2);
+ uint16 operSub(uint16 v1, uint16 v2);
+ uint16 operLogicalAnd(uint16 v1, uint16 v2);
+ uint16 operLogicalOr(uint16 v1, uint16 v2);
+ uint16 operIsEqual(uint16 v1, uint16 v2);
+ uint16 operIsSmaller(uint16 v1, uint16 v2);
+ uint16 operIsGreater(uint16 v1, uint16 v2);
+ uint16 operIsDifferent(uint16 v1, uint16 v2);
+ uint16 operIsSmallerOrEqual(uint16 v1, uint16 v2);
+ uint16 operIsGreaterOrEqual(uint16 v1, uint16 v2);
+ uint16 operFalse(uint16 v1, uint16 v2);
+ uint16 operation(byte op, uint16 v1, uint16 v2);
+ uint16 fetchValue();
+ uint8 getByteVar(uint16 offset);
+ uint16 getWordVar(uint16 offset);
+ void actionNop();
+ void initSinCosTable();
+ void makeMatriceFix();
+ void projectionFix(Cube *cube, int n);
+ void initCubeMac();
+ void engineMac();
+ void displayObject(Cube *cube);
+ void loadMap(int file_id, byte *buffer);
+ void NEWcharge_objet_mob(Cube *cube, int fileNum, byte *texturePtr);
+ static int nextVal(char **ptr, char *error);
+ void selectMap(int16 num);
+ void Eden_dep_and_rot();
+ void restoreZDEP();
+ void displayPolygoneMapping(Cube *cube, CubeFace *face);
+ void drawMappingLine(int16 r3, int16 r4, int16 r5, int16 r6, int16 r7, int16 r8, int16 r9, int16 r10, int16 *lines);
+ void displayMappingLine(int16 r3, int16 r4, byte *target, byte *texture);
+ int16 OpenDialog(void *arg1, void *arg2);
+ void LostEdenMac_InitPrefs();
+
+ void initCubePC();
+ void enginePC();
+ void selectPCMap(int16 num);
+
+ void makeTables();
+ void getSinCosTables(unsigned short angle, signed char **cos_table, signed char **sin_table);
+ void rotatePoint(XYZ *point, XYZ *rpoint);
+ void mapPoint(XYZ *point, short *x, short *y);
+ short calcFaceArea(XYZ *face);
+ void paintPixel(XYZ *point, unsigned char pixel);
+ void paintFace0(XYZ *point);
+ void paintFace1(XYZ *point);
+ void paintFace2(XYZ *point);
+ void paintFace3(XYZ *point);
+ void paintFace4(XYZ *point);
+ void paintFace5(XYZ *point);
+ void paintFaces();
+ void renderCube();
+
+ void incAngleX(int step);
+ void decAngleX();
+ void incAngleY(int step);
+ void decAngleY();
+ void incZoom();
+ void decZoom();
+
+ CubeCursor *_pcCursor;
+
+ int16 tab1[30];
+ int16 tab2[30];
+ int8 tab3[36][71];
+ int16 _angleX, _angleY, _angleZ, _zoomZ, _zoomZStep;
+
+ int8 *_cosX, *_sinX;
+ int8 *_cosY, *_sinY;
+ int8 *_cosZ, *_sinZ;
+
+ uint8 *_face[6], *_newface[6];
+ int16 _faceSkip;
+
+ uint8 _cursor[40 * 40];
+ uint8 *_cursorCenter;
+
+ byte _ownObjects[128];
+
+private:
+ int16 _scrollPos;
+ int16 _oldScrollPos;
+ bool _frescoTalk;
+ byte _oldPix[8];
+ Common::Point _adamMapMarkPos;
+ byte _cursKeepBuf[2500];
+ Common::Point _cursKeepPos;
+ bool _torchCursor;
+ int16 _curBankNum;
+ int16 _glowX;
+ int16 _glowY;
+ int16 _glowW;
+ int16 _glowH;
+ bool _paletteUpdateRequired;
+ bool _cursorSaved;
+ bool _showBlackBars;
+ bool _backgroundSaved;
+ byte *_bankData;
+ color_t _globalPalette[256]; //TODO palette_t
+ perso_t *_tyranPtr;
+ int _lastAnimFrameNumb;
+ int _curAnimFrameNumb;
+ int _lastAnimTicks;
+ prect_t *_curCharacterRect;
+ int16 _numAnimFrames;
+ int16 _maxPersoDesc;
+ int16 _numImgDesc;
+ bool _restartAnimation;
+ bool _animationActive;
+ byte _animationDelay;
+ byte _animationIndex;
+ byte _lastAnimationIndex;
+
+ byte *dword_30724;
+ byte *dword_30728; //TODO: rename - something amim-related
+ byte *_mouthAnimations;
+ byte *_animationTable;
+ byte _imageDesc[512];
+ byte *_characterBankData;
+ bool _savedUnderSubtitles;
+ int16 _numTextLines;
+ byte _sentenceBuffer[400];
+ byte phraseIconsBuffer[10];
+ byte _sentenceCoordsBuffer[22];
+ byte *_textOutPtr;
+ byte *textout;
+ object_t *_curSpecialObject;
+ bool _lastDialogChoice;
+ bool parlemoiNormalFlag;
+
+ bool _closeCharacterDialog;
+ int dword_30B04;
+
+ char _lastPhrasesFile;
+ byte _dialogSkipFlags;
+
+ color3_t newColor;
+ color_t oldPalette[256]; // TODO palette_t ?
+ color_t newPalette[256];
+ Common::Rect rect_dst, rect_src;
+ byte *_voiceSamplesBuffer; //TODO: sound sample buffer
+ Common::File _bigfile;
+ byte _infoList[16];
+ bool _needToFade;
+ byte *_mainBankBuf;
+ byte *_musicBuf;
+ byte *_gameLipsync;
+ byte *_gamePhrases;
+ byte *_gameDialogs; //TODO: rename to dialogs?
+ byte *_gameConditions;
+ byte *_placeRawBuf; //TODO: fixme
+ byte *_bankDataBuf;
+ Icon *_gameIcons;
+ Room *_gameRooms;
+ PakHeaderNode *_bigfileHeader;
+ byte *_glowBuffer;
+ byte *_mainViewBuf;
+ byte *_view2Buf;
+ byte *_gameFont; //TODO: rename to font?
+ byte *_subtitlesViewBuf;
+ byte *_underSubtitlesViewBuf; // CHECKME: Useless?
+ global_t *_globals;
+ uint16 _mouseCenterX;
+ uint16 _mouseCenterY;
+ bool _bufferAllocationErrorFl;
+ bool _quitFlag2;
+ bool _quitFlag3;
+ bool _gameStarted;
+ bool _soundAllocated;
+
+ CSoundChannel *_musicChannel;
+ CSoundChannel *_voiceChannel;
+ CSoundChannel *_hnmSoundChannel;
+ Sound *_voiceSound;
+
+ View *_view2;
+ View *_underSubtitlesView;
+ View *_subtitlesView;
+ View *_underBarsView;
+ View *_mainView;
+ View *_hnmView;
+ Common::Rect _underSubtitlesBackupRect;
+ Common::Rect _underSubtitlesScreenRect;
+ Common::Rect _underBottomBarBackupRect;
+ Common::Rect _underBottomBarScreenRect;
+ Common::Rect _underTopBarBackupRect;
+ Common::Rect _underTopBarScreenRect;
+ int _demoCurrentTicks;
+ int _demoStartTicks;
+ int _currentTime;
+ int16 _cirsorPanX;
+ int16 _inventoryScrollDelay;
+ int16 _cursorPosX;
+ int16 _cursorPosY;
+ int16 _currCursor;
+ Icon *_currSpot;
+ Icon *_curSpot2;
+ bool _keyboardHeld;
+ bool _mouseHeld;
+ bool _normalCursor;
+ byte *_hnmViewBuf;
+ bool _showVideoSubtitle;
+ bool _videoCanceledFlag; //TODO: hnm_canceled
+ bool _specialTextMode;
+ int _hnmFrameNum;
+ int _voiceSamplesSize; //TODO: perso vox sample data len
+ int16 _musicRightVol;
+ int16 _musicLeftVol;
+
+
+ bool _animateTalking;
+ bool _personTalking;
+ byte _musicFadeFlag;
+
+ char _musicSequencePos;
+ bool _musicPlayingFlag;
+
+ byte *_musicSamplesPtr;
+ byte *_musicPatternsPtr; //TODO: sndblock_t ?
+ byte *_musSequencePtr;
+ bool _musicEnabledFlag;
+ uint16 *_currentObjectLocation;
+ bool byte_31D64;
+
+ bool _noPalette;
+ bool _gameLoaded;
+#define MAX_TAPES 16
+ tape_t _tapes[MAX_TAPES];
+ byte _confirmMode;
+ byte *_curSliderValuePtr;
+ byte _lastMenuItemIdLo;
+ int16 _lastTapeRoomNum;
+ int16 _curSliderX;
+ int16 _curSliderY;
+ int16 _destinationRoom;
+ int16 word_31E7A; // CHECKME: Unused?
+
+ int16 word_378CC; // TODO: set by CLComputer_Init to 0
+ int16 word_378CE; // CHECKME: Unused
+
+ int _invIconsCount;
+ int _invIconsBase;
+ int _roomIconsBase;
+
+ //// cube.c
+ int16 _cosTable[361];
+ int16 _sinTable[361];
+ int _passMat31, _passMat21, _passMat11;
+ int _passMat32, _passMat22, _passMat12;
+ int _passMat33, _passMat23, _passMat13;
+ int16 _rotationAngleY; // CHECKME: USeless?
+ int16 _rotationAngleX, _rotationAngleZ;
+ float _translationY, _translationX; // CHECKME: Useless?
+ Cube _cube;
+ int16 _cursCurPCMap;
+ int16 _lines[200 * 8];
+ byte _cubeTexture[0x4000];
+ int _cubeFaces;
+ uint32 _cursorOldTick, _cursorNewTick;
+ byte *_codePtr;
+
+ uint8 tab_2CB1E[8][4];
+
+ const unsigned int kMaxMusicSize; // largest .mus file size
+};
+
+}
+
+#endif
diff --git a/engines/cryo/gameflow.txt b/engines/cryo/gameflow.txt
new file mode 100644
index 0000000000..c932fc86f2
--- /dev/null
+++ b/engines/cryo/gameflow.txt
@@ -0,0 +1,24 @@
+
+game phases
+
+ 0 - game start
+ 10 - enter throne room
+ 20 - heard talk of eloi and father
+ 30 - in prince's room
+ 40 - met dina
+ 41 - talking to tau room: 202
+ 50 - tau died
+ 60 - talked to jabber
+ 70 - got a gift from jabber
+ 71 - part with dina at secret crypt
+ 80 - learned about fresques / got flute
+ 81 - convinced monk to help
+ 82 - enter throne room
+ 90 - got king's permission
+ A0 - met chong
+ A1 - chong joins party
+ B0 - on valley screen after citadel build complete
+ C0 - met ulan
+ D0 - build citadel in uluru
+ E0 - got gift from ulan
+ ...
diff --git a/engines/cryo/module.mk b/engines/cryo/module.mk
new file mode 100644
index 0000000000..d0eae378b7
--- /dev/null
+++ b/engines/cryo/module.mk
@@ -0,0 +1,19 @@
+MODULE := engines/cryo
+
+MODULE_OBJS = \
+ cryo.o \
+ cryolib.o \
+ debugger.o \
+ detection.o \
+ eden.o \
+ sound.o \
+ staticdata.o \
+ video.o
+
+# This module can be built as a plugin
+ifeq ($(ENABLE_CRYO), DYNAMIC_PLUGIN)
+PLUGIN := 1
+endif
+
+# Include common rules
+include $(srcdir)/rules.mk
diff --git a/engines/cryo/platdefs.h b/engines/cryo/platdefs.h
new file mode 100644
index 0000000000..81329fb190
--- /dev/null
+++ b/engines/cryo/platdefs.h
@@ -0,0 +1,48 @@
+/* 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 CRYO_PLATDEFS_H
+#define CRYO_PLATDEFS_H
+
+#if 1
+#include "common/file.h"
+
+namespace Cryo {
+
+#if 1
+const int _subtitlesXMargin = 16; //PC
+const int _subtitlesXScrMargin = 16;
+const int _spaceWidth = 6;
+#define FAKE_DOS_VERSION
+#else
+const int _subtitlesXMargin = 16; //MAC
+const int _subtitlesXScrMargin = 16; //MAC
+const int _spaceWidth = 4;
+#endif
+const int _subtitlesXWidth = (320 - _subtitlesXMargin * 2);
+const int _subtitlesXCenter = _subtitlesXWidth / 2;
+
+#endif
+
+} // End of namespace Cryo
+
+#endif
diff --git a/engines/cryo/readme.txt b/engines/cryo/readme.txt
new file mode 100644
index 0000000000..c0f023be0f
--- /dev/null
+++ b/engines/cryo/readme.txt
@@ -0,0 +1,72 @@
+Citadel of Mo, the last remaining place where humans can be safe from army
+of vicious Tyrannosaurus led by allmighty Morkus Rex. What awaits young Adam,
+prince of Mo, who just came of age and want to travel across the world?
+Will he be able to restore long lost friendship between dinosaurus and humans?
+
+
+This is SCUMMVM reimplementation of Cryo's Lost Eden game engine. In order to
+stay as close as possible to original game and minimize number of bugs
+introduced during code reconstruction, in its current state this project is
+a straight reverse-engineered game code hooked up to SCUMMVM framework.
+Because of that, this code in no way represent the quality or coding practices
+of SCUMMVM itself. Essentially, this is how the game was originally written.
+
+There are several Lost Eden game versions known to exists.
+
+- Non-interactive PC demo version. Basically, a number of video files played
+ in a loop with FM music in background. Google for "ANCIBUR2.HNM" file to
+ find it.
+
+- Interactive PC demo version. Allows to play through whole Citadel of Mo
+ then shows "Coming Soon" banner.
+ Can be found here: http://www.ag.ru/games/lost-eden/demos/2677
+ Download is a self-extracting archive, unpack it with 7zip or similar tool.
+
+- PC version. Main version of the game. Written in assembly and partially based
+ on Dune's game code.
+ Runs in real-mode DOS environment, uses VGA 320x200 graphics and digitized
+ sounds/music. Allows to select several languages for in-game subtitles. It is
+ rumored that bootleg Russian translation also exists. Has 3 predefined slots
+ for game save/load. Uses two different video codecs for HNM files.
+
+- MAC version. Almost identical to PC version. Has slightly modified UI. Such
+ as exta spaces on the inventory bar, resized subtitles overlay and different
+ implementation of mouse cursor (which is worse than the original one). Looks
+ like screen transition effects are also changed / rearranged. Also comes with
+ updated game script.
+ This version has no limit on save game slots. Standard system file selection
+ dialogs are used instead. All screen hot-spots coordinates loaded from the
+ main resource file instead of hard-coded values used in PC version.
+
+- 3DO version. Uses completely different resource formats.
+
+- CDI version. Uses completely different resource formats.
+
+- CD32 version. Mentioned in PC demo version, but never released?
+
+
+This reimplementation project is based on MAC version, since it's much easier
+to work with than any other versions.
+
+At this moment Mac version of the game is fully playabe/completeable. List of
+currently discovered bugs can be found in bugs.txt file. None of those are
+critical or game-breaking. Only single game save/load slot is supported and
+saves are not cross-platform compatible. Also, no game restart feature work
+due to the way it's implemented.
+
+PC versions (Demo and Full) are supported as well, but have a number of more
+severe glitches.
+
+Because of limited development environment, this code is only tested on
+MSVS2013 32-bit compiler. There may be some issues with GCC/LLVM compilers
+or on 64-bit platforms. As mentioned above, this code is neither pretty or
+bug-free (aka it's a can of worms). Several original bugs, various oddities
+and problematic areas are marked with TODO comment in the source code. There
+are number of variables with non-descripitve names like byte_1234, those
+purpose is yet to be clearly understood. To make code debugging easier,
+some commands have been added in the debugger. Some parts, like image
+drawing routines, can be simplified/generalized.
+
+Because parts of this code (mainly decompression and video playback) used
+by other Cryo's games, it might be worthy to make them reusable by future
+engines.
diff --git a/engines/cryo/sound.cpp b/engines/cryo/sound.cpp
new file mode 100644
index 0000000000..68f067588f
--- /dev/null
+++ b/engines/cryo/sound.cpp
@@ -0,0 +1,113 @@
+/* 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 "cryo/sound.h"
+#include "audio/audiostream.h"
+#include "audio/mixer.h"
+#include "audio/decoders/raw.h"
+
+namespace Cryo {
+
+CSoundChannel::CSoundChannel(Audio::Mixer *mixer, unsigned int sampleRate, bool stereo, bool is16bits) : _mixer(mixer), _sampleRate(sampleRate), _stereo(stereo) {
+ _bufferFlags = is16bits ? (Audio::FLAG_LITTLE_ENDIAN | Audio::FLAG_16BITS) : Audio::FLAG_UNSIGNED;
+ if (stereo)
+ _bufferFlags |= Audio::FLAG_STEREO;
+ _audioStream = nullptr;
+ _volumeLeft = _volumeRight = Audio::Mixer::kMaxChannelVolume;
+}
+
+CSoundChannel::~CSoundChannel() {
+ stop();
+ if (_audioStream)
+ delete _audioStream;
+}
+
+void CSoundChannel::queueBuffer(byte *buffer, unsigned int size, bool playNow, bool playQueue, bool buffering) {
+ if (playNow)
+ stop();
+
+ if (!buffer || !size)
+ return;
+
+ if (!_audioStream)
+ _audioStream = Audio::makeQueuingAudioStream(_sampleRate, _stereo);
+
+ if (buffering) {
+ byte *localBuffer = (byte*)malloc(size);
+ memcpy(localBuffer, buffer, size);
+ _audioStream->queueBuffer(localBuffer, size, DisposeAfterUse::YES, _bufferFlags);
+ } else
+ _audioStream->queueBuffer(buffer, size, DisposeAfterUse::NO, _bufferFlags);
+ if (playNow || playQueue)
+ play();
+}
+
+void CSoundChannel::play() {
+ if (!_audioStream)
+ return;
+ if (!_mixer->isSoundHandleActive(_soundHandle)) {
+ _mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundHandle, _audioStream, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO);
+ applyVolumeChange();
+ }
+}
+
+void CSoundChannel::stop() {
+ if (_mixer->isSoundHandleActive(_soundHandle))
+ _mixer->stopHandle(_soundHandle);
+
+ if (_audioStream) {
+ _audioStream->finish();
+ delete _audioStream;
+ _audioStream = nullptr;
+ }
+}
+
+unsigned int CSoundChannel::numQueued() {
+ return _audioStream ? _audioStream->numQueuedStreams() : 0;
+}
+
+unsigned int CSoundChannel::getVolume() {
+ return (_volumeRight + _volumeLeft) / 2;
+}
+
+void CSoundChannel::setVolume(unsigned int volumeLeft, unsigned int volumeRight) {
+ _volumeLeft = volumeLeft;
+ _volumeRight = volumeRight;
+ applyVolumeChange();
+}
+
+void CSoundChannel::setVolumeLeft(unsigned int volume) {
+ setVolume(volume, _volumeRight);
+}
+
+void CSoundChannel::setVolumeRight(unsigned int volume) {
+ setVolume(_volumeLeft, volume);
+}
+
+void CSoundChannel::applyVolumeChange() {
+ unsigned int volume = (_volumeRight + _volumeLeft) / 2;
+ int balance = (signed int)(_volumeRight - _volumeLeft) / 2;
+ _mixer->setChannelVolume(_soundHandle, volume);
+ _mixer->setChannelBalance(_soundHandle, balance);
+}
+
+}
diff --git a/engines/cryo/sound.h b/engines/cryo/sound.h
new file mode 100644
index 0000000000..72232cc4f1
--- /dev/null
+++ b/engines/cryo/sound.h
@@ -0,0 +1,70 @@
+/* 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.
+ *
+ */
+
+#pragma once
+
+#include "audio/audiostream.h"
+#include "audio/mixer.h"
+#include "audio/decoders/raw.h"
+
+#include "cryo/cryolib.h"
+
+namespace Cryo {
+
+class CryoEngine;
+
+class CSoundChannel {
+private:
+ Audio::Mixer *_mixer;
+ Audio::QueuingAudioStream *_audioStream;
+ Audio::SoundHandle _soundHandle;
+ unsigned int _sampleRate;
+ bool _stereo;
+ unsigned int _bufferFlags;
+
+ void applyVolumeChange();
+
+public:
+ CSoundChannel(Audio::Mixer *mixer, unsigned int sampleRate, bool stereo, bool is16bits = false);
+ ~CSoundChannel();
+
+ // Queue a new buffer, cancel any previously queued buffers if playNow is set
+ void queueBuffer(byte *buffer, unsigned int size, bool playNow = false, bool playQueue = true, bool buffering = true);
+
+ // Play any queued buffers
+ void play();
+
+ // Stop playing and purge play queue
+ void stop();
+
+ // How many buffers in queue (including currently playing one)
+ unsigned int numQueued();
+
+ // Volume control
+ int _volumeLeft, _volumeRight;
+ unsigned int getVolume();
+ void setVolume(unsigned int volumeLeft, unsigned int volumeRight);
+ void setVolumeLeft(unsigned int volume);
+ void setVolumeRight(unsigned int volume);
+};
+
+}
diff --git a/engines/cryo/staticdata.cpp b/engines/cryo/staticdata.cpp
new file mode 100644
index 0000000000..1184791850
--- /dev/null
+++ b/engines/cryo/staticdata.cpp
@@ -0,0 +1,495 @@
+/* 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 "cryo/defs.h"
+#include "cryo/cryolib.h"
+
+namespace Cryo {
+
+Follower followerList[] = {
+// char, X, sx, sy, ex, ey,bank,
+ { PersonId::pidGregor, 5, 211, 9, 320, 176, 228, 0, 0 },
+ { PersonId::pidEloi, 4, 162, 47, 223, 176, 228, 112, 78 },
+ { PersonId::pidDina, 3, 55, 0, 172, 176, 228, 90, 16 },
+ { PersonId::pidChongOfChamaar, 4, 0, 5, 114, 176, 229, 0, 16 },
+ { PersonId::pidKommalaOfKoto, 3, 0, 15, 102, 176, 229, 0, 16 },
+ { PersonId::pidUlanOfUlele, 1, 0, 0, 129, 176, 230, 0, 16 },
+ { PersonId::pidCabukaOfCantura, 2, 0, 0, 142, 176, 230, 0, 16 },
+ { PersonId::pidFuggOfTamara, 0, 0, 17, 102, 176, 230, 0, 16 },
+ { PersonId::pidJabber, 2, 0, 6, 134, 176, 228, 0, 16 },
+ { PersonId::pidShazia, 1, 90, 17, 170, 176, 228, 50, 22 },
+ { PersonId::pidThugg, 0, 489, 8, 640, 176, 228, 160, 24 },
+ { PersonId::pidMungo, 5, 361, 0, 517, 176, 229, 0, 16 },
+ { PersonId::pidMonk, 0, 419, 22, 569, 176, 229, 100, 30 },
+ { PersonId::pidEve, 1, 300, 28, 428, 176, 229, 0, 38 },
+ { -1, -1, -1, -1, -1, -1, -1, -1, -1 }
+};
+
+
+/*
+ Labyrinth of Mo
+
+ | | | | | | | |
+
+*/
+
+byte kLabyrinthPath[] = {
+// each nibble tells which direction to choose to exit the labyrinth
+ 0x11, 0x11, 0x11, 0x22, 0x33, 0x55, 0x25, 0x44, 0x25, 0x11, 0x11, 0x11,
+ 0x11, 0x35, 0x55, 0x45, 0x45, 0x44, 0x44, 0x34, 0x44, 0x34, 0x32, 0x52,
+ 0x33, 0x23, 0x24, 0x44, 0x24, 0x22, 0x54, 0x22, 0x54, 0x54, 0x44, 0x22,
+ 0x22, 0x42, 0x45, 0x22, 0x42, 0x45, 0x35, 0x11, 0x44, 0x34, 0x52, 0x11,
+ 0x44, 0x32, 0x55, 0x11, 0x11, 0x33, 0x11, 0x11, 0x53, 0x11, 0x11, 0x53,
+ 0x54, 0x24, 0x11, 0x22, 0x25, 0x33, 0x53, 0x54, 0x23, 0x44
+};
+
+char kDinoSpeedForCitaLevel[16] = { 1, 2, 3, 4, 4, 5, 6, 7, 8, 9 };
+
+char kTabletView[] = { //TODO: make as struct?
+ // opposite tablet id, video id
+ Objects::obUnused10, 83,
+ Objects::obUnused10, 84,
+ Objects::obTablet4, 85,
+ Objects::obTablet3, 86,
+ Objects::obTablet6, 87,
+ Objects::obTablet5, 85
+};
+
+// special character backgrounds for specific rooms
+char kPersoRoomBankTable[] = {
+ // first entry is default bank, then pairs of [roomNum, bankNum], terminated by -1
+ 0, 3, 33, -1,
+ 21, 17, 35, -1,
+ 0, 2, 36, -1,
+ 22, 9, 38, 3, 39, -1,
+ 23, 8, 40, -1,
+ 0, 3, 41, 7, 42, -1,
+ 25, -1,
+ 27, 17, 45, -1,
+ 28, 26, 46, -1,
+ 29, 51, 48, -1,
+ 30, 53, 49, -1,
+ 0, 27, 50, -1,
+ 32, 17, 51, -1,
+ 52, 2, 52, -1,
+ -3, 3, -3, -1,
+ 31, -1,
+ 24, 6, 43, -1,
+ 47, -1,
+ 0, 2, 64, -1,
+ 54, 3, 54, -1,
+ 27, -1,
+ 26, 17, 45, -1
+};
+
+// area transition descriptors
+Goto gotos[] = {
+// area, oldarea, vid, time, valleyVid
+ { 0, 1, 0, 2, 20 },
+ { 0, 1, 162, 3, 168 },
+ { 0, 2, 0, 2, 21 },
+ { 0, 6, 0, 3, 108 },
+ { 0, 9, 151, 3, 0 },
+ { 0, 7, 106, 2, 101 },
+ { 0, 10, 79, 3, 102 },
+ { 0, 12, 0, 3, 0 },
+ { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+ { 1, 3, 58, 2, 104 },
+ { 1, 4, 100, 4, 104 },
+ { 1, 5, 107, 6, 104 },
+ { 1, 6, 155, 8, 104 },
+ { 1, 7, 165, 6, 104 },
+ { 1, 8, 169, 6, 104 },
+ { 1, 10, 111, 2, 104 },
+ { 1, 11, 164, 4, 104 },
+ { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+ { 1, 3, 161, 3, 102 },
+ { 1, 4, 163, 6, 102 },
+ { 1, 5, 157, 9, 102 },
+ { 1, 9, 160, 9, 102 },
+ { 1, 10, 79, 3, 102 },
+ { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+ { 1, 3, 0, 3, 153 }, // 24
+ { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+ { 3, 1, 154, 2, 103 },
+ { 3, 4, 100, 2, 103 },
+ { 3, 5, 107, 4, 103 },
+ { 3, 6, 155, 6, 103 },
+ { 3, 7, 165, 8, 103 },
+ { 3, 8, 169, 6, 103 },
+ { 3, 10, 111, 4, 103 },
+ { 3, 11, 164, 6, 103 },
+ { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+ { 3, 1, 162, 3, 22 },
+ { 3, 4, 163, 6, 22 },
+ { 3, 5, 157, 9, 22 },
+ { 3, 9, 160, 9, 22 },
+ { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+ { 3, 1, 0, 3, 166 }, // 40
+ { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+ { 4, 1, 154, 4, 51 },
+ { 4, 3, 58, 2, 51 },
+ { 4, 5, 107, 2, 51 },
+ { 4, 6, 155, 4, 51 },
+ { 4, 7, 165, 6, 51 },
+ { 4, 8, 169, 8, 51 },
+ { 4, 10, 111, 6, 51 },
+ { 4, 11, 164, 8, 51 },
+ { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+ { 4, 1, 162, 3, 109 }, // 51
+ { 4, 3, 161, 6, 109 },
+ { 4, 5, 157, 9, 109 },
+ { 4, 9, 160, 9, 109 },
+ { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+ { 5, 1, 154, 6, 33 },
+ { 5, 3, 58, 4, 33 },
+ { 5, 4, 100, 2, 33 },
+ { 5, 6, 155, 2, 33 },
+ { 5, 7, 165, 4, 33 },
+ { 5, 8, 169, 8, 33 },
+ { 5, 10, 111, 8, 33 },
+ { 5, 11, 164, 8, 33 },
+ { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+ { 5, 1, 162, 3, 99 }, // 65
+ { 5, 3, 161, 6, 99 },
+ { 5, 4, 163, 9, 99 },
+ { 5, 9, 160, 9, 99 },
+ { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+ { 9, 1, 162, 3, 167 }, // 70
+ { 9, 3, 161, 6, 167 },
+ { 9, 4, 163, 9, 167 },
+ { 9, 5, 157, 9, 167 },
+ { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+ { 6, 1, 154, 8, 105 }, // 75
+ { 6, 3, 58, 6, 105 },
+ { 6, 4, 100, 4, 105 },
+ { 6, 5, 107, 2, 105 },
+ { 6, 7, 165, 2, 105 },
+ { 6, 8, 169, 10, 105 },
+ { 6, 10, 111, 6, 105 },
+ { 6, 11, 164, 8, 105 },
+ { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+ { 7, 1, 154, 4, 158 }, // 84
+ { 7, 3, 58, 6, 158 },
+ { 7, 4, 100, 6, 158 },
+ { 7, 5, 107, 4, 158 },
+ { 7, 6, 155, 2, 158 },
+ { 7, 8, 169, 8, 158 },
+ { 7, 10, 111, 4, 158 },
+ { 7, 11, 164, 6, 158 },
+ { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+ { 8, 1, 154, 2, 159 }, // 93
+ { 8, 3, 58, 4, 159 },
+ { 8, 4, 100, 6, 159 },
+ { 8, 5, 107, 8, 159 },
+ { 8, 6, 155, 10, 159 },
+ { 8, 7, 165, 8, 159 },
+ { 8, 10, 111, 6, 159 },
+ { 8, 11, 164, 4, 159 },
+ { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+ { 10, 1, 154, 2, 77 }, // 102
+ { 10, 3, 58, 4, 77 },
+ { 10, 4, 100, 6, 77 },
+ { 10, 5, 107, 8, 77 },
+ { 10, 6, 155, 6, 77 },
+ { 10, 7, 165, 4, 77 },
+ { 10, 8, 169, 6, 77 },
+ { 10, 11, 164, 4, 77 },
+ { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+ { 11, 1, 154, 2, 80 }, // 111
+ { 11, 3, 58, 4, 80 },
+ { 11, 4, 100, 6, 80 },
+ { 11, 5, 107, 8, 80 },
+ { 11, 6, 155, 8, 80 },
+ { 11, 7, 165, 6, 80 },
+ { 11, 8, 169, 2, 80 },
+ { 11, 10, 111, 4, 80 },
+ { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+ { 12, 1, 154, 8, 56 }, // 120
+ { 12, 3, 58, 4, 56 },
+ { 12, 4, 100, 4, 56 },
+ { 12, 5, 107, 6, 56 },
+ { 12, 6, 155, 8, 56 },
+ { 12, 7, 165, 10, 56 },
+ { 12, 8, 169, 4, 56 },
+ { 12, 10, 111, 10, 56 },
+ { 12, 11, 164, 6, 56 },
+ { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+};
+
+object_t _objects[] = {
+ //id,fl,loc,masklow,maskhi,ct
+ { 1, 0, 3, 1, 0, 0}, // Eve's Way Stone
+ { 2, 0, 3, 2, 0, 0}, // Thau's Seashell
+ { 3, 0, 3, 4, 0, 0}, // Talisman of bravery
+ { 4, 0, 3, 8, 0, 0}, // An old tooth. Very old! Whoever lost it most certainly has no further use for it!
+ { 5, 0, 0, 0x10, 0, 0}, // Prism
+ { 6, 0, 3, 0, 0, 0}, // Flute
+ { 7, 0, 3, 0x4000, 0, 0}, // Apple
+ { 8, 0, 4, 0x1000, 0, 0}, // Egg of Destiny
+ { 9, 0, 3, 0x800, 0, 0}, // Root
+ { 10, 0, 3, 0, 0, 0}, // ???
+ { 11, 0, 6, 0, 0, 0}, // Mushroom
+ { 12, 0, 13, 0, 0, 0}, // Poisonous Mushroom
+ { 13, 0, 2, 0x400, 0, 0}, // Graa's Knife
+ { 14, 0, 22, 0, 0, 0}, // Empty Nest
+ { 15, 0, 26, 0, 0, 0}, // Full Nest
+ { 16, 0, 33, 0x20, 0, 0}, // Gold
+ { 17, 0, 3, 0, 0, 0}, // Sign of Shadow Mistress (moon stone)
+ { 18, 0, 3, 0, 0, 0}, // Sign of Mother of all (bag of soil)
+ { 19, 0, 40, 0, 0, 0}, // Sign of the life-giving (sun star)
+ { 20, 0, 20, 0x200, 0, 0}, // King's Horn
+ { 21, 0, 3, 0, 0, 0}, // Golden Sword of Mashaar
+ // Masks
+ { 22, 0, 3, 0x40, 0, 0}, // Mask of Death
+ { 23, 0, 3, 0x80, 0, 0}, // Mask of Bonding
+ { 24, 0, 3, 0x100, 0, 0}, // Mask of Birth
+ // Objects of power
+ { 25, 0, 3, 0, 1, 0}, // Eye in the Storm
+ { 26, 0, 3, 0, 2, 0}, // Sky Hammer
+ { 27, 0, 3, 0, 4, 0}, // Fire in the Clouds
+ { 28, 0, 3, 0, 8, 0}, // Within and Without
+ { 29, 0, 3, 0, 0x10, 0}, // Eye in the Cyclone
+ { 30, 0, 3, 0, 0x20, 0}, // River that Winds
+ // Musical instruments
+ { 31, 0, 3, 0, 0x40, 0}, // Trumpet
+ { 32, 0, 3, 0, 0x80, 0}, // -- unused (but still has a dialog line)
+ { 33, 0, 3, 0, 0x100, 0}, // Drum
+ { 34, 0, 3, 0, 0x200, 0}, // -- unused (but still has a dialog line)
+ { 35, 0, 3, 0, 0x400, 0}, // -- unused (but still has a dialog line)
+ { 36, 0, 3, 0, 0x800, 0}, // Ring
+ // Tablets
+ { 37, 0, 3, 0, 0, 0}, // Tablet #1 (Mo)
+ { 38, 0, 42, 0x2000, 0, 0}, // Tablet #2 (Morkus' Lair)
+ { 39, 0, 3, 0, 0, 0}, // Tablet #3 (White Arch?)
+ { 40, 0, 3, 0, 0, 0}, // Tablet #4
+ { 41, 0, 3, 0, 0, 0}, // Tablet #5
+ { 42, 0, 3, 0x8000, 0, 0} // Tablet #6 (Castra)
+};
+
+uint16 kObjectLocations[100] = {
+ 0x112, 0xFFFF,
+ 0x202, 0xFFFF,
+ 0x120, 0xFFFF,
+ 0x340, 0x44B, 0x548, 0x640, 0x717, 0x830, 0xFFFF,
+ 0x340, 0x44B, 0x548, 0x640, 0x717, 0x830, 0xFFFF,
+ 0, 0xFFFF,
+ 0x344, 0x53A, 0x831, 0xFFFF,
+ 0x331, 0x420, 0x54B, 0x637, 0x716, 0x840, 0xFFFF,
+ 0x834A, 0x8430, 0x8531, 0x644, 0x745, 0x838, 0xFFFF,
+ 0x510, 0xFFFF,
+ 0xC04, 0xFFFF,
+ 0xFFFF
+};
+
+perso_t kPersons[] = {
+ // room, aid, party mask, id, flags, X,bank,X, X,sprId,sprX,speed, X
+ { 0x103, 230, PersonMask::pmGregor, PersonId::pidGregor , 0, 0, 1, 0, 0, 0, 0, 0, 0 },
+ { 0x116, 231, PersonMask::pmDina , PersonId::pidDina , 0, 4, 2, 0, 0, 3, 9, 0, 0 },
+ { 0x202, 232, PersonMask::pmTau , PersonId::pidTau , 0, 8, 3, 0, 0, 0, 0, 0, 0 },
+ { 0x109, 233, PersonMask::pmMonk , PersonId::pidMonk , 0, 12, 4, 0, 0, 6, 52, 0, 0 },
+ { 0x108, 234, PersonMask::pmJabber, PersonId::pidJabber , 0, 18, 5, 0, 0, 2, 0, 0, 0 },
+ { 0x103, 235, PersonMask::pmEloi , PersonId::pidEloi , 0, 22, 6, 0, 0, 4, 20, 0, 0 },
+ { 0x301, 236, PersonMask::pmMungo , PersonId::pidMungo , 0, 28, 8, 0, 0, 11, 45, 0, 0 },
+ { 0x628, 237, PersonMask::pmEve , PersonId::pidEve , 0, 30, 10, 0, 0, 7, 35, 0, 0 },
+ { 0x81A, 238, PersonMask::pmShazia, PersonId::pidShazia , 0, 34, 11, 0, 0, 1, 11, 0, 0 },
+ { 0x330, 239, PersonMask::pmLeader, PersonId::pidChongOfChamaar , 0, 38, 13, 0, 0, 10, 0, 0, 0 },
+ { 0x41B, 239, PersonMask::pmLeader, PersonId::pidUlanOfUlele , 0, 46, 15, 0, 0, 13, 0, 0, 0 },
+ { 0x53B, 239, PersonMask::pmLeader, PersonId::pidKommalaOfKoto , 0, 42, 14, 0, 0, 9, 0, 0, 0 },
+ { 0x711, 239, PersonMask::pmLeader, PersonId::pidCabukaOfCantura , 0, 50, 16, 0, 0, 14, 0, 0, 0 },
+ { 0xA02, 239, PersonMask::pmLeader, PersonId::pidMarindaOfEmbalmers, 0, 54, 17, 0, 0, 0, 0, 0, 0 },
+ { 0x628, 239, PersonMask::pmLeader, PersonId::pidFuggOfTamara , 0, 62, 18, 0, 0, 12, 0, 0, 0 },
+ { 0x801, 239, PersonMask::pmLeader, PersonId::pidChongOfChamaar , 0, 38, 13, 0, 0, 10, 0, 0, 0 },
+ { 0x41B, 10, PersonMask::pmQuest , PersonId::pidUlanOfUlele , PersonFlags::pfType2 , 46, 15, 0, 0, 13, 0, 0, 0 },
+ { 0x711, 11, PersonMask::pmQuest , PersonId::pidCabukaOfCantura , PersonFlags::pfType2 , 50, 16, 0, 0, 14, 0, 0, 0 },
+ { 0x106, 240, PersonMask::pmThugg , PersonId::pidThugg , 0, 64, 7, 0, 0, 0, 61, 0, 0 },
+ { 0, 13, 0, PersonId::pidNarrator , 0, 68, 12, 0, 0, 0, 0, 0, 0 },
+ { 0x902, 241, PersonMask::pmQuest , PersonId::pidNarrim , 0, 70, 19, 0, 0, 0, 0, 0, 0 },
+ { 0xC03, 244, PersonMask::pmMorkus, PersonId::pidMorkus , 0, 74, 20, 0, 0, 0, 0, 0, 0 },
+ // dinos in each valley
+ { 0x332, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pfType8 , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x329, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pfType8 , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x33B, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pf80 | PersonFlags::pftTriceraptor , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x317, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pf80 | PersonFlags::pftVelociraptor, 0, 0, 0, 0, 0, 0, 1, 0 },
+ { 0x320, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pfType12 , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x349, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pf80 | PersonFlags::pftMosasaurus , 0, 0, 0, 0, 0, 0, 0, 0 },
+
+ { 0x429, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pfType8 , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x43B, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pf80 | PersonFlags::pftTriceraptor , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x422, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pf80 | PersonFlags::pftVelociraptor, 0, 0, 0, 0, 0, 0, 1, 0 },
+ { 0x432, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pf80 | PersonFlags::pftMosasaurus , 0, 0, 0, 0, 0, 0, 0, 0 },
+
+ { 0x522, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pfType8 , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x534, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pf80 | PersonFlags::pftTriceraptor , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x515, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pftVelociraptor , 0, 0, 0, 0, 0, 0, 1, 0 },
+ { 0x533, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pf80 | PersonFlags::pftMosasaurus , 0, 0, 0, 0, 0, 0, 0, 0 },
+
+ { 0x622, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pfType8 , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x630, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pf80 | PersonFlags::pftTriceraptor , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x643, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pf80 | PersonFlags::pftVelociraptor, 0, 0, 0, 0, 0, 0, 1, 0 },
+ { 0x63A, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pf80 | PersonFlags::pftMosasaurus , 0, 0, 0, 0, 0, 0, 0, 0 },
+
+ { 0x737, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pfType8 , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x739, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pf80 | PersonFlags::pftTriceraptor , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x74A, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pf80 | PersonFlags::pftVelociraptor, 0, 0, 0, 0, 0, 0, 1, 0 },
+ { 0x726, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pf80 | PersonFlags::pftMosasaurus , 0, 0, 0, 0, 0, 0, 0, 0 },
+
+ { 0x842, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pf80 | PersonFlags::pfType8 , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x822, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pf80 | PersonFlags::pftTriceraptor , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x828, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pftVelociraptor , 0, 0, 0, 0, 0, 0, 1, 0 },
+ { 0x84B, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pf80 | PersonFlags::pftMosasaurus , 0, 0, 0, 0, 0, 0, 0, 0 },
+
+ { 0xB03, 242, PersonMask::pmDino , PersonId::pidDinosaur , PersonFlags::pfType8 , 58, 252, 0, 0, 0, 0, 0, 0 },
+ // enemy dinos
+ { 0x311, 243, PersonMask::pmEnemy , PersonId::pidEnemy , PersonFlags::pf80 | PersonFlags::pftTyrann , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x410, 243, PersonMask::pmEnemy , PersonId::pidEnemy , PersonFlags::pf80 | PersonFlags::pftTyrann , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x51B, 243, PersonMask::pmEnemy , PersonId::pidEnemy , PersonFlags::pf80 | PersonFlags::pftTyrann , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x618, 243, PersonMask::pmEnemy , PersonId::pidEnemy , PersonFlags::pf80 | PersonFlags::pftTyrann , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x71B, 243, PersonMask::pmEnemy , PersonId::pidEnemy , PersonFlags::pf80 | PersonFlags::pftTyrann , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0x81B, 243, PersonMask::pmEnemy , PersonId::pidEnemy , PersonFlags::pf80 | PersonFlags::pftTyrann , 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0xFFFF, 0xFFFF, 0xFFFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFFFF, 0xFFFF, 0xFF, 0xFF, 0xFF, 0xFF},
+ { 0x628, 237, PersonMask::pmEve , PersonId::pidEve , 0, 80, 9, 0, 0, 8, 35, 0, 0 },
+ { 0x628, 237, PersonMask::pmEve , PersonId::pidEve , 0, 78, 10, 0, 0, 7, 35, 0, 0 }
+};
+
+Citadel _citadelList[] = {
+ { 1, { 163, 182, 0, 0, 124, 147, 193, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0 } },
+ { 48, { 285, 286, 0, 0, 287, 288, 284, 0 }, { 114, 115, 0, 0, 116, 117, 113, 0 } },
+ { 63, { 290, 291, 0, 0, 292, 293, 289, 0 }, { 119, 120, 0, 0, 121, 122, 118, 0 } },
+ { 95, { 295, 296, 0, 0, 297, 298, 294, 0 }, { 124, 125, 0, 0, 126, 127, 123, 0 } },
+ { 127, { 300, 301, 0, 0, 302, 303, 299, 0 }, { 129, 130, 0, 0, 131, 132, 128, 0 } },
+ { 159, { 305, 306, 0, 0, 307, 308, 304, 0 }, { 134, 135, 0, 0, 136, 137, 133, 0 } },
+ { 255, { 310, 311, 0, 0, 312, 313, 309, 0 }, { 139, 140, 0, 0, 141, 142, 138, 0 } }
+};
+
+prect_t _characterRects[] = { //TODO: just an array of int16s?
+ { 93, 69, 223, 176},
+ { 102, 86, 162, 126},
+ { 88, 103, 168, 163},
+ { 116, 66, 192, 176},
+ { 129, 92, 202, 153},
+ { 60, 95, 160, 176},
+ { 155, 97, 230, 145},
+ { 100, 77, 156, 145},
+ { 110, 78, 170, 156},
+ { 84, 76, 166, 162},
+ { 57, 77, 125, 114},
+ { 93, 69, 223, 175},
+ { 93, 69, 223, 176},
+ { 93, 69, 223, 176},
+ { 154, 54, 245, 138},
+ { 200, 50, 261, 116},
+ { 70, 84, 162, 176},
+ { 125, 101, 222, 172},
+ { 188, 83, 251, 158}
+};
+
+byte _characterArray[][5] = { //TODO: struc?
+ { 8, 15, 23, 25, 0xFF},
+ { 0, 9, 0xFF },
+ { 0, 9, 0xFF },
+ { 0, 9, 0xFF },
+ { 0, 13, 0xFF },
+ { 16, 21, 0xFF },
+ { 11, 20, 0xFF },
+ { 0, 12, 0xFF },
+ { 0, 9, 0xFF },
+ { 0, 9, 0xFF },
+ { 5, 13, 0xFF },
+ { 0xFF },
+ { 0, 8, 0xFF },
+ { 0xFF },
+ { 0, 7, 0xFF },
+ { 0, 8, 0xFF },
+ { 8, 12, 0xFF },
+ { 0, 5, 0xFF },
+ { 0, 4, 0xFF },
+ { 0xFF }
+};
+
+Area kAreasTable[] = {
+ { Areas::arMo , AreaType::atCitadel, 0, 0, 0, 1, 0, 0},
+ { Areas::arTausCave , AreaType::atCave , 0, 112, 0, 2, 0, 0},
+ { Areas::arChamaar , AreaType::atValley , 0, 133, 0, 3, 0, 0},
+ { Areas::arUluru , AreaType::atValley , 0, 187, 0, 4, 0, 0},
+ { Areas::arKoto , AreaType::atValley , AreaFlags::HasVelociraptors, 236, 0, 5, 0, 0},
+ { Areas::arTamara , AreaType::atValley , 0, 288, 0, 6, 0, 0},
+ { Areas::arCantura , AreaType::atValley , 0, 334, 0, 7, 0, 0},
+ { Areas::arShandovra , AreaType::atValley , 0, 371, 0, 8, 0, 0},
+ { Areas::arNarimsCave , AreaType::atCave , 0, 115, 0, 9, 0, 0},
+ { Areas::arEmbalmersCave, AreaType::atCave , 0, 118, 0, 10, 0, 0},
+ { Areas::arWhiteArch , AreaType::atCave , 0, 122, 0, 11, 0, 0},
+ { Areas::arMoorkusLair , AreaType::atCave , 0, 127, 0, 12, 0, 0}
+};
+
+int16 tab_2CEF0[64] = {
+ 25, 257, 0, 0, 37, 258, 38, 259, 0, 0, 24, 260, 0, 0, 0, 0,
+ 0, 0, 53, 265, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 39, 261, 0, 0, 40, 262, 62, 263, 0, 0, 63, 264, 0, 0, 0, 0,
+ 18, 275, 0, 0, 35, 254, 36, 255, 19, 318, 23, 256, 0, 0, 0, 0
+};
+
+int16 tab_2CF70[64] = {
+ 65, 266, 0, 0, 66, 267, 67, 268, 0, 0, 68, 269, 0, 0, 0, 0,
+ 0, 0, 73, 274, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 69, 270, 0, 0, 70, 271, 71, 272, 0, 0, 72, 273, 0, 0, 0, 0,
+ 18, 275, 0, 0, 35, 254, 36, 255, 19, 318, 23, 256, 0, 0, 0, 0,
+};
+
+int16 kActionCursors[299] = {
+ 3, 1, 2, 4, 5, 5, 5, 0, 5, 5,
+ 5, 5, 5, 3, 2, 5, 5, 5, 3, 2,
+ 4, 5, 7, 7, 4, 5, 5, 0, 0, 0,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 0, 0, 0, 0, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 0, 0,
+ 0, 0, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 0, 0, 0, 0, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 0, 5, 6,
+ 6, 1, 6, 6, 0, 0, 6, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 6, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 0, 0, 6, 6,
+ 53, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+float _translationZ = -3400;
+float flt_2DF80 = -3400;
+float flt_2DF84 = 200;
+
+} // End of namespace Cryo
diff --git a/engines/cryo/video.cpp b/engines/cryo/video.cpp
new file mode 100644
index 0000000000..88326e647e
--- /dev/null
+++ b/engines/cryo/video.cpp
@@ -0,0 +1,616 @@
+/* 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 "cryo/cryo.h"
+#include "cryo/video.h"
+
+namespace Cryo {
+HnmPlayer::HnmPlayer(CryoEngine *vm) : _vm(vm) {
+ _soundStarted = false;
+ _pendingSounds = 0;
+ _timeDrift = 0.0;
+ _nextFrameTime = 0.0;
+ _expectedFrameTime = 0.0;
+ _rate = 0.0;
+ _useSoundSync = false;
+ _useSound = true;
+ _soundChannel = nullptr;
+ _prevRight = _prevLeft = 0;
+ _useAdpcm = false;
+ _customChunkHandler = nullptr;
+ _preserveColor0 = false;
+ _safePalette = false;
+
+ for (int i = 0; i < 256; i++)
+ decompTable[i] = 0;
+}
+
+// Original name: CLHNM_New
+void HnmPlayer::resetInternals() {
+ _frameNum = 0;
+ _file = nullptr;
+ _tmpBuffer[0] = nullptr;
+ _tmpBuffer[1] = nullptr;
+ _finalBuffer = nullptr;
+ _readBuffer = nullptr;
+ for (int i = 0; i < 256; i++) {
+ _palette[i].a = 0;
+ _palette[i].r = 0;
+ _palette[i].g = 0;
+ _palette[i].b = 0;
+ }
+}
+
+// Original name: CLHNM_SetFile
+void HnmPlayer::setFile(Common::File *file) {
+ _file = file;
+}
+
+// Original name: CLHNM_SetupTimer
+void HnmPlayer::setupTimer(float rate) {
+ _rate = 100.0 / rate;
+}
+
+// Original name: CLHNM_ResetInternalTimer
+void HnmPlayer::resetInternalTimer() {
+ _timeDrift = 0.0;
+ _nextFrameTime = _expectedFrameTime = _vm->_timerTicks;
+}
+
+// Original name: CLHNM_Reset
+void HnmPlayer::reset() {
+ _frameNum = 0;
+ _soundStarted = false;
+ _pendingSounds = 0;
+ resetInternalTimer();
+}
+
+// Original name: CLHNM_Init
+void HnmPlayer::init() {
+ _customChunkHandler = nullptr;
+ _preserveColor0 = false;
+ _useSound = true;
+}
+
+// Original name: CLHNM_SetForceZero2Black
+void HnmPlayer::setForceZero2Black(bool forceblack) {
+ _preserveColor0 = forceblack;
+}
+
+// Original name: CLHNM_WaitLoop
+void HnmPlayer::waitLoop() {
+ _expectedFrameTime += _rate;
+ _nextFrameTime = _expectedFrameTime - _timeDrift;
+ if (_useSoundSync && _vm->_timerTicks > 1000.0 + _nextFrameTime)
+ _useSound = false;
+ while (_vm->_timerTicks < _nextFrameTime) ; // waste time
+ _timeDrift = _vm->_timerTicks - _nextFrameTime;
+}
+
+// Original name: CLHNM_WantsSound
+void HnmPlayer::wantsSound(bool sound) {
+ _useSound = sound;
+}
+
+// Original name: CLHNM_SetupSound
+void HnmPlayer::setupSound(unsigned int rate, bool stereo, bool is16bits) {
+ _soundChannel = new CSoundChannel(_vm->_mixer, rate, stereo, is16bits);
+}
+
+// Original name: CLHNM_CloseSound
+void HnmPlayer::closeSound() {
+ if (_soundChannel) {
+ _soundChannel->stop();
+ delete(_soundChannel);
+ _soundChannel = nullptr;
+ }
+}
+
+// Original name: CLHNM_LoadDecompTable
+void HnmPlayer::loadDecompTable(int16 *buffer) {
+ for (int16 i = 0; i < 256; i++) {
+ int16 e = *buffer++;
+ decompTable[i] = LE16(e);
+ }
+}
+
+// Original name: CLHNM_DecompADPCM
+void HnmPlayer::decompADPCM(byte *buffer, int16 *output, int size) {
+ int16 l = _prevLeft;
+ int16 r = _prevRight;
+ size &= ~1;
+ while (size--) {
+ *output++ = l += decompTable[*buffer++];
+ *output++ = r += decompTable[*buffer++];
+ if (l > 512 || r > 512)
+ error("decompADPCM - Unexpected values");
+ }
+ _prevLeft = l;
+ _prevRight = r;
+}
+
+// Original name: CLHNM_ReadHeader
+void HnmPlayer::readHeader() {
+ _header._signature = _file->readUint32BE();
+ _file->skip(4);
+ _header._width = _file->readUint16LE();
+ _header._height = _file->readUint16LE();
+ _file->skip(4);
+ _header._numbFrame = _file->readSint32LE();
+ _file->skip(8);
+ _header._bufferSize = _file->readSint32LE();
+ _file->skip(32);
+
+ _header._bufferSize += 4096; //TODO: checkme
+}
+
+// Original name: CLHNM_GetVersion
+int16 HnmPlayer::getVersion() {
+ if (_header._signature == MKTAG('H','N','M','4'))
+ return 4;
+ return -1;
+}
+
+// Original name: CLHNM_AllocMemory
+void HnmPlayer::allocMemory() {
+// TODO: rework this code
+ _tmpBuffer[0] = (byte *)malloc(_header._bufferSize + 2);
+
+ if (!_tmpBuffer[0])
+ return;
+
+ _tmpBuffer[1] = (byte *)malloc(_header._bufferSize + 2);
+
+ if (!_tmpBuffer[1]) {
+ free(_tmpBuffer[0]);
+ _tmpBuffer[0] = nullptr;
+ return;
+ }
+
+ _readBuffer = (byte *)malloc(_header._bufferSize + 2);
+ if (!_readBuffer) {
+ free(_tmpBuffer[0]);
+ _tmpBuffer[0] = nullptr;
+ free(_tmpBuffer[1]);
+ _tmpBuffer[1] = nullptr;
+ }
+}
+
+// Original name: CLHNM_DeallocMemory
+void HnmPlayer::deallocMemory() {
+ free(_tmpBuffer[0]);
+ free(_tmpBuffer[1]);
+ free(_readBuffer);
+
+ _tmpBuffer[0] = nullptr;
+ _tmpBuffer[1] = nullptr;
+ _readBuffer = nullptr;
+}
+
+// Original name: CLHNM_SetFinalBuffer
+void HnmPlayer::setFinalBuffer(byte *buffer) {
+ _finalBuffer = buffer;
+}
+
+// Original name: CLHNM_GetFrameNum
+int HnmPlayer::getFrameNum() {
+ return _frameNum;
+}
+
+// Original name: CLHNM_TryRead
+void HnmPlayer::tryRead(int size) {
+ _file->read(_readBuffer, size);
+}
+
+// Original name: CLHNM_LoadFrame
+bool HnmPlayer::loadFrame() {
+ tryRead(4);
+ int chunk = *(int *)_readBuffer;
+ chunk = LE32(chunk);
+ chunk &= 0xFFFFFF; // upper bit - keyframe mark?
+ if (!chunk)
+ return false;
+
+ if (chunk - 4 > _header._bufferSize)
+ error("loadFrame - Chunk size");
+
+ tryRead(chunk - 4);
+ _dataPtr = _readBuffer;
+ return true;
+}
+
+// Original name CLHNM_DecompLempelZiv
+void HnmPlayer::decompLempelZiv(byte *buffer, byte *output) {
+ byte *inp = buffer;
+ byte *out = output;
+
+ unsigned int queue = 0;
+ int qpos = -1;
+
+ //TODO: fix for BE
+#define GetBit() ( 1 & ( (qpos >= 0) ? (queue >> qpos--) : (queue = *(unsigned int*)((inp += 4) - 4)) >> ((qpos = 30) + 1) ) )
+
+ for (;;) {
+ if (GetBit()) {
+ *out++ = *inp++;
+ } else {
+ int l, o;
+ if (GetBit()) {
+ l = *inp & 7;
+ o = *(uint16 *)inp >> 3;
+ inp += 2;
+ o -= 8192;
+ if (!l)
+ l = *inp++;
+ if (!l)
+ break;
+ } else {
+ l = GetBit() * 2 + GetBit();
+ o = *(inp++) - 256;
+ }
+ l += 2;
+ while (l--) {
+ *out = *(out + o);
+ out++;
+ }
+ }
+ }
+
+#undef GetBit
+
+ return;
+}
+
+// Original name: CLHNM_Desentrelace320
+void HnmPlayer::desentrelace320(byte *frame_buffer, byte *final_buffer, uint16 height) {
+ unsigned int *input = (unsigned int *)frame_buffer;
+ unsigned int *line0 = (unsigned int *)final_buffer;
+ unsigned int *line1 = (unsigned int *)(final_buffer + 320);
+ int count = (height) / 2;
+ while (count--) {
+ int16 i;
+ for (i = 0; i < 320 / 4; i++) {
+ unsigned int p0 = *input++;
+ unsigned int p4 = *input++;
+#if 0
+ *line0++ = ((p4 & 0xFF00) >> 8) | ((p4 & 0xFF000000) >> 16) | ((p0 & 0xFF00) << 8) | (p0 & 0xFF000000);
+ // *line0++ = (p0 & 0xFF000000) | ((p0 & 0xFF00) << 8) | ((p4 & 0xFF000000) >> 16) | ((p4 & 0xFF00) >> 8);
+ *line1++ = ((p0 & 0xFF0000) << 8) | ((p0 & 0xFF) << 16) | ((p4 & 0xFF0000) >> 8) | (p4 & 0xFF);
+#else
+ *line0++ = (p0 & 0xFF) | ((p0 & 0xFF0000) >> 8) | ((p4 & 0xFF) << 16) | ((p4 & 0xFF0000) << 8);
+ *line1++ = ((p0 & 0xFF00) >> 8) | ((p0 & 0xFF000000) >> 16) | ((p4 & 0xFF00) << 8) | (p4 & 0xFF000000);
+#endif
+ }
+ line0 += 320 / 4;
+ line1 += 320 / 4;
+ }
+}
+
+// Original name: CLHNM_Desentrelace
+void HnmPlayer::desentrelace() {
+ switch (_header._width) {
+ case 320:
+ desentrelace320(_newFrameBuffer, _finalBuffer, _header._height);
+ break;
+ // case 480:
+ // CLHNM_Desentrelace480(_newFrameBuffer, finalBuffer, _header._height);
+ // break;
+ default:
+ error("desentrelace - Unexpected width");
+ }
+}
+
+// Original name: CLHNM_DecompUBA
+void HnmPlayer::decompUBA(byte *output, byte *curr_buffer, byte *prev_buffer, byte *input, int width, char flags) {
+ // return;
+ byte *out_start = output;
+ byte count;
+ unsigned int code;
+ uint16 offs;
+ byte mode;
+ byte swap;
+
+ if ((flags & 1) == 0) {
+ //HNM4 classic
+ int twolinesabove = -(width * 2);
+ for (;;) {
+ code = READ_LE_UINT32(input) & 0xFFFFFF; //input++;
+ count = code & 0x1F;
+ if (count) {
+ input += 3;
+ offs = code >> 9;
+ //
+ mode = (code >> 5) & 0xF;
+ swap = mode >> 3;
+ byte *ref = ((mode & 1) ? prev_buffer : curr_buffer) + (output - out_start) + (offs * 2) - 32768;
+ int shft1, shft2;
+ if (mode & 2) {
+ // ref += twolinesabove;
+ shft1 = twolinesabove + 1;
+ shft2 = 0;
+ //swap ^= 1;
+ } else {
+ shft1 = 0;
+ shft2 = 1;
+ }
+ while (count--) {
+ byte b0 = ref[shft1];
+ byte b1 = ref[shft2];
+ output[swap] = b0;
+ output[swap ^ 1] = b1;
+ output += 2;
+ ref += (mode & 4) ? -2 : 2;
+ }
+ } else {
+ input++;
+ mode = code & 0xFF; // bits 0..4 are zero
+ switch (mode) {
+ case 0:
+ *(output++) = *(input++);
+ *(output++) = *(input++);
+ break;
+ case 0x20:
+ output += 2 * *(input++);
+ break;
+ case 0x40:
+ output += 2 * (code >> 8);
+ input += 2;
+ break;
+ case 0x60: {
+ count = *(input++);
+ byte color = *(input++);
+ while (count--) {
+ *(output++) = color;
+ *(output++) = color;
+ }
+ break;
+ }
+ default:
+ return;
+ }
+ }
+ }
+ } else {
+ assert(0);
+ //HNM4 hires
+ for (;;) {
+ code = READ_LE_UINT32(input) & 0xFFFFFF;
+ input++;
+ count = code & 0x3F;
+ if (count) {
+ mode = (code >> 5) & 0xF;
+ offs = code >> 9;
+ //
+ } else {
+ mode = code & 0xFF; // bits 0..5 are zero
+ switch (mode) {
+ case 0x00:
+ output += *input++;
+ break;
+ case 0x40:
+ *output++ = *input++;
+ *(output++ + width) = *input++;
+ break;
+ case 0x80:
+ output += width;
+ break;
+ default:
+ return;
+ }
+ }
+ }
+ }
+}
+
+// Original name: CLHNM_NextElement
+bool HnmPlayer::nextElement() {
+ if (_frameNum == 0) {
+ resetInternalTimer();
+ _prevLeft = _prevRight = 0;
+ }
+ if (_frameNum == _header._numbFrame)
+ return false;
+
+ if (!loadFrame())
+ return false;
+
+ for (;;) {
+ int sz = READ_LE_UINT32(_dataPtr) & 0xFFFFFF;
+ _dataPtr += 4;
+ int16 id = READ_LE_UINT16(_dataPtr);
+ _dataPtr += 2;
+ char h6 = *_dataPtr;
+ _dataPtr += 1;
+ char h7 = *_dataPtr;
+ _dataPtr += 1;
+ switch (id) {
+ case MKTAG16('L', 'P'):
+ changePalette();
+ _dataPtr += sz - 8;
+ break;
+ case MKTAG16('Z', 'I'):
+ _frameNum++;
+ selectBuffers();
+ decompLempelZiv(_dataPtr + 4, _newFrameBuffer);
+#if 0
+ switch (_header._width) {
+ case 320:
+ CLBlitter_RawCopy320ASM(_newFrameBuffer, _oldFrameBuffer, _header._height);
+ break;
+ case 480:
+ CLBlitter_RawCopy480ASM(_newFrameBuffer, _oldFrameBuffer, _header._height);
+ break;
+ case 640:
+ CLBlitter_RawCopy640ASM(_newFrameBuffer, _oldFrameBuffer, _header._height);
+ break;
+ default:
+ memcpy(_oldFrameBuffer, _newFrameBuffer, _header._width * _header._height);
+ }
+#else
+ memcpy(_oldFrameBuffer, _newFrameBuffer, _header._bufferSize); //TODO strange buffer size here
+#endif
+ if (!(h6 & 1))
+ desentrelace();
+ else {
+ // if(_header._width == 640)
+ // CLBlitter_RawCopy640(_newFrameBuffer, finalBuffer, _header._height);
+ // else
+ memcpy(_finalBuffer, _newFrameBuffer, _header._height); //TODO: wrong size?
+ }
+
+ if (!_soundStarted) {
+ _soundChannel->play();
+ _soundStarted = true;
+ }
+
+ return true;
+ case MKTAG16('U', 'I'):
+ _frameNum++;
+ selectBuffers();
+ decompUBA(_newFrameBuffer, _newFrameBuffer, _oldFrameBuffer, _dataPtr, _header._width, h6);
+ if (!(h6 & 1))
+ desentrelace();
+ else {
+ // if(_header._width == 640)
+ // CLBlitter_RawCopy640(_newFrameBuffer, _finalBuffer, _header._height);
+ // else
+ memcpy(_finalBuffer, _newFrameBuffer, _header._width * _header._height);
+ }
+ return true;
+
+ case MKTAG16('d', 's'):
+ case MKTAG16('D', 'S'):
+ if (_useSound) {
+ if (!h6) {
+ int sound_size = sz - 8;
+ if (!_useAdpcm) {
+ _soundChannel->queueBuffer(_dataPtr, sound_size - 2, false, _soundStarted);
+ } else {
+#if 0
+ // Not used in Lost Eden
+ int16 *sound_buffer = (int16 *)_soundGroup->getNextBuffer();
+ if (!_pendingSounds) {
+ const int kDecompTableSize = 256 * sizeof(int16);
+ loadDecompTable((int16 *)_dataPtr);
+ decompADPCM(_dataPtr + kDecompTableSize, sound_buffer, sound_size - kDecompTableSize);
+ _soundGroup->assignDatas(sound_buffer, (sound_size - kDecompTableSize) * 2, false);
+ } else {
+ decompADPCM(_dataPtr, sound_buffer, sound_size);
+ _soundGroup->assignDatas(sound_buffer, sound_size * 2, false);
+ }
+ _pendingSounds++;
+ if (_soundStarted)
+ _soundGroup->playNextSample(_soundChannel);
+#endif
+ }
+ } else
+ error("nextElement - unexpected flag");
+ }
+ _dataPtr += sz - 8;
+ break;
+ default:
+ if (_customChunkHandler)
+ _customChunkHandler(_dataPtr, sz - 8, id, h6, h7);
+ _dataPtr += sz - 8;
+ }
+ }
+ return true;
+}
+
+// Original name: CLHNM_GetSoundChannel
+CSoundChannel *HnmPlayer::getSoundChannel() {
+ return _soundChannel;
+}
+
+// Original name: CLHNM_ChangePalette
+void HnmPlayer::changePalette() {
+ CLPalette_GetLastPalette(_palette);
+ byte *pal = _dataPtr;
+ if (*(uint16 *)pal == 0xFFFF)
+ return;
+
+ int16 mincolor = 255;
+ int16 maxcolor = 0;
+ do {
+ uint16 fst = *pal++;
+ uint16 cnt = *pal++;
+ if (cnt == 0)
+ cnt = 256;
+ debug("hnm: setting palette, fst = %d, cnt = %d, last = %d", fst, cnt, fst + cnt - 1);
+ assert(fst + cnt <= 256);
+ if (mincolor > fst)
+ mincolor = fst;
+ if (maxcolor < fst + cnt)
+ maxcolor = fst + cnt;
+ color_t *color = _palette + fst;
+ if (_safePalette) {
+ while (cnt--) {
+ byte r = *pal++;
+ byte g = *pal++;
+ byte b = *pal++;
+ int16 rr = r << 10;
+ int16 gg = g << 10;
+ int16 bb = b << 10;
+ if (color->r != rr || color->g != gg || color->b != bb)
+ CLBlitter_OneBlackFlash();
+ color->r = rr;
+ color->g = gg;
+ color->b = bb;
+ color++;
+ }
+ } else {
+ while (cnt--) {
+ byte r = *pal++;
+ byte g = *pal++;
+ byte b = *pal++;
+ color->r = r << 10;
+ color->g = g << 10;
+ color->b = b << 10;
+ color++;
+ }
+ }
+
+ } while (*(uint16 *)pal != 0xFFFF);
+#if 0
+ if (preserve_color0) {
+ _palette[0].r = 0;
+ _palette[0].g = 0;
+ _palette[0].b = 0;
+ }
+#endif
+ // CLBlitter_Send2ScreenNextCopy(_palette, mincolor, maxcolor - mincolor);
+ CLBlitter_Send2ScreenNextCopy(_palette, 0, 256);
+}
+
+// Original name: CLHNM_SelectBuffers
+void HnmPlayer::selectBuffers() {
+ if (_frameNum % 2) {
+ _newFrameBuffer = _tmpBuffer[1];
+ _oldFrameBuffer = _tmpBuffer[0];
+ } else {
+ _newFrameBuffer = _tmpBuffer[0];
+ _oldFrameBuffer = _tmpBuffer[1];
+ }
+}
+
+} // namespace Cryo
+
diff --git a/engines/cryo/video.h b/engines/cryo/video.h
new file mode 100644
index 0000000000..83eddfb9b1
--- /dev/null
+++ b/engines/cryo/video.h
@@ -0,0 +1,106 @@
+/* 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 CRYO_VIDEO_H
+#define CRYO_VIDEO_H
+
+#include "cryo/sound.h"
+
+namespace Cryo {
+
+class CryoEngine;
+
+class HnmPlayer {
+public:
+ Common::File *_file;
+ HNMHeader _header;
+
+private:
+ CryoEngine *_vm;
+
+ void resetInternalTimer();
+ void wantsSound(bool sound);
+ void decompADPCM(byte *buffer, int16 *output, int size);
+ void loadDecompTable(int16 *buffer);
+ bool loadFrame();
+ void tryRead(int size);
+ void changePalette();
+ void selectBuffers();
+ void decompLempelZiv(byte *buffer, byte *output);
+ void desentrelace320(byte *frame_buffer, byte *final_buffer, uint16 height);
+ void desentrelace();
+ void decompUBA(byte *output, byte *curr_buffer, byte *prev_buffer, byte *input, int width, char flags);
+ void setupSoundADPCM(int16 numSounds, int16 length, int16 sampleSize, float rate, int16 mode);
+ void init();
+
+ bool _soundStarted;
+ int16 _pendingSounds;
+ float _timeDrift;
+ float _nextFrameTime;
+ float _expectedFrameTime;
+ float _rate;
+ bool _useSoundSync;
+ bool _useSound;
+ int16 _prevRight;
+ int16 _prevLeft;
+ bool _useAdpcm;
+ bool _preserveColor0;
+ int16 decompTable[256];
+ bool _safePalette;
+ int _frameNum;
+ byte *_tmpBuffer[2];
+ byte *_finalBuffer;
+ byte *_newFrameBuffer;
+ byte *_oldFrameBuffer;
+ byte *_readBuffer;
+ byte *_dataPtr;
+ color_t _palette[256];
+ int _totalRead;
+
+ void (*_customChunkHandler)(byte *buffer, int size, int16 id, char h6, char h7);
+
+ CSoundChannel *_soundChannel;
+
+public:
+ HnmPlayer(CryoEngine *vm);
+
+ void allocMemory();
+ void closeSound();
+ void deallocMemory();
+ int getFrameNum();
+ CSoundChannel *getSoundChannel();
+ int16 getVersion();
+ bool nextElement();
+ void reset();
+ void readHeader();
+ void resetInternals();
+ void setFile(Common::File *file);
+ void setFinalBuffer(byte *buffer);
+ void setForceZero2Black(bool forceblack);
+ void setupSound(unsigned int rate, bool stereo, bool is16bits);
+ void setupTimer(float rate);
+ void waitLoop();
+};
+
+} // End of namespace Cryo
+
+#endif