540 lines
16 KiB
C++
540 lines
16 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.
|
|
*
|
|
* Additional copyright for this file:
|
|
* Copyright (C) 1995-2013 Presto Studios, Inc.
|
|
*
|
|
* 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/>.
|
|
*
|
|
*/
|
|
|
|
#include "pegasus/pegasus.h"
|
|
#include "pegasus/neighborhood/mars/canyonchase.h"
|
|
#include "pegasus/neighborhood/mars/mars.h"
|
|
|
|
namespace Pegasus {
|
|
|
|
// Segment start and end points.
|
|
|
|
//static const TimeValue kPrepStart = 0;
|
|
static const TimeValue kPrepEnd = 3000;
|
|
static const TimeValue kLaunchStart = kPrepEnd;
|
|
static const TimeValue kLaunchEnd = 6640;
|
|
static const TimeValue kBranch1Start = kLaunchEnd;
|
|
static const TimeValue kBranch1End = 22240;
|
|
static const TimeValue kBranch2Start = kBranch1End;
|
|
static const TimeValue kBranch2End = 28440;
|
|
static const TimeValue kBranch3Start = kBranch2End;
|
|
static const TimeValue kBranch3End = 38640;
|
|
static const TimeValue kBranch4Start = kBranch3End;
|
|
static const TimeValue kBranch4End = 43880;
|
|
static const TimeValue kBranch5Start = kBranch4End;
|
|
static const TimeValue kBranch5End = 58680;
|
|
static const TimeValue kExitStart = kBranch5End;
|
|
static const TimeValue kExitEnd = 66480;
|
|
static const TimeValue kExitLoopPoint = 66200;
|
|
static const TimeValue kExitGenoPoint = 62560;
|
|
|
|
// Death start and end points.
|
|
|
|
static const TimeValue kDeath1Start = 0;
|
|
static const TimeValue kDeath1End = 2400;
|
|
static const TimeValue kDeath2Start = kDeath1End;
|
|
static const TimeValue kDeath2End = 4720;
|
|
static const TimeValue kDeath3Start = kDeath2End;
|
|
static const TimeValue kDeath3End = 7120;
|
|
static const TimeValue kDeath4Start = kDeath3End;
|
|
static const TimeValue kDeath4End = 9280;
|
|
static const TimeValue kDeath5Start = kDeath4End;
|
|
static const TimeValue kDeath5End = 12000;
|
|
|
|
// Chase state.
|
|
|
|
enum {
|
|
kCanyonLaunch,
|
|
kCanyonBranch1Left,
|
|
kCanyonBranch1Right,
|
|
kCanyonBranch2Left,
|
|
kCanyonBranch2Right,
|
|
kCanyonBranch3Left,
|
|
kCanyonBranch4Left,
|
|
kCanyonBranch4Right,
|
|
kCanyonBranch5Left,
|
|
kCanyonBranch5Right,
|
|
kCanyonExit,
|
|
kCanyonLoop
|
|
};
|
|
|
|
void MusicTimerEvent::fire() {
|
|
canyonChase->musicTimerExpired(*this);
|
|
}
|
|
|
|
CanyonChase::CanyonChase(Neighborhood *handler) : ChaseInteraction(kMarsCanyonChaseInteractionID, handler,
|
|
kMarsCanyonChaseNotificationID, g_vm), _canyonMovie1(kNoDisplayElement),
|
|
_canyonMovie2(kNoDisplayElement), _deathMovie(kNoDisplayElement), _genoMovie(kNoDisplayElement) {
|
|
_currentMovie = nullptr;
|
|
_currentCallBack = nullptr;
|
|
}
|
|
|
|
void CanyonChase::setSoundFXLevel(const uint16 fxLevel) {
|
|
_canyonMovie1.setVolume(fxLevel);
|
|
_canyonMovie2.setVolume(fxLevel);
|
|
_deathMovie.setVolume(fxLevel);
|
|
}
|
|
|
|
void CanyonChase::setAmbienceLevel(const uint16 level) {
|
|
_genoMovie.setVolume(level);
|
|
_musicFader.setMasterVolume(level);
|
|
}
|
|
|
|
void CanyonChase::startCanyonMusicLoop(void) {
|
|
FaderMoveSpec spec;
|
|
|
|
_musicLoop.loopSound();
|
|
spec.makeTwoKnotFaderSpec(10, 0, 0, 1, 255);
|
|
_musicFader.startFader(spec);
|
|
}
|
|
|
|
void CanyonChase::stopCanyonMusicLoop(const long ticks) {
|
|
FaderMoveSpec spec;
|
|
|
|
spec.makeTwoKnotFaderSpec(10, 0, 255, ticks, 0);
|
|
_musicFader.startFader(spec);
|
|
}
|
|
|
|
void CanyonChase::openInteraction() {
|
|
_canyonMovie1.initFromMovieFile("Images/Mars/Canyon_hq1.mov");
|
|
_canyonMovie1.setVolume(g_vm->getSoundFXLevel());
|
|
_canyonMovie1.moveElementTo(kShuttleWindowLeft, kShuttleWindowTop);
|
|
_canyonMovie1.setDisplayOrder(kShuttleMonitorOrder);
|
|
|
|
_canyon1CallBack.setNotification(&_chaseNotification);
|
|
_canyon1CallBack.initCallBack(&_canyonMovie1, kCallBackAtExtremes);
|
|
_canyon1CallBack.setCallBackFlag(kChaseEnteredBranchZone);
|
|
_canyon1CallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
|
|
|
|
_canyonMovie2.initFromMovieFile("Images/Mars/Canyon_hq2.mov");
|
|
_canyonMovie2.setVolume(g_vm->getSoundFXLevel());
|
|
_canyonMovie2.moveElementTo(kShuttleWindowLeft, kShuttleWindowTop);
|
|
_canyonMovie2.setDisplayOrder(kShuttleMonitorOrder);
|
|
|
|
_canyon2CallBack.setNotification(&_chaseNotification);
|
|
_canyon2CallBack.initCallBack(&_canyonMovie2, kCallBackAtExtremes);
|
|
_canyon2CallBack.setCallBackFlag(kChaseEnteredBranchZone);
|
|
_canyon2CallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
|
|
|
|
_deathMovie.initFromMovieFile("Images/Mars/Canyon_hqD.mov");
|
|
_deathMovie.setVolume(g_vm->getSoundFXLevel());
|
|
_deathMovie.moveElementTo(kShuttleWindowLeft, kShuttleWindowTop);
|
|
_deathMovie.setDisplayOrder(kShuttleMonitorOrder);
|
|
|
|
_deathCallBack.setNotification(&_chaseNotification);
|
|
_deathCallBack.initCallBack(&_deathMovie, kCallBackAtExtremes);
|
|
_deathCallBack.setCallBackFlag(kChaseFinished);
|
|
_deathCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
|
|
|
|
_musicLoop.attachFader(&_musicFader);
|
|
_musicLoop.initFromAIFFFile("Sounds/Mars/Canyon Loop.44K.16.AIFF");
|
|
_musicFader.setMasterVolume(g_vm->getAmbienceLevel());
|
|
|
|
ChaseInteraction::openInteraction();
|
|
|
|
_steerPict.setDisplayOrder(kShuttleMonitorOrder + 1);
|
|
_steerPict.moveElementTo(kShuttleSteerLeft, kShuttleSteerTop);
|
|
}
|
|
|
|
void CanyonChase::initInteraction() {
|
|
_steerPict.startDisplaying();
|
|
|
|
// Launch branch is identical in both movies
|
|
_canyonState = kCanyonLaunch;
|
|
_canyonMovie1.setSegment(kLaunchStart, kLaunchEnd - kDecisionTime);
|
|
_canyonMovie1.setTime(kLaunchStart);
|
|
switchTo(_canyonMovie1, _canyon1CallBack);
|
|
startCanyonMusicLoop();
|
|
ChaseInteraction::initInteraction();
|
|
}
|
|
|
|
void CanyonChase::closeInteraction() {
|
|
_canyonMovie1.stop();
|
|
_canyonMovie1.stopDisplaying();
|
|
_canyonMovie1.releaseMovie();
|
|
_canyon1CallBack.releaseCallBack();
|
|
|
|
_canyonMovie2.stop();
|
|
_canyonMovie2.stopDisplaying();
|
|
_canyonMovie2.releaseMovie();
|
|
_canyon2CallBack.releaseCallBack();
|
|
|
|
_deathMovie.stop();
|
|
_deathMovie.stopDisplaying();
|
|
_deathMovie.releaseMovie();
|
|
_deathCallBack.releaseCallBack();
|
|
|
|
_genoMovie.stop();
|
|
_genoMovie.stopDisplaying();
|
|
_genoMovie.releaseMovie();
|
|
_genoCallBack.releaseCallBack();
|
|
|
|
ChaseInteraction::closeInteraction();
|
|
}
|
|
|
|
void CanyonChase::receiveNotification(Notification *notification, const NotificationFlags flags) {
|
|
Input input;
|
|
|
|
if (notification == &_chaseNotification && flags == kChaseFinished) {
|
|
if (_canyonState == kCanyonLoop) {
|
|
// Swallow the notification if we loop back to the beginning
|
|
InputDevice.getInput(input, kFilterAllInput);
|
|
if (JMPPPInput::isEasterEggModifierInput(input)) {
|
|
stopCanyonMusicLoop(15);
|
|
doGenoChase();
|
|
} else {
|
|
_canyonMovie2.setSegment(kExitGenoPoint, kExitLoopPoint - kDecisionTime);
|
|
_canyonMovie2.setTime(kExitGenoPoint);
|
|
switchTo(_canyonMovie2, _canyon2CallBack);
|
|
_canyon2CallBack.setCallBackFlag(kChaseEnteredBranchZone);
|
|
_canyon2CallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
|
|
_canyonState = kCanyonLaunch;
|
|
}
|
|
return;
|
|
} else if (_canyonState != kCanyonExit) {
|
|
// We died
|
|
((Mars *)_owner)->die(kDeathRanIntoCanyonWall);
|
|
}
|
|
}
|
|
ChaseInteraction::receiveNotification(notification, flags);
|
|
}
|
|
|
|
void CanyonChase::setUpBranch() {
|
|
TimeValue branchStart, branchEnd;
|
|
|
|
branchStart = 0;
|
|
branchEnd = 0;
|
|
switch (_canyonState) {
|
|
case kCanyonLaunch:
|
|
case kCanyonExit:
|
|
branchStart = kLaunchEnd - kDecisionTime;
|
|
branchEnd = kLaunchEnd;
|
|
break;
|
|
case kCanyonBranch1Left:
|
|
case kCanyonBranch1Right:
|
|
branchStart = kBranch1End - kDecisionTime;
|
|
branchEnd = kBranch1End;
|
|
break;
|
|
case kCanyonBranch2Left:
|
|
case kCanyonBranch2Right:
|
|
branchStart = kBranch2End - kDecisionTime;
|
|
branchEnd = kBranch2End;
|
|
break;
|
|
case kCanyonBranch3Left:
|
|
branchStart = kBranch3End - kDecisionTime;
|
|
branchEnd = kBranch3End;
|
|
break;
|
|
case kCanyonBranch4Left:
|
|
case kCanyonBranch4Right:
|
|
branchStart = kBranch4End - kDecisionTime;
|
|
branchEnd = kBranch4End;
|
|
break;
|
|
case kCanyonBranch5Left:
|
|
case kCanyonBranch5Right:
|
|
branchStart = kBranch5End - kDecisionTime;
|
|
branchEnd = kBranch5End;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
_currentMovie->setSegment(branchStart, branchEnd);
|
|
// Need to call SetTime here in case we loop
|
|
_currentMovie->setTime(branchStart);
|
|
|
|
_currentCallBack->setCallBackFlag(kChaseExitedBranchZone);
|
|
_currentCallBack->scheduleCallBack(kTriggerAtStop, 0, 0);
|
|
}
|
|
|
|
void CanyonChase::branchLeft() {
|
|
TimeValue branchStart, branchEnd;
|
|
Movie *movie;
|
|
NotificationCallBack *callBack;
|
|
|
|
branchStart = 0;
|
|
branchEnd = 0;
|
|
switch (_canyonState) {
|
|
case kCanyonLaunch:
|
|
branchStart = kBranch1Start;
|
|
branchEnd = kBranch1End - kDecisionTime;
|
|
_canyonState = kCanyonBranch1Left;
|
|
break;
|
|
case kCanyonBranch1Left:
|
|
case kCanyonBranch1Right:
|
|
branchStart = kBranch2Start;
|
|
branchEnd = kBranch2End - kDecisionTime;
|
|
_canyonState = kCanyonBranch2Left;
|
|
break;
|
|
case kCanyonBranch2Left:
|
|
case kCanyonBranch2Right:
|
|
branchStart = kBranch3Start;
|
|
branchEnd = kBranch3End - kDecisionTime;
|
|
_canyonState = kCanyonBranch3Left;
|
|
break;
|
|
case kCanyonBranch3Left:
|
|
branchStart = kBranch4Start;
|
|
branchEnd = kBranch4End - kDecisionTime;
|
|
_canyonState = kCanyonBranch4Left;
|
|
break;
|
|
case kCanyonBranch4Left:
|
|
case kCanyonBranch4Right:
|
|
branchStart = kBranch5Start;
|
|
branchEnd = kBranch5End - kDecisionTime;
|
|
_canyonState = kCanyonBranch5Left;
|
|
break;
|
|
case kCanyonBranch5Left:
|
|
case kCanyonBranch5Right:
|
|
dontBranch();
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// Left branches are in hq2 (except exit)
|
|
// Segment 5 branches are switched
|
|
if (_canyonState == kCanyonBranch5Left || _canyonState == kCanyonBranch5Right) {
|
|
movie = &_canyonMovie1;
|
|
callBack = &_canyon1CallBack;
|
|
} else {
|
|
movie = &_canyonMovie2;
|
|
callBack = &_canyon2CallBack;
|
|
}
|
|
|
|
movie->setSegment(branchStart, branchEnd);
|
|
movie->setTime(branchStart);
|
|
|
|
switchTo(*movie, *callBack);
|
|
|
|
callBack->setCallBackFlag(kChaseEnteredBranchZone);
|
|
callBack->scheduleCallBack(kTriggerAtStop, 0, 0);
|
|
}
|
|
|
|
void CanyonChase::branchRight() {
|
|
TimeValue branchStart, branchEnd;
|
|
NotificationFlags flag;
|
|
Movie *movie;
|
|
NotificationCallBack *callBack;
|
|
|
|
branchStart = 0;
|
|
branchEnd = 0;
|
|
flag = 0;
|
|
switch (_canyonState) {
|
|
case kCanyonLaunch:
|
|
branchStart = kBranch1Start;
|
|
branchEnd = kBranch1End - kDecisionTime;
|
|
_canyonState = kCanyonBranch1Right;
|
|
flag = kChaseEnteredBranchZone;
|
|
break;
|
|
case kCanyonBranch1Left:
|
|
case kCanyonBranch1Right:
|
|
branchStart = kBranch2Start;
|
|
branchEnd = kBranch2End - kDecisionTime;
|
|
_canyonState = kCanyonBranch2Right;
|
|
flag = kChaseEnteredBranchZone;
|
|
break;
|
|
case kCanyonBranch2Left:
|
|
case kCanyonBranch2Right:
|
|
dontBranch();
|
|
return;
|
|
case kCanyonBranch3Left:
|
|
branchStart = kBranch4Start;
|
|
branchEnd = kBranch4End - kDecisionTime;
|
|
_canyonState = kCanyonBranch4Right;
|
|
flag = kChaseEnteredBranchZone;
|
|
break;
|
|
case kCanyonBranch4Left:
|
|
case kCanyonBranch4Right:
|
|
branchStart = kBranch5Start;
|
|
branchEnd = kBranch5End - kDecisionTime;
|
|
_canyonState = kCanyonBranch5Right;
|
|
flag = kChaseEnteredBranchZone;
|
|
break;
|
|
case kCanyonBranch5Left:
|
|
case kCanyonBranch5Right:
|
|
// Exit loop branch is in hq2
|
|
branchStart = kExitStart;
|
|
branchEnd = kExitEnd;
|
|
_canyonState = kCanyonExit;
|
|
flag = kChaseFinished;
|
|
startMusicTimer(kCanyonChaseStart + kCanyonChaseExitedTime - kExitStart, kMovieTicksPerSecond,
|
|
kCanyonExited);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// Right branches are in hq1 (except exit)
|
|
// Segment 5 branches are switched
|
|
if (_canyonState == kCanyonBranch5Left || _canyonState == kCanyonBranch5Right) {
|
|
movie = &_canyonMovie2;
|
|
callBack = &_canyon2CallBack;
|
|
} else {
|
|
movie = &_canyonMovie1;
|
|
callBack = &_canyon1CallBack;
|
|
}
|
|
|
|
movie->setSegment(branchStart, branchEnd);
|
|
movie->setTime(branchStart);
|
|
|
|
switchTo(*movie, *callBack);
|
|
|
|
callBack->setCallBackFlag(flag);
|
|
callBack->scheduleCallBack(kTriggerAtStop, 0, 0);
|
|
}
|
|
|
|
void CanyonChase::dontBranch() {
|
|
TimeValue branchStart, branchEnd;
|
|
|
|
branchStart = 0;
|
|
branchEnd = 0;
|
|
switch (_canyonState) {
|
|
case kCanyonLaunch:
|
|
branchStart = kDeath1Start;
|
|
branchEnd = kDeath1End;
|
|
break;
|
|
case kCanyonBranch1Left:
|
|
case kCanyonBranch1Right:
|
|
branchStart = kDeath2Start;
|
|
branchEnd = kDeath2End;
|
|
break;
|
|
case kCanyonBranch2Left:
|
|
case kCanyonBranch2Right:
|
|
branchStart = kDeath3Start;
|
|
branchEnd = kDeath3End;
|
|
break;
|
|
case kCanyonBranch3Left:
|
|
branchStart = kDeath4Start;
|
|
branchEnd = kDeath4End;
|
|
break;
|
|
case kCanyonBranch4Left:
|
|
case kCanyonBranch4Right:
|
|
branchStart = kDeath5Start;
|
|
branchEnd = kDeath5End;
|
|
break;
|
|
case kCanyonBranch5Left:
|
|
case kCanyonBranch5Right:
|
|
_canyonMovie2.setSegment(kExitStart, kExitGenoPoint);
|
|
_canyonMovie2.setTime(kExitStart);
|
|
switchTo(_canyonMovie2, _canyon2CallBack);
|
|
_canyon2CallBack.setCallBackFlag(kChaseFinished);
|
|
_canyon2CallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
|
|
_canyonState = kCanyonLoop;
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
_deathMovie.setSegment(branchStart, branchEnd);
|
|
_deathMovie.setTime(branchStart);
|
|
|
|
switchTo(_deathMovie, _deathCallBack);
|
|
|
|
startMusicTimer(10, 10, kCanyonRanIntoWall);
|
|
}
|
|
|
|
void CanyonChase::showControlsHint() {
|
|
((Mars *)_owner)->_lowerLeftShuttleMovie.setTime(kShuttleLowerLeftKeypadHintTime);
|
|
((Mars *)_owner)->_lowerLeftShuttleMovie.redrawMovieWorld();
|
|
ChaseInteraction::showControlsHint();
|
|
}
|
|
|
|
void CanyonChase::hideControlsHint() {
|
|
((Mars *)_owner)->_lowerLeftShuttleMovie.setTime(kShuttleLowerLeftCollisionTime);
|
|
((Mars *)_owner)->_lowerLeftShuttleMovie.redrawMovieWorld();
|
|
ChaseInteraction::hideControlsHint();
|
|
}
|
|
|
|
void CanyonChase::switchTo(Movie &movie, NotificationCallBack &callBack) {
|
|
if (_currentMovie != &movie) {
|
|
if (_currentMovie != nullptr) {
|
|
_currentMovie->stop();
|
|
_currentMovie->hide();
|
|
_currentMovie->stopDisplaying();
|
|
}
|
|
|
|
_currentMovie = &movie;
|
|
|
|
_currentMovie->startDisplaying();
|
|
_currentMovie->show();
|
|
_currentMovie->start();
|
|
}
|
|
|
|
if (_currentCallBack != &callBack) {
|
|
_currentCallBack = &callBack;
|
|
}
|
|
}
|
|
|
|
void CanyonChase::startMusicTimer(TimeValue time, TimeScale scale, MusicTimerCode code) {
|
|
_musicFuse.primeFuse(time, scale);
|
|
_musicEvent.canyonChase = this;
|
|
_musicEvent.theEvent = code;
|
|
_musicFuse.setFunctor(new Common::Functor0Mem<void, MusicTimerEvent>(&_musicEvent, &MusicTimerEvent::fire));
|
|
_musicFuse.lightFuse();
|
|
}
|
|
|
|
void CanyonChase::musicTimerExpired(MusicTimerEvent &event) {
|
|
FaderMoveSpec spec;
|
|
|
|
switch (event.theEvent) {
|
|
case kCanyonRanIntoWall:
|
|
stopCanyonMusicLoop(5);
|
|
break;
|
|
case kCanyonExited:
|
|
spec.makeTwoKnotFaderSpec(20, 0, 255, 5, 160);
|
|
_musicFader.startFader(spec);
|
|
startMusicTimer(kCanyonChaseFadedTime, kMovieTicksPerSecond, kCanyonFaded);
|
|
break;
|
|
case kCanyonFaded:
|
|
spec.makeTwoKnotFaderSpec(10, 0, 160, 30, 0);
|
|
_musicFader.startFader(spec);
|
|
((Mars *)_owner)->startMarsTimer(kLaunchTubeDVDReachedTime, kMovieTicksPerSecond,
|
|
kMarsLaunchTubeReached);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void CanyonChase::doGenoChase() {
|
|
_genoMovie.initFromMovieFile("Images/Mars/Canyon_hqG.mov");
|
|
_genoMovie.setVolume(g_vm->getAmbienceLevel());
|
|
_genoMovie.moveElementTo(kShuttleWindowLeft, kShuttleWindowTop);
|
|
_genoMovie.setDisplayOrder(kShuttleMonitorOrder);
|
|
_genoMovie.startDisplaying();
|
|
_genoMovie.show();
|
|
_genoMovie.start();
|
|
|
|
_genoCallBack.setNotification(&_chaseNotification);
|
|
_genoCallBack.initCallBack(&_genoMovie, kCallBackAtExtremes);
|
|
_genoCallBack.setCallBackFlag(kChaseFinished);
|
|
_genoCallBack.scheduleCallBack(kTriggerAtStop, 0, 0);
|
|
|
|
_canyonState = kCanyonExit;
|
|
|
|
((Mars *)_owner)->startMarsTimer(_genoMovie.getDuration() - 5 * kMovieTicksPerSecond,
|
|
kMovieTicksPerSecond, kMarsLaunchTubeReached);
|
|
}
|
|
|
|
} // End of namespace Pegasus
|