/* 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 *kAthenaAnim = "c8060ba0"; static const char *kLights = "c8110bb0"; // Keep in order enum { kWonPuzzle = -2, kNowhere = -1, kBubo = 0, kArtist = 1, kOrator = 2, kScholar = 3, kWarrior = 4 }; static const int kNumPuzzleElements = 5; static const struct { const char *hotname; int lights[2]; int rays[2]; } puzzleElements[kNumPuzzleElements] = { {"Bubo", { kArtist, kOrator}, {2, 1}}, {"Artist", { kNowhere, kOrator}, {6, 5}}, {"Orator", { kArtist, kScholar}, {3, 4}}, {"Scholar", { kNowhere, kWarrior}, {8, 9}}, {"Warrior", { kScholar, kWonPuzzle}, {7, 10}} }; enum { kBackgroundZ = 10000, kLightsZ = 201 }; enum { kPhilForgettingEnd = 23009, kPhilHardwareFinished = 23012, kIntroFinished = 1023001 }; class AthenaHandler : public Handler { public: AthenaHandler() { _playAreYouForgetting = true; _playAthenaTempleHardware = true; _isPuzzleWon = false; _hintTimerLength = 20000; memset(_puzzleState, 0, sizeof (_puzzleState)); } void handleClick(const Common::String &name) override { Common::SharedPtr room = g_vm->getVideoRoom(); Persistent *persistent = g_vm->getPersistent(); Quest quest = persistent->_quest; if (name == "Seriphos") { if (quest == kMedusaQuest) { if (persistent->_athenaPuzzleSolved && (!persistent->_athenaSwordTaken || !persistent->_athenaShieldTaken) && persistent->_hintsAreEnabled && _playAreYouForgetting) { _playAreYouForgetting = false; room->disableMouse(); room->playVideo("c8020ba0", 0, kPhilForgettingEnd, Common::Point(0, 216)); return; } else if (persistent->_athenaPuzzleSolved && persistent->_athenaSwordTaken && persistent->_athenaShieldTaken && !persistent->_athenaPlayedPainAndPanic ) { persistent->_athenaPlayedPainAndPanic = true; room->disableMouse(); room->fadeOut(1000, 23019); return; } else if (persistent->_athenaPuzzleSolved && !_playAthenaTempleHardware && persistent->_hintsAreEnabled) { _playAthenaTempleHardware = false; room->disableMouse(); room->playVideo("c8160ba0", 0, kPhilHardwareFinished, Common::Point(0, 216)); return; } } g_vm->moveToRoom(kSeriphosRoom); return; } if (name == "Athena") { Common::Array videos; if (quest == kMedusaQuest && !persistent->_athenaPuzzleSolved) { videos.push_back(persistent->_gender == kMale ? "c8060wa0" : "c8060wb0"); } else { videos.push_back("c8060wc0"); videos.push_back("c8060wd0"); } room->playStatueSMK(kAthenaStatue, kAthenaAnim, 1101, videos, 26, 42); return; } for (unsigned i = 0; i < kNumPuzzleElements; i++) if (name == puzzleElements[i].hotname) { handlePuzzleClick(i); return; } if (name == "Sword") { persistent->_athenaSwordTaken = true; g_vm->getHeroBelt()->placeToInventory(kSword); room->stopAnim("c8130bf0"); room->disableHotzone("Sword"); room->disableMouse(); room->playSpeech(TranscribedSound::make( "c8140wa0", "The magic sword will never leave Perseus' hand, " "so he can successfully cut off Medusa's head"), 23026); return; } if (name == "Shield") { persistent->_athenaShieldTaken = true; g_vm->getHeroBelt()->placeToInventory(kShield); room->stopAnim("c8130be0"); room->disableHotzone("Shield"); room->disableMouse(); room->playSpeech(TranscribedSound::make( "c8150wa0", "Medusa can only turn Perseus to stone if he looks directly at her. " "He'll use this shield to block her gaze"), 23027); return; } if (name == "Athena's Sword") { room->disableMouse(); room->playAnimLoop("c8010oc0", 2101); room->playVideo("c8080wa0", 0, 23043); room->playSFX("C8080eA1"); return; } if (name == "Athena's Shield") { room->disableMouse(); room->playAnimLoop("c8010ob0", 2101); room->playVideo("c8070wa0", 0, 23044); room->playSFX("C8080eA1"); return; } } void handleEvent(int eventId) override { Common::SharedPtr room = g_vm->getVideoRoom(); Persistent *persistent = g_vm->getPersistent(); switch(eventId) { case kIntroFinished: room->stopAnim(kAthenaAnim); room->playAnim("c8110ba0", 0, PlayAnimParams::disappear(), 23035); room->enableMouse(); _hintTimerLength = 20000; rescheduleHintTimer(); break; case kPhilForgettingEnd: case kPhilHardwareFinished: case 23026: case 23027: room->enableMouse(); break; case 23007: handleEvent(23010); _hintTimerLength = 40000; rescheduleHintTimer(true); break; case 23008: room->playAnim("c8140ba0", 1101, PlayAnimParams::disappear(), 23015); room->playAnim("c8150ba0", 1101, PlayAnimParams::disappear(), 23016); room->playMusic("c8130ma0", 23020); room->playSFX("c8130eb0"); room->playSFX("c8130ec0"); break; case 23010: if (persistent->_hintsAreEnabled && room->isMouseEnabled()) { room->disableMouse(); room->playVideo("c8170ba0", 0, 23011, Common::Point(0, 216)); } break; case 23011: room->enableMouse(); break; case 23015: room->playAnimKeepLastFrame("c8130bf0", 1101, 23017); room->playSFX("c8130ef0"); break; case 23016: room->playAnimKeepLastFrame("c8130be0", 1101, 23018); room->playSFX("c8130ee0"); break; case 23017: room->enableHotzone("Sword"); room->enableMouse(); break; case 23018: room->enableHotzone("Shield"); room->enableMouse(); break; case 23019: room->resetFade(); room->disableHeroBelt(); room->resetLayers(); room->addStaticLayer("c8180pa0", 9000); room->playSFX("g0261ma0", 23031); room->playSpeech(persistent->_gender == kMale ? TranscribedSound::make( "c8180wa0", "Oh no. Why did I shine that light in Athena's temple. " "I was just trying to see what the hero was doing") : TranscribedSound::make( "c8180wb0", "Oh no. Why did I shine that light in Athena's temple. " "I was just trying to see what the heroine was doing"), 23029); break; case 23029: room->playSpeech(TranscribedSound::make("c8180wc0", "Well now you can see what I'm doing: tomato heads"), 23030); break; case 23030: room->playVideo("c8180ba0", 0, 23032); break; case 23031: break; case 23032: room->selectFrame("c8180bb0", 101, 0); g_vm->moveToRoom(kSeriphosRoom); break; // TODO: lighting up of the beam: 23035/23036 are for lighting up case 23035: case 23036: room->selectFrame(LayerId(kLights, 0, "source"), kLightsZ, 0); /* Fallthrough */ case 23037: room->playAnimLoop("c8110bc0", 211); room->enableHotzone("Athena's Sword"); room->enableHotzone("Athena's Shield"); for (unsigned i = 0; i < kNumPuzzleElements; i++) room->enableHotzone(puzzleElements[i].hotname); break; case 23020: room->playAnim("c8130bd0", 0, PlayAnimParams::disappear(), 23041); /*Fallthrough */ case 23038: g_vm->addTimer(23040, 640); g_vm->addTimer(23039, 40, 15); break; case 23039: //TODO progressive beams break; case 23040: for (unsigned i = 0; i < 12; i++) room->stopAnim(LayerId(kLights, i, "internal")); room->stopAnim(LayerId(kLights, 0, "source")); room->stopAnim("c8110bc0"); break; case 23043: room->stopAnim("c8010oc0"); room->enableMouse(); break; case 23044: room->stopAnim("c8010ob0"); room->enableMouse(); break; } } void prepareRoom() override { Common::SharedPtr room = g_vm->getVideoRoom(); Persistent *persistent = g_vm->getPersistent(); Quest quest = persistent->_quest; room->loadHotZones("Athena.HOT", false); room->addStaticLayer("c8010pa0", kBackgroundZ); room->addStaticLayer("c8010ta0", 601); room->enableHotzone("Athena"); room->enableHotzone("Seriphos"); if (quest == kMedusaQuest && !persistent->_athenaPuzzleSolved) { persistent->_athenaIntroPlayed = true; room->disableMouse(); room->playVideo(persistent->_gender == kMale ? "c8040wa0" : "c8040wb0", 1101, kIntroFinished); room->playAnim(kAthenaAnim, 1101, PlayAnimParams::loop()); room->playMusic("c8040ma0", 23013); } if (!persistent->_athenaShieldTaken) { if (persistent->_athenaPuzzleSolved) { room->selectFrame("c8130be0", 1101, 4); room->enableHotzone("Shield"); } else { room->selectFrame("c8150ba0", 1101, 0); } } if (!persistent->_athenaSwordTaken) { if (persistent->_athenaPuzzleSolved) { room->selectFrame("c8130bf0", 1101, 7); room->enableHotzone("Sword"); } else { room->selectFrame("c8140ba0", 1101, 0); } } room->playAnimLoop("c8030ba0", 201); g_vm->getHeroBelt()->setColour(HeroBelt::kCool); } private: void rescheduleHintTimer(bool isInHandler = false) { Persistent *persistent = g_vm->getPersistent(); if (!isInHandler) g_vm->cancelTimer(23007); if (!persistent->_athenaPuzzleSolved) g_vm->addTimer(23007, _hintTimerLength); } void handlePuzzleClick(int num) { Common::SharedPtr room = g_vm->getVideoRoom(); Persistent *persistent = g_vm->getPersistent(); rescheduleHintTimer(); _puzzleState[num] = (_puzzleState[num] + 1) % 3; memset(_isPuzzleLit, 0, sizeof (_isPuzzleLit)); _isPuzzleLit[0] = true; bool done = false; while (!done) { done = true; for (unsigned i = 0; i < kNumPuzzleElements; i++) if (_puzzleState[i] != 0 && _isPuzzleLit[i] && puzzleElements[i].lights[_puzzleState[i] - 1] >= 0 && !_isPuzzleLit[puzzleElements[i].lights[_puzzleState[i] - 1]]) { _isPuzzleLit[puzzleElements[i].lights[_puzzleState[i] - 1]] = true; done = false; } } for (unsigned i = 0; i < kNumPuzzleElements; i++) if (_puzzleState[i] != 0 && _isPuzzleLit[i] && puzzleElements[i].lights[_puzzleState[i] - 1] == kWonPuzzle) { _isPuzzleWon = true; break; } for (unsigned i = 0; i < kNumPuzzleElements; i++) if (!_isPuzzleLit[i]) _puzzleState[i] = 0; for (unsigned i = 0; i < 11; i++) room->stopAnim(LayerId(kLights, i, "internal")); for (unsigned i = 0; i < kNumPuzzleElements; i++) if (_puzzleState[i] != 0 && _isPuzzleLit[i]) { int ray = puzzleElements[i].rays[_puzzleState[i] - 1]; if (ray <= 0) continue; room->selectFrame(LayerId(kLights, ray, "internal"), kLightsZ, ray); } if (_isPuzzleLit[kArtist] && _puzzleState[kArtist] == 1) room->playAnimLoop("c8120bg0", 601); else room->stopAnim("c8120bg0"); if (_isPuzzleLit[kScholar] && _puzzleState[kScholar] == 1) room->playAnimLoop("c8120bg1", 601); else room->stopAnim("c8120bg1"); if (_isPuzzleLit[num] && _puzzleState[num]) room->playSFX("c8120ea0"); if (_isPuzzleWon) { room->selectFrame(LayerId(kLights, 11, "internal"), kLightsZ, 11); room->playSFX("C8130eA0"); g_vm->addTimer(23008, 1000); room->disableHotzone("Athena's Sword"); room->disableHotzone("Athena's Shield"); for (unsigned i = 0; i < kNumPuzzleElements; i++) room->disableHotzone(puzzleElements[i].hotname); room->disableMouse(); persistent->_athenaPuzzleSolved = true; } room->playMusicLoop( persistent->_quest != kMedusaQuest || persistent->_athenaPuzzleSolved ? "c8010ea0" : "c8110ea0"); } bool _playAreYouForgetting; bool _playAthenaTempleHardware; bool _isPuzzleLit[kNumPuzzleElements]; int _puzzleState[kNumPuzzleElements]; bool _isPuzzleWon; int _hintTimerLength; }; Common::SharedPtr makeAthenaHandler() { return Common::SharedPtr(new AthenaHandler()); } }