Initial commit
This commit is contained in:
476
engines/hadesch/rooms/quiz.cpp
Normal file
476
engines/hadesch/rooms/quiz.cpp
Normal file
@@ -0,0 +1,476 @@
|
||||
/* 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/>.
|
||||
*
|
||||
* Copyright 2020 Google
|
||||
*
|
||||
*/
|
||||
#include "hadesch/hadesch.h"
|
||||
#include "hadesch/video.h"
|
||||
#include "hadesch/ambient.h"
|
||||
|
||||
namespace Hadesch {
|
||||
|
||||
static const char *kQuestionBackground = "OverlayAnim";
|
||||
static const char *kHadesEyes = "HadesEyesAnim";
|
||||
static const char *kCounter = "CounterAnim";
|
||||
|
||||
enum {
|
||||
kBackgroundZ = 10000,
|
||||
kZeusLightAnimZ = 900,
|
||||
kHadesEyesZ = 850,
|
||||
kHadesAndZeusAnimZ = 850,
|
||||
kBigItemZ = 800,
|
||||
kSmallItemZ = 800,
|
||||
kFlameAnimZ = 800,
|
||||
kFlameBurstAnimZ = 799,
|
||||
kOverlayAnimZ = 550,
|
||||
kQuestionZ = 500,
|
||||
kCounterAnimZ = 549
|
||||
};
|
||||
|
||||
static const char *questNames[] = {
|
||||
"None",
|
||||
"Crete",
|
||||
"Troy",
|
||||
"Medusa",
|
||||
"RescuePhil",
|
||||
"EndGame"
|
||||
};
|
||||
|
||||
static const char *statueNames[] = {
|
||||
"Bacchus",
|
||||
"Hermes",
|
||||
"Zeus",
|
||||
"Poseidon",
|
||||
"Ares",
|
||||
"Aphrodite",
|
||||
"Apollo",
|
||||
"Artemis",
|
||||
"Demeter",
|
||||
"Athena",
|
||||
"Hera",
|
||||
"Hephaestus",
|
||||
};
|
||||
|
||||
static const char *hadesIntroVideos[] = {
|
||||
"H0020bA0",
|
||||
"H0020bG0",
|
||||
"H0020bH0",
|
||||
"H0020bD0",
|
||||
"H0020bE0",
|
||||
"H0020bF0"
|
||||
};
|
||||
|
||||
static const TranscribedSound h0090_names[] = {
|
||||
{ "H0090wF0", _hs("Congratulations. You've shown Mr Sour Grapes") },
|
||||
{ "H0090wA0", _hs("The enveloppe, please. And the winner is ... you. Hey, good job. That's showing him") },
|
||||
{ "H0090wB0", _hs("Way to go") },
|
||||
// Difficult to hear. Please someone check after me
|
||||
{ "H0090wE0", _hs("You're amazing. Or Hades is hard under the gollar") }
|
||||
};
|
||||
|
||||
static const int kNumQuestions = 4;
|
||||
static const int kNumAnswers = 5;
|
||||
|
||||
enum {
|
||||
kZeusStingerFinished = 30006,
|
||||
kZeusGreatFinished = 30007,
|
||||
kHadesVideoFinished = 30008,
|
||||
kFirstQuestion = 30010,
|
||||
kHadesQuestionVideoFinished = 30011,
|
||||
kHadesJokeVideoFinished = 30012,
|
||||
kHadesNagging = 30013,
|
||||
kHadesNaggingCleanup = 30014,
|
||||
kNextQuestion = 30015,
|
||||
kNextQuestionAfterFail = 30016,
|
||||
kBuzzerFinished = 30017,
|
||||
kDingFinished = 30018,
|
||||
kHadesFirstLaugh = 30019,
|
||||
kHadesInstructions = 30020,
|
||||
kFinished = 30028,
|
||||
kBigItemSwitchToLoop = 1030001
|
||||
};
|
||||
|
||||
class QuizHandler : public Handler {
|
||||
public:
|
||||
QuizHandler() {
|
||||
}
|
||||
|
||||
void handleClick(const Common::String &name) override {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
for (int ansidx = 0; ansidx < kNumAnswers; ansidx++) {
|
||||
if (name == Common::String::format("A%d", ansidx + 1)) {
|
||||
nextQuestion(ansidx);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void handleEvent(int eventId) override {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
Persistent *persistent = g_vm->getPersistent();
|
||||
switch (eventId) {
|
||||
case kBigItemSwitchToLoop:
|
||||
room->playAnimWithSFX(
|
||||
_bigItem, "SpinningItemSnd", kBigItemZ, PlayAnimParams::loop().partial(4, -1));
|
||||
break;
|
||||
case kZeusStingerFinished:
|
||||
room->playVideo(_zeusGreat, 0, kZeusGreatFinished);
|
||||
break;
|
||||
case kZeusGreatFinished:
|
||||
room->stopAnim(_bigItem);
|
||||
room->playVideo(_hcQuest.get(_questName, "HadesBurst"), kHadesEyesZ,
|
||||
kHadesVideoFinished);
|
||||
break;
|
||||
case kHadesVideoFinished:
|
||||
room->selectFrame(kQuestionBackground, kOverlayAnimZ, 0);
|
||||
room->playAnimLoop("FlameAnim", kFlameAnimZ);
|
||||
room->playSFXLoop("FlameSnd");
|
||||
room->playMusicLoop("AmbientQuestionMusic");
|
||||
smallAnim();
|
||||
playHadesVideo(hadesIntroVideos[g_vm->getRnd().getRandomNumberRng(0, ARRAYSIZE(hadesIntroVideos) - 1)],
|
||||
kFirstQuestion);
|
||||
break;
|
||||
case kNextQuestion:
|
||||
case kNextQuestionAfterFail:
|
||||
killQuestion();
|
||||
if (_currentQuestion == kNumQuestions - 1) {
|
||||
room->stopAnim("AmbientQuestionMusic");
|
||||
switch (_rightAnswerCount) {
|
||||
case 0:
|
||||
playHadesVideo(Common::String::format("H0090b%c0", 'E' + g_vm->getRnd().getRandomNumberRng(0, 2)),
|
||||
kFinished);
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
playHadesVideo(Common::String::format("H0090b%c0", 'B' + g_vm->getRnd().getRandomNumberRng(0, 2)),
|
||||
kFinished);
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
int v6 = g_vm->getRnd().getRandomNumberRng(0, 3);
|
||||
hadesAndZeus(h0090_names[v6], kFinished);
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
_currentQuestion++;
|
||||
/* Fallthrough */
|
||||
case kFirstQuestion:
|
||||
_pauseMouseover = false;
|
||||
memset(_frames, 0, sizeof (_frames));
|
||||
smallAnim();
|
||||
renderQuestion();
|
||||
room->enableMouse();
|
||||
_hadesCancelableVideo = true;
|
||||
playHadesVideo(getQuestionAttribute("HQuestion"), kHadesQuestionVideoFinished);
|
||||
break;
|
||||
case kHadesQuestionVideoFinished:
|
||||
playHadesVideo(getQuestionAttribute("HJoke"), kHadesJokeVideoFinished);
|
||||
break;
|
||||
case kHadesJokeVideoFinished:
|
||||
room->selectFrame(kHadesEyes, kHadesEyesZ, 0);
|
||||
_hadesIsFree = true;
|
||||
_hadesCancelableVideo = false;
|
||||
break;
|
||||
case kDingFinished:
|
||||
playHadesVideo(Common::String::format("H0080b%c0", 'A' + (_hades_dislike_counter % 5)),
|
||||
kNextQuestion);
|
||||
_hades_dislike_counter++;
|
||||
_rightAnswerCount++;
|
||||
break;
|
||||
|
||||
case kHadesFirstLaugh:
|
||||
hadesAndZeus(TranscribedSound::make("ZeusNotFair", "Hold on, Hades. That's not fair. You've never explained the rules. That doesn't count"),
|
||||
kHadesInstructions);
|
||||
_hadesIsFree = false;
|
||||
break;
|
||||
|
||||
case kHadesInstructions:
|
||||
hadesAndZeusEnd();
|
||||
room->playAnimWithSFX("FlameBurstAnim", "FlameBurstSnd", kFlameBurstAnimZ,
|
||||
PlayAnimParams::disappear(), 30021);
|
||||
_shrinkLevel--;
|
||||
break;
|
||||
|
||||
case kHadesNagging:
|
||||
if (_hadesIsFree) {
|
||||
playHadesVideo(Common::String::format("H0050b%c0",
|
||||
_naggingCounter + 'A'), kHadesNaggingCleanup);
|
||||
_naggingCounter = (_naggingCounter + 1) % 8;
|
||||
}
|
||||
break;
|
||||
|
||||
case 30021:
|
||||
playHadesVideo("HadesInstructions", 30022);
|
||||
break;
|
||||
|
||||
case 30022:
|
||||
room->selectFrame(kHadesEyes, kHadesEyesZ, 0);
|
||||
room->enableMouse();
|
||||
_hadesIsFree = true;
|
||||
memset(_frames, 0, sizeof (_frames));
|
||||
renderQuestion();
|
||||
break;
|
||||
|
||||
case kHadesNaggingCleanup:
|
||||
room->selectFrame(kHadesEyes, kHadesEyesZ, 0);
|
||||
_hadesIsFree = true;
|
||||
break;
|
||||
|
||||
case kBuzzerFinished:
|
||||
room->playAnimWithSFX("FlameBurstAnim", "FlameBurstSnd", kFlameBurstAnimZ,
|
||||
PlayAnimParams::disappear());
|
||||
_shrinkLevel++;
|
||||
if (_wrongAnswerCount == 0) {
|
||||
playHadesVideo("HadesLaugh", kHadesFirstLaugh);
|
||||
} else {
|
||||
playHadesVideo(Common::String::format("H0040b%c0", 'A' + (_hades_like_counter % 5)),
|
||||
kNextQuestionAfterFail);
|
||||
_hades_like_counter++;
|
||||
}
|
||||
_wrongAnswerCount++;
|
||||
break;
|
||||
case kFinished:
|
||||
persistent->_powerLevel[persistent->_quest-kCreteQuest] = countLevel();
|
||||
g_vm->moveToRoom(kWallOfFameRoom);
|
||||
persistent->_quest = (Quest) (persistent->_quest + 1);
|
||||
persistent->clearInventory();
|
||||
persistent->_doQuestIntro = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void handleMouseOver(const Common::String &name) override {
|
||||
if (_pauseMouseover)
|
||||
return;
|
||||
for (int ansidx = 0; ansidx < kNumAnswers; ansidx++) {
|
||||
_frames[ansidx] = (name == Common::String::format("A%d", ansidx + 1)) ? 1 : 0;
|
||||
}
|
||||
renderQuestion();
|
||||
}
|
||||
|
||||
void handleMouseOut(const Common::String &name) override {
|
||||
if (_pauseMouseover)
|
||||
return;
|
||||
memset(_frames, 0, sizeof (_frames));
|
||||
renderQuestion();
|
||||
}
|
||||
|
||||
void prepareRoom() override {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
Persistent *persistent = g_vm->getPersistent();
|
||||
Quest quest = persistent->_quest;
|
||||
room->loadHotZones("HadesCh.HOT", true);
|
||||
room->addStaticLayer("Background", kBackgroundZ);
|
||||
room->disableHeroBelt();
|
||||
room->disableMouse();
|
||||
_questName = questNames[quest];
|
||||
_hcQuest = TextTable(
|
||||
Common::SharedPtr<Common::SeekableReadStream>(room->openFile("HcQuest.txt")), 5);
|
||||
_hcQList = TextTable(
|
||||
Common::SharedPtr<Common::SeekableReadStream>(room->openFile("HcQList.txt")), 12);
|
||||
_hchadesx = TextTable(
|
||||
Common::SharedPtr<Common::SeekableReadStream>(room->openFile("HcHadesX.txt")), 2);
|
||||
_bigItem = _hcQuest.get(_questName, "BigItem");
|
||||
_smallItem = _hcQuest.get(_questName, "SmallItem");
|
||||
_zeusGreat = _hcQuest.get(_questName, "ZeusGreat");
|
||||
room->playAnim(_bigItem, kBigItemZ,
|
||||
PlayAnimParams::keepLastFrame().partial(0, 4), kBigItemSwitchToLoop);
|
||||
room->playVideo("ZeusStingerSnd", 0, kZeusStingerFinished);
|
||||
Common::HashMap<Common::String, bool> touchedStatues;
|
||||
for (int statue = kBacchusStatue; statue < kNumStatues;
|
||||
statue++)
|
||||
if (persistent->_statuesTouched[statue])
|
||||
touchedStatues[statueNames[statue]] = true;
|
||||
|
||||
Common::Array<int> untouchedQuestions;
|
||||
Common::Array<int> touchedQuestions;
|
||||
|
||||
for (int i = 0; i < _hcQList.size(); i++)
|
||||
if (_hcQList.get(i, "Quest") == _questName) {
|
||||
Common::String statue = _hcQList.get(i, "Statue");
|
||||
if (touchedStatues[statue])
|
||||
touchedQuestions.push_back(i);
|
||||
else
|
||||
untouchedQuestions.push_back(i);
|
||||
}
|
||||
|
||||
Common::Array<int> candidates;
|
||||
candidates.push_back(untouchedQuestions);
|
||||
|
||||
if (candidates.size() <= kNumQuestions) {
|
||||
candidates.push_back(touchedQuestions);
|
||||
}
|
||||
|
||||
while (_chosenQuestions.size() <= kNumQuestions) {
|
||||
int x = candidates[g_vm->getRnd().getRandomNumberRng(0, candidates.size() - 1)];
|
||||
bool valid = true;
|
||||
for (unsigned i = 0; i < _chosenQuestions.size(); i++) {
|
||||
if (_chosenQuestions[i] == x) {
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!valid)
|
||||
continue;
|
||||
_chosenQuestions.push_back(x);
|
||||
}
|
||||
_currentQuestion = 0;
|
||||
_shrinkLevel = 0;
|
||||
_hadesCancelableVideo = false;
|
||||
memset(_frames, 0, sizeof (_frames));
|
||||
_hades_dislike_counter = g_vm->getRnd().getRandomBit();
|
||||
_hades_like_counter = g_vm->getRnd().getRandomBit();
|
||||
_naggingCounter = g_vm->getRnd().getRandomBit();
|
||||
g_vm->addTimer(kHadesNagging, 5000, -1);
|
||||
_rightAnswerCount = 0;
|
||||
_wrongAnswerCount = 0;
|
||||
_pauseMouseover = false;
|
||||
_hadesIsFree = false;
|
||||
}
|
||||
|
||||
private:
|
||||
int countLevel() {
|
||||
switch (_rightAnswerCount) {
|
||||
case 0:
|
||||
return 1;
|
||||
case 1:
|
||||
case 2:
|
||||
return 2;
|
||||
case 3:
|
||||
case 4:
|
||||
default:
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
void killQuestion() {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
room->stopAnim(getQuestionAttribute("Question"));
|
||||
for (int ansidx = 0; ansidx < kNumAnswers; ansidx++) {
|
||||
room->stopAnim(getQuestionAttribute(Common::String::format("A%d", ansidx + 1)));
|
||||
}
|
||||
}
|
||||
void renderQuestion() {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
room->selectFrame(kCounter, kCounterAnimZ, _currentQuestion);
|
||||
room->selectFrame(getQuestionAttribute("Question"), kQuestionZ, 0);
|
||||
Common::Point q0, qstep;
|
||||
if (getQuestionAttribute("PrePlaced") == "0") {
|
||||
q0 = Common::Point(0, 256);
|
||||
qstep = Common::Point(0, 22);
|
||||
}
|
||||
for (int ansidx = 0; ansidx < kNumAnswers; ansidx++) {
|
||||
room->selectFrame(getQuestionAttribute(Common::String::format("A%d", ansidx + 1)), kQuestionZ,
|
||||
_frames[ansidx], q0 + ansidx * qstep);
|
||||
}
|
||||
}
|
||||
|
||||
void smallAnim() {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
room->playAnim(_smallItem, kSmallItemZ,
|
||||
PlayAnimParams::loop().partial(_shrinkLevel * 30, _shrinkLevel * 30 + 29),
|
||||
EventHandlerWrapper());
|
||||
}
|
||||
|
||||
Common::String getQuestionAttribute(const Common::String &name) {
|
||||
return _hcQList.get(_chosenQuestions[_currentQuestion], name);
|
||||
}
|
||||
|
||||
void playHadesVideo(const Common::String &name, int eventId) {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
int x = 0;
|
||||
if (name == "HadesInstructions" || name == "HadesLaugh") {
|
||||
x = 110;
|
||||
} else
|
||||
x = _hchadesx.get(name, "X").asUint64();
|
||||
room->stopAnim(kHadesEyes);
|
||||
room->stopAnim("HadesAndZeusAnim");
|
||||
room->playVideo(name, kHadesEyesZ, eventId, Common::Point(x, 0));
|
||||
_hadesIsFree = false;
|
||||
}
|
||||
|
||||
int getRightAnswer() {
|
||||
return (int) getQuestionAttribute("RightAnswer").asUint64() - 1;
|
||||
}
|
||||
|
||||
void nextQuestion(int selected) {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
room->disableMouse();
|
||||
if (_hadesCancelableVideo)
|
||||
room->cancelVideo();
|
||||
_hadesCancelableVideo = false;
|
||||
_hadesIsFree = false;
|
||||
room->selectFrame(kHadesEyes, kHadesEyesZ, 0);
|
||||
if (selected == getRightAnswer())
|
||||
room->playSFX("DingSnd", kDingFinished);
|
||||
else
|
||||
room->playSFX("BuzzerSnd", kBuzzerFinished);
|
||||
memset(_frames, 0, sizeof (_frames));
|
||||
for (int ansidx = 0; ansidx < kNumAnswers; ansidx++) {
|
||||
_frames[ansidx] = 5;
|
||||
}
|
||||
if (selected == getRightAnswer() || _wrongAnswerCount != 0) {
|
||||
_frames[getRightAnswer()] = 1;
|
||||
}
|
||||
_pauseMouseover = true;
|
||||
renderQuestion();
|
||||
}
|
||||
|
||||
void hadesAndZeus(const TranscribedSound &name, int event) {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
room->playAnimWithSpeech("HadesAndZeusAnim", name, kHadesAndZeusAnimZ,
|
||||
PlayAnimParams::keepLastFrame().partial(0, 5), event);
|
||||
room->playAnim("ZeusLightAnim", kZeusLightAnimZ, PlayAnimParams::keepLastFrame());
|
||||
_hadesIsFree = false;
|
||||
}
|
||||
|
||||
void hadesAndZeusEnd() {
|
||||
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
||||
room->playAnim("HadesAndZeusAnim", kHadesAndZeusAnimZ,
|
||||
PlayAnimParams::keepLastFrame().partial(6, 11));
|
||||
room->playAnim("ZeusLightAnim", kZeusLightAnimZ, PlayAnimParams::disappear().backwards());
|
||||
}
|
||||
|
||||
TextTable _hcQuest;
|
||||
TextTable _hcQList;
|
||||
TextTable _hchadesx;
|
||||
Common::Array<int> _chosenQuestions;
|
||||
int _currentQuestion;
|
||||
int _shrinkLevel;
|
||||
int _frames[kNumAnswers];
|
||||
bool _pauseMouseover;
|
||||
int _hades_dislike_counter;
|
||||
int _hades_like_counter;
|
||||
int _rightAnswerCount;
|
||||
int _wrongAnswerCount;
|
||||
bool _hadesCancelableVideo;
|
||||
bool _hadesIsFree;
|
||||
int _naggingCounter;
|
||||
Common::String _questName;
|
||||
Common::String _bigItem, _smallItem, _zeusGreat;
|
||||
};
|
||||
|
||||
Common::SharedPtr<Hadesch::Handler> makeQuizHandler() {
|
||||
return Common::SharedPtr<Hadesch::Handler>(new QuizHandler());
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user