PEGASUS: Stub off spot sound code

This commit is contained in:
Matthew Hoops 2011-09-05 15:47:19 -04:00
parent 7070d886d9
commit fe99e95319
5 changed files with 466 additions and 16 deletions

View File

@ -221,6 +221,252 @@ const TimeValue kPlasmaImpactTime = kTwoSeconds;
const TimeValue kNoradAirMaskTimeLimit = kOneMinute + kFifteenSeconds;
enum {
kButtonDownBit = 0,
kAutoButtonBit = 1,
kBitsPerButton = 2,
kButtonDownMask = 1 << kButtonDownBit,
kAutoButtonMask = 1 << kAutoButtonBit,
kButtonStateBits = kButtonDownMask | kAutoButtonMask,
kRawButtonUp = 0,
kRawButtonDown = kButtonDownMask | kAutoButtonMask,
kButtonUp = 0,
kButtonDown = kButtonDownMask,
kButtonAutoUp = kAutoButtonMask,
kButtonAutoDown = kButtonDownMask | kAutoButtonMask
};
enum {
kUpButtonNum = 0,
kLeftButtonNum = 1,
kDownButtonNum = 2,
kRightButtonNum = 3,
kLeftFireButtonNum = 4,
kRightFireButtonNum = 5,
kOneButtonNum = 6,
kTwoButtonNum = 7,
kThreeButtonNum = 8,
kFourButtonNum = 9,
kMod1ButtonNum = 10,
kMod2ButtonNum = 11,
kMod3ButtonNum = 12
};
enum {
kUpButtonShift = kUpButtonNum * kBitsPerButton,
kLeftButtonShift = kLeftButtonNum * kBitsPerButton,
kDownButtonShift = kDownButtonNum * kBitsPerButton,
kRightButtonShift = kRightButtonNum * kBitsPerButton,
kLeftFireButtonShift = kLeftFireButtonNum * kBitsPerButton,
kRightFireButtonShift = kRightFireButtonNum * kBitsPerButton,
kOneButtonShift = kOneButtonNum * kBitsPerButton,
kTwoButtonShift = kTwoButtonNum * kBitsPerButton,
kThreeButtonShift = kThreeButtonNum * kBitsPerButton,
kFourButtonShift = kFourButtonNum * kBitsPerButton,
kMod1ButtonShift = kMod1ButtonNum * kBitsPerButton,
kMod2ButtonShift = kMod2ButtonNum * kBitsPerButton,
kMod3ButtonShift = kMod3ButtonNum * kBitsPerButton
};
enum {
kAllUpBits = (kButtonUp << kUpButtonShift) |
(kButtonUp << kLeftButtonShift) |
(kButtonUp << kDownButtonShift) |
(kButtonUp << kRightButtonShift) |
(kButtonUp << kLeftFireButtonShift) |
(kButtonUp << kRightFireButtonShift) |
(kButtonUp << kOneButtonShift) |
(kButtonUp << kTwoButtonShift) |
(kButtonUp << kThreeButtonShift) |
(kButtonUp << kFourButtonShift) |
(kButtonUp << kMod1ButtonShift) |
(kButtonUp << kMod2ButtonShift) |
(kButtonUp << kMod3ButtonShift),
kDirectionBits = (kButtonDownMask << kUpButtonShift) |
(kButtonDownMask << kLeftButtonShift) |
(kButtonDownMask << kDownButtonShift) |
(kButtonDownMask << kRightButtonShift),
kButtonBits = (kButtonDownMask << kLeftFireButtonShift) |
(kButtonDownMask << kRightFireButtonShift) |
(kButtonDownMask << kOneButtonShift) |
(kButtonDownMask << kTwoButtonShift) |
(kButtonDownMask << kThreeButtonShift) |
(kButtonDownMask << kFourButtonShift) |
(kButtonDownMask << kMod1ButtonShift) |
(kButtonDownMask << kMod2ButtonShift) |
(kButtonDownMask << kMod3ButtonShift),
kAllButtonDownBits = kDirectionBits | kButtonBits,
kAllAutoBits = (kAutoButtonMask << kUpButtonShift) |
(kAutoButtonMask << kLeftButtonShift) |
(kAutoButtonMask << kDownButtonShift) |
(kAutoButtonMask << kRightButtonShift) |
(kAutoButtonMask << kLeftFireButtonShift) |
(kAutoButtonMask << kRightFireButtonShift) |
(kAutoButtonMask << kOneButtonShift) |
(kAutoButtonMask << kTwoButtonShift) |
(kAutoButtonMask << kThreeButtonShift) |
(kAutoButtonMask << kFourButtonShift) |
(kAutoButtonMask << kMod1ButtonShift) |
(kAutoButtonMask << kMod2ButtonShift) |
(kAutoButtonMask << kMod3ButtonShift),
kFilterUpButton = kButtonDownMask << kUpButtonShift,
kFilterUpAuto = kAutoButtonMask << kUpButtonShift,
kFilterUpButtonAny = kFilterUpButton | kFilterUpAuto,
kFilterLeftButton = kButtonDownMask << kLeftButtonShift,
kFilterLeftAuto = kAutoButtonMask << kLeftButtonShift,
kFilterLeftButtonAny = kFilterLeftButton | kFilterLeftAuto,
kFilterDownButton = kButtonDownMask << kDownButtonShift,
kFilterDownAuto = kAutoButtonMask << kDownButtonShift,
kFilterDownButtonAny = kFilterDownButton | kFilterDownAuto,
kFilterRightButton = kButtonDownMask << kRightButtonShift,
kFilterRightAuto = kAutoButtonMask << kRightButtonShift,
kFilterRightButtonAny = kFilterRightButton | kFilterRightAuto,
kFilterLeftFireButton = kButtonDownMask << kLeftFireButtonShift,
kFilterLeftFireAuto = kAutoButtonMask << kLeftFireButtonShift,
kFilterLeftFireButtonAny = kFilterLeftFireButton | kFilterLeftFireAuto,
kFilterRightFireButton = kButtonDownMask << kRightFireButtonShift,
kFilterRightFireAuto = kAutoButtonMask << kRightFireButtonShift,
kFilterRightFireButtonAny = kFilterRightFireButton | kFilterRightFireAuto,
kFilterOneButton = kButtonDownMask << kOneButtonShift,
kFilterOneAuto = kAutoButtonMask << kOneButtonShift,
kFilterOneButtonAny = kFilterOneButton | kFilterOneAuto,
kFilterTwoButton = kButtonDownMask << kTwoButtonShift,
kFilterTwoAuto = kAutoButtonMask << kTwoButtonShift,
kFilterTwoButtonAny = kFilterTwoButton | kFilterTwoAuto,
kFilterThreeButton = kButtonDownMask << kThreeButtonShift,
kFilterThreeAuto = kAutoButtonMask << kThreeButtonShift,
kFilterThreeButtonAny = kFilterThreeButton | kFilterThreeAuto,
kFilterFourButton = kButtonDownMask << kFourButtonShift,
kFilterFourAuto = kAutoButtonMask << kFourButtonShift,
kFilterFourButtonAny = kFilterFourButton | kFilterFourAuto,
kFilterMod1Button = kButtonDownMask << kMod1ButtonShift,
kFilterMod1Auto = kAutoButtonMask << kMod1ButtonShift,
kFilterMod1ButtonAny = kFilterMod1Button | kFilterMod1Auto,
kFilterMod2Button = kButtonDownMask << kMod2ButtonShift,
kFilterMod2Auto = kAutoButtonMask << kMod2ButtonShift,
kFilterMod2ButtonAny = kFilterMod2Button | kFilterMod2Auto,
kFilterMod3Button = kButtonDownMask << kMod3ButtonShift,
kFilterMod3Auto = kAutoButtonMask << kMod3ButtonShift,
kFilterMod3ButtonAny = kFilterMod3Button | kFilterMod3Auto,
kFilterNoInput = 0,
kFilterAllInput = kFilterUpButton |
kFilterUpAuto |
kFilterLeftButton |
kFilterLeftAuto |
kFilterDownButton |
kFilterDownAuto |
kFilterRightButton |
kFilterRightAuto |
kFilterLeftFireButton |
kFilterLeftFireAuto |
kFilterRightFireButton |
kFilterRightFireAuto |
kFilterOneButton |
kFilterOneAuto |
kFilterTwoButton |
kFilterTwoAuto |
kFilterThreeButton |
kFilterThreeAuto |
kFilterFourButton |
kFilterFourAuto |
kFilterMod1Button |
kFilterMod1Auto |
kFilterMod2Button |
kFilterMod2Auto |
kFilterMod3Button |
kFilterMod3Auto,
kFilterAllDirections = kFilterUpButton |
kFilterUpAuto |
kFilterLeftButton |
kFilterLeftAuto |
kFilterDownButton |
kFilterDownAuto |
kFilterRightButton |
kFilterRightAuto,
kFilterButtons = kFilterOneButton |
kFilterOneAuto |
kFilterTwoButton |
kFilterTwoAuto |
kFilterThreeButton |
kFilterThreeAuto |
kFilterFourButton |
kFilterFourAuto,
kFilterFireButtons = kFilterLeftFireButton |
kFilterLeftFireAuto |
kFilterRightFireButton |
kFilterRightFireAuto,
kFilterAllButtons = kFilterLeftFireButton |
kFilterLeftFireAuto |
kFilterRightFireButton |
kFilterRightFireAuto |
kFilterOneButton |
kFilterOneAuto |
kFilterTwoButton |
kFilterTwoAuto |
kFilterThreeButton |
kFilterThreeAuto |
kFilterFourButton |
kFilterFourAuto |
kFilterMod1Button |
kFilterMod1Auto |
kFilterMod2Button |
kFilterMod2Auto |
kFilterMod3Button |
kFilterMod3Auto,
kFilterAllInputNoAuto = kFilterUpButton |
kFilterLeftButton |
kFilterDownButton |
kFilterRightButton |
kFilterLeftFireButton |
kFilterRightFireButton |
kFilterOneButton |
kFilterTwoButton |
kFilterThreeButton |
kFilterFourButton |
kFilterMod1Button |
kFilterMod2Button |
kFilterMod3Button
};
const tNotificationID kNeighborhoodNotificationID = 1;
const tNotificationID kLastNeighborhoodNotificationID = kNeighborhoodNotificationID;
const tNotificationFlags kNeighborhoodMovieCompletedFlag = 1;
const tNotificationFlags kMoveForwardCompletedFlag = kNeighborhoodMovieCompletedFlag << 1;
const tNotificationFlags kStrideCompletedFlag = kMoveForwardCompletedFlag << 1;
const tNotificationFlags kTurnCompletedFlag = kStrideCompletedFlag << 1;
const tNotificationFlags kSpotCompletedFlag = kTurnCompletedFlag << 1;
const tNotificationFlags kDoorOpenCompletedFlag = kSpotCompletedFlag << 1;
const tNotificationFlags kExtraCompletedFlag = kDoorOpenCompletedFlag << 1;
const tNotificationFlags kSpotSoundCompletedFlag = kExtraCompletedFlag << 1;
const tNotificationFlags kDelayCompletedFlag = kSpotSoundCompletedFlag << 1;
const tNotificationFlags kActionRequestCompletedFlag = kDelayCompletedFlag << 1;
const tNotificationFlags kDeathExtraCompletedFlag = kActionRequestCompletedFlag << 1;
const tNotificationFlags kLastNeighborhoodNotificationFlag = kDeathExtraCompletedFlag;
const tNotificationFlags kNeighborhoodFlags = kNeighborhoodMovieCompletedFlag |
kMoveForwardCompletedFlag |
kStrideCompletedFlag |
kTurnCompletedFlag |
kSpotCompletedFlag |
kDoorOpenCompletedFlag |
kExtraCompletedFlag |
kSpotSoundCompletedFlag |
kDelayCompletedFlag |
kActionRequestCompletedFlag |
kDeathExtraCompletedFlag;
} // End of namespace Pegasus
#endif

View File

@ -32,9 +32,10 @@
namespace Pegasus {
Neighborhood::Neighborhood(PegasusEngine *vm, const Common::String &resName, tNeighborhoodID id) : _vm(vm), _resName(resName) {
Neighborhood::Neighborhood(PegasusEngine *vm, const Common::String &resName, tNeighborhoodID id) : MMIDObject(id), _vm(vm), _resName(resName) {
GameState.setOpenDoorLocation(kNoRoomID, kNoDirection);
_currentAlternate = 0;
_interruptionFilter = kFilterAllInput;
}
Neighborhood::~Neighborhood() {
@ -96,6 +97,7 @@ void Neighborhood::init() {
delete stream;
createNeighborhoodSpots();
loadSoundSpots();
// TODO: AI, movies, notifications, buncha other stuff
}
@ -268,4 +270,125 @@ void Neighborhood::createNeighborhoodSpots() {
delete hotspotList;
}
void Neighborhood::loadSoundSpots() {
// TODO: Eventually push to the subclasses
Common::String fileName = "Sounds/";
switch (getObjectID()) {
case kCaldoriaID:
fileName += "Caldoria/Caldoria Spots";
break;
case kFullTSAID:
case kFinalTSAID:
case kTinyTSAID:
fileName += "TSA/TSA Spots";
break;
case kPrehistoricID:
fileName += "Prehistoric/Prehistoric Spots";
break;
case kMarsID:
fileName += "Mars/Mars Spots";
break;
case kWSCID:
fileName += "World Science Center/WSC Spots";
break;
case kNoradAlphaID:
fileName += "Norad/Norad Alpha Spots";
break;
case kNoradDeltaID:
fileName += "Norad/Norad Delta Spots";
break;
}
_spotSounds.initFromQuickTime(fileName);
}
void Neighborhood::popActionQueue() {
if (!_actionQueue.empty()) {
tQueueRequest topRequest = _actionQueue.pop();
switch (topRequest.requestType) {
case kNavExtraRequest:
// TODO
break;
case kSpotSoundRequest:
_spotSounds.stopSound();
break;
case kDelayRequest:
// TODO
break;
}
serviceActionQueue();
}
}
void Neighborhood::serviceActionQueue() {
if (!_actionQueue.empty()) {
tQueueRequest &topRequest = _actionQueue.front();
if (!topRequest.playing) {
topRequest.playing = true;
switch (topRequest.requestType) {
case kNavExtraRequest:
// TODO
break;
case kSpotSoundRequest:
_spotSounds.stopSound();
_spotSounds.playSoundSegment(topRequest.start, topRequest.stop);
_interruptionFilter = topRequest.interruptionFilter;
// TODO: stop trigger
break;
case kDelayRequest:
// TODO
break;
}
}
} else {
_interruptionFilter = kFilterAllInput;
}
}
void Neighborhood::requestAction(const tQueueRequestType requestType, const tExtraID extra, const TimeValue in, const TimeValue out,
const tInputBits interruptionFilter, const tNotificationFlags flags) {
tQueueRequest request;
request.requestType = requestType;
request.extra = extra;
request.start = in;
request.stop = out;
request.interruptionFilter = interruptionFilter;
request.playing = false;
request.flags = flags | kActionRequestCompletedFlag;
// TODO: notification
_actionQueue.push(request);
if (_actionQueue.size() == 1)
serviceActionQueue();
}
void Neighborhood::requestExtraSequence(const tExtraID whichExtra, const tNotificationFlags flags, const tInputBits interruptionFilter) {
requestAction(kNavExtraRequest, whichExtra, 0, 0, interruptionFilter, flags);
}
void Neighborhood::requestSpotSound(const TimeValue in, const TimeValue out, const tInputBits interruptionFilter, const tNotificationFlags flags) {
requestAction(kSpotSoundRequest, 0xFFFFFFFF, in, out, interruptionFilter, flags);
}
void Neighborhood::requestDelay(const TimeValue delayDuration, const TimeScale delayScale, const tInputBits interruptionFilter, const tNotificationFlags flags) {
requestAction(kDelayRequest, 0xFFFFFFFF, delayDuration, delayScale, interruptionFilter, flags);
}
bool operator==(const tQueueRequest &arg1, const tQueueRequest &arg2) {
return arg1.requestType == arg2.requestType && arg1.extra == arg2.extra &&
arg1.start == arg2.start && arg1.stop == arg2.stop;
}
bool operator!=(const tQueueRequest &arg1, const tQueueRequest &arg2) {
return !operator==(arg1, arg2);
}
} // End of namespace Pegasus

View File

@ -26,9 +26,12 @@
#ifndef PEGASUS_NEIGHBORHOOD_H
#define PEGASUS_NEIGHBORHOOD_H
#include "common/queue.h"
#include "common/str.h"
#include "pegasus/hotspot.h"
#include "pegasus/sound.h"
#include "pegasus/MMShell/Utilities/MMIDObject.h"
#include "pegasus/neighborhood/door.h"
#include "pegasus/neighborhood/exit.h"
#include "pegasus/neighborhood/extra.h"
@ -40,6 +43,7 @@
namespace Pegasus {
class MMNotification;
class PegasusEngine;
// Pegasus Prime neighborhood id's
@ -52,11 +56,35 @@ const tNeighborhoodID kMarsID = 5;
const tNeighborhoodID kWSCID = 6;
const tNeighborhoodID kNoradAlphaID = 7;
const tNeighborhoodID kNoradDeltaID = 8;
// The sub chase is not really a neighborhood, but we define a constant that is used
// to allow an easy transition out of Norad Alpha.
// The sub chase is not really a neighborhood, but we define a constant that is used
// to allow an easy transition out of Norad Alpha.
const tNeighborhoodID kNoradSubChaseID = 1000;
class Neighborhood {
enum tQueueRequestType {
kNavExtraRequest,
kSpotSoundRequest,
kDelayRequest
};
// For delay requests, start is interpreted as the total delay and stop is interpreted
// as the scale the delay is in.
// For extra requests, start and stop are not used.
struct tQueueRequest {
tQueueRequestType requestType;
tExtraID extra;
TimeValue start, stop;
tInputBits interruptionFilter;
bool playing;
tNotificationFlags flags;
MMNotification *notification;
};
bool operator==(const tQueueRequest &arg1, const tQueueRequest &arg2);
bool operator!=(const tQueueRequest &arg1, const tQueueRequest &arg2);
typedef Common::Queue<tQueueRequest> NeighborhoodActionQueue;
class Neighborhood : public MMIDObject {
public:
Neighborhood(PegasusEngine *vm, const Common::String &resName, tNeighborhoodID id);
virtual ~Neighborhood();
@ -79,12 +107,22 @@ public:
tCanTurnReason canTurn(tTurnDirection turn, tDirectionConstant &nextDir);
tCanOpenDoorReason canOpenDoor(DoorTable::Entry &entry);
void requestExtraSequence(const tExtraID, const tNotificationFlags, const tInputBits interruptionFilter);
void requestSpotSound(const TimeValue, const TimeValue, const tInputBits interruptionFilter, const tNotificationFlags);
void requestDelay(const TimeValue, const TimeScale, const tInputBits interruptionFilter, const tNotificationFlags);
virtual bool actionQueueEmpty() { return _actionQueue.empty(); }
protected:
virtual void createNeighborhoodSpots();
virtual void loadSoundSpots();
void popActionQueue();
void serviceActionQueue();
void requestAction(const tQueueRequestType, const tExtraID, const TimeValue, const TimeValue, const tInputBits, const tNotificationFlags);
PegasusEngine *_vm;
Common::String _resName;
tNeighborhoodID _neighborhoodID;
DoorTable _doorTable;
ExitTable _exitTable;
@ -98,6 +136,12 @@ protected:
tAlternateID _currentAlternate;
HotspotList _neighborhoodHotspots;
NeighborhoodActionQueue _actionQueue;
Sound _spotSounds;
tInputBits _interruptionFilter;
};
} // End of namespace Pegasus

View File

@ -25,6 +25,7 @@
#include "audio/audiostream.h"
#include "audio/decoders/aiff.h"
#include "audio/decoders/quicktime.h"
#include "common/file.h"
#include "common/system.h"
@ -33,7 +34,7 @@
namespace Pegasus {
Sound::Sound() {
_aiffStream = 0;
_stream = 0;
_volume = 0xFF;
}
@ -43,17 +44,25 @@ Sound::~Sound() {
void Sound::disposeSound() {
stopSound();
delete _aiffStream; _aiffStream = 0;
delete _stream; _stream = 0;
}
void Sound::initFromAIFFFile(const Common::String &fileName) {
disposeSound();
Common::File *file = new Common::File();
if (!file->open(fileName)) {
delete file;
return;
}
_aiffStream = Audio::makeAIFFStream(file, DisposeAfterUse::YES);
_stream = Audio::makeAIFFStream(file, DisposeAfterUse::YES);
}
void Sound::initFromQuickTime(const Common::String &fileName) {
disposeSound();
_stream = Audio::makeQuickTimeStream(fileName);
}
#if 0
@ -81,7 +90,7 @@ void Sound::playSound() {
setVolume(_fader->getFaderValue());
#endif
g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &_handle, _aiffStream, -1, _volume, 0, DisposeAfterUse::NO);
g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &_handle, _stream, -1, _volume, 0, DisposeAfterUse::NO);
}
void Sound::loopSound() {
@ -91,7 +100,7 @@ void Sound::loopSound() {
stopSound();
// Create a looping stream
Audio::AudioStream *loopStream = new Audio::LoopingAudioStream(_aiffStream, 0, DisposeAfterUse::NO);
Audio::AudioStream *loopStream = new Audio::LoopingAudioStream(_stream, 0, DisposeAfterUse::NO);
#if 0
// TODO!
@ -103,7 +112,29 @@ void Sound::loopSound() {
g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &_handle, loopStream, -1, _volume, 0, DisposeAfterUse::YES);
}
void Sound::stopSound(void) {
void Sound::playSoundSegment(uint32 start, uint32 end) {
if (!isSoundLoaded())
return;
stopSound();
Audio::AudioStream *subStream = new Audio::SubSeekableAudioStream(_stream, Audio::Timestamp(0, start, 600), Audio::Timestamp(0, end, 600), DisposeAfterUse::NO);
g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &_handle, subStream, -1, _volume, 0, DisposeAfterUse::YES);
}
void Sound::loopSoundSegment(uint32 start, uint32 end) {
if (!isSoundLoaded())
return;
stopSound();
Audio::AudioStream *subLoopStream = new Audio::SubLoopingAudioStream(_stream, 0, Audio::Timestamp(0, start, 600), Audio::Timestamp(0, end, 600), DisposeAfterUse::NO);
g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, &_handle, subLoopStream, -1, _volume, 0, DisposeAfterUse::YES);
}
void Sound::stopSound() {
g_system->getMixer()->stopHandle(_handle);
}
@ -120,7 +151,7 @@ bool Sound::isPlaying() {
}
bool Sound::isSoundLoaded() const {
return _aiffStream != 0;
return _stream != 0;
}
} // End of namespace Pegasus

View File

@ -30,14 +30,13 @@
#include "common/str.h"
namespace Audio {
class AudioStream;
class RewindableAudioStream;
class SeekableAudioStream;
}
namespace Pegasus {
// TODO!
//class MMSoundFader;
//class SoundFader;
// Things you might want to do with sound:
// Start it
@ -59,10 +58,17 @@ public:
// not using the resource fork string resources.
void initFromAIFFFile(const Common::String &fileName);
// Unlike the original game, we're going to use a regular
// audio stream for sound spots. The original treated them
// as movies.
void initFromQuickTime(const Common::String &fileName);
void disposeSound();
bool isSoundLoaded() const;
void playSound();
void loopSound();
void playSoundSegment(uint32 start, uint32 end);
void loopSoundSegment(uint32 start, uint32 end);
void stopSound();
void setVolume(const uint16 volume);
bool isPlaying();
@ -71,7 +77,7 @@ public:
//void attachFader(SoundFader *fader);
protected:
Audio::RewindableAudioStream *_aiffStream;
Audio::SeekableAudioStream *_stream;
Audio::SoundHandle _handle;
byte _volume;