Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

View File

@@ -0,0 +1,948 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "cryomni3d/datstream.h"
#include "cryomni3d/versailles/engine.h"
namespace CryOmni3D {
namespace Versailles {
const uint CryOmni3DEngine_Versailles::kSpritesMapTable[] = {
/* 0 */ 242, 240, 243, 241, 256, 93, 97, 94, 160, 98, 178, 161, 179, 196, 197, 244,
/* 16 */ 142, 245, 143, 254, 95, 99, 113, 96, 100, 180, 114, 181, 73, 144, 74, 250,
/* 32 */ 202, 145, 170, 251, 203, 130, 206, 171, 49, 131, 207, 115, 116, 222, 75, 85,
/* 48 */ 76, 252, 204, 236, 86, 172, 253, 205, 237, 132, 81, 208, 173, 133, 82, 209,
/* 64 */ 24, 101, 25, 102, 87, 198, 88, 83, 258, 199, 84, 259, 257, 260, 26, 103,
/* 80 */ 28, 44, 27, 104, 29, 45, 200, 105, 201, 106, 162, 163, 32, 30, 46, 126,
/* 96 */ 33, 31, 47, 5, 127, 122, 219, 227, 123, 220, 107, 69, 108, 70, 164, 165,
/* 112 */ 89, 4, 90, 36, 34, 58, 128, 109, 37, 35, 255, 129, 110, 124, 125, 71,
/* 128 */ 40, 72, 41, 91, 92, 59, 228, 38, 7, 60, 111, 229, 39, 149, 121, 138,
/* 144 */ 112, 6, 139, 148, 42, 43, 232, 230, 233, 231, 140, 141, 134, 150, 135, 234,
/* 160 */ 151, 20, 226, 261, 235, 21, 262, 166, 246, 167, 136, 50, 247, 215, 152, 137,
/* 176 */ 51, 216, 153, 22, 117, 48, 23, 225, 118, 223, 182, 168, 248, 183, 169, 54,
/* 192 */ 52, 249, 217, 55, 53, 218, 8, 214, 119, 120, 186, 184, 154, 61, 187, 185,
/* 208 */ 155, 62, 56, 57, 188, 156, 65, 63, 210, 189, 157, 66, 64, 211, 19, 3,
/* 224 */ 80, 221, 1, 263, 78, 67, 174, 212, 68, 175, 213, 190, 191, 238, 0, 239,
/* 240 */ 224, 77, 146, 2, 147, 79, 158, 176, 159, 177, 194, 192, 195, 193, /*-1u, -1u*/
};
const uint CryOmni3DEngine_Versailles::kSpritesMapTableSize = ARRAYSIZE(kSpritesMapTable);
const LevelInitialState CryOmni3DEngine_Versailles::kLevelInitialStates[] = {
{ 1, M_PI, 0. }, // Level 1
{ 9, M_PI, 0. }, // Level 2
{ 10, M_PI_2, 0. }, // Level 3
{ 10, 0., 0. }, // Level 4
{ 14, M_PI, 0. }, // Level 5
{ 8, 0., 0. }, // Level 6
{ 1, M_PI, 0. }, // Level 7
{ 4, M_PI, 0. } // Level 8
};
const FakeTransitionActionPlace CryOmni3DEngine_Versailles::kFakeTransitions[] = {
{31141, 15},
{31142, 16},
{31143, 17},
{32201, 18},
{32202, 19},
{32203, 20},
{32204, 21},
{35330, 36},
{34172, 18},
{0, 0} // Must be the last one
};
static void readSubtitles(Common::HashMap<Common::String, Common::Array<SubtitleEntry> > &subtitles,
DATSeekableStream *data) {
uint16 vidsCount = data->readUint16LE();
for (uint16 i = 0; i < vidsCount; i++) {
Common::String vidName = data->readString16();
Common::Array<SubtitleEntry> &entries = subtitles[vidName];
uint16 linesCount = data->readUint16LE();
entries.resize(linesCount);
for (uint16 j = 0; j < linesCount; j++) {
SubtitleEntry &entry = entries[j];
entry.frameStart = data->readUint32LE();
entry.text = data->readString16();
}
}
}
void CryOmni3DEngine_Versailles::loadStaticData() {
// This should match data in devtools/create_cryomni3d_dat
DATSeekableStream *data = getStaticData(MKTAG('V', 'R', 'S', 'L'), 1);
// In the dat file we have
// file names
data->readString16Array16(_localizedFilenames);
assert(_localizedFilenames.size() == LocalizedFilenames::kMax);
// epigraph settings, bomb password
_epigraphContent = data->readString16();
_epigraphPassword = data->readString16();
if (getLanguage() == Common::JA_JPN) {
_bombAlphabet = data->readString16().decode(Common::kWindows932);
_bombPassword = data->readString16().decode(Common::kWindows932);
} else {
_bombAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ '";
_bombPassword = data->readString16();
}
// messages, paintings titles
data->readString16Array16(_messages);
if ((getLanguage() == Common::JA_JPN) ||
(getLanguage() == Common::KO_KOR) ||
(getLanguage() == Common::ZH_TWN)) {
assert(_messages.size() == 151);
} else {
assert(_messages.size() == 146);
}
data->readString16Array16(_paintingsTitles);
assert(_paintingsTitles.size() == 48);
_subtitles.clear();
// Only CJK have subtitles, don't change dat format for other languages
if ((getLanguage() == Common::JA_JPN) ||
(getLanguage() == Common::KO_KOR) ||
(getLanguage() == Common::ZH_TWN)) {
readSubtitles(_subtitles, data);
}
delete data;
}
struct VideoSubSetting {
const char *videoName;
int16 textLeft;
int16 textTop;
int16 textRight;
int16 textBottom;
int16 drawLeft;
int16 drawTop;
int16 drawRight;
int16 drawBottom;
};
static const VideoSubSetting kVideoSubSettings[] = {
{"11D_LEB", 15, 11, 190, 479, 208, 129, 562, 479},
{"11E_HUI", 330, 9, 620, 479, 111, 109, 321, 341},
{"11E_MAN", 403, 12, 630, 479, 134, 89, 390, 405},
{"11E_RAC", 10, 9, 241, 479, 271, 147, 628, 479},
{"12E_HUI", 361, 16, 618, 479, 84, 107, 330, 479},
{"13F_HUI", 373, 12, 633, 479, 96, 88, 341, 479},
{"21B1_HUI", 355, 13, 625, 479, 96, 104, 337, 479},
{"21F_BON", 324, 11, 628, 479, 84, 74, 307, 479},
{"21F_BON2", 11, 13, 298, 479, 321, 99, 536, 424},
{"21G_CON", 12, 13, 255, 479, 273, 156, 539, 479},
{"21G_DAU", 358, 11, 631, 479, 82, 151, 346, 479},
{"21G_HUI", 309, 17, 626, 479, 77, 85, 304, 479},
{"21I_LEB", 343, 10, 628, 479, 38, 125, 330, 479},
{"21Z_ALI", 380, 13, 627, 479, 184, 106, 369, 479},
{"21Z_BOU", 365, 13, 629, 479, 95, 65, 341, 321},
{"21Z_MON", 12, 11, 309, 479, 336, 101, 561, 406},
{"21Z_PR", 10, 16, 352, 471, 375, 104, 567, 400},
{"22G_DAU", 339, 13, 629, 479, 114, 152, 326, 479},
{"23I_LEB", 341, 15, 627, 479, 67, 140, 325, 410},
{"24Z_BON", 253, 23, 620, 479, 58, 166, 228, 439},
{"31J_SUI", 9, 9, 183, 475, 195, 159, 428, 479},
{"31L1_LUL", 367, 16, 628, 477, 136, 164, 359, 472},
{"31M_SUI", 19, 16, 212, 479, 231, 193, 395, 479},
{"31O_SUIA", 11, 12, 175, 479, 186, 118, 490, 479},
{"31O_SUIP", 12, 9, 277, 466, 296, 183, 380, 349},
{"31Q_SUI", 334, 15, 626, 479, 158, 169, 313, 308},
{"31X_BO", 332, 11, 615, 479, 89, 78, 313, 296},
{"31X_BON", 329, 12, 618, 456, 0, 171, 243, 479},
{"31X_LOU", 12, 9, 267, 447, 280, 88, 639, 479},
{"31X_SEI", 352, 12, 626, 479, 102, 98, 340, 479},
{"32J_CRO", 418, 7, 618, 477, 103, 58, 402, 438},
{"32M_MR", 13, 11, 175, 477, 184, 113, 476, 447},
{"32Q_MON", 375, 17, 623, 479, 248, 161, 341, 259},
{"32Q_RAC", 294, 11, 627, 479, 110, 152, 287, 479},
{"32Q_RAC2", 374, 13, 625, 479, 0, 101, 366, 479},
{"31O_SUIA", 11, 12, 175, 479, 186, 118, 490, 479},
{"41C_HUI", 345, 17, 626, 479, 69, 147, 330, 479},
{"41X2_CRO", 13, 13, 281, 479, 305, 113, 548, 427},
{"42C_BON", 15, 13, 347, 479, 368, 173, 525, 410},
{"43B1_MAI", 264, 15, 625, 479, 127, 154, 249, 296},
{"43B1_SEI", 17, 14, 369, 479, 390, 142, 639, 479},
{"43C_CON", 312, 11, 635, 479, 21, 137, 294, 476},
{"43C_DUR", 11, 10, 295, 479, 311, 166, 639, 479},
{"44C_BON", 17, 12, 331, 479, 358, 181, 531, 407},
{"4_MAI", 325, 14, 630, 479, 35, 48, 308, 363},
{"51L_LOU", 11, 11, 616, 161, 154, 165, 400, 479},
{"51L_PRI", 26, 19, 601, 153, 130, 167, 311, 479},
{"51M_LEB", 41, 29, 615, 188, 49, 200, 432, 479},
{"51M_MAN", 23, 19, 618, 179, 211, 195, 449, 479},
{"52A4_LAC", 12, 11, 258, 479, 273, 184, 465, 383},
{"52L_BOU", 12, 12, 190, 479, 307, 56, 592, 332},
{"52L_LOU", 8, 13, 604, 168, 135, 171, 413, 479},
{"52L_PRI", 20, 17, 610, 167, 336, 182, 639, 479},
{"53N_BON", 351, 13, 629, 479, 62, 119, 343, 418},
{"54I_BON", 343, 14, 623, 479, 72, 117, 339, 440},
{"61_BON", 10, 7, 311, 479, 336, 101, 581, 479},
{"61_DUC", 10, 14, 344, 473, 376, 156, 639, 479},
{"61_LEN", 13, 9, 269, 479, 285, 63, 590, 479},
{"62_DUC", 18, 21, 317, 479, 388, 154, 614, 479},
};
void CryOmni3DEngine_Versailles::setupDialogVariables() {
#define SET_DIAL_VARIABLE(id, var) _dialogsMan.setupVariable(id, var)
SET_DIAL_VARIABLE(0, "JOUEUR-PARLE-HUISSIER-PETIT-LEVER");
SET_DIAL_VARIABLE(1, "HUBAS-PARLE-LEVER1");
SET_DIAL_VARIABLE(2, "HUBAS-PARLE-LEVER2");
SET_DIAL_VARIABLE(3, "LEBRUN-DIT-COLBERT");
SET_DIAL_VARIABLE(4, "LEBRUN-PARLE-ESQUISSE");
SET_DIAL_VARIABLE(5, "JOUEUR-PARLE-HUISSIER-GRAND-LEVER");
SET_DIAL_VARIABLE(6, "BONTEMPS-PARLE-MAINTENON");
SET_DIAL_VARIABLE(7, "BONTEMPS-PARLE-MAINTENON2");
SET_DIAL_VARIABLE(8, "BONTEMPS-DEMANDE-INDICE");
SET_DIAL_VARIABLE(9, "BONTEMPS-DIT-ENQUETE");
SET_DIAL_VARIABLE(10, "JOUEUR-CONFIE-MESSAGE-HUISSIER");
SET_DIAL_VARIABLE(11, "JOUEUR-PARLE-HUIMA1");
SET_DIAL_VARIABLE(12, "MONSEIGNEUR-ATTEND-ESQUISSES");
SET_DIAL_VARIABLE(13, "MONSEIGNEUR-PREVIENT-BONTEMPS");
SET_DIAL_VARIABLE(14, "JOUEUR-MENT-MONSEIGNEUR");
SET_DIAL_VARIABLE(15, "JOUEUR-ECOUTE-ALIAS");
SET_DIAL_VARIABLE(16, "JOUEUR-PARLE-HUCON");
SET_DIAL_VARIABLE(17, "BONTEMPS-ATTEND-OBJET-GALLERIE");
SET_DIAL_VARIABLE(18, "SUISSE-APOLLON-PARLE-CLEF");
SET_DIAL_VARIABLE(19, "SUISSE-CABINET-DEMANDE-AUTORISATION");
SET_DIAL_VARIABLE(20, "SUISSE-VU-AUTORISATION");
SET_DIAL_VARIABLE(21, "CROISSY-ACCEPTE-TEXTE");
SET_DIAL_VARIABLE(22, "JOUEUR-POSSEDE-CLEF-PETITE-PORTE");
SET_DIAL_VARIABLE(23, "SUISSE-REFUSE-CLEF");
SET_DIAL_VARIABLE(24, "LULLY-ATTEND-MISSION-JOUEUR");
SET_DIAL_VARIABLE(25, "LULLY-DONNE-MISSION1-JOUEUR");
SET_DIAL_VARIABLE(26, "LULLY-DONNE-MISSION-JOUEUR");
SET_DIAL_VARIABLE(27, "RACINE-REPOND-ETRANGERE");
SET_DIAL_VARIABLE(28, "RACINE-REPOND-PEUPLES");
SET_DIAL_VARIABLE(29, "LULLY-DONNE-MISSION2-JOUEUR");
SET_DIAL_VARIABLE(30, "LULLY-DIT-CHAT-PENDU-JOUEUR");
SET_DIAL_VARIABLE(31, "JOUEUR-DIT-PEUPLES-LULLY");
SET_DIAL_VARIABLE(32, "LALANDE-PARLE-BONTEMPS-SCENE3");
SET_DIAL_VARIABLE(33, "BONTEMPS-DONNE-AUTORISATION-CURIOSITES");
SET_DIAL_VARIABLE(34, "BONTEMPS-ATTEND-PAMPHLET");
SET_DIAL_VARIABLE(35, "BONTEMPS-VU-PAMPHLET-DECHIFFRE-LULLY");
SET_DIAL_VARIABLE(36, "CROISSY-DIT-INEPTIES");
SET_DIAL_VARIABLE(37, "CROISSY-ATTEND-PAMPHLET2");
SET_DIAL_VARIABLE(38, "CROISSY-ATTEND-MEDAILLE");
SET_DIAL_VARIABLE(39, "CROISSY-ATTEND-PAMPHLET2-2");
SET_DIAL_VARIABLE(40, "JOUEUR-PARLE-CROISSY1");
SET_DIAL_VARIABLE(41, "MONSIEUR-PARLE-LALANDE1");
SET_DIAL_VARIABLE(42, "MONSIEUR-ATTEND-FUSAIN");
SET_DIAL_VARIABLE(43, "MONSIEUR-DONNE-SOLUTION-MEDAILLES");
SET_DIAL_VARIABLE(44, "HUISSIER-DIT-DINER");
SET_DIAL_VARIABLE(45, "HUISSIER-DIT-PREVENIR-BONTEMPS");
SET_DIAL_VARIABLE(46, "JOUEUR-POSSEDE-PAMPHLET-RELIGION");
SET_DIAL_VARIABLE(47, "JOUEUR-PARLE-BONTEMPS-SCENE4");
SET_DIAL_VARIABLE(48, "BONTEMPS-VU-PAPIER-CROISSY");
SET_DIAL_VARIABLE(49, "BONTEMPS-ATTEND-OBJET-SCENE4");
SET_DIAL_VARIABLE(50, "BONTEMPS-VU-PAMPHLET-GOUVERNEMENT");
SET_DIAL_VARIABLE(51, "JOUEUR-PARLE-VAUBAN");
SET_DIAL_VARIABLE(52, "JOUEUR-PARLE-CODE-LOUVOIS");
SET_DIAL_VARIABLE(53, "LALANDE-ECOUTE-LOUVOIS");
SET_DIAL_VARIABLE(54, "JOUEUR-PARLE-LACHAIZE");
SET_DIAL_VARIABLE(55, "JOUEUR-PARLE-LACHAIZE2");
SET_DIAL_VARIABLE(56, "LACHAIZE-ATTEND-TEXTE");
SET_DIAL_VARIABLE(57, "LACHAIZE-VU-PAMPHLET-RELIGION");
SET_DIAL_VARIABLE(58, "LACHAIZE-DIT-REFORME");
SET_DIAL_VARIABLE(59, "LACHAIZE-PARLE-BOUILLON");
SET_DIAL_VARIABLE(60, "BOUILLON-DIT-DRAGONNADES");
SET_DIAL_VARIABLE(61, "JOUEUR-PARLE-BOUILLON");
SET_DIAL_VARIABLE(62, "LACHAIZE-TROUVE-ECROUELLES");
SET_DIAL_VARIABLE(63, "LACHAIZE-DIT-DRAGONNADES");
SET_DIAL_VARIABLE(64, "LACHAIZE-DEMANDE-TEXTE");
SET_DIAL_VARIABLE(65, "LACHAIZE-PARLE-ARCHITECTURE");
SET_DIAL_VARIABLE(66, "JOUEUR-DIT-DRAGONNADES");
SET_DIAL_VARIABLE(67, "BOUILLON-ATTEND-PAMPHLET");
SET_DIAL_VARIABLE(68, "BONTEMPS-PARLE-LUSTRE");
SET_DIAL_VARIABLE(69, "BONTEMPS-ATTEND-MEMORANDUM2");
SET_DIAL_VARIABLE(70, "BONTEMPS-DIT-PROMENADE");
SET_DIAL_VARIABLE(71, "BONTEMPS-ATTEND-MEMORANDUM");
SET_DIAL_VARIABLE(72, "LENOTRE-DIT-CALME");
SET_DIAL_VARIABLE(73, "MAINE-DIT-APOTHICAIRIE");
SET_DIAL_VARIABLE(74, "JOUEUR-PARLE-BONTEMPS-SCENE6");
SET_DIAL_VARIABLE(75, "{JOUEUR-ESSAYE-OUVRIR-PORTE-CHAMBRE}");
SET_DIAL_VARIABLE(76, "{JOUEUR-TROUVE-TITRE-ET-PAMPHLET}");
SET_DIAL_VARIABLE(77, "{JOUEUR-ESSAYE-OUVRIR-PORTE-SALON}");
SET_DIAL_VARIABLE(78, "{JOUEUR-MONTRE-PAPIER-ECRIT-ENCRE-SYMPATHIQUE}");
SET_DIAL_VARIABLE(79, "{JOUEUR-MONTRE-UN-PAMPHLET}");
SET_DIAL_VARIABLE(80, "{JOUEUR-MONTRE-TOUT-AUTRE-OBJET}");
SET_DIAL_VARIABLE(81, "{JOUEUR-MONTRE-PAMPHLET-ARTS}");
SET_DIAL_VARIABLE(82, "{JOUEUR-A-MONTRE-ESQUISSES-NON-TRIEES-LEBRUN}");
SET_DIAL_VARIABLE(83, "{JOUEUR-DONNE-ESQUISSES}");
SET_DIAL_VARIABLE(84, "{JOUEUR-SE-DIRIGE-VERS-MONSEIGNEUR-AVEC-ESQUISSES}");
SET_DIAL_VARIABLE(85, "{JOUEUR-PRESENTE-FAUX-CROQUIS3}");
SET_DIAL_VARIABLE(86, "{JOUEUR-PRESENTE-FAUX-CROQUIS2}");
SET_DIAL_VARIABLE(87, "{JOUEUR-PRESENTE-FAUX-CROQUIS}");
SET_DIAL_VARIABLE(88, "{LE JOUEUR-PRESENTE-ESQUISSES-TRIEES}");
SET_DIAL_VARIABLE(89, "{LE JOUEUR-PRESENTE-AUTRES-ESQUISSES-OU-ESQUISSE-NON-TRIEES}");
SET_DIAL_VARIABLE(90, "{JOUEUR-PRESENTE-PAMPHLET-SUR-LEBRUN}");
SET_DIAL_VARIABLE(91, "{JOUEUR-PRESENTE-TOUT-AUTRE-PAMPHLET-OU-LETTRE}");
SET_DIAL_VARIABLE(92, "{JOUEUR-MONTRE-ESQUISSE-DETRUITE}");
SET_DIAL_VARIABLE(93, "{JOUEUR-MONTRE-TITRE-FABLE-APPARU-SUR-ESQUISSE}");
SET_DIAL_VARIABLE(94, "{JOUEUR-MONTRE-AUTORISATION-DE-BONTEMPS}");
SET_DIAL_VARIABLE(95, "{LE JOUEUR-A-TENTE-OUVRIR-PETITE-PORTE}");
SET_DIAL_VARIABLE(96, "{JOUEUR-POSSEDE-CLE}");
SET_DIAL_VARIABLE(97, "{JOUEUR-PRESENTE-PAMPHLET-PARTITION}");
SET_DIAL_VARIABLE(98, "{JOUEUR-MONTRE-PAMPHLET-DECHIFFRE-PAR-LULLY}");
SET_DIAL_VARIABLE(99, "{JOUEUR-MONTRE-MEDAILLES-MONSIEUR}");
SET_DIAL_VARIABLE(100, "{JOUEUR-MONTRE-PAMPHLET-ARCHITECTURE}");
SET_DIAL_VARIABLE(101, "{JOUEUR-MONTRE-EPIGRAPHE-MEDAILLES}");
SET_DIAL_VARIABLE(102, "{JOUEUR-MONTRE-TOUT-AUTRE-CHOSE}");
SET_DIAL_VARIABLE(103, "{JOUEUR-POSSEDE-FUSAIN-MEDAILLES}");
SET_DIAL_VARIABLE(104, "{JOUEUR-MONTRE-FUSAIN-MEDAILLES}");
SET_DIAL_VARIABLE(105, "{JOUEUR-PRESENTE-OBJET-HUISSIER}");
SET_DIAL_VARIABLE(106, "{JOUEUR-APPROCHE-MADAME-MAINTENON}");
SET_DIAL_VARIABLE(107, "{JOUEUR-DONNE-REPAS}");
SET_DIAL_VARIABLE(108, "{JOUEUR-TROUVE-PLANS-VAUBAN}");
SET_DIAL_VARIABLE(109, "{JOUEUR-ALLER-BUREAU-LOUVOIS}");
SET_DIAL_VARIABLE(110, "{JOUEUR-MONTRE-PAMPHLET-RELIGION}");
SET_DIAL_VARIABLE(111, "{JOUEUR-MONTRE-PAMPHLET-GOUVERNEMENT}");
SET_DIAL_VARIABLE(112, "{JOUEUR-MONTRE-PAPIER-CROISSY}");
SET_DIAL_VARIABLE(113, "{JOUEUR-MONTRE-ECROUELLES}");
SET_DIAL_VARIABLE(114, "{LACHAIZE-TIENT-TEXTE}");
SET_DIAL_VARIABLE(115, "{JOUEUR-VU-PLANS-SALON-DIANE}");
SET_DIAL_VARIABLE(116, "{JOUEUR-VU-MEMORANDUM-DANS-LUSTRE-DU-SALON-DE-LA-GUERRE}");
SET_DIAL_VARIABLE(117, "{JOUEUR-VU-MEMORANDUM-DANS-LUSTRE-DU-SALON-APOLLON}");
SET_DIAL_VARIABLE(118, "{JOUEUR-MONTRE-MEMORANDUM}");
SET_DIAL_VARIABLE(119, "{JOUEUR-POSSEDE-CLEF-3-ET-4}");
SET_DIAL_VARIABLE(120, "{JOUEUR-DONNE-SIROP-DE-ROSE}");
SET_DIAL_VARIABLE(121, "{JOUEUR-DONNE-AUTRE-MEDICAMENT}");
SET_DIAL_VARIABLE(122, "{DUC_MAIN_A_PARLE}");
SET_DIAL_VARIABLE(123, "{LEVEL1_FINI}");
SET_DIAL_VARIABLE(124, "{LEVEL2_FINI}");
SET_DIAL_VARIABLE(125, "{LEVEL3_FINI}");
SET_DIAL_VARIABLE(126, "{LEVEL4_FINI}");
SET_DIAL_VARIABLE(127, "{LEVEL5_FINI}");
SET_DIAL_VARIABLE(128, "{LEVEL6_FINI}");
SET_DIAL_VARIABLE(129, "{LEVEL7_FINI}");
SET_DIAL_VARIABLE(130, "{JOUEUR_POSSEDE_PAMPHLET_ARCHI}");
SET_DIAL_VARIABLE(131, "{FAUSSE_ESQ_OK}");
SET_DIAL_VARIABLE(132, "{CURRENT_GAME_TIME1}");
SET_DIAL_VARIABLE(133, "{CURRENT_GAME_TIME2}");
SET_DIAL_VARIABLE(134, "{CURRENT_GAME_TIME3}");
SET_DIAL_VARIABLE(135, "{CURRENT_GAME_TIME4}");
SET_DIAL_VARIABLE(136, "{CURRENT_GAME_TIME5}");
SET_DIAL_VARIABLE(137, "{JOUEUR_POSSEDE_EPIGRAPHE}");
#undef SET_DIAL_VARIABLE
for (uint i = 0; i < ARRAYSIZE(kVideoSubSettings); i++) {
const VideoSubSetting &vss = kVideoSubSettings[i];
_dialogsMan.registerSubtitlesSettings(
vss.videoName,
DialogsManager::SubtitlesSettings(
vss.textLeft, vss.textTop, vss.textRight, vss.textBottom,
vss.drawLeft, vss.drawTop, vss.drawRight, vss.drawBottom));
}
}
void CryOmni3DEngine_Versailles::initPlacesStates() {
_placeStates.resize(100);
// Reset all the objects before configuring some
for (Common::Array<PlaceState>::iterator it = _placeStates.begin(); it != _placeStates.end();
it++) {
// Useless because it's only a bunch of simple variables
it->~PlaceState();
new ((void *)it) PlaceState();
}
#define SET_PLACE_STATE(id, init, filter, docImage) _placeStates[id] = PlaceState(init, filter, docImage)
#define FILTER_EVENT(level, place) &CryOmni3DEngine_Versailles::filterEventLevel ## level ## Place ## place
#define INIT_PLACE(level, place) &CryOmni3DEngine_Versailles::initPlaceLevel ## level ## Place ## place
if (_currentLevel == 1) {
SET_PLACE_STATE(1, nullptr, FILTER_EVENT(1, 1), "VS22");
SET_PLACE_STATE(2, nullptr, FILTER_EVENT(1, 2), "VS20");
SET_PLACE_STATE(3, INIT_PLACE(1, 3), FILTER_EVENT(1, 3), "VS19");
SET_PLACE_STATE(4, nullptr, nullptr, nullptr);
SET_PLACE_STATE(5, nullptr, nullptr, nullptr);
SET_PLACE_STATE(6, nullptr, nullptr, nullptr);
SET_PLACE_STATE(7, nullptr, nullptr, nullptr); // Filter is a leftover
// WORKAROUND: Missing VS21
SET_PLACE_STATE(8, nullptr, nullptr, "VS21");
SET_PLACE_STATE(9, nullptr, nullptr, nullptr);
SET_PLACE_STATE(10, nullptr, nullptr, "VS31");
SET_PLACE_STATE(11, nullptr, nullptr, "VS31");
SET_PLACE_STATE(12, nullptr, nullptr, nullptr);
SET_PLACE_STATE(13, nullptr, nullptr, "VS31");
SET_PLACE_STATE(14, nullptr, FILTER_EVENT(1, 14), nullptr);
} else if (_currentLevel == 2) {
SET_PLACE_STATE(1, nullptr, FILTER_EVENT(2, 1), "VS22");
SET_PLACE_STATE(2, nullptr, FILTER_EVENT(2, 2), "VS20");
SET_PLACE_STATE(3, nullptr, nullptr, "VS19");
SET_PLACE_STATE(4, nullptr, nullptr, "VS18");
SET_PLACE_STATE(5, nullptr, FILTER_EVENT(2, 5), nullptr);
SET_PLACE_STATE(6, nullptr, nullptr, "VS19");
SET_PLACE_STATE(7, nullptr, nullptr, nullptr);
// WORKAROUND: Missing VS21
SET_PLACE_STATE(8, nullptr, nullptr, "VS21");
SET_PLACE_STATE(9, INIT_PLACE(2, 9), FILTER_EVENT(2, 9), "VS23");
SET_PLACE_STATE(10, nullptr, nullptr, "VS31");
SET_PLACE_STATE(11, nullptr, FILTER_EVENT(2, 11), "VS31");
SET_PLACE_STATE(12, nullptr, FILTER_EVENT(2, 12), "VS24");
SET_PLACE_STATE(13, nullptr, nullptr, "VS31");
SET_PLACE_STATE(14, nullptr, FILTER_EVENT(2, 14), nullptr);
} else if (_currentLevel == 3) {
SET_PLACE_STATE(1, nullptr, nullptr, "VS35");
SET_PLACE_STATE(2, nullptr, nullptr, "VS40");
SET_PLACE_STATE(3, nullptr, FILTER_EVENT(3, 3), "VS40");
SET_PLACE_STATE(4, nullptr, nullptr, "VS36");
SET_PLACE_STATE(5, nullptr, nullptr, "VS36");
SET_PLACE_STATE(6, nullptr, nullptr, "VS30");
SET_PLACE_STATE(7, nullptr, nullptr, "VS30");
SET_PLACE_STATE(8, nullptr, nullptr, "VS30");
SET_PLACE_STATE(9, nullptr, nullptr, "VS39");
SET_PLACE_STATE(10, nullptr, FILTER_EVENT(3, 10), "VS28");
SET_PLACE_STATE(11, nullptr, nullptr, "VS28");
SET_PLACE_STATE(12, nullptr, nullptr, "VS30");
SET_PLACE_STATE(13, nullptr, FILTER_EVENT(3, 13), "VS27");
SET_PLACE_STATE(14, nullptr, nullptr, "VS26");
SET_PLACE_STATE(15, nullptr, FILTER_EVENT(3, 15), "VS25");
SET_PLACE_STATE(16, nullptr, nullptr, "VS24");
SET_PLACE_STATE(17, nullptr, FILTER_EVENT(3, 17), "VS25");
SET_PLACE_STATE(18, nullptr, FILTER_EVENT(3, 18), nullptr);
SET_PLACE_STATE(19, nullptr, FILTER_EVENT(3, 19), "VS26");
SET_PLACE_STATE(20, nullptr, FILTER_EVENT(3_5, 20), nullptr);
SET_PLACE_STATE(21, nullptr, nullptr, "VS28");
SET_PLACE_STATE(22, nullptr, FILTER_EVENT(3, 22), "VS26");
SET_PLACE_STATE(23, nullptr, FILTER_EVENT(3, 23), nullptr);
SET_PLACE_STATE(24, nullptr, nullptr, "VS30");
} else if (_currentLevel == 4) {
SET_PLACE_STATE(1, nullptr, nullptr, "VS35");
SET_PLACE_STATE(2, nullptr, nullptr, "VS40");
SET_PLACE_STATE(3, nullptr, nullptr, "VS40");
SET_PLACE_STATE(4, nullptr, nullptr, "VS36");
SET_PLACE_STATE(5, nullptr, nullptr, nullptr);
SET_PLACE_STATE(6, nullptr, nullptr, nullptr);
SET_PLACE_STATE(7, nullptr, nullptr, "VS17");
SET_PLACE_STATE(8, nullptr, nullptr, "VS17");
SET_PLACE_STATE(9, INIT_PLACE(4, 9), nullptr, nullptr);
SET_PLACE_STATE(10, nullptr, FILTER_EVENT(4, 10), "VS18");
SET_PLACE_STATE(11, nullptr, nullptr, "VS20");
SET_PLACE_STATE(12, nullptr, FILTER_EVENT(4, 12_13_14), "VS31");
SET_PLACE_STATE(13, nullptr, FILTER_EVENT(4, 12_13_14), "VS31");
SET_PLACE_STATE(14, nullptr, FILTER_EVENT(4, 12_13_14), "VS31");
SET_PLACE_STATE(15, nullptr, FILTER_EVENT(4, 15), "VS36");
SET_PLACE_STATE(16, nullptr, FILTER_EVENT(4, 16), nullptr);
SET_PLACE_STATE(17, nullptr, FILTER_EVENT(4, 17), nullptr);
} else if (_currentLevel == 5) {
SET_PLACE_STATE(1, nullptr, nullptr, "VS35");
SET_PLACE_STATE(2, nullptr, nullptr, "VS35");
SET_PLACE_STATE(3, nullptr, nullptr, "VS36");
SET_PLACE_STATE(4, nullptr, nullptr, "VS36");
SET_PLACE_STATE(5, nullptr, nullptr, "VS36");
SET_PLACE_STATE(6, INIT_PLACE(5, 6), nullptr, "VS30");
SET_PLACE_STATE(7, nullptr, nullptr, "VS30");
SET_PLACE_STATE(8, nullptr, nullptr, "VS30");
SET_PLACE_STATE(9, nullptr, FILTER_EVENT(5, 9), "VS39");
SET_PLACE_STATE(10, nullptr, nullptr, "VS28");
SET_PLACE_STATE(11, nullptr, nullptr, "VS16");
SET_PLACE_STATE(12, nullptr, nullptr, "VS30");
SET_PLACE_STATE(13, nullptr, nullptr, "VS27");
SET_PLACE_STATE(14, nullptr, FILTER_EVENT(5, 14), "VS26");
SET_PLACE_STATE(15, nullptr, FILTER_EVENT(5, 15), "VS25");
SET_PLACE_STATE(16, nullptr, FILTER_EVENT(5, 16), "VS24");
SET_PLACE_STATE(17, nullptr, nullptr, "VS25");
SET_PLACE_STATE(18, nullptr, nullptr, nullptr);
SET_PLACE_STATE(19, nullptr, nullptr, nullptr);
SET_PLACE_STATE(20, nullptr, FILTER_EVENT(3_5, 20), nullptr);
SET_PLACE_STATE(21, nullptr, nullptr, "VS28");
SET_PLACE_STATE(22, nullptr, nullptr, nullptr);
SET_PLACE_STATE(23, nullptr, FILTER_EVENT(5, 23), nullptr);
SET_PLACE_STATE(24, nullptr, nullptr, nullptr);
SET_PLACE_STATE(25, nullptr, nullptr, nullptr);
SET_PLACE_STATE(26, nullptr, nullptr, "VS16");
SET_PLACE_STATE(27, nullptr, FILTER_EVENT(5, 27), "VS16");
SET_PLACE_STATE(28, nullptr, FILTER_EVENT(5, 28), nullptr);
SET_PLACE_STATE(29, nullptr, FILTER_EVENT(5, 29), "VS24");
SET_PLACE_STATE(30, nullptr, nullptr, nullptr);
SET_PLACE_STATE(31, nullptr, nullptr, nullptr);
SET_PLACE_STATE(32, nullptr, nullptr, nullptr);
SET_PLACE_STATE(33, nullptr, FILTER_EVENT(5, 33), nullptr);
SET_PLACE_STATE(34, nullptr, FILTER_EVENT(5, 34), nullptr);
} else if (_currentLevel == 6) {
SET_PLACE_STATE(1, nullptr, FILTER_EVENT(6, 1), "VS34");
SET_PLACE_STATE(2, nullptr, FILTER_EVENT(6, Orangery), "VS32");
SET_PLACE_STATE(3, nullptr, FILTER_EVENT(6, 3), "VS32");
SET_PLACE_STATE(4, nullptr, FILTER_EVENT(6, Orangery), "VS32");
SET_PLACE_STATE(5, nullptr, FILTER_EVENT(6, Orangery), "VS32");
SET_PLACE_STATE(6, nullptr, FILTER_EVENT(6, Orangery), "VS32");
SET_PLACE_STATE(7, nullptr, FILTER_EVENT(6, Orangery), "VS32");
SET_PLACE_STATE(8, nullptr, FILTER_EVENT(6, Orangery), "VS32");
SET_PLACE_STATE(9, nullptr, FILTER_EVENT(6, Orangery), "VS32");
SET_PLACE_STATE(10, nullptr, FILTER_EVENT(6, Orangery), "VS32");
SET_PLACE_STATE(11, nullptr, FILTER_EVENT(6, Orangery), "VS32");
SET_PLACE_STATE(12, nullptr, FILTER_EVENT(6, Orangery), "VS32");
SET_PLACE_STATE(13, nullptr, nullptr, "VS33");
SET_PLACE_STATE(14, nullptr, nullptr, "VS33"); // Filter is a leftover
SET_PLACE_STATE(15, nullptr, nullptr, "VS33");
SET_PLACE_STATE(16, nullptr, nullptr, "VS33");
SET_PLACE_STATE(17, nullptr, nullptr, "VS33");
SET_PLACE_STATE(18, nullptr, nullptr, "VS33");
SET_PLACE_STATE(19, nullptr, FILTER_EVENT(6, 19), "VS33");
SET_PLACE_STATE(20, nullptr, nullptr, "VS33");
SET_PLACE_STATE(21, nullptr, nullptr, "VS33");
SET_PLACE_STATE(22, nullptr, nullptr, "VS33");
SET_PLACE_STATE(23, nullptr, nullptr, "VS33");
SET_PLACE_STATE(24, nullptr, nullptr, "VS33");
SET_PLACE_STATE(25, nullptr, nullptr, "VS33");
SET_PLACE_STATE(26, nullptr, nullptr, "VS33");
SET_PLACE_STATE(27, nullptr, nullptr, "VS33");
SET_PLACE_STATE(28, nullptr, nullptr, "VS33");
SET_PLACE_STATE(29, nullptr, nullptr, "VS33");
SET_PLACE_STATE(30, nullptr, nullptr, "VS33");
SET_PLACE_STATE(31, nullptr, nullptr, "VS33");
SET_PLACE_STATE(32, nullptr, nullptr, "VS33");
SET_PLACE_STATE(33, nullptr, nullptr, "VS33");
SET_PLACE_STATE(34, nullptr, nullptr, "VS33");
SET_PLACE_STATE(35, nullptr, nullptr, "VS33");
SET_PLACE_STATE(36, nullptr, nullptr, "VS33");
SET_PLACE_STATE(37, nullptr, nullptr, "VS33");
SET_PLACE_STATE(38, nullptr, nullptr, "VS33");
SET_PLACE_STATE(39, nullptr, nullptr, "VS33");
SET_PLACE_STATE(40, nullptr, nullptr, "VS33");
SET_PLACE_STATE(41, nullptr, nullptr, "VS33");
SET_PLACE_STATE(42, nullptr, nullptr, "VS33");
SET_PLACE_STATE(43, nullptr, nullptr, "VS33");
SET_PLACE_STATE(44, nullptr, nullptr, "VS33");
} else if (_currentLevel == 7) {
SET_PLACE_STATE(1, nullptr, nullptr, nullptr);
SET_PLACE_STATE(2, nullptr, FILTER_EVENT(7, 2), nullptr);
SET_PLACE_STATE(3, nullptr, nullptr, nullptr);
SET_PLACE_STATE(4, nullptr, nullptr, nullptr);
SET_PLACE_STATE(5, nullptr, nullptr, nullptr);
SET_PLACE_STATE(6, nullptr, nullptr, nullptr);
SET_PLACE_STATE(7, nullptr, nullptr, nullptr); // Filter is a leftover
SET_PLACE_STATE(8, nullptr, nullptr, nullptr);
SET_PLACE_STATE(9, nullptr, FILTER_EVENT(7, 9), nullptr);
SET_PLACE_STATE(10, nullptr, FILTER_EVENT(7, 10_11_13), "VS31");
SET_PLACE_STATE(11, nullptr, FILTER_EVENT(7, 10_11_13), "VS31");
SET_PLACE_STATE(12, nullptr, nullptr, nullptr);
SET_PLACE_STATE(13, nullptr, FILTER_EVENT(7, 10_11_13), "VS31");
SET_PLACE_STATE(14, nullptr, nullptr, nullptr);
SET_PLACE_STATE(15, nullptr, nullptr, nullptr);
SET_PLACE_STATE(16, nullptr, nullptr, nullptr);
SET_PLACE_STATE(17, nullptr, nullptr, nullptr);
SET_PLACE_STATE(18, nullptr, nullptr, nullptr);
SET_PLACE_STATE(19, nullptr, nullptr, nullptr);
SET_PLACE_STATE(20, nullptr, FILTER_EVENT(7, 20), nullptr);
SET_PLACE_STATE(21, nullptr, nullptr, nullptr);
SET_PLACE_STATE(22, nullptr, nullptr, nullptr);
SET_PLACE_STATE(23, nullptr, nullptr, nullptr);
SET_PLACE_STATE(24, nullptr, nullptr, nullptr);
SET_PLACE_STATE(25, nullptr, nullptr, nullptr);
SET_PLACE_STATE(26, nullptr, nullptr, nullptr);
SET_PLACE_STATE(27, nullptr, nullptr, nullptr);
SET_PLACE_STATE(28, nullptr, nullptr, nullptr);
SET_PLACE_STATE(29, nullptr, nullptr, nullptr);
} else if (_currentLevel == 8) {
SET_PLACE_STATE(1, nullptr, nullptr, "VS35");
SET_PLACE_STATE(2, nullptr, nullptr, "VS40");
SET_PLACE_STATE(3, nullptr, nullptr, "VS40");
SET_PLACE_STATE(4, nullptr, nullptr, "VS36");
SET_PLACE_STATE(5, nullptr, nullptr, nullptr);
// WORKAROUND: Missing VS30
SET_PLACE_STATE(6, nullptr, nullptr, "VS30");
SET_PLACE_STATE(7, nullptr, nullptr, "VS30");
SET_PLACE_STATE(8, nullptr, nullptr, "VS30");
SET_PLACE_STATE(9, nullptr, nullptr, "VS39");
SET_PLACE_STATE(10, nullptr, nullptr, "VS28");
SET_PLACE_STATE(11, nullptr, nullptr, "VS16");
SET_PLACE_STATE(12, nullptr, nullptr, "VS30");
SET_PLACE_STATE(13, nullptr, nullptr, "VS27");
SET_PLACE_STATE(14, nullptr, nullptr, "VS26");
SET_PLACE_STATE(15, nullptr, nullptr, "VS25");
SET_PLACE_STATE(16, nullptr, nullptr, "VS24");
SET_PLACE_STATE(17, nullptr, nullptr, nullptr);
SET_PLACE_STATE(18, nullptr, nullptr, nullptr);
SET_PLACE_STATE(19, nullptr, nullptr, nullptr);
SET_PLACE_STATE(20, nullptr, nullptr, nullptr);
SET_PLACE_STATE(21, nullptr, nullptr, nullptr);
SET_PLACE_STATE(22, nullptr, nullptr, nullptr);
SET_PLACE_STATE(23, nullptr, nullptr, nullptr);
SET_PLACE_STATE(24, nullptr, nullptr, "VS30");
SET_PLACE_STATE(25, nullptr, nullptr, nullptr);
SET_PLACE_STATE(26, nullptr, nullptr, nullptr);
SET_PLACE_STATE(27, nullptr, nullptr, nullptr);
SET_PLACE_STATE(28, nullptr, nullptr, nullptr);
SET_PLACE_STATE(29, nullptr, nullptr, nullptr);
SET_PLACE_STATE(30, nullptr, nullptr, nullptr);
SET_PLACE_STATE(31, nullptr, nullptr, nullptr);
SET_PLACE_STATE(32, nullptr, nullptr, nullptr);
SET_PLACE_STATE(33, nullptr, nullptr, "VS31");
SET_PLACE_STATE(34, nullptr, nullptr, "VS31");
SET_PLACE_STATE(35, nullptr, nullptr, "VS31");
SET_PLACE_STATE(36, nullptr, nullptr, "VS23");
SET_PLACE_STATE(37, nullptr, nullptr, "VS22");
SET_PLACE_STATE(38, nullptr, nullptr, "VS20");
// WORKAROUND: In original game VS19 is in 49 and should be in 39
SET_PLACE_STATE(39, nullptr, nullptr, "VS19");
SET_PLACE_STATE(40, nullptr, nullptr, "VS18");
SET_PLACE_STATE(41, nullptr, nullptr, nullptr);
SET_PLACE_STATE(42, nullptr, nullptr, "VS17");
SET_PLACE_STATE(43, nullptr, nullptr, "VS17");
SET_PLACE_STATE(44, nullptr, nullptr, nullptr);
SET_PLACE_STATE(45, nullptr, nullptr, nullptr);
SET_PLACE_STATE(46, nullptr, nullptr, nullptr);
SET_PLACE_STATE(47, nullptr, nullptr, nullptr);
SET_PLACE_STATE(48, nullptr, nullptr, nullptr);
SET_PLACE_STATE(49, nullptr, nullptr, nullptr);
}
#undef INIT_PLACE
#undef FILTER_EVENT
#undef SET_PLACE_STATE
}
void CryOmni3DEngine_Versailles::setupLevelActionsMask() {
_actionMasks.clear();
#define SET_MASK(placeId, placeState, oldActionId, newActionId) _actionMasks[PlaceStateActionKey(placeId, placeState, oldActionId)] = newActionId
if (_currentLevel == 1) {
SET_MASK(1, 0, 11015, 0);
SET_MASK(1, 0, 21015, 0);
SET_MASK(1, 1, 21011, 0);
SET_MASK(1, 1, 21012, 0);
SET_MASK(1, 1, 21013, 0);
SET_MASK(1, 1, 21014, 0);
// 2, 0 is empty
SET_MASK(2, 1, 51201, 0);
SET_MASK(2, 1, 21202, 0);
SET_MASK(2, 1, 21203, 0);
SET_MASK(2, 2, 51201, 0);
SET_MASK(2, 2, 21202, 0);
SET_MASK(2, 2, 21203, 0);
SET_MASK(2, 2, 11201, 1);
SET_MASK(2, 2, 21201, 1);
// 3, 0 is empty
SET_MASK(3, 1, 11301, 0);
SET_MASK(3, 1, 21301, 0);
// 14, 0 is empty
SET_MASK(14, 1, 31141, 0);
} else if (_currentLevel == 2) {
// 1, 0 is empty
SET_MASK(1, 1, 12101, 0);
SET_MASK(1, 1, 22101, 0);
SET_MASK(11, 0, 12111, 0);
SET_MASK(11, 0, 22111, 0);
// 11, 1 is empty
// 9, 0 is empty
SET_MASK(9, 1, 52903, 0);
SET_MASK(9, 1, 22903, 0);
SET_MASK(9, 1, 52902, 12902);
SET_MASK(9, 2, 52903, 0);
SET_MASK(9, 2, 22903, 0);
SET_MASK(9, 2, 52902, 0);
SET_MASK(9, 2, 22902, 0);
} else if (_currentLevel == 3) {
SET_MASK(13, 0, 13131, 0);
SET_MASK(13, 0, 23131, 0);
SET_MASK(13, 1, 13131, 0);
SET_MASK(13, 1, 23131, 0);
SET_MASK(13, 1, 33130, 0);
// 13, 2 is empty
SET_MASK(13, 3, 33130, 0);
// 14, 0 is empty
SET_MASK(14, 1, 23220, 0);
SET_MASK(15, 0, 13151, 43154);
SET_MASK(15, 0, 23151, 0);
// 15, 1 is empty
SET_MASK(17, 0, 13151, 0);
SET_MASK(17, 0, 23151, 0);
// 17, 1 is empty
// 16, 0 is empty
SET_MASK(16, 1, 43160, 0);
// 19, 0 is empty
SET_MASK(19, 1, 43190, 0);
SET_MASK(22, 0, 33220, 0);
SET_MASK(22, 1, 13220, 0);
SET_MASK(22, 1, 23220, 0);
SET_MASK(22, 2, 13220, 0);
SET_MASK(22, 2, 23220, 0);
SET_MASK(22, 2, 33220, 0);
} else if (_currentLevel == 4) {
// 16, 0 is empty
SET_MASK(16, 1, 14161, 0);
SET_MASK(16, 1, 24161, 0);
SET_MASK(16, 2, 14161, 0);
SET_MASK(16, 2, 24161, 0);
// 17, 0 is empty
SET_MASK(17, 1, 34171, 0);
// 7, 0 is empty
SET_MASK(7, 1, 24081, 0);
SET_MASK(7, 1, 44071, 0);
// 8, 0 is empty
SET_MASK(8, 1, 24081, 0);
SET_MASK(9, 0, 54091, 0);
SET_MASK(9, 0, 14091, 0);
SET_MASK(9, 0, 24092, 0);
SET_MASK(9, 0, 24091, 0);
SET_MASK(9, 1, 14091, 54091);
SET_MASK(9, 2, 54091, 24091);
SET_MASK(10, 0, 14105, 0);
SET_MASK(10, 0, 24105, 0);
SET_MASK(10, 0, 24106, 0);
SET_MASK(10, 0, 24107, 0);
SET_MASK(10, 0, 54106, 0);
//SET_MASK(10, 0, 54106, 0);
SET_MASK(10, 1, 24106, 0);
SET_MASK(10, 1, 24107, 0);
SET_MASK(10, 1, 54106, 0);
//SET_MASK(10, 1, 54106, 0);
SET_MASK(10, 2, 14104, 24104);
} else if (_currentLevel == 5) {
SET_MASK(27, 0, 15270, 0);
SET_MASK(27, 0, 25270, 0);
SET_MASK(27, 1, 15270, 0);
SET_MASK(27, 1, 25270, 0);
SET_MASK(27, 1, 35270, 0);
SET_MASK(27, 2, 35270, 0);
SET_MASK(9, 0, 15090, 0);
SET_MASK(9, 0, 25090, 0);
// 9, 1 is empty
// 13, 0 is empty
SET_MASK(13, 1, 25130, 0);
SET_MASK(13, 1, 25131, 0);
SET_MASK(13, 1, 55130, 0);
SET_MASK(13, 1, 55131, 0);
SET_MASK(16, 0, 28, 0);
SET_MASK(16, 0, 35162, 0);
SET_MASK(16, 1, 28, 0);
SET_MASK(16, 1, 35162, 0);
SET_MASK(16, 1, 25160, 0);
SET_MASK(16, 1, 35161, 0);
SET_MASK(16, 2, 28, 0);
SET_MASK(16, 2, 35162, 0);
SET_MASK(16, 2, 25160, 0);
SET_MASK(16, 3, 35162, 28);
SET_MASK(16, 3, 25160, 0);
SET_MASK(16, 3, 35161, 0);
SET_MASK(16, 3, 35160, 0);
SET_MASK(16, 4, 35162, 28);
SET_MASK(16, 4, 25160, 0);
SET_MASK(16, 5, 25160, 0);
SET_MASK(16, 5, 35160, 0);
SET_MASK(16, 6, 35162, 28);
SET_MASK(16, 6, 25160, 0);
SET_MASK(16, 6, 35161, 0);
SET_MASK(16, 6, 35160, 0);
// 29, 0 is empty
SET_MASK(29, 1, 35290, 0);
SET_MASK(15, 0, 15090, 43154);
SET_MASK(15, 0, 25090, 0);
// 15, 1 is empty
SET_MASK(17, 0, 15090, 0);
SET_MASK(17, 0, 25090, 0);
// 17, 1 is empty
// 33, 0 is empty
SET_MASK(33, 1, 35330, 0);
} else if (_currentLevel == 6) {
// 1, 0 is empty
SET_MASK(1, 1, 36010, 0);
// 3, 0 is empty
SET_MASK(3, 1, 36030, 0);
SET_MASK(14, 0, 26140, 0);
SET_MASK(14, 0, 16140, 0);
// 14, 1 is empty
SET_MASK(19, 0, 36190, 0);
SET_MASK(19, 1, 16190, 0);
SET_MASK(19, 1, 26190, 0);
SET_MASK(19, 2, 36190, 0);
SET_MASK(19, 2, 16190, 0);
SET_MASK(19, 2, 26190, 0);
} else if (_currentLevel == 7) {
// 9, 0 is empty
SET_MASK(9, 1, 37090, 0);
} else if (_currentLevel == 8) {
// Nothing to mask
} else {
error("Invalid level");
}
#undef SET_MASK
}
void CryOmni3DEngine_Versailles::initWhoSpeaksWhere() {
_whoSpeaksWhere.clear();
#define SET_WHO(placeId, actionId, dialog) _whoSpeaksWhere[PlaceActionKey(placeId, actionId)] = dialog
if (_currentLevel == 1) {
SET_WHO(1, 11015, "13F_HUI");
SET_WHO(1, 12101, "21F_BON");
SET_WHO(1, 52903, "21G_DAU");
SET_WHO(1, 52902, "21G_DAU");
SET_WHO(2, 11201, "11E_HUI");
SET_WHO(2, 51201, "11E_RAC");
SET_WHO(3, 11301, "11D_LEB");
SET_WHO(5, 12501, "21B1_HUI");
if (currentGameTime() >= 2) {
SET_WHO(2, 11201, "12E_HUI");
}
} else if (_currentLevel == 2) {
SET_WHO(1, 12101, "21F_BON");
SET_WHO(9, 52903, "21G_DAU");
SET_WHO(9, 52902, "21G_DAU");
SET_WHO(9, 12902, "22G_DAU");
SET_WHO(9, 11201, "11E_HUI");
SET_WHO(9, 12901, "21G_HUI");
SET_WHO(5, 12501, "21B1_HUI");
SET_WHO(10, 12130, "21Z_ALI");
SET_WHO(10, 12130, "21Z_MON");
SET_WHO(10, 12111, "24Z_BON");
SET_WHO(11, 12130, "21Z_MON");
SET_WHO(11, 12111, "24Z_BON");
SET_WHO(13, 12130, "21Z_ALI");
SET_WHO(13, 12130, "21Z_MON");
SET_WHO(13, 12111, "24Z_BON");
SET_WHO(12, 12121, "23I_LEB");
SET_WHO(10, 52130, "21Z_ALI");
SET_WHO(11, 52130, "21Z_ALI");
SET_WHO(13, 52130, "21Z_ALI");
SET_WHO(10, 52101, "21Z_MON");
if (currentGameTime() >= 2) {
SET_WHO(9, 52902, "22G_DAU");
}
} else if (_currentLevel == 3) {
SET_WHO(13, 13130, "31M_SUI");
SET_WHO(13, 13131, "32M_MR");
SET_WHO(10, 13100, "31O_SUIA");
SET_WHO(10, 13101, "31O_SUIP");
SET_WHO(22, 13220, "31L1_LUL");
SET_WHO(6, 13060, "31Q_SUI");
SET_WHO(15, 13150, "31J_SUI");
SET_WHO(17, 13150, "31J_SUI");
SET_WHO(3, 13030, "31X_BON");
SET_WHO(24, 53240, "32Q_MON");
SET_WHO(24, 13241, "32Q_RAC2");
SET_WHO(4, 53041, "31X_SEI");
SET_WHO(4, 53040, "31X_LOU");
SET_WHO(15, 13151, "32J_CRO");
SET_WHO(17, 13151, "32J_CRO");
} else if (_currentLevel == 4) {
SET_WHO(10, 14104, "41C_HUI");
SET_WHO(10, 14105, "42C_BON");
SET_WHO(16, 14161, "41X2_CRO");
SET_WHO(10, 54106, "43C_CON");
SET_WHO(10, 54106, "43C_DUR");
SET_WHO(9, 54091, "43B1_SEI");
SET_WHO(9, 14091, "43B1_SEI");
if (currentGameTime() >= 4) {
SET_WHO(9, 54091, "4_MAI");
SET_WHO(9, 14091, "4_MAI");
}
} else if (_currentLevel == 5) {
SET_WHO(27, 15270, "52A4_LAC");
SET_WHO(9, 15090, "53N_BON");
SET_WHO(13, 55130, "51M_MAN");
SET_WHO(13, 55131, "51M_MAN");
SET_WHO(14, 55140, "52L_LOU");
SET_WHO(14, 55140, "52L_PRI");
SET_WHO(14, 15142, "52L_BOU");
SET_WHO(13, 13130, "53M_SUI");
if (currentGameTime() >= 4) {
SET_WHO(9, 15090, "54I_BON");
}
} else if (_currentLevel == 6) {
SET_WHO(9, 16090, "61_LEN");
SET_WHO(19, 16190, "61_DUC");
SET_WHO(14, 16140, "61_BON");
if (_gameVariables[GameVariables::kMaineTalked] == 1) {
SET_WHO(19, 16190, "62_DUC");
}
}
#undef SET_WHO
}
void CryOmni3DEngine_Versailles::initDocPeopleRecord() {
_docPeopleRecord.clear();
#define SET_INFO(actionId, record) _docPeopleRecord[actionId] = record
SET_INFO(22501, "VC25");
SET_INFO(22401, "VC19");
SET_INFO(22402, "VC24");
SET_INFO(22403, "VC24");
SET_INFO(22404, "VC24");
SET_INFO(22405, "VC24");
SET_INFO(22406, "VC24");
SET_INFO(22407, "VC24");
SET_INFO(22408, "VC24");
SET_INFO(21201, "VC25");
SET_INFO(21202, "VS12");
SET_INFO(21203, "VA13");
SET_INFO(21011, "VC13");
SET_INFO(21012, "VC11");
SET_INFO(21013, "VC10");
SET_INFO(21014, "VC18");
SET_INFO(22901, "VC25");
SET_INFO(21015, "VC25");
SET_INFO(22101, "VC18");
SET_INFO(22903, "VC12");
SET_INFO(22902, "VC10");
SET_INFO(22131, "VC16");
SET_INFO(22111, "VC18");
SET_INFO(21301, "VA12");
SET_INFO(22121, "VA12");
SET_INFO(22103, "VC20");
SET_INFO(22102, "VC15");
SET_INFO(23100, "VC23");
SET_INFO(23101, "VC23");
SET_INFO(23130, "VC23");
SET_INFO(23060, "VC23");
SET_INFO(23150, "VC23");
SET_INFO(23220, "VA11");
SET_INFO(23131, "VC11");
SET_INFO(23241, "VA13");
SET_INFO(23151, "VR12");
SET_INFO(23030, "VC18");
SET_INFO(23040, "VR11");
SET_INFO(23041, "VR13");
SET_INFO(23240, "VC15");
SET_INFO(24104, "VC25");
SET_INFO(24105, "VC18");
SET_INFO(24106, "VC12");
SET_INFO(24107, "VC19");
SET_INFO(24102, "VC21");
SET_INFO(24103, "VC21");
SET_INFO(24081, "VC21");
SET_INFO(24101, "VC24");
SET_INFO(24092, "VC14");
SET_INFO(24091, "VR13");
SET_INFO(24161, "VR12");
SET_INFO(25270, "VC26");
SET_INFO(25261, "VC26");
//SET_INFO(25260, nullptr); // Don't put empty records
SET_INFO(25130, "VA12");
SET_INFO(25131, "VS12");
SET_INFO(25060, "VC23");
SET_INFO(25061, "VC22");
SET_INFO(25160, "VC23");
SET_INFO(25140, "VR11");
SET_INFO(25141, "VC16");
SET_INFO(25142, "VC20");
SET_INFO(25143, "VC15");
SET_INFO(25145, "VC17");
SET_INFO(25090, "VC18");
SET_INFO(26190, "VC13");
SET_INFO(24161, "VR12");
SET_INFO(26090, "VS13");
SET_INFO(26140, "VC18");
SET_INFO(27111, "VC21");
#undef SET_INFO
}
} // End of namespace Versailles
} // End of namespace CryOmni3D

View File

@@ -0,0 +1,322 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "cryomni3d/versailles/engine.h"
namespace CryOmni3D {
namespace Versailles {
bool CryOmni3DEngine_Versailles::preprocessDialog(const Common::String &sequence) {
if (_inventory.inInventoryByNameID(96) && _inventory.inInventoryByNameID(98)) {
_dialogsMan["{JOUEUR-TROUVE-TITRE-ET-PAMPHLET}"] = 'Y';
}
if (_inventory.inInventoryByNameID(126)) {
_dialogsMan["{JOUEUR_POSSEDE_EPIGRAPHE}"] = 'Y';
}
if (_currentLevel == 1 && _currentPlaceId == 3) {
playInGameAnimVideo("11D_LEB1");
}
_dialogsMan["{JOUEUR-VU-MEMORANDUM-DANS-LUSTRE-DU-SALON-DE-LA-GUERRE}"] = 'N';
if (_currentLevel == 5 && _gameVariables[GameVariables::kSeenMemorandum] &&
!_inventory.inInventoryByNameID(140)) {
_dialogsMan["{JOUEUR-VU-MEMORANDUM-DANS-LUSTRE-DU-SALON-DE-LA-GUERRE}"] = 'Y';
}
if (_currentLevel == 1 && _currentPlaceId == 1 && currentGameTime() == 3 &&
sequence.hasPrefix("13F_HUI") && _gameVariables[GameVariables::kWarnedIncomplete] == 0 &&
_dialogsMan["{JOUEUR-TROUVE-TITRE-ET-PAMPHLET}"] == 'Y' &&
(!_inventory.inInventoryByNameID(96) || !_inventory.inInventoryByNameID(98))) {
displayMessageBoxWarp(18);
_gameVariables[GameVariables::kWarnedIncomplete] = 1;
return 0;
}
if (_currentLevel == 2 && _currentPlaceId == 11 && currentGameTime() == 4 &&
sequence.hasPrefix("24Z_BON") && _gameVariables[GameVariables::kWarnedIncomplete] == 0 &&
_dialogsMan["{JOUEUR-MONTRE-TITRE-FABLE-APPARU-SUR-ESQUISSE}"] == 'Y' &&
(!_inventory.inInventoryByNameID(101) || !_inventory.inInventoryByNameID(103))) {
displayMessageBoxWarp(18);
_gameVariables[GameVariables::kWarnedIncomplete] = 1;
return 0;
}
if (_currentLevel == 3 && _currentPlaceId == 10 && currentGameTime() == 3 &&
sequence.hasPrefix("31O_SUIA") && _gameVariables[GameVariables::kWarnedIncomplete] == 0 &&
_dialogsMan["CROISSY-ACCEPTE-TEXTE"] == 'Y' &&
(!_inventory.inInventoryByNameID(121) || !_inventory.inInventoryByNameID(119) ||
!_inventory.inInventoryByNameID(115) ||
_gameVariables[GameVariables::kGotMedalsSolution] == 0)) {
displayMessageBoxWarp(18);
_gameVariables[GameVariables::kWarnedIncomplete] = 1;
return 0;
}
if (_currentLevel == 4 && _currentPlaceId == 10 && currentGameTime() == 3 &&
sequence.hasPrefix("42C_BON") && _gameVariables[GameVariables::kWarnedIncomplete] == 0 &&
_dialogsMan["{JOUEUR-MONTRE-PAMPHLET-RELIGION}"] == 'Y' &&
(!_inventory.inInventoryByNameID(127) ||
_gameVariables[GameVariables::kUsedVaubanBlueprint1] == 0 ||
_gameVariables[GameVariables::kUsedVaubanBlueprint2] == 0)) {
displayMessageBoxWarp(18);
_gameVariables[GameVariables::kWarnedIncomplete] = 1;
return 0;
}
if (_currentLevel == 5 && _currentPlaceId == 10 && currentGameTime() == 3 &&
sequence.hasPrefix("42C_BON") && _gameVariables[GameVariables::kWarnedIncomplete] == 0 &&
_dialogsMan["{JOUEUR-MONTRE-PAMPHLET-RELIGION}"] == 'Y' &&
(!_inventory.inInventoryByNameID(127) ||
_gameVariables[GameVariables::kUsedVaubanBlueprint1] == 0 ||
_gameVariables[GameVariables::kUsedVaubanBlueprint2] == 0)) {
displayMessageBoxWarp(18);
_gameVariables[GameVariables::kWarnedIncomplete] = 1;
return 0;
}
if (_currentLevel == 6 && _currentPlaceId == 14 && currentGameTime() == 2 &&
sequence.hasPrefix("61_BON") && _gameVariables[GameVariables::kWarnedIncomplete] == 0) {
displayMessageBoxWarp(19);
_gameVariables[GameVariables::kWarnedIncomplete] = 1;
return 0;
}
return 1;
}
void CryOmni3DEngine_Versailles::postprocessDialog(const Common::String &sequence) {
if (_currentLevel == 1) {
if (_dialogsMan["{LEVEL1_FINI}"] == 'Y') {
playTransitionEndLevel(1);
}
} else if (_currentLevel == 2) {
_dialogsMan["{JOUEUR-PRESENTE-FAUX-CROQUIS}"] = 'N';
_dialogsMan["{JOUEUR-PRESENTE-FAUX-CROQUIS2}"] = 'N';
_dialogsMan["{JOUEUR-PRESENTE-FAUX-CROQUIS3}"] = 'N';
_dialogsMan["{LE JOUEUR-PRESENTE-AUTRES-ESQUISSES-OU-ESQUISSE-NON-TRIEES}"] = 'N';
_dialogsMan["{LE JOUEUR-PRESENTE-ESQUISSES-TRIEES}"] = 'N';
_dialogsMan["{JOUEUR-MONTRE-TITRE-FABLE-APPARU-SUR-ESQUISSE}"] = 'N';
_dialogsMan["{JOUEUR-MONTRE-ESQUISSE-DETRUITE}"] = 'N';
if (_dialogsMan["{LEVEL2_FINI}"] == 'Y') {
playTransitionEndLevel(2);
}
} else if (_currentLevel == 3) {
if (currentGameTime() == 1 && _dialogsMan["LULLY-DONNE-MISSION1-JOUEUR"] == 'Y') {
setGameTime(2, 3);
}
if (!_gameVariables[GameVariables::kGotMedalsSolution] &&
_dialogsMan["MONSIEUR-DONNE-SOLUTION-MEDAILLES"] == 'Y') {
playInGameAnimVideo("32M_MR2");
_gameVariables[GameVariables::kGotMedalsSolution] = 1;
}
if (!_gameVariables[GameVariables::kDecipherScore] &&
_dialogsMan["LULLY-DIT-CHAT-PENDU-JOUEUR"] == 'Y') {
_gameVariables[GameVariables::kDecipherScore] = 1;
collectObject(118);
setGameTime(3, 3);
}
if (currentGameTime() == 3 && _dialogsMan["CROISSY-ACCEPTE-TEXTE"] == 'Y') {
setGameTime(4, 3);
}
if (_dialogsMan["{LEVEL3_FINI}"] == 'Y') {
playTransitionEndLevel(3);
}
if (sequence == "32M_MR" && _dialogsMan["MONSIEUR-DONNE-SOLUTION-MEDAILLES"] == 'Y') {
_dialogsMan["{JOUEUR-MONTRE-MEDAILLES-MONSIEUR}"] = 'Y';
}
_dialogsMan["{JOUEUR-MONTRE-PAMPHLET-ARCHITECTURE}"] = 'N';
_dialogsMan["{JOUEUR-MONTRE-EPIGRAPHE-MEDAILLES}"] = 'N';
_dialogsMan["{JOUEUR-MONTRE-TOUT-AUTRE-CHOSE}"] = 'N';
} else if (_currentLevel == 4) {
if (_dialogsMan["{LEVEL4_FINI}"] == 'Y') {
playTransitionEndLevel(4);
}
} else if (_currentLevel == 5) {
if (sequence == "54I_BON" && _dialogsMan["BONTEMPS-DIT-PROMENADE"] == 'Y') {
collectObject(141);
playTransitionEndLevel(5);
}
if (sequence == "52A4_LAC" && _gameVariables[GameVariables::kStateLampoonReligion] != 3 &&
_dialogsMan["LACHAIZE-DIT-REFORME"] == 'Y' && _dialogsMan["LACHAIZE-DIT-DRAGONNADES"] == 'Y' &&
_dialogsMan["LACHAIZE-TROUVE-ECROUELLES"] == 'Y') {
_inventory.removeByNameID(125);
_gameVariables[GameVariables::kStateLampoonReligion] = 3;
collectObject(125);
_inventory.deselectObject();
}
}
}
void CryOmni3DEngine_Versailles::updateGameTimeDialVariables() {
_dialogsMan["{CURRENT_GAME_TIME1}"] = 'N';
_dialogsMan["{CURRENT_GAME_TIME2}"] = 'N';
_dialogsMan["{CURRENT_GAME_TIME3}"] = 'N';
_dialogsMan["{CURRENT_GAME_TIME4}"] = 'N';
_dialogsMan["{CURRENT_GAME_TIME5}"] = 'N';
switch (currentGameTime()) {
case 1:
_dialogsMan["{CURRENT_GAME_TIME1}"] = 'Y';
break;
case 2:
_dialogsMan["{CURRENT_GAME_TIME2}"] = 'Y';
break;
case 3:
_dialogsMan["{CURRENT_GAME_TIME3}"] = 'Y';
break;
case 4:
_dialogsMan["{CURRENT_GAME_TIME4}"] = 'Y';
break;
case 5:
_dialogsMan["{CURRENT_GAME_TIME5}"] = 'Y';
break;
default:
error("Invalid current game time %d", currentGameTime());
}
}
void CryOmni3DEngine_Versailles::setupDialogShows() {
_dialogsMan.registerShowCallback("(BONTEMPS-MONTRE-TROISIEME-TITRE-DE-FABLE)",
&CryOmni3DEngine_Versailles::dialogShowBontempsShowThird);
_dialogsMan.registerShowCallback("(HUISSIER DONNE PAMPHLET SUR LA FAMILLE ROYALE)",
&CryOmni3DEngine_Versailles::dialogShowHuissierShowPamphlet);
_dialogsMan.registerShowCallback("(MONSEIGNEUR TRIE LES ESQUISSES)",
&CryOmni3DEngine_Versailles::dialogShowMonseigneurSorts);
_dialogsMan.registerShowCallback("(ANIMATION LE BRUN REGARDE LES ESQUISSES)",
&CryOmni3DEngine_Versailles::dialogShowLeBrunWatches);
_dialogsMan.registerShowCallback("(OUVERTURE DES PORTES)",
&CryOmni3DEngine_Versailles::dialogShowDoorsOpen);
_dialogsMan.registerShowCallback("(GARDE SUISSE DONNE CLEF PETITE PORTE)",
&CryOmni3DEngine_Versailles::dialogShowSwissGuardGives);
_dialogsMan.registerShowCallback("(LULLY CORRIGE LA PARTITION.)",
&CryOmni3DEngine_Versailles::dialogShowLullyCorrects);
_dialogsMan.registerShowCallback("(BONTEMPS DONNE AUTORISATION)",
&CryOmni3DEngine_Versailles::dialogShowBontempsGivesAuth);
_dialogsMan.registerShowCallback("(CROISSY PART)",
&CryOmni3DEngine_Versailles::dialogShowCroissyLeave);
_dialogsMan.registerShowCallback("(MAINTENON-DONNE-PAMPHLET-RELIGION)",
&CryOmni3DEngine_Versailles::dialogShowMaintenonGives);
_dialogsMan.registerShowCallback("(LA CHAIZE REND TEXTE)",
&CryOmni3DEngine_Versailles::dialogShowLaChaizeGivesBack);
_dialogsMan.registerShowCallback("(LA CHAIZE " "\x83" "CRIT DRAGONNADES)",
&CryOmni3DEngine_Versailles::dialogShowLaChaizeWrites);
_dialogsMan.registerShowCallback("(LA CHAIZE " "\x8e" "CRIT DRAGONNADES)",
&CryOmni3DEngine_Versailles::dialogShowLaChaizeWrites);
_dialogsMan.registerShowCallback("(LACHAIZE-DONNE-PAMPHLET-JOUEUR)",
&CryOmni3DEngine_Versailles::dialogShowLaChaizeGivesPamphlet);
_dialogsMan.registerShowCallback("(BONTEMPS-DONNE-CLEF-DES-COMBLES)",
&CryOmni3DEngine_Versailles::dialogShowBontempsGivesKey);
_dialogsMan.registerShowCallback("(LE DUC DU MAINE S'EN VA)",
&CryOmni3DEngine_Versailles::dialogShowDuMaineLeaves);
_dialogsMan.registerShowCallback("(SC" "\xe9" "NE DE TRANSITION)",
&CryOmni3DEngine_Versailles::dialogShowTransitionScene);
_dialogsMan.registerShowCallback("(FIN DU JEU)", &CryOmni3DEngine_Versailles::dialogShowEndOfGame);
_dialogsMan.registerShowCallback("(LEBRUN-DONNE-FAUSSES-ESQUISSES)",
&CryOmni3DEngine_Versailles::dialogShowLeBrunGives);
_dialogsMan.registerShowCallback("(LEBRUN_S_EN_VA)",
&CryOmni3DEngine_Versailles::dialogShowLeBrunLeave);
}
void CryOmni3DEngine_Versailles::dialogShowBontempsShowThird() {
// Nothing to do
}
void CryOmni3DEngine_Versailles::dialogShowHuissierShowPamphlet() {
collectObject(101);
_inventory.deselectObject();
}
void CryOmni3DEngine_Versailles::dialogShowMonseigneurSorts() {
_inventory.removeByNameID(105);
collectObject(106);
_gameVariables[GameVariables::kSketchState] = 2; // Sketches sorted
_inventory.deselectObject();
setGameTime(3, 2);
_dialogsMan["MONSEIGNEUR-ATTEND-ESQUISSES"] = 'N';
}
void CryOmni3DEngine_Versailles::dialogShowLeBrunWatches() {
// Nothing to do
}
void CryOmni3DEngine_Versailles::dialogShowDoorsOpen() {
// Nothing to do
}
void CryOmni3DEngine_Versailles::dialogShowSwissGuardGives() {
collectObject(123);
_dialogsMan["{JOUEUR-POSSEDE-CLE}"] = 'Y';
}
void CryOmni3DEngine_Versailles::dialogShowLullyCorrects() {
// Nothing to do
}
void CryOmni3DEngine_Versailles::dialogShowBontempsGivesAuth() {
collectObject(120);
}
void CryOmni3DEngine_Versailles::dialogShowCroissyLeave() {
// Nothing to do
}
void CryOmni3DEngine_Versailles::dialogShowMaintenonGives() {
collectObject(125);
_inventory.deselectObject();
}
void CryOmni3DEngine_Versailles::dialogShowLaChaizeGivesBack() {
// Nothing to do
}
void CryOmni3DEngine_Versailles::dialogShowLaChaizeWrites() {
// Nothing to do
}
void CryOmni3DEngine_Versailles::dialogShowLaChaizeGivesPamphlet() {
// Nothing to do
}
void CryOmni3DEngine_Versailles::dialogShowBontempsGivesKey() {
collectObject(140);
_inventory.deselectObject();
}
void CryOmni3DEngine_Versailles::dialogShowDuMaineLeaves() {
playInGameAnimVideo("62S_DUC1");
_inventory.removeByNameID(144);
setPlaceState(19, 1);
}
void CryOmni3DEngine_Versailles::dialogShowTransitionScene() {
playTransitionEndLevel(6);
}
void CryOmni3DEngine_Versailles::dialogShowEndOfGame() {
doGameOver();
}
void CryOmni3DEngine_Versailles::dialogShowLeBrunGives() {
collectObject(107);
_inventory.deselectObject();
}
void CryOmni3DEngine_Versailles::dialogShowLeBrunLeave() {
playInGameAnimVideo("11D_LEB3");
setGameTime(2, 1);
}
} // End of namespace Versailles
} // End of namespace CryOmni3D

View File

@@ -0,0 +1,376 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "audio/decoders/wave.h"
#include "common/file.h"
#include "common/system.h"
#include "video/hnm_decoder.h"
#include "cryomni3d/versailles/dialogs_manager.h"
#include "cryomni3d/versailles/engine.h"
namespace CryOmni3D {
namespace Versailles {
Versailles_DialogsManager::Versailles_DialogsManager(CryOmni3DEngine_Versailles *engine,
bool padAudioFileName) :
_engine(engine), _padAudioFileName(padAudioFileName) {
}
bool Versailles_DialogsManager::play(const Common::String &sequence) {
// Prepare with specific Versailles stuff
if (!_engine->preprocessDialog(sequence)) {
return false;
}
_engine->musicSetQuiet(true);
_engine->setCursor(181);
// No need to adjust hide cursor counter, there isn't any in ScummVM
bool cursorWasVisible = _engine->showMouse(true);
bool slowStop = false;
bool didSth = DialogsManager::play(sequence, slowStop);
_engine->showMouse(cursorWasVisible);
if (didSth && slowStop) {
if (_engine->showSubtitles()) {
bool skip = false;
uint end = g_system->getMillis() + 2000;
while (!_engine->shouldAbort() && g_system->getMillis() < end && !skip) {
g_system->updateScreen();
g_system->delayMillis(10);
if (_engine->pollEvents() &&
(_engine->checkKeysPressed(1, Common::KEYCODE_SPACE) ||
_engine->getCurrentMouseButton() == 1)) {
skip = true;
}
}
}
}
_engine->postprocessDialog(sequence);
_engine->musicSetQuiet(false);
_lastImage.free();
_engine->waitMouseRelease();
return didSth;
}
void Versailles_DialogsManager::executeShow(const Common::String &show) {
Common::HashMap<Common::String, ShowCallback>::iterator showIt = _shows.find(show);
if (showIt == _shows.end()) {
error("Missing show %s", show.c_str());
}
_lastImage.free();
ShowCallback cb = showIt->_value;
(_engine->*cb)();
}
void Versailles_DialogsManager::playDialog(const Common::String &video, const Common::String &sound,
const Common::String &text, const SubtitlesSettings &settings) {
Common::String soundFName(sound);
if (_padAudioFileName) {
while (soundFName.size() < 8) {
soundFName += '_';
}
}
Common::Path videoPath(_engine->getFilePath(kFileTypeDialAnim, video));
Common::Path soundPath(_engine->getFilePath(kFileTypeDialSound, soundFName));
Video::HNMDecoder *videoDecoder = new Video::HNMDecoder(g_system->getScreenFormat(), true);
if (!videoDecoder->loadFile(videoPath)) {
warning("Failed to open movie file %s/%s", video.c_str(), videoPath.toString(Common::Path::kNativeSeparator).c_str());
delete videoDecoder;
return;
}
Common::File *audioFile = new Common::File();
if (!audioFile->open(soundPath)) {
warning("Failed to open sound file %s/%s", sound.c_str(), soundPath.toString(Common::Path::kNativeSeparator).c_str());
delete videoDecoder;
delete audioFile;
return;
}
Audio::SeekableAudioStream *audioDecoder = Audio::makeWAVStream(audioFile, DisposeAfterUse::YES);
// We lost ownership of the audioFile just set it to nullptr and don't use it
audioFile = nullptr;
if (!audioDecoder) {
delete videoDecoder;
return;
}
_engine->showMouse(false);
uint16 width = videoDecoder->getWidth();
uint16 height = videoDecoder->getHeight();
// Preload first frame to draw subtitles from it
const Graphics::Surface *firstFrame = videoDecoder->decodeNextFrame();
assert(firstFrame != nullptr);
if (videoDecoder->hasDirtyPalette()) {
const byte *palette = videoDecoder->getPalette();
_engine->setupPalette(palette, 0, 256);
}
FontManager &fontManager = _engine->_fontManager;
_lastImage.create(firstFrame->w, firstFrame->h, firstFrame->format);
_lastImage.blitFrom(*firstFrame);
fontManager.setCurrentFont(7);
fontManager.setTransparentBackground(true);
fontManager.setForeColor(241);
fontManager.setLineHeight(22);
fontManager.setSpaceWidth(2);
fontManager.setCharSpacing(1);
if (_engine->showSubtitles()) {
Common::Rect block = settings.textRect;
uint lines = fontManager.getLinesCount(text, block.width() - 8);
if (lines == 0) {
lines = 5;
}
uint blockHeight = fontManager.lineHeight() * lines + 6;
block.setHeight(blockHeight);
if (block.bottom >= 480) {
block.bottom = 470;
warning("Dialog text is really too long");
}
// Make only the block area translucent inplace
Graphics::Surface blockSurface = _lastImage.getSubArea(block);
_engine->makeTranslucent(blockSurface, blockSurface);
fontManager.setSurface(&_lastImage);
block.grow(-4);
fontManager.setupBlock(block);
fontManager.displayBlockText(text);
}
g_system->copyRectToScreen(_lastImage.getPixels(), _lastImage.pitch, 0, 0, width, height);
g_system->updateScreen();
const Common::Rect &drawRect = settings.drawRect;
if (audioDecoder->getLength() == 0) {
// Empty wave file
delete audioDecoder;
uint duration = 100 * text.size();
if (duration < 1000) {
duration = 1000;
}
bool skipWait = false;
uint end = g_system->getMillis() + duration;
while (!_engine->shouldAbort() && g_system->getMillis() < end && !skipWait) {
g_system->updateScreen();
g_system->delayMillis(10);
if (_engine->pollEvents() && _engine->checkKeysPressed(1, Common::KEYCODE_SPACE)) {
skipWait = true;
}
}
} else {
// Let start the show!
videoDecoder->start();
Audio::SoundHandle audioHandle;
_engine->_mixer->playStream(Audio::Mixer::kSpeechSoundType, &audioHandle, audioDecoder);
// We lost ownership of the audioDecoder just set it to nullptr and don't use it
audioDecoder = nullptr;
bool skipVideo = false;
while (!_engine->shouldAbort() && _engine->_mixer->isSoundHandleActive(audioHandle) && !skipVideo) {
if (_engine->pollEvents() && _engine->checkKeysPressed(1, Common::KEYCODE_SPACE)) {
skipVideo = true;
}
if (videoDecoder->needsUpdate()) {
const Graphics::Surface *frame = videoDecoder->decodeNextFrame();
if (frame) {
if (videoDecoder->hasDirtyPalette()) {
const byte *palette = videoDecoder->getPalette();
_engine->setupPalette(palette, 0, 256);
}
// Only refresh the moving part of the animation
const Graphics::Surface subFrame = frame->getSubArea(drawRect);
g_system->copyRectToScreen(subFrame.getPixels(), subFrame.pitch, drawRect.left, drawRect.top,
subFrame.w, subFrame.h);
}
}
g_system->updateScreen();
g_system->delayMillis(10);
}
_engine->_mixer->stopHandle(audioHandle);
}
// It's intentional that _lastImage is set with the first video image
delete videoDecoder;
_engine->showMouse(true);
}
void Versailles_DialogsManager::displayMessage(const Common::String &text) {
_engine->displayMessageBoxWarp(text);
}
uint Versailles_DialogsManager::askPlayerQuestions(const Common::String &video,
const Common::StringArray &questions) {
if (_lastImage.empty()) {
loadFrame(video);
}
if (questions.size() == 0 || questions.size() > 5) {
return uint(-1);
}
FontManager &fontManager = _engine->_fontManager;
fontManager.setCurrentFont(7);
fontManager.setTransparentBackground(true);
fontManager.setLineHeight(18);
fontManager.setSpaceWidth(2);
fontManager.setSurface(&_lastImage);
int16 tops[5];
int16 bottoms[5];
int16 currentHeight = 0;
uint questionId = 0;
for (Common::StringArray::const_iterator it = questions.begin(); it != questions.end();
it++, questionId++) {
tops[questionId] = currentHeight;
uint lines = fontManager.getLinesCount(*it, 598);
if (lines == 0) {
lines = 1;
}
currentHeight += 18 * lines;
bottoms[questionId] = currentHeight;
}
int offsetY = 480 - (bottoms[questions.size() - 1] - tops[0]);
if (offsetY > 402) {
offsetY = 402;
} else if (offsetY < 2) {
offsetY = 2;
}
for (questionId = 0; questionId < questions.size(); questionId++) {
tops[questionId] += offsetY;
bottoms[questionId] += offsetY;
}
_engine->setCursor(181);
Graphics::Surface alphaSurface = _lastImage.getSubArea(Common::Rect(0, offsetY - 2, 640, 480));
_engine->makeTranslucent(alphaSurface, alphaSurface);
bool finished = false;
bool update = true;
uint selectedQuestion = uint(-1);
while (!finished) {
if (update) {
update = false;
questionId = 0;
for (Common::StringArray::const_iterator it = questions.begin(); it != questions.end();
it++, questionId++) {
fontManager.setForeColor(selectedQuestion == questionId ? 241 : 245);
fontManager.setupBlock(Common::Rect(10, tops[questionId], 608, bottoms[questionId]));
fontManager.displayBlockText(*it);
}
g_system->copyRectToScreen(_lastImage.getPixels(), _lastImage.pitch, 0, 0, _lastImage.w,
_lastImage.h);
}
g_system->updateScreen();
g_system->delayMillis(10);
if (_engine->pollEvents()) {
_engine->clearKeys();
if (_engine->shouldAbort()) {
finished = true;
selectedQuestion = uint(-1);
break;
}
Common::Point mousePos = _engine->getMousePos();
if (_engine->getDragStatus() == kDragStatus_Finished && selectedQuestion != uint(-1)) {
finished = true;
} else if (mousePos.x >= 608 || mousePos.y < offsetY) {
if (selectedQuestion != uint(-1)) {
selectedQuestion = uint(-1);
update = true;
}
} else {
for (questionId = 0; questionId < questions.size(); questionId++) {
if (mousePos.y > tops[questionId] && mousePos.y < bottoms[questionId]) {
break;
}
}
if (questionId < questions.size()) {
if (selectedQuestion != questionId) {
selectedQuestion = questionId;
update = true;
}
} else {
selectedQuestion = uint(-1);
update = true;
}
}
}
}
return selectedQuestion;
}
void Versailles_DialogsManager::loadFrame(const Common::String &video) {
Common::Path videoPath(_engine->getFilePath(kFileTypeDialAnim, video));
Video::HNMDecoder videoDecoder(g_system->getScreenFormat());
if (!videoDecoder.loadFile(videoPath)) {
warning("Failed to open movie file %s/%s", video.c_str(), videoPath.toString(Common::Path::kNativeSeparator).c_str());
return;
}
// Preload first frame to draw questions on it
const Graphics::Surface *firstFrame = videoDecoder.decodeNextFrame();
_lastImage.create(firstFrame->w, firstFrame->h, firstFrame->format);
_lastImage.blitFrom(*firstFrame);
if (videoDecoder.hasDirtyPalette()) {
const byte *palette = videoDecoder.getPalette();
_engine->setupPalette(palette, 0, 256);
}
}
} // End of namespace Versailles
} // End of namespace CryOmni3D

View File

@@ -0,0 +1,68 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef CRYOMNI3D_VERSAILLES_DIALOGS_MANAGER_H
#define CRYOMNI3D_VERSAILLES_DIALOGS_MANAGER_H
#include "common/hashmap.h"
#include "common/hash-str.h"
#include "graphics/managed_surface.h"
#include "cryomni3d/dialogs_manager.h"
#include "cryomni3d/font_manager.h"
namespace CryOmni3D {
namespace Versailles {
class CryOmni3DEngine_Versailles;
typedef void (CryOmni3DEngine_Versailles::*ShowCallback)();
class Versailles_DialogsManager : public DialogsManager {
public:
Versailles_DialogsManager(CryOmni3DEngine_Versailles *engine, bool padAudioFileName);
// This overload will hide the base one and this is what we want
bool play(const Common::String &sequence);
void registerShowCallback(const Common::String &showName, ShowCallback callback) { _shows[showName] = callback; }
protected:
void executeShow(const Common::String &show) override;
void playDialog(const Common::String &video, const Common::String &sound,
const Common::String &text, const SubtitlesSettings &settings) override;
void displayMessage(const Common::String &text) override;
uint askPlayerQuestions(const Common::String &video,
const Common::StringArray &questions) override;
private:
CryOmni3DEngine_Versailles *_engine;
Common::HashMap<Common::String, ShowCallback> _shows;
bool _padAudioFileName;
void loadFrame(const Common::String &video);
Graphics::ManagedSurface _lastImage;
};
} // End of namespace Versailles
} // End of namespace CryOmni3D
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,146 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef CRYOMNI3D_VERSAILLES_DOCUMENTATION_H
#define CRYOMNI3D_VERSAILLES_DOCUMENTATION_H
#include "common/hashmap.h"
#include "common/hash-str.h"
#include "common/rect.h"
#include "common/str-array.h"
#include "graphics/managed_surface.h"
namespace CryOmni3D {
class FontManager;
class MouseBoxes;
class Sprites;
namespace Versailles {
class CryOmni3DEngine_Versailles;
class Versailles_Documentation {
public:
Versailles_Documentation() : _engine(nullptr), _fontManager(nullptr), _sprites(nullptr),
_messages(nullptr), _multilineAttributes(false), _linksData(nullptr), _linksSize(0),
_currentInTimeline(false), _currentMapLayout(false), _currentHasMap(false) { }
~Versailles_Documentation() { delete [] _linksData; }
void init(const Sprites *sprites, FontManager *fontManager, const Common::StringArray *messages,
CryOmni3DEngine_Versailles *engine, const Common::Path &allDocsFilePath,
const Common::Path &linksDocsFilePath);
void handleDocArea();
void handleDocInGame(const Common::String &record);
private:
Common::String docAreaHandleSummary();
Common::String docAreaHandleTimeline();
Common::String docAreaHandleGeneralMap();
Common::String docAreaHandleCastleMap();
uint docAreaHandleRecords(const Common::String &record);
void docAreaPrepareNavigation();
void docAreaPrepareRecord(Graphics::ManagedSurface &surface, MouseBoxes &boxes);
uint docAreaHandleRecord(Graphics::ManagedSurface &surface, MouseBoxes &boxes,
Common::String &nextRecord);
void inGamePrepareRecord(Graphics::ManagedSurface &surface, MouseBoxes &boxes);
uint inGameHandleRecord(Graphics::ManagedSurface &surface, MouseBoxes &boxes,
Common::String &nextRecord);
void setupRecordBoxes(bool inDocArea, MouseBoxes &boxes);
void setupTimelineBoxes(MouseBoxes &boxes);
void drawRecordData(Graphics::ManagedSurface &surface,
const Common::String &text, const Common::String &title,
const Common::String &subtitle, const Common::String &caption);
void drawRecordBoxes(Graphics::ManagedSurface &surface, bool inDocArea, MouseBoxes &boxes);
uint handlePopupMenu(const Graphics::ManagedSurface &surface,
const Common::Point &anchor, bool rightAligned, uint itemHeight,
const Common::StringArray &items);
struct RecordInfo {
uint id;
uint position;
uint size;
};
struct LinkInfo {
Common::String record;
Common::String title;
};
struct TimelineEntry {
char year[8];
uint x;
uint y;
};
static const TimelineEntry kTimelineEntries[];
char *getDocPartAddress(char *start, char *end, const char *patterns[]);
const char *getDocTextAddress(char *start, char *end);
const char *getRecordTitle(char *start, char *end);
const char *getRecordSubtitle(char *start, char *end);
const char *getRecordCaption(char *start, char *end);
void getRecordHyperlinks(char *start, char *end, Common::StringArray &hyperlinks);
Common::String getRecordTitle(const Common::String &record);
Common::String getRecordData(const Common::String &record, Common::String &title,
Common::String &subtitle, Common::String &caption,
Common::StringArray &hyperlinks);
void convertHyperlinks(const Common::StringArray &hyperlinks, Common::Array<LinkInfo> &links);
void loadLinksFile();
void getLinks(const Common::String &record, Common::Array<LinkInfo> &links);
Common::Path _allDocsFilePath;
Common::Path _linksDocsFilePath;
static const uint kPopupMenuMargin = 5;
CryOmni3DEngine_Versailles *_engine;
FontManager *_fontManager;
const Sprites *_sprites;
const Common::StringArray *_messages;
bool _multilineAttributes;
Common::StringArray _recordsOrdered;
Common::HashMap<Common::String, RecordInfo> _records;
char *_linksData;
uint _linksSize;
Common::Array<LinkInfo> _allLinks;
Common::StringArray _visitTrace;
Common::String _currentRecord;
Common::String _categoryStartRecord;
Common::String _categoryEndRecord;
Common::String _categoryTitle;
Common::Array<LinkInfo> _currentLinks;
bool _currentInTimeline;
bool _currentMapLayout;
bool _currentHasMap;
};
} // End of namespace Versailles
} // End of namespace CryOmni3D
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,687 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef CRYOMNI3D_VERSAILLES_ENGINE_H
#define CRYOMNI3D_VERSAILLES_ENGINE_H
#include "common/events.h"
#include "common/random.h"
#include "common/array.h"
#include "common/hashmap.h"
#include "common/hash-str.h"
#include "common/str.h"
#include "cryomni3d/cryomni3d.h"
#include "cryomni3d/omni3d.h"
#include "cryomni3d/sprites.h"
#include "cryomni3d/wam_parser.h"
#include "cryomni3d/versailles/documentation.h"
#include "cryomni3d/versailles/toolbar.h"
#include "cryomni3d/versailles/dialogs_manager.h"
namespace Graphics {
class ManagedSurface;
struct Surface;
}
namespace CryOmni3D {
struct FixedImageConfiguration;
class ZonFixedImage;
}
namespace CryOmni3D {
namespace Versailles {
struct PlaceStateActionKey {
uint placeId;
uint placeState;
uint actionId;
PlaceStateActionKey(uint placeId_, uint placeState_, uint actionId_) :
placeId(placeId_), placeState(placeState_), actionId(actionId_) {}
bool operator==(const PlaceStateActionKey &other) const {
return other.placeId == placeId && other.placeState == placeState && other.actionId == actionId;
}
};
struct PlaceActionKey {
uint placeId;
uint actionId;
PlaceActionKey(uint placeId_, uint actionId_) :
placeId(placeId_), actionId(actionId_) {}
bool operator==(const PlaceActionKey &other) const {
return other.placeId == placeId && other.actionId == actionId;
}
};
}
}
namespace Common {
template<>
struct Hash<CryOmni3D::Versailles::PlaceStateActionKey> {
uint operator()(const CryOmni3D::Versailles::PlaceStateActionKey &k) const {
// placeState shouldn't be greater than 8 and placeId shouldn't be greater than 100
// originalActionId shouldn't be greater than 65536
return (k.placeId << 24 | k.placeState << 16) ^ k.actionId;
}
};
template<>
struct Hash<CryOmni3D::Versailles::PlaceActionKey> {
uint operator()(const CryOmni3D::Versailles::PlaceActionKey &k) const {
// placeId shouldn't be greater than 100
// originalActionId shouldn't be greater than 65536
return (k.placeId << 16) ^ k.actionId;
}
};
}
namespace CryOmni3D {
namespace Versailles {
class CryOmni3DEngine_Versailles;
enum AbortCommand {
kAbortNoAbort = 0,
kAbortQuit = 1,
kAbortLoadGame = 2,
kAbortNewGame = 3,
kAbortNextLevel = 5,
kAbortFinished = 6,
kAbortGameOver = 7
};
struct GameVariables {
enum Var {
kCollectScore = 0, // 0
kUnlockHiddenDoor,
kAlreadyWent3_19,
kMedalsDrawerStatus,
kCurrentTime,
kGotMedalsSolution,
kCabinetDrawerStatus,
kDecipherScore,
kCollectLampoonArchitecture,
kGotRevealedPaper,
kCollectKey, // 10
kCollectPortfolio,
kSketchState,
kFakeSketchChatState,
kCollectFood,
kCollectQuill,
kStateLampoonReligion,
kCollectSmallKey3,
kCollectEngraving,
kCollectCord,
kCollectVaubanBlueprint1, // 20
kCollectVaubanBlueprint2,
kLadderState,
kOpenedCurtain,
kLoweredChandelier,
kCombedOrangeTree,
kMaineTalked,
kUsedLitCandle,
kBombState,
kInkSpilled,
kCollectedPaperOnTable, // 30
kSafeUnlocked,
//kUselessVar,
kCollectedPaperInTrunk = 33,
kBrushColor,
kUsedScissors,
kUnlockedAttic,
kHasPlayedLebrun,
kWarnedIncomplete,
kUsedVaubanBlueprint1,
kUsedVaubanBlueprint2, // 40
kSeenMemorandum,
kCollectScissors,
kSavedCountdown,
kMax
};
};
// For random sounds we set a constant ID and avoid to use it elsewhere
struct SoundIds {
enum {
kOrgue = 0,
kLeb001,
kMax
};
};
struct LocalizedFilenames {
enum {
kDialogs = 0,
kAllDocs,
kLinksDocs,
kCredits,
kLeb001,
kMax
};
};
enum FileType {
kFileTypeAnimacti,
kFileTypeDocBg,
kFileTypeDialAnim,
kFileTypeDialSound,
kFileTypeFont,
kFileTypeGTO,
kFileTypeFixedImg,
kFileTypeMenu,
kFileTypeMusic,
kFileTypeObject,
kFileTypeSaveGameVisit,
kFileTypeTransScene,
kFileTypeTransSceneI,
kFileTypeSound,
kFileTypeSprite,
kFileTypeSpriteBmp,
kFileTypeText,
kFileTypeWAM,
kFileTypeWarpCyclo,
kFileTypeWarpHNM
};
struct PlaceState {
typedef void (CryOmni3DEngine_Versailles::*InitFunc)();
typedef bool (CryOmni3DEngine_Versailles::*FilterEventFunc)(uint *event);
PlaceState() : initPlace(nullptr), filterEvent(nullptr), docImage(nullptr), state(0) {}
PlaceState(InitFunc initPlace_, FilterEventFunc filterEvent_, const char *docImage_) :
initPlace(initPlace_), filterEvent(filterEvent_), docImage(docImage_), state(0) {}
InitFunc initPlace;
FilterEventFunc filterEvent;
const char *docImage;
uint state;
};
struct LevelInitialState {
uint placeId;
double alpha;
double beta;
};
struct FakeTransitionActionPlace {
uint actionId;
uint placeId;
};
typedef void (CryOmni3DEngine_Versailles::*FixedImgCallback)(ZonFixedImage *);
struct MsgBoxParameters {
int font;
byte foreColor;
uint lineHeight;
uint spaceWidth;
uint charSpacing;
uint initialWidth;
uint incrementWidth;
uint initialHeight;
uint incrementHeight;
uint timeoutChar;
};
struct SubtitleEntry {
uint32 frameStart;
Common::String text;
};
class CryOmni3DEngine_Versailles : public CryOmni3DEngine {
friend class Versailles_DialogsManager;
protected:
Common::Error run() override;
public:
CryOmni3DEngine_Versailles(OSystem *syst, const CryOmni3DGameDescription *gamedesc);
~CryOmni3DEngine_Versailles() override;
void initializePath(const Common::FSNode &gamePath) override;
bool hasFeature(EngineFeature f) const override;
Common::Error loadGameState(int slot) override;
Common::Error saveGameState(int slot, const Common::String &desc, bool isAutosave = false) override;
Common::String getSaveStateName(int slot) const override;
Common::Path getFilePath(FileType fileType, const Common::String &baseName) const;
void setupPalette(const byte *colors, uint start, uint num) override { setupPalette(colors, start, num, true); }
void makeTranslucent(Graphics::Surface &dst, const Graphics::Surface &src) const override;
bool displayToolbar(const Graphics::Surface *original) override { return _toolbar.displayToolbar(original); };
bool hasPlaceDocumentation() override;
bool displayPlaceDocumentation() override;
uint displayOptions() override;
bool shouldAbort() override;
private:
void setupFonts();
void setupSprites();
void loadCursorsPalette();
void calculateTransparentMapping();
void setupObjects();
void setupDialogVariables();
void setupImgScripts();
void loadStaticData();
void syncOmni3DSettings();
void syncSoundSettings() override;
void playTransitionEndLevel(int level);
void changeLevel(int level);
void initNewLevel(int level);
void setupLevelWarps(int level);
void initPlacesStates();
void initWhoSpeaksWhere();
void initDocPeopleRecord();
void setupLevelActionsMask();
uint currentGameTime() const { return _gameVariables[GameVariables::kCurrentTime]; }
void setGameTime(uint newTime, uint level);
void updateGameTimeDialVariables();
void gameStep();
void doGameOver();
void setPlaceState(uint placeId, uint newState);
void doPlaceChange();
void executeTransition(uint nextPlaceId);
void fakeTransition(uint dstPlaceId);
uint determineTransitionAnimation(uint srcId, uint dstId,
const Transition **transition);
uint getFakeTransition(uint actionId) const;
void fixActionId(uint *actionId) const;
int handleWarp();
bool handleWarpMouse(uint *actionId, uint movingCuror);
void animateWarpTransition(const Transition *transition);
void redrawWarp();
void handleFixedImg(const FixedImgCallback &callback);
void executeSeeAction(uint actionId);
void executeSpeakAction(uint actionId);
void setupDialogShows();
bool preprocessDialog(const Common::String &sequence);
void postprocessDialog(const Common::String &sequence);
void executeDocAction(uint actionId);
void drawMenuTitle(Graphics::ManagedSurface *surface, byte color);
uint displayFilePicker(const Graphics::Surface *bgFrame, bool saveMode,
Common::String &saveName);
uint displayYesNoBox(Graphics::ManagedSurface &surface, const Common::Rect &position,
uint msg_id);
void displayMessageBox(const MsgBoxParameters &params, const Graphics::Surface *surface,
uint msg_id, const Common::Point &position,
const Common::Functor0<void> &callback) { displayMessageBox(params, surface, _messages[msg_id], position, callback); }
void displayMessageBox(const MsgBoxParameters &params, const Graphics::Surface *surface,
const Common::String &msg, const Common::Point &position,
const Common::Functor0<void> &callback);
void displayMessageBoxWarp(const Common::String &message);
void displayMessageBoxWarp(uint msg_id) { displayMessageBoxWarp(_messages[msg_id]); }
void displayCredits();
void warpMsgBoxCB();
bool canVisit() const;
Common::String getSaveFileName(bool visit, uint saveNum) const;
void getSavesList(bool visit, Common::Array<Common::String> &saveNames, int &nextSaveNum);
void saveGame(bool visit, uint saveNum, const Common::String &saveName);
bool loadGame(bool visit, uint saveNum);
void animateCursor(const Object *object);
void collectObject(Object *object, const ZonFixedImage *fimg = nullptr,
bool showObject = true);
void collectObject(uint nameID, const ZonFixedImage *fimg = nullptr,
bool showObject = true) { collectObject(_objects.findObjectByNameID(nameID), fimg, showObject); }
typedef void (CryOmni3DEngine_Versailles::*DisplayObjectHook)(Graphics::ManagedSurface &surface);
void displayObject(const Common::String &imgName, DisplayObjectHook hook = nullptr);
void setMainPaletteColor(byte color, byte red, byte green, byte blue);
void setupPalette(const byte *colors, uint start, uint num, bool commit);
bool showSubtitles() const;
void playInGameAnimVideo(const Common::String &filename) {
playInGameVideo(getFilePath(kFileTypeAnimacti, filename));
}
void playInGameVideo(const Common::Path &filename, bool restoreCursorPalette = true);
void playSubtitledVideo(const Common::String &filename);
void loadBMPs(const char *pattern, Graphics::Surface *bmps, uint count);
uint getMusicId(uint level, uint placeId) const;
bool musicWouldChange(uint level, uint placeId) const;
void musicUpdate();
void musicPause();
void musicResume();
void musicStop();
void musicSetQuiet(bool quiet);
Common::StringArray _localizedFilenames;
Common::StringArray _messages;
static const uint kSpritesMapTable[];
static const uint kSpritesMapTableSize;
static const LevelInitialState kLevelInitialStates[];
static const FakeTransitionActionPlace kFakeTransitions[];
Common::HashMap<uint, FixedImgCallback> _imgScripts;
Common::Array<Common::String> _paintingsTitles;
Toolbar _toolbar;
byte *_mainPalette;
byte *_cursorPalette;
bool _fadedPalette;
bool _forcePaletteUpdate;
bool _forceRedrawWarp;
byte *_transparentPaletteMap;
uint _transparentSrcStart;
uint _transparentSrcStop;
uint _transparentDstStart;
uint _transparentDstStop;
uint _transparentNewStart;
uint _transparentNewStop;
bool _isPlaying;
bool _isVisiting;
AbortCommand _abortCommand;
uint _loadedSave;
int _omni3dSpeed;
uint _currentLevel;
Versailles_DialogsManager _dialogsMan;
Omni3DManager _omni3dMan;
ZonFixedImage *_fixedImage;
Common::Array<uint> _gameVariables;
Common::Array<PlaceState> _placeStates;
Common::HashMap<PlaceStateActionKey, uint> _actionMasks;
Common::HashMap<PlaceActionKey, Common::String> _whoSpeaksWhere;
Common::HashMap<uint, const char *> _docPeopleRecord;
bool _transitionAnimateWarp;
uint _nextPlaceId;
WAMParser _wam;
uint _currentPlaceId;
const Place *_currentPlace;
const Image::ImageDecoder *_currentWarpImage;
const char *_musicCurrentFile;
Audio::SoundHandle _musicHandle;
float _musicVolumeFactor;
static const char *kMusicFiles[8][8];
Versailles_Documentation _docManager;
static const MsgBoxParameters kWarpMsgBoxParameters;
static const MsgBoxParameters kFixedimageMsgBoxParameters;
static const FixedImageConfiguration kFixedImageConfiguration;
// Countdown
void initCountdown();
void syncCountdown();
inline bool countDown() { if (_countingDown) { return doCountDown(); } else { return false; } }
inline void drawCountdown(Graphics::ManagedSurface *surface = nullptr) { if (_countingDown) { doDrawCountdown(surface); } }
void drawCountdownVideo(uint frameNum) { drawCountdown(); }
bool _countingDown;
uint _countdownNextEvent;
char _countdownValue[6];
Graphics::ManagedSurface _countdownSurface;
bool doCountDown();
void doDrawCountdown(Graphics::ManagedSurface *surface);
// Video subtitles
Common::HashMap<Common::String, Common::Array<SubtitleEntry> > _subtitles;
const Common::Array<SubtitleEntry> *_currentSubtitleSet;
Common::Array<SubtitleEntry>::const_iterator _currentSubtitle;
void drawVideoSubtitles(uint frameNum);
// Objects
template<uint ID>
void genericDisplayObject();
void obj_105();
void obj_106();
void obj_107();
void obj_118();
void obj_121();
void obj_125();
void obj_126();
void obj_126hk(Graphics::ManagedSurface &surface);
void obj_129();
void obj_129hk(Graphics::ManagedSurface &surface);
void obj_142();
void obj_142hk(Graphics::ManagedSurface &surface);
// Fixed image
template<uint ID>
void genericDumbImage(ZonFixedImage *fimg);
template<uint ID>
void genericPainting(ZonFixedImage *fimg);
#define IMG_CB(name) void img_ ## name(ZonFixedImage *fimg)
IMG_CB(31101);
IMG_CB(31101b);
IMG_CB(31142);
IMG_CB(31142b);
IMG_CB(31142c);
IMG_CB(31142d);
IMG_CB(31143);
IMG_CB(31143b);
IMG_CB(31143c);
IMG_CB(31143d);
IMG_CB(32120);
IMG_CB(32120b);
IMG_CB(32120c);
IMG_CB(32201);
IMG_CB(32202);
IMG_CB(32203);
IMG_CB(32204);
IMG_CB(32204b);
IMG_CB(34131);
IMG_CB(34132);
IMG_CB(34172);
IMG_CB(34173);
IMG_CB(34173b);
IMG_CB(34173c);
IMG_CB(34174);
IMG_CB(34174b);
IMG_CB(34174c);
IMG_CB(34174d);
IMG_CB(34174e);
IMG_CB(34174f);
static const uint kSafeDigitsCount = 12;
static const uint16 kSafeDigitsX[];
static const uint16 kSafeDigitsY[];
static const char *kSafeDates[];
bool handleSafe(ZonFixedImage *fimg);
void drawSafeDigits(Graphics::ManagedSurface &surface, const Graphics::Surface(&bmpDigits)[10],
const unsigned char (&safeDigits)[kSafeDigitsCount]);
bool checkSafeDigits(unsigned char (&safeDigits)[kSafeDigitsCount]);
IMG_CB(41202);
IMG_CB(41202b);
IMG_CB(41801);
IMG_CB(41801b);
IMG_CB(41801c);
IMG_CB(41802);
IMG_CB(41802b);
IMG_CB(41802c);
IMG_CB(41802d);
IMG_CB(43143);
IMG_CB(43143b);
IMG_CB(43145);
IMG_CB(43145b);
IMG_CB(43145c);
IMG_CB(43146);
IMG_CB(43146b);
IMG_CB(43146c);
IMG_CB(43160);
IMG_CB(43160b);
IMG_CB(43160c);
IMG_CB(43160d);
IMG_CB(43190);
IMG_CB(43190b);
IMG_CB(43190c);
IMG_CB(43190d);
IMG_CB(43190e);
IMG_CB(43190f);
IMG_CB(44071);
IMG_CB(44071b);
IMG_CB(44161);
IMG_CB(44161b);
IMG_CB(44161c);
IMG_CB(44161d);
IMG_CB(44161e);
IMG_CB(44161f);
static const uint kEpigraphMaxLetters = 32;
Common::String _epigraphContent;
Common::String _epigraphPassword;
bool handleEpigraph(ZonFixedImage *fimg);
void drawEpigraphLetters(Graphics::ManagedSurface &surface,
const Graphics::Surface(&bmpLetters)[28], const Common::String &letters);
IMG_CB(45130);
IMG_CB(45270);
IMG_CB(45270b);
IMG_CB(45270c);
IMG_CB(45270d);
IMG_CB(45280);
IMG_CB(88001);
IMG_CB(88001b);
IMG_CB(88001c);
IMG_CB(88002);
IMG_CB(88003);
IMG_CB(88003b);
IMG_CB(88003c);
IMG_CB(88003d);
IMG_CB(88003e);
IMG_CB(88003f);
Common::U32String _bombAlphabet; // For Japanese edition
Common::U32String _bombPassword;
static const uint kBombPasswordSmallLength = 40;
static const uint kBombPasswordMaxLength = 60;
static const uint16 kBombLettersPos[2][kBombPasswordMaxLength][2];
bool handleBomb(ZonFixedImage *fimg);
void handleBombTranslation(Graphics::ManagedSurface &surface);
void drawBombLetters(Graphics::ManagedSurface &surface, const Graphics::Surface(&bmpLetters)[28],
const uint bombPasswordLength,
const uint32(&bombPossibilites)[kBombPasswordMaxLength][5],
const byte(&bombCurrentLetters)[kBombPasswordMaxLength]);
IMG_CB(88004);
IMG_CB(88004b);
#undef IMG_CB
#define FILTER_EVENT(level, place) bool filterEventLevel ## level ## Place ## place(uint *event)
#define INIT_PLACE(level, place) void initPlaceLevel ## level ## Place ## place()
FILTER_EVENT(1, 1);
FILTER_EVENT(1, 2);
INIT_PLACE(1, 3);
FILTER_EVENT(1, 3);
//FILTER_EVENT(1, 7); // Not used
FILTER_EVENT(1, 14);
FILTER_EVENT(2, 1);
FILTER_EVENT(2, 2);
FILTER_EVENT(2, 5);
INIT_PLACE(2, 9);
FILTER_EVENT(2, 9);
FILTER_EVENT(2, 11);
FILTER_EVENT(2, 12);
FILTER_EVENT(2, 14);
FILTER_EVENT(3, 3);
FILTER_EVENT(3, 10);
FILTER_EVENT(3, 13);
FILTER_EVENT(3, 15);
FILTER_EVENT(3, 17);
FILTER_EVENT(3, 18);
FILTER_EVENT(3, 19);
FILTER_EVENT(3_5, 20);
FILTER_EVENT(3, 22);
FILTER_EVENT(3, 23);
bool filterEventLevel3Obj23151();
void collectLampoonArchitecture(const ZonFixedImage *fimg = nullptr);
INIT_PLACE(4, 9);
FILTER_EVENT(4, 10);
FILTER_EVENT(4, 12_13_14);
FILTER_EVENT(4, 15);
FILTER_EVENT(4, 16);
FILTER_EVENT(4, 17);
INIT_PLACE(5, 6);
FILTER_EVENT(5, 9);
FILTER_EVENT(5, 14);
FILTER_EVENT(5, 15);
FILTER_EVENT(5, 16);
void filterEventLevel5UpdatePlaceStates();
//FILTER_EVENT(3_5, 20);
FILTER_EVENT(5, 23);
FILTER_EVENT(5, 27);
FILTER_EVENT(5, 28);
FILTER_EVENT(5, 29);
FILTER_EVENT(5, 33);
FILTER_EVENT(5, 34);
FILTER_EVENT(6, 1);
FILTER_EVENT(6, 3);
FILTER_EVENT(6, Orangery);
FILTER_EVENT(6, 19);
FILTER_EVENT(7, 2);
FILTER_EVENT(7, 9);
FILTER_EVENT(7, 10_11_13);
FILTER_EVENT(7, 20);
#undef FILTER_EVENT
#undef INIT_PLACE
// Dialogs shows
void dialogShowBontempsShowThird();
void dialogShowHuissierShowPamphlet();
void dialogShowMonseigneurSorts();
void dialogShowLeBrunWatches();
void dialogShowDoorsOpen();
void dialogShowSwissGuardGives();
void dialogShowLullyCorrects();
void dialogShowBontempsGivesAuth();
void dialogShowCroissyLeave();
void dialogShowMaintenonGives();
void dialogShowLaChaizeGivesBack();
void dialogShowLaChaizeWrites();
void dialogShowLaChaizeGivesPamphlet();
void dialogShowBontempsGivesKey();
void dialogShowDuMaineLeaves();
void dialogShowTransitionScene();
void dialogShowEndOfGame();
void dialogShowLeBrunGives();
void dialogShowLeBrunLeave();
};
} // End of namespace Versailles
} // End of namespace CryOmni3D
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,280 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "audio/audiostream.h"
#include "audio/decoders/wave.h"
#include "common/config-manager.h"
#include "common/error.h"
#include "common/file.h"
#include "common/system.h"
#include "cryomni3d/versailles/engine.h"
namespace CryOmni3D {
namespace Versailles {
const char *CryOmni3DEngine_Versailles::kMusicFiles[8][8] = {
{ "1amb", }, // Level 1
{ "2amb", "2amb2", "2amb1" }, // Level 2
{ "3amb", "3amb1", "3amb2" }, // Level 3
{ "4amb", "4amb1" }, // Level 4
{ "5amb1", "5amb2" }, // Level 5
{ "6amb1", "6amb2", "6amb3", "6amb4" }, // Level 6
{ "7amb", }, // Level 7
{ "3amb", "3amb1", "3amb2", "2amb", "2amb1", "2amb2", "4amb" }, // Level 8
};
void CryOmni3DEngine_Versailles::musicUpdate() {
if (!_isPlaying || _currentLevel <= 0 ||
_mixer->isSoundTypeMuted(Audio::Mixer::kMusicSoundType) ||
_mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType) == 0) {
// No music in all of these cases
musicStop();
return;
}
uint musicId = getMusicId(_currentLevel, _currentPlaceId);
const char *musicBName = kMusicFiles[_currentLevel - 1][musicId];
assert(musicBName != nullptr);
// Ensure sound is playing in all cases
musicResume();
if (musicBName == _musicCurrentFile) {
// Same file, nothing more to do
return;
}
// New file, stop the old one first
musicStop();
Common::Path musicPath(getFilePath(kFileTypeMusic, musicBName));
Common::File *musicFile = new Common::File();
if (!musicFile->open(musicPath)) {
warning("Failed to open music file %s/%s", musicBName, musicPath.toString(Common::Path::kNativeSeparator).c_str());
delete musicFile;
return;
}
Audio::SeekableAudioStream *musicDecoder = Audio::makeWAVStream(musicFile, DisposeAfterUse::YES);
// We lost ownership of the musicFile just set it to nullptr and don't use it
musicFile = nullptr;
if (!musicDecoder) {
warning("Failed to decode music file %s/%s", musicBName, musicPath.toString(Common::Path::kNativeSeparator).c_str());
return;
}
Audio::AudioStream *loopStream = Audio::makeLoopingAudioStream(musicDecoder, 0);
// We lost ownership of musicDecoder just set it to nullptr and don't use it
musicDecoder = nullptr;
_mixer->playStream(Audio::Mixer::kMusicSoundType, &_musicHandle, loopStream);
_musicCurrentFile = musicBName;
}
void CryOmni3DEngine_Versailles::musicPause() {
_mixer->pauseHandle(_musicHandle, true);
}
void CryOmni3DEngine_Versailles::musicResume() {
_mixer->pauseHandle(_musicHandle, false);
}
void CryOmni3DEngine_Versailles::musicStop() {
// Fade the music first
if (_mixer->isSoundHandleActive(_musicHandle)) {
// We recreate the real channel volume to decrease this one 2 by 2
int musicVol = _mixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType);
byte channelVol = _mixer->getChannelVolume(_musicHandle);
int realVolume = (musicVol * channelVol) / Audio::Mixer::kMaxChannelVolume;
bool skip = false;
while (realVolume > 0 && !skip) {
realVolume -= 2;
channelVol = CLIP((realVolume * Audio::Mixer::kMaxChannelVolume) / musicVol, 0, 255);
_mixer->setChannelVolume(_musicHandle, channelVol);
if (pollEvents() && checkKeysPressed(1, Common::KEYCODE_SPACE)) {
skip = true;
}
g_system->delayMillis(10);
}
}
_mixer->stopHandle(_musicHandle);
_musicCurrentFile = nullptr;
}
void CryOmni3DEngine_Versailles::musicSetQuiet(bool quiet) {
float newFactor = quiet ? 3.5f : 1.f;
if (newFactor != _musicVolumeFactor) {
_musicVolumeFactor = newFactor;
syncSoundSettings();
}
}
bool CryOmni3DEngine_Versailles::musicWouldChange(uint level, uint placeId) const {
uint musicId = getMusicId(level, placeId);
const char *musicFile = kMusicFiles[_currentLevel - 1][musicId];
return musicFile != _musicCurrentFile;
}
uint CryOmni3DEngine_Versailles::getMusicId(uint level,
uint placeId) const {
// No need of place state
switch (level) {
case 1:
// Only one music
return 0;
case 2:
switch (placeId) {
case 4:
return 1;
case 10:
case 11:
case 13:
return 2;
default:
return 0;
}
case 3:
switch (placeId) {
case 1:
case 2:
case 3:
case 4:
return 2;
case 6:
case 7:
case 8:
case 12:
case 24:
return 1;
default:
return 0;
}
case 4:
switch (placeId) {
case 1:
case 2:
case 3:
case 4:
return 1;
default:
return 0;
}
case 5:
switch (placeId) {
case 6:
case 7:
case 8:
case 12:
case 26:
case 27:
case 30:
case 31:
return 1;
default:
return 0;
}
case 6:
switch (placeId) {
case 1:
return 3;
case 3:
case 4:
case 5:
case 6:
case 8:
case 9:
case 10:
case 11:
return 0;
case 14:
case 16:
case 17:
case 19:
case 20:
case 22:
case 24:
case 26:
case 27:
case 32:
case 34:
case 38:
case 44:
return 2;
default:
return 1;
}
case 7:
return 0;
case 8:
switch (placeId) {
case 1:
case 2:
case 3:
case 4:
return 2;
case 6:
case 7:
case 8:
return 1;
case 9:
case 10:
case 11:
return 0;
case 12:
return 1;
case 13:
case 14:
case 15:
case 16:
return 0;
case 24:
return 1;
case 33:
case 34:
case 35:
return 5;
case 36:
case 37:
case 38:
case 39:
return 3;
case 40:
return 4;
case 42:
case 43:
case 44:
return 6;
default:
return 0;
}
default:
error("Invalid level %d when choosing music", level);
}
}
} // End of namespace Versailles
} // End of namespace CryOmni3D

View File

@@ -0,0 +1,337 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/archive.h"
#include "common/config-manager.h"
#include "common/file.h"
#include "common/savefile.h"
#include "common/system.h"
#include "cryomni3d/versailles/engine.h"
namespace CryOmni3D {
namespace Versailles {
Common::Error CryOmni3DEngine_Versailles::loadGameState(int slot) {
_loadedSave = slot + 1;
_abortCommand = kAbortLoadGame;
return Common::kNoError;
}
Common::Error CryOmni3DEngine_Versailles::saveGameState(int slot, const Common::String &desc, bool isAutosave) {
saveGame(_isVisiting, slot + 1, desc);
return Common::kNoError;
}
Common::String CryOmni3DEngine_Versailles::getSaveFileName(bool visit, uint saveNum) const {
return Common::String::format("%s%s.%04u", _targetName.c_str(), visit ? "_visit" : "", saveNum);
}
Common::String CryOmni3DEngine_Versailles::getSaveStateName(int slot) const {
return Common::String::format("%s.%04u", _targetName.c_str(), slot);
}
bool CryOmni3DEngine_Versailles::canVisit() const {
return Common::File::exists(getFilePath(kFileTypeSaveGameVisit, "game0001.sav"));
}
void CryOmni3DEngine_Versailles::getSavesList(bool visit, Common::StringArray &saveNames,
int &nextSaveNum) {
nextSaveNum = 1;
bool supportsAutoName = (_messages.size() >= 148);
char saveName[kSaveDescriptionLen + 1];
// Terminate saveName here forever (we don't overrun kSaveDescriptionLen)
saveName[kSaveDescriptionLen] = '\0';
Common::String pattern = Common::String::format("%s%s.####", _targetName.c_str(),
visit ? "_visit" : "");
Common::StringArray filenames = _saveFileMan->listSavefiles(pattern);
sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
saveNames.clear();
saveNames.reserve(100);
int num = 1;
int slotNum;
if (visit) {
// Add bootstrap visit
Common::Path visitPath(getFilePath(kFileTypeSaveGameVisit, "game0001.sav"));
Common::File visitFile;
if (visitFile.open(visitPath)) {
visitFile.read(saveName, kSaveDescriptionLen);
saveNames.push_back(saveName);
} else {
warning("visiting mode but no bootstrap");
// No bootstrap visit, too bad
saveNames.push_back(_messages[55]); //Fill with free slot
}
num++;
}
for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end();
++file) {
// Obtain the last 4 digits of the filename, since they correspond to the save slot
slotNum = atoi(file->c_str() + file->size() - 4);
if (slotNum >= 1 && slotNum <= 99) {
while (num < slotNum) {
saveNames.push_back(_messages[55]); //Fill with free slot
num++;
}
num++;
Common::InSaveFile *in = _saveFileMan->openForLoading(*file);
if (in) {
if (in->read(saveName, kSaveDescriptionLen) != kSaveDescriptionLen) {
warning("getSavesList(): Corrupted save %s", saveName);
delete in;
continue;
}
Common::String saveNameStr = saveName;
if (supportsAutoName && saveNameStr.hasPrefix("AUTO")) {
int saveNum = atoi(saveName + 4);
if (saveNum >= 1 && saveNum <= 9999) {
in->seek(436); // Go to current level
uint32 level = in->readUint32BE();
if (level < 8) {
saveNameStr = Common::String::format(_messages[146].c_str(), level);
} else {
saveNameStr = _messages[147];
}
saveNameStr += Common::String::format(" - %d", saveNum);
if (saveNum >= nextSaveNum) {
if (saveNum >= 9999) {
nextSaveNum = 9999;
} else {
nextSaveNum = saveNum + 1;
}
}
}
}
saveNames.push_back(saveNameStr);
delete in;
}
}
}
for (uint i = saveNames.size(); i < 100; i++) {
saveNames.push_back(_messages[55]);
}
}
void CryOmni3DEngine_Versailles::saveGame(bool visit, uint saveNum,
const Common::String &saveName) {
if (visit && saveNum == 1) {
error("Can't erase bootstrap visit");
}
Common::String saveFileName = getSaveFileName(visit, saveNum);
Common::OutSaveFile *out;
if (!(out = _saveFileMan->openForSaving(saveFileName))) {
return;
}
// Sync countdown to game variable before saving it to file
syncCountdown();
// Write save name
// Allocate one more byte to silence GCC warning
// The save name doesn't have to be null terminated in the save file
char saveNameC[kSaveDescriptionLen + 1];
memset(saveNameC, 0, sizeof(saveNameC));
strncpy(saveNameC, saveName.c_str(), kSaveDescriptionLen);
out->write(saveNameC, kSaveDescriptionLen);
// dummy values
out->writeUint32LE(0);
out->writeUint32BE(0);
out->writeUint32BE(0);
// Dialog variables
assert(_dialogsMan.size() < 200);
for (uint i = 0; i < _dialogsMan.size(); i++) {
out->writeByte(_dialogsMan[i]);
}
for (uint i = _dialogsMan.size(); i < 200; i++) {
out->writeByte(0);
}
// Inventory
assert(_inventory.size() == 50);
for (Inventory::const_iterator it = _inventory.begin(); it != _inventory.end(); it++) {
uint objId = uint(-1);
if (*it != nullptr) {
// Inventory contains pointers to objects stored in _objects
objId = *it - _objects.begin();
}
out->writeUint32BE(objId);
}
// Offset of inventory in toolbar
out->writeUint32BE(_toolbar.inventoryOffset());
// Level, place, warp position
out->writeUint32BE(_currentLevel);
out->writeUint32BE(_currentPlaceId);
out->writeDoubleBE(_omni3dMan.getAlpha());
out->writeDoubleBE(_omni3dMan.getBeta());
// Places states
assert(_placeStates.size() <= 100);
Common::Array<PlaceState>::const_iterator placeIt = _placeStates.begin();
for (uint i = 0; placeIt != _placeStates.end(); placeIt++, i++) {
out->writeUint32BE(placeIt->state);
}
for (uint i = _placeStates.size(); i < 100; i++) {
out->writeUint32BE(0);
}
// Game variables
assert(_gameVariables.size() < 100);
for (Common::Array<uint>::const_iterator it = _gameVariables.begin();
it != _gameVariables.end(); it++) {
out->writeUint32BE(*it);
}
for (uint i = _gameVariables.size(); i < 100; i++) {
out->writeUint32BE(0);
}
out->finalize();
delete out;
}
bool CryOmni3DEngine_Versailles::loadGame(bool visit, uint saveNum) {
Common::SeekableReadStream *in;
if (visit && saveNum == 1) {
// Load bootstrap visit
Common::File *visitFile = new Common::File();
if (!visitFile->open(getFilePath(kFileTypeSaveGameVisit, "game0001.sav"))) {
delete visitFile;
error("Can't load visit file");
}
in = visitFile;
} else {
Common::String saveFileName = getSaveFileName(visit, saveNum);
in = _saveFileMan->openForLoading(saveFileName);
}
if (!in || in->size() != 1260) {
return false;
}
musicStop();
// Load save name but don't use it
char saveNameC[kSaveDescriptionLen];
in->read(saveNameC, sizeof(saveNameC));
// dummy values
(void) in->readUint32LE();
(void) in->readUint32BE();
(void) in->readUint32BE();
// Dialog variables
assert(_dialogsMan.size() < 200);
for (uint i = 0; i < _dialogsMan.size(); i++) {
_dialogsMan[i] = in->readByte();
}
for (uint i = _dialogsMan.size(); i < 200; i++) {
// Read the remaining bytes but don't use them
(void) in->readByte();
}
// Inventory
assert(_inventory.size() == 50);
for (Inventory::iterator it = _inventory.begin(); it != _inventory.end(); it++) {
uint objId = in->readUint32BE();
if (objId >= _objects.size()) {
objId = uint(-1);
}
if (objId != uint(-1)) {
*it = _objects.begin() + objId;
} else {
*it = nullptr;
}
}
// Offset of inventory in toolbar
_toolbar.setInventoryOffset(in->readUint32BE());
// Level, place, warp position
_currentLevel = in->readUint32BE();
// Use nextPlace to force place move
_nextPlaceId = in->readUint32BE();
// Store alpha and beta for later use
double alpha = in->readDoubleBE();
double beta = in->readDoubleBE();
// Places states
// Store them and use them once we called initNewLevel, we can't call it before because it needs _gameVariables (and especially kCurrentTime) to be correctly set
uint32 placesStates[100];
for (uint i = 0; i < 100; i++) {
placesStates[i] = in->readUint32BE();
}
// Game variables
assert(_gameVariables.size() < 100);
for (Common::Array<uint>::iterator it = _gameVariables.begin(); it != _gameVariables.end();
it++) {
*it = in->readUint32BE();
}
for (uint i = _gameVariables.size(); i < 100; i++) {
// Read the remaining variables but don't use them
(void) in->readUint32BE();
}
delete in;
if (_gameVariables[GameVariables::kCurrentTime] == 0) {
_gameVariables[GameVariables::kCurrentTime] = 1;
}
initCountdown();
// Everything has been loaded, setup new level
// We will set places states and warp coordinates just after that to avoid them from being reset
initNewLevel(_currentLevel);
_omni3dMan.setAlpha(alpha);
_omni3dMan.setBeta(beta);
// _placeStates has just been resized in initNewLevel
uint i = 0;
for (Common::Array<PlaceState>::iterator placeIt = _placeStates.begin();
placeIt != _placeStates.end() && i < ARRAYSIZE(placesStates); placeIt++, i++) {
placeIt->state = placesStates[i];
}
return true;
}
} // End of namespace Versailles
} // End of namespace CryOmni3D

View File

@@ -0,0 +1,602 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/system.h"
#include "cryomni3d/cryomni3d.h"
#include "cryomni3d/versailles/toolbar.h"
namespace CryOmni3D {
namespace Versailles {
void Toolbar::init(const Sprites *sprites, FontManager *fontManager,
const Common::Array<Common::String> *messages, Inventory *inventory,
CryOmni3DEngine *engine) {
_sprites = sprites;
_fontManager = fontManager;
_messages = messages;
_inventory = inventory;
_engine = engine;
_bgSurface.create(640, 60, Graphics::PixelFormat::createFormatCLUT8());
_destSurface.create(640, 60, Graphics::PixelFormat::createFormatCLUT8());
// Inventory
addZone(51, 56, Common::Point(211, 8), &Toolbar::callbackInventory<0>);
addZone(51, 56, Common::Point(258, 8), &Toolbar::callbackInventory<1>);
addZone(51, 56, Common::Point(305, 8), &Toolbar::callbackInventory<2>);
addZone(51, 56, Common::Point(352, 8), &Toolbar::callbackInventory<3>);
addZone(51, 56, Common::Point(399, 8), &Toolbar::callbackInventory<4>);
addZone(51, 56, Common::Point(446, 8), &Toolbar::callbackInventory<5>);
addZone(51, 56, Common::Point(493, 8), &Toolbar::callbackInventory<6>);
addZone(51, 56, Common::Point(540, 8), &Toolbar::callbackInventory<7>);
// Documentation
const Graphics::Cursor &cursorDoc = _sprites->getCursor(133);
Common::Point docPos(627 - cursorDoc.getWidth(), 42 - cursorDoc.getHeight());
addZone(133, 137, docPos, &Toolbar::callbackDocumentation);
// Options
const Graphics::Cursor &cursorOpt = _sprites->getCursor(225);
Common::Point optPos(0, 60 - cursorOpt.getHeight());
addZone(225, 225, optPos, &Toolbar::callbackOptions);
// Previous or next
addZone(183, uint16(-1), Common::Point(190, 18), &Toolbar::callbackInventoryPrev);
addZone(240, uint16(-1), Common::Point(574, 18), &Toolbar::callbackInventoryNext);
// View
addZone(142, uint16(-1), Common::Point(158, 12), &Toolbar::callbackViewObject);
}
Toolbar::~Toolbar() {
_bgSurface.free();
_destSurface.free();
}
void Toolbar::inventoryChanged(uint newPosition) {
if (newPosition != uint(-1) && newPosition > _inventoryOffset) {
_inventoryOffset = newPosition - 7;
}
// Refresh
updateZones();
}
void Toolbar::addZone(uint16 cursorMainId, uint16 cursorSecondaryId, Common::Point position,
ZoneCallback callback) {
const Graphics::Cursor &cursorMain = _sprites->getCursor(cursorMainId);
Common::Rect rct(cursorMain.getWidth(), cursorMain.getHeight());
rct.moveTo(position);
// By default it's the secondary image
Zone zone = { rct, cursorMainId, cursorSecondaryId, callback, true, false };
_zones.push_back(zone);
}
Common::Array<Toolbar::Zone>::const_iterator Toolbar::hitTestZones(const Common::Point &mousePos)
const {
Common::Array<Zone>::const_iterator it;
for (it = _zones.begin(); it != _zones.end(); it++) {
if (!it->hidden && it->rect.contains(mousePos) && it->callback) {
break;
}
}
return it;
}
uint Toolbar::captureEvent(const Common::Point &mousePos, uint dragStatus) {
uint result = 0;
Common::Array<Zone>::const_iterator it = hitTestZones(mousePos);
if (it != _zones.end()) {
result = (this->*(it->callback))(dragStatus);
}
return result;
}
void Toolbar::updateZones() {
_zones[8].secondary = !_engine->hasPlaceDocumentation();
Inventory::const_iterator inventoryIt, inventorySelectedIt;
if (!_inventoryEnabled) {
_inventoryMaxOffset = 0;
_inventoryOffset = 0;
_zones[10].secondary = true;
_zones[11].secondary = true;
inventoryIt = _inventory->end();
inventorySelectedIt = _inventory->end();
} else {
_inventoryMaxOffset = 0;
// Find an object in inventory after the 8 first
for (inventoryIt = _inventory->begin() + 8; inventoryIt != _inventory->end(); inventoryIt++) {
if (*inventoryIt != nullptr) {
_inventoryMaxOffset = (inventoryIt - _inventory->begin()) - 7;
}
}
_zones[10].secondary = !_inventoryMaxOffset;
_zones[11].secondary = !_inventoryMaxOffset;
if (_inventoryOffset > _inventoryMaxOffset) {
// Clamp inventory offset to its max
_inventoryOffset = _inventoryMaxOffset;
}
inventoryIt = _inventory->begin() + _inventoryOffset;
inventorySelectedIt = _inventory->begin() + _inventorySelected;
}
// Inventory zones are from 0 to 7
for (Common::Array<Zone>::iterator zoneIt = _zones.begin(); zoneIt != _zones.begin() + 8;
zoneIt++, inventoryIt++) {
if (!_inventoryEnabled) {
zoneIt->hidden = true;
zoneIt->imageMain = 0;
zoneIt->imageSecondary = 0;
zoneIt->secondary = false;
} else if (inventoryIt >= _inventory->end() || *inventoryIt == nullptr) {
// Nothing in inventory at this position
zoneIt->hidden = false;
zoneIt->imageMain = 51;
zoneIt->imageSecondary = 56;
zoneIt->secondary = true;
} else {
// Setup inventory icon
zoneIt->hidden = false;
zoneIt->imageMain = (*inventoryIt)->idCA();
zoneIt->imageSecondary = (*inventoryIt)->idCl();
zoneIt->secondary = (inventorySelectedIt != inventoryIt);
}
}
}
uint Toolbar::callbackInventory(uint invId, uint dragStatus) {
if (!_inventoryEnabled) {
return 0;
}
invId += _inventoryOffset;
Object *obj = nullptr;
if (invId < _inventory->size()) {
obj = (*_inventory)[invId];
}
if (obj == nullptr) {
return 0;
}
if (!obj->valid()) {
return 0;
}
switch (dragStatus) {
case kDragStatus_Pressed:
_inventorySelected = invId;
_engine->setCursor(181);
_zones[12].secondary = (obj->viewCallback() == nullptr);
_inventoryButtonDragging = true;
return 1;
case kDragStatus_Dragging:
if (_inventorySelected == invId) {
return 0;
}
_inventorySelected = invId;
_zones[12].secondary = (obj->viewCallback() == nullptr);
_inventoryButtonDragging = true;
return 1;
case kDragStatus_Finished:
_engine->setCursor(obj->idSl());
_inventory->setSelectedObject(obj);
_inventorySelected = invId;
return 1;
default:
return 0;
}
}
uint Toolbar::callbackInventoryPrev(uint dragStatus) {
if (!_inventoryEnabled) {
return 0;
}
if (dragStatus == kDragStatus_Pressed && _inventoryOffset > 0) {
// Restart auto repeat only if there could be something
_engine->setAutoRepeatClick(150);
_inventoryOffset--;
return 1;
}
// In any other case we didn't do anything
return 0;
}
uint Toolbar::callbackInventoryNext(uint dragStatus) {
if (!_inventoryEnabled) {
return 0;
}
if (dragStatus == kDragStatus_Pressed && _inventoryOffset < _inventoryMaxOffset) {
_engine->setAutoRepeatClick(150);
_inventoryOffset++;
return 1;
}
// In any other case we didn't do anything
return 0;
}
uint Toolbar::callbackViewObject(uint dragStatus) {
if (!_inventoryEnabled) {
return 0;
}
_mouseInViewObject = true;
if (_inventorySelected == uint(-1)) {
// Nothing selected in toolbar
return 0;
}
Inventory::const_iterator inventorySelectedIt = _inventory->begin() + _inventorySelected;
Object *selectedObject = *inventorySelectedIt;
if (selectedObject == nullptr || selectedObject->viewCallback() == nullptr) {
// Nothing to view, the sprite isn't even displayed
return 0;
}
switch (dragStatus) {
case kDragStatus_NoDrag:
_backupSelectedObject = selectedObject;
_engine->setCursor(181);
return 0;
case kDragStatus_Pressed:
case kDragStatus_Dragging:
return 1;
case kDragStatus_Finished:
// Just clicked
_engine->showMouse(false);
(*selectedObject->viewCallback())();
_engine->showMouse(true);
_parentMustRedraw = true;
_shortExit = true;
return 1;
default:
return 0;
}
}
uint Toolbar::callbackOptions(uint dragStatus) {
_mouseInOptions = true;
switch (dragStatus) {
case kDragStatus_NoDrag:
_backupSelectedObject = _inventory->selectedObject();
_engine->setCursor(181);
return 0;
case kDragStatus_Pressed:
case kDragStatus_Dragging:
// Nothing to do, we wait release
return 0;
case kDragStatus_Finished:
// Just clicked
_engine->displayOptions();
_parentMustRedraw = true;
_shortExit = true;
_engine->setMousePos(Common::Point(320, 240)); // Center of screen
// Displaying options hides the mouse
_engine->showMouse(true);
return 0;
default:
return 0;
}
}
uint Toolbar::callbackDocumentation(uint dragStatus) {
_mouseInOptions = true;
switch (dragStatus) {
case kDragStatus_NoDrag:
case kDragStatus_Pressed:
case kDragStatus_Dragging:
// Nothing to do, we wait release
return 0;
case kDragStatus_Finished:
// Just clicked
if (_engine->displayPlaceDocumentation()) {
_parentMustRedraw = true;
_shortExit = true;
_engine->setMousePos(Common::Point(320, 240)); // Center of screen
}
return 0;
default:
return 0;
}
}
void Toolbar::drawToolbar(const Graphics::Surface *original) {
if (_position > 60) {
_position = 60;
}
if (_position != 0) {
// Not entirely drawn, we must copy a part of the original image
Common::Rect rct(0, 420, 640, 420 + _position);
_destSurface.copyRectToSurface(*original, 0, 0, rct);
}
if (_position == 60) {
// Entirely hidden, just stop there, we have nothing to draw
return;
}
// Not entirely hidden, we must display the transparent background prepared for us
Common::Rect rct(0, _position, 640, 60);
_destSurface.copyRectToSurface(_bgSurface, 0, _position, rct);
// Now draw the various zones on the surface
for (Common::Array<Zone>::const_iterator it = _zones.begin(); it != _zones.end(); it++) {
if (it->hidden) {
continue;
}
uint16 spriteId = it->secondary ? it->imageSecondary : it->imageMain;
if (spriteId == uint16(-1)) {
continue;
}
Common::Rect dst = it->rect;
dst.translate(0, _position);
// Clip the rectangle to fit inside the surface
dst.clip(Common::Rect(_destSurface.w, _destSurface.h));
if (dst.isEmpty()) {
continue;
}
const Graphics::Surface &sprite = _sprites->getSurface(spriteId);
_destSurface.transBlitFrom(sprite, Common::Rect(dst.width(), dst.height()), dst,
_sprites->getKeyColor(spriteId));
}
// And now draw the object description if needed
if (_inventoryEnabled && _inventoryHovered != uint(-1)) {
Object *obj = (*_inventory)[_inventoryHovered];
uint zoneId = _inventoryHovered - _inventoryOffset;
if (zoneId >= 8) {
// The object is hidden: huh?
return;
}
_fontManager->setSurface(&_destSurface);
_fontManager->setForeColor(243);
_fontManager->setCurrentFont(5);
_fontManager->setTransparentBackground(true);
const Common::String &objName = (*_messages)[obj->idOBJ()];
uint x = 195 - _fontManager->getStrWidth(objName);
uint startX = _zones[zoneId].rect.left + kTextOffset;
_fontManager->displayStr(x, 38 + _position, objName);
_destSurface.hLine(x, 54 + _position, startX - 1, 243); // minus 1 because hLine draws inclusive
_destSurface.vLine(startX, 42 + _position, 54 + _position, 243);
}
}
bool Toolbar::displayToolbar(const Graphics::Surface *original) {
/**
* In game there are 2 functions to handle toolbar: one in warp and one in fixed images
* This one is the warp one and fixed images have a more asynchronous one during pop-up/down phases
* Let's make it simple for now
*/
// WORKAROUND: Set cursor here to be more consistent: it's thumb cursor just before showing until just after showed
_engine->setCursor(181);
_parentMustRedraw = false;
_shortExit = false;
// Prepare the background of the toolbar by making it translucent
// Get the lowest part of the image
const Graphics::Surface subset = original->getSubArea(Common::Rect(0, original->h - _bgSurface.h,
_bgSurface.w, original->h));
_engine->makeTranslucent(_bgSurface, subset);
// WORKAROUND: Reset the inventory status at init to let sprites highlighted until toolbar is hidden
_inventorySelected = uint(-1);
_inventoryHovered = uint(-1);
_zones[12].secondary = true;
updateZones();
for (_position = 60; _position > 0; _position--) {
// Make the toolbar go up
drawToolbar(original);
g_system->copyRectToScreen(_destSurface.getPixels(), _destSurface.pitch, 0,
original->h - _destSurface.h, _destSurface.w, _destSurface.h);
g_system->updateScreen();
// Slow down animation
g_system->delayMillis(10);
_engine->pollEvents();
if (_engine->shouldAbort()) {
return false;
}
}
// Flush events
_engine->clearKeys();
_engine->waitMouseRelease();
handleToolbarEvents(original);
if (_engine->shouldAbort()) {
return false;
}
if (_shortExit) {
return _parentMustRedraw;
}
for (_position = 0; _position <= 60; _position++) {
// Make the toolbar go up
drawToolbar(original);
g_system->copyRectToScreen(_destSurface.getPixels(), _destSurface.pitch, 0,
original->h - _destSurface.h, _destSurface.w, _destSurface.h);
g_system->updateScreen();
// Slow down animation
g_system->delayMillis(10);
_engine->pollEvents();
if (_engine->shouldAbort()) {
return false;
}
}
return _parentMustRedraw;
}
void Toolbar::handleToolbarEvents(const Graphics::Surface *original) {
bool mouseInsideToolbar;
bool exitToolbar = false;
bool redrawToolbar;
// Don't have anything hovered for now
_inventoryHovered = uint(-1);
_inventorySelected = uint(-1);
_inventory->setSelectedObject(nullptr);
_backupSelectedObject = nullptr;
// Refresh zones because we erased selected object
updateZones();
// No need of original surface because the toolbar is fully displayed
drawToolbar(original);
g_system->copyRectToScreen(_destSurface.getPixels(), _destSurface.pitch, 0,
original->h - _destSurface.h, _destSurface.w, _destSurface.h);
g_system->updateScreen();
_engine->setCursor(181);
mouseInsideToolbar = (_engine->getMousePos().y > 388);
while (!exitToolbar) {
_mouseInOptions = false;
_mouseInViewObject = false;
_engine->pollEvents();
if (_engine->shouldAbort()) {
exitToolbar = true;
break;
}
redrawToolbar = false;
if (_engine->checkKeysPressed(2, Common::KEYCODE_ESCAPE, Common::KEYCODE_SPACE) ||
_engine->getCurrentMouseButton() == 2) {
_engine->waitMouseRelease();
exitToolbar = true;
break;
}
Common::Point mousePosInToolbar = _engine->getMousePos();
mousePosInToolbar -= Common::Point(0, 420);
if (captureEvent(mousePosInToolbar, _engine->getDragStatus())) {
// Something has changed with the zones handling, update zones
updateZones();
redrawToolbar = true;
} else if (_engine->getDragStatus() == kDragStatus_Pressed) {
// A click happened and wasn't handled, deselect object
_inventorySelected = uint(-1);
_inventory->setSelectedObject(nullptr);
_engine->setCursor(181);
// Reset view object
_zones[12].secondary = true;
updateZones();
redrawToolbar = true;
}
if (!mouseInsideToolbar) {
mouseInsideToolbar = (_engine->getMousePos().y > 388);
} else if (_engine->getMousePos().y <= 388) {
// mouseInsideToolbar is true and the mouse is outside the toolbar
exitToolbar = true;
break;
}
if (_engine->getCurrentMouseButton() == 1) {
// When the mouse button is down, nothing is selected
// It's selected on release
_inventory->setSelectedObject(nullptr);
}
if (_backupSelectedObject != nullptr && !(_mouseInOptions || _mouseInViewObject) &&
!_engine->getCurrentMouseButton()) {
_inventory->setSelectedObject(_backupSelectedObject);
_engine->setCursor(_backupSelectedObject->idSl());
_backupSelectedObject = nullptr;
}
// Hover the inventory objects
if (_inventory->selectedObject() == nullptr /* || _inventoryButtonDragging */) {
// The 2nd above condition is maybe useless because when the mouse button is down the selected object is always null
bool shouldHover = false;
Common::Array<Zone>::const_iterator zoneIt = hitTestZones(mousePosInToolbar);
uint zoneId = zoneIt - _zones.begin();
uint inventoryId = zoneId + _inventoryOffset;
if (zoneId < 8 && inventoryId < _inventory->size() && (*_inventory)[inventoryId] != nullptr) {
// It's the inventory
shouldHover = true;
if (_inventoryHovered != inventoryId && (*_inventory)[inventoryId]->valid()) {
// It's not the one currently hovered and it's a valid object
_inventoryHovered = inventoryId;
redrawToolbar = true;
}
}
if (!shouldHover && _inventoryHovered != uint(-1) && !_mouseInViewObject) {
// Remove hovering
_inventoryHovered = uint(-1);
_inventorySelected = uint(-1);
updateZones();
if (!_inventory->selectedObject()) {
// Reset back the cursor if nothing is selected
_engine->setCursor(181);
}
// Remove view
_zones[12].secondary = true;
redrawToolbar = true;
}
_inventoryButtonDragging = false;
}
if (_parentMustRedraw) {
break;
}
if (redrawToolbar) {
drawToolbar(original);
g_system->copyRectToScreen(_destSurface.getPixels(), _destSurface.pitch, 0,
original->h - _destSurface.h, _destSurface.w, _destSurface.h);
}
g_system->updateScreen();
g_system->delayMillis(10);
}
// Hide description when finished and selected object
// WORKAROUND: moved to the start to keep the selected object hilighted until the toolbar disappearance
}
} // End of namespace Versailles
} // End of namespace CryOmni3D

View File

@@ -0,0 +1,117 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef CRYOMNI3D_VERSAILLES_TOOLBAR_H
#define CRYOMNI3D_VERSAILLES_TOOLBAR_H
#include "common/array.h"
#include "common/rect.h"
#include "graphics/managed_surface.h"
#include "graphics/surface.h"
#include "cryomni3d/font_manager.h"
#include "cryomni3d/objects.h"
#include "cryomni3d/sprites.h"
namespace CryOmni3D {
class CryOmni3DEngine;
namespace Versailles {
class Toolbar {
public:
Toolbar() : _sprites(nullptr), _fontManager(nullptr), _inventory(nullptr),
_messages(nullptr), _engine(nullptr), _inventoryEnabled(true), _inventoryMaxOffset(0),
_inventoryOffset(0), _inventoryHovered(uint(-1)), _inventorySelected(uint(-1)), _backupSelectedObject(nullptr),
_mouseInOptions(false), _mouseInViewObject(false), _inventoryButtonDragging(false), _parentMustRedraw(false),
_shortExit(false), _position(60) { }
~Toolbar();
void init(const Sprites *sprites, FontManager *fontManager,
const Common::Array<Common::String> *messages, Inventory *inventory, CryOmni3DEngine *engine);
Graphics::Surface &getBackgroundSurface() { return _bgSurface; }
bool displayToolbar(const Graphics::Surface *original);
void inventoryChanged(uint newPosition);
uint inventoryOffset() const { return _inventoryOffset; }
void setInventoryOffset(uint offset) { _inventoryOffset = offset; }
void setInventoryEnabled(bool enabled) { _inventoryEnabled = enabled; }
private:
typedef uint(Toolbar::*ZoneCallback)(uint dragStatus);
struct Zone {
Common::Rect rect;
uint16 imageMain;
uint16 imageSecondary;
ZoneCallback callback;
bool secondary;
bool hidden;
};
Common::Array<Zone> _zones;
const Sprites *_sprites;
FontManager *_fontManager;
const Common::Array<Common::String> *_messages;
Inventory *_inventory;
CryOmni3DEngine *_engine;
static const uint kTextOffset = 13;
void addZone(uint16 cursorMainId, uint16 cursorSecondaryId, Common::Point position,
ZoneCallback callback);
void updateZones();
Common::Array<Zone>::const_iterator hitTestZones(const Common::Point &mousePos) const;
uint captureEvent(const Common::Point &mousePos, uint dragStatus);
void drawToolbar(const Graphics::Surface *original);
void handleToolbarEvents(const Graphics::Surface *original);
bool _inventoryEnabled;
uint _inventoryMaxOffset;
uint _inventoryOffset;
uint _inventoryHovered;
uint _inventorySelected;
Object *_backupSelectedObject;
bool _mouseInOptions;
bool _mouseInViewObject;
bool _inventoryButtonDragging;
bool _parentMustRedraw;
bool _shortExit;
uint _position;
Graphics::Surface _bgSurface;
Graphics::ManagedSurface _destSurface;
template<uint N>
uint callbackInventory(uint dragStatus) { return callbackInventory(N, dragStatus); }
uint callbackInventory(uint invId, uint dragStatus);
uint callbackInventoryPrev(uint dragStatus);
uint callbackInventoryNext(uint dragStatus);
uint callbackViewObject(uint dragStatus);
uint callbackOptions(uint dragStatus);
uint callbackDocumentation(uint dragStatus);
};
} // End of namespace Versailles
} // End of namespace CryOmni3D
#endif