aboutsummaryrefslogtreecommitdiff
path: root/sky
diff options
context:
space:
mode:
Diffstat (limited to 'sky')
-rw-r--r--sky/control.cpp30
-rw-r--r--sky/control.h5
-rw-r--r--sky/intro.cpp4
-rw-r--r--sky/logic.cpp3
-rw-r--r--sky/sky.cpp3
-rw-r--r--sky/sound.cpp120
-rw-r--r--sky/sound.h27
7 files changed, 144 insertions, 48 deletions
diff --git a/sky/control.cpp b/sky/control.cpp
index fd8dc17b14..f9f069db31 100644
--- a/sky/control.cpp
+++ b/sky/control.cpp
@@ -115,7 +115,7 @@ void SkyTextResource::drawToScreen(bool doMask) {
_system->copy_rect(_screen + _y * GAME_SCREEN_WIDTH + _x, GAME_SCREEN_WIDTH, _x, _y, cpWidth, PAN_CHAR_HEIGHT);
}
-SkyControl::SkyControl(SkyScreen *screen, SkyDisk *disk, SkyMouse *mouse, SkyText *text, SkyMusicBase *music, SkyLogic *logic, OSystem *system, const char *savePath) {
+SkyControl::SkyControl(SkyScreen *screen, SkyDisk *disk, SkyMouse *mouse, SkyText *text, SkyMusicBase *music, SkyLogic *logic, SkySound *sound, OSystem *system, const char *savePath) {
_skyScreen = screen;
_skyDisk = disk;
@@ -123,6 +123,7 @@ SkyControl::SkyControl(SkyScreen *screen, SkyDisk *disk, SkyMouse *mouse, SkyTex
_skyText = text;
_skyMusic = music;
_skyLogic = logic;
+ _skySound = sound;
_system = system;
_savePath = savePath;
_memListRoot = NULL;
@@ -993,9 +994,11 @@ uint32 SkyControl::prepareSaveData(uint8 *destBuf) {
uint8 *destPos = destBuf + 4;
STOSD(destPos, SAVE_FILE_REVISION);
- STOSD(destPos, _skyMusic->giveCurrentMusic());
+ STOSD(destPos, SkyState::_systemVars.gameVersion);
+ STOSW(destPos, _skySound->_saveSounds[0]);
+ STOSW(destPos, _skySound->_saveSounds[1]);
- //TODO: save queued sfx
+ STOSD(destPos, _skyMusic->giveCurrentMusic());
STOSD(destPos, _skyText->giveCurrentCharSet());
STOSD(destPos, _savedMouse);
STOSD(destPos, SkyState::_systemVars.currentPalette);
@@ -1174,7 +1177,19 @@ uint16 SkyControl::parseSaveData(uint8 *srcBuf) {
freeMemList(); // memory from last restore isn't needed anymore
- uint32 music, charSet, mouseType, palette;
+ uint32 music, charSet, mouseType, palette, gameVersion;
+
+ if (saveRev >= 3) {
+ LODSD(srcPos, gameVersion);
+ if (gameVersion != SkyState::_systemVars.gameVersion) {
+ printf("This savegame was created by Beneath a Steel Sky V.0.0%03d\n",gameVersion);
+ printf("It cannot be loaded by this version (%0.0%3d)\n",SkyState::_systemVars.gameVersion);
+ return RESTORE_FAILED;
+ }
+ LODSW(srcPos, _skySound->_saveSounds[0]);
+ LODSW(srcPos, _skySound->_saveSounds[1]);
+ _skySound->restoreSfx();
+ }
LODSD(srcPos, music);
LODSD(srcPos, charSet);
LODSD(srcPos, mouseType);
@@ -1315,9 +1330,12 @@ void SkyControl::showGameQuitMsg(bool useScreen) {
uint8 *textBuf2 = (uint8*)malloc(GAME_SCREEN_WIDTH * 14 + sizeof(dataFileHeader));
uint8 textNum;
uint8 *screenData;
- if (useScreen)
+ if (useScreen) {
+ if (_skyScreen->sequenceRunning())
+ _skyScreen->stopSequence();
+
screenData = _skyScreen->giveCurrent();
- else
+ } else
screenData = _screenBuf;
switch (SkyState::_systemVars.language) {
case DE_DEU: textNum = 1; break;
diff --git a/sky/control.h b/sky/control.h
index 40590828d7..f96bafcf64 100644
--- a/sky/control.h
+++ b/sky/control.h
@@ -106,7 +106,7 @@ class SkyMouse;
#define SAVE_GRAFX 32
#define SAVE_TURNP 64
-#define SAVE_FILE_REVISION 2
+#define SAVE_FILE_REVISION 3
struct AllocedMem {
uint16 *mem;
@@ -145,7 +145,7 @@ private:
class SkyControl {
public:
- SkyControl(SkyScreen *screen, SkyDisk *disk, SkyMouse *mouse, SkyText *text, SkyMusicBase *music, SkyLogic *logic, OSystem *system, const char *savePath);
+ SkyControl(SkyScreen *screen, SkyDisk *disk, SkyMouse *mouse, SkyText *text, SkyMusicBase *music, SkyLogic *logic, SkySound *sound, OSystem *system, const char *savePath);
void doControlPanel(void);
void doLoadSavePanel(void);
void restartGame(void);
@@ -205,6 +205,7 @@ private:
SkyText *_skyText;
SkyMusicBase *_skyMusic;
SkyLogic *_skyLogic;
+ SkySound *_skySound;
OSystem *_system;
int _mouseX, _mouseY;
bool _mouseClicked;
diff --git a/sky/intro.cpp b/sky/intro.cpp
index d4fb32ebcc..44105fcfea 100644
--- a/sky/intro.cpp
+++ b/sky/intro.cpp
@@ -492,7 +492,7 @@ void SkyState::removeText(uint32 *&cmdPtr) {
void SkyState::introFx(uint32 *&cmdPtr) {
_mixer->stopAll();
- _skySound->playSound((uint16)cmdPtr[2], (uint16)cmdPtr[3]);
+ _skySound->playSound((uint16)cmdPtr[2], (uint16)cmdPtr[3], 0);
cmdPtr += 4;
}
@@ -501,6 +501,6 @@ void SkyState::introVol(uint32 *&cmdPtr) {
// HACK: for some reason, the mixer will only stop playing
// looping sounds if you do it using SoundMixer::stopAll();
_mixer->stopAll();
- _skySound->playSound(1, (uint16)(cmdPtr[2] & 0x7F));
+ _skySound->playSound(1, (uint16)(cmdPtr[2] & 0x7F), 0);
cmdPtr += 3;
}
diff --git a/sky/logic.cpp b/sky/logic.cpp
index f2f0efc4c0..7a3607a3d5 100644
--- a/sky/logic.cpp
+++ b/sky/logic.cpp
@@ -2373,7 +2373,8 @@ bool SkyLogic::fnSetFont(uint32 font, uint32 b, uint32 c) {
}
bool SkyLogic::fnStartFx(uint32 sound, uint32 b, uint32 c) {
- return _skySound->fnStartFx(sound);
+ _skySound->fnStartFx(sound, (uint8)(b & 1));
+ return true;
}
bool SkyLogic::fnStopFx(uint32 a, uint32 b, uint32 c) {
diff --git a/sky/sky.cpp b/sky/sky.cpp
index 0c709f8d55..b7a07ef335 100644
--- a/sky/sky.cpp
+++ b/sky/sky.cpp
@@ -149,6 +149,7 @@ void SkyState::go() {
/*if ((_key_pressed == 27) && (!_systemVars.pastIntro))
_skyControl->restartGame();*/
+ _skySound->checkFxQueue();
_skyMouse->mouseEngine((uint16)_sdl_mouse_x, (uint16)_sdl_mouse_y);
_skyLogic->engine();
if (!_skyLogic->checkProtection()) { // don't let copy prot. screen flash up
@@ -202,7 +203,7 @@ void SkyState::initialise(void) {
_timer = Engine::_timer; // initialize timer *after* _skyScreen has been initialized.
_timer->installProcedure(&timerHandler, 1000000 / 50); //call 50 times per second
- _skyControl = new SkyControl(_skyScreen, _skyDisk, _skyMouse, _skyText, _skyMusic, _skyLogic, _system, getSavePath());
+ _skyControl = new SkyControl(_skyScreen, _skyDisk, _skyMouse, _skyText, _skyMusic, _skyLogic, _skySound, _system, getSavePath());
_skyLogic->useControlInstance(_skyControl);
if (_systemVars.gameVersion == 288)
diff --git a/sky/sound.cpp b/sky/sound.cpp
index be8f22ff60..c174e2f05b 100644
--- a/sky/sound.cpp
+++ b/sky/sound.cpp
@@ -1005,6 +1005,13 @@ static Sfx *musicList[] = {
&fx_25_weld // 394 my anchor weld bodge
};
+SfxQueue SkySound::_sfxQueue[MAX_QUEUED_FX] = {
+ { 0, 0, 0, 0},
+ { 0, 0, 0, 0},
+ { 0, 0, 0, 0},
+ { 0, 0, 0, 0}
+};
+
SkySound::SkySound(SoundMixer *mixer, SkyDisk *pDisk) {
_skyDisk = pDisk;
_soundData = NULL;
@@ -1012,9 +1019,10 @@ SkySound::SkySound(SoundMixer *mixer, SkyDisk *pDisk) {
_voiceHandle = 0;
_effectHandle = 0;
_bgSoundHandle = 0;
- _ingameSound = 0;
_ingameSpeech = 0;
- _sfxPaused = false;
+ _ingameSound0 = _ingameSound1 = 0;
+ _slot0 = _slot1 = -1;
+ _saveSounds[0] = _saveSounds[1] = 0xFFFF;
}
SkySound::~SkySound(void) {
@@ -1048,8 +1056,8 @@ int SkySound::playSound(byte *sound, uint32 size, PlayingSoundHandle *handle) {
void SkySound::loadSection(uint8 pSection) {
- if (_ingameSound) _mixer->stop(_ingameSound - 1);
- _ingameSound = 0;
+ fnStopFx();
+
if (_soundData) free(_soundData);
_soundData = _skyDisk->loadFile(pSection * 4 + SOUND_FILE_BASE, NULL);
if ((_soundData[0x7E] != 0x3C) || (_soundData[0xA5] != 0x8D) || (_soundData[0xA6] != 0x1E) ||
@@ -1060,9 +1068,23 @@ void SkySound::loadSection(uint8 pSection) {
_sfxBaseOfs = (_soundData[0xB0] << 8) | _soundData[0xAF];
_sampleRates = _soundData + sRateTabOfs;
_sfxInfo = _soundData + _sfxBaseOfs;
+ for (uint8 cnt = 0; cnt < 4; cnt++)
+ _sfxQueue[cnt].count = 0;
}
-void SkySound::playSound(uint16 sound, uint16 volume) {
+void SkySound::playSound(uint16 sound, uint16 volume, uint8 channel) {
+
+ if (channel == 0) {
+ if (_slot0 >= 0) {
+ _mixer->stop(_slot0);
+ _slot0 = -1;
+ }
+ } else {
+ if (_slot1 >= 0) {
+ _mixer->stop(_slot1);
+ _slot1 = -1;
+ }
+ }
if (!_soundData) {
warning("SkySound::playSound(%04X, %04X) called with a section having been loaded.\n", sound, volume);
@@ -1070,8 +1092,7 @@ void SkySound::playSound(uint16 sound, uint16 volume) {
}
if (sound > _soundsTotal) {
- if (sound & 0x80) warning("SkySound::playSound(%04X, %04X) not implemented.\n", sound, volume);
- else warning("SkySound::playSound(%04X, %04X) ignored.\n", sound, volume);
+ debug(5, "SkySound::playSound %d ignored, only %d sfx in file.\n", sound, _soundsTotal);
return ;
}
@@ -1080,30 +1101,28 @@ void SkySound::playSound(uint16 sound, uint16 volume) {
// note: all those tables are big endian. Don't ask me why. *sigh*
uint16 sampleRate = (_sampleRates[sound << 2] << 8) | _sampleRates[(sound << 2) | 1];
- uint16 dataOfs = ((_sfxInfo[sound << 3] << 8) | _sfxInfo[(sound << 3) | 1]) << 4;
+ uint32 dataOfs = ((_sfxInfo[sound << 3] << 8) | _sfxInfo[(sound << 3) | 1]) << 4;
dataOfs += _sfxBaseOfs;
uint16 dataSize = (_sfxInfo[(sound << 3) | 2] << 8) | _sfxInfo[(sound << 3) | 3];
uint16 dataLoop = (_sfxInfo[(sound << 3) | 6] << 8) | _sfxInfo[(sound << 3) | 7];
byte flags = SoundMixer::FLAG_UNSIGNED;
- if (dataSize == dataLoop) {
- //flags |= SoundMixer::FLAG_LOOP;
- }
+
+ if (dataSize == dataLoop)
+ flags |= SoundMixer::FLAG_LOOP;
- if (_ingameSound > 0) _mixer->stop(_ingameSound - 1);
_mixer->setVolume(volume);
- _mixer->playRaw(&_ingameSound, _soundData + dataOfs, dataSize, sampleRate, flags);
+ if (channel == 0)
+ _slot0 = _mixer->playRaw(&_ingameSound0, _soundData + dataOfs, dataSize, sampleRate, flags);
+ else
+ _slot1 = _mixer->playRaw(&_ingameSound1, _soundData + dataOfs, dataSize, sampleRate, flags);
}
-void SkySound::fnPauseFx(void) {
+void SkySound::fnStartFx(uint32 sound, uint8 channel) {
- if (_ingameSound) _mixer->stop(_ingameSound - 1);
- _sfxPaused = true;
-}
-
-bool SkySound::fnStartFx(uint32 sound) {
- if (sound < 256 || sound > MAX_FX_NUMBER || _sfxPaused || (SkyState::_systemVars.systemFlags & SF_FX_OFF))
- return true;
+ _saveSounds[channel] = 0xFFFF;
+ if (sound < 256 || sound > MAX_FX_NUMBER || (SkyState::_systemVars.systemFlags & SF_FX_OFF))
+ return;
uint8 screen = (uint8)(SkyLogic::_scriptVariables[SCREEN] & 0xff);
if (sound == 278 && screen == 25) // is this weld in room 25
@@ -1119,7 +1138,7 @@ bool SkySound::fnStartFx(uint32 sound) {
while (roomList[i].room != screen) { // check rooms
i++;
if (roomList[i].room == 0xff)
- return true;
+ return;
}
// get fx volume
@@ -1137,14 +1156,59 @@ bool SkySound::fnStartFx(uint32 sound) {
// Check the flags, the sound may come on after a delay.
if (sfx->flags & SFXF_START_DELAY) {
- // queue sound
+ for (uint8 cnt = 0; cnt < MAX_QUEUED_FX; cnt++) {
+ if (_sfxQueue[cnt].count == 0) {
+ _sfxQueue[cnt].chan = channel;
+ _sfxQueue[cnt].fxNo = sfx->soundNo;
+ _sfxQueue[cnt].vol = volume;
+ _sfxQueue[cnt].count = sfx->flags & 0x7F;
+ return;
+ }
+ }
+ return; // ignore sound if it can't be queued
}
- //if (sfx->flags & SFXF_SAVE)
- // save_fx_0[stfx_cur_chn] = sound;
+ if (sfx->flags & SFXF_SAVE)
+ _saveSounds[channel] = sfx->soundNo | (volume << 8);
- playSound(sfx->soundNo, volume);
- return true;
+ playSound(sfx->soundNo, volume, channel);
+}
+
+void SkySound::checkFxQueue(void) {
+ for (uint8 cnt = 0; cnt < MAX_QUEUED_FX; cnt++) {
+ if (_sfxQueue[cnt].count) {
+ _sfxQueue[cnt].count--;
+ if (_sfxQueue[cnt].count == 0)
+ playSound(_sfxQueue[cnt].fxNo, _sfxQueue[cnt].vol, _sfxQueue[cnt].chan);
+ }
+ }
+}
+
+void SkySound::restoreSfx(void) {
+
+ // queue sfx, so they will be started when the player exits the control panel
+ memset(_sfxQueue, 0, sizeof(_sfxQueue));
+ uint8 queueSlot = 0;
+ if (_saveSounds[0] != 0xFFFF) {
+ _sfxQueue[queueSlot].fxNo = (uint8)_saveSounds[0];
+ _sfxQueue[queueSlot].vol = (uint8)(_saveSounds[0] >> 8);
+ _sfxQueue[queueSlot].chan = 0;
+ _sfxQueue[queueSlot].count = 1;
+ queueSlot++;
+ }
+ if (_saveSounds[1] != 0xFFFF) {
+ _sfxQueue[queueSlot].fxNo = (uint8)_saveSounds[1];
+ _sfxQueue[queueSlot].vol = (uint8)(_saveSounds[1] >> 8);
+ _sfxQueue[queueSlot].chan = 1;
+ _sfxQueue[queueSlot].count = 1;
+ }
+}
+
+void SkySound::fnStopFx(void) {
+ if (_slot0 >= 0) _mixer->stop(_slot0);
+ if (_slot1 >= 0) _mixer->stop(_slot1);
+ _slot0 = _slot1 = -1;
+ _saveSounds[0] = _saveSounds[1] = 0xFFFF;
}
bool SkySound::startSpeech(uint16 textNum) {
@@ -1168,6 +1232,6 @@ bool SkySound::startSpeech(uint16 textNum) {
// TODO: implement pre_after_table_area to find and prefetch file for next speech
- _mixer->playRaw(&_ingameSpeech, playBuffer, speechSize - 64, 11025, SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE);
+ int slt = _mixer->playRaw(&_ingameSpeech, playBuffer, speechSize - 64, 11025, SoundMixer::FLAG_UNSIGNED | SoundMixer::FLAG_AUTOFREE);
return true;
}
diff --git a/sky/sound.h b/sky/sound.h
index 93e6cd9e26..8a64655589 100644
--- a/sky/sound.h
+++ b/sky/sound.h
@@ -26,6 +26,12 @@
#include "sky/disk.h"
#include "common/engine.h"
+struct SfxQueue {
+ uint8 count, fxNo, chan, vol;
+};
+
+#define MAX_QUEUED_FX 4
+
class SkySound {
protected:
@@ -35,7 +41,9 @@ public:
PlayingSoundHandle _voiceHandle;
PlayingSoundHandle _effectHandle;
PlayingSoundHandle _bgSoundHandle;
- PlayingSoundHandle _ingameSound, _ingameSpeech;
+ PlayingSoundHandle _ingameSound0, _ingameSound1, _ingameSpeech;
+
+ uint16 _saveSounds[2];
protected:
@@ -48,23 +56,26 @@ public:
int playBgSound(byte *sound, uint32 size);
void loadSection(uint8 pSection);
- void playSound(uint16 sound, uint16 volume);
- bool fnStartFx(uint32 sound);
+ void playSound(uint16 sound, uint16 volume, uint8 channel);
+ void fnStartFx(uint32 sound, uint8 channel);
bool startSpeech(uint16 textNum);
bool speechFinished(void) { return _ingameSpeech == 0; };
- void fnPauseFx(void);
- void fnUnPauseFx(void) { _sfxPaused = false; };
- void fnStopFx(void) { if (_ingameSound) _mixer->stop(_ingameSound - 1); };
+ void fnPauseFx(void) { _mixer->pause(true); };
+ void fnUnPauseFx(void) { _mixer->pause(false); };
+ void fnStopFx(void);
+ void checkFxQueue(void);
+ void restoreSfx(void);
+ uint8 _soundsTotal;
private:
SkyDisk *_skyDisk;
- uint8 _soundsTotal;
uint16 _sfxBaseOfs;
uint8 *_soundData;
uint8 *_sampleRates, *_sfxInfo;
- bool _sfxPaused;
+ int _slot0, _slot1;
static uint16 _speechConvertTable[8];
+ static SfxQueue _sfxQueue[MAX_QUEUED_FX];
};
#endif