363 lines
12 KiB
C++
363 lines
12 KiB
C++
/* 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"
|
|
|
|
namespace Hadesch {
|
|
|
|
static const char *kIslandNames = "islandnames";
|
|
static const char *kMastHeadAnim = "mastheadanim";
|
|
|
|
enum {
|
|
kSkyZ = 10200,
|
|
kCloudsZ = 10100,
|
|
kWavesRightZ = 10050,
|
|
kWavesLeftZ = 10050,
|
|
kBackgroundZ = 10000,
|
|
kFlagsZ = 9000,
|
|
kMastHeadZ = 8000,
|
|
kChessPieceZ = 701,
|
|
kIslandNamesZ = 601
|
|
};
|
|
|
|
static const struct island {
|
|
const char *hotname;
|
|
const char *mouseoverAnim;
|
|
TranscribedSound nameSound;
|
|
const char *sfxSound;
|
|
RoomId roomId;
|
|
int zValue;
|
|
} islands[] = {
|
|
{"Phils", "a1030bh0", {"a1030nf0", _hs("Phil's") }, "a1030ef0", kWallOfFameRoom, 901},
|
|
{"Medusa", "a1030bf0", {"a1030nc0", _hs("Medusa Isle")}, "a1030ed0", kMedIsleRoom, 901},
|
|
{"Troy", "a1030bd0", {"a1030na0", _hs("Troy")}, "a1030eb0", kTroyRoom, 901},
|
|
{"Seriphos", "a1030be0", {"a1030nd0", _hs("Seriphos")}, "a1030ec0", kSeriphosRoom, 801},
|
|
{"Crete", "a1030bc0", {"a1030nb0", _hs("Crete")}, "a1030ea0", kCreteRoom, 801},
|
|
{"Volcano", "a1030bg0", {"a1030ne0", _hs("Volcano island")}, "a1030ee0", kVolcanoRoom, 801},
|
|
};
|
|
|
|
static const int nislands = ARRAYSIZE(islands);
|
|
|
|
static const TranscribedSound intros[] = {
|
|
{ "a1150na0", _hs("Aye, welcome onboard ladie") },
|
|
{ "a1150nb0", _hs("So, are you hero yet?") },
|
|
{ "a1150nc0", _hs("So, are you heroine yet?") },
|
|
{ "a1150nd0", _hs("So, made it back, you did? Frankly, I'm surprised") },
|
|
{ "a1150ne0", _hs("Glad I'm, you're still alive. I hate sailing alone") },
|
|
{ "a1150nf0", _hs("So where will we be headed now?") }
|
|
};
|
|
|
|
static const TranscribedSound defaultOutros[] = {
|
|
{ "a1170na0", _hs("Heave anchor") },
|
|
{ "a1170nb0", _hs("Hurry, hoist the main") },
|
|
{ "a1170nc0", _hs("All hands on deck. Man the sails") },
|
|
{ "a1170nd0", _hs("Pull her to starboard and bring her around") },
|
|
{ "a1170ne0", _hs("Pull back on that rudder. Hold her steady") }
|
|
};
|
|
|
|
enum {
|
|
kPlayIntro2 = 27001,
|
|
kPlayIntro3 = 27002,
|
|
kReturnToIdleEvent = 27003,
|
|
kIdleEvent = 27008,
|
|
kOutroFinished = 27009,
|
|
kOutroFinishedCounter = 1027001,
|
|
kMastSoundFinished = 1027002
|
|
};
|
|
|
|
static const TranscribedSound
|
|
getOutroName(RoomId dest) {
|
|
Persistent *persistent = g_vm->getPersistent();
|
|
Quest quest = persistent->_quest;
|
|
|
|
switch (dest) {
|
|
case kWallOfFameRoom:
|
|
if (!persistent->_argoSailedInQuest[dest][quest])
|
|
return TranscribedSound::make("philsfirst", "That'd be where the grand heroes and heroines of the world go to train");
|
|
break;
|
|
case kSeriphosRoom:
|
|
if ((quest == kTroyQuest || quest == kCreteQuest) && !persistent->_argoSailedInQuest[dest][quest])
|
|
return TranscribedSound::make("seriphoscretetroy", "This place be ruled by the evil tyrant king Polydectes");
|
|
if (quest == kMedusaQuest && !persistent->_argoSailedInQuest[dest][quest])
|
|
return TranscribedSound::make("seriphosperseus", "Arr, Perseus be in trouble deep. Could use a hand");
|
|
break;
|
|
case kMedIsleRoom:
|
|
if (quest == kMedusaQuest && !persistent->_argoSailedInQuest[dest][quest])
|
|
return TranscribedSound::make("medusabeware", "Beware of Medusa. She be one scary looking lady. All her mirrors be made of shatter-proof glass");
|
|
break;
|
|
case kTroyRoom:
|
|
if (!persistent->isRoomVisited(kTroyRoom))
|
|
return TranscribedSound::make("troytenyears", "For ten years now trojan and greek soldiers have been fighting that trojan war. Talk about job security");
|
|
if (quest == kTroyQuest && !persistent->_argoSailedInQuest[dest][quest])
|
|
return TranscribedSound::make("troyregards", "Send me regards to Odysseus");
|
|
if (quest > kTroyQuest && !persistent->_argoSaidTroyFinally) {
|
|
persistent->_argoSaidTroyFinally = true;
|
|
return TranscribedSound::make("troyfinally", "Finally, the trojan war be over and Helen be back with Menelaus. Now those two can fight without an interruption");
|
|
}
|
|
break;
|
|
case kCreteRoom:
|
|
if (!persistent->isRoomVisited(kCreteRoom))
|
|
return TranscribedSound::make("cretedaedalus", "This be where Daedalus, the inventor, lives");
|
|
|
|
if (quest != kCreteQuest && !persistent->_argoSaidCretePort)
|
|
return TranscribedSound::make("creteport", "Crete, the famous international port of trade");
|
|
break;
|
|
case kVolcanoRoom:
|
|
if (!persistent->isRoomVisited(kVolcanoRoom))
|
|
return TranscribedSound::make("volcanotopfirst", "Know this: should you go down there, you may not come back");
|
|
|
|
if (quest == kRescuePhilQuest && !!persistent->_argoSailedInQuest[dest][quest])
|
|
return TranscribedSound::make("volcanotopyoufirst", "Hah, many are monsters down there. Very dangerous. You go first");
|
|
break;
|
|
|
|
default:
|
|
assert(0);
|
|
}
|
|
int rnd = g_vm->getRnd().getRandomNumberRng(0, ARRAYSIZE(defaultOutros) - 1);
|
|
debug("rnd = %d", rnd);
|
|
return defaultOutros[rnd];
|
|
}
|
|
|
|
class ArgoHandler : public Handler {
|
|
public:
|
|
ArgoHandler() {
|
|
_prevId = kInvalidRoom;
|
|
_destination = kInvalidRoom;
|
|
_mastHeadIsBusy = false;
|
|
}
|
|
void handleClick(const Common::String &name) override {
|
|
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
|
_destination = kInvalidRoom;
|
|
for (unsigned i = 0; i < nislands; i++) {
|
|
if (name == islands[i].hotname) {
|
|
_destination = islands[i].roomId;
|
|
break;
|
|
}
|
|
}
|
|
if (_destination != kInvalidRoom) {
|
|
Persistent *persistent = g_vm->getPersistent();
|
|
room->disableMouse();
|
|
room->stopAnim("idlesound");
|
|
if (_destination == _prevId) {
|
|
playMastSound(TranscribedSound::make(
|
|
"currentlocation",
|
|
"Here be your current location, matie."),
|
|
kOutroFinished);
|
|
return;
|
|
}
|
|
|
|
_outroCounter = 4;
|
|
_cloudsMoving = true;
|
|
_cloudsMoveStart = g_vm->getCurrentTime();
|
|
playMastSound(getOutroName(_destination), kOutroFinishedCounter);
|
|
room->playAnimWithSFX("wavesleft", "wavesleftSFX", kWavesLeftZ,
|
|
PlayAnimParams::disappear(),
|
|
kOutroFinishedCounter);
|
|
room->playAnimWithSFX("wavesright", "wavesrightSFX", kWavesRightZ,
|
|
PlayAnimParams::disappear(),
|
|
kOutroFinishedCounter);
|
|
room->playSFX("A1030eG0", kOutroFinishedCounter);
|
|
persistent->_argoSailedInQuest[_destination][persistent->_quest] = true;
|
|
}
|
|
}
|
|
void handleEvent(int eventId) override {
|
|
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
|
switch (eventId) {
|
|
case kPlayIntro2:
|
|
playMastSound(TranscribedSound::make("intro2", "Navigate by clicking on the island you want to go to"), kPlayIntro3);
|
|
break;
|
|
case kPlayIntro3:
|
|
playMastSound(TranscribedSound::make(
|
|
"intro3",
|
|
"The map shall always show the location of the Argo in relation to the other islands in the region"),
|
|
kReturnToIdleEvent);
|
|
break;
|
|
case kReturnToIdleEvent:
|
|
_mastHeadIsBusy = false;
|
|
room->enableMouse();
|
|
break;
|
|
case kOutroFinishedCounter:
|
|
if (--_outroCounter > 0)
|
|
break;
|
|
// Fallthrough
|
|
case kOutroFinished:
|
|
room->selectFrame(kMastHeadAnim, kMastHeadZ, 0);
|
|
g_vm->moveToRoom(_destination);
|
|
break;
|
|
case kIdleEvent:
|
|
g_vm->addTimer(kIdleEvent, 30000);
|
|
if (_mastHeadIsBusy)
|
|
break;
|
|
playMastSound(TranscribedSound::make("idlesound", "And what course lies ahead for you, matie?"), kMastSoundFinished);
|
|
room->selectFrame(kMastHeadAnim, kMastHeadZ, 1);
|
|
break;
|
|
case 27301:
|
|
room->playAnimWithSpeech(kMastHeadAnim, _mastSound, kMastHeadZ,
|
|
PlayAnimParams::keepLastFrame().partial(8, 21), 27303);
|
|
break;
|
|
// 27302 was for event chaining and frame keeping
|
|
case 27303:
|
|
room->playAnim(kMastHeadAnim, kMastHeadZ,
|
|
PlayAnimParams::keepLastFrame().partial(8, 0), _mastHeadEndEvent);
|
|
break;
|
|
case kMastSoundFinished:
|
|
_mastHeadIsBusy = false;
|
|
break;
|
|
}
|
|
}
|
|
void handleMouseOver(const Common::String &name) override {
|
|
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
|
for (unsigned i = 0; i < nislands; i++) {
|
|
if (name == islands[i].hotname) {
|
|
room->selectFrame(kIslandNames, kIslandNamesZ, i);
|
|
room->playAnimKeepLastFrame(islands[i].mouseoverAnim, islands[i].zValue);
|
|
playMastSound(islands[i].nameSound);
|
|
room->playSFXLoop(islands[i].sfxSound);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void handleMouseOut(const Common::String &name) override {
|
|
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
|
for (unsigned i = 0; i < nislands; i++)
|
|
if (name == islands[i].hotname) {
|
|
if (_destination != islands[i].roomId) {
|
|
room->stopAnim(kIslandNames);
|
|
room->stopAnim(islands[i].mouseoverAnim);
|
|
}
|
|
room->stopAnim(islands[i].nameSound.soundName);
|
|
room->stopAnim(islands[i].sfxSound);
|
|
return;
|
|
}
|
|
}
|
|
|
|
void prepareRoom() override {
|
|
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
|
Persistent *persistent = g_vm->getPersistent();
|
|
_prevId = g_vm->getPreviousRoomId();
|
|
room->loadHotZones("argo.HOT");
|
|
room->addStaticLayer("background", kBackgroundZ);
|
|
Common::String sky;
|
|
int chesspiece;
|
|
Common::String bgsound;
|
|
|
|
switch (_prevId) {
|
|
default:
|
|
sky = "bluesky";
|
|
chesspiece = 0;
|
|
bgsound = "a1180ea0";
|
|
break;
|
|
case kSeriphosRoom:
|
|
sky = "pinksky";
|
|
chesspiece = 3;
|
|
bgsound = "A1070eA0";
|
|
break;
|
|
case kMedIsleRoom:
|
|
sky = "mauvesky";
|
|
chesspiece = 1;
|
|
bgsound = "a1210ea0";
|
|
break;
|
|
case kTroyRoom:
|
|
sky = "goldsky";
|
|
chesspiece = 2;
|
|
bgsound = "a1190eb0";
|
|
break;
|
|
case kCreteRoom:
|
|
sky = "bluesky";
|
|
chesspiece = 4;
|
|
bgsound = "a1180ea0";
|
|
break;
|
|
case kVolcanoRoom:
|
|
sky = "pinksky";
|
|
chesspiece = 5;
|
|
bgsound = "a1210ea0";
|
|
break;
|
|
}
|
|
room->addStaticLayer(sky, kSkyZ);
|
|
room->playMusicLoop(bgsound);
|
|
|
|
room->selectFrame("chesspiece", kChessPieceZ, chesspiece);
|
|
|
|
room->disableMouse();
|
|
// Originally event 4015
|
|
if (!persistent->isRoomVisited(kArgoRoom))
|
|
playMastSound(TranscribedSound::make(
|
|
"intro1",
|
|
"Sharpen up now, matie. You'll be on the Argo now. It's a hero of ships. It used to belong to Jason and his crew, the argonauts. And now it'll be here for you"),
|
|
kPlayIntro2);
|
|
else {
|
|
int rnd = g_vm->getRnd().getRandomNumberRng(0, ARRAYSIZE(intros) - 1);
|
|
debug("rnd = %d", rnd);
|
|
if (rnd == 1 || rnd == 2)
|
|
rnd = persistent->_gender == kFemale ? 2 : 1;
|
|
playMastSound(intros[rnd], kReturnToIdleEvent);
|
|
}
|
|
|
|
room->playAnimWithSFX("flags", "flagsSFX", kFlagsZ, PlayAnimParams::loop());
|
|
g_vm->addTimer(kIdleEvent, 30000);
|
|
g_vm->getHeroBelt()->setColour(HeroBelt::kCool);
|
|
room->playMusic("intromusic");
|
|
_cloudsMoving = false;
|
|
cloudMove(0);
|
|
}
|
|
|
|
void frameCallback() override {
|
|
if (_cloudsMoving) {
|
|
cloudMove(g_vm->getCurrentTime() - _cloudsMoveStart);
|
|
}
|
|
}
|
|
|
|
void cloudMove(int cloudMoveTime) {
|
|
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
|
double div = cloudMoveTime / 15000.0;
|
|
room->selectFrame("cloudright", kCloudsZ, 0, Common::Point(450, 0) + Common::Point(650, -50) * div);
|
|
room->selectFrame("cloudmiddle", kCloudsZ, 1, Common::Point(220, 0) + Common::Point(220, -50) * div);
|
|
room->selectFrame("cloudleft", kCloudsZ, 2, Common::Point(0, 0) + Common::Point(-200, -50) * div);
|
|
}
|
|
|
|
private:
|
|
void playMastSound(const TranscribedSound &sound, int event = kMastSoundFinished) {
|
|
Common::SharedPtr<VideoRoom> room = g_vm->getVideoRoom();
|
|
_mastSound = sound;
|
|
_mastHeadEndEvent = event;
|
|
_mastHeadIsBusy = true;
|
|
room->playAnim(kMastHeadAnim, kMastHeadZ, PlayAnimParams::keepLastFrame().partial(1, 8), 27301);
|
|
}
|
|
|
|
RoomId _prevId;
|
|
RoomId _destination;
|
|
int _outroCounter;
|
|
int _cloudsMoveStart;
|
|
bool _cloudsMoving;
|
|
int _mastHeadEndEvent;
|
|
bool _mastHeadIsBusy;
|
|
TranscribedSound _mastSound;
|
|
};
|
|
|
|
Common::SharedPtr<Hadesch::Handler> makeArgoHandler() {
|
|
return Common::SharedPtr<Hadesch::Handler>(new ArgoHandler());
|
|
}
|
|
|
|
}
|