aboutsummaryrefslogtreecommitdiff
path: root/engines
diff options
context:
space:
mode:
Diffstat (limited to 'engines')
-rw-r--r--engines/agi/cycle.cpp4
-rw-r--r--engines/agi/menu.cpp1
-rw-r--r--engines/agos/agos.cpp2
-rw-r--r--engines/cruise/cruise_main.cpp4
-rw-r--r--engines/drascula/drascula.cpp1
-rw-r--r--engines/gob/inter.h1
-rw-r--r--engines/gob/inter_playtoons.cpp22
-rw-r--r--engines/gob/sound/cdrom.cpp1
-rw-r--r--engines/groovie/music.cpp4
-rw-r--r--engines/groovie/music.h2
-rw-r--r--engines/kyra/screen.cpp3
-rw-r--r--engines/kyra/sequences_lok.cpp16
-rw-r--r--engines/lure/res.cpp9
-rw-r--r--engines/made/made.cpp2
-rw-r--r--engines/made/pmvplayer.cpp19
-rw-r--r--engines/made/screen.cpp3
-rw-r--r--engines/saga/actor.h4
-rw-r--r--engines/saga/music.cpp233
-rw-r--r--engines/saga/sndres.cpp59
-rw-r--r--engines/saga/sound.cpp67
-rw-r--r--engines/saga/sound.h6
-rw-r--r--engines/sci/console.cpp38
-rw-r--r--engines/sci/console.h1
-rw-r--r--engines/sci/debug.h3
-rw-r--r--engines/sci/detection.cpp103
-rw-r--r--engines/sci/engine/game.cpp173
-rw-r--r--engines/sci/engine/kernel.cpp151
-rw-r--r--engines/sci/engine/kernel.h23
-rw-r--r--engines/sci/engine/kmovement.cpp2
-rw-r--r--engines/sci/engine/kscripts.cpp16
-rw-r--r--engines/sci/engine/ksound.cpp23
-rw-r--r--engines/sci/engine/memobj.cpp1
-rw-r--r--engines/sci/engine/memobj.h1
-rw-r--r--engines/sci/engine/savegame.cpp33
-rw-r--r--engines/sci/engine/scriptdebug.cpp7
-rw-r--r--engines/sci/engine/seg_manager.cpp244
-rw-r--r--engines/sci/engine/seg_manager.h44
-rw-r--r--engines/sci/engine/state.cpp75
-rw-r--r--engines/sci/engine/state.h17
-rw-r--r--engines/sci/engine/vm.cpp224
-rw-r--r--engines/sci/engine/vm.h59
-rw-r--r--engines/sci/gfx/gfx_state_internal.h1
-rw-r--r--engines/sci/gfx/gfx_widgets.h1
-rw-r--r--engines/sci/resource.cpp181
-rw-r--r--engines/sci/resource.h36
-rw-r--r--engines/sci/sci.cpp5
-rw-r--r--engines/scumm/sound.cpp2
-rw-r--r--engines/tinsel/pcode.cpp8
-rw-r--r--engines/tinsel/tinsel.cpp1
49 files changed, 1024 insertions, 912 deletions
diff --git a/engines/agi/cycle.cpp b/engines/agi/cycle.cpp
index d212f8c2e0..2b4ef7f60a 100644
--- a/engines/agi/cycle.cpp
+++ b/engines/agi/cycle.cpp
@@ -266,8 +266,8 @@ process_key:
}
// commented out to close Sarien bug #438872
- if (key)
- _game.keypress = key;
+ //if (key)
+ // _game.keypress = key;
}
break;
case INPUT_GETSTRING:
diff --git a/engines/agi/menu.cpp b/engines/agi/menu.cpp
index 5d30eda81d..e1db04ff49 100644
--- a/engines/agi/menu.cpp
+++ b/engines/agi/menu.cpp
@@ -408,6 +408,7 @@ bool Menu::keyhandler(int key) {
if (d->enabled) {
debugC(6, kDebugLevelMenu | kDebugLevelInput, "event %d registered", d->event);
_vm->_game.controllerOccured[d->event] = true;
+ _vm->_menuSelected = true;
goto exit_menu;
}
break;
diff --git a/engines/agos/agos.cpp b/engines/agos/agos.cpp
index 07b5c12247..ee2ef98c42 100644
--- a/engines/agos/agos.cpp
+++ b/engines/agos/agos.cpp
@@ -899,7 +899,7 @@ AGOSEngine::~AGOSEngine() {
if (_driver)
delete _driver;
- AudioCD.destroy();
+ AudioCD.stop();
for (uint i = 0; i < _itemHeap.size(); i++) {
delete[] _itemHeap[i];
diff --git a/engines/cruise/cruise_main.cpp b/engines/cruise/cruise_main.cpp
index 94dfc95cb5..aa3283aab7 100644
--- a/engines/cruise/cruise_main.cpp
+++ b/engines/cruise/cruise_main.cpp
@@ -1738,7 +1738,7 @@ void CruiseEngine::mainLoop(void) {
// Delay for the specified amount of time, but still respond to events
bool skipEvents = false;
- while (currentTick < lastTick + _gameSpeed) {
+ do {
g_system->delayMillis(10);
currentTick = g_system->getMillis();
@@ -1749,7 +1749,7 @@ void CruiseEngine::mainLoop(void) {
if (_vm->getDebugger()->isAttached())
_vm->getDebugger()->onFrame();
- }
+ } while (currentTick < lastTick + _gameSpeed);
} else {
manageEvents();
diff --git a/engines/drascula/drascula.cpp b/engines/drascula/drascula.cpp
index 2e3db3478e..3920f8a56c 100644
--- a/engines/drascula/drascula.cpp
+++ b/engines/drascula/drascula.cpp
@@ -106,6 +106,7 @@ DrasculaEngine::DrasculaEngine(OSystem *syst, const DrasculaGameDescription *gam
DrasculaEngine::~DrasculaEngine() {
delete _rnd;
+ stopSound();
free(_charMap);
free(_itemLocations);
diff --git a/engines/gob/inter.h b/engines/gob/inter.h
index c3d3a26f47..057f52b360 100644
--- a/engines/gob/inter.h
+++ b/engines/gob/inter.h
@@ -560,6 +560,7 @@ protected:
bool oPlaytoons_checkData(OpFuncParams &params);
void oPlaytoons_CD_20_23();
void oPlaytoons_CD_25();
+ void oPlaytoons_openItk();
};
} // End of namespace Gob
diff --git a/engines/gob/inter_playtoons.cpp b/engines/gob/inter_playtoons.cpp
index 285360c613..e224f29734 100644
--- a/engines/gob/inter_playtoons.cpp
+++ b/engines/gob/inter_playtoons.cpp
@@ -27,6 +27,7 @@
#include "gob/gob.h"
#include "gob/inter.h"
+#include "gob/helper.h"
#include "gob/global.h"
#include "gob/util.h"
#include "gob/dataio.h"
@@ -70,6 +71,7 @@ void Inter_Playtoons::setupOpcodesDraw() {
OPCODEDRAW(0x20, oPlaytoons_CD_20_23);
OPCODEDRAW(0x23, oPlaytoons_CD_20_23);
OPCODEDRAW(0x25, oPlaytoons_CD_25);
+ OPCODEDRAW(0x85, oPlaytoons_openItk);
}
void Inter_Playtoons::setupOpcodesFunc() {
@@ -137,5 +139,25 @@ void Inter_Playtoons::oPlaytoons_CD_25() {
_vm->_game->_script->readVarIndex();
}
+void Inter_Playtoons::oPlaytoons_openItk() {
+ char fileName[128];
+ char *backSlash;
+
+ _vm->_game->_script->evalExpr(0);
+ strncpy0(fileName, _vm->_game->_script->getResultStr(), 124);
+
+ if (!strchr(fileName, '.'))
+ strcat(fileName, ".ITK");
+
+ // Workaround for Bambou : In the script, the path is hardcoded (!!)
+ if ((backSlash = strrchr(fileName, '\\'))) {
+ debugC(2, kDebugFileIO, "Opening ITK file \"%s\" instead of \"%s\"", backSlash + 1, fileName);
+ _vm->_dataIO->openDataFile(backSlash + 1, true);
+ } else
+ _vm->_dataIO->openDataFile(fileName, true);
+ // All the other checks are meant to verify (if not found at the first try)
+ // if the file is present on the CD or not. As everything is supposed to
+ // be copied, those checks are skipped
+}
} // End of namespace Gob
diff --git a/engines/gob/sound/cdrom.cpp b/engines/gob/sound/cdrom.cpp
index 4d6a7ec966..68cbb1b9e2 100644
--- a/engines/gob/sound/cdrom.cpp
+++ b/engines/gob/sound/cdrom.cpp
@@ -46,6 +46,7 @@ CDROM::CDROM() {
}
CDROM::~CDROM() {
+ stop();
}
void CDROM::readLIC(DataStream &stream) {
diff --git a/engines/groovie/music.cpp b/engines/groovie/music.cpp
index 797290a6f3..a92beee17e 100644
--- a/engines/groovie/music.cpp
+++ b/engines/groovie/music.cpp
@@ -38,6 +38,10 @@ MusicPlayer::MusicPlayer(GroovieEngine *vm) :
_prevCDtrack(0), _backgroundDelay(0) {
}
+MusicPlayer::~MusicPlayer() {
+ AudioCD.stop();
+}
+
void MusicPlayer::playSong(uint32 fileref) {
Common::StackLock lock(_mutex);
diff --git a/engines/groovie/music.h b/engines/groovie/music.h
index 9909c8a185..fb1ddfe9c3 100644
--- a/engines/groovie/music.h
+++ b/engines/groovie/music.h
@@ -37,7 +37,7 @@ namespace Groovie {
class MusicPlayer {
public:
MusicPlayer(GroovieEngine *vm);
- virtual ~MusicPlayer() {}
+ virtual ~MusicPlayer();
void playSong(uint32 fileref);
void setBackgroundSong(uint32 fileref);
diff --git a/engines/kyra/screen.cpp b/engines/kyra/screen.cpp
index 73a3e675e8..f5570acd72 100644
--- a/engines/kyra/screen.cpp
+++ b/engines/kyra/screen.cpp
@@ -1253,8 +1253,7 @@ void Screen::drawShape(uint8 pageNum, const uint8 *shapeData, int x, int y, int
}
if (flags & 0x200) {
- ++_drawShapeVar1;
- _drawShapeVar1 &= (_vm->gameFlags().gameID == GI_KYRA1) ? 0x7 : 0xF;
+ _drawShapeVar1 = (_drawShapeVar1 + 1) & 0x7;
_drawShapeVar3 = drawShapeVar2[_drawShapeVar1];
_drawShapeVar4 = 0;
_drawShapeVar5 = 256;
diff --git a/engines/kyra/sequences_lok.cpp b/engines/kyra/sequences_lok.cpp
index 35f434698b..d2ef351767 100644
--- a/engines/kyra/sequences_lok.cpp
+++ b/engines/kyra/sequences_lok.cpp
@@ -1134,6 +1134,11 @@ void KyraEngine_LoK::seq_playEnding() {
_seqPlayerFlag = false;
_screen->showMouse();
+
+ // To avoid any remaining input events, we remove the queue
+ // over here.
+ _eventList.clear();
+
if (_flags.platform == Common::kPlatformAmiga) {
_screen->_charWidth = -2;
_screen->setCurPage(2);
@@ -1354,15 +1359,12 @@ void KyraEngine_LoK::seq_playCreditsAmiga() {
}
int size = 0;
- const uint8 *bufferTmp = _staticres->loadRawData(k1CreditsStrings, size);
- char *buffer = new char[size];
- assert(buffer);
- memcpy(buffer, bufferTmp, size);
+ const char *creditsData = (const char *)_staticres->loadRawData(k1CreditsStrings, size);
char stringBuffer[81];
memset(stringBuffer, 0, sizeof(stringBuffer));
- char *cur = buffer;
+ const char *cur = creditsData;
char *specialString = stringBuffer;
bool fillRectFlag = false, subWidth = false, centerFlag = false;
x = 0;
@@ -1424,9 +1426,7 @@ void KyraEngine_LoK::seq_playCreditsAmiga() {
removeInputTop();
break;
}
- } while (++cur != buffer + size && !shouldQuit());
-
- delete[] buffer;
+ } while (++cur != (creditsData + size) && !shouldQuit());
}
bool KyraEngine_LoK::seq_skipSequence() const {
diff --git a/engines/lure/res.cpp b/engines/lure/res.cpp
index 7eb76cad32..e921b93384 100644
--- a/engines/lure/res.cpp
+++ b/engines/lure/res.cpp
@@ -550,6 +550,7 @@ void Resources::setTalkingCharacter(uint16 id) {
uint16 englishLoadOffsets[] = {0x3afe, 0x41BD, 0x7167, 0x7172, 0x8617, 0x88ac, 0};
Hotspot *Resources::activateHotspot(uint16 hotspotId) {
+ Resources &resources = Resources::getReference();
HotspotData *res = getHotspot(hotspotId);
if (!res) return NULL;
res->roomNumber &= 0x7fff; // clear any suppression bit in room #
@@ -561,7 +562,6 @@ Hotspot *Resources::activateHotspot(uint16 hotspotId) {
// If it's NPC with a schedule, then activate the schedule
if ((res->npcScheduleId != 0) && (res->npcSchedule.isEmpty())) {
- Resources &resources = Resources::getReference();
CharacterScheduleEntry *entry = resources.charSchedules().getEntry(res->npcScheduleId);
res->npcSchedule.addFront(DISPATCH_ACTION, entry, res->roomNumber);
}
@@ -621,9 +621,12 @@ Hotspot *Resources::activateHotspot(uint16 hotspotId) {
// Special post-load handling
if (res->loadOffset == 3) hotspot->setPersistant(true);
if (res->loadOffset == 5) hotspot->handleTalkDialog();
- if (hotspotId == CASTLE_SKORL_ID)
+ if (hotspotId == CASTLE_SKORL_ID) {
// The Castle skorl has a default room #99, so it needs to be adjusted dynamically
- res->npcSchedule.top().setRoomNumber(res->roomNumber);
+ res->npcSchedule.clear();
+ CharacterScheduleEntry *entry = resources.charSchedules().getEntry(res->npcScheduleId);
+ res->npcSchedule.addFront(DISPATCH_ACTION, entry, res->roomNumber);
+ }
// TODO: Figure out why there's a room set in the animation decode for a range of characters,
// particularly since it doesn't seem to match what happens in-game
diff --git a/engines/made/made.cpp b/engines/made/made.cpp
index c83f7aaf02..e826e3788a 100644
--- a/engines/made/made.cpp
+++ b/engines/made/made.cpp
@@ -127,6 +127,8 @@ MadeEngine::MadeEngine(OSystem *syst, const MadeGameDescription *gameDesc) : Eng
}
MadeEngine::~MadeEngine() {
+ AudioCD.stop();
+
delete _rnd;
delete _pmvPlayer;
delete _res;
diff --git a/engines/made/pmvplayer.cpp b/engines/made/pmvplayer.cpp
index 9796b01dfc..a6ee649eda 100644
--- a/engines/made/pmvplayer.cpp
+++ b/engines/made/pmvplayer.cpp
@@ -62,12 +62,8 @@ bool PmvPlayer::play(const char *filename) {
}
uint frameDelay = _fd->readUint16LE();
- int unk;
_fd->skip(4); // always 0?
- unk = _fd->readByte();
- debug(2, "%i", unk);
- unk = _fd->readByte();
- debug(2, "%i", unk);
+ uint frameCount = _fd->readUint16LE();
_fd->skip(4); // always 0?
uint soundFreq = _fd->readUint16LE();
@@ -80,7 +76,7 @@ bool PmvPlayer::play(const char *filename) {
if (soundFreq == 22254) soundFreq = 22050;
for (int i = 0; i < 22; i++) {
- unk = _fd->readUint16LE();
+ int unk = _fd->readUint16LE();
debug(2, "%i ", unk);
}
@@ -90,7 +86,7 @@ bool PmvPlayer::play(const char *filename) {
_fd->read(_paletteRGB, 768);
_vm->_screen->setRGBPalette(_paletteRGB);
- uint32 frameCount = 0;
+ uint32 frameNumber = 0;
uint16 chunkCount = 0;
uint32 soundSize = 0;
uint32 soundChunkOfs = 0, palChunkOfs = 0;
@@ -108,7 +104,7 @@ bool PmvPlayer::play(const char *filename) {
// get it to work well?
_audioStream = Audio::makeAppendableAudioStream(soundFreq, Audio::Mixer::FLAG_UNSIGNED);
- while (!_vm->shouldQuit() && !_aborted && !_fd->eos()) {
+ while (!_vm->shouldQuit() && !_aborted && !_fd->eos() && frameNumber < frameCount) {
int32 frameTime = _vm->_system->getMillis();
@@ -117,9 +113,6 @@ bool PmvPlayer::play(const char *filename) {
warning("Unknown chunk type");
}
- if (_fd->eos())
- break;
-
// Only reallocate the frame data buffer if its size has changed
if (prevChunkSize != chunkSize || !frameData) {
if (frameData)
@@ -192,7 +185,7 @@ bool PmvPlayer::play(const char *filename) {
updateScreen();
if (skipFrames == 0) {
- int32 waitTime = (frameCount * frameDelay) -
+ int32 waitTime = (frameNumber * frameDelay) -
(g_system->getMillis() - soundStartTime) - (_vm->_system->getMillis() - frameTime);
if (waitTime < 0) {
@@ -204,7 +197,7 @@ bool PmvPlayer::play(const char *filename) {
} else
skipFrames--;
- frameCount++;
+ frameNumber++;
}
diff --git a/engines/made/screen.cpp b/engines/made/screen.cpp
index d55b663296..7471743ba4 100644
--- a/engines/made/screen.cpp
+++ b/engines/made/screen.cpp
@@ -188,7 +188,7 @@ void Screen::drawSurface(Graphics::Surface *sourceSurface, int x, int y, int16 f
if (flipX) {
linePtrAdd = -1;
- sourceAdd = sourceSurface->w;
+ sourceAdd = sourceSurface->w - 1;
} else {
linePtrAdd = 1;
sourceAdd = 0;
@@ -210,6 +210,7 @@ void Screen::drawSurface(Graphics::Surface *sourceSurface, int x, int y, int16 f
}
linePtr += linePtrAdd;
}
+
source += sourcePitch;
dest += clipInfo.destSurface->pitch;
if (_vm->getGameID() != GID_RTZ)
diff --git a/engines/saga/actor.h b/engines/saga/actor.h
index d998c65240..57d06e9e3a 100644
--- a/engines/saga/actor.h
+++ b/engines/saga/actor.h
@@ -183,8 +183,8 @@ enum DragonMoveTypes {
struct PathDirectionData {
int8 direction;
- int x;
- int y;
+ int16 x;
+ int16 y;
};
struct ActorFrameRange {
diff --git a/engines/saga/music.cpp b/engines/saga/music.cpp
index 27566de2c3..8ca946a127 100644
--- a/engines/saga/music.cpp
+++ b/engines/saga/music.cpp
@@ -41,190 +41,6 @@ namespace Saga {
#define BUFFER_SIZE 4096
#define MUSIC_SUNSPOT 26
-class DigitalMusicInputStream : public Audio::AudioStream {
-private:
- Audio::AudioStream *_compressedStream;
- ResourceContext *_context;
- ResourceData * resourceData;
- GameSoundTypes soundType;
- Common::File *_file;
- uint32 _filePos;
- uint32 _startPos;
- uint32 _endPos;
- bool _finished;
- bool _looping;
- int16 _buf[BUFFER_SIZE];
- const int16 *_bufferEnd;
- const int16 *_pos;
- MemoryReadStream *_memoryStream;
- SagaEngine *_vm;
-
- void refill();
- bool eosIntern() const {
- return _pos >= _bufferEnd;
- }
-
-public:
- DigitalMusicInputStream(SagaEngine *vm, ResourceContext *context, uint32 resourceId, bool looping, uint32 loopStart);
- ~DigitalMusicInputStream();
-
- void createCompressedStream();
-
- int readBuffer(int16 *buffer, const int numSamples);
-
- bool endOfData() const { return eosIntern(); }
- bool isStereo() const {
- // The digital music in the ITE Mac demo version is not stereo
- return _vm->getFeatures() & GF_MONO_MUSIC ? false : true;
- }
- int getRate() const { return 11025; }
-};
-
-DigitalMusicInputStream::DigitalMusicInputStream(SagaEngine *vm, ResourceContext *context, uint32 resourceId, bool looping, uint32 loopStart)
- : _vm(vm), _context(context), _finished(false), _looping(looping), _bufferEnd(_buf + BUFFER_SIZE) {
-
- byte compressedHeader[10];
-
- resourceData = context->getResourceData(resourceId);
- _file = context->getFile(resourceData);
-
- _compressedStream = NULL;
-
- if (context->isCompressed) {
- // Read compressed header to determine compression type
- _file->seek((long)resourceData->offset, SEEK_SET);
- _file->read(compressedHeader, 9);
-
- if (compressedHeader[0] == char(0)) {
- soundType = kSoundMP3;
- } else if (compressedHeader[0] == char(1)) {
- soundType = kSoundOGG;
- } else if (compressedHeader[0] == char(2)) {
- soundType = kSoundFLAC;
- }
-
- createCompressedStream();
- }
-
- // Determine the end position
- _filePos = resourceData->offset;
- _endPos = _filePos + resourceData->size;
-
- if (_compressedStream != NULL) {
- _filePos += 9; // skip compressed header
- _endPos -= 9; // decrease size by the size of the compressed header
- }
-
- _startPos = _filePos + loopStart;
- if (_startPos >= _endPos)
- _startPos = _filePos;
-
- // Read in initial data
- refill();
-}
-
-DigitalMusicInputStream::~DigitalMusicInputStream() {
- delete _compressedStream;
-}
-
-void DigitalMusicInputStream::createCompressedStream() {
-#if defined(USE_MAD) || defined(USE_VORBIS) || defined(USE_FLAC)
- uint numLoops = _looping ? 0 : 1;
-#endif
- _memoryStream = _file->readStream(resourceData->size - 9);
-
- switch (soundType) {
-#ifdef USE_MAD
- case kSoundMP3:
- debug(1, "Playing MP3 compressed digital music");
- _compressedStream = Audio::makeMP3Stream(_memoryStream, true, 0, 0, numLoops);
- break;
-#endif
-#ifdef USE_VORBIS
- case kSoundOGG:
- debug(1, "Playing OGG compressed digital music");
- _compressedStream = Audio::makeVorbisStream(_memoryStream, true, 0, 0, numLoops);
- break;
-#endif
-#ifdef USE_FLAC
- case kSoundFLAC:
- debug(1, "Playing FLAC compressed digital music");
- _compressedStream = Audio::makeFlacStream(_memoryStream, true, 0, 0, numLoops);
- break;
-#endif
- default:
- // Unknown compression
- error("Trying to play compressed digital music, but the compression is not known");
- break;
- }
-}
-
-int DigitalMusicInputStream::readBuffer(int16 *buffer, const int numSamples) {
- if (_compressedStream != NULL)
- return _compressedStream->readBuffer(buffer, numSamples);
-
- int samples = 0;
- int len = 0;
-
- while (samples < numSamples && !eosIntern()) {
- len = MIN(numSamples - samples, (int) (_bufferEnd - _pos));
- memcpy(buffer, _pos, len * 2);
- buffer += len;
- _pos += len;
- samples += len;
- if (_pos >= _bufferEnd)
- refill();
- }
- return samples;
-}
-
-void DigitalMusicInputStream::refill() {
- if (_finished)
- return;
-
- uint32 lengthLeft;
- byte *ptr = (byte *) _buf;
-
- _file->seek(_filePos, SEEK_SET);
-
- if (_looping)
- lengthLeft = 2 * BUFFER_SIZE;
- else
- lengthLeft = MIN((uint32) (2 * BUFFER_SIZE), _endPos - _filePos);
-
- while (lengthLeft > 0) {
- uint32 len = _file->read(ptr, MIN(lengthLeft, _endPos - _file->pos()));
-
- if (len & 1)
- len--;
-
-#ifdef SCUMM_BIG_ENDIAN
- if (!_context->isBigEndian) {
-#else
- if (_context->isBigEndian) {
-#endif
- uint16 *ptr16 = (uint16 *)ptr;
- for (uint32 i = 0; i < (len / 2); i++)
- ptr16[i] = SWAP_BYTES_16(ptr16[i]);
- }
-
- lengthLeft -= len;
- ptr += len;
-
- if (lengthLeft > 0)
- _file->seek(_startPos);
- }
-
- _filePos = _file->pos();
- _pos = _buf;
- _bufferEnd = (int16 *)ptr;
-
- if (!_looping && _filePos >= _endPos) {
- _finished = true;
- }
-}
-
-
MusicPlayer::MusicPlayer(MidiDriver *driver) : _parser(0), _driver(driver), _looping(false), _isPlaying(false), _passThrough(false), _isGM(false) {
memset(_channel, 0, sizeof(_channel));
_masterVolume = 0;
@@ -461,9 +277,7 @@ void Music::play(uint32 resourceId, MusicFlags flags) {
sprintf(trackName[1], "track%02d", realTrackNumber);
Audio::AudioStream *stream = 0;
for (int i = 0; i < 2; ++i) {
- // We multiply by 40 / 3 = 1000 / 75 to convert frames to milliseconds
- // FIXME: Do we really want a duration of 10000 frames = 133 seconds, or is that just a random value?
- stream = Audio::AudioStream::openStreamFile(trackName[i], 0, 10000 * 40 / 3, (flags == MUSIC_LOOP) ? 0 : 1);
+ stream = Audio::AudioStream::openStreamFile(trackName[i], 0, 0, (flags == MUSIC_LOOP) ? 0 : 1);
if (stream) {
_mixer->playInputStream(Audio::Mixer::kMusicSoundType, &_musicHandle, stream);
_digitalMusic = true;
@@ -474,15 +288,48 @@ void Music::play(uint32 resourceId, MusicFlags flags) {
if (_vm->getGameId() == GID_ITE) {
if (resourceId >= 9 && resourceId <= 34) {
if (_digitalMusicContext != NULL) {
- //TODO: check resource size
loopStart = 0;
- // fix ITE sunstatm/sunspot score
- if ((_vm->getGameId() == GID_ITE) && (resourceId == MUSIC_SUNSPOT)) {
+ // Fix ITE sunstatm/sunspot score
+ if (resourceId == MUSIC_SUNSPOT)
loopStart = 4 * 18727;
- }
- // digital music
- audioStream = new DigitalMusicInputStream(_vm, _digitalMusicContext, resourceId - 9, flags == MUSIC_LOOP, loopStart);
+ // Digital music
+ ResourceData *resData = _digitalMusicContext->getResourceData(resourceId - 9);
+ Common::File *musicFile = _digitalMusicContext->getFile(resData);
+ int offs = (_digitalMusicContext->isCompressed) ? 9 : 0;
+
+ Common::SeekableSubReadStream *musicStream = new Common::SeekableSubReadStream(musicFile,
+ (uint32)resData->offset + offs, (uint32)resData->offset + resData->size - offs);
+
+ if (!_digitalMusicContext->isCompressed) {
+ byte musicFlags = Audio::Mixer::FLAG_AUTOFREE | Audio::Mixer::FLAG_STEREO |
+ Audio::Mixer::FLAG_16BITS | Audio::Mixer::FLAG_LITTLE_ENDIAN;
+ if (flags == MUSIC_LOOP)
+ musicFlags |= Audio::Mixer::FLAG_LOOP;
+
+ Audio::LinearDiskStreamAudioBlock audioBlocks[1];
+ audioBlocks[0].pos = 0;
+ audioBlocks[0].len = resData->size / 2; // 16-bit sound
+ audioStream = Audio::makeLinearDiskStream(musicStream, audioBlocks, 1, 11025, musicFlags, false, loopStart, 0);
+ } else {
+ // Read compressed header to determine compression type
+ musicFile->seek((uint32)resData->offset, SEEK_SET);
+ byte identifier = musicFile->readByte();
+
+ if (identifier == 0) { // MP3
+#ifdef USE_MAD
+ audioStream = Audio::makeMP3Stream(musicStream, false, 0, 0, (flags == MUSIC_LOOP ? 0 : 1));
+#endif
+ } else if (identifier == 1) { // OGG
+#ifdef USE_VORBIS
+ audioStream = Audio::makeVorbisStream(musicStream, false, 0, 0, (flags == MUSIC_LOOP ? 0 : 1));
+#endif
+ } else if (identifier == 2) { // FLAC
+#ifdef USE_FLAC
+ audioStream = Audio::makeFlacStream(musicStream, false, 0, 0, (flags == MUSIC_LOOP ? 0 : 1));
+#endif
+ }
+ }
}
}
}
diff --git a/engines/saga/sndres.cpp b/engines/saga/sndres.cpp
index b2744482bd..eddd35300e 100644
--- a/engines/saga/sndres.cpp
+++ b/engines/saga/sndres.cpp
@@ -192,7 +192,6 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff
GameSoundTypes resourceType = kSoundPCM;
byte *data = 0;
int rate = 0, size = 0;
- byte flags = 0;
Common::File* file;
if (resourceId == (uint32)-1) {
@@ -269,21 +268,17 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff
}
- // Default sound type is 16-bit PCM (used in ITE)
- buffer.isBigEndian = context->isBigEndian;
- if ((context->fileType & GAME_VOICEFILE) && (_vm->getFeatures() & GF_LE_VOICES))
- buffer.isBigEndian = false;
+ // Default sound type is 16-bit signed PCM, used in ITE by PCM and VOX files
buffer.isCompressed = context->isCompressed;
buffer.soundType = resourceType;
buffer.originalSize = 0;
- buffer.stereo = false;
- buffer.isSigned = true; // default for PCM and VOX
- buffer.frequency = 22050; // default for PCM and VOX
- buffer.sampleBits = 16; // default for PCM and VOX
+ // Set default flags and frequency for PCM, VOC and VOX files, which got no header
+ buffer.flags = Audio::Mixer::FLAG_16BITS;
+ buffer.frequency = 22050;
if (_vm->getGameId() == GID_ITE) {
if (_vm->getFeatures() & GF_8BIT_UNSIGNED_PCM) { // older ITE demos
- buffer.isSigned = false;
- buffer.sampleBits = 8;
+ buffer.flags |= Audio::Mixer::FLAG_UNSIGNED;
+ buffer.flags &= ~Audio::Mixer::FLAG_16BITS;
} else {
// Voice files in newer ITE demo versions are OKI ADPCM (VOX) encoded
if (!scumm_stricmp(context->fileName, "voicesd.rsc"))
@@ -292,6 +287,12 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff
}
buffer.buffer = NULL;
+ // Check for LE sounds
+ if (!context->isBigEndian)
+ buffer.flags |= Audio::Mixer::FLAG_LITTLE_ENDIAN;
+ if ((context->fileType & GAME_VOICEFILE) && (_vm->getFeatures() & GF_LE_VOICES))
+ buffer.flags |= Audio::Mixer::FLAG_LITTLE_ENDIAN;
+
// Older Mac versions of ITE were Macbinary packed
int soundOffset = (context->fileType & GAME_MACBINARY) ? 36 : 0;
@@ -321,25 +322,23 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff
case kSoundShorten:
case kSoundVOC:
if (resourceType == kSoundWAV) {
- result = Audio::loadWAVFromStream(readS, size, rate, flags);
+ result = Audio::loadWAVFromStream(readS, size, rate, buffer.flags);
} else if (resourceType == kSoundAIFF) {
- result = Audio::loadAIFFFromStream(readS, size, rate, flags);
+ result = Audio::loadAIFFFromStream(readS, size, rate, buffer.flags);
+#ifdef ENABLE_SAGA2
+ } else if (resourceType == kSoundShorten) {
+ result = Audio::loadShortenFromStream(readS, size, rate, buffer.flags);
+#endif
} else if (resourceType == kSoundVOC) {
data = Audio::loadVOCFromStream(readS, size, rate);
result = (data != 0);
if (onlyHeader)
free(data);
-#ifdef ENABLE_SAGA2
- } else if (resourceType == kSoundShorten) {
- result = Audio::loadShortenFromStream(readS, size, rate, flags);
-#endif
+ buffer.flags |= Audio::Mixer::FLAG_UNSIGNED;
}
if (result) {
buffer.frequency = rate;
- buffer.sampleBits = (flags & Audio::Mixer::FLAG_16BITS) ? 16 : 8;
- buffer.stereo = flags & Audio::Mixer::FLAG_STEREO;
- buffer.isSigned = (resourceType == kSoundVOC) ? false : !(flags & Audio::Mixer::FLAG_UNSIGNED);
buffer.size = size;
if (!onlyHeader && resourceType != kSoundVOC) {
@@ -360,14 +359,20 @@ bool SndRes::load(ResourceContext *context, uint32 resourceId, SoundBuffer &buff
readS.readByte(); // Skip compression identifier byte
buffer.frequency = readS.readUint16LE();
buffer.originalSize = readS.readUint32LE();
- buffer.sampleBits = readS.readByte();
- buffer.stereo = (readS.readByte() == char(0)) ? false : true;
+ if (readS.readByte() == 8) // read sample bits
+ buffer.flags &= ~Audio::Mixer::FLAG_16BITS;
+ if (readS.readByte() != 0) // read stereo flag
+ buffer.flags |= Audio::Mixer::FLAG_STEREO;
buffer.size = soundResourceLength;
buffer.soundType = resourceType;
- buffer.soundFile = context->getFile(resourceData);
buffer.fileOffset = resourceData->offset + 9; // skip compressed sfx header: byte + uint16 + uint32 + byte + byte
+ if (!onlyHeader) {
+ buffer.buffer = (byte *)malloc(buffer.size);
+ readS.read(buffer.buffer, buffer.size);
+ }
+
result = true;
break;
default:
@@ -403,12 +408,12 @@ int SndRes::getVoiceLength(uint32 resourceId) {
msDouble = (double)buffer.size;
else
msDouble = (double)buffer.originalSize;
- if (buffer.sampleBits == 16) {
+
+ if (buffer.flags & Audio::Mixer::FLAG_16BITS)
msDouble /= 2.0;
- }
- if (buffer.stereo) {
+
+ if (buffer.flags & Audio::Mixer::FLAG_STEREO)
msDouble /= 2.0;
- }
msDouble = msDouble / buffer.frequency * 1000.0;
return (int)msDouble;
diff --git a/engines/saga/sound.cpp b/engines/saga/sound.cpp
index fb7acaca8c..14e5492a48 100644
--- a/engines/saga/sound.cpp
+++ b/engines/saga/sound.cpp
@@ -65,84 +65,45 @@ SndHandle *Sound::getHandle() {
void Sound::playSoundBuffer(Audio::SoundHandle *handle, SoundBuffer &buffer, int volume,
sndHandleType handleType, bool loop) {
- byte flags;
- flags = Audio::Mixer::FLAG_AUTOFREE;
+ buffer.flags |= Audio::Mixer::FLAG_AUTOFREE;
if (loop)
- flags |= Audio::Mixer::FLAG_LOOP;
+ buffer.flags |= Audio::Mixer::FLAG_LOOP;
- if (buffer.sampleBits == 16) {
- flags |= Audio::Mixer::FLAG_16BITS;
-
- if (!buffer.isBigEndian)
- flags |= Audio::Mixer::FLAG_LITTLE_ENDIAN;
- }
- if (buffer.stereo)
- flags |= Audio::Mixer::FLAG_STEREO;
- if (!buffer.isSigned)
- flags |= Audio::Mixer::FLAG_UNSIGNED;
+ Audio::Mixer::SoundType soundType = (handleType == kVoiceHandle) ?
+ Audio::Mixer::kSpeechSoundType : Audio::Mixer::kSFXSoundType;
if (!buffer.isCompressed) {
- if (handleType == kVoiceHandle)
- _mixer->playRaw(Audio::Mixer::kSpeechSoundType, handle, buffer.buffer,
- buffer.size, buffer.frequency, flags, -1, volume);
- else
- _mixer->playRaw(Audio::Mixer::kSFXSoundType, handle, buffer.buffer,
- buffer.size, buffer.frequency, flags, -1, volume);
+ _mixer->playRaw(soundType, handle, buffer.buffer,
+ buffer.size, buffer.frequency, buffer.flags, -1, volume);
} else {
- Audio::AudioStream *stream = NULL;
-#if defined(USE_MAD) || defined(USE_VORBIS) || defined(USE_FLAC)
- MemoryReadStream *tmp = NULL;
-#endif
+ Audio::AudioStream *stream = 0;
switch (buffer.soundType) {
#ifdef USE_MAD
case kSoundMP3:
- debug(1, "Playing MP3 compressed sound");
- buffer.soundFile->seek((long)buffer.fileOffset, SEEK_SET);
- tmp = buffer.soundFile->readStream(buffer.size);
- assert(tmp);
- stream = Audio::makeMP3Stream(tmp, true);
+ stream = Audio::makeMP3Stream(new Common::MemoryReadStream(buffer.buffer, buffer.size, true), true);
break;
#endif
#ifdef USE_VORBIS
case kSoundOGG:
- debug(1, "Playing OGG compressed sound");
- buffer.soundFile->seek((long)buffer.fileOffset, SEEK_SET);
- tmp = buffer.soundFile->readStream(buffer.size);
- assert(tmp);
- stream = Audio::makeVorbisStream(tmp, true);
+ stream = Audio::makeVorbisStream(new Common::MemoryReadStream(buffer.buffer, buffer.size, true), true);
break;
#endif
#ifdef USE_FLAC
case kSoundFLAC:
- debug(1, "Playing FLAC compressed sound");
- buffer.soundFile->seek((long)buffer.fileOffset, SEEK_SET);
- tmp = buffer.soundFile->readStream(buffer.size);
- assert(tmp);
- stream = Audio::makeFlacStream(tmp, true);
+ stream = Audio::makeFlacStream(new Common::MemoryReadStream(buffer.buffer, buffer.size, true), true);
break;
#endif
default:
- // No compression, play it as raw sound
- if (handleType == kVoiceHandle)
- _mixer->playRaw(Audio::Mixer::kSpeechSoundType, handle, buffer.buffer,
- buffer.size, buffer.frequency, flags, -1, volume);
- else
- _mixer->playRaw(Audio::Mixer::kSFXSoundType, handle, buffer.buffer,
- buffer.size, buffer.frequency, flags, -1, volume);
+ // Unknown compression, ignore sample
+ warning("Unknown compression, ignoring sound");
break;
}
- if (stream != NULL) {
- if (handleType == kVoiceHandle)
- _mixer->playInputStream(Audio::Mixer::kSpeechSoundType, handle, stream, -1,
- volume, 0, true, false);
- else
- _mixer->playInputStream(Audio::Mixer::kSFXSoundType, handle, stream, -1,
- volume, 0, true, false);
- }
+ if (stream != NULL)
+ _mixer->playInputStream(soundType, handle, stream, -1, volume, 0, true, false);
}
}
diff --git a/engines/saga/sound.h b/engines/saga/sound.h
index b61cbbbe90..0aeb54a55f 100644
--- a/engines/saga/sound.h
+++ b/engines/saga/sound.h
@@ -44,17 +44,13 @@ enum SOUND_FLAGS {
struct SoundBuffer {
uint16 frequency;
- int sampleBits;
- bool stereo;
- bool isSigned;
bool isCompressed;
+ byte flags;
byte *buffer;
size_t size;
size_t originalSize;
- bool isBigEndian;
GameSoundTypes soundType;
- Common::File *soundFile;
size_t fileOffset;
};
diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp
index 35ca688233..7b329864ce 100644
--- a/engines/sci/console.cpp
+++ b/engines/sci/console.cpp
@@ -889,10 +889,11 @@ bool Console::cmdRestartGame(int argc, const char **argv) {
bool Console::cmdClassTable(int argc, const char **argv) {
DebugPrintf("Available classes:\n");
- for (uint i = 0; i < _vm->_gamestate->_classtable.size(); i++) {
- if (_vm->_gamestate->_classtable[i].reg.segment) {
+ for (uint i = 0; i < _vm->_gamestate->seg_manager->_classtable.size(); i++) {
+ if (_vm->_gamestate->seg_manager->_classtable[i].reg.segment) {
DebugPrintf(" Class 0x%x at %04x:%04x (script 0x%x)\n", i,
- PRINT_REG(_vm->_gamestate->_classtable[i].reg), _vm->_gamestate->_classtable[i].script);
+ PRINT_REG(_vm->_gamestate->seg_manager->_classtable[i].reg),
+ _vm->_gamestate->seg_manager->_classtable[i].script);
}
}
@@ -1394,10 +1395,11 @@ bool Console::segmentInfo(int nr) {
for (uint i = 0; i < scr->_objects.size(); i++) {
DebugPrintf(" ");
// Object header
- Object *obj = obj_get(_vm->_gamestate, scr->_objects[i].pos);
+ Object *obj = obj_get(_vm->_gamestate->seg_manager, _vm->_gamestate->_version, scr->_objects[i].pos);
if (obj)
DebugPrintf("[%04x:%04x] %s : %3d vars, %3d methods\n", PRINT_REG(scr->_objects[i].pos),
- obj_get_name(_vm->_gamestate, scr->_objects[i].pos), obj->_variables.size(), obj->methods_nr);
+ obj_get_name(_vm->_gamestate->seg_manager, _vm->_gamestate->_version,
+ scr->_objects[i].pos), obj->_variables.size(), obj->methods_nr);
}
}
break;
@@ -1438,12 +1440,13 @@ bool Console::segmentInfo(int nr) {
reg_t objpos;
objpos.offset = i;
objpos.segment = nr;
- DebugPrintf(" [%04x] %s; copy of ", i, obj_get_name(_vm->_gamestate, objpos));
+ DebugPrintf(" [%04x] %s; copy of ", i, obj_get_name(_vm->_gamestate->seg_manager, _vm->_gamestate->_version, objpos));
// Object header
- Object *obj = obj_get(_vm->_gamestate, ct->_table[i].pos);
+ Object *obj = obj_get(_vm->_gamestate->seg_manager, _vm->_gamestate->_version, ct->_table[i].pos);
if (obj)
DebugPrintf("[%04x:%04x] %s : %3d vars, %3d methods\n", PRINT_REG(ct->_table[i].pos),
- obj_get_name(_vm->_gamestate, ct->_table[i].pos), obj->_variables.size(), obj->methods_nr);
+ obj_get_name(_vm->_gamestate->seg_manager, _vm->_gamestate->_version, ct->_table[i].pos),
+ obj->_variables.size(), obj->methods_nr);
}
}
break;
@@ -2045,7 +2048,7 @@ bool Console::cmdBacktrace(int argc, const char **argv) {
for (iter = _vm->_gamestate->_executionStack.begin();
iter != _vm->_gamestate->_executionStack.end(); ++iter, ++i) {
ExecStack &call = *iter;
- const char *objname = obj_get_name(_vm->_gamestate, call.sendp);
+ const char *objname = obj_get_name(_vm->_gamestate->seg_manager, _vm->_gamestate->_version, call.sendp);
int paramc, totalparamc;
switch (call.type) {
@@ -2187,7 +2190,7 @@ bool Console::cmdDissassemble(int argc, const char **argv) {
return true;
}
- Object *obj = obj_get(_vm->_gamestate, objAddr);
+ Object *obj = obj_get(_vm->_gamestate->seg_manager, _vm->_gamestate->_version, objAddr);
int selector_id = _vm->getKernel()->findSelector(argv[2]);
reg_t addr;
@@ -2295,7 +2298,7 @@ bool Console::cmdSend(int argc, const char **argv) {
return true;
}
- o = obj_get(_vm->_gamestate, object);
+ o = obj_get(_vm->_gamestate->seg_manager, _vm->_gamestate->_version, object);
if (o == NULL) {
DebugPrintf("Address \"%04x:%04x\" is not an object\n", PRINT_REG(object));
return true;
@@ -2900,7 +2903,7 @@ int parse_reg_t(EngineState *s, const char *str, reg_t *dest) { // Returns 0 on
}
if (valid) {
- const char *objname = obj_get_name(s, objpos);
+ const char *objname = obj_get_name(s->seg_manager, s->_version, objpos);
if (!strcmp(objname, str_objname)) {
// Found a match!
if ((index < 0) && (times_found > 0)) {
@@ -3042,9 +3045,10 @@ int Console::printNode(reg_t addr) {
int Console::printObject(reg_t pos) {
EngineState *s = _vm->_gamestate; // for the several defines in this function
- Object *obj = obj_get(s, pos);
+ Object *obj = obj_get(s->seg_manager, s->_version, pos);
Object *var_container = obj;
int i;
+ SciVersion version = s->_version; // for the selector defines
if (!obj) {
DebugPrintf("[%04x:%04x]: Not an object.", PRINT_REG(pos));
@@ -3052,11 +3056,11 @@ int Console::printObject(reg_t pos) {
}
// Object header
- DebugPrintf("[%04x:%04x] %s : %3d vars, %3d methods\n", PRINT_REG(pos), obj_get_name(s, pos),
+ DebugPrintf("[%04x:%04x] %s : %3d vars, %3d methods\n", PRINT_REG(pos), obj_get_name(s->seg_manager, s->_version, pos),
obj->_variables.size(), obj->methods_nr);
if (!(obj->_variables[SCRIPT_INFO_SELECTOR].offset & SCRIPT_INFO_CLASS))
- var_container = obj_get(s, obj->_variables[SCRIPT_SUPERCLASS_SELECTOR]);
+ var_container = obj_get(s->seg_manager, s->_version, obj->_variables[SCRIPT_SUPERCLASS_SELECTOR]);
DebugPrintf(" -- member variables:\n");
for (i = 0; (uint)i < obj->_variables.size(); i++) {
printf(" ");
@@ -3068,9 +3072,9 @@ int Console::printObject(reg_t pos) {
reg_t val = obj->_variables[i];
DebugPrintf("%04x:%04x", PRINT_REG(val));
- Object *ref = obj_get(s, val);
+ Object *ref = obj_get(s->seg_manager, s->_version, val);
if (ref)
- DebugPrintf(" (%s)", obj_get_name(s, val));
+ DebugPrintf(" (%s)", obj_get_name(s->seg_manager, s->_version, val));
DebugPrintf("\n");
}
diff --git a/engines/sci/console.h b/engines/sci/console.h
index 8d1299dd1e..032a2ff865 100644
--- a/engines/sci/console.h
+++ b/engines/sci/console.h
@@ -29,6 +29,7 @@
#define SCI_CONSOLE_H
#include "gui/debugger.h"
+#include "sci/engine/vm.h"
namespace Sci {
diff --git a/engines/sci/debug.h b/engines/sci/debug.h
index a3c4fab372..e3bca1f0c1 100644
--- a/engines/sci/debug.h
+++ b/engines/sci/debug.h
@@ -26,6 +26,9 @@
#ifndef SCI_DEBUG_H
#define SCI_DEBUG_H
+#include "sci/engine/vm_types.h" // for StackPtr
+#include "sci/engine/vm.h" // for ExecStack
+
namespace Sci {
enum DebugSeeking {
diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp
index 3df5bdb63a..ee9fd5fb18 100644
--- a/engines/sci/detection.cpp
+++ b/engines/sci/detection.cpp
@@ -27,7 +27,9 @@
#include "base/plugins.h"
#include "sci/sci.h"
+#include "sci/engine/kernel.h"
#include "sci/exereader.h"
+#include "sci/engine/seg_manager.h"
namespace Sci {
@@ -3031,6 +3033,76 @@ public:
const ADGameDescription *fallbackDetect(const Common::FSList &fslist) const;
};
+Common::String convertSierraGameId(Common::String sierraId) {
+ // TODO: SCI32 IDs
+
+ // TODO: astrochicken
+ // TODO: The internal id of christmas1998 is "demo"
+ if (sierraId == "card")
+ return "christmas1990";
+ // TODO: christmas1992
+ if (sierraId == "arthur")
+ return "camelot";
+ if (sierraId == "brain")
+ return "castlebrain";
+ // iceman is the same
+ // longbow is the same
+ if (sierraId == "eco")
+ return "ecoquest";
+ if (sierraId == "rain")
+ return "ecoquest2";
+ if (sierraId == "fp")
+ return "freddypharkas";
+ if (sierraId == "emc")
+ return "funseeker";
+ if (sierraId == "cardgames")
+ return "hoyle1";
+ if (sierraId == "solitare")
+ return "hoyle2";
+ // TODO: hoyle3
+ // TODO: hoyle4
+ if (sierraId == "kq1")
+ return "kq1sci";
+ if (sierraId == "kq4")
+ return "kq4sci";
+ if (sierraId == "lsl1")
+ return "lsl1sci";
+ // lsl2 is the same
+ // lsl3 is the same
+ // lsl5 is the same
+ // lsl6 is the same
+ // TODO: lslcasino
+ // TODO: fairytales
+ // TODO: mothergoose
+ // TODO: msastrochicken
+ if (sierraId == "cb1")
+ return "laurabow";
+ if (sierraId == "lb2")
+ return "laurabow2";
+ // TODO: lb2 floppy (its resources can't be read)
+ if (sierraId == "twisty")
+ return "pepper";
+ // TODO: pq1sci (its resources can't be read)
+ if (sierraId == "pq")
+ return "pq2";
+ // pq3 is the same
+ if (sierraId == "glory")
+ return "qfg1";
+ // TODO: qfg1 VGA (its resources can't be read)
+ if (sierraId == "trial")
+ return "qfg2";
+ if (sierraId == "qfg1")
+ return "qfg3";
+ // TODO: slater
+ if (sierraId == "sq1")
+ return "sq1sci";
+ // sq3 is the same
+ // sq4 is the same
+ // sq5 is the same
+ // TODO: islandbrain
+
+ return sierraId;
+}
const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fslist) const {
bool foundResMap = false;
@@ -3046,8 +3118,16 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fsl
Common::String filename = file->getName();
filename.toLowercase();
- if (filename.contains("resource.map") || filename.contains("resmap.000"))
+ if (filename.contains("resource.map") || filename.contains("resmap.000")) {
+ // HACK: resource.map is located in the same directory as the other resource files,
+ // therefore add the directory here, so that the game files can be opened later on
+ // TODO/FIXME: This should be removed, as it will cause problems with game detection:
+ // if we got a game A, and then try to detect another game B, adding a default
+ // directory here means that game A's files will be opened first. We need to rewrite
+ // all the functions that access game files to use FSNodes instead
+ Common::File::addDefaultDirectory(file->getParent().getPath());
foundResMap = true;
+ }
if (filename.contains("resource.000") || filename.contains("resource.001")
|| filename.contains("ressci.000") || filename.contains("ressci.001"))
@@ -3080,12 +3160,31 @@ const ADGameDescription *SciMetaEngine::fallbackDetect(const Common::FSList &fsl
return 0;
// Set some defaults
- s_fallbackDesc.desc.gameid = "sci";
s_fallbackDesc.desc.extra = "";
s_fallbackDesc.desc.language = Common::UNK_LANG;
s_fallbackDesc.desc.platform = exePlatform;
s_fallbackDesc.desc.flags = ADGF_NO_FLAGS;
+ // Determine the game id
+ ResourceManager *resMgr = new ResourceManager(fslist);
+ SciVersion version = resMgr->sciVersion();
+ Kernel *kernel = new Kernel(resMgr, true);
+ bool hasOldScriptHeader = kernel->hasOldScriptHeader();
+ delete kernel;
+
+ SegManager *segManager = new SegManager(resMgr, version, hasOldScriptHeader);
+ if (!script_instantiate(resMgr, segManager, version, hasOldScriptHeader, 0)) {
+ warning("fallbackDetect(): Could not instantiate script 0");
+ return 0;
+ }
+ reg_t game_obj = script_lookup_export(segManager, 0, 0);
+ Common::String gameName = obj_get_name(segManager, version, game_obj);
+ debug(2, "Detected ID: \"%s\" at %04x:%04x", gameName.c_str(), PRINT_REG(game_obj));
+ gameName.toLowercase();
+ s_fallbackDesc.desc.gameid = strdup(convertSierraGameId(gameName).c_str());
+ delete segManager;
+ delete resMgr;
+
printf("If this is *NOT* a fan-modified version (in particular, not a fan-made\n");
printf("translation), please, report the data above, including the following\n");
printf("version number, from the game's executable:\n");
diff --git a/engines/sci/engine/game.cpp b/engines/sci/engine/game.cpp
index 1fa0e03d4c..c34ac1cf00 100644
--- a/engines/sci/engine/game.cpp
+++ b/engines/sci/engine/game.cpp
@@ -188,159 +188,13 @@ int game_init_sound(EngineState *s, int sound_flags) {
return 0;
}
-int create_class_table_sci11(EngineState *s) {
- int scriptnr;
- unsigned int seeker_offset;
- char *seeker_ptr;
- int classnr;
-
- Resource *vocab996 = s->resmgr->findResource(ResourceId(kResourceTypeVocab, 996), 1);
-
- if (!vocab996)
- s->_classtable.resize(20);
- else
- s->_classtable.resize(vocab996->size >> 2);
-
- for (scriptnr = 0; scriptnr < 1000; scriptnr++) {
- Resource *heap = s->resmgr->findResource(ResourceId(kResourceTypeHeap, scriptnr), 0);
-
- if (heap) {
- int global_vars = READ_LE_UINT16(heap->data + 2);
-
- seeker_ptr = (char*)heap->data + 4 + global_vars * 2;
- seeker_offset = 4 + global_vars * 2;
-
- while (READ_LE_UINT16((byte*)seeker_ptr) == SCRIPT_OBJECT_MAGIC_NUMBER) {
- if (READ_LE_UINT16((byte*)seeker_ptr + 14) & SCRIPT_INFO_CLASS) {
- classnr = READ_LE_UINT16((byte*)seeker_ptr + 10);
- if (classnr >= (int)s->_classtable.size()) {
- if (classnr >= SCRIPT_MAX_CLASSTABLE_SIZE) {
- warning("Invalid class number 0x%x in script.%d(0x%x), offset %04x",
- classnr, scriptnr, scriptnr, seeker_offset);
- return 1;
- }
-
- s->_classtable.resize(classnr + 1); // Adjust maximum number of entries
- }
-
- s->_classtable[classnr].reg.offset = seeker_offset;
- s->_classtable[classnr].reg.segment = 0;
- s->_classtable[classnr].script = scriptnr;
- }
-
- seeker_ptr += READ_LE_UINT16((byte*)seeker_ptr + 2) * 2;
- seeker_offset += READ_LE_UINT16((byte*)seeker_ptr + 2) * 2;
- }
- }
- }
-
- s->resmgr->unlockResource(vocab996);
- vocab996 = NULL;
- return 0;
-}
-
-static int create_class_table_sci0(EngineState *s) {
- int scriptnr;
- unsigned int seeker;
- int classnr;
- int magic_offset; // For strange scripts in older SCI versions
-
- Resource *vocab996 = s->resmgr->findResource(ResourceId(kResourceTypeVocab, 996), 1);
-
- if (!vocab996)
- s->_classtable.resize(20);
- else
- s->_classtable.resize(vocab996->size >> 2);
-
- for (scriptnr = 0; scriptnr < 1000; scriptnr++) {
- int objtype = 0;
- Resource *script = s->resmgr->findResource(ResourceId(kResourceTypeScript, scriptnr), 0);
-
- if (script) {
- if (((SciEngine*)g_engine)->getKernel()->hasOldScriptHeader())
- magic_offset = seeker = 2;
- else
- magic_offset = seeker = 0;
-
- do {
- while (seeker < script->size) {
- unsigned int lastseeker = seeker;
- objtype = (int16)READ_LE_UINT16(script->data + seeker);
- if (objtype == SCI_OBJ_CLASS || objtype == SCI_OBJ_TERMINATOR)
- break;
- seeker += (int16)READ_LE_UINT16(script->data + seeker + 2);
- if (seeker <= lastseeker) {
- s->_classtable.clear();
- error("Script version is invalid");
- }
- }
-
- if (objtype == SCI_OBJ_CLASS) {
- int sugg_script;
-
- seeker -= SCRIPT_OBJECT_MAGIC_OFFSET; // Adjust position; script home is base +8 bytes
-
- classnr = (int16)READ_LE_UINT16(script->data + seeker + 4 + SCRIPT_SPECIES_OFFSET);
- if (classnr >= (int)s->_classtable.size()) {
-
- if (classnr >= SCRIPT_MAX_CLASSTABLE_SIZE) {
- warning("Invalid class number 0x%x in script.%d(0x%x), offset %04x",
- classnr, scriptnr, scriptnr, seeker);
- return 1;
- }
-
- s->_classtable.resize(classnr + 1); // Adjust maximum number of entries
- }
-
- // Map the class ID to the script the corresponding class is contained in
- // The script number is found in vocab.996, if it exists
- if (!vocab996 || (uint32)classnr >= vocab996->size >> 2)
- sugg_script = -1;
- else
- sugg_script = (int16)READ_LE_UINT16(vocab996->data + 2 + (classnr << 2));
-
- // First, test whether the script hasn't been claimed, or if it's been claimed by the wrong script
-
- if (sugg_script == -1 || scriptnr == sugg_script /*|| !s->_classtable[classnr].reg.segment*/) {
- // Now set the home script of the class
- s->_classtable[classnr].reg.offset = seeker + 4 - magic_offset;
- s->_classtable[classnr].reg.segment = 0;
- s->_classtable[classnr].script = scriptnr;
- }
-
- seeker += SCRIPT_OBJECT_MAGIC_OFFSET; // Re-adjust position
- seeker += (int16)READ_LE_UINT16(script->data + seeker + 2); // Move to next
- }
-
- } while (objtype != SCI_OBJ_TERMINATOR && seeker <= script->size);
-
- }
- }
- s->resmgr->unlockResource(vocab996);
- vocab996 = NULL;
- return 0;
-}
-
// Architectural stuff: Init/Unintialize engine
int script_init_engine(EngineState *s) {
- int result;
-
s->kernel_opt_flags = 0;
-
- if (s->_version >= SCI_VERSION_1_1)
- result = create_class_table_sci11(s);
- else
- result = create_class_table_sci0(s);
-
- if (result) {
- debug(2, "Failed to initialize class table");
- return 1;
- }
-
- s->seg_manager = new SegManager(s->_version >= SCI_VERSION_1_1);
+ s->seg_manager = new SegManager(s->resmgr, s->_version, ((SciEngine*)g_engine)->getKernel()->hasOldScriptHeader());
s->gc_countdown = GC_INTERVAL - 1;
- SegmentId script_000_segment = script_get_segment(s, 0, SCRIPT_GET_LOCK);
+ SegmentId script_000_segment = s->seg_manager->getSegment(0, SCRIPT_GET_LOCK);
if (script_000_segment <= 0) {
debug(2, "Failed to instantiate script.000");
@@ -398,7 +252,8 @@ void internal_stringfrag_strncpy(EngineState *s, reg_t *dest, reg_t *src, int le
void script_free_vm_memory(EngineState *s) {
debug(2, "Freeing VM memory");
- s->_classtable.clear();
+ if (s->seg_manager)
+ s->seg_manager->_classtable.clear();
// Close all opened file handles
s->_fileHandles.clear();
@@ -433,14 +288,13 @@ void script_free_breakpoints(EngineState *s) {
int game_init(EngineState *s) {
// FIXME Use new VM instantiation code all over the place"
- reg_t game_obj; // Address of the game object
DataStack *stack;
stack = s->seg_manager->allocateStack(VM_STACK_SIZE, &s->stack_segment);
s->stack_base = stack->entries;
s->stack_top = s->stack_base + VM_STACK_SIZE;
- if (!script_instantiate(s, 0)) {
+ if (!script_instantiate(s->resmgr, s->seg_manager, s->_version, ((SciEngine*)g_engine)->getKernel()->hasOldScriptHeader(), 0)) {
warning("game_init(): Could not instantiate script 0");
return 1;
}
@@ -473,20 +327,11 @@ int game_init(EngineState *s) {
srand(g_system->getMillis()); // Initialize random number generator
// script_dissect(0, s->_selectorNames);
- game_obj = script_lookup_export(s, 0, 0);
// The first entry in the export table of script 0 points to the game object
+ s->game_obj = script_lookup_export(s->seg_manager, 0, 0);
+ s->_gameName = obj_get_name(s->seg_manager, s->_version, s->game_obj);
- const char *tmp = obj_get_name(s, game_obj);
-
- if (!tmp) {
- warning("Error: script.000, export 0 (%04x:%04x) does not yield an object with a name -> sanity check failed", PRINT_REG(game_obj));
- return 1;
- }
- s->_gameName = tmp;
-
- debug(2, " \"%s\" at %04x:%04x", s->_gameName.c_str(), PRINT_REG(game_obj));
-
- s->game_obj = game_obj;
+ debug(2, " \"%s\" at %04x:%04x", s->_gameName.c_str(), PRINT_REG(s->game_obj));
// Mark parse tree as unused
s->parser_nodes[0].type = kParseTreeLeafNode;
@@ -512,7 +357,9 @@ int game_exit(EngineState *s) {
game_init_sound(s, SFX_STATE_FLAG_NOSOUND);
}
+ s->seg_manager->_classtable.clear();
delete s->seg_manager;
+ s->seg_manager = 0;
s->_synonyms.clear();
diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp
index 193ff4cc51..223e7fc1e9 100644
--- a/engines/sci/engine/kernel.cpp
+++ b/engines/sci/engine/kernel.cpp
@@ -33,11 +33,7 @@
namespace Sci {
-/** The string used to identify the "unknown" SCI0 function for each game */
-#define SCRIPT_UNKNOWN_FUNCTION_STRING "[Unknown]"
-
// Default kernel name table
-#define SCI0_KNAMES_WELL_DEFINED 0x6e
#define SCI_KNAMES_DEFAULT_ENTRIES_NR 0x89
static const char *sci_default_knames[SCI_KNAMES_DEFAULT_ENTRIES_NR] = {
@@ -367,11 +363,15 @@ static const char *argtype_description[] = {
"Arithmetic"
};
-Kernel::Kernel(ResourceManager *resmgr) : _resmgr(resmgr) {
+Kernel::Kernel(ResourceManager *resmgr, bool minimalLoad) : _resmgr(resmgr) {
memset(&_selectorMap, 0, sizeof(_selectorMap)); // FIXME: Remove this once/if we C++ify selector_map_t
- detectSciFeatures(); // must be called before loadSelectorNames()
loadSelectorNames();
+ detectSciFeatures();
+
+ if (minimalLoad) // If we're only asked to detect game features, stop here
+ return;
+
mapSelectors(); // Map a few special selectors for later use
loadOpcodes();
loadKernelNames();
@@ -382,61 +382,30 @@ Kernel::~Kernel() {
}
void Kernel::detectSciFeatures() {
- // FIXME Much of this is unreliable
-
- Resource *r = _resmgr->findResource(ResourceId(kResourceTypeVocab, VOCAB_RESOURCE_SNAMES), 0);
+ SciVersion version = _resmgr->sciVersion();
- Common::StringList staticSelectorTable;
-
- if (!r) { // No such resource?
- staticSelectorTable = checkStaticSelectorNames();
- if (staticSelectorTable.empty())
- error("Kernel: Could not retrieve selector names");
- }
-
- int count = staticSelectorTable.empty() ? READ_LE_UINT16(r->data) + 1 : staticSelectorTable.size(); // Counter is slightly off
features = 0;
// Initialize features based on SCI version
- switch (_resmgr->sciVersion()) {
- case SCI_VERSION_0_EARLY:
- features |= kFeatureOldScriptHeader;
- /* Fallthrough */
- case SCI_VERSION_0_LATE:
- features |= kFeatureOldGfxFunctions;
- break;
- default:
- break;
- }
-
- for (int i = 0; i < count; i++) {
- Common::String tmp;
-
- if (staticSelectorTable.empty()) {
- int offset = READ_LE_UINT16(r->data + 2 + i * 2);
- int len = READ_LE_UINT16(r->data + offset);
-
- tmp = Common::String((const char *)r->data + offset + 2, len);
- } else {
- tmp = staticSelectorTable[i];
- }
- if (tmp == "motionCue")
- features &= ~kFeatureOldGfxFunctions;
+ // Script header and graphics functions
+ if (version == SCI_VERSION_0_EARLY) {
+ features |= kFeatureOldScriptHeader | kFeatureOldGfxFunctions;
+ } else if (version == SCI_VERSION_0_LATE) {
+ if (findSelector("motionCue") == -1)
+ features |= kFeatureOldGfxFunctions;
+ }
- if (tmp == "egoMoveSpeed" && _resmgr->sciVersion() < SCI_VERSION_1_1)
+ // Lofs absolute/relative
+ if (version >= SCI_VERSION_1_MIDDLE && version < SCI_VERSION_1_1) {
+ // Assume all games use absolute lofs
+ features |= kFeatureLofsAbsolute;
+ } else if (version == SCI_VERSION_1_EARLY) {
+ // Use heuristic
+ if (findSelector("egoMoveSpeed") != -1)
features |= kFeatureLofsAbsolute;
-
- if (tmp == "setVol")
- features |= kFeatureSci1Sound;
-
- if (tmp == "nodePtr")
- features |= kFeatureSci01Sound;
}
- if (features & kFeatureSci1Sound)
- features &= ~kFeatureSci01Sound;
-
printf("Kernel auto-detected features:\n");
printf("Graphics functions: ");
@@ -445,19 +414,13 @@ void Kernel::detectSciFeatures() {
else
printf("new\n");
- printf("lofs parameters: ");
- if (features & kFeatureLofsAbsolute)
- printf("absolute\n");
- else
- printf("relative\n");
-
- printf("Sound functions: ");
- if (features & kFeatureSci1Sound)
- printf("SCI1\n");
- else if (features & kFeatureSci01Sound)
- printf("SCI01\n");
- else
- printf("SCI0\n");
+ if (version < SCI_VERSION_1_1) {
+ printf("lofs parameters: ");
+ if (features & kFeatureLofsAbsolute)
+ printf("absolute\n");
+ else
+ printf("relative\n");
+ }
}
void Kernel::loadSelectorNames() {
@@ -473,7 +436,7 @@ void Kernel::loadSelectorNames() {
for (uint32 i = 0; i < staticSelectorTable.size(); i++) {
_selectorNames.push_back(staticSelectorTable[i]);
- if (features & kFeatureOldScriptHeader)
+ if (_resmgr->sciVersion() == SCI_VERSION_0_EARLY)
_selectorNames.push_back(staticSelectorTable[i]);
}
@@ -492,7 +455,7 @@ void Kernel::loadSelectorNames() {
// Early SCI versions used the LSB in the selector ID as a read/write
// toggle. To compensate for that, we add every selector name twice.
- if (features & kFeatureOldScriptHeader)
+ if (_resmgr->sciVersion() == SCI_VERSION_0_EARLY)
_selectorNames.push_back(tmp);
}
}
@@ -706,6 +669,8 @@ int determine_reg_type(EngineState *s, reg_t reg, bool allow_invalid) {
mobj = s->seg_manager->_heap[reg.segment];
+ SciVersion version = s->_version; // for the offset defines
+
switch (mobj->getType()) {
case MEM_OBJ_SCRIPT:
if (reg.offset <= (*(Script *)mobj).buf_size && reg.offset >= -SCRIPT_OBJECT_MAGIC_OFFSET
@@ -817,32 +782,40 @@ reg_t *kernel_dereference_reg_pointer(EngineState *s, reg_t pointer, int entries
}
void Kernel::setDefaultKernelNames() {
- bool isSci0 = (_resmgr->sciVersion() <= SCI_VERSION_0_LATE);
- int offset = 0;
-
- _kernelNames.resize(SCI_KNAMES_DEFAULT_ENTRIES_NR + (isSci0 ? 4 : 0));
- for (int i = 0; i < SCI_KNAMES_DEFAULT_ENTRIES_NR; i++) {
- // In SCI0, Platform was DoAvoider
- if (!strcmp(sci_default_knames[i], "Platform") && isSci0) {
- _kernelNames[i + offset] = "DoAvoider";
- continue;
- }
+ _kernelNames = Common::StringList(sci_default_knames, SCI_KNAMES_DEFAULT_ENTRIES_NR);
+
+ switch (_resmgr->sciVersion()) {
+ case SCI_VERSION_0_EARLY:
+ case SCI_VERSION_0_LATE:
+ // Insert SCI0 file functions after SetCursor (0x28)
+ _kernelNames.insert_at(0x29, "FOpen");
+ _kernelNames.insert_at(0x2A, "FPuts");
+ _kernelNames.insert_at(0x2B, "FGets");
+ _kernelNames.insert_at(0x2C, "FClose");
- _kernelNames[i + offset] = sci_default_knames[i];
+ // Function 0x55 is DoAvoider
+ _kernelNames[0x55] = "DoAvoider";
- // SCI0 has 4 extra functions between SetCursor (0x28) and Savegame
- if (!strcmp(sci_default_knames[i], "SetCursor") && isSci0) {
- _kernelNames[i + 1] = "FOpen";
- _kernelNames[i + 2] = "FPuts";
- _kernelNames[i + 3] = "FGets";
- _kernelNames[i + 4] = "FClose";
- offset = 4;
- }
- }
+ // Cut off unused functions
+ _kernelNames.resize(0x72);
+ break;
+
+ case SCI_VERSION_01:
+ // Multilingual SCI01 games have StrSplit as function 0x78
+ _kernelNames[0x78] = "StrSplit";
- if (_resmgr->sciVersion() == SCI_VERSION_1_1) {
- // HACK: KQ6CD calls unimplemented function 0x26
+ // Cut off unused functions
+ _kernelNames.resize(0x79);
+ break;
+
+ case SCI_VERSION_1_1:
+ // KQ6CD calls unimplemented function 0x26
_kernelNames[0x26] = "Dummy";
+ break;
+
+ default:
+ // Use default table for the other versions
+ break;
}
}
diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h
index 2c90728fb0..997cdaea77 100644
--- a/engines/sci/engine/kernel.h
+++ b/engines/sci/engine/kernel.h
@@ -32,6 +32,8 @@
#include "sci/uinput.h"
#include "sci/vocabulary.h"
+#include "sci/engine/vm_types.h" // for reg_t
+#include "sci/engine/vm.h"
namespace Sci {
@@ -58,14 +60,17 @@ struct KernelFuncWithSignature {
enum AutoDetectedFeatures {
kFeatureOldScriptHeader = 1 << 0,
kFeatureOldGfxFunctions = 1 << 1,
- kFeatureLofsAbsolute = 1 << 2,
- kFeatureSci01Sound = 1 << 3,
- kFeatureSci1Sound = 1 << 4
+ kFeatureLofsAbsolute = 1 << 2
};
class Kernel {
public:
- Kernel(ResourceManager *resmgr);
+ /**
+ * Initializes the SCI kernel
+ * @param minimalLoad If true, only the selector names are loaded, to detect game features.
+ * It's set to true by the advanced game detector to speed it up
+ */
+ Kernel(ResourceManager *resmgr, bool minimalLoad = false);
~Kernel();
uint getOpcodesSize() const { return _opcodes.size(); }
@@ -117,16 +122,6 @@ public:
*/
bool hasLofsAbsolute() const { return (features & kFeatureLofsAbsolute); }
- /**
- * Determines if the game is using SCI01 sound functions
- */
- bool usesSci01SoundFunctions() const { return (features & kFeatureSci01Sound); }
-
- /**
- * Determines if the game is using SCI1 sound functions
- */
- bool usesSci1SoundFunctions() const { return (features & kFeatureSci1Sound); }
-
// Script dissection/dumping functions
void dissectScript(int scriptNumber, Vocabulary *vocab);
void dumpScriptObject(char *data, int seeker, int objsize);
diff --git a/engines/sci/engine/kmovement.cpp b/engines/sci/engine/kmovement.cpp
index 7433324a70..58dc3b73f1 100644
--- a/engines/sci/engine/kmovement.cpp
+++ b/engines/sci/engine/kmovement.cpp
@@ -257,7 +257,7 @@ static void bresenham_autodetect(EngineState *s) {
reg_t motion_class;
if (!parse_reg_t(s, "?Motion", &motion_class)) {
- Object *obj = obj_get(s, motion_class);
+ Object *obj = obj_get(s->seg_manager, s->_version, motion_class);
reg_t fptr;
byte *buf;
diff --git a/engines/sci/engine/kscripts.cpp b/engines/sci/engine/kscripts.cpp
index df25e11729..4d90dd68ac 100644
--- a/engines/sci/engine/kscripts.cpp
+++ b/engines/sci/engine/kscripts.cpp
@@ -108,7 +108,7 @@ int invoke_selector(EngineState *s, reg_t object, int selector_id, SelectorInvoc
}
bool is_object(EngineState *s, reg_t object) {
- return obj_get(s, object) != NULL;
+ return obj_get(s->seg_manager, s->_version, object) != NULL;
}
// Loads arbitrary resources of type 'restype' with resource numbers 'resnrs'
@@ -184,7 +184,7 @@ reg_t kResCheck(EngineState *s, int funct_nr, int argc, reg_t *argv) {
reg_t kClone(EngineState *s, int funct_nr, int argc, reg_t *argv) {
reg_t parent_addr = argv[0];
- Object *parent_obj = obj_get(s, parent_addr);
+ Object *parent_obj = obj_get(s->seg_manager, s->_version, parent_addr);
reg_t clone_addr;
Clone *clone_obj; // same as Object*
@@ -205,6 +205,8 @@ reg_t kClone(EngineState *s, int funct_nr, int argc, reg_t *argv) {
*clone_obj = *parent_obj;
clone_obj->flags = 0;
+ SciVersion version = s->_version; // for the selector defines
+
// Mark as clone
clone_obj->_variables[SCRIPT_INFO_SELECTOR].offset = SCRIPT_INFO_CLONE;
clone_obj->_variables[SCRIPT_SPECIES_SELECTOR] = clone_obj->pos;
@@ -220,7 +222,7 @@ extern void _k_view_list_mark_free(EngineState *s, reg_t off);
reg_t kDisposeClone(EngineState *s, int funct_nr, int argc, reg_t *argv) {
reg_t victim_addr = argv[0];
- Clone *victim_obj = obj_get(s, victim_addr);
+ Clone *victim_obj = obj_get(s->seg_manager, s->_version, victim_addr);
uint16 underBits;
if (!victim_obj) {
@@ -229,6 +231,8 @@ reg_t kDisposeClone(EngineState *s, int funct_nr, int argc, reg_t *argv) {
return s->r_acc;
}
+ SciVersion version = s->_version; // for the selector defines
+
if (victim_obj->_variables[SCRIPT_INFO_SELECTOR].offset != SCRIPT_INFO_CLONE) {
//warning("Attempt to dispose something other than a clone at %04x", offset);
// SCI silently ignores this behaviour; some games actually depend on it
@@ -260,7 +264,7 @@ reg_t kScriptID(EngineState *s, int funct_nr, int argc, reg_t *argv) {
int script = argv[0].toUint16();
int index = (argc > 1) ? argv[1].toUint16() : 0;
- SegmentId scriptid = script_get_segment(s, script, SCRIPT_GET_LOAD);
+ SegmentId scriptid = s->seg_manager->getSegment(script, SCRIPT_GET_LOAD);
Script *scr;
if (argv[0].segment)
@@ -299,13 +303,13 @@ reg_t kDisposeScript(EngineState *s, int funct_nr, int argc, reg_t *argv) {
scr->setLockers(1);
}
- script_uninstantiate(s, script);
+ script_uninstantiate(s->seg_manager, s->_version, script);
s->_executionStackPosChanged = true;
return s->r_acc;
}
int is_heap_object(EngineState *s, reg_t pos) {
- Object *obj = obj_get(s, pos);
+ Object *obj = obj_get(s->seg_manager, s->_version, pos);
return (obj != NULL && (!(obj->flags & OBJECT_FLAG_FREED)) && (!s->seg_manager->scriptIsMarkedAsDeleted(pos.segment)));
}
diff --git a/engines/sci/engine/ksound.cpp b/engines/sci/engine/ksound.cpp
index 38baeafad8..44b2404e41 100644
--- a/engines/sci/engine/ksound.cpp
+++ b/engines/sci/engine/ksound.cpp
@@ -204,7 +204,7 @@ void process_sound_events(EngineState *s) { /* Get all sound events, apply their
}
-reg_t kDoSound_SCI0(EngineState *s, int funct_nr, int argc, reg_t *argv) {
+reg_t kDoSoundSci0(EngineState *s, int funct_nr, int argc, reg_t *argv) {
reg_t obj = (argc > 1) ? argv[1] : NULL_REG;
uint16 command = argv[0].toUint16();
SongHandle handle = FROBNICATE_HANDLE(obj);
@@ -383,7 +383,7 @@ reg_t kDoSound_SCI0(EngineState *s, int funct_nr, int argc, reg_t *argv) {
}
-reg_t kDoSound_SCI01(EngineState *s, int funct_nr, int argc, reg_t *argv) {
+reg_t kDoSoundSci1Early(EngineState *s, int funct_nr, int argc, reg_t *argv) {
uint16 command = argv[0].toUint16();
reg_t obj = (argc > 1) ? argv[1] : NULL_REG;
SongHandle handle = FROBNICATE_HANDLE(obj);
@@ -673,7 +673,7 @@ reg_t kDoSound_SCI01(EngineState *s, int funct_nr, int argc, reg_t *argv) {
return s->r_acc;
}
-reg_t kDoSound_SCI1(EngineState *s, int funct_nr, int argc, reg_t *argv) {
+reg_t kDoSoundSci1Late(EngineState *s, int funct_nr, int argc, reg_t *argv) {
uint16 command = argv[0].toUint16();
reg_t obj = (argc > 1) ? argv[1] : NULL_REG;
SongHandle handle = FROBNICATE_HANDLE(obj);
@@ -988,12 +988,17 @@ reg_t kDoSound_SCI1(EngineState *s, int funct_nr, int argc, reg_t *argv) {
* Used for synthesized music playback
*/
reg_t kDoSound(EngineState *s, int funct_nr, int argc, reg_t *argv) {
- if (((SciEngine*)g_engine)->getKernel()->usesSci1SoundFunctions())
- return kDoSound_SCI1(s, funct_nr, argc, argv);
- else if (((SciEngine*)g_engine)->getKernel()->usesSci01SoundFunctions())
- return kDoSound_SCI01(s, funct_nr, argc, argv);
- else
- return kDoSound_SCI0(s, funct_nr, argc, argv);
+ switch(s->detectDoSoundType()) {
+ case EngineState::kDoSoundTypeSci0:
+ return kDoSoundSci0(s, funct_nr, argc, argv);
+ case EngineState::kDoSoundTypeSci1Early:
+ return kDoSoundSci1Early(s, funct_nr, argc, argv);
+ case EngineState::kDoSoundTypeSci1Late:
+ return kDoSoundSci1Late(s, funct_nr, argc, argv);
+ default:
+ warning("Unknown DoSound type");
+ return NULL_REG;
+ }
}
/**
diff --git a/engines/sci/engine/memobj.cpp b/engines/sci/engine/memobj.cpp
index ab8e14efc7..34432521a0 100644
--- a/engines/sci/engine/memobj.cpp
+++ b/engines/sci/engine/memobj.cpp
@@ -246,6 +246,7 @@ void Script::listAllDeallocatable(SegmentId segId, void *param, NoteCallback not
void Script::listAllOutgoingReferences(EngineState *s, reg_t addr, void *param, NoteCallback note) {
Script *script = this;
+ SciVersion version = s->_version; // for the offset defines
if (addr.offset <= script->buf_size && addr.offset >= -SCRIPT_OBJECT_MAGIC_OFFSET && RAW_IS_OBJECT(script->buf + addr.offset)) {
int idx = RAW_GET_CLASS_INDEX(script, addr);
diff --git a/engines/sci/engine/memobj.h b/engines/sci/engine/memobj.h
index 50c43a0e88..efe7f26f1c 100644
--- a/engines/sci/engine/memobj.h
+++ b/engines/sci/engine/memobj.h
@@ -27,6 +27,7 @@
#define SCI_ENGINE_MEMOBJ_H
#include "common/serializer.h"
+#include "sci/engine/vm.h"
#include "sci/engine/vm_types.h" // for reg_t
//#include "common/util.h"
diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp
index 75cd4aee54..0ddb5187ac 100644
--- a/engines/sci/engine/savegame.cpp
+++ b/engines/sci/engine/savegame.cpp
@@ -205,19 +205,21 @@ void SegManager::saveLoadWithSerializer(Common::Serializer &s) {
}
static void sync_SegManagerPtr(Common::Serializer &s, SegManager *&obj) {
- bool sci11 = false;
+ SciVersion version = SCI_VERSION_AUTODETECT;
+ ResourceManager *resMgr = 0;
if (s.isSaving()) {
assert(obj);
- sci11 = obj->isSci1_1;
+ version = obj->_version;
+ resMgr = obj->_resMgr;
}
- s.syncAsByte(sci11);
+ s.skip(1); // obsolete: used to be a flag indicating if we got sci11 or not
if (s.isLoading()) {
// FIXME: Do in-place loading at some point, instead of creating a new EngineState instance from scratch.
delete obj;
- obj = new SegManager(sci11);
+ obj = new SegManager(resMgr, version, ((SciEngine*)g_engine)->getKernel()->hasOldScriptHeader());
}
obj->saveLoadWithSerializer(s);
@@ -266,7 +268,7 @@ void EngineState::saveLoadWithSerializer(Common::Serializer &s) {
sync_SegManagerPtr(s, seg_manager);
- syncArray<Class>(s, _classtable);
+ syncArray<Class>(s, seg_manager->_classtable);
sync_sfx_state_t(s, _sound);
}
@@ -549,7 +551,7 @@ static void load_script(EngineState *s, SegmentId seg) {
heap = s->resmgr->findResource(ResourceId(kResourceTypeHeap, scr->nr), 0);
memcpy(scr->buf, script->data, script->size);
- if (s->seg_manager->isSci1_1)
+ if (s->seg_manager->_version == SCI_VERSION_1_1)
memcpy(scr->buf + scr->script_size, heap->data, heap->size);
}
@@ -557,6 +559,8 @@ static void load_script(EngineState *s, SegmentId seg) {
static void reconstruct_scripts(EngineState *s, SegManager *self) {
uint i, j;
MemObject *mobj;
+ SciVersion version = s->_version; // for the selector defines
+
for (i = 0; i < self->_heap.size(); i++) {
if (self->_heap[i]) {
mobj = self->_heap[i];
@@ -567,7 +571,7 @@ static void reconstruct_scripts(EngineState *s, SegManager *self) {
// FIXME: Unify this code with script_instantiate_*
load_script(s, i);
scr->locals_block = (scr->locals_segment == 0) ? NULL : (LocalVariables *)(s->seg_manager->_heap[scr->locals_segment]);
- if (s->seg_manager->isSci1_1) {
+ if (s->seg_manager->_version == SCI_VERSION_1_1) {
scr->export_table = 0;
scr->synonyms = 0;
if (READ_LE_UINT16(scr->buf + 6) > 0) {
@@ -603,7 +607,7 @@ static void reconstruct_scripts(EngineState *s, SegManager *self) {
for (j = 0; j < scr->_objects.size(); j++) {
byte *data = scr->buf + scr->_objects[j].pos.offset;
- if (self->isSci1_1) {
+ if (self->_version == SCI_VERSION_1_1) {
uint16 *funct_area = (uint16 *) (scr->buf + READ_LE_UINT16( data + 6 ));
uint16 *prop_area = (uint16 *) (scr->buf + READ_LE_UINT16( data + 4 ));
@@ -613,7 +617,7 @@ static void reconstruct_scripts(EngineState *s, SegManager *self) {
int funct_area = READ_LE_UINT16( data + SCRIPT_FUNCTAREAPTR_OFFSET );
Object *base_obj;
- base_obj = obj_get(s, scr->_objects[j]._variables[SCRIPT_SPECIES_SELECTOR]);
+ base_obj = obj_get(s->seg_manager, s->_version, scr->_objects[j]._variables[SCRIPT_SPECIES_SELECTOR]);
if (!base_obj) {
warning("Object without a base class: Script %d, index %d (reg address %04x:%04x",
@@ -638,6 +642,8 @@ static void reconstruct_scripts(EngineState *s, SegManager *self) {
// FIXME: The following should likely become a SegManager method
static void reconstruct_clones(EngineState *s, SegManager *self) {
+ SciVersion version = s->_version; // for the selector defines
+
for (uint i = 0; i < self->_heap.size(); i++) {
if (self->_heap[i]) {
MemObject *mobj = self->_heap[i];
@@ -667,7 +673,7 @@ static void reconstruct_clones(EngineState *s, SegManager *self) {
continue;
}
CloneTable::Entry &seeker = ct->_table[j];
- base_obj = obj_get(s, seeker._variables[SCRIPT_SPECIES_SELECTOR]);
+ base_obj = obj_get(s->seg_manager, s->_version, seeker._variables[SCRIPT_SPECIES_SELECTOR]);
if (!base_obj) {
printf("Clone entry without a base class: %d\n", j);
seeker.base = seeker.base_obj = NULL;
@@ -695,8 +701,7 @@ static void reconstruct_sounds(EngineState *s) {
Song *seeker;
SongIteratorType it_type;
- if (((SciEngine *)g_engine)->getKernel()->usesSci01SoundFunctions()
- || ((SciEngine *)g_engine)->getKernel()->usesSci1SoundFunctions())
+ if (s->_version > SCI_VERSION_01)
it_type = SCI_SONG_ITERATOR_TYPE_SCI1;
else
it_type = SCI_SONG_ITERATOR_TYPE_SCI0;
@@ -791,7 +796,7 @@ EngineState *gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) {
reconstruct_scripts(retval, retval->seg_manager);
reconstruct_clones(retval, retval->seg_manager);
retval->game_obj = s->game_obj;
- retval->script_000 = retval->seg_manager->getScript(script_get_segment(s, 0, SCRIPT_GET_DONT_LOAD));
+ retval->script_000 = retval->seg_manager->getScript(retval->seg_manager->getSegment(0, SCRIPT_GET_DONT_LOAD));
retval->gc_countdown = GC_INTERVAL - 1;
retval->sys_strings_segment = find_unique_seg_by_type(retval->seg_manager, MEM_OBJ_SYS_STRINGS);
retval->sys_strings = (SystemStrings *)GET_SEGMENT(*retval->seg_manager, retval->sys_strings_segment, MEM_OBJ_SYS_STRINGS);
@@ -831,7 +836,7 @@ EngineState *gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) {
retval->successor = NULL;
retval->pic_priority_table = (int *)gfxop_get_pic_metainfo(retval->gfx_state);
- retval->_gameName = obj_get_name(retval, retval->game_obj);
+ retval->_gameName = obj_get_name(retval->seg_manager, retval->_version, retval->game_obj);
retval->_sound._it = NULL;
retval->_sound._flags = s->_sound._flags;
diff --git a/engines/sci/engine/scriptdebug.cpp b/engines/sci/engine/scriptdebug.cpp
index 0341ecb73d..fd7219bc85 100644
--- a/engines/sci/engine/scriptdebug.cpp
+++ b/engines/sci/engine/scriptdebug.cpp
@@ -37,9 +37,10 @@ extern const char *selector_name(EngineState *s, int selector);
ScriptState scriptState;
int propertyOffsetToId(EngineState *s, int prop_ofs, reg_t objp) {
- Object *obj = obj_get(s, objp);
+ Object *obj = obj_get(s->seg_manager, s->_version, objp);
byte *selectoroffset;
int selectors;
+ SciVersion version = s->_version; // for the selector defines
if (!obj) {
warning("Applied propertyOffsetToId on non-object at %04x:%04x", PRINT_REG(objp));
@@ -52,7 +53,7 @@ int propertyOffsetToId(EngineState *s, int prop_ofs, reg_t objp) {
selectoroffset = ((byte *)(obj->base_obj)) + SCRIPT_SELECTOR_OFFSET + selectors * 2;
else {
if (!(obj->_variables[SCRIPT_INFO_SELECTOR].offset & SCRIPT_INFO_CLASS)) {
- obj = obj_get(s, obj->_variables[SCRIPT_SUPERCLASS_SELECTOR]);
+ obj = obj_get(s->seg_manager, s->_version, obj->_variables[SCRIPT_SUPERCLASS_SELECTOR]);
selectoroffset = (byte *)obj->base_vars;
} else
selectoroffset = (byte *)obj->base_vars;
@@ -268,7 +269,7 @@ reg_t disassemble(EngineState *s, reg_t pos, int print_bw_tag, int print_bytecod
selector = sb[- stackframe].offset;
- name = obj_get_name(s, called_obj_addr);
+ name = obj_get_name(s->seg_manager, s->_version, called_obj_addr);
if (!name)
name = "<invalid>";
diff --git a/engines/sci/engine/seg_manager.cpp b/engines/sci/engine/seg_manager.cpp
index 905cba9d94..a6f54c5bf7 100644
--- a/engines/sci/engine/seg_manager.cpp
+++ b/engines/sci/engine/seg_manager.cpp
@@ -52,7 +52,7 @@ namespace Sci {
#define INVALID_SCRIPT_ID -1
-SegManager::SegManager(bool sci1_1) {
+SegManager::SegManager(ResourceManager *resMgr, SciVersion version, bool oldScriptHeader) {
id_seg_map = new IntMapper();
reserved_id = INVALID_SCRIPT_ID;
id_seg_map->checkKey(reserved_id, true); // reserve entry 0 for INVALID_SCRIPT_ID
@@ -66,7 +66,19 @@ SegManager::SegManager(bool sci1_1) {
Hunks_seg_id = 0;
exports_wide = 0;
- isSci1_1 = sci1_1;
+ _version = version;
+ _resMgr = resMgr;
+ _oldScriptHeader = oldScriptHeader;
+
+ int result = 0;
+
+ if (version >= SCI_VERSION_1_1)
+ result = createSci11ClassTable();
+ else
+ result = createSci0ClassTable();
+
+ if (result)
+ error("SegManager: Failed to initialize class table");
}
// Destroy the object, free the memorys if allocated before
@@ -109,7 +121,7 @@ MemObject *SegManager::allocNonscriptSegment(MemObjectType type, SegmentId *segi
// Returns : 0 - allocation failure
// 1 - allocated successfully
// seg_id - allocated segment id
-Script *SegManager::allocateScript(EngineState *s, int script_nr, SegmentId *seg_id) {
+Script *SegManager::allocateScript(int script_nr, SegmentId *seg_id) {
bool was_added;
MemObject *mem;
@@ -128,20 +140,20 @@ Script *SegManager::allocateScript(EngineState *s, int script_nr, SegmentId *seg
return (Script *)mem;
}
-void SegManager::setScriptSize(Script &scr, EngineState *s, int script_nr) {
- Resource *script = s->resmgr->findResource(ResourceId(kResourceTypeScript, script_nr), 0);
- Resource *heap = s->resmgr->findResource(ResourceId(kResourceTypeHeap, script_nr), 0);
+void SegManager::setScriptSize(Script &scr, int script_nr) {
+ Resource *script = _resMgr->findResource(ResourceId(kResourceTypeScript, script_nr), 0);
+ Resource *heap = _resMgr->findResource(ResourceId(kResourceTypeHeap, script_nr), 0);
scr.script_size = script->size;
scr.heap_size = 0; // Set later
- if (!script || (s->_version >= SCI_VERSION_1_1 && !heap)) {
+ if (!script || (_version >= SCI_VERSION_1_1 && !heap)) {
error("SegManager::setScriptSize: failed to load %s", !script ? "script" : "heap");
}
- if (((SciEngine*)g_engine)->getKernel()->hasOldScriptHeader()) {
+ if (_oldScriptHeader) {
scr.buf_size = script->size + READ_LE_UINT16(script->data) * 2;
//locals_size = READ_LE_UINT16(script->data) * 2;
- } else if (s->_version < SCI_VERSION_1_1) {
+ } else if (_version < SCI_VERSION_1_1) {
scr.buf_size = script->size;
} else {
scr.buf_size = script->size + heap->size;
@@ -163,10 +175,10 @@ void SegManager::setScriptSize(Script &scr, EngineState *s, int script_nr) {
}
}
-int SegManager::initialiseScript(Script &scr, EngineState *s, int script_nr) {
+int SegManager::initialiseScript(Script &scr, int script_nr) {
// allocate the script.buf
- setScriptSize(scr, s, script_nr);
+ setScriptSize(scr, script_nr);
scr.buf = (byte *)malloc(scr.buf_size);
#ifdef DEBUG_SEG_MANAGER
@@ -191,7 +203,7 @@ int SegManager::initialiseScript(Script &scr, EngineState *s, int script_nr) {
scr.obj_indices = new IntMapper();
- if (s->_version >= SCI_VERSION_1_1)
+ if (_version >= SCI_VERSION_1_1)
scr.heap_start = scr.buf + scr.script_size;
else
scr.heap_start = scr.buf;
@@ -319,7 +331,7 @@ int SegManager::relocateBlock(Common::Array<reg_t> &block, int block_location, S
return 0;
}
block[idx].segment = segment; // Perform relocation
- if (isSci1_1)
+ if (_version == SCI_VERSION_1_1)
block[idx].offset += getScript(segment)->script_size;
return 1;
@@ -429,13 +441,51 @@ void SegManager::heapRelocate(reg_t block) {
}
}
-#define INST_LOOKUP_CLASS(id) ((id == 0xffff) ? NULL_REG : get_class_address(s, id, SCRIPT_GET_LOCK, NULL_REG))
+SegmentId SegManager::getSegment(int script_nr, SCRIPT_GET load) {
+ SegmentId segment;
+
+ if ((load & SCRIPT_GET_LOAD) == SCRIPT_GET_LOAD)
+ script_instantiate(_resMgr, this, _version, _oldScriptHeader, script_nr);
+
+ segment = segGet(script_nr);
+
+ if (segment > 0) {
+ if ((load & SCRIPT_GET_LOCK) == SCRIPT_GET_LOCK)
+ getScript(segment)->incrementLockers();
+
+ return segment;
+ } else
+ return 0;
+}
-reg_t get_class_address(EngineState *s, int classnr, SCRIPT_GET lock, reg_t caller);
+#define INST_LOOKUP_CLASS(id) ((id == 0xffff) ? NULL_REG : get_class_address(id, SCRIPT_GET_LOCK, NULL_REG))
-Object *SegManager::scriptObjInit0(EngineState *s, reg_t obj_pos) {
+reg_t SegManager::get_class_address(int classnr, SCRIPT_GET lock, reg_t caller) {
+ if (classnr < 0 || (int)_classtable.size() <= classnr || _classtable[classnr].script < 0) {
+ error("[VM] Attempt to dereference class %x, which doesn't exist (max %x)", classnr, _classtable.size());
+ return NULL_REG;
+ } else {
+ Class *the_class = &_classtable[classnr];
+ if (!the_class->reg.segment) {
+ getSegment(the_class->script, lock);
+
+ if (!the_class->reg.segment) {
+ error("[VM] Trying to instantiate class %x by instantiating script 0x%x (%03d) failed;"
+ " Entering debugger.", classnr, the_class->script, the_class->script);
+ return NULL_REG;
+ }
+ } else
+ if (caller.segment != the_class->reg.segment)
+ getScript(the_class->reg.segment)->incrementLockers();
+
+ return the_class->reg;
+ }
+}
+
+Object *SegManager::scriptObjInit0(reg_t obj_pos) {
Object *obj;
int id;
+ SciVersion version = _version; // for the offset defines
unsigned int base = obj_pos.offset - SCRIPT_OBJECT_MAGIC_OFFSET;
reg_t temp;
@@ -489,7 +539,7 @@ Object *SegManager::scriptObjInit0(EngineState *s, reg_t obj_pos) {
return obj;
}
-Object *SegManager::scriptObjInit11(EngineState *s, reg_t obj_pos) {
+Object *SegManager::scriptObjInit11(reg_t obj_pos) {
Object *obj;
int id;
int base = obj_pos.offset;
@@ -543,11 +593,11 @@ Object *SegManager::scriptObjInit11(EngineState *s, reg_t obj_pos) {
return obj;
}
-Object *SegManager::scriptObjInit(EngineState *s, reg_t obj_pos) {
- if (!isSci1_1)
- return scriptObjInit0(s, obj_pos);
+Object *SegManager::scriptObjInit(reg_t obj_pos) {
+ if (_version != SCI_VERSION_1_1)
+ return scriptObjInit0(obj_pos);
else
- return scriptObjInit11(s, obj_pos);
+ return scriptObjInit11(obj_pos);
}
LocalVariables *SegManager::allocLocalsSegment(Script *scr, int count) {
@@ -588,7 +638,7 @@ void SegManager::scriptInitialiseLocals(reg_t location) {
VERIFY(location.offset + 1 < (uint16)scr->buf_size, "Locals beyond end of script\n");
- if (isSci1_1)
+ if (_version == SCI_VERSION_1_1)
count = READ_LE_UINT16(scr->buf + location.offset - 2);
else
count = (READ_LE_UINT16(scr->buf + location.offset - 2) - 4) >> 1;
@@ -627,24 +677,25 @@ void SegManager::scriptRelocateExportsSci11(SegmentId seg) {
}
}
-void SegManager::scriptInitialiseObjectsSci11(EngineState *s, SegmentId seg) {
+void SegManager::scriptInitialiseObjectsSci11(SegmentId seg) {
Script *scr = getScript(seg);
byte *seeker = scr->heap_start + 4 + READ_LE_UINT16(scr->heap_start + 2) * 2;
+ SciVersion version = _version; // for the selector defines
while (READ_LE_UINT16(seeker) == SCRIPT_OBJECT_MAGIC_NUMBER) {
if (READ_LE_UINT16(seeker + 14) & SCRIPT_INFO_CLASS) {
int classpos = seeker - scr->buf;
int species = READ_LE_UINT16(seeker + 10);
- if (species < 0 || species >= (int)s->_classtable.size()) {
+ if (species < 0 || species >= (int)_classtable.size()) {
error("Invalid species %d(0x%x) not in interval [0,%d) while instantiating script %d\n",
- species, species, s->_classtable.size(), scr->nr);
+ species, species, _classtable.size(), scr->nr);
return;
}
- s->_classtable[species].script = scr->nr;
- s->_classtable[species].reg.segment = seg;
- s->_classtable[species].reg.offset = classpos;
+ _classtable[species].script = scr->nr;
+ _classtable[species].reg.segment = seg;
+ _classtable[species].reg.offset = classpos;
}
seeker += READ_LE_UINT16(seeker + 2) * 2;
}
@@ -656,12 +707,12 @@ void SegManager::scriptInitialiseObjectsSci11(EngineState *s, SegmentId seg) {
reg.segment = seg;
reg.offset = seeker - scr->buf;
- obj = scriptObjInit(s, reg);
+ obj = scriptObjInit(reg);
#if 0
if (obj->_variables[5].offset != 0xffff) {
obj->_variables[5] = INST_LOOKUP_CLASS(obj->_variables[5].offset);
- base_obj = obj_get(s, obj->_variables[5]);
+ base_obj = obj_get(s->seg_manager, s->_version, obj->_variables[5]);
obj->variable_names_nr = base_obj->variables_nr;
obj->base_obj = base_obj->base_obj;
}
@@ -866,5 +917,138 @@ int SegManager::freeDynmem(reg_t addr) {
return 0; // OK
}
+int SegManager::createSci11ClassTable() {
+ int scriptnr;
+ unsigned int seeker_offset;
+ char *seeker_ptr;
+ int classnr;
+
+ Resource *vocab996 = _resMgr->findResource(ResourceId(kResourceTypeVocab, 996), 1);
+
+ if (!vocab996)
+ _classtable.resize(20);
+ else
+ _classtable.resize(vocab996->size >> 2);
+
+ for (scriptnr = 0; scriptnr < 1000; scriptnr++) {
+ Resource *heap = _resMgr->findResource(ResourceId(kResourceTypeHeap, scriptnr), 0);
+
+ if (heap) {
+ int global_vars = READ_LE_UINT16(heap->data + 2);
+
+ seeker_ptr = (char*)heap->data + 4 + global_vars * 2;
+ seeker_offset = 4 + global_vars * 2;
+
+ while (READ_LE_UINT16((byte*)seeker_ptr) == SCRIPT_OBJECT_MAGIC_NUMBER) {
+ if (READ_LE_UINT16((byte*)seeker_ptr + 14) & SCRIPT_INFO_CLASS) {
+ classnr = READ_LE_UINT16((byte*)seeker_ptr + 10);
+ if (classnr >= (int)_classtable.size()) {
+ if (classnr >= SCRIPT_MAX_CLASSTABLE_SIZE) {
+ warning("Invalid class number 0x%x in script.%d(0x%x), offset %04x",
+ classnr, scriptnr, scriptnr, seeker_offset);
+ return 1;
+ }
+
+ _classtable.resize(classnr + 1); // Adjust maximum number of entries
+ }
+
+ _classtable[classnr].reg.offset = seeker_offset;
+ _classtable[classnr].reg.segment = 0;
+ _classtable[classnr].script = scriptnr;
+ }
+
+ seeker_ptr += READ_LE_UINT16((byte*)seeker_ptr + 2) * 2;
+ seeker_offset += READ_LE_UINT16((byte*)seeker_ptr + 2) * 2;
+ }
+ }
+ }
+
+ _resMgr->unlockResource(vocab996);
+ vocab996 = NULL;
+ return 0;
+}
+
+int SegManager::createSci0ClassTable() {
+ int scriptnr;
+ unsigned int seeker;
+ int classnr;
+ int magic_offset; // For strange scripts in older SCI versions
+
+ Resource *vocab996 = _resMgr->findResource(ResourceId(kResourceTypeVocab, 996), 1);
+ SciVersion version = _version; // for the offset defines
+
+ if (!vocab996)
+ _classtable.resize(20);
+ else
+ _classtable.resize(vocab996->size >> 2);
+
+ for (scriptnr = 0; scriptnr < 1000; scriptnr++) {
+ int objtype = 0;
+ Resource *script = _resMgr->findResource(ResourceId(kResourceTypeScript, scriptnr), 0);
+
+ if (script) {
+ if (_oldScriptHeader)
+ magic_offset = seeker = 2;
+ else
+ magic_offset = seeker = 0;
+
+ do {
+ while (seeker < script->size) {
+ unsigned int lastseeker = seeker;
+ objtype = (int16)READ_LE_UINT16(script->data + seeker);
+ if (objtype == SCI_OBJ_CLASS || objtype == SCI_OBJ_TERMINATOR)
+ break;
+ seeker += (int16)READ_LE_UINT16(script->data + seeker + 2);
+ if (seeker <= lastseeker) {
+ _classtable.clear();
+ error("Script version is invalid");
+ }
+ }
+
+ if (objtype == SCI_OBJ_CLASS) {
+ int sugg_script;
+
+ seeker -= SCRIPT_OBJECT_MAGIC_OFFSET; // Adjust position; script home is base +8 bytes
+
+ classnr = (int16)READ_LE_UINT16(script->data + seeker + 4 + SCRIPT_SPECIES_OFFSET);
+ if (classnr >= (int)_classtable.size()) {
+
+ if (classnr >= SCRIPT_MAX_CLASSTABLE_SIZE) {
+ warning("Invalid class number 0x%x in script.%d(0x%x), offset %04x",
+ classnr, scriptnr, scriptnr, seeker);
+ return 1;
+ }
+
+ _classtable.resize(classnr + 1); // Adjust maximum number of entries
+ }
+
+ // Map the class ID to the script the corresponding class is contained in
+ // The script number is found in vocab.996, if it exists
+ if (!vocab996 || (uint32)classnr >= vocab996->size >> 2)
+ sugg_script = -1;
+ else
+ sugg_script = (int16)READ_LE_UINT16(vocab996->data + 2 + (classnr << 2));
+
+ // First, test whether the script hasn't been claimed, or if it's been claimed by the wrong script
+
+ if (sugg_script == -1 || scriptnr == sugg_script /*|| !s->_classtable[classnr].reg.segment*/) {
+ // Now set the home script of the class
+ _classtable[classnr].reg.offset = seeker + 4 - magic_offset;
+ _classtable[classnr].reg.segment = 0;
+ _classtable[classnr].script = scriptnr;
+ }
+
+ seeker += SCRIPT_OBJECT_MAGIC_OFFSET; // Re-adjust position
+ seeker += (int16)READ_LE_UINT16(script->data + seeker + 2); // Move to next
+ }
+
+ } while (objtype != SCI_OBJ_TERMINATOR && seeker <= script->size);
+
+ }
+ }
+ _resMgr->unlockResource(vocab996);
+ vocab996 = NULL;
+ return 0;
+}
} // End of namespace Sci
diff --git a/engines/sci/engine/seg_manager.h b/engines/sci/engine/seg_manager.h
index 9d406f559f..fcf2659df3 100644
--- a/engines/sci/engine/seg_manager.h
+++ b/engines/sci/engine/seg_manager.h
@@ -43,12 +43,22 @@ namespace Sci {
(((mgr)._heap[index] && ((mgr)._heap[index]->getType() == MEM_OBJ_SCRIPT || (mgr)._heap[index]->getType() == MEM_OBJ_CLONES))? (mgr)._heap[index] \
: NULL): NULL)
+/**
+ * Parameters for getSegment()
+ */
+typedef enum {
+ SCRIPT_GET_DONT_LOAD = 0, /**< Fail if not loaded */
+ SCRIPT_GET_LOAD = 1, /**< Load, if neccessary */
+ SCRIPT_GET_LOCK = 3 /**< Load, if neccessary, and lock */
+} SCRIPT_GET;
+
+
class SegManager : public Common::Serializable {
public:
/**
* Initialize the segment manager
*/
- SegManager(bool sci1_1);
+ SegManager(ResourceManager *resMgr, SciVersion version, bool oldScriptHeader);
/**
* Deallocate all memory associated with the segment manager
@@ -61,14 +71,12 @@ public:
/**
* Allocate a script into the segment manager
- * @param s The state containing resource manager
- * handlers to load the script data
* @param script_nr The number of the script to load
* @param seg_id The segment ID of the newly allocated segment,
* on success
* @return 0 on failure, 1 on success
*/
- Script *allocateScript(EngineState *s, int script_nr, SegmentId *seg_id);
+ Script *allocateScript(int script_nr, SegmentId *seg_id);
// The script must then be initialised; see section (1b.), below.
@@ -154,7 +162,7 @@ public:
* @returns A newly created Object describing the object,
* stored within the relevant script
*/
- Object *scriptObjInit(EngineState *s, reg_t obj_pos);
+ Object *scriptObjInit(reg_t obj_pos);
/**
* Informs the segment manager that a code block must be relocated
@@ -317,21 +325,31 @@ public:
*/
byte *dereference(reg_t reg, int *size);
-
+ /**
+ * Determines the segment occupied by a certain script
+ * @param[in] script_id The script in question
+ * @param[in] load One of SCRIPT_GET_*
+ * @return The script's segment, or 0 on failure
+ */
+ SegmentId getSegment(int script_nr, SCRIPT_GET load);
+ reg_t get_class_address(int classnr, SCRIPT_GET lock, reg_t caller);
void heapRelocate(reg_t block);
void scriptRelocateExportsSci11(SegmentId seg);
- void scriptInitialiseObjectsSci11(EngineState *s, SegmentId seg);
- int initialiseScript(Script &scr, EngineState *s, int script_nr);
+ void scriptInitialiseObjectsSci11(SegmentId seg);
+ int initialiseScript(Script &scr, int script_nr);
private:
IntMapper *id_seg_map; ///< id - script id; seg - index of heap
+ bool _oldScriptHeader;
public: // TODO: make private
Common::Array<MemObject *> _heap;
int reserved_id;
int exports_wide;
- bool isSci1_1;
+ SciVersion _version;
+ ResourceManager *_resMgr;
+ Common::Array<Class> _classtable; /**< Table of all classes */
SegmentId Clones_seg_id; ///< ID of the (a) clones segment
SegmentId Lists_seg_id; ///< ID of the (a) list segment
@@ -343,6 +361,8 @@ private:
LocalVariables *allocLocalsSegment(Script *scr, int count);
MemObject *memObjAllocate(SegmentId segid, int hash_id, MemObjectType type);
int deallocate(SegmentId seg, bool recursive);
+ int createSci0ClassTable();
+ int createSci11ClassTable();
Hunk *alloc_Hunk(reg_t *);
@@ -351,9 +371,9 @@ private:
int relocateObject(Object *obj, SegmentId segment, int location);
int findFreeId(int *id);
- static void setScriptSize(Script &scr, EngineState *s, int script_nr);
- Object *scriptObjInit0(EngineState *s, reg_t obj_pos);
- Object *scriptObjInit11(EngineState *s, reg_t obj_pos);
+ void setScriptSize(Script &scr, int script_nr);
+ Object *scriptObjInit0(reg_t obj_pos);
+ Object *scriptObjInit11(reg_t obj_pos);
/**
* Check segment validity
diff --git a/engines/sci/engine/state.cpp b/engines/sci/engine/state.cpp
index fd45ef5834..baa51bcb58 100644
--- a/engines/sci/engine/state.cpp
+++ b/engines/sci/engine/state.cpp
@@ -24,6 +24,8 @@
*/
#include "sci/engine/state.h"
+#include "sci/engine/vm.h"
+#include "sci/console.h" // For parse_reg_t
namespace Sci {
@@ -116,6 +118,8 @@ EngineState::EngineState(ResourceManager *res, SciVersion version, uint32 flags)
successor = 0;
speedThrottler = new SpeedThrottler(version);
+
+ _doSoundType = kDoSoundTypeUnknown;
}
EngineState::~EngineState() {
@@ -242,4 +246,75 @@ Common::String EngineState::strSplit(const char *str, const char *sep) {
return retval;
}
+EngineState::DoSoundType EngineState::detectDoSoundType() {
+ if (_doSoundType == kDoSoundTypeUnknown) {
+ reg_t soundClass;
+ const uint checkBytes = 6; // Number of bytes to check
+
+ if (!parse_reg_t(this, "?Sound", &soundClass)) {
+ reg_t fptr;
+
+ Object *obj = obj_get(seg_manager, _version, soundClass);
+ SelectorType sel = lookup_selector(this, soundClass, ((SciEngine*)g_engine)->getKernel()->_selectorMap.play, NULL, &fptr);
+
+ if (obj && (sel == kSelectorMethod)) {
+ Script *script = seg_manager->getScript(fptr.segment);
+
+ if (fptr.offset > checkBytes) {
+ // Go to the last portion of Sound::init, should be right before the play function
+ fptr.offset -= checkBytes;
+ byte *buf = script->buf + fptr.offset;
+
+ // Check the call to DoSound's INIT_HANDLE function.
+ // It's either subfunction 0, 5 or 6, depending on the version of DoSound.
+ uint sum = 0;
+ for (uint i = 0; i < checkBytes; i++)
+ sum += buf[i];
+
+ switch(sum) {
+ case 0x1B2: // SCI0
+ case 0x1AE: // SCI01
+ _doSoundType = kDoSoundTypeSci0;
+ break;
+ case 0x13D:
+ _doSoundType = kDoSoundTypeSci1Early;
+ break;
+ case 0x13E:
+ _doSoundType = kDoSoundTypeSci1Late;
+ }
+ }
+ }
+ }
+
+ if (_doSoundType == kDoSoundTypeUnknown) {
+ warning("DoSound detection failed, taking an educated guess");
+
+ if (_version >= SCI_VERSION_1_MIDDLE)
+ _doSoundType = kDoSoundTypeSci1Late;
+ else if (_version > SCI_VERSION_01)
+ _doSoundType = kDoSoundTypeSci1Early;
+ else
+ _doSoundType = kDoSoundTypeSci0;
+ }
+
+ debugCN(1, kDebugLevelSound, "Detected DoSound type: ");
+
+ switch(_doSoundType) {
+ case kDoSoundTypeSci0:
+ debugC(1, kDebugLevelSound, "SCI0");
+ break;
+ case kDoSoundTypeSci1Early:
+ debugC(1, kDebugLevelSound, "SCI1 Early");
+ break;
+ case kDoSoundTypeSci1Late:
+ debugC(1, kDebugLevelSound, "SCI1 Late");
+ break;
+ default:
+ break;
+ }
+ }
+
+ return _doSoundType;
+}
+
} // End of namespace Sci
diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h
index 39dcbb0c0b..a3983f6ae4 100644
--- a/engines/sci/engine/state.h
+++ b/engines/sci/engine/state.h
@@ -163,6 +163,14 @@ struct EngineState : public Common::Serializable {
public:
EngineState(ResourceManager *res, SciVersion version, uint32 flags);
virtual ~EngineState();
+
+ enum DoSoundType {
+ kDoSoundTypeUnknown,
+ kDoSoundTypeSci0,
+ kDoSoundTypeSci1Early,
+ kDoSoundTypeSci1Late
+ };
+
virtual void saveLoadWithSerializer(Common::Serializer &ser);
kLanguage getLanguage();
@@ -272,6 +280,12 @@ public:
*/
Common::String strSplit(const char *str, const char *sep = "\r----------\r");
+ /**
+ * Autodetects the DoSound type
+ * @return DoSound type
+ */
+ DoSoundType detectDoSoundType();
+
/* Debugger data: */
Breakpoint *bp_list; /**< List of breakpoints */
int have_bp; /**< Bit mask specifying which types of breakpoints are used in bp_list */
@@ -291,8 +305,6 @@ public:
reg_t game_obj; /**< Pointer to the game object */
- Common::Array<Class> _classtable; /**< Table of all classes */
-
SegManager *seg_manager;
int gc_countdown; /**< Number of kernel calls until next gc */
@@ -303,6 +315,7 @@ public:
EngineState *successor; /**< Successor of this state: Used for restoring */
private:
+ DoSoundType _doSoundType;
kLanguage charToLanguage(const char c) const;
Common::String getLanguageString(const char *str, kLanguage lang) const;
};
diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp
index ae07c314d4..64ee7243fb 100644
--- a/engines/sci/engine/vm.cpp
+++ b/engines/sci/engine/vm.cpp
@@ -187,34 +187,6 @@ static void validate_write_var(reg_t *r, reg_t *stack_base, int type, int max, i
#define OBJ_PROPERTY(o, p) (validate_property(o, p))
-reg_t get_class_address(EngineState *s, int classnr, SCRIPT_GET lock, reg_t caller) {
-
- if (NULL == s) {
- warning("vm.c: get_class_address(): NULL passed for \"s\"");
- return NULL_REG;
- }
-
- if (classnr < 0 || (int)s->_classtable.size() <= classnr || s->_classtable[classnr].script < 0) {
- error("[VM] Attempt to dereference class %x, which doesn't exist (max %x)", classnr, s->_classtable.size());
- return NULL_REG;
- } else {
- Class *the_class = &s->_classtable[classnr];
- if (!the_class->reg.segment) {
- script_get_segment(s, the_class->script, lock);
-
- if (!the_class->reg.segment) {
- error("[VM] Trying to instantiate class %x by instantiating script 0x%x (%03d) failed;"
- " Entering debugger.", classnr, the_class->script, the_class->script);
- return NULL_REG;
- }
- } else
- if (caller.segment != the_class->reg.segment)
- s->seg_manager->getScript(the_class->reg.segment)->incrementLockers();
-
- return the_class->reg;
- }
-}
-
// Operating on the stack
// 16 bit:
#define PUSH(v) PUSH32(make_reg(0, v))
@@ -236,7 +208,7 @@ ExecStack *execute_method(EngineState *s, uint16 script, uint16 pubfunct, StackP
Script *scr = s->seg_manager->getScriptIfLoaded(seg);
if (!scr) // Script not present yet?
- seg = script_instantiate(s, script);
+ seg = script_instantiate(s->resmgr, s->seg_manager, s->_version, ((SciEngine*)g_engine)->getKernel()->hasOldScriptHeader(), script);
else
scr->unmarkDeleted();
@@ -313,7 +285,7 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt
Breakpoint *bp;
char method_name [256];
- sprintf(method_name, "%s::%s", obj_get_name(s, send_obj), ((SciEngine*)g_engine)->getKernel()->getSelectorName(selector).c_str());
+ sprintf(method_name, "%s::%s", obj_get_name(s->seg_manager, s->_version, send_obj), ((SciEngine*)g_engine)->getKernel()->getSelectorName(selector).c_str());
bp = s->bp_list;
while (bp) {
@@ -501,10 +473,6 @@ void vm_handle_fatal_error(EngineState *s, int line, const char *file) {
error("Fatal VM error in %s, L%d; aborting...", file, line);
}
-static Script *script_locate_by_segment(EngineState *s, SegmentId seg) {
- return s->seg_manager->getScriptIfLoaded(seg);
-}
-
static reg_t pointer_add(EngineState *s, reg_t base, int offset) {
MemObject *mobj = GET_SEGMENT_ANY(*s->seg_manager, base.segment);
@@ -559,8 +527,8 @@ void run_vm(EngineState *s, int restoring) {
// Current execution data:
scriptState.xs = &(s->_executionStack.back());
ExecStack *xs_new = NULL;
- Object *obj = obj_get(s, scriptState.xs->objp);
- Script *local_script = script_locate_by_segment(s, scriptState.xs->local_segment);
+ Object *obj = obj_get(s->seg_manager, s->_version, scriptState.xs->objp);
+ Script *local_script = s->seg_manager->getScriptIfLoaded(scriptState.xs->local_segment);
int old_execution_stack_base = s->execution_stack_base;
// Used to detect the stack bottom, for "physical" returns
const byte *code_buf = NULL; // (Avoid spurious warning)
@@ -606,7 +574,7 @@ void run_vm(EngineState *s, int restoring) {
scriptState.xs = &(s->_executionStack.back());
s->_executionStackPosChanged = false;
- scr = script_locate_by_segment(s, scriptState.xs->addr.pc.segment);
+ scr = s->seg_manager->getScriptIfLoaded(scriptState.xs->addr.pc.segment);
if (!scr) {
// No script? Implicit return via fake instruction buffer
warning("Running on non-existant script in segment %x", scriptState.xs->addr.pc.segment);
@@ -619,12 +587,12 @@ void run_vm(EngineState *s, int restoring) {
scr = NULL;
obj = NULL;
} else {
- obj = obj_get(s, scriptState.xs->objp);
+ obj = obj_get(s->seg_manager, s->_version, scriptState.xs->objp);
code_buf = scr->buf;
#ifndef DISABLE_VALIDATIONS
code_buf_size = scr->buf_size;
#endif
- local_script = script_locate_by_segment(s, scriptState.xs->local_segment);
+ local_script = s->seg_manager->getScriptIfLoaded(scriptState.xs->local_segment);
if (!local_script) {
warning("Could not find local script from segment %x", scriptState.xs->local_segment);
local_script = NULL;
@@ -1077,7 +1045,7 @@ void run_vm(EngineState *s, int restoring) {
break;
case 0x28: // class
- s->r_acc = get_class_address(s, (unsigned)opparams[0], SCRIPT_GET_LOCK,
+ s->r_acc = s->seg_manager->get_class_address((unsigned)opparams[0], SCRIPT_GET_LOCK,
scriptState.xs->addr.pc);
break;
@@ -1097,7 +1065,7 @@ void run_vm(EngineState *s, int restoring) {
break;
case 0x2b: // super
- r_temp = get_class_address(s, opparams[0], SCRIPT_GET_LOAD, scriptState.xs->addr.pc);
+ r_temp = s->seg_manager->get_class_address(opparams[0], SCRIPT_GET_LOAD, scriptState.xs->addr.pc);
if (!r_temp.segment)
error("[VM]: Invalid superclass in object");
@@ -1432,6 +1400,7 @@ void run_vm(EngineState *s, int restoring) {
static int _obj_locate_varselector(EngineState *s, Object *obj, Selector slc) {
// Determines if obj explicitly defines slc as a varselector
// Returns -1 if not found
+ SciVersion version = s->_version; // for the selector defines
if (s->_version < SCI_VERSION_1_1) {
int varnum = obj->variable_names_nr;
@@ -1452,7 +1421,7 @@ static int _obj_locate_varselector(EngineState *s, Object *obj, Selector slc) {
int varnum = obj->_variables[1].offset;
if (!(obj->_variables[SCRIPT_INFO_SELECTOR].offset & SCRIPT_INFO_CLASS))
- buf = ((byte *) obj_get(s, obj->_variables[SCRIPT_SUPERCLASS_SELECTOR])->base_vars);
+ buf = ((byte *) obj_get(s->seg_manager, s->_version, obj->_variables[SCRIPT_SUPERCLASS_SELECTOR])->base_vars);
for (i = 0; i < varnum; i++)
if (READ_LE_UINT16(buf + (i << 1)) == slc) // Found it?
@@ -1478,6 +1447,7 @@ static int _class_locate_funcselector(EngineState *s, Object *obj, Selector slc)
static SelectorType _lookup_selector_function(EngineState *s, int seg_id, Object *obj, Selector selector_id, reg_t *fptr) {
int index;
+ SciVersion version = s->_version; // for the selector defines
// "recursive" lookup
@@ -1492,7 +1462,7 @@ static SelectorType _lookup_selector_function(EngineState *s, int seg_id, Object
return kSelectorMethod;
} else {
seg_id = obj->_variables[SCRIPT_SUPERCLASS_SELECTOR].segment;
- obj = obj_get(s, obj->_variables[SCRIPT_SUPERCLASS_SELECTOR]);
+ obj = obj_get(s->seg_manager, s->_version, obj->_variables[SCRIPT_SUPERCLASS_SELECTOR]);
}
}
@@ -1500,9 +1470,10 @@ static SelectorType _lookup_selector_function(EngineState *s, int seg_id, Object
}
SelectorType lookup_selector(EngineState *s, reg_t obj_location, Selector selector_id, ObjVarRef *varp, reg_t *fptr) {
- Object *obj = obj_get(s, obj_location);
+ Object *obj = obj_get(s->seg_manager, s->_version, obj_location);
Object *species;
int index;
+ SciVersion version = s->_version; // for the selector defines
// Early SCI versions used the LSB in the selector ID as a read/write
// toggle, meaning that we must remove it for selector lookup.
@@ -1517,7 +1488,7 @@ SelectorType lookup_selector(EngineState *s, reg_t obj_location, Selector select
if (IS_CLASS(obj))
species = obj;
else
- species = obj_get(s, obj->_variables[SCRIPT_SPECIES_SELECTOR]);
+ species = obj_get(s->seg_manager, s->_version, obj->_variables[SCRIPT_SPECIES_SELECTOR]);
if (!obj) {
@@ -1540,65 +1511,27 @@ SelectorType lookup_selector(EngineState *s, reg_t obj_location, Selector select
return _lookup_selector_function(s, obj_location.segment, obj, selector_id, fptr);
}
-SegmentId script_get_segment(EngineState *s, int script_nr, SCRIPT_GET load) {
- SegmentId segment;
-
- if ((load & SCRIPT_GET_LOAD) == SCRIPT_GET_LOAD)
- script_instantiate(s, script_nr);
-
- segment = s->seg_manager->segGet(script_nr);
-
- if (segment > 0) {
- if ((load & SCRIPT_GET_LOCK) == SCRIPT_GET_LOCK)
- s->seg_manager->getScript(segment)->incrementLockers();
-
- return segment;
- } else
- return 0;
+reg_t script_lookup_export(SegManager *segManager, int script_nr, int export_index) {
+ SegmentId seg = segManager->getSegment(script_nr, SCRIPT_GET_DONT_LOAD);
+ Script *script = segManager->getScriptIfLoaded(seg);
+ return make_reg(seg, READ_LE_UINT16((byte *)(script->export_table + export_index)));
}
-reg_t script_lookup_export(EngineState *s, int script_nr, int export_index) {
- SegmentId seg = script_get_segment(s, script_nr, SCRIPT_GET_DONT_LOAD);
- Script *script = NULL;
+#define INST_LOOKUP_CLASS(id) ((id == 0xffff)? NULL_REG : segManager->get_class_address(id, SCRIPT_GET_LOCK, reg))
-#ifndef DISABLE_VALIDATIONS
- if (!seg)
- error("script_lookup_export(): script.%03d (0x%x) is invalid or not loaded",
- script_nr, script_nr);
-#endif
-
- script = script_locate_by_segment(s, seg);
-
-#ifndef DISABLE_VALIDATIONS
- if (script && export_index < script->exports_nr && export_index >= 0)
-#endif
- return make_reg(seg, READ_LE_UINT16((byte *)(script->export_table + export_index)));
-#ifndef DISABLE_VALIDATIONS
- else {
- if (!script)
- error("script_lookup_export(): script.%03d missing", script_nr);
- else
- error("script_lookup_export(): script.%03d: Sought invalid export %d/%d",
- script_nr, export_index, script->exports_nr);
- }
-#endif
-}
-
-#define INST_LOOKUP_CLASS(id) ((id == 0xffff)? NULL_REG : get_class_address(s, id, SCRIPT_GET_LOCK, reg))
-
-int script_instantiate_common(EngineState *s, int script_nr, Resource **script, Resource **heap, int *was_new) {
+int script_instantiate_common(ResourceManager *resMgr, SegManager *segManager, SciVersion version, int script_nr, Resource **script, Resource **heap, int *was_new) {
int seg_id;
reg_t reg;
*was_new = 1;
- *script = s->resmgr->findResource(ResourceId(kResourceTypeScript, script_nr), 0);
- if (s->_version >= SCI_VERSION_1_1)
- *heap = s->resmgr->findResource(ResourceId(kResourceTypeHeap, script_nr), 0);
+ *script = resMgr->findResource(ResourceId(kResourceTypeScript, script_nr), 0);
+ if (version >= SCI_VERSION_1_1)
+ *heap = resMgr->findResource(ResourceId(kResourceTypeHeap, script_nr), 0);
- if (!*script || (s->_version >= SCI_VERSION_1_1 && !heap)) {
+ if (!*script || (version >= SCI_VERSION_1_1 && !heap)) {
warning("Script 0x%x requested but not found", script_nr);
- if (s->_version >= SCI_VERSION_1_1) {
+ if (version >= SCI_VERSION_1_1) {
if (*heap)
warning("Inconsistency: heap resource WAS found");
else if (*script)
@@ -1607,13 +1540,8 @@ int script_instantiate_common(EngineState *s, int script_nr, Resource **script,
return 0;
}
- if (NULL == s) {
- warning("script_instantiate_common(): script_instantiate(): NULL passed for \"s\"");
- return 0;
- }
-
- seg_id = s->seg_manager->segGet(script_nr);
- Script *scr = script_locate_by_segment(s, seg_id);
+ seg_id = segManager->segGet(script_nr);
+ Script *scr = segManager->getScriptIfLoaded(seg_id);
if (scr) {
if (!scr->isMarkedAsDeleted()) {
scr->incrementLockers();
@@ -1622,14 +1550,14 @@ int script_instantiate_common(EngineState *s, int script_nr, Resource **script,
scr->freeScript();
}
} else {
- scr = s->seg_manager->allocateScript(s, script_nr, &seg_id);
+ scr = segManager->allocateScript(script_nr, &seg_id);
if (!scr) { // ALL YOUR SCRIPT BASE ARE BELONG TO US
error("Not enough heap space for script size 0x%x of script 0x%x (Should this happen?)", (*script)->size, script_nr);
return 0;
}
}
- s->seg_manager->initialiseScript(*scr, s, script_nr);
+ segManager->initialiseScript(*scr, script_nr);
reg.segment = seg_id;
reg.offset = 0;
@@ -1645,7 +1573,7 @@ int script_instantiate_common(EngineState *s, int script_nr, Resource **script,
return seg_id;
}
-int script_instantiate_sci0(EngineState *s, int script_nr) {
+int script_instantiate_sci0(ResourceManager *resMgr, SegManager *segManager, SciVersion version, bool oldScriptHeader, int script_nr) {
int objtype;
unsigned int objlength;
reg_t reg;
@@ -1655,7 +1583,7 @@ int script_instantiate_sci0(EngineState *s, int script_nr) {
Resource *script;
int was_new;
- seg_id = script_instantiate_common(s, script_nr, &script, NULL, &was_new);
+ seg_id = script_instantiate_common(resMgr, segManager, version, script_nr, &script, NULL, &was_new);
if (was_new)
return seg_id;
@@ -1663,9 +1591,9 @@ int script_instantiate_sci0(EngineState *s, int script_nr) {
reg.segment = seg_id;
reg.offset = 0;
- Script *scr = s->seg_manager->getScript(seg_id);
+ Script *scr = segManager->getScript(seg_id);
- if (((SciEngine*)g_engine)->getKernel()->hasOldScriptHeader()) {
+ if (oldScriptHeader) {
//
int locals_nr = READ_LE_UINT16(script->data);
@@ -1678,7 +1606,7 @@ int script_instantiate_sci0(EngineState *s, int script_nr) {
magic_pos_adder = 2; // Step over the funny prefix
if (locals_nr)
- s->seg_manager->scriptInitialiseLocalsZero(reg.segment, locals_nr);
+ segManager->scriptInitialiseLocalsZero(reg.segment, locals_nr);
} else {
scr->mcpyInOut(0, script->data, script->size);
@@ -1717,24 +1645,24 @@ int script_instantiate_sci0(EngineState *s, int script_nr) {
break;
case SCI_OBJ_LOCALVARS:
- s->seg_manager->scriptInitialiseLocals(data_base);
+ segManager->scriptInitialiseLocals(data_base);
break;
case SCI_OBJ_CLASS: {
int classpos = addr.offset - SCRIPT_OBJECT_MAGIC_OFFSET;
int species;
species = scr->getHeap(addr.offset - SCRIPT_OBJECT_MAGIC_OFFSET + SCRIPT_SPECIES_OFFSET);
- if (species < 0 || species >= (int)s->_classtable.size()) {
+ if (species < 0 || species >= (int)segManager->_classtable.size()) {
error("Invalid species %d(0x%x) not in interval "
"[0,%d) while instantiating script %d\n",
- species, species, s->_classtable.size(),
+ species, species, segManager->_classtable.size(),
script_nr);
return 1;
}
- s->_classtable[species].script = script_nr;
- s->_classtable[species].reg = addr;
- s->_classtable[species].reg.offset = classpos;
+ segManager->_classtable[species].script = script_nr;
+ segManager->_classtable[species].reg = addr;
+ segManager->_classtable[species].reg.offset = classpos;
// Set technical class position-- into the block allocated for it
}
break;
@@ -1760,17 +1688,17 @@ int script_instantiate_sci0(EngineState *s, int script_nr) {
switch (objtype) {
case SCI_OBJ_CODE:
- s->seg_manager->scriptAddCodeBlock(addr);
+ segManager->scriptAddCodeBlock(addr);
break;
case SCI_OBJ_OBJECT:
case SCI_OBJ_CLASS: { // object or class?
- Object *obj = s->seg_manager->scriptObjInit(s, addr);
+ Object *obj = segManager->scriptObjInit(addr);
Object *base_obj;
// Instantiate the superclass, if neccessary
obj->_variables[SCRIPT_SPECIES_SELECTOR] = INST_LOOKUP_CLASS(obj->_variables[SCRIPT_SPECIES_SELECTOR].offset);
- base_obj = obj_get(s, obj->_variables[SCRIPT_SPECIES_SELECTOR]);
+ base_obj = obj_get(segManager, version, obj->_variables[SCRIPT_SPECIES_SELECTOR]);
obj->variable_names_nr = base_obj->_variables.size();
obj->base_obj = base_obj->base_obj;
// Copy base from species class, as we need its selector IDs
@@ -1791,24 +1719,24 @@ int script_instantiate_sci0(EngineState *s, int script_nr) {
} while ((objtype != 0) && (((unsigned)reg.offset) < script->size - 2));
if (relocation >= 0)
- s->seg_manager->scriptRelocate(make_reg(reg.segment, relocation));
+ segManager->scriptRelocate(make_reg(reg.segment, relocation));
return reg.segment; // instantiation successful
}
-int script_instantiate_sci11(EngineState *s, int script_nr) {
+int script_instantiate_sci11(ResourceManager *resMgr, SegManager *segManager, SciVersion version, int script_nr) {
Resource *script, *heap;
int seg_id;
int heap_start;
reg_t reg;
int was_new;
- seg_id = script_instantiate_common(s, script_nr, &script, &heap, &was_new);
+ seg_id = script_instantiate_common(resMgr, segManager, version, script_nr, &script, &heap, &was_new);
if (was_new)
return seg_id;
- Script *scr = s->seg_manager->getScript(seg_id);
+ Script *scr = segManager->getScript(seg_id);
heap_start = script->size;
if (script->size & 2)
@@ -1822,28 +1750,28 @@ int script_instantiate_sci11(EngineState *s, int script_nr) {
reg.segment = seg_id;
reg.offset = heap_start + 4;
- s->seg_manager->scriptInitialiseLocals(reg);
+ segManager->scriptInitialiseLocals(reg);
- s->seg_manager->scriptRelocateExportsSci11(seg_id);
- s->seg_manager->scriptInitialiseObjectsSci11(s, seg_id);
+ segManager->scriptRelocateExportsSci11(seg_id);
+ segManager->scriptInitialiseObjectsSci11(seg_id);
reg.offset = READ_LE_UINT16(heap->data);
- s->seg_manager->heapRelocate(reg);
+ segManager->heapRelocate(reg);
return seg_id;
}
-int script_instantiate(EngineState *s, int script_nr) {
- if (s->_version >= SCI_VERSION_1_1)
- return script_instantiate_sci11(s, script_nr);
+int script_instantiate(ResourceManager *resMgr, SegManager *segManager, SciVersion version, bool oldScriptHeader, int script_nr) {
+ if (version >= SCI_VERSION_1_1)
+ return script_instantiate_sci11(resMgr, segManager, version, script_nr);
else
- return script_instantiate_sci0(s, script_nr);
+ return script_instantiate_sci0(resMgr, segManager, version, oldScriptHeader, script_nr);
}
-void script_uninstantiate_sci0(EngineState *s, int script_nr, SegmentId seg) {
+void script_uninstantiate_sci0(SegManager *segManager, SciVersion version, int script_nr, SegmentId seg) {
reg_t reg = make_reg(seg, ((SciEngine*)g_engine)->getKernel()->hasOldScriptHeader() ? 2 : 0);
int objtype, objlength;
- Script *scr = s->seg_manager->getScript(seg);
+ Script *scr = segManager->getScript(seg);
// Make a pass over the object in order uninstantiate all superclasses
objlength = 0;
@@ -1866,13 +1794,13 @@ void script_uninstantiate_sci0(EngineState *s, int script_nr, SegmentId seg) {
superclass = scr->getHeap(reg.offset + SCRIPT_SUPERCLASS_OFFSET); // Get superclass...
if (superclass >= 0) {
- int superclass_script = s->_classtable[superclass].script;
+ int superclass_script = segManager->_classtable[superclass].script;
if (superclass_script == script_nr) {
if (scr->getLockers())
scr->decrementLockers(); // Decrease lockers if this is us ourselves
} else
- script_uninstantiate(s, superclass_script);
+ script_uninstantiate(segManager, version, superclass_script);
// Recurse to assure that the superclass lockers number gets decreased
}
@@ -1884,11 +1812,9 @@ void script_uninstantiate_sci0(EngineState *s, int script_nr, SegmentId seg) {
} while (objtype != 0);
}
-void script_uninstantiate(EngineState *s, int script_nr) {
- reg_t reg = make_reg(0, ((SciEngine*)g_engine)->getKernel()->hasOldScriptHeader() ? 2 : 0);
-
- reg.segment = s->seg_manager->segGet(script_nr);
- Script *scr = script_locate_by_segment(s, reg.segment);
+void script_uninstantiate(SegManager *segManager, SciVersion version, int script_nr) {
+ SegmentId segment = segManager->segGet(script_nr);
+ Script *scr = segManager->getScriptIfLoaded(segment);
if (!scr) { // Is it already loaded?
//warning("unloading script 0x%x requested although not loaded", script_nr);
@@ -1902,12 +1828,12 @@ void script_uninstantiate(EngineState *s, int script_nr) {
return;
// Free all classtable references to this script
- for (uint i = 0; i < s->_classtable.size(); i++)
- if (s->_classtable[i].reg.segment == reg.segment)
- s->_classtable[i].reg = NULL_REG;
+ for (uint i = 0; i < segManager->_classtable.size(); i++)
+ if (segManager->_classtable[i].reg.segment == segment)
+ segManager->_classtable[i].reg = NULL_REG;
- if (s->_version < SCI_VERSION_1_1)
- script_uninstantiate_sci0(s, script_nr, reg.segment);
+ if (version < SCI_VERSION_1_1)
+ script_uninstantiate_sci0(segManager, version, script_nr, segment);
else
warning("FIXME: Add proper script uninstantiation for SCI 1.1");
@@ -1999,8 +1925,8 @@ int game_run(EngineState **_s) {
return 0;
}
-Object *obj_get(EngineState *s, reg_t offset) {
- MemObject *mobj = GET_OBJECT_SEGMENT(*s->seg_manager, offset.segment);
+Object *obj_get(SegManager *segManager, SciVersion version, reg_t offset) {
+ MemObject *mobj = GET_OBJECT_SEGMENT(*segManager, offset.segment);
Object *obj = NULL;
int idx;
@@ -2023,8 +1949,8 @@ Object *obj_get(EngineState *s, reg_t offset) {
return obj;
}
-const char *obj_get_name(EngineState *s, reg_t pos) {
- Object *obj = obj_get(s, pos);
+const char *obj_get_name(SegManager *segManager, SciVersion version, reg_t pos) {
+ Object *obj = obj_get(segManager, version, pos);
if (!obj)
return "<no such object>";
@@ -2032,7 +1958,7 @@ const char *obj_get_name(EngineState *s, reg_t pos) {
if (nameReg.isNull())
return "<no name>";
- const char *name = (const char*)s->seg_manager->dereference(obj->_variables[SCRIPT_NAME_SELECTOR], NULL);
+ const char *name = (const char*)segManager->dereference(obj->_variables[SCRIPT_NAME_SELECTOR], NULL);
if (!name)
return "<invalid name>";
@@ -2056,7 +1982,7 @@ void shrink_execution_stack(EngineState *s, uint size) {
}
reg_t* ObjVarRef::getPointer(EngineState *s) const {
- Object *o = obj_get(s, obj);
+ Object *o = obj_get(s->seg_manager, s->_version, obj);
if (!o) return 0;
return &(o->_variables[varindex]);
}
diff --git a/engines/sci/engine/vm.h b/engines/sci/engine/vm.h
index ba225a9c00..867f732e2a 100644
--- a/engines/sci/engine/vm.h
+++ b/engines/sci/engine/vm.h
@@ -29,6 +29,7 @@
/* VM and kernel declarations */
#include "sci/engine/vm_types.h" // for reg_t
+#include "sci/resource.h" // for SciVersion
#include "common/util.h"
@@ -39,6 +40,7 @@ struct EngineState;
typedef int sci_version_t;
struct IntMapper;
struct Object;
+class ResourceManager;
/** Number of bytes to be allocated for the stack */
#define VM_STACK_SIZE 0x1000
@@ -67,12 +69,12 @@ struct Object;
#define SCRIPT_FUNCTAREAPTR_MAGIC 8 -8
/** Offset of the name pointer */
-#define SCRIPT_NAME_OFFSET (s->_version < SCI_VERSION_1_1 ? 14 -8 : 16)
-#define SCRIPT_NAME_SELECTOR (s->_version < SCI_VERSION_1_1 ? 3 : 8)
+#define SCRIPT_NAME_OFFSET (version < SCI_VERSION_1_1 ? 14 -8 : 16)
+#define SCRIPT_NAME_SELECTOR (version < SCI_VERSION_1_1 ? 3 : 8)
/** Object-relative offset of the -info- selector */
-#define SCRIPT_INFO_OFFSET (s->_version < SCI_VERSION_1_1 ? 12 -8 : 14)
-#define SCRIPT_INFO_SELECTOR (s->_version < SCI_VERSION_1_1 ? 2 : 7)
+#define SCRIPT_INFO_OFFSET (version < SCI_VERSION_1_1 ? 12 -8 : 14)
+#define SCRIPT_INFO_SELECTOR (version < SCI_VERSION_1_1 ? 2 : 7)
/** Flag fo the -info- selector */
#define SCRIPT_INFO_CLONE 0x0001
@@ -84,18 +86,18 @@ struct Object;
/** Magical object identifier */
#define SCRIPT_OBJECT_MAGIC_NUMBER 0x1234
/** Offset of this identifier */
-#define SCRIPT_OBJECT_MAGIC_OFFSET (s->_version < SCI_VERSION_1_1 ? -8 : 0)
+#define SCRIPT_OBJECT_MAGIC_OFFSET (version < SCI_VERSION_1_1 ? -8 : 0)
/** Script-relative offset of the species ID */
#define SCRIPT_SPECIES_OFFSET 8 -8
-#define SCRIPT_SUPERCLASS_OFFSET (s->_version < SCI_VERSION_1_1 ? 10 -8 : 12)
+#define SCRIPT_SUPERCLASS_OFFSET (version < SCI_VERSION_1_1 ? 10 -8 : 12)
/*---------------------------------*/
/* Script selector index variables */
/*---------------------------------*/
-#define SCRIPT_SPECIES_SELECTOR (s->_version < SCI_VERSION_1_1 ? 0 : 5)
-#define SCRIPT_SUPERCLASS_SELECTOR (s->_version < SCI_VERSION_1_1 ? 1 : 6)
+#define SCRIPT_SPECIES_SELECTOR (version < SCI_VERSION_1_1 ? 0 : 5)
+#define SCRIPT_SUPERCLASS_SELECTOR (version < SCI_VERSION_1_1 ? 1 : 6)
#define SCRIPT_CLASSSCRIPT_SELECTOR 4
/** Magic adjustment value for lofsa and lofss */
@@ -467,31 +469,13 @@ SelectorType lookup_selector(EngineState *s, reg_t obj, Selector selectorid,
ObjVarRef *varp, reg_t *fptr);
/**
- * Parameters for script_get_segment()
- */
-typedef enum {
- SCRIPT_GET_DONT_LOAD = 0, /**< Fail if not loaded */
- SCRIPT_GET_LOAD = 1, /**< Load, if neccessary */
- SCRIPT_GET_LOCK = 3 /**< Load, if neccessary, and lock */
-} SCRIPT_GET;
-
-/**
- * Determines the segment occupied by a certain script
- * @param[in] s The state to operate on
- * @param[in] script_id The script in question
- * @param[in] load One of SCRIPT_GET_*
- * @return The script's segment, or 0 on failure
- */
-SegmentId script_get_segment(EngineState *s, int script_id, SCRIPT_GET load);
-
-/**
* Looks up an entry of the exports table of a script
- * @param[in] s The state to operate on
+ * @param[in] segManager The segment manager
* @param[in] script_nr The script to look up in
* @param[out] export_index The index of the export entry to look up
* @return The handle
*/
-reg_t script_lookup_export(EngineState *s, int script_nr, int export_index);
+reg_t script_lookup_export(SegManager *segManager, int script_nr, int export_index);
/**
* Makes sure that a script and its superclasses get loaded to the heap.
@@ -499,21 +483,24 @@ reg_t script_lookup_export(EngineState *s, int script_nr, int export_index);
* increased. All scripts containing superclasses of this script are loaded
* recursively as well, unless 'recursive' is set to zero. The
* complementary function is "script_uninstantiate()" below.
- * @param[in] s The state to operate on
- * @param[in] script_nr The script number to load
- * @return The script's segment ID or 0 if out of heap
+ * @param[in] resMgr The resource manager
+ * @param[in] segManager The segment manager
+ * @param[in] version The SCI version to use
+ * @param[in] script_nr The script number to load
+ * @return The script's segment ID or 0 if out of heap
*/
-int script_instantiate(EngineState *s, int script_nr);
+int script_instantiate(ResourceManager *resMgr, SegManager *segManager, SciVersion version, bool oldScriptHeader, int script_nr);
/**
* Decreases the numer of lockers of a script and unloads it if that number
* reaches zero.
* This function will recursively unload scripts containing its
* superclasses, if those aren't locked by other scripts as well.
- * @param[in] s The state to operate on
+ * @param[in] segManager The segment manager
+ * @param[in] version The SCI version to use
* @param[in] script_nr The script number that is requestet to be unloaded
*/
-void script_uninstantiate(EngineState *s, int script_nr);
+void script_uninstantiate(SegManager *segManager, SciVersion version, int script_nr);
/**
* Initializes an SCI game
@@ -613,7 +600,7 @@ int kfree(EngineState *s, reg_t handle);
* in a static buffer and need not be freed (neither may
* it be modified).
*/
-const char *obj_get_name(EngineState *s, reg_t pos);
+const char *obj_get_name(SegManager *segManager, SciVersion version, reg_t pos);
/**
* Retrieves an object from the specified location
@@ -621,7 +608,7 @@ const char *obj_get_name(EngineState *s, reg_t pos);
* @param[in] offset The object's offset
* @return The object in question, or NULL if there is none
*/
-Object *obj_get(EngineState *s, reg_t offset);
+Object *obj_get(SegManager *segManager, SciVersion version, reg_t offset);
/**
* Shrink execution stack to size.
diff --git a/engines/sci/gfx/gfx_state_internal.h b/engines/sci/gfx/gfx_state_internal.h
index 3beb0ea067..1bff83e713 100644
--- a/engines/sci/gfx/gfx_state_internal.h
+++ b/engines/sci/gfx/gfx_state_internal.h
@@ -26,6 +26,7 @@
#ifndef SCI_GFX_GFX_STATE_INTERNAL_H
#define SCI_GFX_GFX_STATE_INTERNAL_H
+#include "sci/engine/vm.h"
#include "sci/gfx/gfx_tools.h"
#include "sci/gfx/gfx_options.h"
#include "sci/gfx/operations.h"
diff --git a/engines/sci/gfx/gfx_widgets.h b/engines/sci/gfx/gfx_widgets.h
index 80129152cb..ace13ff1b9 100644
--- a/engines/sci/gfx/gfx_widgets.h
+++ b/engines/sci/gfx/gfx_widgets.h
@@ -29,6 +29,7 @@
#include "common/rect.h"
+#include "sci/engine/vm.h"
#include "sci/gfx/gfx_system.h"
#include "sci/gfx/operations.h"
diff --git a/engines/sci/resource.cpp b/engines/sci/resource.cpp
index ef31fcdd7d..9b9c9ee26c 100644
--- a/engines/sci/resource.cpp
+++ b/engines/sci/resource.cpp
@@ -112,6 +112,20 @@ ResourceSource *ResourceManager::addExternalMap(const char *file_name) {
newsrc->source_type = kSourceExtMap;
newsrc->location_name = file_name;
+ newsrc->resourceFile = 0;
+ newsrc->scanned = false;
+ newsrc->associated_map = NULL;
+
+ _sources.push_back(newsrc);
+ return newsrc;
+}
+
+ResourceSource *ResourceManager::addExternalMap(const Common::FSNode *mapFile) {
+ ResourceSource *newsrc = new ResourceSource();
+
+ newsrc->source_type = kSourceExtMap;
+ newsrc->location_name = mapFile->getName();
+ newsrc->resourceFile = mapFile;
newsrc->scanned = false;
newsrc->associated_map = NULL;
@@ -125,6 +139,21 @@ ResourceSource *ResourceManager::addSource(ResourceSource *map, ResSourceType ty
newsrc->source_type = type;
newsrc->scanned = false;
newsrc->location_name = filename;
+ newsrc->resourceFile = 0;
+ newsrc->volume_number = number;
+ newsrc->associated_map = map;
+
+ _sources.push_back(newsrc);
+ return newsrc;
+}
+
+ResourceSource *ResourceManager::addSource(ResourceSource *map, ResSourceType type, const Common::FSNode *resFile, int number) {
+ ResourceSource *newsrc = new ResourceSource();
+
+ newsrc->source_type = type;
+ newsrc->scanned = false;
+ newsrc->location_name = resFile->getName();
+ newsrc->resourceFile = resFile;
newsrc->volume_number = number;
newsrc->associated_map = map;
@@ -342,6 +371,48 @@ int ResourceManager::addAppropriateSources() {
return 1;
}
+int ResourceManager::addAppropriateSources(const Common::FSList &fslist) {
+ ResourceSource *map = 0;
+
+ // First, find resource.map
+ for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
+ if (file->isDirectory())
+ continue;
+
+ Common::String filename = file->getName();
+ filename.toLowercase();
+
+ if (filename.contains("resource.map") || filename.contains("resmap.000")) {
+ map = addExternalMap(file);
+ break;
+ }
+ }
+
+ if (!map)
+ return 0;
+
+ // Now find all the resource.0?? files
+ for (Common::FSList::const_iterator file = fslist.begin(); file != fslist.end(); ++file) {
+ if (file->isDirectory())
+ continue;
+
+ Common::String filename = file->getName();
+ filename.toLowercase();
+
+ if (filename.contains("resource.0") || filename.contains("ressci.0")) {
+ const char *dot = strrchr(filename.c_str(), '.');
+ int number = atoi(dot + 1);
+
+ addSource(map, kSourceVolume, file, number);
+ }
+ }
+
+ // This function is only called by the advanced detector, and we don't really need
+ // to add a patch directory or message.map here
+
+ return 1;
+}
+
int ResourceManager::addInternalSources() {
Common::List<ResourceId> *resources = listResources(kResourceTypeMap);
Common::List<ResourceId>::iterator itr = resources->begin();
@@ -396,16 +467,23 @@ void ResourceManager::freeResourceSources() {
_sources.clear();
}
-ResourceManager::ResourceManager(int maxMemory) {
- _maxMemory = maxMemory;
+ResourceManager::ResourceManager() {
+ addAppropriateSources();
+ init();
+}
+
+ResourceManager::ResourceManager(const Common::FSList &fslist) {
+ addAppropriateSources(fslist);
+ init();
+}
+
+void ResourceManager::init() {
_memoryLocked = 0;
_memoryLRU = 0;
_LRU.clear();
_resMap.clear();
_audioMapSCI1 = NULL;
- addAppropriateSources();
-
// FIXME: put this in an Init() function, so that we can error out if detection fails completely
_mapVersion = detectMapVersion();
@@ -506,7 +584,7 @@ void ResourceManager::printLRU() {
}
void ResourceManager::freeOldResources() {
- while (_maxMemory < _memoryLRU) {
+ while (MAX_MEMORY < _memoryLRU) {
assert(!_LRU.empty());
Resource *goner = *_LRU.reverse_begin();
removeFromLRU(goner);
@@ -602,7 +680,8 @@ const char *ResourceManager::versionDescription(ResVersion version) const {
}
ResourceManager::ResVersion ResourceManager::detectMapVersion() {
- Common::File file;
+ Common::SeekableReadStream *fileStream = 0;
+ Common::File *file = 0;
byte buff[6];
ResourceSource *rsrc= 0;
@@ -610,22 +689,30 @@ ResourceManager::ResVersion ResourceManager::detectMapVersion() {
rsrc = *it;
if (rsrc->source_type == kSourceExtMap) {
- file.open(rsrc->location_name);
+ if (rsrc->resourceFile) {
+ fileStream = rsrc->resourceFile->createReadStream();
+ } else {
+ file = new Common::File();
+ file->open(rsrc->location_name);
+ if (file->isOpen())
+ fileStream = file;
+ }
break;
}
}
- if (file.isOpen() == false) {
+
+ if (!fileStream) {
error("Failed to open resource map file");
return kResVersionUnknown;
}
// detection
// SCI0 and SCI01 maps have last 6 bytes set to FF
- file.seek(-4, SEEK_END);
- uint32 uEnd = file.readUint32LE();
+ fileStream->seek(-4, SEEK_END);
+ uint32 uEnd = fileStream->readUint32LE();
if (uEnd == 0xFFFFFFFF) {
// check if 0 or 01 - try to read resources in SCI0 format and see if exists
- file.seek(0, SEEK_SET);
- while (file.read(buff, 6) == 6 && !(buff[0] == 0xFF && buff[1] == 0xFF && buff[2] == 0xFF)) {
+ fileStream->seek(0, SEEK_SET);
+ while (fileStream->read(buff, 6) == 6 && !(buff[0] == 0xFF && buff[1] == 0xFF && buff[2] == 0xFF)) {
if (getVolume(rsrc, (buff[5] & 0xFC) >> 2) == NULL)
return kResVersionSci1Middle;
}
@@ -639,14 +726,15 @@ ResourceManager::ResVersion ResourceManager::detectMapVersion() {
uint16 lastDirectoryOffset = 0;
uint16 directorySize = 0;
ResVersion mapDetected = kResVersionUnknown;
- file.seek(0, SEEK_SET);
- while (!file.eos()) {
- directoryType = file.readByte();
- directoryOffset = file.readUint16LE();
+ fileStream->seek(0, SEEK_SET);
+
+ while (!fileStream->eos()) {
+ directoryType = fileStream->readByte();
+ directoryOffset = fileStream->readUint16LE();
if ((directoryType < 0x80) || ((directoryType > 0xA0) && (directoryType != 0xFF)))
break;
// Offset is above file size? -> definitely not SCI1/SCI1.1
- if (directoryOffset > file.size())
+ if (directoryOffset > fileStream->size())
break;
if (lastDirectoryOffset) {
directorySize = directoryOffset - lastDirectoryOffset;
@@ -655,11 +743,14 @@ ResourceManager::ResVersion ResourceManager::detectMapVersion() {
if ((directorySize % 5 == 0) && (directorySize % 6))
mapDetected = kResVersionSci11;
}
- if (directoryType==0xFF) {
+ if (directoryType == 0xFF) {
// FFh entry needs to point to EOF
- if (directoryOffset != file.size())
+ if (directoryOffset != fileStream->size())
break;
- if (mapDetected)
+
+ delete fileStream;
+
+ if (mapDetected)
return mapDetected;
return kResVersionSci1Late;
}
@@ -675,29 +766,41 @@ ResourceManager::ResVersion ResourceManager::detectMapVersion() {
// "lastDirectoryOffset". This is probably not the correct fix, since before r43000
// the loop above could not prematurely terminate and thus this would always check the
// last directory entry instead of the last checked directory entry.
- file.seek(lastDirectoryOffset - 7, SEEK_SET);
- if (file.readByte() == 0xFF && file.readUint16LE() == file.size())
+ fileStream->seek(lastDirectoryOffset - 7, SEEK_SET);
+ if (fileStream->readByte() == 0xFF && fileStream->readUint16LE() == fileStream->size())
return kResVersionSci32; // TODO : check if there is a difference between these maps
#endif
+ delete fileStream;
+
return kResVersionUnknown;
}
ResourceManager::ResVersion ResourceManager::detectVolVersion() {
- Common::File file;
+ Common::SeekableReadStream *fileStream = 0;
+ Common::File *file = 0;
ResourceSource *rsrc;
+
for (Common::List<ResourceSource *>::iterator it = _sources.begin(); it != _sources.end(); ++it) {
rsrc = *it;
if (rsrc->source_type == kSourceVolume) {
- file.open(rsrc->location_name);
+ if (rsrc->resourceFile) {
+ fileStream = rsrc->resourceFile->createReadStream();
+ } else {
+ file = new Common::File();
+ file->open(rsrc->location_name);
+ if (file->isOpen())
+ fileStream = file;
+ }
break;
}
}
- if (file.isOpen() == false) {
+ if (!fileStream) {
error("Failed to open volume file");
return kResVersionUnknown;
}
+
// SCI0 volume format: {wResId wPacked+4 wUnpacked wCompression} = 8 bytes
// SCI1 volume format: {bResType wResNumber wPacked+4 wUnpacked wCompression} = 9 bytes
// SCI1.1 volume format: {bResType wResNumber wPacked wUnpacked wCompression} = 9 bytes
@@ -710,15 +813,17 @@ ResourceManager::ResVersion ResourceManager::detectVolVersion() {
bool failed = false;
// Check for SCI0, SCI1, SCI1.1 and SCI32 v2 (Gabriel Knight 1 CD) formats
- while (!file.eos() && file.pos() < 0x100000) {
+ while (!fileStream->eos() && fileStream->pos() < 0x100000) {
if (curVersion > kResVersionSci0Sci1Early)
- file.readByte();
- resId = file.readUint16LE();
- dwPacked = (curVersion < kResVersionSci32) ? file.readUint16LE() : file.readUint32LE();
- dwUnpacked = (curVersion < kResVersionSci32) ? file.readUint16LE() : file.readUint32LE();
- wCompression = (curVersion < kResVersionSci32) ? file.readUint16LE() : file.readUint32LE();
- if (file.eos())
+ fileStream->readByte();
+ resId = fileStream->readUint16LE();
+ dwPacked = (curVersion < kResVersionSci32) ? fileStream->readUint16LE() : fileStream->readUint32LE();
+ dwUnpacked = (curVersion < kResVersionSci32) ? fileStream->readUint16LE() : fileStream->readUint32LE();
+ wCompression = (curVersion < kResVersionSci32) ? fileStream->readUint16LE() : fileStream->readUint32LE();
+ if (fileStream->eos()) {
+ delete fileStream;
return curVersion;
+ }
int chk = (curVersion == kResVersionSci0Sci1Early) ? 4 : 20;
int offs = curVersion < kResVersionSci11 ? 4 : 0;
@@ -740,18 +845,20 @@ ResourceManager::ResVersion ResourceManager::detectVolVersion() {
break;
}
- file.seek(0, SEEK_SET);
+ fileStream->seek(0, SEEK_SET);
continue;
}
if (curVersion < kResVersionSci11)
- file.seek(dwPacked - 4, SEEK_CUR);
+ fileStream->seek(dwPacked - 4, SEEK_CUR);
else if (curVersion == kResVersionSci11)
- file.seek((9 + dwPacked) % 2 ? dwPacked + 1 : dwPacked, SEEK_CUR);
+ fileStream->seek((9 + dwPacked) % 2 ? dwPacked + 1 : dwPacked, SEEK_CUR);
else if (curVersion == kResVersionSci32)
- file.seek(dwPacked, SEEK_CUR);//(9 + wPacked) % 2 ? wPacked + 1 : wPacked, SEEK_CUR);
+ fileStream->seek(dwPacked, SEEK_CUR);//(9 + wPacked) % 2 ? wPacked + 1 : wPacked, SEEK_CUR);
}
+ delete fileStream;
+
if (!failed)
return curVersion;
@@ -1480,7 +1587,7 @@ SciVersion ResourceManager::detectSciVersion() {
// If this turns out to be unreliable, we could do some pic resource checks instead.
return SCI_VERSION_1_EARLY;
case kResVersionSci1Middle:
- return SCI_VERSION_1_LATE;
+ return SCI_VERSION_1_MIDDLE;
case kResVersionSci1Late:
if (_viewType == kViewVga11) {
// SCI1.1 resources, assume SCI1.1
diff --git a/engines/sci/resource.h b/engines/sci/resource.h
index 1ab49c834e..4250225ffe 100644
--- a/engines/sci/resource.h
+++ b/engines/sci/resource.h
@@ -28,12 +28,12 @@
#include "common/str.h"
#include "common/file.h"
+#include "common/fs.h"
#include "common/archive.h"
#include "sound/audiostream.h"
#include "sound/mixer.h" // for SoundHandle
-#include "sci/engine/vm.h" // for Object
#include "sci/decompressor.h"
namespace Common {
@@ -53,7 +53,8 @@ enum SciVersion {
SCI_VERSION_01, // KQ1 and multilingual games (S.old.*)
SCI_VERSION_1_EGA, // EGA with parser, QFG2
SCI_VERSION_1_EARLY, // KQ5. (EGA/VGA)
- SCI_VERSION_1_LATE, // ECO1, LSL1, LSL5. (EGA/VGA)
+ SCI_VERSION_1_MIDDLE, // LSL1, JONESCD. (EGA?/VGA)
+ SCI_VERSION_1_LATE, // ECO1, LSL5. (EGA/VGA)
SCI_VERSION_1_1, // KQ6, ECO2
SCI_VERSION_32 // GK
};
@@ -136,6 +137,7 @@ struct ResourceSource {
ResSourceType source_type;
bool scanned;
Common::String location_name; // FIXME: Replace by FSNode ?
+ const Common::FSNode *resourceFile;
int volume_number;
ResourceSource *associated_map;
};
@@ -245,15 +247,9 @@ public:
/**
* Creates a new SCI resource manager.
- * @param version The SCI version to look for; use SCI_VERSION_AUTODETECT
- * in the default case.
- * @param maxMemory Maximum number of bytes to allow allocated for resources
- *
- * @note maxMemory will not be interpreted as a hard limit, only as a restriction
- * for resources which are not explicitly locked. However, a warning will be
- * issued whenever this limit is exceeded.
*/
- ResourceManager(int maxMemory);
+ ResourceManager();
+ ResourceManager(const Common::FSList &fslist);
~ResourceManager();
/**
@@ -294,8 +290,13 @@ public:
void setAudioLanguage(int language);
protected:
+ // Maximum number of bytes to allow being allocated for resources
+ // Note: maxMemory will not be interpreted as a hard limit, only as a restriction
+ // for resources which are not explicitly locked. However, a warning will be
+ // issued whenever this limit is exceeded.
+ #define MAX_MEMORY 256 * 1024 // 256KB
+
ViewType _viewType; // Used to determine if the game has EGA or VGA graphics
- int _maxMemory; //!< Config option: Maximum total byte number allocated
Common::List<ResourceSource *> _sources;
int _memoryLocked; //!< Amount of resource bytes in locked memory
int _memoryLRU; //!< Amount of resource bytes under LRU control
@@ -308,6 +309,11 @@ protected:
SciVersion _sciVersion; //!< Detected SCI version */
/**
+ * Initializes the resource manager
+ */
+ void init();
+
+ /**
* Add a path to the resource manager's list of sources.
* @return a pointer to the added source structure, or NULL if an error occurred.
*/
@@ -324,12 +330,19 @@ protected:
*/
ResourceSource *addSource(ResourceSource *map, ResSourceType type, const char *filename,
int number);
+
+ ResourceSource *addSource(ResourceSource *map, ResSourceType type,
+ const Common::FSNode *resFile, int number);
+
/**
* Add an external (i.e., separate file) map resource to the resource manager's list of sources.
* @param file_name The name of the volume to add
* @return A pointer to the added source structure, or NULL if an error occurred.
*/
ResourceSource *addExternalMap(const char *file_name);
+
+ ResourceSource *addExternalMap(const Common::FSNode *mapFile);
+
/**
* Add an internal (i.e., resource) map to the resource manager's list of sources.
* @param name The name of the resource to add
@@ -346,6 +359,7 @@ protected:
*/
void scanNewSources();
int addAppropriateSources();
+ int addAppropriateSources(const Common::FSList &fslist);
int addInternalSources();
void freeResourceSources();
diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp
index 478f8645d4..596895d1cb 100644
--- a/engines/sci/sci.cpp
+++ b/engines/sci/sci.cpp
@@ -44,13 +44,14 @@ namespace Sci {
class GfxDriver;
// FIXME: error-prone
-const char *versionNames[9] = {
+const char *versionNames[10] = {
"Autodetect",
"SCI0 Early",
"SCI0 Late",
"SCI01",
"SCI1 EGA",
"SCI1 Early",
+ "SCI1 Middle",
"SCI1 Late",
"SCI1.1",
"SCI32"
@@ -140,7 +141,7 @@ Common::Error SciEngine::run() {
const uint32 flags = getFlags();
- _resmgr = new ResourceManager(256 * 1024);
+ _resmgr = new ResourceManager();
_version = _resmgr->sciVersion();
if (!_resmgr) {
diff --git a/engines/scumm/sound.cpp b/engines/scumm/sound.cpp
index 528cceb0cc..524dbf70ea 100644
--- a/engines/scumm/sound.cpp
+++ b/engines/scumm/sound.cpp
@@ -86,7 +86,7 @@ Sound::Sound(ScummEngine *parent, Audio::Mixer *mixer)
Sound::~Sound() {
stopCDTimer();
- AudioCD.destroy();
+ AudioCD.stop();
delete _sfxFile;
}
diff --git a/engines/tinsel/pcode.cpp b/engines/tinsel/pcode.cpp
index e6ed9df5c9..8646ad3267 100644
--- a/engines/tinsel/pcode.cpp
+++ b/engines/tinsel/pcode.cpp
@@ -126,6 +126,10 @@ const byte fragment5[] = {OP_IMM | OPSIZE16, 901 % 256, 901 / 256, OP_JUMP, 488
const int fragment5_size = 6;
const byte fragment6[] = {OP_IMM | OPSIZE16, 903 % 256, 903 / 256, OP_JUMP, 516 % 256, 516 / 256};
const int fragment6_size = 6;
+const byte fragment7[] = {OP_IMM | OPSIZE16, 908 % 256, 908 / 256, OP_JUMP, 616 % 256, 616 / 256};
+const int fragment7_size = 6;
+const byte fragment8[] = {OP_IMM | OPSIZE16, 910 % 256, 910 / 256, OP_JUMP, 644 % 256, 644 / 256};
+const int fragment8_size = 6;
const WorkaroundEntry workaroundList[] = {
// DW1-SCN: Global 206 is whether Rincewind is trying to take the book back to the present.
@@ -146,6 +150,8 @@ const WorkaroundEntry workaroundList[] = {
{TINSEL_V1, false, 310506872, 463, fragment4_size, fragment4},
{TINSEL_V1, false, 310506872, 485, fragment5_size, fragment5},
{TINSEL_V1, false, 310506872, 513, fragment6_size, fragment6},
+ {TINSEL_V1, false, 310506872, 613, fragment7_size, fragment7},
+ {TINSEL_V1, false, 310506872, 641, fragment8_size, fragment8},
// DW2: In the garden, global #490 is set when the bees begin their 'out of hive' animation, and reset when done.
// But if the game is saved/restored during it, the animation sequence is reset without the global being cleared.
@@ -158,7 +164,7 @@ const WorkaroundEntry workaroundList[] = {
{TINSEL_V0, false, 0, 0, 0, NULL}
};
-
+//310505453, x
//----------------- LOCAL GLOBAL DATA --------------------
/**
diff --git a/engines/tinsel/tinsel.cpp b/engines/tinsel/tinsel.cpp
index 5f056351b6..7586c5e749 100644
--- a/engines/tinsel/tinsel.cpp
+++ b/engines/tinsel/tinsel.cpp
@@ -888,6 +888,7 @@ TinselEngine::~TinselEngine() {
if (MoviePlaying())
FinishBMV();
+ AudioCD.stop();
delete _sound;
delete _midiMusic;
delete _pcmMusic;