/* 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 . * * Copyright 2020 Google * */ #include "hadesch/hadesch.h" #include "hadesch/video.h" #include "hadesch/ambient.h" namespace Hadesch { static const char *kBackground = "background"; static const char *kHotspots = "HallTrph.hot"; static const char *kArgo = "argo"; static const char *kZeusYooHoo = "zeus yoo-hoo"; static const char *kZeusYellsPhil = "zeus yells phil"; static const char *kZeusVacationIsOver = "zeus vacation's over"; static const char *kZeusFineChoiceHero = "zeus fine choice hero"; static const char *kZeusShaftOfLightLeft = "zeus shaft of light left"; static const char *kRope = "rope"; static const char *kHerculesLintel = "hercules lintel"; static const char *kApplicationHotspots = "applicat.hot"; static const char *kApplication = "application"; static const char *kApplicationHeroine = "application heroine"; static const char *kApplicationHeroineHotzone = "heroine"; static const char *kApplicationHero = "application hero"; static const char *kApplicationHeroHotzone = "hero"; static const char *kApplicationEnterButton = "application enter button"; static const char *kApplicationEnterHotzone = "enter"; static const char *kApplicationBurntHole = "application burnt hole"; static const char *kApplicationText = "application text"; static const char *kApplicationHeroineText = "application heroine text"; static const char *kApplicationHeroText = "application hero text"; static const char *kApplicationNameText = "application name text"; static const char *kApplicationUnfurls = "application unfurls"; static const char *kApplicationUnfurlsSound = "application unfurls sound"; static const char *kApplicationRollsUpHeroine = "application rolls up heroine"; static const char *kApplicationRollsUpHero = "application rolls up hero"; static const char *kApplicationChooseHeroSound = "application choose hero sound"; static const char *kApplicationChooseHeroineSound = "application choose heroine sound"; static const char *kHadesBurstsIn = "hades bursts in"; static const char *kHadesNoMoreHeroes = "hades no more heroes got it"; static const char *kHadesNoMoreHeroines = "hades no more heroines got it"; #define kPhilWalksCenterToLeft "phil walks center to left" #define kPhilSighsLeft "phil sighs left" #define kPhilSnores "phil snores" static const char *kPhilSnoresSound = "phil snores sound"; #define kPhilRollsOver "phil rolls over" #define kPhilJumpsOffPillow "phil jumps off pillow" static const char *kPhilOfCourseIdo = "phil of course i do"; static const char *kPhilWhatAHothead = "phil what a hothead"; static const char *kPhilTimeToGetStarted = "phil time to get started"; static const char *kPhilTreasuresOfHercules = "phil treasures of hercules"; static const char *kPhilBasicInformation = "phil basic information"; static const char *kPhilFlakyPlaster = "phil flaky plaster"; static const char *kPhilGettinStarted = "phil gettin started"; static const char *kPhilToolsOfTrade = "phil tools of the trade"; static const char *kPhilHeroBelt = "phil hero belt"; static const char *kPhilHeroBeltBuckle = "phil left belt buckle"; static const char *kPhilClickAnItem = "phil click an item"; static const char *kPhilHeroPowers = "phil hero powers"; static const char *kPhilRightNotches = "phil right notches"; static const char *kPhilEyeOfFates = "phil eye of fates"; static const char *kPhilBadNews = "phil bad news"; static const char *kPhilFirstQuest = "phil first quest"; #define kPhilTakesScroll "phil takes scroll" #define kPhilDropsScroll "phil drops scroll" static const char *kPhilDaedalusNeedsHelp = "phil daedalus needs help"; static const char *kPhilOffToCrete = "phil off to crete"; static const char *kPhilArgo = "phil argo"; #define kPhilTapsFootLeft "phil taps foot left" #define kPhilYapsWithoutSound "phil yaps without sound" static const char *kMugshot = "mug shot"; static const char *kMugshotSound = "mug shot sound"; static const char *kPanicAndPainSting = "pain and panic sting"; #define kHeroStatue "hero statue" #define kHeroineStatue "heroine statue" static const char *kScroll = "scroll"; static const char *kScrollSound = "scroll sound"; static const char *kHeroBelt = "hero belt"; static const char *kHeroBeltUpSound = "hero belt up sound"; static const char *kHeroBeltDownSound = "hero belt down sound"; static const char *herculesRoomElements[] = { "mares", "cattle", "girdle", "horns", "hydra", "bull", "lion", "apples", "stables", "boar", "birds", "cerberus", "hercules", }; static const char *allPhils[] = { "phil walks left to center", kPhilWalksCenterToLeft, "phil faces backward left", kPhilSighsLeft, kPhilTapsFootLeft, "phil dusts left", "phil dusts center", kPhilSnores, kPhilRollsOver, kPhilJumpsOffPillow, kPhilYapsWithoutSound, kPhilTakesScroll, kPhilDropsScroll, kPhilSighsLeft, "phil scans left" }; static const char *powerLevelNames[] = { "thunderbolt", "trojan horse", "owl" }; static const char *zeusComments[] = { "minotaur", "medusa", "trojan armor", "cyclops", kHeroStatue, kHeroineStatue }; enum { kPhilJokeEvent = 19003, kPhilNewQuestScroll = 1019020, kPhilBecomesIdle = 1019025, kPhilJokeEventCleanup = 1019029, kPhilRereadDropScroll = 1019030 }; enum { kBackgroundZ = 10000, kQuestOverlayZ = 925, kMugshotZ = 900, kScrollZ = 900, kShaftOfLightLeftZ = 500, kShaftOfLightRightZ = 500, kTrophyZ = 450, kPhilZ = 400, kApplicationZ = 300, kApplicationButtonZ = 299, kSoundOnlyZ = 0, // TODO: figure proper values kHadesVideoZ = 0, kHeroBeltZ = 0, kGlowZ = 0 }; Common::String nameQuest() { Persistent *persistent = g_vm->getPersistent(); switch(persistent->_quest) { case kNoQuest: return ""; case kCreteQuest: return "crete quest"; case kTroyQuest: return "troy quest"; case kMedusaQuest: return "medusa quest"; case kRescuePhilQuest: return "rescue phil quest"; case kEndGame: return "finished game"; // To silence warning case kNumQuests: return ""; } return ""; } Common::String getShaftOfLightRight() { Persistent *persistent = g_vm->getPersistent(); if (persistent->_quest == kEndGame) return "zeus shaft of light right"; return "zeus shaft of light " + nameQuest(); } class WallOfFameHandler : public Handler { public: WallOfFameHandler() { bool isNewGame = !g_vm->isRoomVisited(kWallOfFameRoom); Persistent *persistent = g_vm->getPersistent(); if (isNewGame) { _gender = kUnknown; _philIsOnTheRight = false; } else { _gender = persistent->_gender; _philIsOnTheRight = true; } _isEnterMouseover = false; _philWalkPhase = 0; _philIsBusy = isNewGame; _endGameOutro = false; _applicationIsActive = false; _philSaidDoingGreat = false; } void handleClick(const Common::String &hotname) override { Common::SharedPtr room = g_vm->getVideoRoom(); Persistent *persistent = g_vm->getPersistent(); Quest quest = persistent->_quest; if (hotname == kApplicationHeroineHotzone) { room->selectFrame(kApplicationHeroine, kApplicationButtonZ, 1); room->selectFrame(kApplicationHero, kApplicationButtonZ, 0); room->playSFX(kApplicationChooseHeroineSound); _gender = kFemale; computeEnter(); return; } if (hotname == kApplicationHeroHotzone) { room->selectFrame(kApplicationHeroine, kApplicationButtonZ, 0); room->selectFrame(kApplicationHero, kApplicationButtonZ, 1); room->playSFX(kApplicationChooseHeroSound); _gender = kMale; computeEnter(); return; } if (hotname == kApplicationEnterHotzone) { pressEnter(); return; } if (hotname == "argo") { g_vm->moveToRoom(kArgoRoom); return; } for (unsigned i = 0; i < sizeof (herculesRoomElements) / sizeof(herculesRoomElements[0]); i++) if (hotname == herculesRoomElements[i]) { room->disableMouse(); room->playAnimKeepLastFrame(hotname + " glow", kGlowZ); room->playSFX("click"); room->playVideo("zeus " + hotname, kSoundOnlyZ, 1019026); return; } for (unsigned power = 0; power < ARRAYSIZE(powerLevelNames); power++) { if (hotname.matchString(Common::String::format("%s#", powerLevelNames[power]))) { Common::String pl(powerLevelNames[power]); room->playSFX("click"); if (strcmp(powerLevelNames[power], "thunderbolt") == 0) room->playSFX("thunder sound"); zeusCommentRight("zeus " + pl); return; } } for (unsigned i = 0; i < sizeof (zeusComments) / sizeof(zeusComments[0]); i++) if (hotname == zeusComments[i]) { room->playSFX("click"); zeusCommentRight(Common::String("zeus ") + hotname); return; } if (hotname == "typhon") { room->playSFX("click"); zeusCommentRight(persistent->_gender == kFemale ? "zeus typhon heroine" : "zeus typhon hero"); return; } if (hotname == "phil" && quest >= kCreteQuest && quest <= kMedusaQuest) { philBecomesListening(); playPhilVideo(Common::String("phil reread ") + nameQuest(), kPhilRereadDropScroll, Common::Point(22, 301)); return; } if (hotname == "hades note") { g_vm->cancelTimer(19048); handleEvent(19048); return; } if (hotname == "hades note popup background" || hotname == "hades note popup background2") { room->popHotZones(); room->setPannable(true); room->stopAnim("hades note popup"); room->stopAnim("hades note text"); room->stopAnim("hades note"); if (persistent->_hintsAreEnabled) { zeusCommentRight("zeus counting on ya"); } room->setHotzoneEnabled("argo", true); return; } if (hotname == "monster frieze") { g_vm->moveToRoom(kMonsterPuzzle); return; } if (hotname == "ferryman frieze") { g_vm->moveToRoom(kFerrymanPuzzle); return; } /* TODO: MNSH: medusa frieze MNSH: trojan horse frieze MNSH: labyrinth frieze */ } void handleMouseOver(const Common::String &hotname) override { Persistent *persistent = g_vm->getPersistent(); if (hotname == kApplicationEnterHotzone) { _isEnterMouseover = true; computeEnter(); return; } if (persistent->_quest <= kMedusaQuest && (hotname == "labyrinth frieze" || hotname == "trojan horse frieze")) { if (_philIsBusy) return; _philIsBusy = true; if (hotname == "labyrinth frieze") playPhilVideo("phil labyrinth frieze", kPhilBecomesIdle, Common::Point(40, 324)); // state 51 else playPhilVideo("phil trojan horse frieze", kPhilBecomesIdle, Common::Point(14, 320)); // state 52 return; } if (hotname.hasSuffix(" frieze")) { zeusCommentRight("zeus " + hotname, true); return; } } void handleMouseOut(const Common::String &hotname) override { if (hotname == kApplicationEnterHotzone) { _isEnterMouseover = false; computeEnter(); return; } } void handleEvent(int eventId) override { Common::SharedPtr room = g_vm->getVideoRoom(); Persistent *persistent = g_vm->getPersistent(); Quest quest = persistent->_quest; switch (eventId) { case 19004: g_vm->addSkippableTimer(19005, 7000); room->playAnim(kZeusShaftOfLightLeft, kShaftOfLightLeftZ, PlayAnimParams::keepLastFrame().speed(500)); room->playVideo(kZeusYooHoo, kSoundOnlyZ, 19701); // zeus yoo-hoo break; case 19005: playPhilAnimSFX(kPhilRollsOver, 1019001, Common::Point(-26, 2)); // state 1 break; case 19011: room->playVideo(kZeusVacationIsOver, kSoundOnlyZ, 19012); break; case 19012: playPhilVideo(kPhilOfCourseIdo, 1019002, Common::Point(30, 304)); // state 5 break; case 1019002: displayPhilIdle(); room->playVideo(kZeusFineChoiceHero, kSoundOnlyZ, 19013); break; case 19013: room->playAnim(kZeusShaftOfLightLeft, kShaftOfLightLeftZ, PlayAnimParams::disappear().backwards().speed(500)); room->setLayerEnabled(kRope, false); playPhilVideo(kPhilBasicInformation, 1019003, Common::Point(-4, 2)); // state 6 break; case 19016: room->addStaticLayer(kApplicationBurntHole, kApplicationButtonZ); room->playVideo(persistent->_gender == kFemale ? kHadesNoMoreHeroines : kHadesNoMoreHeroes, kHadesVideoZ, 19018, Common::Point(207, 103)); break; case 19018: applicationClose(); break; case 19019: playPhilVideo(kPhilWhatAHothead, 1019005, Common::Point(40, 327)); // state 7 break; case 1019001: cancelAllPhils(); playPhilAnimSFX(kPhilJumpsOffPillow, -1, Common::Point(-26, 2)); // state 4 room->playVideo(kZeusYellsPhil, kSoundOnlyZ, 19011); break; case 1019003: room->setLayerEnabled(kRope, true); displayPhilIdle(); room->playAnimWithSFX( kApplicationUnfurls, kApplicationUnfurlsSound, kApplicationZ, PlayAnimParams::disappear().speed(200), 1019004); break; case 1019004: room->enableMouse(); startApplication(); break; case 1019005: playPhilVideo(kPhilTimeToGetStarted, 1019006, Common::Point(36, 319)); // state 8 break; case 1019006: playPhilVideo(kPhilTreasuresOfHercules, 1019007, Common::Point(40, 323)); // state 9 break; case 1019007: displayPhilIdle(); room->panRightAnim(1019008); break; case 1019008: _philIsOnTheRight = true; updatePhilHotzone(); playPhilVideo(kPhilFlakyPlaster, 1019009, Common::Point(0, 0)); //state 10 break; case 1019009: playPhilVideo(kPhilGettinStarted, 1019010, Common::Point(14, 324)); //state 11 break; case 1019010: room->disableHeroBelt(); playPhilVideo(kPhilToolsOfTrade, 1019011, Common::Point(40, 320)); //state 12 break; case 1019011: displayPhilYap(); room->playAnimWithSFX( kHeroBelt, kHeroBeltUpSound, kHeroBeltZ, PlayAnimParams::keepLastFrame().partial(0, 9), 19022, kOffsetRightRoom); break; case 19022: room->playVideo(kPhilHeroBelt, kPhilZ, 1019012); // state 13 break; case 1019012: room->playVideo(kPhilHeroBeltBuckle, kPhilZ, 1019013); // state 14 break; case 1019013: room->selectFrame(kHeroBelt, kHeroBeltZ, 10, kOffsetRightRoom); room->playSFX("hero belt items highlight sound"); room->playVideo(kPhilClickAnItem, kPhilZ, 1019014); // state 15 break; case 1019014: room->selectFrame(kHeroBelt, kHeroBeltZ, 11, kOffsetRightRoom); room->playSFX("hero belt items highlight sound"); room->playVideo(kPhilHeroPowers, kPhilZ, 1019015); // state 16 break; case 1019015: room->selectFrame(kHeroBelt, kHeroBeltZ, 12, kOffsetRightRoom); room->playSFX("hero belt items highlight sound"); g_vm->addTimer(19029, 4000); room->playVideo(kPhilRightNotches, kPhilZ, 1019016); // state 17 break; case 1019016: g_vm->cancelTimer(19029); room->playAnimWithSFX( kHeroBelt, kHeroBeltDownSound, kHeroBeltZ, PlayAnimParams::disappear().partial(9, 0), 1019017, kOffsetRightRoom); break; case 1019017: room->enableHeroBelt(); playPhilVideo(kPhilEyeOfFates, 1019018, Common::Point(-8, 144)); // state 18 break; case 1019018: room->playSFX(kPanicAndPainSting); playPhilVideo(kPhilBadNews, 1019019, Common::Point(14, 320)); // state 19 break; case 1019019: displayPhilIdle(); room->playAnimWithSFX(kMugshot, kMugshotSound, kMugshotZ, PlayAnimParams::keepLastFrame(), 19006, kOffsetRightRoom); break; case 19006: room->playAnimWithSFX(kScroll, kScrollSound, kScrollZ, PlayAnimParams::keepLastFrame(), 19009, kOffsetRightRoom); break; case 19009: playPhilVideo(kPhilFirstQuest, kPhilNewQuestScroll, Common::Point(40, 324)); // state 21 break; case kPhilNewQuestScroll: room->selectFrame(kScroll, kScrollZ, 0, kOffsetRightRoom); room->playMusic("quest intro music"); playPhilAnimSFX(kPhilTakesScroll, 1019021); // state 22 break; case 1019021: switch (quest) { default: case kCreteQuest: playPhilVideo(kPhilDaedalusNeedsHelp, 1019022, Common::Point(28, 312)); // state 24 break; case kTroyQuest: playPhilVideo("phil holy hera", 1019022, Common::Point(28, 312)); // state 29 break; case kMedusaQuest: playPhilVideo("phil who writes these things", 1019022, Common::Point(28, 312)); // state 36 break; } break; case 1019022: playPhilAnimSFX(kPhilDropsScroll, 1019023); // state 23 break; case 1019023: switch (quest) { default: case kCreteQuest: playPhilVideo(kPhilOffToCrete, 1019024, Common::Point(40, 324)); // state 25 break; case kTroyQuest: playPhilVideo("phil hourly rates", 1019033, Common::Point(28, 312)); // state 30 break; case kMedusaQuest: playPhilVideo("phil off to seriphos", kPhilBecomesIdle, Common::Point(14, 320)); // state 37 } break; case 1019024: playPhilVideo(kPhilArgo, kPhilBecomesIdle, Common::Point(40, 324)); // state 26 break; case kPhilBecomesIdle: philBecomesIdle(); break; case 1019026: room->enableMouse(); for (unsigned i = 0; i < sizeof (herculesRoomElements) / sizeof(herculesRoomElements[0]); i++) room->stopAnim(Common::String(herculesRoomElements[i]) + " glow"); break; case 1019027: if (!_philIsBusy) schedulePhilJoke(); break; case 1019028: g_vm->cancelTimer(kPhilJokeEvent); break; case kPhilJokeEvent: { if (_philIsBusy) { schedulePhilJoke(); break; } if (!_philSaidDoingGreat && quest != kCreteQuest) { _philSaidDoingGreat = true; // state 50 playPhilVideo("phil doing great", kPhilJokeEventCleanup, Common::Point(14, 320)); break; } int rnd = g_vm->getRnd().getRandomNumberRng(1, 10); debug("rnd = %d", rnd); switch(rnd) { case 1: // state 40 playPhilVideo("phil break time over", kPhilJokeEventCleanup, Common::Point(40, 320)); break; case 2: // state 41 playPhilVideo("phil back to work", kPhilJokeEventCleanup, Common::Point(14, 320)); break; case 3: // state 42 playPhilVideo("phil lets go", kPhilJokeEventCleanup, Common::Point(16, 320)); break; case 4: // state 43 playPhilAnimWithoutSound("phil scans left", kPhilJokeEventCleanup, Common::Point(-26, 2)); break; case 5: // state 44, go right if (_philWalkPhase == 3) { schedulePhilJoke(); break; } _philWalkPhase++; updatePhilHotzone(); playPhilAnimSFX("phil walks left to center", kPhilJokeEventCleanup, Common::Point(-166, +2)); break; case 6: // state 45, go left if (_philWalkPhase == 0) { schedulePhilJoke(); break; } _philWalkPhase--; updatePhilHotzone(); playPhilAnimSFX(kPhilWalksCenterToLeft, kPhilJokeEventCleanup); break; case 7: // state 46 playPhilAnimSFX("phil faces backward left", kPhilJokeEventCleanup, Common::Point(-640, 0)); break; case 8: // state 47 playPhilAnimSFX(kPhilSighsLeft, kPhilJokeEventCleanup); break; case 9: // state 48 playPhilAnimSFX(kPhilTapsFootLeft, kPhilJokeEventCleanup); break; case 10: // state 49, dusts switch (_philWalkPhase) { case 0: playPhilAnimSFX("phil dusts left", kPhilJokeEventCleanup); break; case 1: case 2: playPhilAnimSFX("phil dusts center", kPhilJokeEventCleanup, Common::Point(-166, 2)); break; case 3: schedulePhilJoke(); break; } break; } break; } case 19029: room->selectFrame(kHeroBelt, kHeroBeltZ, 13, kOffsetRightRoom); room->playSFX("hero belt items highlight sound"); break; case kPhilJokeEventCleanup: schedulePhilJoke(); break; case 19045: philBecomesIdle(); room->playAnim( getShaftOfLightRight(), kShaftOfLightRightZ, PlayAnimParams::disappear().speed(500)); room->enableMouse(); break; case kPhilRereadDropScroll: playPhilAnimSFX(kPhilDropsScroll, 19047); break; case 19047: philBecomesIdle(); break; case 19048: room->disableMouse(); room->disableHotzone("hades note"); room->enableHotzone("hades note popup"); room->disableHotzone("hades note popup background"); room->enableHotzone("hades note popup background2"); room->selectFrame("hades note popup", 150, 0, kOffsetRightRoom); room->selectFrame("hades note text", 149, 0, kOffsetRightRoom); room->playVideo("hades reads note", 0, 19049); break; case 19049: room->enableMouse(); break; case 19051: _hercules = AmbientAnim("herc blinks", "", 0, 2000, 5000, AmbientAnim::KEEP_LOOP, kOffsetRightRoom, AmbientAnim::PAN_ANY); _hercules.start(); playPhilVideo("phil that was awesome", 19052, Common::Point(14, 320)); // state 56 break; case 19052: philBecomesListening(); room->fadeOut(250, 19053); break; case 19053: _hercules.hide(); room->resetFade(); room->disableHeroBelt(); room->resetLayers(); room->disableMouse(); room->setPannable(false); room->addStaticLayer("black background", kBackgroundZ, kOffsetRightRoom); room->playVideo("hades eye of fates", 0, 19054, kOffsetRightRoom); room->playSFX("herc laughs"); room->playSFX("phil laughs"); break; case 19054: g_vm->moveToRoom(kCreditsRoom); break; case 1019031: _philWalkPhase--; updatePhilHotzone(); playPhilAnimSFX(kPhilWalksCenterToLeft, 1019032); break; case 1019032: playPhilVideo("phil lots more to do", kPhilNewQuestScroll, Common::Point(14, 312)); // state 28 break; case 1019033: playPhilVideo(persistent->_gender == kFemale ? "phil go to it heroine" : "phil go to it hero", 1019034, Common::Point(40, 324)); // state 32/31 break; case 1019034: playPhilVideo("phil off to troy", kPhilBecomesIdle, Common::Point(40, 324)); // state 33 break; case 1019035: playPhilVideo("phil sneaky devil", 1019036, Common::Point(40, 324)); // state 34 break; case 1019036: _philWalkPhase--; updatePhilHotzone(); playPhilAnimSFX(kPhilWalksCenterToLeft, 1019037); break; case 1019037: playPhilVideo("phil good work", kPhilNewQuestScroll, Common::Point(40, 324)); // state 35 break; case 19900: if (_gender != kUnknown && !_heroName.empty()) { break; } if (!_heroName.empty()) { room->playVideo("phil pick a statue", 0, 19901); break; } if (g_vm->getRnd().getRandomBit()) { room->playVideo("phil not a mind reader", 0, 19901); } else { room->playVideo("phil type in your name", 0, 19901); } break; case 19901: g_vm->addTimer(19900, 12000); break; } } void handleKeypress(uint32 code) override { Common::SharedPtr room = g_vm->getVideoRoom(); if (_applicationIsActive && room->isMouseEnabled()) { if (_heroName.size() < 18 && (('a' <= code && code <= 'z') || ('A' <= code && code <= 'Z') || code == '.' || code == '-' || code == ' ') && room->computeStringWidth("application sign-in text", _heroName + code) <= 318) { _heroName += code; room->playSFX("application click"); renderNameInApplication(); computeEnter(); return; } if (_heroName.size() > 0 && code == '\b') { _heroName.deleteLastChar(); room->playSFX("application click"); renderNameInApplication(); computeEnter(); return; } if (_heroName.size() > 0 && (code == '\r' || code == '\n')) { pressEnter(); return; } } } void prepareRoom() override { Common::SharedPtr room = g_vm->getVideoRoom(); bool newGame = !g_vm->isRoomVisited(kWallOfFameRoom); Persistent *persistent = g_vm->getPersistent(); room->loadHotZones(kHotspots, false); room->addStaticLayer(kBackground, kBackgroundZ); room->addStaticLayer(kHerculesLintel, 900); room->addStaticLayer(kRope, 900); Quest quest = persistent->_quest; if (quest != kEndGame) { room->addStaticLayer(kArgo, 950, kOffsetRightRoom); room->enableHotzone("argo"); room->playAnimLoop("argo ambient", 949, kOffsetRightRoom); } room->playAnimLoop("water ambient", 975, kOffsetRightRoom); room->playAnimLoop("hercules hall ambients", 900); room->addStaticLayer(nameQuest() + " overlay", kQuestOverlayZ, kOffsetRightRoom); if (quest == kEndGame) { const char *heroStatue = persistent->_gender == kFemale ? kHeroineStatue : kHeroStatue; room->selectFrame(heroStatue, 450, 0, kOffsetRightRoom); room->enableHotzone(heroStatue); room->setHotZoneOffset(heroStatue, kOffsetRightRoom); room->enableHotzone("monster frieze"); room->enableHotzone("ferryman frieze"); room->enableHotzone("cyclops"); room->enableHotzone("typhon"); } if (quest > kMedusaQuest) { room->enableHotzone("medusa frieze"); room->enableHotzone("medusa"); } if (quest > kTroyQuest) { room->enableHotzone("trojan horse frieze"); room->enableHotzone("trojan armor"); } if (quest > kCreteQuest) { room->enableHotzone("labyrinth frieze"); room->enableHotzone("minotaur"); } if (quest < kRescuePhilQuest) { room->enableHotzone("phil"); room->setHotZoneOffset("phil", kOffsetRightRoom); } // Hercules room for (unsigned i = 0; i < sizeof (herculesRoomElements) / sizeof(herculesRoomElements[0]); i++) room->enableHotzone(herculesRoomElements[i]); for (unsigned power = 0; power < sizeof(powerLevelNames) / sizeof(powerLevelNames[0]); power++) { int level = persistent->_powerLevel[power]; if (level > 0) { int off = (4 - level) * 30; Common::String hz = Common::String::format("%s%d", powerLevelNames[power], level); room->playAnim(powerLevelNames[power], kTrophyZ, PlayAnimParams::loop().partial(off, off + 29), -1, kOffsetRightRoom); room->enableHotzone(hz); room->setHotZoneOffset(hz, kOffsetRightRoom); } } room->selectFrame(kScroll, kScrollZ, 0, kOffsetRightRoom); room->setPannable(true); if (newGame) { room->disableMouse(); room->playAnimWithSFX(kPhilSnores, kPhilSnoresSound, kPhilZ, PlayAnimParams::loop()); //state 0 room->selectFrame(kMugshot, kMugshotZ, 0, kOffsetRightRoom); g_vm->addSkippableTimer(19004, 4000); } else if (persistent->_doQuestIntro) { persistent->_doQuestIntro = false; room->disableMouse(); switch (quest) { case kTroyQuest: _philWalkPhase = 1; playPhilVideo("phil congrats trapped minotaur", 1019031, Common::Point(14, 320)); // state 27 room->playMusic("done crete quest theme"); break; case kMedusaQuest: _philWalkPhase = 1; playPhilVideo("phil dances", 1019035, Common::Point(36, 257)); // state 38 room->playMusic("done troy quest theme"); break; case kRescuePhilQuest: g_vm->addTimer(19048, 5000, 1); room->pushHotZones("HTNote.HOT", true, kOffsetRightRoom); room->disableHotzone("hades note popup background2"); room->setPannable(false); room->enableMouse(); room->playAnimWithSFX("hades note", "hades note sound", 150, PlayAnimParams::loop(), EventHandlerWrapper(), kOffsetRightRoom); room->setHotzoneEnabled("argo", false); room->playMusic("done medusa quest theme"); _endGameOutro = true; break; case kNumQuests: // To silence warning case kEndGame: case kNoQuest: _philWalkPhase = 1; philBecomesListening(); room->playVideo("herc congratulates", 0, 19051, kOffsetRightRoom); break; case kCreteQuest: break; } room->panRightInstant(); } else { if (persistent->_quest < kRescuePhilQuest) schedulePhilJoke(); room->panRightInstant(); } renderLintel(); room->playMusicLoop("C1010eA0"); g_vm->getHeroBelt()->setColour(HeroBelt::kWarm); } ~WallOfFameHandler() override {} private: void clearNameInApplication() { Common::SharedPtr room = g_vm->getVideoRoom(); // One character more to handle possible backspace clicks. room->hideString("application sign-in text", _heroName.size() + 1); } void renderNameInApplication() { Common::SharedPtr room = g_vm->getVideoRoom(); clearNameInApplication(); room->renderString("application sign-in text", _heroName, Common::Point(202, 338), 298); } void philBecomesIdle() { _philIsBusy = false; schedulePhilJoke(); } void philBecomesBusy() { _philIsBusy = true; g_vm->cancelTimer(kPhilJokeEvent); } void philBecomesListening() { philBecomesBusy(); displayPhilIdle(); } void schedulePhilJoke() { Common::SharedPtr room = g_vm->getVideoRoom(); displayPhilIdle(); room->enableMouse(); g_vm->addTimer(kPhilJokeEvent, g_vm->getRnd().getRandomNumberRng(10000, 15000)); room->setUserPanCallback(1019028, -1, -1, 1019027); } void pressEnter() { Common::SharedPtr room = g_vm->getVideoRoom(); Persistent *persistent = g_vm->getPersistent(); // originally event 19015 if (_gender != kUnknown /*&& name != ""*/) { persistent->_gender = _gender; persistent->_heroName = _heroName; room->disableMouse(); // Or should it be music? Unclear to me room->playSFX("hades evil intro theme"); g_vm->cancelTimer(19900); room->playVideo(kHadesBurstsIn, kHadesVideoZ, 19016); } } void zeusCommentRight(const Common::String &id, bool mouseIsEnabled = false) { Common::SharedPtr room = g_vm->getVideoRoom(); if (!mouseIsEnabled) room->disableMouse(); room->playVideo(id, kSoundOnlyZ, 19045); room->playAnim( getShaftOfLightRight(), kShaftOfLightRightZ, PlayAnimParams::keepLastFrame().speed(500), -1, kOffsetRightRoom); philBecomesListening(); } Common::Point getPhilBase() const { Common::Point v; if (_philIsOnTheRight) v = Common::Point(640, 0); else v = Common::Point(26, -2); if (_philWalkPhase >= 0 && _philWalkPhase <= 3) v += Common::Point(166 * _philWalkPhase, -2 * _philWalkPhase); return v; } void playPhilVideo(const Common::String &name, int callback, const Common::Point &videoOffset) { Persistent *persistent = g_vm->getPersistent(); cancelAllPhils(); if (persistent->_quest == kRescuePhilQuest) return; g_vm->getVideoRoom()->playVideo(name, kPhilZ, callback, videoOffset + getPhilBase()); } void playPhilAnimSFX(const Common::String &name, int callback, const Common::Point videoOffset = Common::Point(0, 0)) { Persistent *persistent = g_vm->getPersistent(); cancelAllPhils(); if (persistent->_quest == kRescuePhilQuest) return; g_vm->getVideoRoom()->playAnimWithSFX( name, name + " sound", kPhilZ, PlayAnimParams::keepLastFrame(), callback, videoOffset + getPhilBase()); } void playPhilAnimWithoutSound(const Common::String &name, int callback, const Common::Point videoOffset = Common::Point(0, 0)) { Persistent *persistent = g_vm->getPersistent(); cancelAllPhils(); if (persistent->_quest == kRescuePhilQuest) return; g_vm->getVideoRoom()->playAnimKeepLastFrame( name, kPhilZ, callback, videoOffset + getPhilBase()); } void displayPhilIdle() { Persistent *persistent = g_vm->getPersistent(); cancelAllPhils(); if (persistent->_quest == kRescuePhilQuest || (!_endGameOutro && persistent->_quest == kEndGame)) return; g_vm->getVideoRoom()->selectFrame(kPhilSighsLeft, kPhilZ, 0, getPhilBase()); } void displayPhilYap() { cancelAllPhils(); g_vm->getVideoRoom()->playAnimLoop( kPhilYapsWithoutSound, kPhilZ, Common::Point(640-166, 0)); } void computeEnter() { Common::SharedPtr room = g_vm->getVideoRoom(); if (_gender == kUnknown /*|| name == ""*/) { room->selectFrame(kApplicationEnterButton, kApplicationButtonZ, 0); room->disableHotzone(kApplicationEnterHotzone); return; } room->selectFrame(kApplicationEnterButton, kApplicationButtonZ, _isEnterMouseover ? 2 : 1); room->enableHotzone(kApplicationEnterHotzone); } void startApplication() { Common::SharedPtr room = g_vm->getVideoRoom(); room->addStaticLayer(kApplication, kApplicationZ); room->selectFrame(kApplicationHeroine, kApplicationButtonZ, 0); // heroine room->selectFrame(kApplicationHero, kApplicationButtonZ, 0); // hero room->selectFrame(kApplicationEnterButton, kApplicationButtonZ, 0); room->addStaticLayer(kApplicationText, kApplicationButtonZ); room->addStaticLayer(kApplicationHeroineText, kApplicationButtonZ); room->addStaticLayer(kApplicationHeroText, kApplicationButtonZ); room->addStaticLayer(kApplicationNameText, kApplicationButtonZ); room->pushHotZones(kApplicationHotspots); room->disableHotzone(kApplicationEnterHotzone); _applicationIsActive = true; g_vm->addTimer(19900, 5000); } void applicationClose() { Common::SharedPtr room = g_vm->getVideoRoom(); Persistent *persistent = g_vm->getPersistent(); room->setLayerEnabled(kApplication, false); room->setLayerEnabled(kApplicationHeroine, false); room->setLayerEnabled(kApplicationHero, false); room->setLayerEnabled(kApplicationEnterButton, false); room->setLayerEnabled(kApplicationText, false); room->setLayerEnabled(kApplicationHeroineText, false); room->setLayerEnabled(kApplicationHeroText, false); room->setLayerEnabled(kApplicationNameText, false); room->setLayerEnabled(kApplicationBurntHole, false); room->setLayerEnabled(kApplicationUnfurls, false); room->popHotZones(); clearNameInApplication(); _applicationIsActive = false; // TODO: does it have any sound? room->playAnim(persistent->_gender == kFemale ? kApplicationRollsUpHeroine : kApplicationRollsUpHero, kApplicationZ, PlayAnimParams::disappear(), 19019); renderLintel(); } void cancelAllPhils() { Common::SharedPtr room = g_vm->getVideoRoom(); for (uint i = 0; i < ARRAYSIZE(allPhils); i++) room->stopAnim(allPhils[i]); } void updatePhilHotzone() { g_vm->getVideoRoom()->setHotZoneOffset( "phil", getPhilBase()); } void renderLintel() { Common::SharedPtr room = g_vm->getVideoRoom(); Persistent *persistent = g_vm->getPersistent(); room->renderStringCentered("player lintel text", persistent->_heroName, Common::Point(942, 19), 900, -1); } Gender _gender; bool _isEnterMouseover; bool _philIsOnTheRight; int _philWalkPhase; bool _philIsBusy; Common::U32String _heroName; AmbientAnim _hercules; bool _endGameOutro; bool _applicationIsActive; bool _philSaidDoingGreat; }; Common::SharedPtr makeWallOfFameHandler() { return Common::SharedPtr(new WallOfFameHandler()); } }