diff options
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 |