diff options
Diffstat (limited to 'engines')
-rw-r--r-- | engines/cryomni3d/versailles/data.cpp | 17 | ||||
-rw-r--r-- | engines/cryomni3d/versailles/dialogs.cpp | 14 | ||||
-rw-r--r-- | engines/cryomni3d/versailles/engine.cpp | 2 | ||||
-rw-r--r-- | engines/cryomni3d/versailles/engine.h | 62 | ||||
-rw-r--r-- | engines/cryomni3d/versailles/logic.cpp | 879 |
5 files changed, 944 insertions, 30 deletions
diff --git a/engines/cryomni3d/versailles/data.cpp b/engines/cryomni3d/versailles/data.cpp index ea44442523..365afbbe8e 100644 --- a/engines/cryomni3d/versailles/data.cpp +++ b/engines/cryomni3d/versailles/data.cpp @@ -582,7 +582,6 @@ void CryOmni3DEngine_Versailles::initPlacesStates() { SET_PLACE_STATE(23, nullptr, FILTER_EVENT(3, 23), nullptr); SET_PLACE_STATE(24, nullptr, nullptr, "VS30"); } else if (_currentLevel == 4) { - // TODO: implement functions SET_PLACE_STATE(1, nullptr, nullptr, "VS35"); SET_PLACE_STATE(2, nullptr, nullptr, "VS40"); SET_PLACE_STATE(3, nullptr, nullptr, "VS40"); @@ -591,15 +590,15 @@ void CryOmni3DEngine_Versailles::initPlacesStates() { 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, nullptr, nullptr, nullptr); - SET_PLACE_STATE(10, nullptr, nullptr, "VS18"); + 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, nullptr, "VS31"); - SET_PLACE_STATE(13, nullptr, nullptr, "VS31"); - SET_PLACE_STATE(14, nullptr, nullptr, "VS31"); - SET_PLACE_STATE(15, nullptr, nullptr, "VS36"); - SET_PLACE_STATE(16, nullptr, nullptr, nullptr); - SET_PLACE_STATE(17, nullptr, nullptr, nullptr); + 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) { // TODO: implement functions SET_PLACE_STATE(1, nullptr, nullptr, "VS35"); diff --git a/engines/cryomni3d/versailles/dialogs.cpp b/engines/cryomni3d/versailles/dialogs.cpp index 580b56e89d..cd7de6c616 100644 --- a/engines/cryomni3d/versailles/dialogs.cpp +++ b/engines/cryomni3d/versailles/dialogs.cpp @@ -72,8 +72,9 @@ bool CryOmni3DEngine_Versailles::preprocessDialog(const Common::String &sequence 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::kUsedPlanVauban1] == 0 || - _gameVariables[GameVariables::kUsedPlanVauban2] == 0)) { + (!_inventory.inInventoryByNameID(127) || + _gameVariables[GameVariables::kUsedVaubanBlueprint1] == 0 || + _gameVariables[GameVariables::kUsedVaubanBlueprint2] == 0)) { displayMessageBoxWarp(18); _gameVariables[GameVariables::kWarnedIncomplete] = 1; return 0; @@ -81,8 +82,9 @@ bool CryOmni3DEngine_Versailles::preprocessDialog(const Common::String &sequence 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::kUsedPlanVauban1] == 0 || - _gameVariables[GameVariables::kUsedPlanVauban2] == 0)) { + (!_inventory.inInventoryByNameID(127) || + _gameVariables[GameVariables::kUsedVaubanBlueprint1] == 0 || + _gameVariables[GameVariables::kUsedVaubanBlueprint2] == 0)) { displayMessageBoxWarp(18); _gameVariables[GameVariables::kWarnedIncomplete] = 1; return 0; @@ -148,11 +150,11 @@ void CryOmni3DEngine_Versailles::postprocessDialog(const Common::String &sequenc collectObject(141); playTransitionEndLevel(5); } - if (sequence == "52A4_LAC" && _gameVariables[GameVariables::kStatePamphletReligion] != 3 && + 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::kStatePamphletReligion] = 3; + _gameVariables[GameVariables::kStateLampoonReligion] = 3; collectObject(125); _inventory.deselectObject(); } diff --git a/engines/cryomni3d/versailles/engine.cpp b/engines/cryomni3d/versailles/engine.cpp index b021a63763..d68cfaa0ec 100644 --- a/engines/cryomni3d/versailles/engine.cpp +++ b/engines/cryomni3d/versailles/engine.cpp @@ -611,7 +611,7 @@ void CryOmni3DEngine_Versailles::changeLevel(int level) { } // TODO: countdown _inventory.clear(); - } else if (_currentLevel <= 3) { + } else if (_currentLevel <= 4) { // TODO: remove this when we implemented all levels } else { error("New level %d is not implemented (yet)", level); diff --git a/engines/cryomni3d/versailles/engine.h b/engines/cryomni3d/versailles/engine.h index 438ae16395..44ef6514bd 100644 --- a/engines/cryomni3d/versailles/engine.h +++ b/engines/cryomni3d/versailles/engine.h @@ -126,14 +126,14 @@ struct GameVariables { kCollectPortfolio, // OK kSketchState, // OK kFakeSketchChatState, // OK - kCollectNourriture, - kCollectPlume, - kStatePamphletReligion, + kCollectFood, // OK + kCollectQuill, // OK + kStateLampoonReligion, // OK kCollectPetiteCle3, kCollectGravure, kCollectCordon, - kCollectPlanVauban, // 20 - kCollectPlanVauban2, + kCollectVaubanBlueprint1, // OK// 20 + kCollectVaubanBlueprint2, // OK kCollectEchelle, kLostCordon, kDescendreLustre, @@ -143,7 +143,7 @@ struct GameVariables { kStateBombe, kInkSpilled, // OK kCollectedPaperOnTable, // OK // 30 - kCoffreUnlocked, + kSafeUnlocked, // OK //kUselessVar, kCollectedPaperInTrunk = 33, // OK kBrushColor, // OK @@ -151,8 +151,8 @@ struct GameVariables { kUnlockedAttic, // OK kHasPlayedLebrun, // OK kWarnedIncomplete, - kUsedPlanVauban1, - kUsedPlanVauban2, // 40 + kUsedVaubanBlueprint1, // OK + kUsedVaubanBlueprint2, // OK // 40 kSeenMemorandum, kCollectScissors, // OK kSavedCountdown, // TODO: calculate it in real time @@ -397,7 +397,7 @@ private: static const MsgBoxParameters kFixedimageMsgBoxParameters; static const FixedImageConfiguration kFixedImageConfiguration; - //Objects + // Objects template<unsigned int ID> void genericDisplayObject(); void obj_105(); @@ -406,6 +406,8 @@ private: void obj_118(); void obj_121(); void obj_125(); + void obj_126(); + void obj_126hk(Graphics::ManagedSurface &surface); // Fixed image template<unsigned int ID> @@ -431,6 +433,27 @@ private: 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 unsigned int kSafeDigitsCount = 12; + static const unsigned int kSafeDigitsX[]; + static const unsigned int 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); @@ -458,6 +481,20 @@ private: 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 unsigned int kEpigraphMaxLetters = 32; + static const char *kEpigraphContent; + static const char *kEpigraphPassword; + bool handleEpigraph(ZonFixedImage *fimg); + void drawEpigraphLetters(Graphics::ManagedSurface &surface, + const Graphics::Surface(&bmpLetters)[26], const Common::String &letters); IMG_CB(88001); IMG_CB(88001b); @@ -497,6 +534,13 @@ private: 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); + #undef FILTER_EVENT #undef INIT_PLACE diff --git a/engines/cryomni3d/versailles/logic.cpp b/engines/cryomni3d/versailles/logic.cpp index 2f4555b8f2..e45c574f24 100644 --- a/engines/cryomni3d/versailles/logic.cpp +++ b/engines/cryomni3d/versailles/logic.cpp @@ -102,8 +102,8 @@ void CryOmni3DEngine_Versailles::setupObjects() { SET_OBJECT(143, 122); SET_OBJECT(101, 123); SET_OBJECT(204, 124); - SET_OBJECT(10, 125); // TODO: - SET_OBJECT(112, 126); // TODO: EPIL.gif + SET_OBJECT_CB(10, 125); + SET_OBJECT_CB(112, 126); SET_OBJECT_GENERIC_CB(90, 127, 17); SET_OBJECT(216, 128); SET_OBJECT_GENERIC_CB(32, 129, 18); @@ -172,13 +172,28 @@ void CryOmni3DEngine_Versailles::obj_121() { } void CryOmni3DEngine_Versailles::obj_125() { - if (_gameVariables[GameVariables::kStatePamphletReligion]) { + if (_gameVariables[GameVariables::kStateLampoonReligion]) { displayObject(imagesObjects[15]); } else { displayObject(imagesObjects[14]); } } +void CryOmni3DEngine_Versailles::obj_126() { + displayObject(imagesObjects[16], &CryOmni3DEngine_Versailles::obj_126hk); +} + +void CryOmni3DEngine_Versailles::obj_126hk(Graphics::ManagedSurface &surface) { + Graphics::Surface bmpLetters[26]; + loadBMPs("bomb_%02d.bmp", bmpLetters, 26); + + drawEpigraphLetters(surface, bmpLetters, kEpigraphPassword); + + for (unsigned int i = 0; i < 26; i++) { + bmpLetters[i].free(); + } +} + // This array contains images for all paintings it must be kept in sync with _paintingsTitles static const char *imagesPaintings[] = { "10E_1.GIF", // 0: 41201 @@ -333,8 +348,8 @@ void CryOmni3DEngine_Versailles::setupImgScripts() { SET_SCRIPT_BY_ID(43146); SET_SCRIPT_BY_ID(43160); SET_SCRIPT_BY_ID(43190); - //SET_SCRIPT_BY_ID(44071); // TODO: implement it - //SET_SCRIPT_BY_ID(44161); // TODO: implement it + SET_SCRIPT_BY_ID(44071); + SET_SCRIPT_BY_ID(44161); //SET_SCRIPT_BY_ID(45130); // TODO: implement it // Almost dumb //SET_SCRIPT_BY_ID(45270); // TODO: implement it //SET_SCRIPT_BY_ID(45280); // TODO: implement it // Almost dumb @@ -812,6 +827,397 @@ IMG_CB(32204b) { } } +IMG_CB(34131) { + fimg->load("43ZA_1.GIF"); + while (1) { + fimg->manage(); + if (fimg->_exit || fimg->_zoneLow) { + fimg->_exit = true; + break; + } + } +} + +IMG_CB(34132) { + fimg->load("43ZB_2.GIF"); + while (1) { + fimg->manage(); + if (fimg->_exit || fimg->_zoneLow) { + fimg->_exit = true; + break; + } + } +} + +IMG_CB(34172) { + playInGameVideo("43X3_10"); + // Force reload of the place + if (_nextPlaceId == -1u) { + _nextPlaceId = _currentPlaceId; + } + fimg->_exit = true; +} + +IMG_CB(34173) { + fimg->load("43X3_2.GIF"); + while (1) { + fimg->manage(); + if (fimg->_exit || fimg->_zoneLow) { + fimg->_exit = true; + break; + } + if (fimg->_zoneUse) { + // WORKAROUND: The video doesn't exist there is only a fixed image unused in original game. We will use it. + /* + playInGameVideo("43X3_21"); + // Force reload of the place + if (_nextPlaceId == -1u) { + _nextPlaceId = _currentPlaceId; + } + */ + + ZonFixedImage::CallbackFunctor *functor = + new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this, + &CryOmni3DEngine_Versailles::img_34173b); + fimg->changeCallback(functor); + break; + } + } +} + +// WORKAROUND: In original game an empty clickable drawer is displayed +// Happily for them, when you click on an area and change zones, the next zone +// under the cursor get activated too (fixed in fixed_image.cpp). So you don't +// see what happens. You just get the reminder and see the empty drawer. +IMG_CB(34173b) { + // 43X3_21 doesn't have a ZON file, use the one of 43X3_22 + fimg->load("43X3_21.GIF", "43X3_22.ZON"); + while (1) { + fimg->manage(); + if (fimg->_exit || fimg->_zoneLow) { + fimg->_exit = true; + break; + } + if (fimg->_zoneUse && !_inventory.inInventoryByNameID(129)) { + // Collect reminder + collectObject(129, fimg); + setGameTime(3, 4); + + ZonFixedImage::CallbackFunctor *functor = + new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this, + &CryOmni3DEngine_Versailles::img_34173c); + fimg->changeCallback(functor); + break; + } + } +} + +IMG_CB(34173c) { + fimg->load("43X3_22.GIF"); + // WORKAROUND: Drawer is empty, just disable the use zone + fimg->disableZone(0); + while (1) { + fimg->manage(); + if (fimg->_exit || fimg->_zoneLow) { + fimg->_exit = true; + break; + } + } +} + +IMG_CB(34174) { + fimg->load("43X3_42.GIF"); + while (1) { + fimg->manage(); + if (fimg->_exit || fimg->_zoneLow) { + fimg->_exit = true; + break; + } + if (fimg->_zoneUse) { + // Open the door + ZonFixedImage::CallbackFunctor *functor = + new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this, + &CryOmni3DEngine_Versailles::img_34174b); + fimg->changeCallback(functor); + break; + } + } +} + +IMG_CB(34174b) { + // Door is open but safe is closed + fimg->load("43X3_40.GIF"); + while (1) { + fimg->manage(); + if (fimg->_exit || fimg->_zoneLow) { + fimg->_exit = true; + break; + } + if (fimg->_zoneUse) { + if (_gameVariables[GameVariables::kSafeUnlocked]) { + // Open the safe + ZonFixedImage::CallbackFunctor *functor = + new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this, + &CryOmni3DEngine_Versailles::img_34174c); + fimg->changeCallback(functor); + break; + } + _dialogsMan["{JOUEUR-ALLER-BUREAU-LOUVOIS}"] = 'Y'; + if (handleSafe(fimg)) { + // Unlocked the safe + _gameVariables[GameVariables::kSafeUnlocked] = 1; + _dialogsMan["{JOUEUR-ALLER-BUREAU-LOUVOIS}"] = 'N'; + // Open it + ZonFixedImage::CallbackFunctor *functor = + new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this, + &CryOmni3DEngine_Versailles::img_34174c); + fimg->changeCallback(functor); + break; + } + } + } +} + +IMG_CB(34174c) { + // Dispatch to the correct state + if (_gameVariables[GameVariables::kCollectVaubanBlueprint1] && + _gameVariables[GameVariables::kCollectVaubanBlueprint2]) { + // Safe is empty + ZonFixedImage::CallbackFunctor *functor = + new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this, + &CryOmni3DEngine_Versailles::img_34174f); + fimg->changeCallback(functor); + return; + } + if (!_gameVariables[GameVariables::kCollectVaubanBlueprint1] && + _gameVariables[GameVariables::kCollectVaubanBlueprint2] == 1) { + // Blueprint 1 is there not the 2nd one + ZonFixedImage::CallbackFunctor *functor = + new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this, + &CryOmni3DEngine_Versailles::img_34174e); + fimg->changeCallback(functor); + return; + } + if (_gameVariables[GameVariables::kCollectVaubanBlueprint1] && + !_gameVariables[GameVariables::kCollectVaubanBlueprint2]) { + // Blueprint 2 is there not the 1st one + ZonFixedImage::CallbackFunctor *functor = + new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this, + &CryOmni3DEngine_Versailles::img_34174d); + fimg->changeCallback(functor); + return; + } + + playInGameVideo("cofouv"); + // Force reload of the place + if (_nextPlaceId == -1u) { + _nextPlaceId = _currentPlaceId; + } + + // Safe has both blueprints + fimg->load("43X3_30.GIF"); + while (1) { + fimg->manage(); + if (fimg->_exit || fimg->_zoneLow) { + fimg->_exit = true; + break; + } + if (fimg->_zoneUse) { + if (fimg->_currentZone == 0) { + // Collect 1st blueprint + collectObject(131, fimg); + _dialogsMan["{JOUEUR-TROUVE-PLANS-VAUBAN}"] = 'Y'; + _gameVariables[GameVariables::kCollectVaubanBlueprint1] = 1; + + ZonFixedImage::CallbackFunctor *functor = + new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this, + &CryOmni3DEngine_Versailles::img_34174d); + fimg->changeCallback(functor); + break; + } else if (fimg->_currentZone == 1) { + // Collect 2nd blueprint + collectObject(132, fimg); + _gameVariables[GameVariables::kCollectVaubanBlueprint2] = 1; + + ZonFixedImage::CallbackFunctor *functor = + new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this, + &CryOmni3DEngine_Versailles::img_34174e); + fimg->changeCallback(functor); + break; + } + } + } +} + +IMG_CB(34174d) { + // Safe has only blueprint 2 + fimg->load("43X3_43.GIF"); + while (1) { + fimg->manage(); + if (fimg->_exit || fimg->_zoneLow) { + fimg->_exit = true; + break; + } + if (fimg->_zoneUse) { + // Collect 2nd blueprint + collectObject(132, fimg); + _gameVariables[GameVariables::kCollectVaubanBlueprint2] = 1; + + ZonFixedImage::CallbackFunctor *functor = + new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this, + &CryOmni3DEngine_Versailles::img_34174f); + fimg->changeCallback(functor); + break; + } + } +} + +IMG_CB(34174e) { + // Safe has only blueprint 1 + fimg->load("43X3_41.GIF"); + while (1) { + fimg->manage(); + if (fimg->_exit || fimg->_zoneLow) { + fimg->_exit = true; + break; + } + if (fimg->_zoneUse) { + // Collect 1st blueprint + collectObject(131, fimg); + _dialogsMan["{JOUEUR-TROUVE-PLANS-VAUBAN}"] = 'Y'; + _gameVariables[GameVariables::kCollectVaubanBlueprint1] = 1; + + ZonFixedImage::CallbackFunctor *functor = + new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this, + &CryOmni3DEngine_Versailles::img_34174f); + fimg->changeCallback(functor); + break; + } + } +} + +IMG_CB(34174f) { + // Safe is empty + fimg->load("43X3_45.GIF"); + while (1) { + fimg->manage(); + if (fimg->_exit || fimg->_zoneLow) { + fimg->_exit = true; + break; + } + if (fimg->_zoneUse) { + // Close safe + ZonFixedImage::CallbackFunctor *functor = + new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this, + &CryOmni3DEngine_Versailles::img_34174b); + fimg->changeCallback(functor); + break; + } + } +} + +bool CryOmni3DEngine_Versailles::handleSafe(ZonFixedImage *fimg) { + bool success = false; + Common::RandomSource rnd("VersaillesSafe"); + Graphics::Surface bmpDigits[10]; + unsigned char safeDigits[kSafeDigitsCount]; + Graphics::ManagedSurface tempSurf; + + loadBMPs("coff_%02d.bmp", bmpDigits, 10); + for (unsigned int i = 0; i < kSafeDigitsCount; i++) { + safeDigits[i] = rnd.getRandomNumber(9); + } + + fimg->load("43x3_cof.GIF"); + const Graphics::Surface *fimgSurface = fimg->surface(); + tempSurf.create(fimgSurface->w, fimgSurface->h, fimgSurface->format); + tempSurf.blitFrom(*fimgSurface); + drawSafeDigits(tempSurf, bmpDigits, safeDigits); + fimg->updateSurface(&tempSurf.rawSurface()); + + while (1) { + fimg->manage(); + if (fimg->_exit || fimg->_zoneLow) { + break; + } + if (fimg->_zoneUse) { + if (fimg->_currentZone == 15) { + // Safe handle + + // Animate handle + playInGameVideo("43x3_poi"); + // Force reload of the place + if (_nextPlaceId == -1u) { + _nextPlaceId = _currentPlaceId; + } + + // Redraw our safe image + fimg->display(); + + if (checkSafeDigits(safeDigits)) { + success = true; + break; + } + } else if (fimg->_currentZone < kSafeDigitsCount) { + // Safe digit + safeDigits[fimg->_currentZone] = (safeDigits[fimg->_currentZone] + 1) % 10; + // Reset the surface and redraw digits on it + tempSurf.blitFrom(*fimgSurface); + drawSafeDigits(tempSurf, bmpDigits, safeDigits); + fimg->updateSurface(&tempSurf.rawSurface()); + + waitMouseRelease(); + } + } + } + + for (unsigned int i = 0; i < 10; i++) { + bmpDigits[i].free(); + } + return success; +} + +const unsigned int CryOmni3DEngine_Versailles::kSafeDigitsX[] = { 267, 318, 370, 421 }; +const unsigned int CryOmni3DEngine_Versailles::kSafeDigitsY[] = { 148, 230, 311 }; + +void CryOmni3DEngine_Versailles::drawSafeDigits(Graphics::ManagedSurface &surface, + const Graphics::Surface(&bmpDigits)[10], const unsigned char (&safeDigits)[kSafeDigitsCount]) { + for (unsigned int i = 0; i < ARRAYSIZE(safeDigits); i++) { + const Graphics::Surface &digit = bmpDigits[safeDigits[i]]; + Common::Point dst(kSafeDigitsX[i % 4], kSafeDigitsY[i / 4]); + surface.transBlitFrom(digit, dst); + } +} + +const char *CryOmni3DEngine_Versailles::kSafeDates[] = { "1643", "1668", "1674" }; +bool CryOmni3DEngine_Versailles::checkSafeDigits(unsigned char (&safeDigits)[kSafeDigitsCount]) { + unsigned int dateChecked; + for (dateChecked = 0; dateChecked < ARRAYSIZE(kSafeDates); dateChecked++) { + const char *checkDate = kSafeDates[dateChecked]; + // Find the date in one of safe digits lines + unsigned int line; + for (line = 0; line < kSafeDigitsCount; line += 4) { + unsigned int digit; + for (digit = 0; digit < 4; digit++) { + if (safeDigits[line + digit] != checkDate[digit] - '0') { + break; + } + } + if (digit == 4) { + // Check was a success: go to next date + break; + } + // Failure: try next line + } + if (line >= kSafeDigitsCount) { + // All lines were tested and none had the date: failure + return false; + } + } + // All dates were found + return true; +} + IMG_CB(41202) { fimg->load("10E_20.GIF"); while (1) { @@ -1653,6 +2059,301 @@ IMG_CB(43190f) { } } +IMG_CB(44071) { + // Dispatch to the correct state + if (_gameVariables[GameVariables::kCollectFood]) { + // Draw plate with less food + ZonFixedImage::CallbackFunctor *functor = + new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this, + &CryOmni3DEngine_Versailles::img_44071b); + fimg->changeCallback(functor); + return; + } + + // There we have a full plate + fimg->load("41B_bboy.GIF"); + while (1) { + fimg->manage(); + if (fimg->_exit || fimg->_zoneLow) { + fimg->_exit = true; + break; + } + if (fimg->_zoneUse) { + // Collected food + collectObject(124, fimg); + _gameVariables[GameVariables::kCollectFood] = 1; + // Draw plate with less food + ZonFixedImage::CallbackFunctor *functor = + new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this, + &CryOmni3DEngine_Versailles::img_44071b); + fimg->changeCallback(functor); + break; + } + } +} + +IMG_CB(44071b) { + // There we have less food on plate + fimg->load("41B_bbo2.GIF"); + while (1) { + fimg->manage(); + if (fimg->_exit || fimg->_zoneLow) { + fimg->_exit = true; + break; + } + } +} + +IMG_CB(44161) { + // Dispatch to the correct state + if (_gameVariables[GameVariables::kCollectQuill] == 1 && !_inventory.inInventoryByNameID(126)) { + // We have collected quill but not solved epigraph yet + ZonFixedImage::CallbackFunctor *functor = + new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this, + &CryOmni3DEngine_Versailles::img_44161b); + fimg->changeCallback(functor); + return; + } else if (_gameVariables[GameVariables::kUsedVaubanBlueprint1] == 1 && + _gameVariables[GameVariables::kUsedVaubanBlueprint2] == 1) { + // We have used vauban blueprints: display the solution + ZonFixedImage::CallbackFunctor *functor = + new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this, + &CryOmni3DEngine_Versailles::img_44161f); + fimg->changeCallback(functor); + return; + } else if (_gameVariables[GameVariables::kCollectQuill] == 1 && + _inventory.inInventoryByNameID(126)) { + // We have collected quill and epigraph + ZonFixedImage::CallbackFunctor *functor = + new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this, + &CryOmni3DEngine_Versailles::img_44161c); + fimg->changeCallback(functor); + return; + } + + // There we have blueprints, quill and epigraph on desk + fimg->load("42X2_20.GIF"); + while (1) { + fimg->manage(); + if (fimg->_exit || fimg->_zoneLow) { + fimg->_exit = true; + break; + } + if (fimg->_zoneUse && fimg->_currentZone == 0 && currentGameTime() >= 2) { + // Collected quill + collectObject(128, fimg); + _gameVariables[GameVariables::kCollectQuill] = 1; + // Try to solve epigraph + ZonFixedImage::CallbackFunctor *functor = + new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this, + &CryOmni3DEngine_Versailles::img_44161b); + fimg->changeCallback(functor); + break; + } else if (fimg->_zoneSee) { + // Look at blueprints + ZonFixedImage::CallbackFunctor *functor = + new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this, + &CryOmni3DEngine_Versailles::img_44161d); + fimg->changeCallback(functor); + break; + } + } +} + +IMG_CB(44161b) { + // There we have blueprints and epigraph on desk. + fimg->load("42X2_10.GIF"); + while (1) { + fimg->manage(); + if (fimg->_exit || fimg->_zoneLow) { + fimg->_exit = true; + break; + } + if (fimg->_usedObject && fimg->_usedObject->idOBJ() == 128 && fimg->_currentZone == 1) { + if (handleEpigraph(fimg)) { + // Epigraph is solved + _inventory.removeByNameID(128); + collectObject(126, fimg, false); + _dialogsMan["{JOUEUR_POSSEDE_EPIGRAPHE}"] = 'Y'; + setPlaceState(16, 2); + // No more epigraphe nor quill + ZonFixedImage::CallbackFunctor *functor = + new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this, + &CryOmni3DEngine_Versailles::img_44161c); + fimg->changeCallback(functor); + } + // If failed to solve: just display this image again + break; + } else if (fimg->_zoneSee) { + // Look at blueprints + ZonFixedImage::CallbackFunctor *functor = + new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this, + &CryOmni3DEngine_Versailles::img_44161d); + fimg->changeCallback(functor); + break; + } + } +} + +IMG_CB(44161c) { + // There we have no quill nor epigraph anymore + fimg->load("42X2_11.GIF"); + while (1) { + fimg->manage(); + if (fimg->_exit || fimg->_zoneLow) { + fimg->_exit = true; + break; + } + if (fimg->_zoneSee) { + // Look at blueprints + ZonFixedImage::CallbackFunctor *functor = + new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this, + &CryOmni3DEngine_Versailles::img_44161d); + fimg->changeCallback(functor); + break; + } + } +} + +IMG_CB(44161d) { + // Look at blueprints + fimg->load("VAU1.GIF"); + while (1) { + fimg->manage(); + if (fimg->_exit || fimg->_zoneLow) { + fimg->_exit = true; + break; + } + if (fimg->_usedObject && fimg->_usedObject->idOBJ() == 131) { + // Overlay blueprints + ZonFixedImage::CallbackFunctor *functor = + new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this, + &CryOmni3DEngine_Versailles::img_44161e); + fimg->changeCallback(functor); + break; + } + } +} + +IMG_CB(44161e) { + // Look at blueprints + fimg->load("VAUB22.GIF"); + while (1) { + fimg->manage(); + if (fimg->_exit || fimg->_zoneLow) { + fimg->_exit = true; + break; + } + if (fimg->_usedObject && fimg->_usedObject->idOBJ() == 132) { + // Overlay blueprints + _gameVariables[GameVariables::kUsedVaubanBlueprint1] = 1; + _gameVariables[GameVariables::kUsedVaubanBlueprint2] = 1; + _inventory.removeByNameID(131); + _inventory.removeByNameID(132); + setGameTime(4, 4); + // Look at the final result + ZonFixedImage::CallbackFunctor *functor = + new Common::Functor1Mem<ZonFixedImage *, void, CryOmni3DEngine_Versailles>(this, + &CryOmni3DEngine_Versailles::img_44161f); + fimg->changeCallback(functor); + break; + } + } +} + +IMG_CB(44161f) { + // Look at blueprints result + fimg->load("VAU.GIF"); + while (1) { + fimg->manage(); + if (fimg->_exit || fimg->_zoneLow) { + fimg->_exit = true; + break; + } + } +} + +bool CryOmni3DEngine_Versailles::handleEpigraph(ZonFixedImage *fimg) { + bool success = false; + Graphics::Surface bmpLetters[26]; + Common::String password; + Graphics::ManagedSurface tempSurf; + + loadBMPs("bomb_%02d.bmp", bmpLetters, 26); + + fimg->load("EPIL.GIF"); + const Graphics::Surface *fimgSurface = fimg->surface(); + tempSurf.create(fimgSurface->w, fimgSurface->h, fimgSurface->format); + // No need to customize image yet + + while (1) { + fimg->manage(); + if (fimg->_exit || fimg->_zoneLow) { + break; + } + if (fimg->_zoneUse) { + if (password.size() >= kEpigraphMaxLetters) { + continue; + } + // Find which letter got clicked + char letter = kEpigraphContent[fimg->_currentZone]; + password += letter; + // Reset the surface and redraw digits on it + tempSurf.blitFrom(*fimgSurface); + drawEpigraphLetters(tempSurf, bmpLetters, password); + fimg->updateSurface(&tempSurf.rawSurface()); + + waitMouseRelease(); + } else if (fimg->_key.keycode) { + Common::KeyCode keyCode = fimg->_key.keycode; + if (keyCode == Common::KEYCODE_BACKSPACE) { + password.deleteLastChar(); + } else { + if (password.size() >= kEpigraphMaxLetters) { + continue; + } + if (keyCode >= Common::KEYCODE_a && + keyCode <= Common::KEYCODE_z && + strchr(kEpigraphContent, keyCode - Common::KEYCODE_a + 'A')) { + password += keyCode - Common::KEYCODE_a + 'A'; + } else { + continue; + } + } + // Reset the surface and redraw digits on it + tempSurf.blitFrom(*fimgSurface); + drawEpigraphLetters(tempSurf, bmpLetters, password); + fimg->updateSurface(&tempSurf.rawSurface()); + } + + if (password == kEpigraphPassword) { + success = true; + break; + } + } + + for (unsigned int i = 0; i < 26; i++) { + bmpLetters[i].free(); + } + return success; +} + +const char *CryOmni3DEngine_Versailles::kEpigraphContent = "FELIXFORTUNADIVINUMEXPLORATUMACTUIIT"; +const char *CryOmni3DEngine_Versailles::kEpigraphPassword = "LELOUPETLATETE"; + +void CryOmni3DEngine_Versailles::drawEpigraphLetters(Graphics::ManagedSurface &surface, + const Graphics::Surface(&bmpLetters)[26], const Common::String &letters) { + for (unsigned int i = 0; i < letters.size() && i < kEpigraphMaxLetters; i++) { + unsigned int letterId = 0; + if (letters[i] >= 'A' && letters[i] <= 'Z') { + letterId = letters[i] - 'A'; + } + const Graphics::Surface &letter = bmpLetters[letterId]; + Common::Point dst(34 * i + 4, 380); + surface.transBlitFrom(letter, dst); + } +} + IMG_CB(88001) { if (!_inventory.inInventoryByNameID(121) && _gameVariables[GameVariables::kMedalsDrawerStatus] == 3) { @@ -2562,6 +3263,174 @@ void CryOmni3DEngine_Versailles::collectLampoonArchitecture(const ZonFixedImage _dialogsMan["{JOUEUR_POSSEDE_PAMPHLET_ARCHI}"] = 'Y'; } +INIT_PLACE(4, 9) { + if (currentGameTime() == 4 && !_inventory.inInventoryByNameID(125)) { + _dialogsMan.play("4_MAI"); + _forcePaletteUpdate = true; + // Force reload of the place + if (_nextPlaceId == -1u) { + _nextPlaceId = _currentPlaceId; + } + } +} + +FILTER_EVENT(4, 10) { + if (*event == 24104 && _inventory.selectedObject()) { + _dialogsMan["{JOUEUR-PRESENTE-OBJET-HUISSIER}"] = 'Y'; + _dialogsMan.play("41C_HUI"); + + _forcePaletteUpdate = true; + // Force reload of the place + if (_nextPlaceId == -1u) { + _nextPlaceId = _currentPlaceId; + } + + _dialogsMan["{JOUEUR-PRESENTE-OBJET-HUISSIER}"] = 'N'; + _inventory.deselectObject(); + return true; + } else if (*event == 24105 && _inventory.selectedObject()) { + if (_inventory.selectedObject()->idOBJ() == 127) { + _dialogsMan["{JOUEUR-MONTRE-PAMPHLET-GOUVERNEMENT}"] = 'Y'; + } else if (_inventory.selectedObject()->idOBJ() == 125) { + _dialogsMan["{JOUEUR-MONTRE-PAMPHLET-RELIGION}"] = 'Y'; + } else if (_inventory.selectedObject()->idOBJ() == 126) { + _dialogsMan["{JOUEUR-MONTRE-PAPIER-CROISSY}"] = 'Y'; + } else { + _dialogsMan["{JOUEUR-MONTRE-TOUT-AUTRE-OBJET}"] = 'Y'; + } + _dialogsMan.play("42C_BON"); + + _forcePaletteUpdate = true; + // Force reload of the place + if (_nextPlaceId == -1u) { + _nextPlaceId = _currentPlaceId; + } + + _dialogsMan["{JOUEUR-MONTRE-PAMPHLET-GOUVERNEMENT}"] = 'N'; + _dialogsMan["{JOUEUR-MONTRE-PAMPHLET-RELIGION}"] = 'N'; + _dialogsMan["{JOUEUR-MONTRE-PAPIER-CROISSY}"] = 'N'; + _dialogsMan["{JOUEUR-MONTRE-TOUT-AUTRE-OBJET}"] = 'N'; + _inventory.deselectObject(); + return true; + } else if (*event == 11 && currentGameTime() < 3) { + // Closed + displayMessageBoxWarp(2); + return false; + } else { + return true; + } +} + +FILTER_EVENT(4, 12_13_14) { + if (*event != 34131 && *event != 34132) { + // Not for us + return true; + } + + if (!_inventory.selectedObject() || + _inventory.selectedObject()->idOBJ() != 130) { + // Not using scope: do nothing + return false; + } + + // Using scope + const char *video; + FixedImgCallback callback; + + if (*event == 34131) { + video = "43ZA_1"; + callback = &CryOmni3DEngine_Versailles::img_34131; + } else if (*event == 34132) { + video = "43ZB_2"; + callback = &CryOmni3DEngine_Versailles::img_34132; + } + + playInGameVideo(video); + + // Force reload of the place + if (_nextPlaceId == -1u) { + _nextPlaceId = _currentPlaceId; + } + + handleFixedImg(callback); + + // Don't pass the event: it has been handled + return false; +} + +FILTER_EVENT(4, 15) { + if (*event == 17 && (_dialogsMan["BONTEMPS-VU-PAPIER-CROISSY"] == 'N' || + _dialogsMan["BONTEMPS-VU-PAMPHLET-GOUVERNEMENT"] == 'N')) { + // Closed + displayMessageBoxWarp(2); + return false; + } + + return true; +} + +FILTER_EVENT(4, 16) { + if (*event == 24161 && _inventory.selectedObject()) { + unsigned int idOBJ = _inventory.selectedObject()->idOBJ(); + if (idOBJ == 124) { + _dialogsMan["{JOUEUR-DONNE-REPAS}"] = 'Y'; + } else { + _dialogsMan["{JOUEUR-MONTRE-TOUT-AUTRE-OBJET}"] = 'Y'; + } + _dialogsMan.play("41X2_CRO"); + + _forcePaletteUpdate = true; + // Force reload of the place + if (_nextPlaceId == -1u) { + _nextPlaceId = _currentPlaceId; + } + + _dialogsMan["{JOUEUR-DONNE-REPAS}"] = 'N'; + _dialogsMan["{JOUEUR-MONTRE-TOUT-AUTRE-OBJET}"] = 'N'; + + if (idOBJ == 124) { + _inventory.removeByNameID(124); + playInGameVideo("41X2_CR1"); + setGameTime(2, 4); + } + _inventory.deselectObject(); + return true; + } else if (*event == 34162) { + if (!_inventory.inInventoryByNameID(127)) { + collectObject(127); + _forcePaletteUpdate = true; + } else { + // Nothing there anymore + displayMessageBoxWarp(21); + } + + // Don't pass the event: it has been handled + return false; + } + return true; +} + +FILTER_EVENT(4, 17) { + if (*event == 34171) { + collectObject(130); + setPlaceState(17, 1); + return false; + } else if (*event == 34172) { + unsigned int fakePlaceId = getFakeTransition(*event); + fakeTransition(fakePlaceId); + handleFixedImg(&CryOmni3DEngine_Versailles::img_34172); + return false; + } else if (*event == 34173) { + handleFixedImg(&CryOmni3DEngine_Versailles::img_34173); + return false; + } else if (*event == 34174) { + handleFixedImg(&CryOmni3DEngine_Versailles::img_34174); + return false; + } + + return true; +} + #undef FILTER_EVENT #undef INIT_PLACE |